summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.org60
-rw-r--r--README.org500
-rw-r--r--consult-icomplete.el55
-rw-r--r--consult-org.el26
-rw-r--r--consult-register.el14
-rw-r--r--consult-vertico.el63
-rw-r--r--consult.el1441
-rw-r--r--debian/changelog7
-rw-r--r--debian/patches/replace-external-references-when-possible.patch33
9 files changed, 1147 insertions, 1052 deletions
diff --git a/CHANGELOG.org b/CHANGELOG.org
index 9202293..368b968 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -2,13 +2,69 @@
#+author: Daniel Mendler
#+language: en
+* Version 0.35 (2023-07-02)
+
+- Bugfixes.
+- =consult--read= now accepts programmable completion tables as argument, e.g.,
+ =completion-table-dynamic= or =completion--file-name-table=. This allows you to
+ reuse existing completion tables to write completion commands enhanced with
+ Consult candidate preview.
+- Replace =consult-preview-cursor= face with =cursor-highlight-mark=.
+- Change calling convention of =consult-focus-lines= and =consult-keep-lines=.
+- The regexps in =consult-buffer-filter= are matched case sensitively now.
+ Similarly, the =INCLUDE= and =EXCLUDE= arguments of =consult--buffer-query= are also
+ case sensitive.
+- Do not preview remote files by default, see =consult-preview-excluded-files=.
+- Use =consult--maybe-recenter= instead of =recenter= in =consult-after-jump-hook=.
+- =consult-goto-line=: Support =line:column= input.
+
+* Version 0.34 (2023-04-21)
+
+- Bugfixes.
+- =consult-org-heading=: Support tag inheritance.
+- Use pure =consult--fast-abbreviate-file-name= function to abbreviate file names
+ in =consult-buffer= and =consult-recent-file=. This ensures that abbreviation does
+ not access the file system (or worse remote hosts via Tramp) and is always
+ fast. The downside is that some paths may not get abbreviated.
+- Introduce buffer sources =consult--source-project-buffer-hidden= and
+ =consult--source-project-recent-file-hidden=. Set the buffer sources of
+ =consult-project= to =consult--source-project-buffer= and
+ =consult--source-project-recent-file= to ease customization.
+- =consult-buffer=: Explicitly save =window-next-buffers= and =window-prev-buffers=.
+- When previewing files literally (=consult-preview-raw-size=), set the multi byte
+ flag of the previewed buffer, such that UTF-8 buffers are not garbled.
+- Do not create preview cursor overlay. Instead display the actual point by
+ ensuring that =cursor-in-non-selected-windows= is set.
+
+* Version 0.33 (2023-03-11)
+
+- BREAKING: The key convention has been updated. The old key convention is not
+ supported anymore. Keys must now be strings valid according to =key-valid-p=.
+ This changes affects the keys =consult-narrow-key=, =consult-widen-key=,
+ =consult-preview-key= and the =:preview-key= of sources and passed as keyword
+ argument to =consult--read=. See the example configurations in the manual.
+- BREAKING: Remove the "." argument from =consult-grep-args= and
+ =consult-ripgrep-args=, since directories or files to search are appended by the
+ command line builder. Take this change into account, when you use a customized
+ version of those variables.
+- =consult-grep=: Add support for grep and find over multiple files or directory.
+ If the prefix argument DIR is a single C-u, prompt for comma separated
+ directories or files to search recursively via =completing-read-multiple=.
+- =consult-buffer= and =consult-isearch-history=: Align annotations dynamically
+ depending on candidate width, instead of computing the alignment beforehand.
+- Add the full path as =help-echo= property to abbreviated directory paths and
+ project names. Enable =tooltip-mode= and hover with the mouse over the
+ abbreviated directory path to see the full path.
+- =consult-grep/find/etc=: Print first line of stderr output if command failed.
+
* Version 0.32 (2023-02-06)
- Bugfixes
-- Update the key convention. Keys must now be strings valid according to
+- Deprecate the old key convention. Keys must now be strings valid according to
=key-valid-p=. This changes affects the keys =consult-narrow-key=,
=consult-widen-key=, =consult-preview-key= and the =:preview-key= of sources and
- passed as keyword argument to =consult--read=.
+ passed as keyword argument to =consult--read=. See the example configurations in
+ the manual.
- Add =consult-info= command (#634, #727).
- =consult-buffer=: Always select the first candidate when narrowing (#714).
- =consult-locate-args=: Remove =--existing=, which is not supported by =plocate= on
diff --git a/README.org b/README.org
index d000589..c12f3b4 100644
--- a/README.org
+++ b/README.org
@@ -173,8 +173,10 @@ their descriptions.
#+findex: consult-outline
#+findex: consult-imenu
#+findex: consult-imenu-multi
-- =consult-goto-line=: Jump to line number enhanced with live preview.
- This is a drop-in replacement for =goto-line=.
+- =consult-goto-line=: Jump to line number enhanced with live preview. This is a
+ drop-in replacement for =goto-line=. Enter a line number to jump to the first
+ column of the given line. Alternatively enter =line:column= in order to jump to
+ a specific column.
- =consult-mark=: Jump to a marker in the =mark-ring=. Supports live
preview and recursive editing.
- =consult-global-mark=: Jump to a marker in the =global-mark-ring=.
@@ -239,24 +241,25 @@ their descriptions.
term. After at least =consult-async-min-input= characters, the search gets
started. Consult splits the input string into two parts, if the first
character is a punctuation character, like =#=. For example
- =#regexps#filter-string=, is split at the second =#=. The string =regexps= is
- passed to Grep. Note that Consult transforms Emacs regular expressions to
- expressions understand by the search program. Always use Emacs regular
- expressions at the prompt. If you enter multiple regular expressions
- separated by space only lines matching all regular expressions are shown. In
- order to match space literally, escape the space with a backslash. The
- =filter-string= is passed to the /fast/ Emacs filtering to further narrow down
- the list of matches. This is particularly useful if you are using an advanced
- completion style like orderless. =consult-grep= supports preview. If the
- =consult-project-function= returns non-nil, =consult-grep= searches the
- current project directory. Otherwise the =default-directory= is searched. If
- =consult-grep= is invoked with prefix argument =C-u M-s g=, you can specify the
- directory manually.
+ =#regexps#filter-string=, is split at the second =#=. The string =regexps= is passed
+ to Grep. Note that Consult transforms Emacs regular expressions to expressions
+ understand by the search program. Always use Emacs regular expressions at the
+ prompt. If you enter multiple regular expressions separated by space only
+ lines matching all regular expressions are shown. In order to match space
+ literally, escape the space with a backslash. The =filter-string= is passed to
+ the /fast/ Emacs filtering to further narrow down the list of matches. This is
+ particularly useful if you are using an advanced completion style like
+ orderless. =consult-grep= supports preview. If the =consult-project-function=
+ returns non-nil, =consult-grep= searches the current project directory.
+ Otherwise the =default-directory= is searched. If =consult-grep= is invoked
+ with prefix argument =C-u M-s g=, you can specify one or more comma-separated files
+ and directories manually.
- =consult-find=, =consult-locate=: Find file by matching the path against a regexp.
Like for =consult-grep=, either the project root or the current directory is the
root directory for the search. The input string is treated similarly to
=consult-grep=, where the first part is passed to find, and the second part is
- used for Emacs filtering.
+ used for Emacs filtering. Prefix arguments to =consult-find= work just like those
+ for the consult grep commands.
** Compilation
:properties:
@@ -269,7 +272,7 @@ their descriptions.
#+findex: consult-xref
- =consult-compile-error=: Jump to a compilation error. Supports live preview
narrowing and recursive editing.
-- =consult-flymake=: Jump to flymake diagnostic. Supports live preview and
+- =consult-flymake=: Jump to Flymake diagnostic. Supports live preview and
recursive editing. The command supports narrowing. Press =e SPC=, =w SPC=, =n SPC=
to only show errors, warnings and notes respectively.
- =consult-xref=: Integration with xref. This function can be set as
@@ -342,21 +345,21 @@ their descriptions.
may want to create your own commands which search through a predefined set of
info pages, for example:
#+begin_src emacs-lisp
- (defun consult-info-emacs ()
- "Search through Emacs info pages."
- (interactive)
- (consult-info "emacs" "efaq" "elisp" "cl" "compat"))
-
- (defun consult-info-org ()
- "Search through the Org info page."
- (interactive)
- (consult-info "org"))
-
- (defun consult-info-completion ()
- "Search through completion info pages."
- (interactive)
- (consult-info "vertico" "consult" "marginalia" "orderless" "embark"
- "corfu" "cape" "tempel"))
+(defun consult-info-emacs ()
+ "Search through Emacs info pages."
+ (interactive)
+ (consult-info "emacs" "efaq" "elisp" "cl" "compat"))
+
+(defun consult-info-org ()
+ "Search through the Org info page."
+ (interactive)
+ (consult-info "org"))
+
+(defun consult-info-completion ()
+ "Search through completion info pages."
+ (interactive)
+ (consult-info "vertico" "consult" "marginalia" "orderless" "embark"
+ "corfu" "cape" "tempel"))
#+end_src
** Miscellaneous
@@ -376,16 +379,16 @@ their descriptions.
- =consult-completion-in-region=: In case you don't use [[https://github.com/minad/corfu][Corfu]] as your in-buffer
completion UI, this function can be set as =completion-in-region-function=. Then
your minibuffer completion UI (e.g., Vertico or Icomplete) will be used for
- =completion-at-point=. If you use Mct, you can give =mct-region-mode= a try.
+ =completion-at-point=.
#+begin_src emacs-lisp
- ;; Use `consult-completion-in-region' if Vertico is enabled.
- ;; Otherwise use the default `completion--in-region' function.
- (setq completion-in-region-function
- (lambda (&rest args)
- (apply (if vertico-mode
- #'consult-completion-in-region
- #'completion--in-region)
- args)))
+ ;; Use `consult-completion-in-region' if Vertico is enabled.
+ ;; Otherwise use the default `completion--in-region' function.
+ (setq completion-in-region-function
+ (lambda (&rest args)
+ (apply (if vertico-mode
+ #'consult-completion-in-region
+ #'completion--in-region)
+ args)))
#+end_src
Instead of =consult-completion-in-region=, you may prefer to see the
completions directly in the buffer as a small popup. In that case, I recommend
@@ -447,36 +450,46 @@ your own function or command, you will also need to add the name of
to be considered.
#+begin_src emacs-lisp
- (consult-customize
- consult-ripgrep consult-git-grep consult-grep
- consult-bookmark consult-recent-file consult-xref
- consult--source-bookmark consult--source-file-register
- consult--source-recent-file consult--source-project-recent-file
- ;; my/command-wrapping-consult ;; disable auto previews inside my command
- :preview-key '(:debounce 0.4 any) ;; Option 1: Delay preview
- ;; :preview-key "M-.") ;; Option 2: Manual preview
+(consult-customize
+ consult-ripgrep consult-git-grep consult-grep
+ consult-bookmark consult-recent-file consult-xref
+ consult--source-bookmark consult--source-file-register
+ consult--source-recent-file consult--source-project-recent-file
+ ;; my/command-wrapping-consult ;; disable auto previews inside my command
+ :preview-key '(:debounce 0.4 any) ;; Option 1: Delay preview
+ ;; :preview-key "M-.") ;; Option 2: Manual preview
#+end_src
In this case one may wonder what the difference is between using an Embark
action on the current candidate in comparison to a manually triggered preview.
The main difference is that the files opened by manual preview are closed again
-after the completion session. Furthermore during preview some functionality is
-disabled to improve the performance, see for example the customization variables
-=consult-preview-allowed-hooks= and =consult-preview-variables=. Files larger than
-=consult-preview-raw-size= are previewed literally without syntax highlighting and
-without changing the major mode. Delaying the preview is also useful for
-=consult-theme=, since the theme preview is slow. The delay results in a smoother
-UI experience.
+after the completion session. During preview some functionality is disabled to
+improve the performance, see for example the customization variables
+=consult-preview-variables= and =consult-preview-allowed-hooks=. Only the hooks
+listed in =consult-preview-allowed-hooks= are executed when a file is opened
+(=find-file-hook=). In order to enable additional font locking during preview, add
+the corresponding hooks to the allow list. The following code demonstrates this
+for [[https://github.com/minad/org-modern][org-modern]] and [[https://github.com/tarsius/hl-todo][hl-todo]].
#+begin_src emacs-lisp
- ;; Preview on any key press, but delay 0.5s
- (consult-customize consult-theme :preview-key '(:debounce 0.5 any))
- ;; Preview immediately on M-., on up/down after 0.5s, on any other key after 1s
- (consult-customize consult-theme
- :preview-key
- '("M-."
- :debounce 0.5 "<up>" "<down>"
- :debounce 1 any))
+(add-to-list 'consult-preview-allowed-hooks 'global-org-modern-mode-check-buffers)
+(add-to-list 'consult-preview-allowed-hooks 'global-hl-todo-mode-check-buffers)
+#+end_src
+
+Files larger than =consult-preview-raw-size= are previewed literally without
+syntax highlighting and without changing the major mode. Delaying the preview is
+also useful for =consult-theme=, since the theme preview is slow. The delay
+results in a smoother UI experience.
+
+#+begin_src emacs-lisp
+;; Preview on any key press, but delay 0.5s
+(consult-customize consult-theme :preview-key '(:debounce 0.5 any))
+;; Preview immediately on M-., on up/down after 0.5s, on any other key after 1s
+(consult-customize consult-theme
+ :preview-key
+ '("M-."
+ :debounce 0.5 "<up>" "<down>"
+ :debounce 1 any))
#+end_src
** Narrowing and grouping
@@ -627,10 +640,10 @@ files or bookmarks can result in expensive operations. However it is possible to
configure a manual preview as follows.
#+begin_src emacs-lisp
- (consult-customize
- consult--source-bookmark consult--source-file-register
- consult--source-recent-file consult--source-project-recent-file
- :preview-key "M-.")
+(consult-customize
+ consult--source-bookmark consult--source-file-register
+ consult--source-recent-file consult--source-project-recent-file
+ :preview-key "M-.")
#+end_src
Sources can be added directly to the =consult-buffer-source= list for convenience.
@@ -666,28 +679,28 @@ Another useful source lists all Org buffers and lets you create new ones. One
can create similar sources for other major modes, e.g., for Eshell.
#+begin_src emacs-lisp
- (defvar org-source
- (list :name "Org Buffer"
- :category 'buffer
- :narrow ?o
- :face 'consult-buffer
- :history 'buffer-name-history
- :state #'consult--buffer-state
- :new
- (lambda (name)
- (with-current-buffer (get-buffer-create name)
- (insert "#+title: " name "\n\n")
- (org-mode)
- (consult--buffer-action (current-buffer))))
- :items
- (lambda ()
- (mapcar #'buffer-name
- (seq-filter
- (lambda (x)
- (eq (buffer-local-value 'major-mode x) 'org-mode))
- (buffer-list))))))
-
- (add-to-list 'consult-buffer-sources 'org-source 'append)
+(defvar org-source
+ (list :name "Org Buffer"
+ :category 'buffer
+ :narrow ?o
+ :face 'consult-buffer
+ :history 'buffer-name-history
+ :state #'consult--buffer-state
+ :new
+ (lambda (name)
+ (with-current-buffer (get-buffer-create name)
+ (insert "#+title: " name "\n\n")
+ (org-mode)
+ (consult--buffer-action (current-buffer))))
+ :items
+ (lambda ()
+ (mapcar #'buffer-name
+ (seq-filter
+ (lambda (x)
+ (eq (buffer-local-value 'major-mode x) 'org-mode))
+ (buffer-list))))))
+
+(add-to-list 'consult-buffer-sources 'org-source 'append)
#+end_src
For more details, see the documentation of =consult-buffer= and of the
@@ -765,124 +778,124 @@ elpa-use-package~), which is a convenient tool to manage package configurations.
configuration examples.
#+begin_src emacs-lisp
- ;; Example configuration for Consult
- (use-package consult
- ;; Replace bindings. Lazily loaded due by `use-package'.
- :bind (;; C-c bindings (mode-specific-map)
- ("C-c M-x" . consult-mode-command)
- ("C-c h" . consult-history)
- ("C-c k" . consult-kmacro)
- ("C-c m" . consult-man)
- ("C-c i" . consult-info)
- ([remap Info-search] . consult-info)
- ;; C-x bindings (ctl-x-map)
- ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
- ("C-x b" . consult-buffer) ;; orig. switch-to-buffer
- ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
- ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
- ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
- ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
- ;; Custom M-# bindings for fast register access
- ("M-#" . consult-register-load)
- ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
- ("C-M-#" . consult-register)
- ;; Other custom bindings
- ("M-y" . consult-yank-pop) ;; orig. yank-pop
- ;; M-g bindings (goto-map)
- ("M-g e" . consult-compile-error)
- ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
- ("M-g g" . consult-goto-line) ;; orig. goto-line
- ("M-g M-g" . consult-goto-line) ;; orig. goto-line
- ("M-g o" . consult-outline) ;; Alternative: consult-org-heading
- ("M-g m" . consult-mark)
- ("M-g k" . consult-global-mark)
- ("M-g i" . consult-imenu)
- ("M-g I" . consult-imenu-multi)
- ;; M-s bindings (search-map)
- ("M-s d" . consult-find)
- ("M-s D" . consult-locate)
- ("M-s g" . consult-grep)
- ("M-s G" . consult-git-grep)
- ("M-s r" . consult-ripgrep)
- ("M-s l" . consult-line)
- ("M-s L" . consult-line-multi)
- ("M-s k" . consult-keep-lines)
- ("M-s u" . consult-focus-lines)
- ;; Isearch integration
- ("M-s e" . consult-isearch-history)
- :map isearch-mode-map
- ("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
- ("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
- ("M-s l" . consult-line) ;; needed by consult-line to detect isearch
- ("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
- ;; Minibuffer history
- :map minibuffer-local-map
- ("M-s" . consult-history) ;; orig. next-matching-history-element
- ("M-r" . consult-history)) ;; orig. previous-matching-history-element
-
- ;; Enable automatic preview at point in the *Completions* buffer. This is
- ;; relevant when you use the default completion UI.
- :hook (completion-list-mode . consult-preview-at-point-mode)
-
- ;; The :init configuration is always executed (Not lazy)
- :init
-
- ;; Optionally configure the register formatting. This improves the register
- ;; preview for `consult-register', `consult-register-load',
- ;; `consult-register-store' and the Emacs built-ins.
- (setq register-preview-delay 0.5
- register-preview-function #'consult-register-format)
-
- ;; Optionally tweak the register preview window.
- ;; This adds thin lines, sorting and hides the mode line of the window.
- (advice-add #'register-preview :override #'consult-register-window)
-
- ;; Use Consult to select xref locations with preview
- (setq xref-show-xrefs-function #'consult-xref
- xref-show-definitions-function #'consult-xref)
-
- ;; Configure other variables and modes in the :config section,
- ;; after lazily loading the package.
- :config
-
- ;; Optionally configure preview. The default value
- ;; is 'any, such that any key triggers the preview.
- ;; (setq consult-preview-key 'any)
- ;; (setq consult-preview-key "M-.")
- ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
- ;; For some commands and buffer sources it is useful to configure the
- ;; :preview-key on a per-command basis using the `consult-customize' macro.
- (consult-customize
- consult-theme :preview-key '(:debounce 0.2 any)
- consult-ripgrep consult-git-grep consult-grep
- consult-bookmark consult-recent-file consult-xref
- consult--source-bookmark consult--source-file-register
- consult--source-recent-file consult--source-project-recent-file
- ;; :preview-key "M-."
- :preview-key '(:debounce 0.4 any))
-
- ;; Optionally configure the narrowing key.
- ;; Both < and C-+ work reasonably well.
- (setq consult-narrow-key "<") ;; "C-+"
-
- ;; Optionally make narrowing help available in the minibuffer.
- ;; You may want to use `embark-prefix-help-command' or which-key instead.
- ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
-
- ;; By default `consult-project-function' uses `project-root' from project.el.
- ;; Optionally configure a different project root function.
- ;;;; 1. project.el (the default)
- ;; (setq consult-project-function #'consult--default-project--function)
- ;;;; 2. vc.el (vc-root-dir)
- ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
- ;;;; 3. locate-dominating-file
- ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
- ;;;; 4. projectile.el (projectile-project-root)
- ;; (autoload 'projectile-project-root "projectile")
- ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
- ;;;; 5. No project support
- ;; (setq consult-project-function nil)
- )
+;; Example configuration for Consult
+(use-package consult
+ ;; Replace bindings. Lazily loaded due by `use-package'.
+ :bind (;; C-c bindings in `mode-specific-map'
+ ("C-c M-x" . consult-mode-command)
+ ("C-c h" . consult-history)
+ ("C-c k" . consult-kmacro)
+ ("C-c m" . consult-man)
+ ("C-c i" . consult-info)
+ ([remap Info-search] . consult-info)
+ ;; C-x bindings in `ctl-x-map'
+ ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
+ ("C-x b" . consult-buffer) ;; orig. switch-to-buffer
+ ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
+ ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
+ ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
+ ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
+ ;; Custom M-# bindings for fast register access
+ ("M-#" . consult-register-load)
+ ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
+ ("C-M-#" . consult-register)
+ ;; Other custom bindings
+ ("M-y" . consult-yank-pop) ;; orig. yank-pop
+ ;; M-g bindings in `goto-map'
+ ("M-g e" . consult-compile-error)
+ ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
+ ("M-g g" . consult-goto-line) ;; orig. goto-line
+ ("M-g M-g" . consult-goto-line) ;; orig. goto-line
+ ("M-g o" . consult-outline) ;; Alternative: consult-org-heading
+ ("M-g m" . consult-mark)
+ ("M-g k" . consult-global-mark)
+ ("M-g i" . consult-imenu)
+ ("M-g I" . consult-imenu-multi)
+ ;; M-s bindings in `search-map'
+ ("M-s d" . consult-find)
+ ("M-s D" . consult-locate)
+ ("M-s g" . consult-grep)
+ ("M-s G" . consult-git-grep)
+ ("M-s r" . consult-ripgrep)
+ ("M-s l" . consult-line)
+ ("M-s L" . consult-line-multi)
+ ("M-s k" . consult-keep-lines)
+ ("M-s u" . consult-focus-lines)
+ ;; Isearch integration
+ ("M-s e" . consult-isearch-history)
+ :map isearch-mode-map
+ ("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
+ ("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
+ ("M-s l" . consult-line) ;; needed by consult-line to detect isearch
+ ("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch
+ ;; Minibuffer history
+ :map minibuffer-local-map
+ ("M-s" . consult-history) ;; orig. next-matching-history-element
+ ("M-r" . consult-history)) ;; orig. previous-matching-history-element
+
+ ;; Enable automatic preview at point in the *Completions* buffer. This is
+ ;; relevant when you use the default completion UI.
+ :hook (completion-list-mode . consult-preview-at-point-mode)
+
+ ;; The :init configuration is always executed (Not lazy)
+ :init
+
+ ;; Optionally configure the register formatting. This improves the register
+ ;; preview for `consult-register', `consult-register-load',
+ ;; `consult-register-store' and the Emacs built-ins.
+ (setq register-preview-delay 0.5
+ register-preview-function #'consult-register-format)
+
+ ;; Optionally tweak the register preview window.
+ ;; This adds thin lines, sorting and hides the mode line of the window.
+ (advice-add #'register-preview :override #'consult-register-window)
+
+ ;; Use Consult to select xref locations with preview
+ (setq xref-show-xrefs-function #'consult-xref
+ xref-show-definitions-function #'consult-xref)
+
+ ;; Configure other variables and modes in the :config section,
+ ;; after lazily loading the package.
+ :config
+
+ ;; Optionally configure preview. The default value
+ ;; is 'any, such that any key triggers the preview.
+ ;; (setq consult-preview-key 'any)
+ ;; (setq consult-preview-key "M-.")
+ ;; (setq consult-preview-key '("S-<down>" "S-<up>"))
+ ;; For some commands and buffer sources it is useful to configure the
+ ;; :preview-key on a per-command basis using the `consult-customize' macro.
+ (consult-customize
+ consult-theme :preview-key '(:debounce 0.2 any)
+ consult-ripgrep consult-git-grep consult-grep
+ consult-bookmark consult-recent-file consult-xref
+ consult--source-bookmark consult--source-file-register
+ consult--source-recent-file consult--source-project-recent-file
+ ;; :preview-key "M-."
+ :preview-key '(:debounce 0.4 any))
+
+ ;; Optionally configure the narrowing key.
+ ;; Both < and C-+ work reasonably well.
+ (setq consult-narrow-key "<") ;; "C-+"
+
+ ;; Optionally make narrowing help available in the minibuffer.
+ ;; You may want to use `embark-prefix-help-command' or which-key instead.
+ ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help)
+
+ ;; By default `consult-project-function' uses `project-root' from project.el.
+ ;; Optionally configure a different project root function.
+ ;;;; 1. project.el (the default)
+ ;; (setq consult-project-function #'consult--default-project--function)
+ ;;;; 2. vc.el (vc-root-dir)
+ ;; (setq consult-project-function (lambda (_) (vc-root-dir)))
+ ;;;; 3. locate-dominating-file
+ ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git")))
+ ;;;; 4. projectile.el (projectile-project-root)
+ ;; (autoload 'projectile-project-root "projectile")
+ ;; (setq consult-project-function (lambda (_) (projectile-project-root)))
+ ;;;; 5. No project support
+ ;; (setq consult-project-function nil)
+)
#+end_src
** Custom variables
@@ -951,10 +964,8 @@ There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where we c
Commands and buffer sources allow flexible, individual customization by using
the =consult-customize= macro. You can override any option passed to the internal
-=consult--read= API. The [[https://github.com/minad/consult/wiki][Consult wiki]] already contains a numerous useful
-configuration examples. Note that since =consult--read= is part of the internal
-API, options could be removed, replaced or renamed in future versions of the
-package.
+=consult--read= API. Note that since =consult--read= is part of the internal API,
+options could be removed, replaced or renamed in future versions of the package.
Useful options are:
- =:prompt= set the prompt string
@@ -968,17 +979,17 @@ Useful options are:
- =:inherit-input-method= set to non-nil to inherit the input method.
#+begin_src emacs-lisp
- (consult-customize
- ;; Disable preview for `consult-theme' completely.
- consult-theme :preview-key nil
- ;; Set preview for `consult-buffer' to key `M-.'
- consult-buffer :preview-key "M-."
- ;; For `consult-line' change the prompt and specify multiple preview
- ;; keybindings. Note that you should bind <S-up> and <S-down> in the
- ;; `minibuffer-local-completion-map' or `vertico-map' to the commands which
- ;; select the previous or next candidate.
- consult-line :prompt "Search: "
- :preview-key '("S-<down>" "S-<up>"))
+(consult-customize
+ ;; Disable preview for `consult-theme' completely.
+ consult-theme :preview-key nil
+ ;; Set preview for `consult-buffer' to key `M-.'
+ consult-buffer :preview-key "M-."
+ ;; For `consult-line' change the prompt and specify multiple preview
+ ;; keybindings. Note that you should bind <S-up> and <S-down> in the
+ ;; `minibuffer-local-completion-map' or `vertico-map' to the commands which
+ ;; select the previous or next candidate.
+ consult-line :prompt "Search: "
+ :preview-key '("S-<down>" "S-<up>"))
#+end_src
The configuration values are evaluated at runtime, just before the completion
@@ -986,15 +997,15 @@ session is started. Therefore you can use for example =thing-at-point= to adjust
the initial input or the future history.
#+begin_src emacs-lisp
- (consult-customize
- consult-line
- :add-history (seq-some #'thing-at-point '(region symbol)))
+(consult-customize
+ consult-line
+ :add-history (seq-some #'thing-at-point '(region symbol)))
- (defalias 'consult-line-thing-at-point 'consult-line)
+(defalias 'consult-line-thing-at-point 'consult-line)
- (consult-customize
- consult-line-thing-at-point
- :initial (thing-at-point 'symbol))
+(consult-customize
+ consult-line-thing-at-point
+ :initial (thing-at-point 'symbol))
#+end_src
Generally it is possible to modify commands for your individual needs by the
@@ -1048,12 +1059,13 @@ wider Emacs ecosystem. You may want to install some of theses packages depending
on your preferences and requirements.
- [[https://github.com/yadex205/consult-ag][consult-ag]]: Support for the Silver Searcher (~apt install silversearcher-ag~) in the style of =consult-grep=.
-- [[https://github.com/mohkale/consult-company][consult-company]]: Completion at point using the Company (~apt install elpa-company~) backends.
- [[https://github.com/youngker/consult-codesearch.el][consult-codesearch]]: Integration with [[https://github.com/google/codesearch][Code Search]].
+- [[https://github.com/mohkale/consult-company][consult-company]]: Completion at point using the Company (~apt install elpa-company~) backends.
+- [[https://github.com/mohkale/consult-compile-multi][consult-compile-multi]]: Integration with [[https://github.com/mohkale/compile-multi][compile-multi]].
- [[https://github.com/karthink/consult-dir][consult-dir]]: Directory jumper using Consult multi sources.
- [[https://codeberg.org/ravi/consult-dash][consult-dash]]: Consult interface to [[https://github.com/dash-docs-el/dash-docs][Dash documentation]]
- [[https://github.com/mohkale/consult-eglot][consult-eglot]]: Integration with Eglot (LSP client, ~apt install elpa-eglot~).
-- [[https://github.com/minad/consult-flycheck][consult-flycheck]]: Additional Flycheck (~apt install elpa-flycheck~) integration.
+- [[https://github.com/minad/consult-flycheck][consult-flycheck]]: Additional Flycheck integration (~apt install elpa-flycheck~).
- [[https://gitlab.com/OlMon/consult-flyspell][consult-flyspell]]: Additional Flyspell integration.
- [[https://github.com/ghosty141/consult-git-log-grep][consult-git-log-grep]]: Consult interface to git log.
- [[https://github.com/Nyoho/consult-hatena-bookmark][consult-hatena-bookmark]]: Access Hatena bookmarks.
@@ -1073,14 +1085,14 @@ Not directly related to Consult, but maybe still of interest are the following
packages. These packages should work well with Consult, follow a similar spirit or
offer functionality based on ~completing-read~.
-- [[https://github.com/minad/corfu][corfu]]: Completion systems for =completion-at-point= using small popups (Alternative to Company).
+- corfu (~apt install elpa-corfu~): Completion systems for =completion-at-point= using small popups (Alternative to Company).
- [[https://github.com/minad/cape][cape]]: Completion At Point Extensions, which can be used with =consult-completion-in-region= and [[https://github.com/minad/corfu][Corfu]].
- [[https://github.com/minad/bookmark-view][bookmark-view]]: Store window configuration as bookmarks, possible integration with =consult-buffer=.
- citar (~apt install elpa-citar~): Versatile package for citation insertion and bibliography management.
- [[https://github.com/astoff/devdocs.el][devdocs]]: Emacs viewer for [[https://devdocs.io/][DevDocs]] with a convenient completion interface.
- [[https://github.com/d12frosted/flyspell-correct][flyspell-correct]]: Apply spelling corrections by selecting via =completing-read=.
- wgrep (~apt install elpa-wgrep~): Editing of grep buffers, use together with =consult-grep= via =embark-export=.
-- [[https://github.com/iyefrat/all-the-icons-completion][all-the-icons-completion]]: Icons for the completion UI.
+- [[https://github.com/iyefrat/all-the-icons-completion][all-the-icons-completion]], [[https://github.com/rainstormstudio/nerd-icons-completion][nerd-icons-completion]]: Icons for the completion UI.
* Bug reports
:properties:
@@ -1092,15 +1104,18 @@ out the following steps:
1. *Search through the issue tracker* if your issue has been reported before (and
has been resolved eventually) in the meantime.
-2. *Update all the relevant packages to the newest version*. This includes
- Consult, Compat, Vertico or other completion UIs, Marginalia, Embark and
- Orderless.
-3. Either use the default completion UI or ensure that exactly one of
+2. *Remove all packages involved in the suspected bug from your installation.*
+3. *Reinstall the newest version of all relevant packages*. Updating alone is not
+ sufficient, since package.el is known to cause miscompilation. The list of
+ packages includes Consult, Compat, Vertico or other completion UIs,
+ Marginalia, Embark and Orderless.
+4. Either use the default completion UI or ensure that exactly one of
=vertico-mode=, =mct-mode=, or =icomplete-mode= is enabled. The unsupported modes
- =selectrum-mode=, =ivy-mode=, =helm-mode= and =ido-ubiquitous-mode= must be disabled.
-4. Ensure that the =completion-styles= variable is properly configured. Try to set
+ =selectrum-mode=, =ivy-mode=, =helm-mode=, =ido-mode= and =ido-ubiquitous-mode= must be
+ disabled.
+5. Ensure that the =completion-styles= variable is properly configured. Try to set
=completion-styles= to a list including =substring= or =orderless=.
-5. Try to reproduce the issue by starting a bare bone Emacs instance with =emacs -Q=
+6. Try to reproduce the issue by starting a bare bone Emacs instance with =emacs -Q=
on the command line. Execute the following minimal code snippets in the
scratch buffer. This way we can exclude side effects due to configuration
settings. If other packages are relevant to reproduce the issue, include them
@@ -1187,6 +1202,7 @@ Code contributions:
- [[https://github.com/aagon][Aymeric Agon-Rambosson]]
- [[https://github.com/geolessel][Geoffrey Lessel]]
- [[https://github.com/piotrkwiecinski][Piotr Kwiecinski]]
+- [[https://github.com/rswgnu][Robert Weiner]]
Advice and useful discussions:
- [[https://github.com/clemera/][Clemens Radermacher]]
@@ -1210,7 +1226,7 @@ Authors of supplementary =consult-*= packages:
- [[https://codeberg.org/jao/][Jose A Ortega Ruiz]] ([[https://codeberg.org/jao/consult-notmuch][consult-notmuch]], [[https://codeberg.org/jao/consult-recoll][consult-recoll]], [[https://codeberg.org/jao/espotify][consult-spotify]])
- [[https://github.com/gagbo/][Gerry Agbobada]] ([[https://github.com/gagbo/consult-lsp][consult-lsp]])
- [[https://github.com/karthink][Karthik Chikmagalur]] ([[https://github.com/karthink/consult-dir][consult-dir]])
-- [[https://github.com/mohkale][Mohsin Kaleem]] ([[https://github.com/mohkale/consult-company][consult-company]], [[https://github.com/mohkale/consult-eglot][consult-eglot]], [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]])
+- [[https://github.com/mohkale][Mohsin Kaleem]] ([[https://github.com/mohkale/consult-company][consult-company]], [[https://github.com/mohkale/consult-compile-multi][consult-compile-multi]], [[https://github.com/mohkale/consult-eglot][consult-eglot]], [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]])
- [[https://gitlab.com/OlMon][Marco Pawłowski]] ([[https://gitlab.com/OlMon/consult-flyspell][consult-flyspell]], [[https://gitlab.com/OlMon/consult-projectile][consult-projectile]])
- [[https://github.com/Qkessler][Enrique Kessler Martínez]] ([[https://github.com/Qkessler/consult-project-extra][consult-project-extra]])
- [[https://github.com/jgru][Jan Gru]] ([[https://github.com/jgru/consult-org-roam][consult-org-roam]])
diff --git a/consult-icomplete.el b/consult-icomplete.el
deleted file mode 100644
index 4dcf2c1..0000000
--- a/consult-icomplete.el
+++ /dev/null
@@ -1,55 +0,0 @@
-;;; consult-icomplete.el --- Icomplete integration for Consult -*- lexical-binding: t -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Integration code for the Icomplete completion system. This package
-;; is automatically loaded by Consult.
-
-;;; Code:
-
-(require 'consult)
-(require 'icomplete)
-
-(defun consult-icomplete--refresh ()
- "Refresh icomplete view."
- (when icomplete-mode
- (let ((top (car completion-all-sorted-completions)))
- (completion--flush-all-sorted-completions)
- ;; force flushing, otherwise narrowing is broken!
- (setq completion-all-sorted-completions nil)
- (when top
- (let* ((completions (completion-all-sorted-completions))
- (last (last completions))
- (before)) ;; completions before top
- ;; warning: completions is an improper list
- (while (consp completions)
- (if (equal (car completions) top)
- (progn
- (setcdr last (append (nreverse before) (cdr last)))
- (setq completion-all-sorted-completions completions
- completions nil))
- (push (car completions) before)
- (setq completions (cdr completions)))))))
- (icomplete-exhibit)))
-
-(add-hook 'consult--completion-refresh-hook #'consult-icomplete--refresh)
-
-(provide 'consult-icomplete)
-;;; consult-icomplete.el ends here
diff --git a/consult-org.el b/consult-org.el
index 6512c34..ed96e39 100644
--- a/consult-org.el
+++ b/consult-org.el
@@ -59,24 +59,30 @@
If PREFIX is non-nil, prefix the candidates with the buffer name.
MATCH, SCOPE and SKIP are as in `org-map-entries'."
- (let (buffer)
+ (let (buffer (idx 0))
(apply
#'org-map-entries
(lambda ()
- ;; Reset the cache when the buffer changes, since `org-get-outline-path' uses the cache
+ ;; Reset the cache when the buffer changes, since `org-get-outline-path' uses the cache
(unless (eq buffer (buffer-name))
(setq buffer (buffer-name)
org-outline-path-cache nil))
- (pcase-let ((`(_ ,level ,todo ,prio ,_hl ,tags) (org-heading-components))
- (cand (org-format-outline-path
- (org-get-outline-path 'with-self 'use-cache)
- most-positive-fixnum)))
+ (pcase-let* ((`(_ ,level ,todo ,prio ,_hl ,tags) (org-heading-components))
+ (tags (if org-use-tag-inheritance
+ (when-let ((tags (org-get-tags)))
+ (concat ":" (string-join tags ":") ":"))
+ tags))
+ (cand (org-format-outline-path
+ (org-get-outline-path 'with-self 'use-cache)
+ most-positive-fixnum)))
(when tags
- (setq tags (concat " " tags))
- (put-text-property 1 (length tags) 'face 'org-tag tags))
+ (put-text-property 0 (length tags) 'face 'org-tag tags))
(setq cand (if prefix
- (concat buffer " " cand tags (consult--tofu-encode (point)))
- (concat cand tags (consult--tofu-encode (point)))))
+ (concat buffer " " cand (and tags " ")
+ tags (consult--tofu-encode idx))
+ (concat cand (and tags " ")
+ tags (consult--tofu-encode idx))))
+ (cl-incf idx)
(add-text-properties 0 1
`(consult--candidate ,(point-marker)
consult-org--heading (,level ,todo . ,prio))
diff --git a/consult-register.el b/consult-register.el
index 72f1867..f7e58cb 100644
--- a/consult-register.el
+++ b/consult-register.el
@@ -66,20 +66,22 @@ Each element of the list must have the form (char . name).")
(cl-defmethod consult-register--describe ((val marker))
"Describe marker register VAL."
(with-current-buffer (marker-buffer val)
- (save-restriction
- (save-excursion
+ (save-excursion
+ (save-restriction
(widen)
(goto-char val)
(let* ((line (line-number-at-pos))
- (str (propertize (consult--line-with-cursor val)
+ (str (propertize (consult--line-with-mark val)
'consult-location (cons val line))))
(list (consult--format-file-line-match (buffer-name) line str)
'multi-category `(consult-location . ,str)
'consult--type ?p))))))
-(cl-defmethod consult-register--describe ((val kmacro-register))
- "Describe kmacro register VAL."
- (list (consult-register--format-value val) 'consult--type ?k))
+(defmacro consult-register--describe-kmacro ()
+ "Generate method which describes kmacro register."
+ `(cl-defmethod consult-register--describe ((val ,(if (< emacs-major-version 30) 'kmacro-register 'kmacro)))
+ (list (consult-register--format-value val) 'consult--type ?k)))
+(consult-register--describe-kmacro)
(cl-defmethod consult-register--describe ((val (head file)))
"Describe file register VAL."
diff --git a/consult-vertico.el b/consult-vertico.el
deleted file mode 100644
index 79eb08f..0000000
--- a/consult-vertico.el
+++ /dev/null
@@ -1,63 +0,0 @@
-;;; consult-vertico.el --- Vertico integration for Consult -*- lexical-binding: t -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; 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 <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Integration code for the Vertico completion system. This package
-;; is automatically loaded by Consult.
-
-;;; Code:
-
-(require 'consult)
-
-;; NOTE: It is not guaranteed that Vertico is available during compilation!
-(defvar vertico--input)
-(declare-function vertico--exhibit "ext:vertico")
-(declare-function vertico--candidate "ext:vertico")
-(declare-function vertico--all-completions "ext:vertico")
-
-(defun consult-vertico--candidate ()
- "Return current candidate for Consult preview."
- (and vertico--input (vertico--candidate 'highlight)))
-
-(defun consult-vertico--refresh ()
- "Refresh completion UI."
- (when vertico--input
- (setq vertico--input t)
- (vertico--exhibit)))
-
-(defun consult-vertico--filter-adv (orig pattern cands category highlight)
- "Advice for ORIG `consult--completion-filter' function.
-See `consult--completion-filter' for arguments PATTERN, CANDS, CATEGORY
-and HIGHLIGHT."
- (if (and (bound-and-true-p vertico-mode) (not highlight))
- ;; Optimize `consult--completion-filter' using the deferred highlighting
- ;; from Vertico. The advice is not necessary - it is a pure optimization.
- (nconc (car (vertico--all-completions pattern cands nil (length pattern)
- `(metadata (category . ,category))))
- nil)
- (funcall orig pattern cands category highlight)))
-
-(advice-add #'consult--completion-filter :around #'consult-vertico--filter-adv)
-(add-hook 'consult--completion-candidate-hook #'consult-vertico--candidate)
-(add-hook 'consult--completion-refresh-hook #'consult-vertico--refresh)
-(define-key consult-async-map [remap vertico-insert] 'vertico-next-group)
-
-(provide 'consult-vertico)
-;;; consult-vertico.el ends here
diff --git a/consult.el b/consult.el
index 80cbb93..37cfc57 100644
--- a/consult.el
+++ b/consult.el
@@ -5,9 +5,10 @@
;; Author: Daniel Mendler and Consult contributors
;; Maintainer: Daniel Mendler <mail@daniel-mendler.de>
;; Created: 2020
-;; Version: 0.32
-;; Package-Requires: ((emacs "27.1") (compat "29.1.3.2"))
+;; Version: 0.35
+;; Package-Requires: ((emacs "27.1") (compat "29.1.4.1"))
;; Homepage: https://github.com/minad/consult
+;; Keywords: matching, files, completion
;; This file is part of GNU Emacs.
@@ -52,7 +53,6 @@
(eval-when-compile
(require 'cl-lib)
(require 'subr-x))
-(require 'seq)
(require 'compat)
(require 'bookmark)
@@ -73,29 +73,30 @@
Good choices for this key are \"<\" and \"C-+\" for example. The
key must be a string accepted by `key-valid-p'."
- :type '(choice string (const nil)))
+ :type '(choice key (const nil)))
(defcustom consult-widen-key nil
"Key used for widening during completion.
If this key is unset, defaults to twice the `consult-narrow-key'.
The key must be a string accepted by `key-valid-p'."
- :type '(choice string (const nil)))
+ :type '(choice key (const nil)))
(defcustom consult-project-function
#'consult--default-project-function
"Function which returns project root directory.
-The function takes one boolargument MAY-PROMPT. If MAY-PROMPT is non-nil,
-the function may ask the prompt the user for a project directory.
-The root directory is used by `consult-buffer' and `consult-grep'."
+The function takes one boolean argument MAY-PROMPT. If
+MAY-PROMPT is non-nil, the function may ask the prompt the user
+for a project directory. The root directory is used by
+`consult-buffer' and `consult-grep'."
:type '(choice function (const nil)))
(defcustom consult-async-refresh-delay 0.2
- "Refreshing delay of the completion ui for asynchronous commands.
+ "Refreshing delay of the completion UI for asynchronous commands.
-The completion ui is only updated every `consult-async-refresh-delay'
-seconds. This applies to asynchronous commands like for example
-`consult-grep'."
+The completion UI is only updated every
+`consult-async-refresh-delay' seconds. This applies to
+asynchronous commands like for example `consult-grep'."
:type 'float)
(defcustom consult-async-input-throttle 0.4
@@ -118,7 +119,7 @@ asynchronous commands, e.g., `consult-grep'."
"Minimum number of letters needed, before asynchronous process is called.
This applies to asynchronous commands, e.g., `consult-grep'."
- :type 'integer)
+ :type 'natnum)
(defcustom consult-async-split-style 'perl
"Async splitting style, see `consult-async-split-styles-alist'."
@@ -155,13 +156,14 @@ of the line after the prompt."
nil shows all `custom-available-themes'."
:type '(repeat (choice symbol regexp)))
-(defcustom consult-after-jump-hook '(recenter)
+(defcustom consult-after-jump-hook (list #'consult--maybe-recenter)
"Function called after jumping to a location.
-Commonly used functions for this hook are `recenter' and
-`reposition-window'. You may want to add a function which pulses the
-current line, e.g., `pulse-momentary-highlight-one-line' is supported on
-Emacs 28 and newer. The hook called during preview and for the jump
+Commonly used functions for this hook are
+`consult--maybe-recenter', `recenter' and `reposition-window'.
+You may want to add a function which pulses the current line,
+e.g., `pulse-momentary-highlight-one-line' is supported on Emacs
+28 and newer. The hook called during preview and for the jump
after selection."
:type 'hook)
@@ -196,7 +198,7 @@ See also `display-line-numbers-widen'."
This is necessary in order to prevent a large startup time
for navigation commands like `consult-line'."
- :type 'integer)
+ :type 'natnum)
(defcustom consult-buffer-filter
'("\\` "
@@ -206,8 +208,9 @@ for navigation commands like `consult-line'."
"\\`\\*tramp/.*\\*\\'")
"Filter regexps for `consult-buffer'.
-The default setting is to filter ephemeral buffer names beginning with a space
-character, the *Completions* buffer and a few log buffers."
+The default setting is to filter ephemeral buffer names beginning
+with a space character, the *Completions* buffer and a few log
+buffers. The regular expressions are matched case sensitively."
:type '(repeat regexp))
(defcustom consult-buffer-sources
@@ -217,14 +220,16 @@ character, the *Completions* buffer and a few log buffers."
consult--source-recent-file
consult--source-file-register
consult--source-bookmark
- consult--source-project-buffer
- consult--source-project-recent-file)
+ consult--source-project-buffer-hidden
+ consult--source-project-recent-file-hidden)
"Sources used by `consult-buffer'.
See also `consult-project-buffer-sources'.
See `consult--multi' for a description of the source data structure."
:type '(repeat symbol))
-(defcustom consult-project-buffer-sources nil
+(defcustom consult-project-buffer-sources
+ '(consult--source-project-buffer
+ consult--source-project-recent-file)
"Sources used by `consult-project-buffer'.
See also `consult-buffer-sources'.
See `consult--multi' for a description of the source data structure."
@@ -234,13 +239,13 @@ See `consult--multi' for a description of the source data structure."
'(;; Filter commands
"-mode\\'" "--"
;; Filter whole features
- simple mwheel time so-long recentf)
+ simple mwheel time so-long recentf tab-bar tab-line)
"Filter commands for `consult-mode-command'."
:type '(repeat (choice symbol regexp)))
(defcustom consult-grep-max-columns 300
"Maximal number of columns of grep output."
- :type 'integer)
+ :type 'natnum)
(defconst consult--grep-match-regexp
"\\`\\(?:\\./\\)?\\([^\n\0]+\\)\0\\([0-9]+\\)\\([-:\0]\\)"
@@ -248,7 +253,8 @@ See `consult--multi' for a description of the source data structure."
(defcustom consult-grep-args
'("grep" (consult--grep-exclude-args)
- "--null --line-buffered --color=never --ignore-case --line-number -I -r .")
+ "--null --line-buffered --color=never --ignore-case\
+ --with-filename --line-number -I -r")
"Command line arguments for grep, see `consult-grep'.
The dynamically computed arguments are appended.
Can be either a string, or a list of strings or expressions."
@@ -264,7 +270,7 @@ Can be either a string, or a list of strings or expressions."
(defcustom consult-ripgrep-args
"rg --null --line-buffered --color=never --max-columns=1000 --path-separator /\
- --smart-case --no-heading --line-number --search-zip ."
+ --smart-case --no-heading --with-filename --line-number --search-zip"
"Command line arguments for ripgrep, see `consult-ripgrep'.
The dynamically computed arguments are appended.
Can be either a string, or a list of strings or expressions."
@@ -301,22 +307,23 @@ individual keys must be strings accepted by `key-valid-p'."
(float :tag "Seconds" 0.1)
(const any))
(const :tag "No preview" nil)
- (string :tag "Key")
- (repeat :tag "List of keys" string)))
+ (key :tag "Key")
+ (repeat :tag "List of keys" key)))
(defcustom consult-preview-max-size 10485760
"Files larger than this byte limit are not previewed."
- :type 'integer)
+ :type 'natnum)
(defcustom consult-preview-raw-size 524288
"Files larger than this byte limit are previewed in raw form."
- :type 'integer)
+ :type 'natnum)
(defcustom consult-preview-max-count 10
"Number of files to keep open at once during preview."
- :type 'integer)
+ :type 'natnum)
-(defcustom consult-preview-excluded-files nil
+(defcustom consult-preview-excluded-files
+ '("\\`/[^/|:]+:") ;; Do not preview remote files
"List of regexps matched against names of files, which are not previewed."
:type '(repeat regexp))
@@ -374,16 +381,18 @@ Each element of the list must have the form (char name handler)."
(defface consult-highlight-match
'((t :inherit match))
"Face used to highlight matches in the completion candidates.
-Used for example in `consult-grep'.")
+Used for example by `consult-grep'.")
+
+(defface consult-highlight-mark
+ '((t :inherit consult-highlight-match))
+ "Face used for mark positions in completion candidates.
+Used for example by `consult-mark'. The face should be different
+than the `cursor' face to avoid confusion.")
(defface consult-preview-match
'((t :inherit isearch))
"Face used for match previews, e.g., in `consult-line'.")
-(defface consult-preview-cursor
- '((t :inherit cursor))
- "Face used for cursor previews and marks, e.g., in `consult-mark'.")
-
(defface consult-preview-insertion
'((t :inherit region))
"Face used for previews of text to be inserted.
@@ -452,9 +461,10 @@ Used by `consult-completion-in-region', `consult-yank' and `consult-history'.")
:foreground "#333"))
"Face used for thin line separators in `consult-register-window'.")
-;;;; History variables
+;;;; Input history variables
(defvar consult--keep-lines-history nil)
+(defvar consult--path-history nil)
(defvar consult--grep-history nil)
(defvar consult--find-history nil)
(defvar consult--man-history nil)
@@ -501,6 +511,12 @@ as the public API.")
This function can be called by custom completion systems from
outside the minibuffer.")
+(defvar consult--annotate-align-step 10
+ "Round candidate width.")
+
+(defvar consult--annotate-align-width 0
+ "Maximum candidate width used for annotation alignment.")
+
(defconst consult--tofu-char #x200000
"Special character used to encode line prefixes for disambiguation.
We use invalid characters outside the Unicode range.")
@@ -521,10 +537,10 @@ We use invalid characters outside the Unicode range.")
"Narrowing indicator overlay.")
(defvar consult--gc-threshold (* 64 1024 1024)
- "Large gc threshold for temporary increase.")
+ "Large GC threshold for temporary increase.")
(defvar consult--gc-percentage 0.5
- "Large gc percentage for temporary increase.")
+ "Large GC percentage for temporary increase.")
(defvar consult--process-chunk (* 1024 1024)
"Increase process output chunk size.")
@@ -541,6 +557,17 @@ We use invalid characters outside the Unicode range.")
;;;; Miscellaneous helper functions
+(defun consult--maybe-recenter ()
+ "Maybe recenter current window if point is outside of visible region."
+ (when (or (< (point) (window-start)) (> (point) (window-end nil t)))
+ (recenter)))
+
+(defun consult--key-parse (key)
+ "Parse KEY or signal error if invalid."
+ (unless (key-valid-p key)
+ (error "%S is not a valid key definition; see `key-valid-p'" key))
+ (key-parse key))
+
(defun consult--in-buffer (fun &optional buffer)
"Ensure that FUN is executed inside BUFFER."
(unless buffer (setq buffer (current-buffer)))
@@ -553,14 +580,20 @@ We use invalid characters outside the Unicode range.")
(if (functionp table)
(consult--in-buffer
(lambda (str pred action)
- (if (eq action 'metadata)
- (mapcar
- (lambda (x)
- (if (and (string-suffix-p (symbol-name (car-safe x)) "-function") (cdr x))
- (cons (car x) (consult--in-buffer (cdr x)))
- x))
- (funcall table str pred action))
- (funcall table str pred action)))
+ (let ((result (funcall table str pred action)))
+ (pcase action
+ ('metadata
+ (setq result
+ (mapcar
+ (lambda (x)
+ (if (and (string-suffix-p (symbol-name (car-safe x)) "-function") (cdr x))
+ (cons (car x) (consult--in-buffer (cdr x)))
+ x))
+ result)))
+ ((and 'completion--unquote (guard (functionp (cadr result))))
+ (cl-callf consult--in-buffer (cadr result) buffer)
+ (cl-callf consult--in-buffer (cadddr result) buffer)))
+ result))
buffer)
table))
@@ -570,11 +603,11 @@ We use invalid characters outside the Unicode range.")
Turn ARG into a list, and for each element either:
- split it if it a string.
- eval it if it is an expression."
- (mapcan (lambda (x)
- (if (stringp x)
- (split-string-and-unquote x)
- (ensure-list (eval x 'lexical))))
- (ensure-list arg)))
+ (seq-mapcat (lambda (x)
+ (if (stringp x)
+ (split-string-and-unquote x)
+ (ensure-list (eval x 'lexical))))
+ (ensure-list arg)))
(defun consult--command-split (str)
"Return command argument and options list given input STR."
@@ -588,9 +621,7 @@ Turn ARG into a list, and for each element either:
(defmacro consult--keep! (list form)
"Evaluate FORM for every element of LIST and keep the non-nil results."
(declare (indent 1))
- (let ((head (make-symbol "head"))
- (prev (make-symbol "prev"))
- (result (make-symbol "result")))
+ (cl-with-gensyms (head prev result)
`(let* ((,head (cons nil ,list))
(,prev ,head))
(while (cdr ,prev)
@@ -610,11 +641,11 @@ This macro is only needed to prevent memory leaking issues with
the upstream `minibuffer-with-setup-hook' macro.
FUN is the hook function and BODY opens the minibuffer."
(declare (indent 1) (debug t))
- (let ((hook (make-symbol "hook"))
+ (let ((hook (gensym "hook"))
(append))
(when (eq (car-safe fun) :append)
(setq append '(t) fun (cadr fun)))
- `(let ((,hook (make-symbol "consult--minibuffer-setup")))
+ `(let ((,hook (make-symbol "consult--minibuffer-setup-hook")))
(fset ,hook (lambda ()
(remove-hook 'minibuffer-setup-hook ,hook)
(funcall ,fun)))
@@ -659,7 +690,7 @@ HIGHLIGHT."
The line beginning/ending BEG/END is bound in BODY."
(declare (indent 2))
- (let ((max (make-symbol "max")))
+ (cl-with-gensyms (max)
`(save-excursion
(let ((,beg (point-min)) (,max (point-max)) end)
(while (< ,beg ,max)
@@ -685,7 +716,7 @@ The line beginning/ending BEG/END is bound in BODY."
width))
(defun consult--string-hash (strings)
- "Create hashtable from STRINGS."
+ "Create hash table from STRINGS."
(let ((ht (make-hash-table :test #'equal :size (length strings))))
(dolist (str strings)
(puthash str t ht))
@@ -694,8 +725,8 @@ The line beginning/ending BEG/END is bound in BODY."
(defmacro consult--local-let (binds &rest body)
"Buffer local let BINDS of dynamic variables in BODY."
(declare (indent 1))
- (let ((buffer (make-symbol "buffer"))
- (local (mapcar (lambda (x) (cons (make-symbol "local") (car x))) binds)))
+ (let ((buffer (gensym "buffer"))
+ (local (mapcar (lambda (x) (cons (gensym "local") (car x))) binds)))
`(let ((,buffer (current-buffer))
,@(mapcar (lambda (x) `(,(car x) (local-variable-p ',(cdr x)))) local))
(unwind-protect
@@ -710,44 +741,79 @@ The line beginning/ending BEG/END is bound in BODY."
(kill-local-variable ',(cdr x))))
local)))))))
-(defun consult--abbreviate-directory (dir)
- "Return abbreviated directory DIR for use in `completing-read' prompt."
+(defvar consult--fast-abbreviate-file-name nil)
+(defun consult--fast-abbreviate-file-name (name)
+ "Return abbreviate file NAME.
+This function is a pure variant of `abbreviate-file-name', which
+does not access the file system. This is important if we require
+that the operation is fast, even for remote paths or paths on
+network file systems."
+ (save-match-data
+ (let (case-fold-search) ;; Assume that file system is case sensitive.
+ (setq name (directory-abbrev-apply name))
+ (if (string-match (with-memoization consult--fast-abbreviate-file-name
+ (directory-abbrev-make-regexp (expand-file-name "~")))
+ name)
+ (concat "~" (substring name (match-beginning 1)))
+ name))))
+
+(defun consult--left-truncate-file (file)
+ "Return abbreviated file name of FILE for use in `completing-read' prompt."
(save-match-data
- (let ((adir (abbreviate-file-name dir)))
- (if (string-match "/\\([^/]+\\)/\\([^/]+\\)/\\'" adir)
- (format "…/%s/%s/" (match-string 1 adir) (match-string 2 adir))
- adir))))
+ (let ((afile (abbreviate-file-name file)))
+ (if (string-match "/\\([^/]+\\)/\\([^/]+/?\\)\\'" afile)
+ (propertize (format "…/%s/%s" (match-string 1 afile) (match-string 2 afile))
+ 'help-echo afile)
+ afile))))
(defun consult--directory-prompt (prompt dir)
- "Return prompt and directory.
-
-PROMPT is the prompt prefix. The directory
-is appended to the prompt prefix. For projects
-only the project name is shown. The `default-directory'
-is not shown. Other directories are abbreviated and
-only the last two path components are shown.
-
-If DIR is a string, it is returned.
-If DIR is a true value, the user is asked.
-Then the `consult-project-function' is tried.
-Otherwise the `default-directory' is returned."
- (let* ((dir
- (cond
- ((stringp dir) dir)
- (dir
- ;; Preserve this-command across `read-directory-name' call,
- ;; such that `consult-customize' continues to work.
- (let ((this-command this-command))
- (read-directory-name "Directory: " nil nil t)))
- (t (or (consult--project-root) default-directory))))
+ "Return prompt, paths and default directory.
+
+PROMPT is the prompt prefix. The directory is appended to the
+prompt prefix. For projects only the project name is shown. The
+`default-directory' is not shown. Other directories are
+abbreviated and only the last two path components are shown.
+
+If DIR is a string, it is returned as default directory. If DIR
+is a list of strings, the list is returned as search paths. If
+DIR is nil the `consult-project-function' is tried to retrieve
+the default directory. If no project is found the
+`default-directory' is returned as is. Otherwise the user is
+asked for the directories or files to search via
+`completing-read-multiple'."
+ (let* ((paths nil)
+ (dir
+ (pcase dir
+ ((pred stringp) dir)
+ ('nil (or (consult--project-root) default-directory))
+ (_
+ (pcase (if (stringp (car-safe dir))
+ dir
+ ;; Preserve this-command across `completing-read-multiple' call,
+ ;; such that `consult-customize' continues to work.
+ (let ((this-command this-command)
+ (def (abbreviate-file-name default-directory)))
+ (completing-read-multiple "Directories or files: "
+ #'completion-file-name-table
+ nil t def 'consult--path-history def)))
+ ((and `(,p) (guard (file-directory-p p))) p)
+ (ps (setq paths (mapcar (lambda (p)
+ (file-relative-name (expand-file-name p)))
+ ps))
+ default-directory)))))
(edir (file-name-as-directory (expand-file-name dir)))
- ;; Bind default-directory in order to find the project
- (pdir (let ((default-directory edir)) (consult--project-root))))
- (cons
+ (pdir (let ((default-directory edir))
+ ;; Bind default-directory in order to find the project
+ (consult--project-root))))
+ (list
(format "%s (%s): " prompt
- (if (equal edir pdir)
- (concat "Project " (consult--project-name pdir))
- (consult--abbreviate-directory dir)))
+ (pcase paths
+ (`(,p) (consult--left-truncate-file p))
+ (`(,p . ,_)
+ (format "%d paths, %s, …" (length paths) (consult--left-truncate-file p)))
+ ((guard (equal edir pdir)) (concat "Project " (consult--project-name pdir)))
+ (_ (consult--left-truncate-file edir))))
+ (or paths '("."))
edir)))
(defun consult--default-project-function (may-prompt)
@@ -771,31 +837,25 @@ When no project is found and MAY-PROMPT is non-nil ask the user."
(defun consult--project-name (dir)
"Return the project name for DIR."
(if (string-match "/\\([^/]+\\)/\\'" dir)
- (match-string 1 dir)
+ (propertize (match-string 1 dir) 'help-echo (abbreviate-file-name dir))
dir))
-(defun consult--format-file-line-match (file line &optional match)
+(defun consult--format-file-line-match (file line match)
"Format string FILE:LINE:MATCH with faces."
(setq line (number-to-string line)
- match (concat file ":" line (and match ":") match)
+ match (concat file ":" line ":" match)
file (length file))
(put-text-property 0 file 'face 'consult-file match)
(put-text-property (1+ file) (+ 1 file (length line)) 'face 'consult-line-number match)
match)
-(define-obsolete-function-alias
- 'consult--format-location 'consult--format-file-line-match "0.31")
-
-(defmacro consult--overlay (beg end &rest props)
+(defun consult--make-overlay (beg end &rest props)
"Make consult overlay between BEG and END with PROPS."
- (let ((ov (make-symbol "ov"))
- (puts))
+ (let ((ov (make-overlay beg end)))
(while props
- (push `(overlay-put ,ov ,(car props) ,(cadr props)) puts)
+ (overlay-put ov (car props) (cadr props))
(setq props (cddr props)))
- `(let ((,ov (make-overlay ,beg ,end)))
- ,@puts
- ,ov)))
+ ov))
(defun consult--remove-dups (list)
"Remove duplicate strings from LIST."
@@ -837,8 +897,8 @@ When no project is found and MAY-PROMPT is non-nil ask the user."
(jit-lock-fontify-now start end)))
(defmacro consult--with-increased-gc (&rest body)
- "Temporarily increase the gc limit in BODY to optimize for throughput."
- (let ((overwrite (make-symbol "overwrite")))
+ "Temporarily increase the GC limit in BODY to optimize for throughput."
+ (cl-with-gensyms (overwrite)
`(let* ((,overwrite (> consult--gc-threshold gc-cons-threshold))
(gc-cons-threshold (if ,overwrite consult--gc-threshold gc-cons-threshold))
(gc-cons-percentage (if ,overwrite consult--gc-percentage gc-cons-percentage)))
@@ -846,11 +906,12 @@ When no project is found and MAY-PROMPT is non-nil ask the user."
(defmacro consult--slow-operation (message &rest body)
"Show delayed MESSAGE if BODY takes too long.
-Also temporarily increase the gc limit via `consult--with-increased-gc'."
+Also temporarily increase the GC limit via `consult--with-increased-gc'."
(declare (indent 1))
- `(with-delayed-message (1 ,message)
- (consult--with-increased-gc
- ,@body)))
+ `(let (set-message-function) ;; bug#63253: Broken `with-delayed-message'
+ (with-delayed-message (1 ,message)
+ (consult--with-increased-gc
+ ,@body))))
(defun consult--count-lines (pos)
"Move to position POS and return number of lines."
@@ -866,14 +927,14 @@ Also temporarily increase the gc limit via `consult--with-increased-gc'."
"Get marker in BUFFER from LINE and COLUMN."
(when (buffer-live-p buffer)
(with-current-buffer buffer
- (save-restriction
- (save-excursion
+ (save-excursion
+ (save-restriction
(widen)
(goto-char (point-min))
;; Location data might be invalid by now!
(ignore-errors
(forward-line (1- line))
- (forward-char column))
+ (goto-char (min (+ (point) column) (pos-eol))))
(point-marker))))))
(defun consult--line-prefix (&optional curr-line)
@@ -923,22 +984,64 @@ region has been fontified."
str)
(buffer-substring-no-properties beg end)))
-(defun consult--region-with-cursor (beg end marker)
- "Return region string with a marking at the cursor position.
-
-BEG is the begin position.
-END is the end position.
-MARKER is the cursor position."
- (let ((str (consult--buffer-substring beg end 'fontify)))
+(defun consult--line-with-mark (marker)
+ "Current line string where the MARKER position is highlighted."
+ (let* ((beg (pos-bol))
+ (end (pos-eol))
+ (str (consult--buffer-substring beg end 'fontify)))
(if (>= marker end)
- (concat str #(" " 0 1 (face consult-preview-cursor)))
+ (concat str #(" " 0 1 (face consult-highlight-mark)))
(put-text-property (- marker beg) (- (1+ marker) beg)
- 'face 'consult-preview-cursor str)
+ 'face 'consult-highlight-mark str)
str)))
-(defun consult--line-with-cursor (marker)
- "Return current line where the cursor MARKER is highlighted."
- (consult--region-with-cursor (pos-bol) (pos-eol) marker))
+;;;; Tofu cooks
+
+(defsubst consult--tofu-p (char)
+ "Return non-nil if CHAR is a tofu."
+ (<= consult--tofu-char char (+ consult--tofu-char consult--tofu-range -1)))
+
+(defun consult--tofu-hide (str)
+ "Hide the tofus in STR."
+ (let* ((max (length str))
+ (end max))
+ (while (and (> end 0) (consult--tofu-p (aref str (1- end))))
+ (cl-decf end))
+ (when (< end max)
+ (setq str (copy-sequence str))
+ (put-text-property end max 'invisible t str))
+ str))
+
+(defsubst consult--tofu-append (cand id)
+ "Append tofu-encoded ID to CAND.
+The ID must fit within a single character. It must be smaller
+than `consult--tofu-range'."
+ (setq id (char-to-string (+ consult--tofu-char id)))
+ (add-text-properties 0 1 '(invisible t consult-strip t) id)
+ (concat cand id))
+
+(defsubst consult--tofu-get (cand)
+ "Extract tofu-encoded ID from CAND.
+See `consult--tofu-append'."
+ (- (aref cand (1- (length cand))) consult--tofu-char))
+
+;; We must disambiguate the lines by adding a prefix such that two lines with
+;; the same text can be distinguished. In order to avoid matching the line
+;; number, such that the user can search for numbers with `consult-line', we
+;; encode the line number as characters outside the Unicode range. By doing
+;; that, no accidental matching can occur.
+(defun consult--tofu-encode (n)
+ "Return tofu-encoded number N as a string.
+Large numbers are encoded as multiple tofu characters."
+ (let (str tofu)
+ (while (progn
+ (setq tofu (char-to-string
+ (+ consult--tofu-char (% n consult--tofu-range)))
+ str (if str (concat tofu str) tofu))
+ (and (>= n consult--tofu-range)
+ (setq n (/ n consult--tofu-range)))))
+ (add-text-properties 0 (length str) '(invisible t consult-strip t) str)
+ str))
;;;; Regexp utilities
@@ -1066,7 +1169,7 @@ matches case insensitively."
(defun consult--join-regexps (regexps type)
"Join REGEXPS of TYPE."
- ;; Add lookahead wrapper only if there is more than one regular expression
+ ;; Add look-ahead wrapper only if there is more than one regular expression
(cond
((and (eq type 'pcre) (cdr regexps))
(concat "^" (mapconcat (lambda (x) (format "(?=.*%s)" x))
@@ -1078,20 +1181,18 @@ matches case insensitively."
(message "Too many regexps, %S ignored. Use post-filtering!"
(string-join (seq-drop regexps 3) " "))
(setq regexps (seq-take regexps 3)))
- (consult--regexp-join-permutations regexps
- (and (memq type '(basic emacs)) "\\")))))
+ (consult--join-regexps-permutations regexps (and (eq type 'emacs) "\\")))))
-(defun consult--regexp-join-permutations (regexps esc)
+(defun consult--join-regexps-permutations (regexps esc)
"Join all permutations of REGEXPS.
ESC is the escaping string for choice and groups."
(pcase regexps
('nil "")
(`(,r) r)
- (`(,r1 ,r2) (concat r1 ".*" r2 esc "|" r2 ".*" r1))
(_ (mapconcat
(lambda (r)
- (concat r ".*" esc "("
- (consult--regexp-join-permutations (remove r regexps) esc)
+ (concat esc "(" r esc ").*" esc "("
+ (consult--join-regexps-permutations (remove r regexps) esc)
esc ")"))
regexps (concat esc "|")))))
@@ -1118,7 +1219,7 @@ ESC is the escaping string for choice and groups."
(assoc selected candidates))
(defun consult--lookup-cdr (selected candidates &rest _)
- "Lookup SELECTED in CANDIDATES alist, return cdr of element."
+ "Lookup SELECTED in CANDIDATES alist, return `cdr' of element."
(cdr (assoc selected candidates)))
(defun consult--lookup-location (selected candidates &rest _)
@@ -1160,18 +1261,21 @@ ORIG is the original function, HOOKS the arguments."
;; file-attributes may throw permission denied error
(attrs (ignore-errors (file-attributes name)))
(size (file-attribute-size attrs)))
- (if (> size consult-preview-max-size)
+ (if (>= size consult-preview-max-size)
(format "File `%s' (%s) is too large for preview"
name (file-size-human-readable size))
- (let ((buf (find-file-noselect name 'nowarn (> size consult-preview-raw-size))))
+ (let ((buf (find-file-noselect name 'nowarn (>= size consult-preview-raw-size))))
(cond
- ((and (> size consult-preview-raw-size)
- (with-current-buffer buf
- (save-excursion
- (goto-char (point-min))
- (search-forward "\0" nil 'noerror))))
- (kill-buffer buf)
- (format "Binary file `%s' not previewed literally" name))
+ ((>= size consult-preview-raw-size)
+ (with-current-buffer buf
+ (if (save-excursion
+ (goto-char (point-min))
+ (search-forward "\0" nil 'noerror))
+ (progn
+ (kill-buffer buf)
+ (format "Binary file `%s' not previewed literally" name))
+ (set-buffer-multibyte t)
+ buf)))
((ignore-errors (buffer-local-value 'so-long-detected-p buf))
(kill-buffer buf)
(format "File `%s' with long lines not previewed" name))
@@ -1204,7 +1308,7 @@ ORIG is the original function, HOOKS the arguments."
(defun consult--temporary-files ()
"Return a function to open files temporarily for preview."
(let ((dir default-directory)
- (hook (make-symbol "consult--temporary-files-window-selection-change"))
+ (hook (make-symbol "consult--temporary-files-upgrade-hook"))
(orig-buffers (buffer-list))
temporary-buffers)
(fset hook
@@ -1268,7 +1372,7 @@ ORIG is the original function, HOOKS the arguments."
;; like `pdf-view-mode' or `doc-view-mode' which rely on
;; `buffer-file-name'. Executing (set-visited-file-name nil)
;; early also prevents the major mode initialization.
- (let ((hook (make-symbol "consult--temporary-files-disassociate")))
+ (let ((hook (make-symbol "consult--temporary-files-disassociate-hook")))
(fset hook (lambda ()
(when (buffer-live-p buf)
(with-current-buffer buf
@@ -1295,7 +1399,8 @@ ORIG is the original function, HOOKS the arguments."
See `isearch-open-necessary-overlays' and `isearch-open-overlay-temporary'."
(if (and (derived-mode-p #'org-mode) (fboundp 'org-fold-show-set-visibility))
;; New Org 9.6 fold-core API
- (org-fold-show-set-visibility 'canonical)
+ (let ((inhibit-redisplay t)) ;; HACK: Prevent flicker due to premature redisplay
+ (org-fold-show-set-visibility 'canonical))
(dolist (ov (overlays-in (pos-bol) (pos-eol)))
(when-let (fun (overlay-get ov 'isearch-open-invisible))
(when (invisible-p (overlay-get ov 'invisible))
@@ -1316,21 +1421,25 @@ See `isearch-open-necessary-overlays' and `isearch-open-overlay-temporary'."
(delq nil (org-fold-core-get-regions
:with-markers t :from (point-min) :to (point-max))))
(when consult--org-fold-regions
- (let ((hook (make-symbol "consult--invisible-open-temporarily-cleanup")))
- (fset hook (apply-partially
- #'run-at-time 0 nil
- (lambda (buffer)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (pcase-dolist (`(,beg ,end ,_) consult--org-fold-regions)
- (when (markerp beg) (set-marker beg nil))
- (when (markerp end) (set-marker end nil)))
- (kill-local-variable 'consult--org-fold-regions))))
- (current-buffer)))
- (when-let (win (active-minibuffer-window))
- (with-current-buffer (window-buffer win)
- (add-hook 'minibuffer-exit-hook hook nil 'local))))))
- (org-fold-show-set-visibility 'canonical)
+ (let ((hook (make-symbol "consult--invisible-open-temporarily-cleanup-hook"))
+ (buffer (current-buffer))
+ (depth (recursion-depth)))
+ (fset hook
+ (lambda ()
+ (when (= (recursion-depth) depth)
+ (remove-hook 'minibuffer-exit-hook hook)
+ (run-at-time
+ 0 nil
+ (lambda ()
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (pcase-dolist (`(,beg ,end ,_) consult--org-fold-regions)
+ (when (markerp beg) (set-marker beg nil))
+ (when (markerp end) (set-marker end nil)))
+ (kill-local-variable 'consult--org-fold-regions))))))))
+ (add-hook 'minibuffer-exit-hook hook))))
+ (let ((inhibit-redisplay t)) ;; HACK: Prevent flicker due to premature redisplay
+ (org-fold-show-set-visibility 'canonical))
(list (lambda ()
(pcase-dolist (`(,beg ,end ,spec) consult--org-fold-regions)
(org-fold-core-region beg end t spec)))))
@@ -1348,7 +1457,7 @@ See `isearch-open-necessary-overlays' and `isearch-open-overlay-temporary'."
restore)))
(defun consult--jump-1 (pos)
- "Go to POS and recenter."
+ "Go to POS, switch buffer and widen if necessary."
(if (and (markerp pos) (not (marker-buffer pos)))
;; Only print a message, no error in order to not mess
;; with the minibuffer update hook.
@@ -1357,13 +1466,15 @@ See `isearch-open-necessary-overlays' and `isearch-open-overlay-temporary'."
(when-let (buf (and (markerp pos) (marker-buffer pos)))
(unless (and (eq (current-buffer) buf) (eq (window-buffer) buf))
(consult--buffer-action buf 'norecord)))
- ;; Widen if we cannot jump to the position (idea from flycheck-jump-to-error)
+ ;; Widen if we cannot jump to the position
(unless (= (goto-char pos) (point))
(widen)
(goto-char pos))))
(defun consult--jump (pos)
- "Push current position to mark ring, go to POS and recenter."
+ "Jump to POS.
+First push current position to mark ring, then move to new
+position and run `consult-after-jump-hook'."
(when pos
;; Extract marker from list with with overlay positions, see `consult--line-match'
(when (consp pos) (setq pos (car pos)))
@@ -1386,13 +1497,12 @@ The function can be used as the `:state' argument of `consult--read'."
(let ((saved-min (point-min-marker))
(saved-max (point-max-marker))
(saved-pos (point-marker))
- overlays invisible)
+ restore)
(set-marker-insertion-type saved-max t) ;; Grow when text is inserted
(lambda (action cand)
(when (eq action 'preview)
- (mapc #'funcall invisible)
- (mapc #'delete-overlay overlays)
- (setq invisible nil overlays nil)
+ (mapc #'funcall restore)
+ (setq restore nil)
(if (not cand)
;; If position cannot be previewed, return to saved position
(let ((saved-buffer (marker-buffer saved-pos)))
@@ -1401,29 +1511,43 @@ The function can be used as the `:state' argument of `consult--read'."
(set-buffer saved-buffer)
(narrow-to-region saved-min saved-max)
(goto-char saved-pos)))
- ;; Handle positions with overlay information
+ ;; Candidate can be previewed
(consult--jump-1 (or (car-safe cand) cand))
- (setq invisible (consult--invisible-open-temporarily)
- overlays
- (list (save-excursion
- (let ((vbeg (progn (beginning-of-visual-line) (point)))
- (vend (progn (end-of-visual-line) (point)))
- (end (pos-eol)))
- (consult--overlay vbeg (if (= vend end) (1+ end) vend)
- 'face 'consult-preview-line
- 'window (selected-window)
- 'priority 1)))
- (consult--overlay (point) (1+ (point))
- 'face 'consult-preview-cursor
- 'window (selected-window)
- 'priority 3)))
- (dolist (match (cdr-safe cand))
- (push (consult--overlay (+ (point) (car match))
- (+ (point) (cdr match))
- 'face 'consult-preview-match
- 'window (selected-window)
- 'priority 2)
- overlays))
+ (setq restore (consult--invisible-open-temporarily))
+ ;; Ensure that cursor is properly previewed (gh:minad/consult#764)
+ (unless (eq cursor-in-non-selected-windows 'box)
+ (let ((orig cursor-in-non-selected-windows)
+ (buf (current-buffer)))
+ (push
+ (if (local-variable-p 'cursor-in-non-selected-windows)
+ (lambda ()
+ (when (buffer-live-p buf)
+ (with-current-buffer buf
+ (setq-local cursor-in-non-selected-windows orig))))
+ (lambda ()
+ (when (buffer-live-p buf)
+ (with-current-buffer buf
+ (kill-local-variable 'cursor-in-non-selected-windows)))))
+ restore)
+ (setq-local cursor-in-non-selected-windows 'box)))
+ ;; Match previews
+ (let ((overlays
+ (list (save-excursion
+ (let ((vbeg (progn (beginning-of-visual-line) (point)))
+ (vend (progn (end-of-visual-line) (point)))
+ (end (pos-eol)))
+ (consult--make-overlay vbeg (if (= vend end) (1+ end) vend)
+ 'face 'consult-preview-line
+ 'window (selected-window)
+ 'priority 1))))))
+ (dolist (match (cdr-safe cand))
+ (push (consult--make-overlay (+ (point) (car match))
+ (+ (point) (cdr match))
+ 'face 'consult-preview-match
+ 'window (selected-window)
+ 'priority 2)
+ overlays))
+ (push (lambda () (mapc #'delete-overlay overlays)) restore))
(run-hooks 'consult-after-jump-hook))))))
(defun consult--jump-state ()
@@ -1443,7 +1567,7 @@ The function can be used as the `:state' argument of `consult--read'."
The cheap location markers from CANDIDATES are upgraded on window
selection change to full Emacs markers."
(let ((jump (consult--jump-state))
- (hook (make-symbol "consult--location-upgrade")))
+ (hook (make-symbol "consult--location-upgrade-hook")))
(fset hook
(lambda (_)
(unless (consult--completion-window-p)
@@ -1482,10 +1606,7 @@ The result can be passed as :state argument to `consult--read'." type)
preview-key (cddr preview-key))
(let ((key (car preview-key)))
(unless (eq key 'any)
- (if (key-valid-p key)
- (setq key (key-parse key))
- ;; TODO: Remove compatibility code, throw error.
- (message "Invalid preview key according to `key-valid-p': %S" key)))
+ (setq key (consult--key-parse key)))
(push (cons key debounce) keys))
(pop preview-key)))
keys))
@@ -1504,14 +1625,14 @@ The result can be passed as :state argument to `consult--read'." type)
(setq keys (lookup-key map keys))
(if (functionp keys) (funcall keys) any)))
-(defun consult--append-local-post-command-hook (fun)
+(defun consult--preview-append-local-pch (fun)
"Append FUN to local `post-command-hook' list."
;; Symbol indirection because of bug#46407.
- (let ((hook (make-symbol "consult--preview-post-command")))
+ (let ((hook (make-symbol "consult--preview-post-command-hook")))
(fset hook fun)
;; TODO Emacs 28 has a bug, where the hook--depth-alist is not cleaned up properly
;; Do not use the broken add-hook here.
- ;;(add-hook 'post-command-hook sym 'append 'local)
+ ;;(add-hook 'post-command-hook hook 'append 'local)
(setq-local post-command-hook
(append
(remove t post-command-hook)
@@ -1526,12 +1647,12 @@ PREVIEW-KEY, STATE, TRANSFORM and CANDIDATE."
(consult--minibuffer-with-setup-hook
(if (and state preview-key)
(lambda ()
- (let ((exit-hook (make-symbol "consult--preview-minibuffer-exit"))
+ (let ((hook (make-symbol "consult--preview-minibuffer-exit-hook"))
(depth (recursion-depth)))
- (fset exit-hook
+ (fset hook
(lambda ()
(when (= (recursion-depth) depth)
- (remove-hook 'minibuffer-exit-hook exit-hook)
+ (remove-hook 'minibuffer-exit-hook hook)
(when timer
(cancel-timer timer)
(setq timer nil))
@@ -1541,7 +1662,7 @@ PREVIEW-KEY, STATE, TRANSFORM and CANDIDATE."
(funcall state 'preview nil))
;; STEP 4: Notify the preview function of the minibuffer exit
(funcall state 'exit nil)))))
- (add-hook 'minibuffer-exit-hook exit-hook))
+ (add-hook 'minibuffer-exit-hook hook))
;; STEP 1: Setup the preview function
(with-selected-window (or (minibuffer-selected-window) (next-window))
(funcall state 'setup nil))
@@ -1593,13 +1714,13 @@ PREVIEW-KEY, STATE, TRANSFORM and CANDIDATE."
(funcall state 'preview (setq previewed transformed))))))))
;; STEP 2: Preview candidate
(funcall state 'preview (setq previewed transformed)))))))))))
- (consult--append-local-post-command-hook
+ (consult--preview-append-local-pch
(lambda ()
(setq mb-input (minibuffer-contents-no-properties)
mb-narrow consult--narrow)
(funcall consult--preview-function))))
(lambda ()
- (consult--append-local-post-command-hook
+ (consult--preview-append-local-pch
(lambda ()
(setq mb-input (minibuffer-contents-no-properties)
mb-narrow consult--narrow)))))
@@ -1682,17 +1803,9 @@ The candidate must have a `consult--prefix-group' property."
The default is twice the `consult-narrow-key'."
(cond
(consult-widen-key
- (if (key-valid-p consult-widen-key)
- (key-parse consult-widen-key)
- ;; TODO: Remove compatibility code, throw error.
- (message "Invalid `consult-widen-key' according to `key-valid-p': %S" consult-widen-key)
- consult-widen-key))
+ (consult--key-parse consult-widen-key))
(consult-narrow-key
- (let ((key consult-narrow-key))
- (if (key-valid-p key)
- (setq key (key-parse key))
- ;; TODO: Remove compatibility code, throw error.
- (message "Invalid `consult-narrow-key' according to `key-valid-p': %S" key))
+ (let ((key (consult--key-parse consult-narrow-key)))
(vconcat key key)))))
(defun consult-narrow (key)
@@ -1710,7 +1823,7 @@ This command is used internally by the narrowing system of `consult--read'."
(delete-overlay consult--narrow-overlay))
(when consult--narrow
(setq consult--narrow-overlay
- (consult--overlay
+ (consult--make-overlay
(1- (minibuffer-prompt-end)) (minibuffer-prompt-end)
'before-string
(propertize (format " [%s]" (alist-get consult--narrow
@@ -1735,7 +1848,7 @@ This command is used internally by the narrowing system of `consult--read'."
(when-let (pair (or (and (length= str 1)
(assoc (aref str 0) consult--narrow-keys))
(and (equal str "")
- (assoc 32 consult--narrow-keys))))
+ (assoc ?\s consult--narrow-keys))))
(lambda ()
(interactive)
(delete-minibuffer-contents)
@@ -1766,10 +1879,7 @@ to make it available for commands with narrowing."
(setq consult--narrow-predicate nil
consult--narrow-keys settings))
(when-let ((key consult-narrow-key))
- (if (key-valid-p key)
- (setq key (key-parse key))
- ;; TODO: Remove compatibility code, throw error.
- (message "Invalid `consult-narrow-key' according to `key-valid-p': %S" key))
+ (setq key (consult--key-parse key))
(dolist (pair consult--narrow-keys)
(define-key map (vconcat key (vector (car pair)))
(cons (cdr pair) #'consult-narrow))))
@@ -1852,6 +1962,13 @@ PLIST is the splitter configuration, including the separator."
;;;; Asynchronous filtering functions
+(defun consult--async-p (fun)
+ "Return t if FUN is an asynchronous completion function."
+ (and (functionp fun)
+ (condition-case nil
+ (progn (funcall fun "" nil 'metadata) nil)
+ (wrong-number-of-arguments t))))
+
(defmacro consult--with-async (bind &rest body)
"Setup asynchronous completion in BODY.
@@ -1867,7 +1984,7 @@ BIND is the asynchronous function binding."
;; `consult--split-setup'.
(:append
(lambda ()
- (when (functionp ,async)
+ (when (consult--async-p ,async)
(setq orig-chunk read-process-output-max
read-process-output-max new-chunk)
(funcall ,async 'setup)
@@ -1882,14 +1999,14 @@ BIND is the asynchronous function binding."
;; We use a symbol in order to avoid adding lambdas to
;; the hook variable. Symbol indirection because of
;; bug#46407.
- (sym (make-symbol "consult--async-after-change")))
+ (hook (make-symbol "consult--async-after-change-hook")))
;; Delay modification hook to ensure that minibuffer is still
;; alive after the change, such that we don't restart a new
;; asynchronous search right before exiting the minibuffer.
- (fset sym (lambda (&rest _) (run-at-time 0 nil fun)))
- (add-hook 'after-change-functions sym nil 'local)
- (funcall sym)))))
- (let ((,async (if (functionp ,async) ,async (lambda (_) ,async))))
+ (fset hook (lambda (&rest _) (run-at-time 0 nil fun)))
+ (add-hook 'after-change-functions hook nil 'local)
+ (funcall hook)))))
+ (let ((,async (if (consult--async-p ,async) ,async (lambda (_) ,async))))
(unwind-protect
,(macroexp-progn body)
(funcall ,async 'destroy)
@@ -1926,7 +2043,7 @@ string Update with the current user input string. Return nil."
(when (eq (window-buffer win) buffer)
(with-selected-window win
(run-hooks 'consult--completion-refresh-hook)
- ;; Interaction between asynchronous completion tables and
+ ;; Interaction between asynchronous completion functions and
;; preview: We have to trigger preview immediately when
;; candidates arrive (gh:minad/consult#436).
(when (and consult--preview-function candidates)
@@ -1970,18 +2087,12 @@ SPLIT is the splitting function."
(funcall split action))
(async-len (length async-str))
(input-len (length action))
- (prompt (minibuffer-prompt-end))
- (field-beg prompt)
- (field-idx 0))
+ (end (minibuffer-prompt-end)))
;; Highlight punctuation characters
- (remove-list-of-text-properties prompt (+ prompt input-len) '(face field))
+ (remove-list-of-text-properties end (+ end input-len) '(face))
(dolist (hl highlights)
- (put-text-property field-beg (+ prompt (cdr hl))
- 'field field-idx)
- (put-text-property (+ prompt (car hl)) (+ prompt (cdr hl))
- 'face 'consult-async-split)
- (setq field-beg (+ prompt (cdr hl))
- field-idx (1+ field-idx)))
+ (put-text-property (+ end (car hl)) (+ end (cdr hl))
+ 'face 'consult-async-split))
(funcall async
;; Pass through if the input is long enough!
(if (or force (>= async-len consult-async-min-input))
@@ -2069,18 +2180,20 @@ PROPS are optional properties passed to `make-process'."
(consult--async-log
"consult--async-process sentinel: event=%s lines=%d\n"
(string-trim event) count)
- (with-current-buffer (get-buffer-create consult--async-log)
- (goto-char (point-max))
- (insert ">>>>> stderr >>>>>\n")
- (insert-buffer-substring proc-buf)
- (insert "<<<<< stderr <<<<<\n"))))
+ (when (> (buffer-size proc-buf) 0)
+ (with-current-buffer (get-buffer-create consult--async-log)
+ (goto-char (point-max))
+ (insert ">>>>> stderr >>>>>\n")
+ (let ((beg (point)))
+ (insert-buffer-substring proc-buf)
+ (save-excursion
+ (goto-char beg)
+ (message #("%s" 0 2 (face error))
+ (buffer-substring-no-properties (pos-bol) (pos-eol)))))
+ (insert "<<<<< stderr <<<<<\n")))))
(args (funcall builder action)))
(unless (stringp (car args))
- (if (not (keywordp (car args)))
- (setq args (car args))
- ;; TODO remove backward compatibility code
- (message "Consult: The command builder return value changed, it should be a pair instead of a plist")
- (setq args (plist-get args :command))))
+ (setq args (car args)))
(unless (equal args last-args)
(setq last-args args)
(when proc
@@ -2112,18 +2225,13 @@ PROPS are optional properties passed to `make-process'."
(_ (funcall async action))))))
(defun consult--async-highlight (async builder)
- "Return ASYNC function which highlightes the candidates.
+ "Return a new ASYNC function with candidate highlighting.
BUILDER is the command line builder function."
(let (highlight)
(lambda (action)
(cond
((stringp action)
- (let ((tmp (funcall builder action)))
- (if (not (keywordp (car tmp)))
- (setq highlight (cdr tmp))
- ;; TODO remove backward compatibility code
- (message "Consult: The command builder return value changed, it should be a pair instead of a plist")
- (setq highlight (plist-get tmp :highlight))))
+ (setq highlight (cdr (funcall builder action)))
(funcall async action))
((and (consp action) highlight)
(dolist (str action)
@@ -2215,8 +2323,7 @@ highlighting function."
(defmacro consult--async-transform (async &rest transform)
"Use FUN to TRANSFORM candidates of ASYNC."
- (let ((async-var (make-symbol "async"))
- (action-var (make-symbol "action")))
+ (cl-with-gensyms (async-var action-var)
`(let ((,async-var ,async))
(lambda (,action-var)
(funcall ,async-var (if (consp ,action-var) (,@transform ,action-var) ,action-var))))))
@@ -2302,6 +2409,18 @@ Note that `consult-narrow-key' and `consult-widen-key' are bound dynamically."
;;;; Internal API: consult--read
+(defun consult--annotate-align (cand ann)
+ "Align annotation ANN by computing the maximum CAND width."
+ (setq consult--annotate-align-width
+ (max consult--annotate-align-width
+ (* (ceiling (consult--display-width cand)
+ consult--annotate-align-step)
+ consult--annotate-align-step)))
+ (when ann
+ (concat
+ #(" " 0 1 (display (space :align-to (+ left consult--annotate-align-width))))
+ ann)))
+
(defun consult--add-history (async items)
"Add ITEMS to the minibuffer future history.
ASYNC must be non-nil for async completion functions."
@@ -2353,21 +2472,6 @@ PREVIEW-KEY are the preview keys."
map))
old-map))))
-(defsubst consult--tofu-p (char)
- "Return non-nil if CHAR is a tofu."
- (<= consult--tofu-char char (+ consult--tofu-char consult--tofu-range -1)))
-
-(defun consult--tofu-hide (str)
- "Hide the tofus in STR."
- (let* ((max (length str))
- (end max))
- (while (and (> end 0) (consult--tofu-p (aref str (1- end))))
- (cl-decf end))
- (when (< end max)
- (setq str (copy-sequence str))
- (put-text-property end max 'invisible t str))
- str))
-
(defun consult--tofu-hide-in-minibuffer (&rest _)
"Hide the tofus in the minibuffer."
(let* ((min (minibuffer-prompt-end))
@@ -2378,37 +2482,6 @@ PREVIEW-KEY are the preview keys."
(when (< pos max)
(add-text-properties pos max '(invisible t rear-nonsticky t cursor-intangible t)))))
-(defsubst consult--tofu-append (cand id)
- "Append tofu-encoded ID to CAND.
-The ID must fit within a single character. It must be smaller
-than `consult--tofu-range'."
- (setq id (char-to-string (+ consult--tofu-char id)))
- (add-text-properties 0 1 '(invisible t consult-strip t) id)
- (concat cand id))
-
-(defsubst consult--tofu-get (cand)
- "Extract tofu-encoded ID from CAND.
-See `consult--tofu-append'."
- (- (aref cand (1- (length cand))) consult--tofu-char))
-
-;; We must disambiguate the lines by adding a prefix such that two lines with
-;; the same text can be distinguished. In order to avoid matching the line
-;; number, such that the user can search for numbers with `consult-line', we
-;; encode the line number as characters outside the unicode range. By doing
-;; that, no accidential matching can occur.
-(defun consult--tofu-encode (n)
- "Return tofu-encoded number N as a string.
-Large numbers are encoded as multiple tofu characters."
- (let (str tofu)
- (while (progn
- (setq tofu (char-to-string
- (+ consult--tofu-char (% n consult--tofu-range)))
- str (if str (concat tofu str) tofu))
- (and (>= n consult--tofu-range)
- (setq n (/ n consult--tofu-range)))))
- (add-text-properties 0 (length str) '(invisible t consult-strip t) str)
- str))
-
(defun consult--read-annotate (fun cand)
"Annotate CAND with annotation function FUN."
(pcase (funcall fun cand)
@@ -2431,23 +2504,23 @@ Large numbers are encoded as multiple tofu characters."
(propertize ann 'face 'completions-annotations))))))
cands))
-(cl-defun consult--read-1 (candidates &key
- prompt predicate require-match history default
- keymap category initial narrow add-history annotate
- state preview-key sort lookup group inherit-input-method)
+(cl-defun consult--read-1 (table &key
+ prompt predicate require-match history default
+ keymap category initial narrow add-history annotate
+ state preview-key sort lookup group inherit-input-method)
"See `consult--read' for the documentation of the arguments."
(consult--minibuffer-with-setup-hook
(:append (lambda ()
(add-hook 'after-change-functions #'consult--tofu-hide-in-minibuffer nil 'local)
- (consult--setup-keymap keymap (functionp candidates) narrow preview-key)
+ (consult--setup-keymap keymap (consult--async-p table) narrow preview-key)
(setq-local minibuffer-default-add-function
- (apply-partially #'consult--add-history (functionp candidates) add-history))))
- (consult--with-async (async candidates)
- ;; NOTE: Do not unnecessarily let-bind the lambdas to avoid overcapturing
+ (apply-partially #'consult--add-history (consult--async-p table) add-history))))
+ (consult--with-async (async table)
+ ;; NOTE: Do not unnecessarily let-bind the lambdas to avoid over-capturing
;; in the interpreter. This will make closures and the lambda string
;; representation larger, which makes debugging much worse. Fortunately
- ;; the overcapturing problem does not affect the bytecode interpreter
- ;; which does a proper scope analyis.
+ ;; the over-capturing problem does not affect the bytecode interpreter
+ ;; which does a proper scope analysis.
(let* ((metadata `(metadata
,@(when category `((category . ,category)))
,@(when group `((group-function . ,group)))
@@ -2458,6 +2531,7 @@ Large numbers are encoded as multiple tofu characters."
. ,(apply-partially #'consult--read-annotate annotate))))
,@(unless sort '((cycle-sort-function . identity)
(display-sort-function . identity)))))
+ (consult--annotate-align-width 0)
(result
(consult--with-preview
preview-key state
@@ -2467,9 +2541,13 @@ Large numbers are encoded as multiple tofu characters."
'consult--completion-candidate-hook)
(completing-read prompt
(lambda (str pred action)
- (if (eq action 'metadata)
- metadata
- (complete-with-action action (funcall async nil) str pred)))
+ (let ((result (complete-with-action action (funcall async nil) str pred)))
+ (if (eq action 'metadata)
+ (if (and (eq (car result) 'metadata) (cdr result))
+ ;; Merge metadata
+ `(metadata ,@(cdr metadata) ,@(cdr result))
+ metadata)
+ result)))
predicate require-match initial
(if (symbolp history) history (cadr history))
default
@@ -2481,11 +2559,11 @@ Large numbers are encoded as multiple tofu characters."
((pred symbolp)))
(car result)))))
-(cl-defun consult--read (candidates &rest options &key
- prompt predicate require-match history default
- keymap category initial narrow add-history annotate
- state preview-key sort lookup group inherit-input-method)
- "Enhanced completing read function to select from CANDIDATES.
+(cl-defun consult--read (table &rest options &key
+ prompt predicate require-match history default
+ keymap category initial narrow add-history annotate
+ state preview-key sort lookup group inherit-input-method)
+ "Enhanced completing read function to select from TABLE.
The function is a thin wrapper around `completing-read'. Keyword
arguments are used instead of positional arguments for code
@@ -2522,17 +2600,17 @@ KEYMAP is a command-specific keymap.
INHERIT-INPUT-METHOD, if non-nil the minibuffer inherits the
input method."
;; supported types
- (cl-assert (or (functionp candidates) ;; async table
- (obarrayp candidates) ;; obarray
- (hash-table-p candidates) ;; hash table
- (not candidates) ;; empty list
- (stringp (car candidates)) ;; string list
- (and (consp (car candidates)) (stringp (caar candidates))) ;; string alist
- (and (consp (car candidates)) (symbolp (caar candidates))))) ;; symbol alist
+ (cl-assert (or (functionp table) ;; dynamic table or asynchronous function
+ (obarrayp table) ;; obarray
+ (hash-table-p table) ;; hash table
+ (not table) ;; empty list
+ (stringp (car table)) ;; string list
+ (and (consp (car table)) (stringp (caar table))) ;; string alist
+ (and (consp (car table)) (symbolp (caar table))))) ;; symbol alist
(ignore prompt predicate require-match history default
keymap category initial narrow add-history annotate
state preview-key sort lookup group inherit-input-method)
- (apply #'consult--read-1 candidates
+ (apply #'consult--read-1 table
(append
(consult--customize-get)
options
@@ -2541,6 +2619,47 @@ input method."
:sort t
:lookup (lambda (selected &rest _) selected)))))
+;;;; Internal API: consult--prompt
+
+(cl-defun consult--prompt-1 (&key prompt history add-history initial default
+ keymap state preview-key transform inherit-input-method)
+ "See `consult--prompt' for documentation."
+ (consult--minibuffer-with-setup-hook
+ (:append (lambda ()
+ (consult--setup-keymap keymap nil nil preview-key)
+ (setq-local minibuffer-default-add-function
+ (apply-partially #'consult--add-history nil add-history))))
+ (car (consult--with-preview
+ preview-key state
+ (lambda (_narrow inp _cand) (funcall transform inp))
+ (lambda () "")
+ (read-from-minibuffer prompt initial nil nil history default inherit-input-method)))))
+
+(cl-defun consult--prompt (&rest options &key prompt history add-history initial default
+ keymap state preview-key transform inherit-input-method)
+ "Read from minibuffer.
+
+Keyword OPTIONS:
+
+PROMPT is the string to prompt with.
+TRANSFORM is a function which is applied to the current input string.
+HISTORY is the symbol of the history variable.
+INITIAL is initial input.
+DEFAULT is the default selected value.
+ADD-HISTORY is a list of items to add to the history.
+STATE is the state function, see `consult--with-preview'.
+PREVIEW-KEY are the preview keys (nil, `any', a single key or a list of keys).
+KEYMAP is a command-specific keymap."
+ (ignore prompt history add-history initial default
+ keymap state preview-key transform inherit-input-method)
+ (apply #'consult--prompt-1
+ (append
+ (consult--customize-get)
+ options
+ (list :prompt "Input: "
+ :preview-key consult-preview-key
+ :transform #'identity))))
+
;;;; Internal API: consult--multi
(defsubst consult--multi-source (sources cand)
@@ -2567,14 +2686,14 @@ input method."
(delq nil)
(delete-dups)))
-(defun consult--multi-annotate (sources align cand)
- "Annotate candidate CAND with `consult--multi' type, given SOURCES and ALIGN."
- (let* ((src (consult--multi-source sources cand))
- (annotate (plist-get src :annotate))
- (ann (if annotate
- (funcall annotate (cdr (get-text-property 0 'multi-category cand)))
- (plist-get src :name))))
- (and ann (concat align ann))))
+(defun consult--multi-annotate (sources cand)
+ "Annotate candidate CAND from multi SOURCES."
+ (consult--annotate-align
+ cand
+ (let ((src (consult--multi-source sources cand)))
+ (if-let ((fun (plist-get src :annotate)))
+ (funcall fun (cdr (get-text-property 0 'multi-category cand)))
+ (plist-get src :name)))))
(defun consult--multi-group (sources cand transform)
"Return title of candidate CAND or TRANSFORM the candidate given SOURCES."
@@ -2624,25 +2743,23 @@ input method."
(defun consult--multi-candidates (sources)
"Return `consult--multi' candidates from SOURCES."
- (let ((idx 0) (max-width 0) (candidates))
+ (let ((idx 0) candidates)
(seq-doseq (src sources)
(let* ((face (and (plist-member src :face) `(face ,(plist-get src :face))))
(cat (plist-get src :category))
(items (plist-get src :items))
(items (if (functionp items) (funcall items) items)))
(dolist (item items)
- (let ((cand (consult--tofu-append item idx))
- (width (consult--display-width item)))
+ (let ((cand (consult--tofu-append item idx)))
;; Preserve existing `multi-category' datum of the candidate.
(if (get-text-property 0 'multi-category cand)
(when face (add-text-properties 0 (length item) face cand))
;; Attach `multi-category' datum and face.
(add-text-properties 0 (length item)
`(multi-category (,cat . ,item) ,@face) cand))
- (when (> width max-width) (setq max-width width))
(push cand candidates))))
(cl-incf idx))
- (cons (+ 3 max-width) (nreverse candidates))))
+ (nreverse candidates)))
(defun consult--multi-enabled-sources (sources)
"Return vector of enabled SOURCES."
@@ -2709,7 +2826,7 @@ Required source fields:
* :category - Completion category symbol.
* :items - List of strings to select from or function returning
list of strings. Note that the strings can use text properties
- to carry mtadata, which is then available to the :annotate,
+ to carry metadata, which is then available to the :annotate,
:action and :state functions.
Optional source fields:
@@ -2733,18 +2850,15 @@ Optional source fields:
(let* ((sources (consult--multi-enabled-sources sources))
(candidates (consult--with-increased-gc
(consult--multi-candidates sources)))
- (align (propertize
- " " 'display
- `(space :align-to (+ left ,(car candidates)))))
(selected
(apply #'consult--read
- (cdr candidates)
+ candidates
(append
options
(list
:category 'multi-category
:predicate (apply-partially #'consult--multi-predicate sources)
- :annotate (apply-partially #'consult--multi-annotate sources align)
+ :annotate (apply-partially #'consult--multi-annotate sources)
:group (apply-partially #'consult--multi-group sources)
:lookup (apply-partially #'consult--multi-lookup sources)
:preview-key (consult--multi-preview-key sources)
@@ -2761,47 +2875,6 @@ Optional source fields:
(setq selected `(,(car selected) :match t ,@(cdr selected))))
selected))
-;;;; Internal API: consult--prompt
-
-(cl-defun consult--prompt-1 (&key prompt history add-history initial default
- keymap state preview-key transform inherit-input-method)
- "See `consult--prompt' for documentation."
- (consult--minibuffer-with-setup-hook
- (:append (lambda ()
- (consult--setup-keymap keymap nil nil preview-key)
- (setq-local minibuffer-default-add-function
- (apply-partially #'consult--add-history nil add-history))))
- (car (consult--with-preview
- preview-key state
- (lambda (_narrow inp _cand) (funcall transform inp))
- (lambda () "")
- (read-from-minibuffer prompt initial nil nil history default inherit-input-method)))))
-
-(cl-defun consult--prompt (&rest options &key prompt history add-history initial default
- keymap state preview-key transform inherit-input-method)
- "Read from minibuffer.
-
-Keyword OPTIONS:
-
-PROMPT is the string to prompt with.
-TRANSFORM is a function which is applied to the current input string.
-HISTORY is the symbol of the history variable.
-INITIAL is initial input.
-DEFAULT is the default selected value.
-ADD-HISTORY is a list of items to add to the history.
-STATE is the state function, see `consult--with-preview'.
-PREVIEW-KEY are the preview keys (nil, `any', a single key or a list of keys).
-KEYMAP is a command-specific keymap."
- (ignore prompt history add-history initial default
- keymap state preview-key transform inherit-input-method)
- (apply #'consult--prompt-1
- (append
- (consult--customize-get)
- options
- (list :prompt "Input: "
- :preview-key consult-preview-key
- :transform #'identity))))
-
;;;; Customization macro
(defun consult--customize-put (cmds prop form)
@@ -2863,9 +2936,9 @@ of functions and in `consult-completion-in-region'."
(setq ov nil))
((and (eq action 'preview) cand)
(unless ov
- (setq ov (consult--overlay start end
- 'invisible t
- 'window (selected-window))))
+ (setq ov (consult--make-overlay start end
+ 'invisible t
+ 'window (selected-window))))
;; Use `add-face-text-property' on a copy of "cand in order to merge face properties
(setq cand (copy-sequence cand))
(add-face-text-property 0 (length cand) 'consult-preview-insertion t cand)
@@ -2908,7 +2981,12 @@ These configuration options are supported:
consult-preview-key))
(initial (buffer-substring-no-properties start end))
(metadata (completion-metadata initial collection predicate))
- (threshold (or (plist-get config :cycle-threshold) (completion--cycle-threshold metadata)))
+ ;; NOTE: `minibuffer-completing-file-name' is mostly
+ ;; deprecated. Packages should instead use the completion metadata!
+ (minibuffer-completing-file-name
+ (eq 'file (completion-metadata-get metadata 'category)))
+ (threshold (or (plist-get config :cycle-threshold)
+ (completion--cycle-threshold metadata)))
(all (completion-all-completions initial collection predicate (length initial)))
;; Wrap all annotation functions to ensure that they are executed
;; in the original buffer.
@@ -2932,7 +3010,6 @@ These configuration options are supported:
(and completion-cycling completion-all-sorted-completions)))
(completion--in-region start end collection predicate)
(let* ((limit (car (completion-boundaries initial collection predicate "")))
- (category (completion-metadata-get metadata 'category))
(completion
(cond
((atom all) nil)
@@ -2944,52 +3021,27 @@ These configuration options are supported:
;; preview state
(consult--insertion-preview start end)
;; transformation function
- (if (eq category 'file)
- (cond
- ;; Transform absolute file names
- ((file-name-absolute-p initial)
- (lambda (_narrow _inp cand)
- (substitute-in-file-name cand)))
- ;; Ensure that ./ prefix is kept for the shell
- ;; (gh:minad/consult#356).
- ((string-match-p "\\`\\.\\.?/" initial)
- (lambda (_narrow _inp cand)
- (setq cand (file-relative-name (substitute-in-file-name cand)))
- (if (string-match-p "\\`\\.\\.?/" cand) cand (concat "./" cand))))
- ;; Simplify relative file names
- (t
- (lambda (_narrow _inp cand)
- (file-relative-name (substitute-in-file-name cand)))))
- (lambda (_narrow _inp cand) cand))
+ (lambda (_narrow _inp cand) cand)
;; candidate function
(apply-partially #'run-hook-with-args-until-success
'consult--completion-candidate-hook)
(consult--local-let ((enable-recursive-minibuffers t))
- (if (eq category 'file)
- ;; We use read-file-name, since many completion UIs make it nicer to
- ;; navigate the file system this way; and we insert the initial text
- ;; directly into the minibuffer to allow the user's completion
- ;; styles to expand it as appropriate (particularly useful for the
- ;; partial-completion and initials styles, which allow for very
- ;; condensed path specification).
- (consult--minibuffer-with-setup-hook
- (lambda () (insert initial))
- (read-file-name prompt nil initial require-match nil predicate))
- ;; Evaluate completion table in the original buffer.
- ;; This is a reasonable thing to do and required by
- ;; some completion tables in particular by lsp-mode.
- ;; See gh:minad/vertico#61.
- (completing-read prompt
- (consult--completion-table-in-buffer collection)
- predicate require-match initial)))))))))
+ ;; Evaluate completion table in the original buffer.
+ ;; This is a reasonable thing to do and required by
+ ;; some completion tables in particular by lsp-mode.
+ ;; See gh:minad/vertico#61.
+ (completing-read prompt
+ (consult--completion-table-in-buffer collection)
+ predicate require-match initial))))))))
(if completion
(progn
;; bug#55205: completion--replace removes properties!
(completion--replace start end (setq completion (concat completion)))
(when exit-fun
(funcall exit-fun completion
- ;; If completion is finished and cannot be further completed,
- ;; return 'finished. Otherwise return 'exact.
+ ;; If completion is finished and cannot be further
+ ;; completed, return `finished'. Otherwise return
+ ;; `exact'.
(if (eq (try-completion completion collection predicate) t)
'finished 'exact)))
t)
@@ -3082,7 +3134,7 @@ The symbol at point is added to the future history."
;; line-number-at-pos does not hurt much, since the mark ring is
;; usually small since it is limited by `mark-ring-max'.
(push (consult--location-candidate
- (consult--line-with-cursor marker) marker
+ (consult--line-with-mark marker) marker
(line-number-at-pos pos consult-line-numbers-widen)
marker)
candidates)))))
@@ -3131,7 +3183,7 @@ The symbol at point is added to the future history."
(consult--format-file-line-match (buffer-name buf) line "")
'consult-location (cons marker line)
'consult-strip t)
- (consult--line-with-cursor marker)
+ (consult--line-with-mark marker)
(consult--tofu-encode marker))
candidates))))))))
(unless candidates
@@ -3149,8 +3201,8 @@ The symbol at point is added to the future history."
(consult--global-mark-candidates
(or markers global-mark-ring))
:prompt "Go to global mark: "
- ;; Despite `consult-global-mark' formating the candidates in grep-like
- ;; style, we are not using the 'consult-grep category, since the candidates
+ ;; Despite `consult-global-mark' formatting the candidates in grep-like
+ ;; style, we are not using the `consult-grep' category, since the candidates
;; have location markers attached.
:category 'consult-location
:sort nil
@@ -3243,12 +3295,12 @@ and the last `isearch-string' is added to the future history."
:category 'consult-location
:sort nil
:require-match t
- ;; Always add last isearch string to future history
+ ;; Always add last `isearch-string' to future history
:add-history (list (thing-at-point 'symbol) isearch-string)
:history '(:input consult--line-history)
:lookup #'consult--line-match
:default (car candidates)
- ;; Add isearch-string as initial input if starting from isearch
+ ;; Add `isearch-string' as initial input if starting from Isearch
:initial (or initial
(and isearch-mode
(prog1 isearch-string (isearch-done))))
@@ -3331,13 +3383,13 @@ to `consult--buffer-query'."
:category 'consult-location
:sort nil
:require-match t
- ;; Always add last isearch string to future history
+ ;; Always add last Isearch string to future history
:add-history (mapcar #'consult--async-split-initial
(delq nil (list (thing-at-point 'symbol)
isearch-string)))
:history '(:input consult--line-multi-history)
:lookup #'consult--line-multi-match
- ;; Add isearch-string as initial input if starting from isearch
+ ;; Add `isearch-string' as initial input if starting from Isearch
:initial (consult--async-split-initial
(or initial
(and isearch-mode
@@ -3350,6 +3402,7 @@ to `consult--buffer-query'."
(defun consult--keep-lines-state (filter)
"State function for `consult-keep-lines' with FILTER function."
(let ((font-lock-orig font-lock-mode)
+ (whitespace-orig (bound-and-true-p whitespace-mode))
(hl-line-orig (bound-and-true-p hl-line-mode))
(point-orig (point))
lines content-orig replace last-input)
@@ -3388,7 +3441,7 @@ to `consult--buffer-query'."
;; No undo recording, modification hooks, buffer modified-status
(with-silent-modifications (funcall replace content-orig point-orig)))
;; Committing or new input provided -> Update
- (when (and input ;; Input has been povided
+ (when (and input ;; Input has been provided
(or
;; Committing, but not with empty input
(and (eq action 'return) (not (string-match-p "\\`!? ?\\'" input)))
@@ -3410,6 +3463,7 @@ to `consult--buffer-query'."
(funcall filter input (mapcar #'copy-sequence lines)))))))))
(when (stringp filtered-content)
(when font-lock-mode (font-lock-mode -1))
+ (when (bound-and-true-p whitespace-mode) (whitespace-mode -1))
(when (bound-and-true-p hl-line-mode) (hl-line-mode -1))
(if (eq action 'return)
(atomic-change-group
@@ -3423,16 +3477,17 @@ to `consult--buffer-query'."
;; Restore modes
(when (eq action 'return)
(when hl-line-orig (hl-line-mode 1))
+ (when whitespace-orig (whitespace-mode 1))
(when font-lock-orig (font-lock-mode 1))))))
;;;###autoload
-(defun consult-keep-lines (&optional filter initial)
+(defun consult-keep-lines (filter &optional initial)
"Select a subset of the lines in the current buffer with live preview.
The selected lines are kept and the other lines are deleted. When called
interactively, the lines selected are those that match the minibuffer input. In
order to match the inverse of the input, prefix the input with `! '. When
-called from elisp, the filtering is performed by a FILTER function. This
+called from Elisp, the filtering is performed by a FILTER function. This
command obeys narrowing.
FILTER is the filter function.
@@ -3514,7 +3569,7 @@ INITIAL is the initial input."
(let ((a (if not block-beg block-end))
(b (if not block-end beg)))
(when (/= a b)
- (push (consult--overlay a b 'invisible t) new-overlays)))
+ (push (consult--make-overlay a b 'invisible t) new-overlays)))
(setq block-beg beg))
(setq block-end end old-ind ind)))))
'commit)
@@ -3528,10 +3583,10 @@ INITIAL is the initial input."
(mapc #'delete-overlay overlays)
(goto-char pt-orig))
((equal input "")
- (consult-focus-lines 'show)
+ (consult-focus-lines nil 'show)
(goto-char pt-orig))
(t
- ;; Sucessfully terminated -> Remember invisible overlays
+ ;; Successfully terminated -> Remember invisible overlays
(setq consult--focus-lines-overlays
(nconc consult--focus-lines-overlays overlays))
;; move point past invisible
@@ -3542,24 +3597,24 @@ INITIAL is the initial input."
pt-orig))))))))
;;;###autoload
-(defun consult-focus-lines (&optional show filter initial)
+(defun consult-focus-lines (filter &optional show initial)
"Hide or show lines using overlays.
The selected lines are shown and the other lines hidden. When called
interactively, the lines selected are those that match the minibuffer input. In
order to match the inverse of the input, prefix the input with `! '. With
optional prefix argument SHOW reveal the hidden lines. Alternatively the
-command can be restarted to reveal the lines. When called from elisp, the
+command can be restarted to reveal the lines. When called from Elisp, the
filtering is performed by a FILTER function. This command obeys narrowing.
FILTER is the filter function.
INITIAL is the initial input."
(interactive
- (list current-prefix-arg
- (lambda (pattern cands)
+ (list (lambda (pattern cands)
;; Use consult-location completion category when filtering lines
(consult--completion-filter-dispatch
- pattern cands 'consult-location nil))))
+ pattern cands 'consult-location nil))
+ current-prefix-arg))
(if show
(progn
(mapc #'delete-overlay consult--focus-lines-overlays)
@@ -3581,31 +3636,31 @@ INITIAL is the initial input."
(defun consult--goto-line-position (str msg)
"Transform input STR to line number.
Print an error message with MSG function."
- (if-let (line (and str
- (string-match-p "\\`[[:digit:]]+\\'" str)
- (string-to-number str)))
- (let ((pos (save-excursion
- (save-restriction
- (when consult-line-numbers-widen
- (widen))
- (goto-char (point-min))
- (forward-line (1- line))
- (point)))))
- (if (consult--in-range-p pos)
- pos
- (funcall msg "Line number out of range.")
- nil))
- (when (and str (not (equal str "")))
- (funcall msg "Please enter a number."))
- nil))
+ (save-match-data
+ (if (and str (string-match "\\`\\([[:digit:]]+\\):?\\([[:digit:]]*\\)\\'" str))
+ (let ((line (string-to-number (match-string 1 str)))
+ (col (string-to-number (match-string 2 str))))
+ (save-excursion
+ (save-restriction
+ (when consult-line-numbers-widen
+ (widen))
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (goto-char (min (+ (point) col) (pos-eol)))
+ (point))))
+ (when (and str (not (equal str "")))
+ (funcall msg "Please enter a number."))
+ nil)))
;;;###autoload
(defun consult-goto-line (&optional arg)
"Read line number and jump to the line with preview.
-Jump directly if a line number is given as prefix ARG. The command respects
-narrowing and the settings `consult-goto-line-numbers' and
-`consult-line-numbers-widen'."
+Enter either a line number to jump to the first column of the
+given line or line:column in order to jump to a specific column.
+Jump directly if a line number is given as prefix ARG. The
+command respects narrowing and the settings
+`consult-goto-line-numbers' and `consult-line-numbers-widen'."
(interactive "P")
(if arg
(call-interactively #'goto-line)
@@ -3652,8 +3707,7 @@ narrowing and the settings `consult-goto-line-numbers' and
(find-file
(consult--read
(or
- (let (file-name-handler-alist) ;; No Tramp slowdown please
- (mapcar #'abbreviate-file-name (bound-and-true-p recentf-list)))
+ (mapcar #'consult--fast-abbreviate-file-name (bound-and-true-p recentf-list))
(user-error "No recent files, `recentf-mode' is %s"
(if recentf-mode "enabled" "disabled")))
:prompt "Find recent file: "
@@ -3682,7 +3736,8 @@ narrowing and the settings `consult-goto-line-numbers' and
The list of features is searched for files belonging to the modes.
From these files, the commands are extracted."
- (let* ((buffer (current-buffer))
+ (let* ((case-fold-search)
+ (buffer (current-buffer))
(command-filter (consult--regexp-filter (seq-filter #'stringp consult-mode-command-filter)))
(feature-filter (seq-filter #'symbolp consult-mode-command-filter))
(minor-hash (consult--string-hash minor-mode-list))
@@ -3881,10 +3936,9 @@ There exists no equivalent of this command in Emacs 28."
preview action
;; Only preview bookmarks with the default handler.
(when-let ((bm (and cand (eq action 'preview) (assoc cand bookmark-alist)))
- (handler (bookmark-get-handler bm))
- (file (and (or (not handler)
- (eq handler #'bookmark-default-handler))
- (bookmark-get-filename bm)))
+ (handler (or (bookmark-get-handler bm) #'bookmark-default-handler))
+ ((eq handler #'bookmark-default-handler))
+ (file (bookmark-get-filename bm))
(pos (bookmark-get-position bm))
(buf (funcall open file)))
(set-marker (make-marker) pos buf))))))
@@ -3991,8 +4045,6 @@ history is used."
(unless found
(user-error "No history configured for `%s', see `consult-mode-histories'"
major-mode))
- (unless (consp (cdr found))
- (user-error "Obsolete mode history entry: %S" found))
(cons (symbol-value (cadr found)) (cddr found))))))
;;;###autoload
@@ -4041,14 +4093,14 @@ of the prompt. See also `cape-history' from the Cape package."
;;;;; Command: consult-isearch-history
(defun consult-isearch-forward (&optional reverse)
- "Continue isearch forward optionally in REVERSE."
+ "Continue Isearch forward optionally in REVERSE."
(interactive)
(consult--require-minibuffer)
(setq isearch-new-forward (not reverse) isearch-new-nonincremental nil)
(funcall (or (command-remapping #'exit-minibuffer) #'exit-minibuffer)))
(defun consult-isearch-backward (&optional reverse)
- "Continue isearch backward optionally in REVERSE."
+ "Continue Isearch backward optionally in REVERSE."
(interactive)
(consult-isearch-forward (not reverse)))
@@ -4062,34 +4114,30 @@ of the prompt. See also `cape-history' from the Cape package."
"<remap> <isearch-backward>" #'consult-isearch-backward)
(defun consult--isearch-history-candidates ()
- "Return isearch history candidates."
+ "Return Isearch history candidates."
;; NOTE: Do not throw an error on empty history,
;; in order to allow starting a search.
;; We do not :require-match here!
(let ((history (if (eq t search-default-mode)
(append regexp-search-ring search-ring)
(append search-ring regexp-search-ring))))
- (cons
- (delete-dups
- (mapcar
- (lambda (cand)
- ;; The search type can be distinguished via text properties.
- (let* ((props (plist-member (text-properties-at 0 cand)
- 'isearch-regexp-function))
- (type (pcase (cadr props)
- ((and 'nil (guard (not props))) ?r)
- ('nil ?l)
- ('word-search-regexp ?w)
- ('isearch-symbol-regexp ?s)
- ('char-fold-to-regexp ?c)
- (_ ?u))))
- ;; Disambiguate history items. The same string could
- ;; occur with different search types.
- (consult--tofu-append cand type)))
- history))
- (if history
- (+ 4 (apply #'max (mapcar #'length history)))
- 0))))
+ (delete-dups
+ (mapcar
+ (lambda (cand)
+ ;; The search type can be distinguished via text properties.
+ (let* ((props (plist-member (text-properties-at 0 cand)
+ 'isearch-regexp-function))
+ (type (pcase (cadr props)
+ ((and 'nil (guard (not props))) ?r)
+ ('nil ?l)
+ ('word-search-regexp ?w)
+ ('isearch-symbol-regexp ?s)
+ ('char-fold-to-regexp ?c)
+ (_ ?u))))
+ ;; Disambiguate history items. The same string could
+ ;; occur with different search types.
+ (consult--tofu-append cand type)))
+ history))))
(defconst consult--isearch-history-narrow
'((?c . "Char")
@@ -4107,24 +4155,25 @@ This replaces the current search string if Isearch is active, and
starts a new Isearch session otherwise."
(interactive)
(consult--forbid-minibuffer)
- (let* ((isearch-message-function 'ignore) ;; Avoid flicker in echo area
- (inhibit-redisplay t) ;; Avoid flicker in mode line
- (candidates (consult--isearch-history-candidates))
- (align (propertize " " 'display `(space :align-to (+ left ,(cdr candidates))))))
+ (let* ((isearch-message-function #'ignore)
+ (cursor-in-echo-area t) ;; Avoid cursor flickering
+ (candidates (consult--isearch-history-candidates)))
(unless isearch-mode (isearch-mode t))
(with-isearch-suspended
(setq isearch-new-string
(consult--read
- (car candidates)
+ candidates
:prompt "I-search: "
- :category 'consult-isearch
+ :category 'consult-isearch-history
:history t ;; disable history
:sort nil
:initial isearch-string
:keymap consult-isearch-history-map
:annotate
(lambda (cand)
- (concat align (alist-get (consult--tofu-get cand) consult--isearch-history-narrow)))
+ (consult--annotate-align
+ cand
+ (alist-get (consult--tofu-get cand) consult--isearch-history-narrow)))
:group
(lambda (cand transform)
(if transform
@@ -4306,7 +4355,7 @@ QUERY is passed to `consult--buffer-query'."
(cond
((and ndir (eq dir 'project))
(format ", Project %s" (consult--project-name ndir)))
- (ndir (concat ", " (consult--abbreviate-directory ndir)))
+ (ndir (concat ", " (consult--left-truncate-file ndir)))
(t "")))
buffers)))
@@ -4331,7 +4380,8 @@ AS is a conversion function."
(when (or filter mode as root)
(let ((mode (ensure-list mode))
(exclude-re (consult--regexp-filter exclude))
- (include-re (consult--regexp-filter include)))
+ (include-re (consult--regexp-filter include))
+ (case-fold-search))
(consult--keep! buffers
(and
(or (not mode)
@@ -4362,21 +4412,28 @@ AS is a conversion function."
(defun consult--buffer-preview ()
"Buffer preview function."
- (let ((orig-buf (current-buffer)) other-win)
+ (let ((orig-buf (current-buffer))
+ (orig-prev (copy-sequence (window-prev-buffers)))
+ (orig-next (copy-sequence (window-next-buffers)))
+ other-win)
(lambda (action cand)
- (when (eq action 'preview)
- (when (and (eq consult--buffer-display #'switch-to-buffer-other-window)
- (not other-win))
- (switch-to-buffer-other-window orig-buf)
- (setq other-win (selected-window)))
- (let ((win (or other-win (selected-window))))
- (when (window-live-p win)
- (with-selected-window win
- (cond
- ((and cand (get-buffer cand))
- (switch-to-buffer cand 'norecord))
- ((buffer-live-p orig-buf)
- (switch-to-buffer orig-buf 'norecord))))))))))
+ (pcase action
+ ('exit
+ (set-window-prev-buffers other-win orig-prev)
+ (set-window-next-buffers other-win orig-next))
+ ('preview
+ (when (and (eq consult--buffer-display #'switch-to-buffer-other-window)
+ (not other-win))
+ (switch-to-buffer-other-window orig-buf)
+ (setq other-win (selected-window)))
+ (let ((win (or other-win (selected-window)))
+ (buf (or (and cand (get-buffer cand)) orig-buf)))
+ (when (and (window-live-p win) (buffer-live-p buf))
+ (with-selected-window win
+ (unless (or orig-prev orig-next)
+ (setq orig-prev (copy-sequence (window-prev-buffers))
+ orig-next (copy-sequence (window-next-buffers))))
+ (switch-to-buffer buf 'norecord)))))))))
(defun consult--buffer-action (buffer &optional norecord)
"Switch to BUFFER via `consult--buffer-display' function.
@@ -4397,8 +4454,7 @@ If NORECORD is non-nil, do not record the buffer switch in the buffer list."
(defvar consult--source-project-buffer
`(:name "Project Buffer"
- :narrow (?p . "Project")
- :hidden t
+ :narrow ?b
:category buffer
:face consult-buffer
:history buffer-name-history
@@ -4414,8 +4470,7 @@ If NORECORD is non-nil, do not record the buffer switch in the buffer list."
(defvar consult--source-project-recent-file
`(:name "Project File"
- :narrow (?p . "Project")
- :hidden t
+ :narrow ?f
:category file
:face consult-file
:history file-name-history
@@ -4430,26 +4485,35 @@ If NORECORD is non-nil, do not record the buffer switch in the buffer list."
recentf-mode))
:items
,(lambda ()
- (when-let (root (consult--project-root))
- (let ((len (length root))
- (ht (consult--buffer-file-hash))
- file-name-handler-alist ;; No Tramp slowdown please.
- items)
- (dolist (file (bound-and-true-p recentf-list) (nreverse items))
- ;; Emacs 29 abbreviates file paths by default, see
- ;; `recentf-filename-handlers'.
- (unless (eq (aref file 0) ?/)
- (setq file (expand-file-name file)))
- (when (and (not (gethash file ht)) (string-prefix-p root file))
- (let ((part (substring file len)))
- (when (equal part "") (setq part "./"))
- (put-text-property 0 1 'multi-category `(file . ,file) part)
- (push part items))))))))
+ (when-let (root (consult--project-root))
+ (let ((len (length root))
+ (ht (consult--buffer-file-hash))
+ items)
+ (dolist (file (bound-and-true-p recentf-list) (nreverse items))
+ ;; Emacs 29 abbreviates file paths by default, see
+ ;; `recentf-filename-handlers'. I recommend to set
+ ;; `recentf-filename-handlers' to nil to avoid any slow down.
+ (unless (eq (aref file 0) ?/)
+ (let (file-name-handler-alist) ;; No Tramp slowdown please.
+ (setq file (expand-file-name file))))
+ (when (and (not (gethash file ht)) (string-prefix-p root file))
+ (let ((part (substring file len)))
+ (when (equal part "") (setq part "./"))
+ (put-text-property 0 1 'multi-category `(file . ,file) part)
+ (push part items))))))))
"Project file candidate source for `consult-buffer'.")
+(defvar consult--source-project-buffer-hidden
+ `(:hidden t :narrow (?p . "Project") ,@consult--source-project-buffer)
+ "Like `consult--source-project-buffer' but hidden by default.")
+
+(defvar consult--source-project-recent-file-hidden
+ `(:hidden t :narrow (?p . "Project") ,@consult--source-project-recent-file)
+ "Like `consult--source-project-recent-file' but hidden by default.")
+
(defvar consult--source-hidden-buffer
`(:name "Hidden Buffer"
- :narrow 32
+ :narrow ?\s
:hidden t
:category buffer
:face consult-buffer
@@ -4517,15 +4581,16 @@ If NORECORD is non-nil, do not record the buffer switch in the buffer list."
:items
,(lambda ()
(let ((ht (consult--buffer-file-hash))
- file-name-handler-alist ;; No Tramp slowdown please.
items)
(dolist (file (bound-and-true-p recentf-list) (nreverse items))
;; Emacs 29 abbreviates file paths by default, see
- ;; `recentf-filename-handlers'.
+ ;; `recentf-filename-handlers'. I recommend to set
+ ;; `recentf-filename-handlers' to nil to avoid any slow down.
(unless (eq (aref file 0) ?/)
- (setq file (expand-file-name file)))
+ (let (file-name-handler-alist) ;; No Tramp slowdown please.
+ (setq file (expand-file-name file))))
(unless (gethash file ht)
- (push (abbreviate-file-name file) items))))))
+ (push (consult--fast-abbreviate-file-name file) items))))))
"Recent file candidate source for `consult-buffer'.")
;;;###autoload
@@ -4550,16 +4615,10 @@ configuration of the virtual buffer sources."
(unless (plist-get (cdr selected) :match)
(consult--buffer-action (car selected)))))
-;; Populate `consult-project-buffer-sources'.
-(setq consult-project-buffer-sources
- (list
- `(:hidden nil :narrow ?b ,@consult--source-project-buffer)
- `(:hidden nil :narrow ?f ,@consult--source-project-recent-file)))
-
(defmacro consult--with-project (&rest body)
"Ensure that BODY is executed with a project root."
;; We have to work quite hard here to ensure that the project root is
- ;; only overriden at the current recursion level. When entering a
+ ;; only overridden at the current recursion level. When entering a
;; recursive minibuffer session, we should be able to still switch the
;; project. But who does that? Working on the first level on project A
;; and on the second level on project B and on the third level on project C?
@@ -4606,12 +4665,7 @@ BUILDER is the command line builder function."
(lambda (action)
(cond
((stringp action)
- (let ((tmp (funcall builder action)))
- (if (not (keywordp (car tmp)))
- (setq highlight (cdr tmp))
- ;; TODO remove backward compatibility code
- (message "Consult: The command builder return value changed, it should be a pair instead of a plist")
- (setq highlight (plist-get tmp :highlight))))
+ (setq highlight (cdr (funcall builder action)))
(funcall async action))
((consp action)
(let ((file "") (file-len 0) result)
@@ -4683,19 +4737,21 @@ Take the variables `grep-find-ignored-directories' and
(mapcar (lambda (s) (concat "--exclude-dir=" s))
(bound-and-true-p grep-find-ignored-directories))))
-(defun consult--grep (prompt builder dir initial)
- "Run grep in DIR.
+(defun consult--grep (prompt make-builder dir initial)
+ "Run asynchronous grep.
-BUILDER is the command line builder function.
-PROMPT is the prompt string.
-INITIAL is inital input."
- (let* ((prompt-dir (consult--directory-prompt prompt dir))
- (default-directory (cdr prompt-dir)))
+MAKE-BUILDER is the function that returns the command line
+builder function. DIR is a directory or a list of file or
+directories. PROMPT is the prompt string. INITIAL is initial
+input."
+ (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt prompt dir))
+ (default-directory dir)
+ (builder (funcall make-builder paths)))
(consult--read
(consult--async-command builder
(consult--grep-format builder)
:file-handler t) ;; allow tramp
- :prompt (car prompt-dir)
+ :prompt prompt
:lookup #'consult--lookup-member
:state (consult--grep-state)
:initial (consult--async-split-initial initial)
@@ -4707,14 +4763,13 @@ INITIAL is inital input."
:sort nil)))
(defun consult--grep-lookahead-p (&rest cmd)
- "Return t if grep CMD supports lookahead."
- (with-temp-buffer
- (insert "xaxbx")
- (eq 0 (apply #'call-process-region (point-min) (point-max)
- (car cmd) nil nil nil `(,@(cdr cmd) "^(?=.*b)(?=.*a)")))))
-
-(defun consult--grep-make-builder ()
- "Create grep command line builder."
+ "Return t if grep CMD supports look-ahead."
+ (eq 0 (process-file-shell-command
+ (concat "echo xaxbx | "
+ (mapconcat #'shell-quote-argument `(,@cmd "^(?=.*b)(?=.*a)") " ")))))
+
+(defun consult--grep-make-builder (paths)
+ "Build grep command line and grep across PATHS."
(let* ((cmd (consult--build-args consult-grep-args))
(type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended)))
(lambda (input)
@@ -4722,7 +4777,7 @@ INITIAL is inital input."
(flags (append cmd opts))
(ignore-case (or (member "-i" flags) (member "--ignore-case" flags))))
(if (or (member "-F" flags) (member "--fixed-strings" flags))
- (cons (append cmd (list "-e" arg) opts)
+ (cons (append cmd (list "-e" arg) opts paths)
(apply-partially #'consult--highlight-regexps
(list (regexp-quote arg)) ignore-case))
(pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg type ignore-case)))
@@ -4730,33 +4785,43 @@ INITIAL is inital input."
(cons (append cmd
(list (if (eq type 'pcre) "-P" "-E") ;; perl or extended
"-e" (consult--join-regexps re type))
- opts)
+ opts paths)
hl))))))))
;;;###autoload
(defun consult-grep (&optional dir initial)
"Search with `grep' for files in DIR where the content matches a regexp.
-The initial input is given by the INITIAL argument.
-
-The input string is split, the first part of the string (grep input) is
-passed to the asynchronous grep process and the second part of the string is
-passed to the completion-style filtering.
-
-The input string is split at a punctuation character, which is given as the
-first character of the input string. The format is similar to Perl-style
-regular expressions, e.g., /regexp/. Furthermore command line options can be
-passed to grep, specified behind --. The overall prompt input has the form
+The initial input is given by the INITIAL argument. DIR can be
+nil, a directory string or a list of file/directory paths. If
+`consult-grep' is called interactively with a prefix argument,
+the user can specify the directories or files to search in.
+Multiple directories must be separated by comma in the
+minibuffer, since they are read via `completing-read-multiple'.
+By default the project directory is used if
+`consult-project-function' is defined and returns non-nil.
+Otherwise the `default-directory' is searched.
+
+The input string is split, the first part of the string (grep
+input) is passed to the asynchronous grep process and the second
+part of the string is passed to the completion-style filtering.
+
+The input string is split at a punctuation character, which is
+given as the first character of the input string. The format is
+similar to Perl-style regular expressions, e.g., /regexp/.
+Furthermore command line options can be passed to grep, specified
+behind --. The overall prompt input has the form
`#async-input -- grep-opts#filter-string'.
-Note that the grep input string is transformed from Emacs regular expressions
-to Posix regular expressions. Always enter Emacs regular expressions at the
-prompt. `consult-grep' behaves like builtin Emacs search commands, e.g.,
-Isearch, which take Emacs regular expressions. Furthermore the asynchronous
-input split into words, each word must match separately and in any order. See
-`consult--regexp-compiler' for the inner workings. In order to disable
-transformations of the grep input, adjust `consult--regexp-compiler'
-accordingly.
+Note that the grep input string is transformed from Emacs regular
+expressions to Posix regular expressions. Always enter Emacs
+regular expressions at the prompt. `consult-grep' behaves like
+builtin Emacs search commands, e.g., Isearch, which take Emacs
+regular expressions. Furthermore the asynchronous input split
+into words, each word must match separately and in any order.
+See `consult--regexp-compiler' for the inner workings. In order
+to disable transformations of the grep input, adjust
+`consult--regexp-compiler' accordingly.
Here we give a few example inputs:
@@ -4766,43 +4831,41 @@ Here we give a few example inputs:
#word -- -C3 : Search for word, include 3 lines as context
#first#second : Search for first, quick filter for second.
-The symbol at point is added to the future history. If `consult-grep'
-is called interactively with a prefix argument, the user can specify
-the directory to search in. By default the project directory is used
-if `consult-project-function' is defined and returns non-nil.
-Otherwise the `default-directory' is searched."
+The symbol at point is added to the future history."
(interactive "P")
- (consult--grep "Grep" (consult--grep-make-builder) dir initial))
+ (consult--grep "Grep" #'consult--grep-make-builder dir initial))
;;;;; Command: consult-git-grep
-(defun consult--git-grep-builder (input)
- "Build command line given CONFIG and INPUT."
- (pcase-let* ((cmd (consult--build-args consult-git-grep-args))
- (`(,arg . ,opts) (consult--command-split input))
- (flags (append cmd opts))
- (ignore-case (or (member "-i" flags) (member "--ignore-case" flags))))
- (if (or (member "-F" flags) (member "--fixed-strings" flags))
- (cons (append cmd (list "-e" arg) opts)
- (apply-partially #'consult--highlight-regexps
- (list (regexp-quote arg)) ignore-case))
- (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended ignore-case)))
- (when re
- (cons (append cmd (cdr (mapcan (lambda (x) (list "--and" "-e" x)) re)) opts)
- hl))))))
+(defun consult--git-grep-make-builder (paths)
+ "Create grep command line builder given PATHS."
+ (let ((cmd (consult--build-args consult-git-grep-args)))
+ (lambda (input)
+ (pcase-let* ((`(,arg . ,opts) (consult--command-split input))
+ (flags (append cmd opts))
+ (ignore-case (or (member "-i" flags) (member "--ignore-case" flags))))
+ (if (or (member "-F" flags) (member "--fixed-strings" flags))
+ (cons (append cmd (list "-e" arg) opts paths)
+ (apply-partially #'consult--highlight-regexps
+ (list (regexp-quote arg)) ignore-case))
+ (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended ignore-case)))
+ (when re
+ (cons (append cmd
+ (cdr (mapcan (lambda (x) (list "--and" "-e" x)) re))
+ opts paths)
+ hl))))))))
;;;###autoload
(defun consult-git-grep (&optional dir initial)
- "Search with `git grep' for files in DIR where the content matches a regexp.
-The initial input is given by the INITIAL argument. See `consult-grep'
-for more details."
+ "Search with `git grep' for files in DIR with INITIAL input.
+See `consult-grep' for details."
(interactive "P")
- (consult--grep "Git-grep" #'consult--git-grep-builder dir initial))
+ (consult--grep "Git-grep" #'consult--git-grep-make-builder dir initial))
;;;;; Command: consult-ripgrep
-(defun consult--ripgrep-make-builder ()
- "Create ripgrep command line builder."
+(defun consult--ripgrep-make-builder (paths)
+ "Create ripgrep command line builder given PATHS."
(let* ((cmd (consult--build-args consult-ripgrep-args))
(type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended)))
(lambda (input)
@@ -4814,23 +4877,22 @@ for more details."
(not (string-match-p "[[:upper:]]" arg)))
(or (member "-i" flags) (member "--ignore-case" flags)))))
(if (or (member "-F" flags) (member "--fixed-strings" flags))
- (cons (append cmd (list "-e" arg) opts)
+ (cons (append cmd (list "-e" arg) opts paths)
(apply-partially #'consult--highlight-regexps
(list (regexp-quote arg)) ignore-case))
(pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg type ignore-case)))
(when re
(cons (append cmd (and (eq type 'pcre) '("-P"))
(list "-e" (consult--join-regexps re type))
- opts)
+ opts paths)
hl))))))))
;;;###autoload
(defun consult-ripgrep (&optional dir initial)
- "Search with `rg' for files in DIR where the content matches a regexp.
-The initial input is given by the INITIAL argument. See `consult-grep'
-for more details."
+ "Search with `rg' for files in DIR with INITIAL input.
+See `consult-grep' for details."
(interactive "P")
- (consult--grep "Ripgrep" (consult--ripgrep-make-builder) dir initial))
+ (consult--grep "Ripgrep" #'consult--ripgrep-make-builder dir initial))
;;;;; Command: consult-find
@@ -4842,7 +4904,7 @@ The filename at point is added to the future history.
BUILDER is the command line builder function.
PROMPT is the prompt.
-INITIAL is inital input."
+INITIAL is initial input."
(consult--read
(consult--async-command builder
(consult--async-map (lambda (x) (string-remove-prefix "./" x)))
@@ -4856,10 +4918,12 @@ INITIAL is inital input."
:category 'file
:history '(:input consult--find-history)))
-(defun consult--find-make-builder ()
- "Create find command line builder."
- (let* ((cmd (consult--build-args consult-find-args))
- (type (if (eq 0 (call-process-shell-command
+(defun consult--find-make-builder (paths)
+ "Build find command line, finding across PATHS."
+ (let* ((cmd (seq-mapcat (lambda (x)
+ (if (equal x ".") paths (list x)))
+ (consult--build-args consult-find-args)))
+ (type (if (eq 0 (process-file-shell-command
(concat (car cmd) " -regextype emacs -version")))
'emacs 'basic)))
(lambda (input)
@@ -4883,18 +4947,18 @@ INITIAL is inital input."
;;;###autoload
(defun consult-find (&optional dir initial)
"Search for files in DIR matching input regexp given INITIAL input.
-
-The find process is started asynchronously, similar to `consult-grep'.
-See `consult-grep' for more details regarding the asynchronous search."
+See `consult-grep' for details regarding the asynchronous search
+and the arguments."
(interactive "P")
- (let* ((prompt-dir (consult--directory-prompt "Find" dir))
- (default-directory (cdr prompt-dir)))
- (find-file (consult--find (car prompt-dir) (consult--find-make-builder) initial))))
+ (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt "Find" dir))
+ (default-directory dir)
+ (builder (consult--find-make-builder paths)))
+ (find-file (consult--find prompt builder initial))))
;;;;; Command: consult-locate
(defun consult--locate-builder (input)
- "Build command line given CONFIG and INPUT."
+ "Build command line from INPUT."
(pcase-let ((`(,arg . ,opts) (consult--command-split input)))
(unless (string-blank-p arg)
(cons (append (consult--build-args consult-locate-args)
@@ -4916,12 +4980,12 @@ details regarding the asynchronous search."
;;;;; Command: consult-man
(defun consult--man-builder (input)
- "Build command line given CONFIG and INPUT."
+ "Build command line from INPUT."
(pcase-let* ((`(,arg . ,opts) (consult--command-split input))
- (`(,re . ,hl) (funcall consult--regexp-compiler arg 'basic t)))
+ (`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended t)))
(when re
(cons (append (consult--build-args consult-man-args)
- (list (consult--join-regexps re 'basic))
+ (list (consult--join-regexps re 'extended))
opts)
hl))))
@@ -4983,7 +5047,9 @@ automatically previewed."
(fun (buffer-local-value 'consult--preview-function buf)))
(funcall fun)))
-;;;; Integration with the default completion system
+;;;; Integration with completion systems
+
+;;;;; Integration: Default *Completions*
(defun consult--default-completion-minibuffer-candidate ()
"Return current minibuffer candidate from default completion system or Icomplete."
@@ -5018,16 +5084,75 @@ automatically previewed."
(or (get-text-property beg 'completion--string)
(buffer-substring-no-properties beg end)))))
-;; Announce now that consult has been loaded
-(provide 'consult)
+;;;;; Integration: Vertico
+
+(defvar vertico--input)
+(declare-function vertico--exhibit "ext:vertico")
+(declare-function vertico--candidate "ext:vertico")
+(declare-function vertico--all-completions "ext:vertico")
+
+(defun consult--vertico-candidate ()
+ "Return current candidate for Consult preview."
+ (and vertico--input (vertico--candidate 'highlight)))
+
+(defun consult--vertico-refresh ()
+ "Refresh completion UI."
+ (when vertico--input
+ (setq vertico--input t)
+ (vertico--exhibit)))
+
+(defun consult--vertico-filter-adv (orig pattern cands category highlight)
+ "Advice for ORIG `consult--completion-filter' function.
+See `consult--completion-filter' for arguments PATTERN, CANDS, CATEGORY
+and HIGHLIGHT."
+ (if (and (bound-and-true-p vertico-mode) (not highlight))
+ ;; Optimize `consult--completion-filter' using the deferred highlighting
+ ;; from Vertico. The advice is not necessary - it is a pure optimization.
+ (nconc (car (vertico--all-completions pattern cands nil (length pattern)
+ `(metadata (category . ,category))))
+ nil)
+ (funcall orig pattern cands category highlight)))
+
+(with-eval-after-load 'vertico
+ (advice-add #'consult--completion-filter :around #'consult--vertico-filter-adv)
+ (add-hook 'consult--completion-candidate-hook #'consult--vertico-candidate)
+ (add-hook 'consult--completion-refresh-hook #'consult--vertico-refresh)
+ (define-key consult-async-map [remap vertico-insert] 'vertico-next-group))
+
+;;;;; Integration: Mct
-;;;; Integration with other completion systems
-
-(with-eval-after-load 'icomplete (require 'consult-icomplete))
-(with-eval-after-load 'vertico (require 'consult-vertico))
(with-eval-after-load 'mct (add-hook 'consult--completion-refresh-hook
'mct--live-completions-refresh))
-(with-eval-after-load 'selectrum
- (warn (propertize "Consult: Selectrum has been deprecated in favor of Vertico" 'face 'warning)))
+;;;;; Integration: Icomplete
+
+(defvar icomplete-mode)
+(declare-function icomplete-exhibit "icomplete")
+
+(defun consult--icomplete-refresh ()
+ "Refresh icomplete view."
+ (when icomplete-mode
+ (let ((top (car completion-all-sorted-completions)))
+ (completion--flush-all-sorted-completions)
+ ;; force flushing, otherwise narrowing is broken!
+ (setq completion-all-sorted-completions nil)
+ (when top
+ (let* ((completions (completion-all-sorted-completions))
+ (last (last completions))
+ (before)) ;; completions before top
+ ;; warning: completions is an improper list
+ (while (consp completions)
+ (if (equal (car completions) top)
+ (progn
+ (setcdr last (append (nreverse before) (cdr last)))
+ (setq completion-all-sorted-completions completions
+ completions nil))
+ (push (car completions) before)
+ (setq completions (cdr completions)))))))
+ (icomplete-exhibit)))
+
+(with-eval-after-load 'icomplete
+ (add-hook 'consult--completion-refresh-hook #'consult--icomplete-refresh))
+
+(provide 'consult)
;;; consult.el ends here
diff --git a/debian/changelog b/debian/changelog
index 085bbe5..b5afaf9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+consult-el (0.35-1) unstable; urgency=medium
+
+ * New upstream release.
+ * Refresh patches.
+
+ -- Aymeric Agon-Rambosson <aymeric.agon@yandex.com> Fri, 20 Oct 2023 03:46:59 +0200
+
consult-el (0.32-1) unstable; urgency=medium
[ Aymeric Agon-Rambosson ]
diff --git a/debian/patches/replace-external-references-when-possible.patch b/debian/patches/replace-external-references-when-possible.patch
index 9d6136c..e3c9c73 100644
--- a/debian/patches/replace-external-references-when-possible.patch
+++ b/debian/patches/replace-external-references-when-possible.patch
@@ -43,7 +43,7 @@ Forwarded: not-needed
all Consult commands with their abbreviated description. Alternatively, type
=C-h a ^consult= to get an overview of all Consult variables and functions with
their descriptions.
-@@ -389,7 +389,7 @@ their descriptions.
+@@ -392,7 +392,7 @@ their descriptions.
#+end_src
Instead of =consult-completion-in-region=, you may prefer to see the
completions directly in the buffer as a small popup. In that case, I recommend
@@ -52,7 +52,7 @@ Forwarded: not-needed
=consult-completion-in-region= in combination with Lsp-mode or Eglot. The Lsp
server relies on the input at point, in order to generate refined candidate
strings. Since the completion is transferred from the original buffer to the
-@@ -507,7 +507,7 @@ pressing =C-h=. When pressing =C-h= afte
+@@ -520,7 +520,7 @@ pressing =C-h=. When pressing =C-h= afte
is invoked, which shows the keybinding help window by default. As a more compact
alternative, there is the =consult-narrow-help= command which can be bound to a
key, for example =?= or =C-h= in the =consult-narrow-map=, as shown in the [[#use-package-example][example
@@ -61,7 +61,7 @@ Forwarded: not-needed
shown in the which-key window after pressing the =consult-narrow-key=.
** Asynchronous search
-@@ -702,11 +702,11 @@ since some details may still change.
+@@ -715,11 +715,11 @@ since some details may still change.
:end:
#+cindex: embark
@@ -76,7 +76,7 @@ Forwarded: not-needed
capabilities.
Actions are commands which can operate on the currently selected candidate (or
-@@ -726,7 +726,7 @@ the matching lines from =consult-line=,
+@@ -739,7 +739,7 @@ the matching lines from =consult-line=,
they can be edited via the =occur-edit-mode= (press key =e=). Similarly, Embark
supports exporting the matches found by =consult-grep=, =consult-ripgrep= and
=consult-git-grep= to a Grep buffer, where the matches across files can be edited,
@@ -85,7 +85,7 @@ Forwarded: not-needed
+ =consult-line= -> =embark-export= to =occur-mode= buffer -> =occur-edit-mode= for editing of matches in buffer.
+ =consult-grep= -> =embark-export= to =grep-mode= buffer -> =wgrep= for editing of all matches.
-@@ -737,14 +737,12 @@ if the [[https://github.com/mhayashi1120
+@@ -750,14 +750,12 @@ if the [[https://github.com/mhayashi1120
:description: Example configuration and customization variables
:end:
@@ -102,7 +102,7 @@ Forwarded: not-needed
configuration. Consult relies on lambdas and lexical closures. For this reason
many Consult-related snippets require lexical binding.
-@@ -760,8 +758,8 @@ modes. Therefore the package is non-intr
+@@ -773,8 +771,8 @@ modes. Therefore the package is non-intr
effort. In order to use the Consult commands, it is advised to add keybindings
for commands which are accessed often. Rarely used commands can be invoked via
=M-x=. Feel free to only bind the commands you consider useful to your workflow.
@@ -113,7 +113,7 @@ Forwarded: not-needed
*NOTE:* There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where you can contribute additional
configuration examples.
-@@ -893,7 +891,7 @@ configuration examples.
+@@ -906,7 +904,7 @@ configuration examples.
:end:
#+cindex: customization
@@ -122,7 +122,7 @@ Forwarded: not-needed
^consult= to see all Consult-specific customizable variables with their current
values and abbreviated description. Alternatively, type =C-h a ^consult= to get
an overview of all Consult variables and functions with their descriptions.
-@@ -1016,10 +1014,12 @@ following techniques:
+@@ -1027,10 +1025,12 @@ following techniques:
I use and recommend this combination of packages:
- consult: This package
@@ -139,21 +139,22 @@ Forwarded: not-needed
There exist many other fine completion UIs beside Vertico, which are supported
by Consult. Give them a try and find out which interaction model fits best for
-@@ -1047,39 +1047,39 @@ You can integrate Consult with special p
+@@ -1058,40 +1058,40 @@ You can integrate Consult with special p
wider Emacs ecosystem. You may want to install some of theses packages depending
on your preferences and requirements.
-- [[https://github.com/yadex205/consult-ag][consult-ag]]: Support for the [[https://github.com/ggreer/the_silver_searcher][Silver Searcher]] in the style of =consult-grep=.
--- [[https://github.com/mohkale/consult-company][consult-company]]: Completion at point using the [[https://github.com/company-mode/company-mode][Company]] backends.
+- [[https://github.com/yadex205/consult-ag][consult-ag]]: Support for the Silver Searcher (~apt install silversearcher-ag~) in the style of =consult-grep=.
-+- [[https://github.com/mohkale/consult-company][consult-company]]: Completion at point using the Company (~apt install elpa-company~) backends.
- [[https://github.com/youngker/consult-codesearch.el][consult-codesearch]]: Integration with [[https://github.com/google/codesearch][Code Search]].
+-- [[https://github.com/mohkale/consult-company][consult-company]]: Completion at point using the [[https://github.com/company-mode/company-mode][Company]] backends.
++- [[https://github.com/mohkale/consult-company][consult-company]]: Completion at point using the Company (~apt install elpa-company~) backends.
+ - [[https://github.com/mohkale/consult-compile-multi][consult-compile-multi]]: Integration with [[https://github.com/mohkale/compile-multi][compile-multi]].
- [[https://github.com/karthink/consult-dir][consult-dir]]: Directory jumper using Consult multi sources.
- [[https://codeberg.org/ravi/consult-dash][consult-dash]]: Consult interface to [[https://github.com/dash-docs-el/dash-docs][Dash documentation]]
-- [[https://github.com/mohkale/consult-eglot][consult-eglot]]: Integration with Eglot (LSP client).
-- [[https://github.com/minad/consult-flycheck][consult-flycheck]]: Additional Flycheck integration.
+- [[https://github.com/mohkale/consult-eglot][consult-eglot]]: Integration with Eglot (LSP client, ~apt install elpa-eglot~).
-+- [[https://github.com/minad/consult-flycheck][consult-flycheck]]: Additional Flycheck (~apt install elpa-flycheck~) integration.
++- [[https://github.com/minad/consult-flycheck][consult-flycheck]]: Additional Flycheck integration (~apt install elpa-flycheck~).
- [[https://gitlab.com/OlMon/consult-flyspell][consult-flyspell]]: Additional Flyspell integration.
- [[https://github.com/ghosty141/consult-git-log-grep][consult-git-log-grep]]: Consult interface to git log.
- [[https://github.com/Nyoho/consult-hatena-bookmark][consult-hatena-bookmark]]: Access Hatena bookmarks.
@@ -180,7 +181,7 @@ Forwarded: not-needed
offer functionality based on ~completing-read~.
-- [[https://github.com/minad/corfu][corfu]]: Completion systems for =completion-at-point= using small popups (Alternative to [[https://github.com/company-mode/company-mode][Company]]).
-+- [[https://github.com/minad/corfu][corfu]]: Completion systems for =completion-at-point= using small popups (Alternative to Company).
++- corfu (~apt install elpa-corfu~): Completion systems for =completion-at-point= using small popups (Alternative to Company).
- [[https://github.com/minad/cape][cape]]: Completion At Point Extensions, which can be used with =consult-completion-in-region= and [[https://github.com/minad/corfu][Corfu]].
- [[https://github.com/minad/bookmark-view][bookmark-view]]: Store window configuration as bookmarks, possible integration with =consult-buffer=.
-- [[https://github.com/bdarcus/citar][citar]]: Versatile package for citation insertion and bibliography management.
@@ -189,10 +190,10 @@ Forwarded: not-needed
- [[https://github.com/d12frosted/flyspell-correct][flyspell-correct]]: Apply spelling corrections by selecting via =completing-read=.
-- [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]]: Editing of grep buffers, use together with =consult-grep= via =embark-export=.
+- wgrep (~apt install elpa-wgrep~): Editing of grep buffers, use together with =consult-grep= via =embark-export=.
- - [[https://github.com/iyefrat/all-the-icons-completion][all-the-icons-completion]]: Icons for the completion UI.
+ - [[https://github.com/iyefrat/all-the-icons-completion][all-the-icons-completion]], [[https://github.com/rainstormstudio/nerd-icons-completion][nerd-icons-completion]]: Icons for the completion UI.
* Bug reports
-@@ -1137,7 +1137,7 @@ Please provide the necessary important i
+@@ -1152,7 +1152,7 @@ Please provide the necessary important i
Consult does not provide Evil integration out of the box, but there is some
support in [[https://github.com/emacs-evil/evil-collection][evil-collection]].
@@ -201,7 +202,7 @@ Forwarded: not-needed
Consult often relies on lambdas and lexical closures.
* Contributions
-@@ -1161,7 +1161,7 @@ small configuration or command snippets.
+@@ -1176,7 +1176,7 @@ small configuration or command snippets.
:description: Contributors and Sources of Inspiration
:end: