branch: externals/vertico commit f281aac2e875d8333e29206ec25aaeea8f3d6800 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
Do not overwrite the file predicate (Fix #20) This optimizes Tramp file completion. The problem was that completion-file-name-table special-cases the predicates file-exist-p and file-directory-p. By overwriting the predicate with a lambda in Vertico, we broke this optimization. --- README.org | 68 +++++++++++++++++++++++++++----------------------------------- vertico.el | 33 +++++++++++++----------------- 2 files changed, 43 insertions(+), 58 deletions(-) diff --git a/README.org b/README.org index 49cf862..8b6b10e 100644 --- a/README.org +++ b/README.org @@ -173,59 +173,49 @@ follow a similar philosophy: - [[https://github.com/raxod502/selectrum][Selectrum]]: If you are looking for a less minimalistic and more full-featured (but also more complex) package, you may be interested in Selectrum, which has - a similar UI as Vertico. Additionally Selectrum optimizes Tramp file directory - browsing with caching, supports Avy-style quick keys, a horizontal display and - a configurable buffer display. + a similar UI as Vertico. Additionally Selectrum supports Avy-style quick keys, + a horizontal display and a configurable buffer display. - [[https://github.com/oantolin/icomplete-vertical][Icomplete-vertical]]: This package enhances the Emacs builtin Icomplete with a vertical display. In contrast to Vertico, the candidates are rotated such that the current candidate always appears at the top. From my perspective, candidate rotation feels a bit less intuitive than the UI of Vertico or Selectrum. Note that Emacs 28 offers an built-in ~icomplete-vertical-mode~. -* Caveats +* Problematic completion commands -Vertico is robust and works well for most use cases, except when navigating -remote directories via Tramp (See [[https://github.com/minad/vertico/issues/20][issue 20]]). My opinion is that the Tramp -performance problems should be resolved on a lower layer within the file -completion table. In case you are a heavy Tramp user, I recommend to give -Selectrum a try. Furthermore there are a few problematic completion commands -described in the next section. + A few completion commands make certain assumptions about the completion + styles and the completion UI. Some of the assumptions may not hold in Vertico + and as such require minor workarounds. -** Problematic completion commands +** ~org-set-tags-command~ - A few completion commands make certain assumptions about the completion - styles and the completion UI. Some of the assumptions may not hold in Vertico - and as such require minor workarounds. + ~org-set-tags-command~ implements a completion table which relies on the ~basic~ + completion style and TAB completion. This table does not work well with Vertico + and Icomplete. The issue can be mitigated by deactivating most of the Vertico UI + and relying purely on TAB completion. The UI is still enhanced by Vertico, since + Vertico shows the available tags. -*** ~org-set-tags-command~ + #+begin_src emacs-lisp + (defun disable-selection () + (when (eq minibuffer-completion-table #'org-tags-completion-function) + (setq-local vertico-map minibuffer-local-completion-map + completion-cycle-threshold nil + completion-styles '(basic)))) + (advice-add #'vertico--setup :before #'disable-selection) + #+end_src - ~org-set-tags-command~ implements a completion table which relies on the ~basic~ - completion style and TAB completion. This table does not work well with Vertico - and Icomplete. The issue can be mitigated by deactivating most of the Vertico UI - and relying purely on TAB completion. The UI is still enhanced by Vertico, since - Vertico shows the available tags. + In order to fix the issues properly, ~org-set-tags-command~ should be + implemented using ~completing-read-multiple~ as discussed on the [[https://lists.gnu.org/archive/html/emacs-orgmode/2020-07/msg00222.html][mailing list]]. - #+begin_src emacs-lisp - (defun disable-selection () - (when (eq minibuffer-completion-table #'org-tags-completion-function) - (setq-local vertico-map minibuffer-local-completion-map - completion-cycle-threshold nil - completion-styles '(basic)))) - (advice-add #'vertico--setup :before #'disable-selection) - #+end_src +** ~tmm-menubar~ - In order to fix the issues properly, ~org-set-tags-command~ should be - implemented using ~completing-read-multiple~ as discussed on the [[https://lists.gnu.org/archive/html/emacs-orgmode/2020-07/msg00222.html][mailing list]]. + The text menu bar works well with Vertico but always shows a =*Completions*= + buffer, which is unwanted if you are using the Vertico UI. This completion + buffer can be disabled as follows. -*** ~tmm-menubar~ - - The text menu bar works well with Vertico but always shows a =*Completions*= - buffer, which is unwanted if you are using the Vertico UI. This completion - buffer can be disabled as follows. - - #+begin_src emacs-lisp - (advice-add #'tmm-add-prompt :after #'minibuffer-hide-completions) - #+end_src + #+begin_src emacs-lisp + (advice-add #'tmm-add-prompt :after #'minibuffer-hide-completions) + #+end_src * Contributions diff --git a/vertico.el b/vertico.el index 6011b56..d233ab9 100644 --- a/vertico.el +++ b/vertico.el @@ -34,10 +34,8 @@ ;;; Code: -(require 'seq) -(eval-when-compile - (require 'cl-lib) - (require 'subr-x)) +(require 'cl-lib) +(eval-when-compile (require 'subr-x)) (defgroup vertico nil "VERTical Interactive COmpletion." @@ -212,15 +210,6 @@ (nconc head (delq (setcar found nil) list))) list)) -(defun vertico--file-predicate () - "Filter predicate for files." - (let ((ignore (concat "\\(?:\\`\\|/\\)\\.?\\./\\'" - (and completion-ignored-extensions - (concat "\\|" (regexp-opt completion-ignored-extensions) "\\'"))))) - (if-let (pred minibuffer-completion-predicate) - (lambda (x) (and (not (string-match-p ignore x)) (funcall pred x))) - (lambda (x) (not (string-match-p ignore x)))))) - ;; bug#47711: Deferred highlighting for `completion-all-completions' ;; XXX There is one complication: `completion--twq-all' already adds `completions-common-part'. ;; See below `vertico--candidate'. @@ -261,13 +250,19 @@ (completing-file (eq 'file (completion-metadata-get metadata 'category))) (all-hl (vertico--all-completions content minibuffer-completion-table - (if completing-file - (vertico--file-predicate) - minibuffer-completion-predicate) + minibuffer-completion-predicate pt metadata)) (all (car all-hl)) (base (or (when-let (z (last all)) (prog1 (cdr z) (setcdr z nil))) 0)) (def (or (car-safe minibuffer-default) minibuffer-default))) + ;; Filter the ignored file extensions. We cannot use modified predicate for this filtering, + ;; since this breaks the special casing in the `completion-file-name-table' for `file-exists-p' + ;; and `file-directory-p'. + (when completing-file + (let ((ignore (concat "\\(?:\\`\\|/\\)\\.?\\./\\'" + (and completion-ignored-extensions + (concat "\\|" (regexp-opt completion-ignored-extensions) "\\'"))))) + (setq all (cl-delete-if (lambda (x) (string-match-p ignore x)) all)))) (setq all (if-let (sort (completion-metadata-get metadata 'display-sort-function)) (funcall sort all) (vertico--sort (substring content 0 base) all))) @@ -305,7 +300,7 @@ vertico--keep (>= vertico--index 0) (nth vertico--index vertico--candidates)))) - (setq vertico--index (and old (seq-position candidates old))))) + (setq vertico--index (and old (cl-position old candidates :test #'equal))))) (setq vertico--input (cons content pt) vertico--base base vertico--total total @@ -345,8 +340,8 @@ (index (min (max 0 (- vertico--index (/ vertico-count 2) (if group-format -1 0))) (max 0 (- vertico--total vertico-count)))) (candidates - (thread-last (seq-subseq vertico--candidates index - (min (+ index vertico-count) vertico--total)) + (thread-last (cl-subseq vertico--candidates index + (min (+ index vertico-count) vertico--total)) (funcall vertico--highlight) (vertico--annotate metadata))) (max-width (- (window-width) 4))