From 864b352e7ecc649cd13ff23172c9cc8039129cc9 Mon Sep 17 00:00:00 2001 From: okamsn <28612288+okamsn@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:57:58 +0000 Subject: [PATCH] Vertico Prescient: Change how candidates are remembered. (#156) - Fix #155, remembering candidates when entering a new directory with `vertico-directory-enter`. - Remember candidates on minibuffer exit as well as candidate insertion. - Add Compat (https://github.com/emacs-compat/compat) as a dependency. It is already a dependency of Vertico. - Add stub file `stub/compat.el`. - Remove `vertico-prescient--remember`. - Add `vertico-prescient--remember-minibuffer-contents`. If completing a file name, only remember the last component of the file path, since that is the actual candidate. If the candidate is a directory, include the trailing directory separator. - Add `vertico-prescient--insertion-commands` and `vertico-prescient--remember-inserted-candidate` for remembering in `post-command-hook`. - Add `vertico-prescient--remember-exited-candidate` and `vertico-prescient--exit-commands` for remembering in `minibuffer-exit-hook`. - Hook `vertico-prescient--setup-remembrance` into `minibuffer-setup-hook`. --- CHANGELOG.md | 6 +++ stub/compat.el | 7 ++++ vertico-prescient.el | 94 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 stub/compat.el diff --git a/CHANGELOG.md b/CHANGELOG.md index 508d4c7..9883c35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,14 @@ The format is based on [Keep a Changelog]. `completion-lazy-hilit` and `completion-lazy-hilit-fn`, new in Emacs 30 and already supported by some completion UIs ([#152], [#153]). +### Bugs fixed +* Change how candidates are remembered for Vertico to work with + `vertico-directory-enter` and to remember the minibuffer contents + when exiting the minibuffer. + [#152]: https://github.com/radian-software/prescient.el/issues/152 [#153]: https://github.com/radian-software/prescient.el/pull/153 +[#156]: https://github.com/radian-software/prescient.el/pull/156 ## 6.2 (released 2023-11-23) ### Features diff --git a/stub/compat.el b/stub/compat.el new file mode 100644 index 0000000..93a50f2 --- /dev/null +++ b/stub/compat.el @@ -0,0 +1,7 @@ +;; This file contains stub definitions from compat.el which allows +;; files to be byte-compiled in the absence of compat.el. + +(unless (fboundp 'file-name-split) + (defun file-name-split (_FILENAME))) + +(provide 'compat) diff --git a/vertico-prescient.el b/vertico-prescient.el index c2d481e..24c7f09 100644 --- a/vertico-prescient.el +++ b/vertico-prescient.el @@ -6,7 +6,7 @@ ;; Homepage: https://github.com/radian-software/prescient.el ;; Keywords: extensions ;; Created: 23 Sep 2022 -;; Package-Requires: ((emacs "27.1") (prescient "6.1.0") (vertico "0.28")) +;; Package-Requires: ((emacs "27.1") (prescient "6.1.0") (vertico "0.28") (compat "29.1")) ;; SPDX-License-Identifier: MIT ;; Version: 6.2.0 @@ -24,10 +24,13 @@ ;;;; Libraries and Declarations (eval-when-compile (require 'cl-lib)) +(require 'compat) (require 'prescient) (require 'subr-x) (require 'vertico) +(defvar vertico-mode) + ;;;; Customization (defgroup vertico-prescient nil @@ -92,13 +95,6 @@ by `vertico-prescient-mode'." (defvar vertico-prescient--old-toggle-binding nil "Previous binding of `M-s' in `vertico-map'.") -(defun vertico-prescient--remember () - "Advice for remembering candidates in Vertico." - (when (>= vertico--index 0) - (prescient-remember - (substring-no-properties - (nth vertico--index vertico--candidates))))) - (defvar-local vertico-prescient--local-settings nil "Whether this buffer has local settings due to `vertico-prescient-mode'.") @@ -120,6 +116,77 @@ by `vertico-prescient-mode'." (prescient--completion-kill-local-vars) (setq vertico-prescient--local-settings nil)) +(defun vertico-prescient--remember-minibuffer-contents () + "Remember the minibuffer contents as a candidate. + +If we are not completing a file name (according to +`minibuffer-completing-file-name'), then we remember the +minibuffer contents. When completing file names, we remember the +last component of the completed file name path, including a +trailing directory separator as needed." + (let ((txt (minibuffer-contents-no-properties))) + (unless (string-empty-p txt) + (prescient-remember (if minibuffer-completing-file-name + (if (directory-name-p txt) + (thread-first txt + file-name-split + (last 2) + car + file-name-as-directory) + (thread-first txt + file-name-split + last + car)) + txt))))) + +(defvar vertico-prescient--insertion-commands + '(vertico-insert + vertico-quick-insert + vertico-directory-enter) + "Commands that trigger `prescient-remember' after running.") + +(defun vertico-prescient--remember-inserted-candidate () + "Remember the minibuffer contents as a candidate after insertion commands. + +Such commands are listed in `vertico-prescient--insertion-commands'." + (when (and (memq this-command vertico-prescient--insertion-commands) + ;; Pro-actively try to avoid running the remembrance + ;; function twice for commands that can insert and exit. + ;; This might not be needed? + (let ((buf (current-buffer))) + ;; In Emacs 28+, we would use the new second argument + ;; to `minibufferp' check if the buffer is the active + ;; minibuffer, but we want to support Emacs 27. + (and (> 0 (minibuffer-depth)) + (minibufferp buf) + (eq (active-minibuffer-window) + (get-buffer-window buf))))) + (vertico-prescient--remember-minibuffer-contents))) + +(defvar vertico-prescient--exit-commands + '(vertico-exit + vertico-quick-exit + exit-minibuffer + vertico-directory-enter) + "Commands that trigger `prescient-remember' when exiting the minibuffer.") + +(defun vertico-prescient--remember-exited-candidate () + "Remember the minibuffer contents as a candidate after exiting commands. + +Such commands are listed in `vertico-prescient--exit-commands'." + (when (memq this-command vertico-prescient--exit-commands) + (vertico-prescient--remember-minibuffer-contents))) + +(defun vertico-prescient--setup-remembrance () + "Set up the remembering functions in the relevant hooks." + (when vertico-mode + (add-hook 'post-command-hook + #'vertico-prescient--remember-inserted-candidate + nil t) + (add-hook 'minibuffer-exit-hook + #'vertico-prescient--remember-exited-candidate + nil t))) + ;;;###autoload (define-minor-mode vertico-prescient-mode "Minor mode to use prescient.el in Vertico menus. @@ -139,7 +206,8 @@ This mode will: to `completion-category-overrides' - set `completion-category-defaults' to nil -- advise `vertico-insert' to remember candidates" +- insert code for remembering candidates into `minibuffer-exit-hook' + and `post-command-hook'." :global t :group 'prescient (if vertico-prescient-mode @@ -178,7 +246,8 @@ This mode will: ;; While sorting might not be enabled in Vertico, it might ;; still be enabled in another UI, such as Company or Corfu. ;; Therefore, we still want to remember candidates. - (advice-add 'vertico-insert :before #'vertico-prescient--remember)) + (add-hook 'minibuffer-setup-hook + #'vertico-prescient--setup-remembrance)) ;; Turn off mode. @@ -193,7 +262,7 @@ This mode will: (when (equal (lookup-key vertico-map (kbd "M-s")) prescient-toggle-map) (define-key vertico-map (kbd "M-s") - vertico-prescient--old-toggle-binding)) + vertico-prescient--old-toggle-binding)) (remove-hook 'prescient--toggle-refresh-functions #'vertico-prescient--toggle-refresh) @@ -206,7 +275,8 @@ This mode will: (vertico-prescient--undo-completion-settings)))) ;; Undo remembrance settings. - (advice-remove 'vertico-insert #'vertico-prescient--remember))) + (remove-hook 'minibuffer-setup-hook + #'vertico-prescient--setup-remembrance))) (provide 'vertico-prescient) ;;; vertico-prescient.el ends here