Added corfu-candidate-overlay-complete-at-point function

This commit is contained in:
Adam Kruszewski 2023-07-04 10:54:43 +02:00
parent 56b5d12641
commit 6cdc33aa21
2 changed files with 111 additions and 87 deletions

View file

@ -5,7 +5,7 @@
;; Author: Adam Kruszewski <adam@kruszewski.name> ;; Author: Adam Kruszewski <adam@kruszewski.name>
;; Maintainer: Adam Kruszewski <adam@kruszewski.name> ;; Maintainer: Adam Kruszewski <adam@kruszewski.name>
;; Created: 2023 ;; Created: 2023
;; Version: 1.3 ;; Version: 1.4
;; Package-Requires: ((emacs "28.1") (corfu "0.36")) ;; Package-Requires: ((emacs "28.1") (corfu "0.36"))
;; Homepage: https://code.bsdgeek.org/adam/corfu-candidate-overlay/ ;; Homepage: https://code.bsdgeek.org/adam/corfu-candidate-overlay/
@ -232,6 +232,20 @@ Otherwise the overlay can influence movement commands (i.e. the cursor is
is-delete-command)))) is-delete-command))))
(corfu-candidate-overlay--hide))))) (corfu-candidate-overlay--hide)))))
(defun corfu-candidate-overlay-at-word-boundary-p ()
"Return non-nil when cursor is at the word boundary for completion purposes.
Or nil otherwise."
(let ((next-char (char-after)))
(or (not next-char) ;; end of file
;; one of whitespace, quoting character, punctuation,
;; closing bracket, etc is next.
;; When those characters follow next completion won't trigger
;; either-way: ' = * - + / ~ _ (have not investigated further),
;; so they are not in the list.
(memq next-char '(?\s ?\t ?\r ?\n
?\" ?\` ?\) ?\] ?\>
?\. ?\, ?\: ?\;)))))
(defun corfu-candidate-overlay--post-command () (defun corfu-candidate-overlay--post-command ()
"Post command hook to update candidate overlay. "Post command hook to update candidate overlay.
Update happens when the user types character and the cursor is at Update happens when the user types character and the cursor is at
@ -246,8 +260,8 @@ the end of word."
(corfu--match-symbol-p corfu-auto-commands this-command)) (corfu--match-symbol-p corfu-auto-commands this-command))
(is-delete-command (is-delete-command
(corfu--match-symbol-p corfu-candidate-overlay-auto-commands this-command))) (corfu--match-symbol-p corfu-candidate-overlay-auto-commands this-command)))
;; short-circuit conditions -- the earlier we return if don't need to do ;; short-circuit conditions -- the earlier we return, if don't need to do
;; anything the better. ;; anything, the better.
(if (and (if (and
;; we are not in minibuffer, as it looks awkward. ;; we are not in minibuffer, as it looks awkward.
(not (minibuffer-window-active-p (selected-window))) (not (minibuffer-window-active-p (selected-window)))
@ -259,24 +273,16 @@ the end of word."
(= corfu-candidate-overlay--last-point (point)))) (= corfu-candidate-overlay--last-point (point))))
(or ;; do not update if it is not one of the insert or delete commands. (or ;; do not update if it is not one of the insert or delete commands.
is-insert-command is-insert-command
is-delete-command)) is-delete-command)
;; now we check additional short-circuit conditions, but those operate on ;; check whether we are at word boundardy.
;; next character. (corfu-candidate-overlay-at-word-boundary-p))
(let ((next-char (char-after))) ;; ...when main compound conditions is true clause...
(when (or ;; do not update if we are not at the end of the word. (progn
(not next-char) ;; end of file
;; one of whitespace, quoting character, punctuation,
;; closing bracket, etc is next.
;; When those characters follow next completion won't trigger
;; either-way: ' = * - + / ~ _ (have not investigated further)
(memq next-char '(?\s ?\t ?\r ?\n
?\" ?\` ?\) ?\] ?\>
?\. ?\, ?\: ?\;)))
;; When the completion backend is SLOW, i.e. like every LSP client, ;; When the completion backend is SLOW, i.e. like every LSP client,
;; then the overlay will often not update and will interfere with the typing. ;; then the overlay will often not update and will interfere with the typing.
;; That's why we operate on stored prefix and candidate giving an illusion ;; That's why we operate on stored prefix and candidate giving an illusion
;; of updating the overlay -- but using the previous auto suggestion candidate. ;; of updating the overlay -- but using the previous auto suggestion candidate.
(when corfu-candidate-overlay--overlay ;; need overlay active (when corfu-candidate-overlay--overlay
(let* ((candidate (let* ((candidate
(corfu-candidate-overlay--get-overlay-property 'corfu-candidate)) (corfu-candidate-overlay--get-overlay-property 'corfu-candidate))
(prefix (prefix
@ -323,10 +329,22 @@ the end of word."
;; the corfu-candidate-overlay--show CAN be interrupted, that's why ;; the corfu-candidate-overlay--show CAN be interrupted, that's why
;; we did the shuffling above. ;; we did the shuffling above.
(setq corfu-candidate-overlay--last-point (point)) (setq corfu-candidate-overlay--last-point (point))
(corfu-candidate-overlay--show))) (corfu-candidate-overlay--show))
;; or hide the overlay if the conditions to show the overlay where not met. ;; ...when main compound conditions is false clause...
;; so hide the overlay if the conditions to show the overlay where not met.
(corfu-candidate-overlay--hide))))) (corfu-candidate-overlay--hide)))))
;;;###autoload
(defun corfu-candidate-overlay-complete-at-point ()
"Insert the first completion candidate shown in the overlay."
(interactive)
(when
(and corfu-candidate-overlay--overlay
(overlayp corfu-candidate-overlay--overlay)
(corfu-candidate-overlay-at-word-boundary-p))
(insert (corfu-candidate-overlay--get-overlay-property 'corfu-candidate))))
;;;###autoload ;;;###autoload
(define-minor-mode corfu-candidate-overlay-mode (define-minor-mode corfu-candidate-overlay-mode
"Show first candidate in an overlay while typing." "Show first candidate in an overlay while typing."

View file

@ -12,6 +12,8 @@ Overlay showing auto-completion candidate when there is only one available (so i
[[./readme-images/corfu-candidate-overlay-one.png]] [[./readme-images/corfu-candidate-overlay-one.png]]
It show the first auto-suggestion from [[https://github.com/minad/corfu][corfu]] and when there is only one it will show it underlined (face attributes can be configured). In case of many suggestions available, invoking =completion-at-point= will open the corfu popup menu to choose from, in case of single completion available (i.e. underlined) it will get auto-completed seeing the menu when invoked =completion-at-point=. It show the first auto-suggestion from [[https://github.com/minad/corfu][corfu]] and when there is only one it will show it underlined (face attributes can be configured). In case of many suggestions available, invoking =completion-at-point= will open the corfu popup menu to choose from, in case of single completion available (i.e. underlined) it will get auto-completed seeing the menu when invoked =completion-at-point=.
Package exposes also one interactive function =corfu-candidate-overlay-complete-at-point= which you can bind to a key combination. Invoking the function will complete the exact candidate overlay is currently showing[fn:4] (i.e. it will not show corfu's popup even if there are more candidates present, just complete what you see).
** Motivation ** Motivation
Similarly to Michell Hashimoto[fn:1] of HashiCorp fame, I like my editor to do less than more. I'm not as ascetic though ;-) From time to time I do use the auto-suggestion menu of [[https://github.com/minad/corfu][corfu]], especially when I forget the exact wording of a function. I do however trigger the auto-suggestion popup manually. Similarly to Michell Hashimoto[fn:1] of HashiCorp fame, I like my editor to do less than more. I'm not as ascetic though ;-) From time to time I do use the auto-suggestion menu of [[https://github.com/minad/corfu][corfu]], especially when I forget the exact wording of a function. I do however trigger the auto-suggestion popup manually.
@ -40,8 +42,11 @@ When using slow or cpu-heavy corfu backends (e.g. [[https://github.com/minad/cap
;; enable corfu-candidate-overlay mode globally ;; enable corfu-candidate-overlay mode globally
;; this relies on having corfu-auto set to nil ;; this relies on having corfu-auto set to nil
(corfu-candidate-overlay-mode +1) (corfu-candidate-overlay-mode +1)
;; bind Ctr + TAB to trigger the completion popup of corfu ;; bind Ctrl + TAB to trigger the completion popup of corfu
(global-set-key (kbd "C-<tab>") 'completion-at-point)) (global-set-key (kbd "C-<tab>") 'completion-at-point)
;; bind Ctrl + Shift + Tab to trigger completion of the first candidate
;; (keybing <iso-lefttab> may not work for your keyboard model)
(global-set-key (kbd "C-<iso-lefttab>") 'corfu-candidate-overlay-complete-at-point))
#+end_src #+end_src
** Customization ** Customization
Faces available for customization: Faces available for customization:
@ -72,6 +77,7 @@ Issue reports, questions, comments and code patches are welcome -- you can send
If you haven't sent code patches via e-mail yet and would like to learn how to work with an e-mail based workflow, you can read more at [[https://git-scm.com/docs/git-format-patch][git format-patch]] man page or at [[https://git-send-email.io/][git-send-email.io]]. If you haven't sent code patches via e-mail yet and would like to learn how to work with an e-mail based workflow, you can read more at [[https://git-scm.com/docs/git-format-patch][git format-patch]] man page or at [[https://git-send-email.io/][git-send-email.io]].
* Footnotes * Footnotes
[fn:4] Thanks to [[https://github.com/terlar][Terje Larsen]] for suggestion!
[fn:1] See video cast: [fn:1] See video cast:
[[https://www.youtube.com/watch?v=rysgxl35EGc][Worst Practices in Software Development: Mitchell Hashimoto uses a simple code editor]]. [[https://www.youtube.com/watch?v=rysgxl35EGc][Worst Practices in Software Development: Mitchell Hashimoto uses a simple code editor]].