branch: externals/corfu commit cff3ca580e5fca1234699e5ab13a064af109f173 Author: Luis <l...@luishp.xyz> Commit: GitHub <nore...@github.com>
Add corfu indexed and corfu-quick. (#127) --- extensions/corfu-indexed.el | 88 +++++++++++++++++++++++++++++ extensions/corfu-quick.el | 132 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) diff --git a/extensions/corfu-indexed.el b/extensions/corfu-indexed.el new file mode 100644 index 0000000000..05e4cb8f1b --- /dev/null +++ b/extensions/corfu-indexed.el @@ -0,0 +1,88 @@ +;;; corfu.el --- Completion Overlay Region FUnction -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; Author: Luis Henriquez-Perez <l...@luishp.xyz> +;; Maintainer: Daniel Mendler <m...@daniel-mendler.de> +;; Created: 2022 +;; Version: 0.19 +;; Package-Requires: ((emacs "27.1")) +;; Homepage: https://github.com/minad/corfu + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package is a Corfu extension, which prefixes candidates with indices and +;; allows you to select with prefix arguments. This is designed to be a faster +;; alternative to selecting a candidate with `corfu-next' and `corfu-previous'. + +;;; Code: + +(require 'corfu) + +(defface corfu-indexed + '((t :height 0.75 :inherit font-lock-comment-face)) + "Face used for the candidate index prefix." + :group 'corfu-faces) + +(defvar corfu-indexed--commands + '(corfu-insert corfu-complete) + "Commands that should be indexed.") + +(defvar corfu-indexed--max 0) + +(defun corfu-indexed--format-candidate (orig cands) + "Advice for `corfu--format-candidates' that add an index to candidates. +See `corfu--format-candidates'." + (let ((updated-cands nil) + (index 0) + (index-string nil)) + (pcase-dolist (`(,prefix ,suffix ,cand) cands) + (cl-incf index) + (setq index-string (format (format "%%%ds " (if (> corfu-count 10) 2 1)) index)) + (setq prefix (concat (propertize index-string 'face 'corfu-indexed) prefix)) + (push (list prefix suffix cand) updated-cands)) + (setq corfu-indexed--max index) + (funcall orig (reverse updated-cands)))) + +(defun corfu-indexed--handle-prefix (orig &rest args) + "Handle prefix argument before calling ORIG function with ARGS." + (if (and current-prefix-arg (called-interactively-p t)) + (let ((corfu--index (+ 0 (prefix-numeric-value current-prefix-arg)))) + (if (or (< corfu--index 0) + (> corfu--index corfu-indexed--max) + (= corfu--total 0)) + (message "Out of range") + (funcall orig))) + (apply orig args))) + +;;;###autoload +(define-minor-mode corfu-indexed-mode + "Prefix candidates with indices." + :global t :group 'corfu + (cond + (corfu-indexed-mode + (advice-add #'corfu--format-candidates :around #'corfu-indexed--format-candidate) + (dolist (cmd corfu-indexed--commands) + (advice-add cmd :around #'corfu-indexed--handle-prefix))) + (t + (advice-remove #'corfu--format-candidates #'corfu-indexed--format-candidate) + (dolist (cmd corfu-indexed--commands) + (advice-remove cmd #'corfu-indexed--handle-prefix))))) + +(provide 'corfu-indexed) +;;; corfu-indexed.el ends here diff --git a/extensions/corfu-quick.el b/extensions/corfu-quick.el new file mode 100644 index 0000000000..5dbacd42f2 --- /dev/null +++ b/extensions/corfu-quick.el @@ -0,0 +1,132 @@ +;;; corfu-quick.el --- Completion Overlay Region FUnction -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; Author: Luis Henriquez-Perez <l...@luishp.xyz> +;; Maintainer: Daniel Mendler <m...@daniel-mendler.de> +;; Created: 2022 +;; Version: 0.19 +;; Package-Requires: ((emacs "27.1")) +;; Homepage: https://github.com/minad/corfu + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package is a Corfu extension, which prefixes candidates with quick +;; keys. The term "quick keys" refers to letters displayed in the `corfu' popup +;; in front each candidate. Typing these quick keys allows you to select the +;; candidate in front of them. This is designed to be a faster alternative to +;; selecting a candidate with `corfu-next' and `corfu-previous'. + +;;; Code: + +(require 'corfu) + +(defcustom corfu-quick1 "asdfgh" + "First level quick keys." + :type 'string + :group 'corfu) + +(defcustom corfu-quick2 "jkl" + "Second level quick keys." + :type 'string + :group 'corfu) + +(defface corfu-quick1 + '((((class color) (min-colors 88) (background dark)) + :background "#7042a2" :weight bold :foreground "white") + (((class color) (min-colors 88) (background light)) + :weight bold :background "#d5baff" :foreground "black") + (t :background "magenta" :foreground "white")) + "Face used for the first quick key." + :group 'corfu-faces) + +(defface corfu-quick2 + '((((class color) (min-colors 88) (background dark)) + :background "#004065" :weight bold :foreground "white") + (((class color) (min-colors 88) (background light)) + :weight bold :background "#8ae4f2" :foreground "black") + (t :background "blue" :foreground "white")) + "Face used for the second quick key." + :group 'corfu-faces) + +(defvar-local corfu-quick--alist nil + "An alist whose elements are (QUICK-KEYS . INDEX). +QUICK-KEYS is a string containing the quick keys. INDEX is the index of +the candidate that corresponds to QUICK-KEYS.") + +(defun corfu-quick--keys (index) + "Return `corfu-quick' keys for candidate at INDEX." + (let ((length1 (seq-length corfu-quick1)) + (length2 (seq-length corfu-quick2)) + (key1 "") + (key2 "")) + (if (< index length1) + (setq key1 (char-to-string (seq-elt corfu-quick1 index))) + (setq key1 (char-to-string (seq-elt corfu-quick1 (% (- index length1) length1)))) + (setq key2 (char-to-string (seq-elt corfu-quick2 (% (- index length1) length2))))) + (concat (propertize key2 'face 'corfu-quick1) + (propertize key1 'face 'corfu-quick2)))) + +(defun corfu-quick--format-candidates (orig candidates) + "Advice for `corfu--format-candidates' that adds quick keys to candidates. +See `corfu--format-candidates'." + (let ((updated-candidates nil) + (quick-keys nil) + (index 0)) + (setq corfu-quick--alist nil) + (pcase-dolist (`(,candidate ,prefix ,suffix) candidates) + (setq quick-keys (corfu-quick--keys index)) + (push (list candidate (concat quick-keys " " prefix) suffix) updated-candidates) + (push (cons (substring-no-properties quick-keys) index) corfu-quick--alist) + (cl-incf index)) + (setq updated-candidates (reverse updated-candidates)) + (funcall orig updated-candidates))) + +(defun corfu-quick--read () + "Read quick keys and return index of candidate specified by quick keys." + (cl-letf* ((old-fn (symbol-function #'corfu--format-candidates)) + (new-fn (apply-partially #'corfu-quick--format-candidates old-fn)) + ((symbol-function #'corfu--format-candidates) new-fn)) + (corfu--candidates-popup (point)) + (let* ((key (read-key)) + (quick-keys (char-to-string key))) + (when (seq-contains-p corfu-quick2 key) + (cl-letf* ((orig-fn (symbol-function #'corfu-quick--keys)) + ((symbol-function #'corfu-quick--keys) (lambda (index) (seq-rest (funcall orig-fn index))))) + (corfu--candidates-popup (point))) + (setq quick-keys (char-to-string (read-key)))) + (or (alist-get quick-keys corfu-quick--alist 0 nil #'string=) + (corfu-quick-exit))))) + +;;;###autoload +(defun corfu-quick-jump () + "Jump to candidate using quick keys." + (interactive) + (if (zerop corfu--total) + (and (message "No match") nil) + (setq corfu--index (or (corfu-quick--read) corfu--index)))) + +;;;###autoload +(defun corfu-quick-insert () + "Insert candidate using quick keys." + (interactive) + (when (corfu-quick-jump) + (corfu-insert))) + +(provide 'corfu-quick) +;;; corfu-quick.el ends here