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

Use separator character for boundary quit logic and prefix sort #120

Merged
merged 17 commits into from
Feb 7, 2022
Merged
52 changes: 44 additions & 8 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
- The selected candidate automatically committed on further input by default
(configurable via ~corfu-commit-predicate~).
- The [[https://github.com/oantolin/orderless][Orderless]] completion style is supported. The filter string can contain
arbitrary characters, including spaces, if ~corfu-quit-at-boundary~ is nil.
arbitrary characters, including spaces, if ~corfu-separator~ is configured (try =M-SPC=).
- Deferred completion style highlighting for performance.
- Jumping to location/documentation of current candidate.
- Show candidate documentation/signature string in the echo area.
Expand Down Expand Up @@ -77,7 +77,7 @@
;; (corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
;; (corfu-auto t) ;; Enable auto completion
;; (corfu-commit-predicate nil) ;; Do not commit selected candidates on next input
;; (corfu-quit-at-boundary t) ;; Automatically quit at word boundary
;; (corfu-separator ?\s) ;; Orderless field separator
;; (corfu-quit-no-match t) ;; Automatically quit if there is no match
;; (corfu-preview-current nil) ;; Disable current candidate preview
;; (corfu-preselect-first nil) ;; Disable candidate preselection
Expand Down Expand Up @@ -144,14 +144,13 @@
#+begin_src emacs-lisp
;; Enable auto completion and eager quitting
(setq corfu-auto t
corfu-quit-at-boundary t
corfu-quit-no-match t)
#+end_src

In general, I recommend to experiment a bit with the various settings and key
bindings to find a configuration which works for you. There is no one size
fits all solution. Some people like auto completion, some like manual
completion, some want to cycle with TAB or and some with the arrow keys...
completion, some want to cycle with TAB and some with the arrow keys...

** Completing with Corfu in the minibuffer

Expand Down Expand Up @@ -190,13 +189,12 @@ completion UI, the following snippet should yield the desired result.
** Completing with Corfu in the Shell or Eshell

When completing in the Eshell I recommend conservative local settings, no auto
completion, quitting at boundary and quitting if there is no match.
completion, and quitting if there is no match.

#+begin_src emacs-lisp
(add-hook 'eshell-mode-hook
(lambda ()
(setq-local corfu-quit-at-boundary t
corfu-quit-no-match t
(setq-local corfu-quit-no-match t
corfu-auto nil)
(corfu-mode)))
#+end_src
Expand Down Expand Up @@ -224,6 +222,43 @@ sane Eshell experience.*
(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)
#+end_src

** Orderless auto-completion

[[https://github.com/oantolin/orderless][Orderless]] is an advanced completion style that supports multi-component search
filters separated by a configurable character (space, by default). Normally,
entering characters like space which lie outside the completion region
boundaries (words, typically) causes corfu to quit. This behavior is very
helpful with auto-completion, which may pop-up when not desired, e.g. on
entering a new variable name. Just keep typing and corfu will get out of the
way.

But orderless search terms can contain any characters; they are regular
expressions. To use orderless in the buffer with ~corfu-auto~, set
~corfu-separator~ (a space, by default) to the primary character of your
orderless component separator.

Then, when a new orderless component is desired, simply use =M-SPC=
(~corfu-insert-separator~) to enter the /first/ component separator in the
input, and arbitrary orderless search terms and new separators can be entered
thereafter.

Note that ~corfu-separator~ replaced and obsoleted ~corfu-quit-at-boundary~. If you
want to restore the old behavior of ~corfu-quit-at-boundary=t~ you can bind
~corfu-insert-separator~ to =SPC= in ~corfu-map~.

#+begin_src emacs-lisp
(use-package corfu
;; Orderless customizations
:custom
(corfu-auto t)
;; (corfu-separator ?_) ;; Set to orderless separator, if not using space
:bind
;; (:map corfu-map ;; Another key binding can be used, such as S-SPC
;; ("M-SPC" . corfu-insert-separator))
:init
(corfu-global-mode))
#+end_src

** TAB-and-Go completion

You may be interested in configuring Corfu in TAB-and-Go style. Pressing TAB
Expand Down Expand Up @@ -263,6 +298,7 @@ moves to the next candidate and further input will then commit the selection.
- =RET= -> ~corfu-insert~
- =M-g= -> ~corfu-show-location~
- =M-h= -> ~corfu-show-documentation~
- =M-SPC= -> ~corfu-insert-separator~
- =C-g= -> ~corfu-quit~
- ~keyboard-escape-quit~ -> ~corfu-reset~

Expand All @@ -275,7 +311,7 @@ moves to the next candidate and further input will then commit the selection.

- [[https://github.com/oantolin/orderless][Orderless]]: Corfu supports completion styles,
including the advanced [[https://github.com/oantolin/orderless][Orderless]] completion style, where the filtering
expressions are separated by spaces (see ~corfu-quit-at-boundary~).
expressions are separated by spaces or another character (see ~corfu-separator~).

- [[https://github.com/minad/cape][Cape]]: I collect additional Capf backends and =completion-in-region= commands
in my [[https://github.com/minad/cape][Cape]] package. The package provides a file path, a dabbrev completion
Expand Down
37 changes: 29 additions & 8 deletions corfu.el
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,21 @@ The value should lie between 0 and corfu-count/2."
"Preselect first candidate."
:type 'boolean)

(defcustom corfu-quit-at-boundary nil
"Automatically quit at completion field/word boundary.
If automatic quitting is disabled, Orderless filter strings with spaces
are allowed."
:type 'boolean)
(make-obsolete
'corfu-quit-at-boundary
"See the new `corfu-separator' customization."
"0.19")

(defcustom corfu-separator ?\s
"Component separator character.
The character used for separating components in the input. If
non-nil, the presence of this separator character will inhibit
quitting at completion boundaries, so that any further characters
can be entered. If nil, always quit at completion boundaries.
To enter the first separator character, call
`corfu-insert-separator' (bound to M-SPC by default).
Useful for multi-component completion styles such as orderless."
:type '(choice (const nil) 'character))

(defcustom corfu-quit-no-match 1.0
"Automatically quit if no matching candidate is found.
Expand Down Expand Up @@ -215,6 +225,7 @@ The completion backend can override this with
(define-key map "\t" #'corfu-complete)
(define-key map "\eg" #'corfu-show-location)
(define-key map "\eh" #'corfu-show-documentation)
(define-key map "\e " #'corfu-insert-separator)
map)
"Corfu keymap used when popup is shown.")

Expand Down Expand Up @@ -558,7 +569,8 @@ A scroll bar is displayed from LO to LO+BAR."

(defun corfu--move-prefix-candidates-to-front (field candidates)
"Move CANDIDATES which match prefix of FIELD to the beginning."
(let* ((word (replace-regexp-in-string " .*" "" field))
(let* ((word (substring field 0
(seq-position field corfu-separator)))
(len (length word)))
(corfu--partition!
candidates
Expand Down Expand Up @@ -842,6 +854,12 @@ there hasn't been any input, then quit."
"Return t if a candidate is selected and previewed."
(and corfu-preview-current (/= corfu--index corfu--preselect)))

(defun corfu-insert-separator ()
"Insert a separator character, inhibiting quit on completion boundary."
(interactive)
(unless corfu-separator (error "`corfu-separator' character is nil"))
(insert corfu-separator))

(defun corfu--post-command ()
"Refresh Corfu after last command."
(or (pcase completion-in-region--data
Expand All @@ -855,8 +873,11 @@ there hasn't been any input, then quit."
(save-excursion
(goto-char beg)
(<= (line-beginning-position) pt (line-end-position)))
(or (not corfu-quit-at-boundary)
(funcall completion-in-region-mode--predicate))))
(or (and corfu-separator ;; command enables separator insertion
(or (eq this-command #'corfu-insert-separator)
;; with separator, any further chars allowed
(seq-contains-p (car corfu--input) corfu-separator)))
(funcall completion-in-region-mode--predicate))))
jdtsmith marked this conversation as resolved.
Show resolved Hide resolved
(corfu--update)
t)))
(corfu-quit)))
Expand Down