Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grab the completion prefix correctly #3659

Merged
merged 22 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
32 changes: 18 additions & 14 deletions cider-completion.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
toniz4 marked this conversation as resolved.
Show resolved Hide resolved
(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
Expand Down Expand Up @@ -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)))
vemv marked this conversation as resolved.
Show resolved Hide resolved

(defun cider-company-enable-fuzzy-completion ()
"Enable backend-driven fuzzy completion in the current buffer.

Expand All @@ -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
Expand Down
54 changes: 26 additions & 28 deletions doc/modules/ROOT/pages/usage/code_completion.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
----
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down
22 changes: 18 additions & 4 deletions test/cider-completion-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)))))
Expand Down
Loading