From 167634a3695e7b0dbe2cd9bc8afe209062a37e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A1ssio=20=C3=81vila?= Date: Tue, 21 May 2024 12:01:37 -0300 Subject: [PATCH] Fix completions when using `flex`-like completion styles (#3659) --- CHANGELOG.md | 1 + cider-completion.el | 32 ++++++----- .../ROOT/pages/usage/code_completion.adoc | 54 +++++++++---------- test/cider-completion-tests.el | 22 ++++++-- 4 files changed, 63 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa326e539..f65d4996f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ ### Bugs fixed +- [#3659](https://github.com/clojure-emacs/cider/pull/3659): Fixes completions when using `flex`-like completion styles. - [#3600](https://github.com/clojure-emacs/cider/pull/3600): Fix scittle jack-in when using `cider-jack-in-clj`. - [#3663](https://github.com/clojure-emacs/cider/issues/3663): Fix `cider-interactive-eval-override` invocation. diff --git a/cider-completion.el b/cider-completion.el index 6b54420c7..bd23c3859 100644 --- a/cider-completion.el +++ b/cider-completion.el @@ -181,16 +181,25 @@ performed by `cider-annotate-completion-function'." (defun cider-complete-at-point () "Complete the symbol at point." - (when-let* ((bounds (bounds-of-thing-at-point 'symbol))) + (when-let* ((bounds (or (bounds-of-thing-at-point 'symbol) + (cons (point) (point)))) + (bounds-string (buffer-substring (car bounds) (cdr bounds)))) (when (and (cider-connected-p) (not (or (cider-in-string-p) (cider-in-comment-p)))) - (let* (last-prefix + (let* (last-bounds-string last-result (complete - (lambda (prefix) - (unless (string-equal last-prefix prefix) - (setq last-prefix prefix) - (setq last-result (cider-complete prefix))) + (lambda () + ;; We are Not using the prefix extracted within the (prefix pred action) + ;; lambda. In certain completion styles, the prefix might be an empty + ;; string, which is unreliable. A more dependable method is to use the + ;; string defined by the bounds of the symbol at point. + ;; + ;; Caching just within the function is sufficient. Keeping it local + ;; ensures that it will not extend across different CIDER sessions. + (unless (string= bounds-string last-bounds-string) + (setq last-bounds-string bounds-string) + (setq last-result (cider-complete bounds-string))) last-result))) (list (car bounds) (cdr bounds) (lambda (prefix pred action) @@ -205,8 +214,7 @@ performed by `cider-annotate-completion-function'." (cond ((eq action 'metadata) `(metadata (category . cider))) ;; defines a completion category named 'cider, used later in our `completion-category-overrides` logic. ((eq (car-safe action) 'boundaries) nil) (t (with-current-buffer (current-buffer) - (complete-with-action action - (funcall complete prefix) prefix pred))))) + (complete-with-action action (funcall complete) prefix pred))))) :annotation-function #'cider-annotate-symbol :company-kind #'cider-company-symbol-kind :company-doc-buffer #'cider-create-compact-doc-buffer @@ -264,12 +272,6 @@ in the buffer." cider-company-unfiltered-candidates "CIDER backend-driven completion style.")) -;; Currently CIDER completions only work for `basic`, and not `initials`, `partial-completion`, `orderless`, etc. -;; So we ensure that those other styles aren't used with CIDER, otherwise one would see bad or no completions at all. -;; This `add-to-list` call can be removed once we implement the other completion styles. -;; (When doing that, please refactor `cider-enable-flex-completion' as well) -(add-to-list 'completion-category-overrides '(cider (styles basic))) - (defun cider-company-enable-fuzzy-completion () "Enable backend-driven fuzzy completion in the current buffer. @@ -292,6 +294,8 @@ Only affects the `cider' completion category.`" (setq completion-category-overrides (seq-remove (lambda (x) (equal 'cider (car x))) completion-category-overrides)) + (unless found-styles + (setq found-styles '(styles basic))) (unless (member 'flex found-styles) (setq found-styles (append found-styles '(flex)))) (add-to-list 'completion-category-overrides (apply #'list 'cider found-styles (when found-cycle diff --git a/doc/modules/ROOT/pages/usage/code_completion.adoc b/doc/modules/ROOT/pages/usage/code_completion.adoc index c83dcc66e..9665b99c7 100644 --- a/doc/modules/ROOT/pages/usage/code_completion.adoc +++ b/doc/modules/ROOT/pages/usage/code_completion.adoc @@ -37,18 +37,27 @@ is already properly indented. == Completion styles -CIDER defines (via the `completion-styles-alist` Elisp variable) a completion category named `cider`. +CIDER defines a specialized completion category through the `cider-complete-at-point` function, +added to `completion-at-point-functions`, establishing a dedicated completion category named +`cider`. -The `cider` completion category currently only supports `basic` completion styles (and not `partial-completion`, `orderless`, etc), -and `flex`, optionally (read more below). +The CIDER completion at point function supports most completion styles, including +`partial-completion`, `orderless` and `flex` (read more below). -CIDER declares so in this fashion: + +Sometimes the user may want to use a different completion style just for the CIDER +complete at point function. That can be achieved by setting +`completion-category-overrides`, overwriting the completion style of the CIDER +complete at point function. The following snippet accomplishes that: [source,lisp] ---- (add-to-list 'completion-category-overrides '(cider (styles basic))) ---- +This specifies that the `cider` completion category should employ the basic completion style by +default. + You can also enable the `flex` completion style by activating xref:usage/code_completion.adoc#fuzzy-candidate-matching[fuzzy candidate matching]. == Auto-completion @@ -131,13 +140,14 @@ without needing to hit an extra key, please customize: === Fuzzy candidate matching -By default, CIDER will provide completion candidates with the -assumption that whatever you've typed so far is a prefix of what -you're really trying to type. For example, if you type `map-` then -you'll only get completion candidates that have `map-` as the -beginning of their names. Sometimes, you don't know the exact prefix -for the item you want to type. In this case, you can get -CIDER-specific "fuzzy completion" by setting up in your Emacs init file: +By default, CIDER will use the completion styles defined in +`completion-styles`, the defaults being `(basic partial-completion +emacs22)` since Emacs 23. For a better description of how those +completion styles operates, refer to the official Emacs manual on +https://www.gnu.org/software/emacs/manual/html_node/emacs/Completion-Styles.html[how completion alternatives are chosen]. + +CIDER provides a function to enable the `flex` completion style for CIDER-specific +completions. If you wish to enable that, you can add this to your config: [source,lisp] ---- @@ -146,11 +156,11 @@ CIDER-specific "fuzzy completion" by setting up in your Emacs init file: This adds the `flex` completion style, as introduced in Emacs 27. -Now, `company-mode` will accept certain fuzziness when matching -candidates against the prefix. For example, typing `mi` will show you -`map-indexed` as one of the possible completion candidates and `cji` -will complete to `clojure.java.io`. Different completion examples are -shown +Now, `company-mode` (and other completion packages like `corfu`) will +accept certain fuzziness when matching candidates against the +prefix. For example, typing `mi` will show you `map-indexed` as one of +the possible completion candidates and `cji` will complete to +`clojure.java.io`. Different completion examples are shown https://github.com/alexander-yakushev/compliment/wiki/Examples[here]. NOTE: `cider-company-enable-fuzzy-completion` (now deprecated) should be used for Emacs < 27. @@ -189,18 +199,6 @@ keys to cancel the prompt by customizing: (funcall f a b)))) ---- -=== Changing the completion style - -Sometimes the user may want to use a different completion style just for the CIDER -complete at point function. That can be achieved by setting -`completion-category-defaults`, overriting the completion style of the CIDER -complete at point function. The following snippet accomplishes that: - -[source,lisp] ----- -(add-to-list 'completion-category-defaults '(cider (styles basic))) ----- - === Updating stale classes and methods cache Sometimes, the completion fails to recognize new classes that came with diff --git a/test/cider-completion-tests.el b/test/cider-completion-tests.el index bfbba1ee7..e80f4253a 100644 --- a/test/cider-completion-tests.el +++ b/test/cider-completion-tests.el @@ -36,15 +36,29 @@ (let ((old-value completion-category-overrides)) (unwind-protect (progn - (it "adds `flex'" - (cider-enable-flex-completion) - (expect (member 'flex (assq 'styles (assq 'cider completion-category-overrides))) - :to-be-truthy)) + (it "adds `flex' and `basic' as a fallback" + (let ((expected-category-overrides '((cider (styles basic flex))))) + (cider-enable-flex-completion) + (expect (member 'flex (assq 'styles (assq 'cider completion-category-overrides))) + :to-be-truthy) + (expect (member 'basic (assq 'styles (assq 'cider completion-category-overrides))) + :to-be-truthy) + (expect completion-category-overrides :to-equal expected-category-overrides))) (it "doesn't add `cycle'" (expect (assq 'cycle (assq 'cider completion-category-overrides)) :to-be nil)) + (it "adds just `flex' if there is another style present" + (setq completion-category-overrides '((cider (styles partial-completion)))) + (cider-enable-flex-completion) + (expect (member 'flex (assq 'styles (assq 'cider completion-category-overrides))) + :to-be-truthy) + (expect (member 'partial-completion (assq 'styles (assq 'cider completion-category-overrides))) + :to-be-truthy) + (expect (member 'basic (assq 'styles (assq 'cider completion-category-overrides))) + :to-be nil)) + (it "doesn't re-add `flex' if already present, preserving `cycle' as well" (let ((with-flex-and-cycle '((cider (styles basic flex) (cycle t)))))