From 6f955744e919a5622102a57e4cd0859e64a05740 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external images Forwarded: not-needed Gbp-Pq: Name remove-external-images.patch --- README.org | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.org b/README.org index 1d11ac3..5874131 100644 --- a/README.org +++ b/README.org @@ -6,12 +6,6 @@ #+texinfo_dir_title: Consult: (consult). #+texinfo_dir_desc: Useful commands built on completing-read. -#+html: GNU Emacs -#+html: GNU ELPA -#+html: GNU-devel ELPA -#+html: MELPA -#+html: MELPA Stable - Consult provides practical commands based on the Emacs completion function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command -- cgit v1.2.3 From 4a983345cfb7b61beef61f4b148df6d74dcb8c35 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external pages and debianise Forwarded: not-needed Gbp-Pq: Name replace-external-references-when-possible.patch --- README.org | 74 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/README.org b/README.org index 5874131..df1e21b 100644 --- a/README.org +++ b/README.org @@ -7,7 +7,7 @@ #+texinfo_dir_desc: Useful commands built on completing-read. Consult provides practical commands based on the Emacs completion function -[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of +[[info:elisp#Minibuffer Completion][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command =consult-buffer= to switch between buffers and recently opened files. Furthermore Consult provides multiple search commands, an asynchronous =consult-grep= and @@ -17,17 +17,17 @@ the command =consult-imenu= presents a flat list of the Imenu with [[#live-previ [[#narrowing-and-grouping][grouping and narrowing]]. Please take a look at the [[#available-commands][full list of commands]]. Consult is fully compatible with completion systems based on the standard Emacs -=completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], -[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]] and [[https://github.com/radian-software/selectrum][Selectrum]]. +=completing-read= API, notably the default completion system, Vertico (~apt install vertico~), [[https://github.com/protesilaos/mct][Mct]], +[[info:emacs#Icomplete][Icomplete]] and [[https://github.com/radian-software/selectrum][Selectrum]]. This package keeps the completion system specifics to a minimum. The ability of the Consult commands to work well with arbitrary completion systems is one of the main advantages of the package. Consult fits well into existing setups and it helps you to create a full completion environment out of small and -independent components. Note that, if you use [[https://github.com/abo-abo/swiper#ivy][Ivy]] or [[https://github.com/emacs-helm/helm][Helm]], you probably don't +independent components. Note that, if you use Ivy (~apt install elpa-ivy~) or Helm (~apt install elpa-helm~), you probably don't need Consult, since both packages bring their own Consult-like functionality. -You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with +You can combine the complementary packages Marginalia (~apt install elpa-marginalia~), Embark (~apt install elpa-embark~) and Orderless (~apt install elpa-orderless~) with Consult. Marginalia enriches the completion display with annotations, e.g., documentation strings or file information. The versatile Embark package provides local actions, comparable to a context menu. These actions operate on the @@ -66,7 +66,7 @@ Many commands implement a little known but convenient Emacs feature called type =M-n= and typically Consult will insert the symbol or thing at point into the input. -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see +*TIP:* If you have Marginalia annotators activated, type =M-x ^consult= to see 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. @@ -372,7 +372,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 - either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of + either the [[https://github.com/minad/corfu][Corfu]] or the Company (~apt install elpa-company~) package. There is a technical limitation of =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 @@ -490,7 +490,7 @@ pressing =C-h=. When pressing =C-h= after some prefix key, the =prefix-help-comm 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 -configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically +configuration]]. If which-key (~apt install elpa-which-key~) is installed, the narrowing keys are automatically shown in the which-key window after pressing the =consult-narrow-key=. ** Asynchronous search @@ -684,11 +684,11 @@ since some details may still change. :end: #+cindex: embark -*NOTE*: Install the =embark-consult= package from MELPA, which provides -Consult-specific Embark actions and the Occur buffer export. +*NOTE*: Install the embark-consult package (~apt install elpa-embark-consult~), +which provides Consult-specific Embark actions and the Occur buffer export. Embark is a versatile package which offers context dependent actions, comparable -to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its +to a context menu. See the [[info:embark][Embark manual]] for an extensive description of its capabilities. Actions are commands which can operate on the currently selected candidate (or @@ -708,7 +708,7 @@ the matching lines from =consult-line=, =consult-outline=, =consult-mark= and 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, -if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. +if the wgrep (~apt install elpa-wgrep~) package is installed. These three workflows are symmetric. + =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. @@ -719,14 +719,12 @@ if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is install :description: Example configuration and customization variables :end: -Consult can be installed from [[http://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package -manager. Alternatively it can be directly installed from the development -repository via other non-standard package managers. +Consult can be installed via ~apt install elpa-consult~. There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be contributed. -*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your +*IMPORTANT:* It is strongly recommended that you enable [[info:elisp#Lexical Binding][lexical binding]] in your configuration. Consult relies on lambdas and lexical closures. For this reason many Consult-related snippets require lexical binding. @@ -742,8 +740,8 @@ modes. Therefore the package is non-intrusive but requires a little setup 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. -The configuration shown here relies on the =use-package= macro, which is a -convenient tool to manage package configurations. +The configuration shown here relies on the =use-package= macro (~apt install +elpa-use-package~), which is a convenient tool to manage package configurations. *NOTE:* There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where you can contribute additional configuration examples. @@ -873,7 +871,7 @@ configuration examples. :end: #+cindex: customization -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET +*TIP:* If you have Marginalia installed, type =M-x customize-variable RET ^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. @@ -995,10 +993,12 @@ following techniques: I use and recommend this combination of packages: - consult: This package -- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system -- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates -- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates -- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering +- vertico (~apt install elpa-vertico~): Fast and minimal vertical completion system +- marginalia (~apt install elpa-marginalia~): Annotations for the completion candidates +- embark and embark-consult (~apt install elpa-embark elpa-embark-consult~): + Action commands, which can act on the completion candidates +- orderless (~apt install elpa-orderless~): Completion style which offers + flexible candidate filtering 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 @@ -1014,36 +1014,36 @@ You can integrated Consult with special programs or with other packages in the 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/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 [[https://github.com/company-mode/company-mode][Company]] backends. - [[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://gitlab.com/OlMon/consult-flyspell][consult-flyspell]]: Additional Flyspell integration. - [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. -- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). -- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. +- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client, ~apt install elpa-lsp-mode~). +- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the Notmuch (~apt install notmuch~) email system using Consult. - [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. -- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. +- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with Org-roam (~apt install elpa-org-roam~). - [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. -- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. -- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. +- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional Projectile (~apt install elpa-projectile~) integration and buffer sources. +- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the Recoll (~apt install recoll~) desktop full-text search using Consult. - [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. -- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. +- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet (~apt install elpa-yasnippet elpa-yasnippet-snippets~). - [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. 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 [[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). - [[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. +- 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=. -- [[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. Note that all packages are independent and can be exchanged with alternative @@ -1107,7 +1107,7 @@ Please provide the necessary important information with your bug report: 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]]. -When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. +When evaluating Consult-related code snippets you should enable [[info:elisp#Lexical Binding][lexical binding]]. Consult often relies on lambdas and lexical closures. * Contributions @@ -1131,7 +1131,7 @@ small configuration or command snippets. :description: Contributors and Sources of Inspiration :end: -This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult +This package took inspiration from Counsel (~apt install elpa-counsel~) by Oleh Krehel. Some of the Consult commands originated in the Counsel package or the [[https://github.com/radian-software/selectrum/wiki/Useful-Commands][Selectrum wiki]]. The commands have been rewritten and greatly enhanced in comparison to the original versions. -- cgit v1.2.3 From 2977a20ed269ab6052c5f73a086b1b1411442ea1 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external images Forwarded: not-needed Gbp-Pq: Name remove-external-images.patch --- README.org | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.org b/README.org index 1d11ac3..5874131 100644 --- a/README.org +++ b/README.org @@ -6,12 +6,6 @@ #+texinfo_dir_title: Consult: (consult). #+texinfo_dir_desc: Useful commands built on completing-read. -#+html: GNU Emacs -#+html: GNU ELPA -#+html: GNU-devel ELPA -#+html: MELPA -#+html: MELPA Stable - Consult provides practical commands based on the Emacs completion function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command -- cgit v1.2.3 From daadfb708378c410653d1ad26642b11a6c0add23 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external pages and debianise Forwarded: not-needed Gbp-Pq: Name replace-external-references-when-possible.patch --- README.org | 74 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/README.org b/README.org index 5874131..df1e21b 100644 --- a/README.org +++ b/README.org @@ -7,7 +7,7 @@ #+texinfo_dir_desc: Useful commands built on completing-read. Consult provides practical commands based on the Emacs completion function -[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of +[[info:elisp#Minibuffer Completion][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command =consult-buffer= to switch between buffers and recently opened files. Furthermore Consult provides multiple search commands, an asynchronous =consult-grep= and @@ -17,17 +17,17 @@ the command =consult-imenu= presents a flat list of the Imenu with [[#live-previ [[#narrowing-and-grouping][grouping and narrowing]]. Please take a look at the [[#available-commands][full list of commands]]. Consult is fully compatible with completion systems based on the standard Emacs -=completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], -[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]] and [[https://github.com/radian-software/selectrum][Selectrum]]. +=completing-read= API, notably the default completion system, Vertico (~apt install vertico~), [[https://github.com/protesilaos/mct][Mct]], +[[info:emacs#Icomplete][Icomplete]] and [[https://github.com/radian-software/selectrum][Selectrum]]. This package keeps the completion system specifics to a minimum. The ability of the Consult commands to work well with arbitrary completion systems is one of the main advantages of the package. Consult fits well into existing setups and it helps you to create a full completion environment out of small and -independent components. Note that, if you use [[https://github.com/abo-abo/swiper#ivy][Ivy]] or [[https://github.com/emacs-helm/helm][Helm]], you probably don't +independent components. Note that, if you use Ivy (~apt install elpa-ivy~) or Helm (~apt install elpa-helm~), you probably don't need Consult, since both packages bring their own Consult-like functionality. -You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with +You can combine the complementary packages Marginalia (~apt install elpa-marginalia~), Embark (~apt install elpa-embark~) and Orderless (~apt install elpa-orderless~) with Consult. Marginalia enriches the completion display with annotations, e.g., documentation strings or file information. The versatile Embark package provides local actions, comparable to a context menu. These actions operate on the @@ -66,7 +66,7 @@ Many commands implement a little known but convenient Emacs feature called type =M-n= and typically Consult will insert the symbol or thing at point into the input. -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see +*TIP:* If you have Marginalia annotators activated, type =M-x ^consult= to see 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. @@ -372,7 +372,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 - either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of + either the [[https://github.com/minad/corfu][Corfu]] or the Company (~apt install elpa-company~) package. There is a technical limitation of =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 @@ -490,7 +490,7 @@ pressing =C-h=. When pressing =C-h= after some prefix key, the =prefix-help-comm 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 -configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically +configuration]]. If which-key (~apt install elpa-which-key~) is installed, the narrowing keys are automatically shown in the which-key window after pressing the =consult-narrow-key=. ** Asynchronous search @@ -684,11 +684,11 @@ since some details may still change. :end: #+cindex: embark -*NOTE*: Install the =embark-consult= package from MELPA, which provides -Consult-specific Embark actions and the Occur buffer export. +*NOTE*: Install the embark-consult package (~apt install elpa-embark-consult~), +which provides Consult-specific Embark actions and the Occur buffer export. Embark is a versatile package which offers context dependent actions, comparable -to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its +to a context menu. See the [[info:embark][Embark manual]] for an extensive description of its capabilities. Actions are commands which can operate on the currently selected candidate (or @@ -708,7 +708,7 @@ the matching lines from =consult-line=, =consult-outline=, =consult-mark= and 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, -if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. +if the wgrep (~apt install elpa-wgrep~) package is installed. These three workflows are symmetric. + =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. @@ -719,14 +719,12 @@ if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is install :description: Example configuration and customization variables :end: -Consult can be installed from [[http://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package -manager. Alternatively it can be directly installed from the development -repository via other non-standard package managers. +Consult can be installed via ~apt install elpa-consult~. There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be contributed. -*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your +*IMPORTANT:* It is strongly recommended that you enable [[info:elisp#Lexical Binding][lexical binding]] in your configuration. Consult relies on lambdas and lexical closures. For this reason many Consult-related snippets require lexical binding. @@ -742,8 +740,8 @@ modes. Therefore the package is non-intrusive but requires a little setup 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. -The configuration shown here relies on the =use-package= macro, which is a -convenient tool to manage package configurations. +The configuration shown here relies on the =use-package= macro (~apt install +elpa-use-package~), which is a convenient tool to manage package configurations. *NOTE:* There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where you can contribute additional configuration examples. @@ -873,7 +871,7 @@ configuration examples. :end: #+cindex: customization -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET +*TIP:* If you have Marginalia installed, type =M-x customize-variable RET ^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. @@ -995,10 +993,12 @@ following techniques: I use and recommend this combination of packages: - consult: This package -- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system -- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates -- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates -- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering +- vertico (~apt install elpa-vertico~): Fast and minimal vertical completion system +- marginalia (~apt install elpa-marginalia~): Annotations for the completion candidates +- embark and embark-consult (~apt install elpa-embark elpa-embark-consult~): + Action commands, which can act on the completion candidates +- orderless (~apt install elpa-orderless~): Completion style which offers + flexible candidate filtering 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 @@ -1014,36 +1014,36 @@ You can integrated Consult with special programs or with other packages in the 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/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 [[https://github.com/company-mode/company-mode][Company]] backends. - [[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://gitlab.com/OlMon/consult-flyspell][consult-flyspell]]: Additional Flyspell integration. - [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. -- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). -- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. +- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client, ~apt install elpa-lsp-mode~). +- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the Notmuch (~apt install notmuch~) email system using Consult. - [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. -- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. +- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with Org-roam (~apt install elpa-org-roam~). - [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. -- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. -- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. +- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional Projectile (~apt install elpa-projectile~) integration and buffer sources. +- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the Recoll (~apt install recoll~) desktop full-text search using Consult. - [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. -- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. +- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet (~apt install elpa-yasnippet elpa-yasnippet-snippets~). - [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. 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 [[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). - [[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. +- 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=. -- [[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. Note that all packages are independent and can be exchanged with alternative @@ -1107,7 +1107,7 @@ Please provide the necessary important information with your bug report: 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]]. -When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. +When evaluating Consult-related code snippets you should enable [[info:elisp#Lexical Binding][lexical binding]]. Consult often relies on lambdas and lexical closures. * Contributions @@ -1131,7 +1131,7 @@ small configuration or command snippets. :description: Contributors and Sources of Inspiration :end: -This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult +This package took inspiration from Counsel (~apt install elpa-counsel~) by Oleh Krehel. Some of the Consult commands originated in the Counsel package or the [[https://github.com/radian-software/selectrum/wiki/Useful-Commands][Selectrum wiki]]. The commands have been rewritten and greatly enhanced in comparison to the original versions. -- cgit v1.2.3 From 9fec2e4b71bff5f00a9a5581cbbb5360bd3da102 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external images Forwarded: not-needed Gbp-Pq: Name remove-external-images.patch --- README.org | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.org b/README.org index 8f465af..d042f9b 100644 --- a/README.org +++ b/README.org @@ -6,12 +6,6 @@ #+texinfo_dir_title: Consult: (consult). #+texinfo_dir_desc: Useful commands built on completing-read. -#+html: GNU Emacs -#+html: GNU ELPA -#+html: GNU-devel ELPA -#+html: MELPA -#+html: MELPA Stable - Consult provides practical commands based on the Emacs completion function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command -- cgit v1.2.3 From c69c54b23bb32c565eb6f9e2a3d111a4cd9c6387 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external pages and debianise Forwarded: not-needed Gbp-Pq: Name replace-external-references-when-possible.patch --- README.org | 72 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/README.org b/README.org index d042f9b..02bdb18 100644 --- a/README.org +++ b/README.org @@ -7,7 +7,7 @@ #+texinfo_dir_desc: Useful commands built on completing-read. Consult provides practical commands based on the Emacs completion function -[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of +[[info:elisp#Minibuffer Completion][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command =consult-buffer= to switch between buffers and recently opened files. Furthermore Consult provides multiple search commands, an asynchronous =consult-grep= and @@ -17,8 +17,8 @@ the command =consult-imenu= presents a flat list of the Imenu with [[#live-previ [[#narrowing-and-grouping][grouping and narrowing]]. Please take a look at the [[#available-commands][full list of commands]]. Consult is fully compatible with completion systems centered around the standard -Emacs =completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], -and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]]. +Emacs =completing-read= API, notably the default completion system, Vertico (~apt install elpa-vertico~), [[https://github.com/protesilaos/mct][Mct]], +and [[info:emacs#Icomplete][Icomplete]]. This package keeps the completion system specifics to a minimum. The ability of the Consult commands to work well with arbitrary completion systems is one of @@ -26,7 +26,7 @@ the main advantages of the package. Consult fits well into existing setups and it helps you to create a full completion environment out of small and independent components. -You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with +You can combine the complementary packages Marginalia (~apt install elpa-marginalia~), Embark (~apt install elpa-embark~) and Orderless (~apt install elpa-orderless~) with Consult. Marginalia enriches the completion display with annotations, e.g., documentation strings or file information. The versatile Embark package provides local actions, comparable to a context menu. These actions operate on the @@ -65,7 +65,7 @@ Many commands implement a little known but convenient Emacs feature called type =M-n= and typically Consult will insert the symbol or thing at point into the input. -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see +*TIP:* If you have Marginalia annotators activated, type =M-x ^consult= to see 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. @@ -369,7 +369,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 - either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of + either the [[https://github.com/minad/corfu][Corfu]] or the Company (~apt install elpa-company~) package. There is a technical limitation of =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 @@ -487,7 +487,7 @@ pressing =C-h=. When pressing =C-h= after some prefix key, the =prefix-help-comm 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 -configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically +configuration]]. If which-key (~apt install elpa-which-key~) is installed, the narrowing keys are automatically shown in the which-key window after pressing the =consult-narrow-key=. ** Asynchronous search @@ -681,11 +681,11 @@ since some details may still change. :end: #+cindex: embark -*NOTE*: Install the =embark-consult= package from MELPA, which provides -Consult-specific Embark actions and the Occur buffer export. +*NOTE*: Install the embark-consult package (~apt install elpa-embark-consult~), +which provides Consult-specific Embark actions and the Occur buffer export. Embark is a versatile package which offers context dependent actions, comparable -to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its +to a context menu. See the [[info:embark][Embark manual]] for an extensive description of its capabilities. Actions are commands which can operate on the currently selected candidate (or @@ -705,7 +705,7 @@ the matching lines from =consult-line=, =consult-outline=, =consult-mark= and 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, -if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. +if the wgrep (~apt install elpa-wgrep~) package is installed. These three workflows are symmetric. + =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. @@ -716,14 +716,12 @@ if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is install :description: Example configuration and customization variables :end: -Consult can be installed from [[https://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package -manager. Alternatively it can be directly installed from the development -repository via other non-standard package managers. +Consult can be installed via ~apt install elpa-consult~. There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be contributed. -*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your +*IMPORTANT:* It is strongly recommended that you enable [[info:elisp#Lexical Binding][lexical binding]] in your configuration. Consult relies on lambdas and lexical closures. For this reason many Consult-related snippets require lexical binding. @@ -739,8 +737,8 @@ modes. Therefore the package is non-intrusive but requires a little setup 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. -The configuration shown here relies on the =use-package= macro, which is a -convenient tool to manage package configurations. +The configuration shown here relies on the =use-package= macro (~apt install +elpa-use-package~), which is a convenient tool to manage package configurations. *NOTE:* There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where you can contribute additional configuration examples. @@ -870,7 +868,7 @@ configuration examples. :end: #+cindex: customization -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET +*TIP:* If you have Marginalia installed, type =M-x customize-variable RET ^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. @@ -992,10 +990,12 @@ following techniques: I use and recommend this combination of packages: - consult: This package -- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system -- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates -- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates -- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering +- vertico (~apt install elpa-vertico~): Fast and minimal vertical completion system +- marginalia (~apt install elpa-marginalia~): Annotations for the completion candidates +- embark and embark-consult (~apt install elpa-embark elpa-embark-consult~): + Action commands, which can act on the completion candidates +- orderless (~apt install elpa-orderless~): Completion style which offers + flexible candidate filtering 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 @@ -1010,36 +1010,36 @@ You can integrated Consult with special programs or with other packages in the 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/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 [[https://github.com/company-mode/company-mode][Company]] backends. - [[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://gitlab.com/OlMon/consult-flyspell][consult-flyspell]]: Additional Flyspell integration. - [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. -- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). -- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. +- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client, ~apt install elpa-lsp-mode~). +- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the Notmuch (~apt install notmuch~) email system using Consult. - [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. -- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. +- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with Org-roam (~apt install elpa-org-roam~). - [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. -- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. -- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. +- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional Projectile (~apt install elpa-projectile~) integration and buffer sources. +- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the Recoll (~apt install recoll~) desktop full-text search using Consult. - [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. -- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. +- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet (~apt install elpa-yasnippet elpa-yasnippet-snippets~). - [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. 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 [[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). - [[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. +- 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=. -- [[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. Note that all packages are independent and can be exchanged with alternative @@ -1103,7 +1103,7 @@ Please provide the necessary important information with your bug report: 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]]. -When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. +When evaluating Consult-related code snippets you should enable [[info:elisp#Lexical Binding][lexical binding]]. Consult often relies on lambdas and lexical closures. * Contributions @@ -1127,7 +1127,7 @@ small configuration or command snippets. :description: Contributors and Sources of Inspiration :end: -This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult +This package took inspiration from Counsel (~apt install elpa-counsel~) by Oleh Krehel. Some of the Consult commands originated in the Counsel package or the wiki of the Selectrum package. This package exists only thanks to the help of these great contributors and thanks to the feedback of many users. Thank you! -- cgit v1.2.3 From 5e5141bb1ec9c34bc38c117e040b978d09735288 Mon Sep 17 00:00:00 2001 From: Lev Lamberov Date: Tue, 7 Feb 2023 05:58:38 +0100 Subject: Import consult-el_0.32-1.debian.tar.xz [dgit import tarball consult-el 0.32-1 consult-el_0.32-1.debian.tar.xz] --- changelog | 33 ++++ clean | 4 + control | 31 +++ copyright | 28 +++ doc-base | 15 ++ docs | 1 + elpa | 1 + gbp.conf | 3 + info | 1 + install | 2 + patches/remove-external-images.patch | 20 ++ ...replace-external-references-when-possible.patch | 212 +++++++++++++++++++++ patches/series | 2 + rules | 7 + source/format | 1 + watch | 4 + 16 files changed, 365 insertions(+) create mode 100644 changelog create mode 100644 clean create mode 100644 control create mode 100644 copyright create mode 100644 doc-base create mode 100644 docs create mode 100644 elpa create mode 100644 gbp.conf create mode 100644 info create mode 100755 install create mode 100644 patches/remove-external-images.patch create mode 100644 patches/replace-external-references-when-possible.patch create mode 100644 patches/series create mode 100755 rules create mode 100644 source/format create mode 100644 watch diff --git a/changelog b/changelog new file mode 100644 index 0000000..085bbe5 --- /dev/null +++ b/changelog @@ -0,0 +1,33 @@ +consult-el (0.32-1) unstable; urgency=medium + + [ Aymeric Agon-Rambosson ] + * New upstream release. + * Refresh patches. + * d/control: Bump Standards-Version to 4.6.2 (no changes required). + + [ Lev Lamberov ] + * Team upload. + * Add gbp.conf to handle upstream version tags and pristine-tar. + + -- Lev Lamberov Tue, 07 Feb 2023 09:58:38 +0500 + +consult-el (0.20-1) unstable; urgency=medium + + * New upstream release. + * Add explicit emacs recommends to elpa-consult. + * Correct d/clean. + * Refresh patches. + + -- Aymeric Agon-Rambosson Sun, 16 Oct 2022 20:50:02 +0200 + +consult-el (0.19-2) unstable; urgency=medium + + * Source-only upload. + + -- Sean Whitton Fri, 07 Oct 2022 18:36:17 -0700 + +consult-el (0.19-1) unstable; urgency=medium + + * Initial release (Closes: #1016946). + + -- Aymeric Agon-Rambosson Tue, 04 Oct 2022 19:28:07 +0200 diff --git a/clean b/clean new file mode 100644 index 0000000..59c1149 --- /dev/null +++ b/clean @@ -0,0 +1,4 @@ +# Removing produced texi, info and html files +consult.texi +consult.info* +consult.html* diff --git a/control b/control new file mode 100644 index 0000000..043fcfb --- /dev/null +++ b/control @@ -0,0 +1,31 @@ +Source: consult-el +Section: editors +Priority: optional +Maintainer: Debian Emacsen team +Uploaders: Aymeric Agon-Rambosson +Build-Depends: debhelper-compat (= 13), + dh-elpa, + dh-exec, + texinfo, + elpa-htmlize, +Standards-Version: 4.6.2 +Homepage: https://github.com/minad/consult +Rules-Requires-Root: no +Vcs-Browser: https://salsa.debian.org/emacsen-team/consult-el +Vcs-Git: https://salsa.debian.org/emacsen-team/consult-el.git + +Package: elpa-consult +Architecture: all +Depends: ${elpa:Depends}, ${misc:Depends} +Recommends: elpa-vertico, elpa-embark-consult, emacs +Enhances: emacs +Description: Useful commands based on completing-read for Emacs + Consult provides practical commands based on the Emacs completion function + completing-read. Completion allows you to quickly select an item from a list of + candidates. Consult offers in particular an advanced buffer switching command + consult-buffer to switch between buffers and recently opened files. Furthermore + Consult provides multiple search commands, an asynchronous consult-grep and + consult-ripgrep, and the line-based search command consult-line. Some of the + Consult commands are enhanced versions of built-in Emacs commands. For example + the command consult-imenu presents a flat list of the Imenu with live preview, + grouping and narrowing. Please take a look at the full list of commands. diff --git a/copyright b/copyright new file mode 100644 index 0000000..a99cb5c --- /dev/null +++ b/copyright @@ -0,0 +1,28 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: consult +Source: https://github.com/minad/consult + +Files: * +Copyright: (C) 2021, 2022 Free Software Foundation, Inc. +License: GPL-3+ + +Files: debian/* +Copyright: (C) 2022 Aymeric Agon-Rambosson +License: GPL-3+ + +License: GPL-3+ + 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 . + . + On Debian systems, the complete text of the GNU General + Public License version 3 can be found in `/usr/share/common-licenses/GPL-3' diff --git a/doc-base b/doc-base new file mode 100644 index 0000000..064321f --- /dev/null +++ b/doc-base @@ -0,0 +1,15 @@ +Document: consult-documentation +Title: Consult documentation +Author: Daniel Mendler +Abstract: This manual describes what consult is + and how it can provide practical improved commands + to emacs. +Section: Editors + +Format: HTML +Index: /usr/share/doc/elpa-consult/consult.html +Files: /usr/share/doc/elpa-consult/consult.html + +Format: Info +Index: /usr/share/info/consult.info.gz +Files: /usr/share/info/consult.info.gz diff --git a/docs b/docs new file mode 100644 index 0000000..449bc41 --- /dev/null +++ b/docs @@ -0,0 +1 @@ +consult.html diff --git a/elpa b/elpa new file mode 100644 index 0000000..abf136d --- /dev/null +++ b/elpa @@ -0,0 +1 @@ +*.el diff --git a/gbp.conf b/gbp.conf new file mode 100644 index 0000000..f29c043 --- /dev/null +++ b/gbp.conf @@ -0,0 +1,3 @@ +[DEFAULT] +upstream-tag = %(version)s +pristine-tar = False diff --git a/info b/info new file mode 100644 index 0000000..b84c699 --- /dev/null +++ b/info @@ -0,0 +1 @@ +consult.info diff --git a/install b/install new file mode 100755 index 0000000..1f8a4f6 --- /dev/null +++ b/install @@ -0,0 +1,2 @@ +#!/usr/bin/dh-exec +CHANGELOG.org => usr/share/doc/elpa-consult/NEWS \ No newline at end of file diff --git a/patches/remove-external-images.patch b/patches/remove-external-images.patch new file mode 100644 index 0000000..8e5e963 --- /dev/null +++ b/patches/remove-external-images.patch @@ -0,0 +1,20 @@ +From: Aymeric Agon-Rambosson +Date: Wed, 10 Aug 2022 04:55:32 +0200 +Subject: Drop references to external images +Forwarded: not-needed + +--- a/README.org ++++ b/README.org +@@ -6,12 +6,6 @@ + #+texinfo_dir_title: Consult: (consult). + #+texinfo_dir_desc: Useful commands built on completing-read. + +-#+html: GNU Emacs +-#+html: GNU ELPA +-#+html: GNU-devel ELPA +-#+html: MELPA +-#+html: MELPA Stable +- + Consult provides search and navigation commands based on the Emacs completion + function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a + list of candidates. Consult offers asynchronous and interactive =consult-grep= and diff --git a/patches/replace-external-references-when-possible.patch b/patches/replace-external-references-when-possible.patch new file mode 100644 index 0000000..9d6136c --- /dev/null +++ b/patches/replace-external-references-when-possible.patch @@ -0,0 +1,212 @@ +From: Aymeric Agon-Rambosson +Date: Wed, 10 Aug 2022 04:55:32 +0200 +Subject: Drop references to external pages and debianise +Forwarded: not-needed + +--- a/README.org ++++ b/README.org +@@ -7,7 +7,7 @@ + #+texinfo_dir_desc: Useful commands built on completing-read. + + Consult provides search and navigation commands based on the Emacs completion +-function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a ++function [[info:elisp#Minibuffer Completion][completing-read]]. Completion allows you to quickly select an item from a + list of candidates. Consult offers asynchronous and interactive =consult-grep= and + =consult-ripgrep= commands, and the line-based search command =consult-line=. + Furthermore Consult provides an advanced buffer switching command =consult-buffer= +@@ -18,8 +18,8 @@ presents a flat list of the Imenu with [ + Please take a look at the [[#available-commands][full list of commands]]. + + Consult is fully compatible with completion systems centered around the standard +-Emacs =completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], +-and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]]. ++Emacs =completing-read= API, notably the default completion system, Vertico (~apt install elpa-vertico~), [[https://github.com/protesilaos/mct][Mct]], ++and [[info:emacs#Icomplete][Icomplete]]. + + This package keeps the completion system specifics to a minimum. The ability of + the Consult commands to work well with arbitrary completion systems is one of +@@ -27,7 +27,7 @@ the main advantages of the package. Cons + it helps you to create a full completion environment out of small and + independent components. + +-You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with ++You can combine the complementary packages Marginalia (~apt install elpa-marginalia~), Embark (~apt install elpa-embark~) and Orderless (~apt install elpa-orderless~) with + Consult. Marginalia enriches the completion display with annotations, e.g., + documentation strings or file information. The versatile Embark package provides + local actions, comparable to a context menu. These actions operate on the +@@ -66,7 +66,7 @@ Many commands implement a little known b + type =M-n= and typically Consult will insert the symbol or thing at point into + the input. + +-*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see ++*TIP:* If you have Marginalia annotators activated, type =M-x ^consult= to see + 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. + #+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 +- either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of ++ either the [[https://github.com/minad/corfu][Corfu]] or the Company (~apt install elpa-company~) package. There is a technical limitation of + =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 + 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 +-configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically ++configuration]]. If which-key (~apt install elpa-which-key~) is installed, the narrowing keys are automatically + shown in the which-key window after pressing the =consult-narrow-key=. + + ** Asynchronous search +@@ -702,11 +702,11 @@ since some details may still change. + :end: + #+cindex: embark + +-*NOTE*: Install the =embark-consult= package from MELPA, which provides +-Consult-specific Embark actions and the Occur buffer export. ++*NOTE*: Install the embark-consult package (~apt install elpa-embark-consult~), ++which provides Consult-specific Embark actions and the Occur buffer export. + + Embark is a versatile package which offers context dependent actions, comparable +-to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its ++to a context menu. See the [[info:embark][Embark manual]] for an extensive description of its + capabilities. + + Actions are commands which can operate on the currently selected candidate (or +@@ -726,7 +726,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, +-if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. ++if the wgrep (~apt install elpa-wgrep~) package is installed. These three workflows are symmetric. + + + =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 + :description: Example configuration and customization variables + :end: + +-Consult can be installed from [[https://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package +-manager. Alternatively it can be directly installed from the development +-repository via other non-standard package managers. ++Consult can be installed via ~apt install elpa-consult~. + + There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be + contributed. + +-*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your ++*IMPORTANT:* It is strongly recommended that you enable [[info:elisp#Lexical Binding][lexical binding]] in your + 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 + 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. +-The configuration shown here relies on the =use-package= macro, which is a +-convenient tool to manage package configurations. ++The configuration shown here relies on the =use-package= macro (~apt install ++elpa-use-package~), which is a convenient tool to manage package configurations. + + *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. + :end: + #+cindex: customization + +-*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET ++*TIP:* If you have Marginalia installed, type =M-x customize-variable RET + ^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: + I use and recommend this combination of packages: + + - consult: This package +-- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system +-- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates +-- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates +-- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering ++- vertico (~apt install elpa-vertico~): Fast and minimal vertical completion system ++- marginalia (~apt install elpa-marginalia~): Annotations for the completion candidates ++- embark and embark-consult (~apt install elpa-embark elpa-embark-consult~): ++ Action commands, which can act on the completion candidates ++- orderless (~apt install elpa-orderless~): Completion style which offers ++ flexible candidate filtering + + 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 + 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/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://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. + - [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. +-- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). +-- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. ++- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client, ~apt install elpa-lsp-mode~). ++- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the Notmuch (~apt install notmuch~) email system using Consult. + - [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. +-- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. ++- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with Org-roam (~apt install elpa-org-roam~). + - [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. +-- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. +-- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. ++- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional Projectile (~apt install elpa-projectile~) integration and buffer sources. ++- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the Recoll (~apt install elpa-recoll~) desktop full-text search using Consult. + - [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. +-- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. ++- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet (~apt install elpa-yasnippet elpa-yasnippet-snippets~). + - [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. + + 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 [[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). + - [[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. ++- 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=. +-- [[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. + + * Bug reports +@@ -1137,7 +1137,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]]. + +-When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. ++When evaluating Consult-related code snippets you should enable [[info:elisp#Lexical Binding][lexical binding]]. + Consult often relies on lambdas and lexical closures. + + * Contributions +@@ -1161,7 +1161,7 @@ small configuration or command snippets. + :description: Contributors and Sources of Inspiration + :end: + +-This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult ++This package took inspiration from Counsel (~apt install elpa-counsel~) by Oleh Krehel. Some of the Consult + commands originated in the Counsel package or the wiki of the Selectrum package. + This package exists only thanks to the help of these great contributors and + thanks to the feedback of many users. Thank you! diff --git a/patches/series b/patches/series new file mode 100644 index 0000000..02a27c4 --- /dev/null +++ b/patches/series @@ -0,0 +1,2 @@ +remove-external-images.patch +replace-external-references-when-possible.patch diff --git a/rules b/rules new file mode 100755 index 0000000..4e43d97 --- /dev/null +++ b/rules @@ -0,0 +1,7 @@ +#!/usr/bin/make -f + +%: + dh $@ --with elpa + +override_dh_auto_build: + emacs -q --batch -l htmlize README.org -f org-texinfo-export-to-info -f org-html-export-to-html diff --git a/source/format b/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/watch b/watch new file mode 100644 index 0000000..787152d --- /dev/null +++ b/watch @@ -0,0 +1,4 @@ +version=4 +opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE@-$1.tar.gz%" \ + https://github.com/minad/consult/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate -- cgit v1.2.3 From 94666a323783fbeabd45266ad21e20ac52ddf5f1 Mon Sep 17 00:00:00 2001 From: Lev Lamberov Date: Tue, 7 Feb 2023 05:58:38 +0100 Subject: Import consult-el_0.32.orig.tar.gz [dgit import orig consult-el_0.32.orig.tar.gz] --- CHANGELOG.org | 297 +++ LICENSE | 674 +++++++ README.org | 1250 +++++++++++++ consult-compile.el | 127 ++ consult-flymake.el | 117 ++ consult-icomplete.el | 55 + consult-imenu.el | 264 +++ consult-info.el | 181 ++ consult-kmacro.el | 92 + consult-org.el | 129 ++ consult-register.el | 326 ++++ consult-vertico.el | 63 + consult-xref.el | 120 ++ consult.el | 5033 ++++++++++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 8728 insertions(+) create mode 100644 CHANGELOG.org create mode 100644 LICENSE create mode 100644 README.org create mode 100644 consult-compile.el create mode 100644 consult-flymake.el create mode 100644 consult-icomplete.el create mode 100644 consult-imenu.el create mode 100644 consult-info.el create mode 100644 consult-kmacro.el create mode 100644 consult-org.el create mode 100644 consult-register.el create mode 100644 consult-vertico.el create mode 100644 consult-xref.el create mode 100644 consult.el diff --git a/CHANGELOG.org b/CHANGELOG.org new file mode 100644 index 0000000..9202293 --- /dev/null +++ b/CHANGELOG.org @@ -0,0 +1,297 @@ +#+title: consult.el - Changelog +#+author: Daniel Mendler +#+language: en + +* Version 0.32 (2023-02-06) + +- Bugfixes +- Update the 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=. +- 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 + Debian stable. +- =consult-ripgrep-args=: Add =--search-zip= option to automatically search through + compressed files. This will allow you to search Elisp files bundled with your + Emacs installation. Move to an Elisp library via =find-library=, then invoke + =consult-ripgrep=. +- Drop obsolete =consult-apropos=. Alternatives: =describe-symbol= in combination + with =embark-export=. See also =consult-info= and =consult-ripgrep= to search + through info manuals and Elisp source code. +- Drop obsolete =consult-multi-occur=. Alternative: Built-in =multi-occur=, + =multi-occur-in-matching-buffers= or =consult-line-multi=. +- Drop obsolete =consult-file-externally=. The command has been moved to Embark + under the name =embark-open-externally=. + +* Version 0.31 (2023-01-06) + +- Version bump to update the Compat package dependency (29.1.0.1) + +* Version 0.30 (2023-01-02) + +- Bugfixes +- Drop Selectrum support +- Deprecate =consult-file-externally= in favor of =embark-open-externally= +- Deprecate =consult-multi-occur=. The =multi-occur= command should be improved + upstream to take advantage of =completing-read-multiple=. Consult provides the + command =consult-line-multi= as an alternative. +- =consult-history=: Use input as initial completion input + +* Version 0.29 (2022-12-03) + +- Bugfixes +- =consult-line-multi= has been rewritten completely. The candidates are computed + on demand based on the input. This reduces startup speed greatly. The command + behaves like =consult-grep=, but operates on buffers instead of files. +- Add =consult--source-file-register=, and make the registers available in + =consult-buffer=. Registers are often used as quick access keys for files, e.g., + =(add-to-list 'register-alist '(?i file . "~/.emacs.d/init.el")))=. +- Remove obsolete =consult-line-point-placement= +- =consult-grep/find=: Always show directory in the prompt +- Add variable =consult-yank-rotate=, =consult-yank-from-kill-ring= rotates kill ring +- Emacs 29: =consult-register= supports =buffer= register type +- Emacs 29: Support =outline-search-function= +- Org 9.6: Support new =org-fold-core= API (both overlays and text-properties) +- Support abbreviated file names in =recentf-list=, see =recentf-filename-handler=. +- Deprecate =consult-apropos= + +* Version 0.20 (2022-10-16) + +- Bugfixes +- Allow =consult-*-args= to be a string, or a list of strings or expressions. +- Introduce face =consult-highlight-match= to highlight grep matches in the + completion buffer. +- Highlight full matches in =consult-line=, =consult-outline=, =consult-*grep= and + =consult-flymake=. +- Remove face =consult-preview-error=. +- Deprecate =consult-line-point-placement= in favor of more general + =consult-point-placement=, which is also used by the =consult-*grep= commands. +- =consult-imenu=: Support imenu-after-jump-hook and non-default + =imenu-default-goto-function= +- =consult-history=: Add support for history index variables, which are updated + after selection. +- Deprecate support for Selectrum in favor of Vertico. If you use Selectrum + consider switching to Vertico, Icomplete, Mct or default completion. + +* Version 0.19 (2022-09-09) + +- Bugfixes +- Allow =consult-flymake= to work across all buffers in a project +- Remove deprecated =consult-completing-read-multiple= +- =consult-grep/git-grep/ripgrep=: Add =--fixed-strings= support +- =consult-grep=: Respect =grep-find-ignored-directories/files= +- =consult-org-heading=: Add tags to completion candidates +- Add =consult-preview-excluded-files= +- =consult-themes=: Support regexps + +* Version 0.18 (2022-05-25) + +- Bugfixes +- Removed obsolete =consult-recent-file-filter= and =consult-preview-excluded-hooks= +- Deprecate =consult-completing-read-multiple=. See #567 for details. +- Add =consult--source-modified-buffer= + +* Version 0.17 (2022-04-22) + +- Bugfixes +- Drop Emacs 26 support. +- =consult-goto-line=: Use =goto-line-history= on Emacs 28. +- =consult-customize=: Evaluate settings at runtime. This change makes it possible + to use =thing-at-point= to overwrite the =:initial= and =:add-history= settings. +- Rename =consult--read-config= to =consult--customize-alist= and change the format. + The configuration is an alist. The car must be a command symbol. The cdr must + be a plist of keys and expressions, where the expressions evaluate to the + actual configuration values. +- Mode hooks in previewed file buffers are delayed. The buffer is only fully + initialized when leaving the minibuffer for recursive editing. +- Increase =consult-preview-raw-size=. +- Replace =consult-preview-excluded-hooks= by =consult-preview-allowed-hooks=. +- Add =consult-preview-variables= to bind variables for file preview. +- BREAKING API CHANGE of =consult--read=, =consult--prompt=, =consult--multi=: The + state function protocol changed. The function gets notified of more completion + state changes. See the docstring of =consult--with-preview= for details. +- BREAKING API CHANGE of =consult--read=: The lookup function protocol changed. + The function must now accept four or more arguments. +- Remove unused =consult-preview-map=. +- Remove unnecessary =consult-recent-file-filter=. Use =recentf-exclude= instead. +- =consult--multi= sources can have a =:new= function to create candidates. + When narrowed to a source, new candidates will be created by calling the + respective =:new= function. +- =consult--multi= returns =:match= information. =:match= can be nil, t, or new, + depending on if the candidate does not exist, exists or has been created. +- =consult-locate= treats the input literally to take advantage of the db index. + +* Version 0.16 (2022-03-08) + +- Bugfixes +- Deprecate =consult-project-root-function= in favor of =consult-project-function=. +- Preconfigure =consult-project-function= with a default function based + on project.el. +- Add =consult-project-buffer=, a variant of =consult-buffer= restricted to the + current project. +- Add =consult-register-prefix= option. +- Introduced a generic and extensible =consult-register= implementation. +- Lazy marker creation in =consult-line/outline= (performance improvements) + +* Version 0.15 (2022-01-31) + +- Bugfixes +- =consult-xref=: Prettify the group titles, use =xref--group-name-for-display= + if available. +- =consult-focus-lines=: Thanks to @jdtsmith, the command is much faster and + actually useable in large files. +- Added Mct integration, auto refreshing of asynchronous Consult commands. + +* Version 0.14 (2021-12-31) + +- Bugfixes +- Add =consult-recent-file-filter= +- Rename =consult--source-(project-)file= to =consult-source-(project-)recent-file= +- =consult-keep-lines= makes read-only buffers temporarily writable if confirmed + +* Version 0.13 (2021-11-12) + +- Bugfixes +- =consult-register=: Add support for file register values. +- Rename =consult-isearch= to =consult-isearch-history=. The command is a history + browsing command and not a replacement for Isearch. +- =consult-grep= support -[ABC] grep options +- Add =consult-grep-context= face + +* Version 0.12 (2021-10-11) + +- Bugfixes +- Removed obsolete =consult-project-imenu= and =consult-x-command= variables +- =consult-grep=: Use ~--null~ argument to support file names with colons + +* Version 0.11 (2021-08-18) + +- Bugfixes only + +* Version 0.10 (2021-08-11) + +- =consult-mark=, =consult-global-mark=: Add optional marker list argument +- =consult-completing-read-multiple=: New function +- Rename =consult-project-imenu= to =consult-imenu-multi= +- Add =consult-line-multi= to search multiple buffers +- Removed obsolete =consult-yank=, =consult-async-default-split=, =consult-config= +- =consult-ripgrep=: Use =--smart-case= +- =consult-grep/git-grep=: Use =--ignore-case= +- Deprecate =consult--command= in favor of =consult--config.= +- =consult-find=: Use regular expressions instead of globbing/wildcards by default. + Due to the changes to =consult-find= it is not possible anymore to configure + =fd= as backend for =consult-find=. A replacement is documented in the wiki. +- =consult-find/locate/man=: Add highlighting to the matching file/man page names. +- =consult-grep/git-grep/ripgrep/find/locate=: Add support for multiple unordered + patterns. Each of the input patterns must be matched. For example, + =consult-find= transforms the input "first second third" to "first -and second + -and third". +- =consult-grep/git-grep/ripgrep=: Compute the highlighting based on the input, + instead of relying on the ANSI-escaped output. This works better with multiple + patterns, but may occasionally produce false highlighting. +- Deprecate =consult-x-command= configuration variables in favor of =consult-x-args=. + The variables have been renamed since the configuration format changed. +- =consult-async-split-styles-alist=: Remove the =space= splitting style, since + it has been obsoleted by the support for multiple unordered patterns. + +* Version 0.9 (2021-06-22) + +- Add =consult-preview-excluded-hooks= +- =consult--read/consult--prompt=: Add =:inherit-input-method= argument +- Add debouncing support for preview + +* Version 0.8 (2021-05-30) + +- Async commands: Do not fix vertical height in Selectrum. +- =consult-imenu=: Deduplicate items (some imenu backends generate duplicates). +- =consult-org-heading=: Deduplicate items. +- =consult-buffer-filter=: Hide more buffers. +- =consult-line=: Matching line preview overlay only in the selected window. +- =consult-yank/completion-in-region=: Insertion preview only in selected window. +- =consult-yank=: Rename to =consult-yank-from-kill-ring= (Emacs 28 naming). +- =consult-yank= commands: =delete-selection-mode= support, added properties. +- =consult-preview-at-point=, =consult-preview-at-point-mode=: New command and + minor mode to preview candidate at point in =*Completions*= buffer. +- Add =consult-async-split-style= and =consult-async-split-styles-alist=. +- =consult-async-default-split=: Obsoleted in favor of =consult-async-split-style=. +- Deprecate =consult-config= in favor of new =consult-customize= macro. +- =consult-buffer=: Enable previews for files and bookmarks by default. +- =consult-buffer=/=consult--multi=: Add support for =:preview-key= per source. +- =consult-buffer=: Push visible buffers down in the buffer list. +- =consult-flycheck=: Moved to separate repository prior to ELPA submission. +- Submitted Consult to ELPA. + +* Version 0.7 (2021-04-29) + +- Bugfixes +- =consult-buffer=: Respect =confirm-nonexistent-file-or-buffer= +- =consult-widen-key=: Change default setting to twice the =consult-narrow-key= +- =consult-flycheck=: Sort errors first +- Added support for the Vertico completion system +- Consult adds disambiguation suffixes as suffix instead of as prefix now + for the commands =consult-line=, =consult-buffer=, etc. + This enables support for the =basic= completion style and TAB completion. +- =consult--read=: The =:title= function must accept two arguments now, + the candidate string and a flag. If the flag is nil, the function should + return the title of the candidate, otherwise the function should return the + transformed candidate. +- =consult-grep= and related commands: Strip the file name if grouping is used. +- =consult-find/grep=: Ensure that the commands work with Tramp +- =consult-outline=: Add narrowing +- Added =consult-org-heading= and =consult-org-agenda= +- =consult-line=: Highlight visual line during jump preview +- =consult-line=: Start search at current line, add configuration variable + =consult-start-from-top=. The starting point can be toggled by the prefix + argument =C-u=. + +* Version 0.6 (2021-03-02) + +- Bugfixes +- =consult-keep/focus-lines=: Align behavior on regions with built-in =keep-lines=. +- =consult-buffer=: Enable file sources only when =recentf-mode= is enabled +- =consult--multi=: Add =:default= flag, use flag for =consult--source-buffer= +- Add =consult-grep-max-columns= to prevent performance issues for long lines +- Add =consult-fontify-preserve= customization variable +- =consult-line=: Quits Isearch, when started from an Isearch session +- =consult-register-load=: Align prefix argument handling with =insert-register= +- Rename =consult-error= to =consult-compile-error= +- =consult-compile-error=: Allow calling the command from any buffer, + use the errors from all compilation buffers related to the current buffer. +- =consult-man=: Handle aggregated entries returned by mandoc +- =consult-completion-in-region=: Added preview and =consult-preview-region= face +- Added =consult-completion-in-region-styles= customization variable +- Added =consult-xref=. The function can be set as =xref-show-xrefs-function= + and =xref-show-definitions-function=. +- Added support for the candidate grouping function =x-group-function= + +* Version 0.5 (2021-02-09) + +- Bugfixes +- =consult-keep/focus-lines=: If region is active, operate only on the region. +- =consult-register-format=: Do not truncate register strings. +- =consult-buffer= multi sources: Ensure that original buffer is + shown, when the currently selected source does not perform preview. +- Add =consult-preview-raw-size= +- Expose preview functionality for multi-source bookmarks/files +- Multi sources: Add =:enabled=, =:state= and =:action= fields +- =consult-imenu=: Add faces depending on item types + +* Version 0.4 (2021-02-01) + +- Bugfixes +- Introduce multi sources, reimplement =consult-buffer= with multi sources +- =consult-isearch=: Add preview highlighting +- =consult-line=: Use =isearch-string= when invoked from running isearch + +* Version 0.3 (2021-01-28) + +- Bugfixes +- New command =consult-isearch= +- New functions =consult-register-format=, =consult-register-window=, + removed =consult-register-preview= + +* Version 0.2 (2021-01-16) + +- Initial stable release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.org b/README.org new file mode 100644 index 0000000..7caf5a5 --- /dev/null +++ b/README.org @@ -0,0 +1,1250 @@ +#+title: consult.el - Consulting completing-read +#+author: Daniel Mendler +#+language: en +#+export_file_name: consult.texi +#+texinfo_dir_category: Emacs misc features +#+texinfo_dir_title: Consult: (consult). +#+texinfo_dir_desc: Useful commands built on completing-read. + +#+html: GNU Emacs +#+html: GNU ELPA +#+html: GNU-devel ELPA +#+html: MELPA +#+html: MELPA Stable + +Consult provides search and navigation commands based on the Emacs completion +function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a +list of candidates. Consult offers asynchronous and interactive =consult-grep= and +=consult-ripgrep= commands, and the line-based search command =consult-line=. +Furthermore Consult provides an advanced buffer switching command =consult-buffer= +to switch between buffers, recently opened files, bookmarks and buffer-like +candidates from other sources. Some of the Consult commands are enhanced +versions of built-in Emacs commands. For example the command =consult-imenu= +presents a flat list of the Imenu with [[#live-previews][live preview]], [[#narrowing-and-grouping][grouping and narrowing]]. +Please take a look at the [[#available-commands][full list of commands]]. + +Consult is fully compatible with completion systems centered around the standard +Emacs =completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], +and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]]. + +This package keeps the completion system specifics to a minimum. The ability of +the Consult commands to work well with arbitrary completion systems is one of +the main advantages of the package. Consult fits well into existing setups and +it helps you to create a full completion environment out of small and +independent components. + +You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with +Consult. Marginalia enriches the completion display with annotations, e.g., +documentation strings or file information. The versatile Embark package provides +local actions, comparable to a context menu. These actions operate on the +selected candidate in the minibuffer or at point in normal buffers. For example, +when selecting from a list of files, Embark offers an action to delete the file. +Additionally Embark offers a facility to collect completion candidates in a +collect buffer. The section [[#embark-integration][Embark integration]] documents in greater detail how +Consult and Embark work together. + +#+toc: headlines 8 + +* Screenshots :noexport: + +#+caption: consult-grep +[[https://github.com/minad/consult/blob/screenshots/consult-grep.gif?raw=true]] +Fig. 1: Command =consult-git-grep= + +#+caption: consult-imenu +[[https://github.com/minad/consult/blob/screenshots/consult-imenu.png?raw=true]] +Fig. 2: Command =consult-imenu= + +#+caption: consult-line +[[https://github.com/minad/consult/blob/screenshots/consult-line.png?raw=true]] +Fig. 3: Command =consult-line= + +* Available commands +:properties: +:custom_id: available-commands +:description: Navigation, search, editing commands and more +:end: +#+cindex: commands + +Most Consult commands follow the meaningful naming scheme =consult-=. +Many commands implement a little known but convenient Emacs feature called +"future history", which guesses what input the user wants. At a command prompt +type =M-n= and typically Consult will insert the symbol or thing at point into +the input. + +*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see +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. + +** Virtual Buffers +:properties: +:description: Buffers, bookmarks and recent files +:end: +#+cindex: virtual buffers + +#+findex: consult-buffer +#+findex: consult-buffer-other-window +#+findex: consult-buffer-other-frame +#+findex: consult-project-buffer +#+findex: consult-recent-file +#+findex: consult-bookmark +- =consult-buffer= (=-other-window=, =-other-frame=): Enhanced version + of =switch-to-buffer= with support for virtual buffers. Supports live preview + of buffers and narrowing to the virtual buffer types. You can type =f SPC= in + order to narrow to recent files. Press =SPC= to show ephemeral buffers. + Supported narrowing keys: + - b Buffers + - SPC Hidden buffers + - * Modified buffers + - f Files (Requires =recentf-mode=) + - r File registers + - m Bookmarks + - p Project + - Custom [[#multiple-sources][other sources]] configured in =consult-buffer-sources=. +- =consult-project-buffer=: Variant of =consult-buffer= restricted to buffers and + recent files of the current project. You can add custom sources to + =consult-project-buffer-sources=. The command may prompt you for a project if + you invoke it from outside a project. +- =consult-bookmark=: Select or create bookmark. To select bookmarks you might use the + =consult-buffer= as an alternative, which can include a bookmark virtual buffer + source. Note that =consult-bookmark= supports preview of bookmarks and + narrowing. +- =consult-recent-file=: Select from recent files with preview. + You might prefer the powerful =consult-buffer= instead, which can include + recent files as a virtual buffer source. The =recentf-mode= enables tracking of + recent files. + +** Editing +:properties: +:description: Commands useful for editing +:end: +#+cindex: editing + +#+findex: consult-yank-pop +#+findex: consult-yank-from-kill-ring +#+findex: consult-yank-replace +#+findex: consult-kmacro +- =consult-yank-from-kill-ring=: Enhanced version of =yank= to select an item + from the =kill-ring=. The selected text previewed as overlay in the buffer. +- =consult-yank-pop=: Enhanced version of =yank-pop= with DWIM-behavior, which + either replaces the last =yank= by cycling through the =kill-ring=, or if there + has not been a last =yank= consults the =kill-ring=. The selected text previewed + as overlay in the buffer. +- =consult-yank-replace=: Like =consult-yank-pop=, but always replaces the last + =yank= with an item from the =kill-ring=. +- =consult-kmacro=: Select macro from the macro ring and execute it. + +** Register +:properties: +:description: Searching through registers and fast access +:end: +#+cindex: register + +#+findex: consult-register +#+findex: consult-register-load +#+findex: consult-register-store +#+findex: consult-register-format +#+findex: consult-register-window +- =consult-register=: Select from list of registers. The command + supports narrowing to register types and preview of marker positions. This + command is useful to search the register contents. For quick access use the + commands =consult-register-load=, =consult-register-store= or the built-in Emacs + register commands. +- =consult-register-format=: Set =register-preview-function= to this function for + an enhanced register formatting. See the [[#use-package-example][example configuration]]. +- =consult-register-window=: Replace =register-preview= with this function for a + better register window. See the [[#use-package-example][example configuration]]. +- =consult-register-load=: Utility command to quickly load a register. + The command either jumps to the register value or inserts it. +- =consult-register-store=: Improved UI to store registers depending on the current + context with an action menu. With an active region, store/append/prepend the + contents, optionally deleting the region when a prefix argument is given. + With a numeric prefix argument, store/add the number. Otherwise store point, + frameset, window or kmacro. Usage examples: + * =M-' x=: If no region is active, store point in register =x=. + If a region is active, store the region in register =x=. + * =M-' M-w x=: Store window configuration in register =x=. + * =C-u 100 M-' x=: Store number in register =x=. + +** Navigation +:properties: +:description: Mark rings, outlines and imenu +:end: +#+cindex: navigation + +#+findex: consult-goto-line +#+findex: consult-mark +#+findex: consult-global-mark +#+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-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=. + Supports live preview and recursive editing. +- =consult-outline=: Jump to a heading of the outline. Supports narrowing + to a heading level, live preview and recursive editing. +- =consult-imenu=: Jump to imenu item in the current buffer. Supports + live preview, recursive editing and narrowing. +- =consult-imenu-multi=: Jump to imenu item in project buffers, with + the same major mode as the current buffer. Supports live preview, + recursive editing and narrowing. This feature has been inspired by + [[https://github.com/vspinu/imenu-anywhere][imenu-anywhere]]. + +** Search +:properties: +:description: Line search, grep and file search +:end: +#+cindex: search + +#+findex: consult-line +#+findex: consult-line-multi +#+findex: consult-keep-lines +#+findex: consult-focus-lines +- =consult-line=: Enter search string and select from matching lines. + Supports live preview and recursive editing. The symbol at point and the + recent Isearch string are added to the "future history" and can be accessed + by pressing =M-n=. When =consult-line= is bound to the =isearch-mode-map= and + is invoked during a running Isearch, it will use the current Isearch string. +- =consult-line-multi=: Search dynamically across multiple buffers. By default + search across project buffers. If invoked with a prefix argument search across + all buffers. The candidates are computed on demand based on the input. The + command behaves like =consult-grep=, but operates on buffers instead of files. +- =consult-keep-lines=: Replacement for =keep/flush-lines= which uses the current + completion style for filtering the buffer. The function updates the buffer + while typing. In particular =consult-keep-lines= can narrow down an exported + Embark collect buffer further, relying on the same completion filtering as + ~completing-read~. If the input begins with the negation operator, i.e., ~! SPC~, + the filter matches the complement. If a region is active, the region restricts + the filtering. +- =consult-focus-lines=: Temporarily hide lines by filtering them using the + current completion style. Call with =C-u= prefix argument in order to show the + hidden lines again. If the input begins with the negation operator, i.e., ~! + SPC~, the filter matches the complement. In contrast to =consult-keep-lines= this + function does not edit the buffer. If a region is active, the region restricts + the filtering. + +** Grep and Find +:properties: +:description: Searching through the filesystem +:end: +#+cindex: grep +#+cindex: find +#+cindex: locate + +#+findex: consult-grep +#+findex: consult-ripgrep +#+findex: consult-git-grep +#+findex: consult-find +#+findex: consult-locate +- =consult-grep=, =consult-ripgrep=, =consult-git-grep=: Search for regular expression + in files. Consult invokes Grep asynchronously, while you enter the search + 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. +- =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. + +** Compilation +:properties: +:description: Jumping to references and compilation errors +:end: +#+cindex: compilation errors + +#+findex: consult-compile-error +#+findex: consult-flymake +#+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 + 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 + =xref-show-xrefs-function= and =xref-show-definitions-function=. + +** Histories +:properties: +:description: Navigating histories +:end: +#+cindex: history + +#+findex: consult-complex-command +#+findex: consult-history +#+findex: consult-isearch-history +- =consult-complex-command=: Select a command from the + =command-history=. This command is a =completing-read= version of + =repeat-complex-command= and is also a replacement for the =command-history= + command from chistory.el. +- =consult-history=: Insert a string from the current buffer history, for example + the Eshell or Comint history. You can also invoke this command from the + minibuffer. In that case =consult-history= uses the history stored in the + =minibuffer-history-variable=. If you prefer =completion-at-point=, take a look at + =cape-history= from the [[https://github.com/minad/cape][Cape]] package. +- =consult-isearch-history=: During an Isearch session, this command picks a + search string from history and continues the search with the newly selected + string. Outside of Isearch, the command allows you to pick a string from the + history and starts a new Isearch. =consult-isearch-history= acts as a drop-in + replacement for =isearch-edit-string=. + +** Modes +:properties: +:description: Toggling minor modes and executing commands +:end: +#+cindex: minor mode +#+cindex: major mode + +#+findex: consult-minor-mode-menu +#+findex: consult-mode-command +- =consult-minor-mode-menu=: Enable/disable minor mode. Supports + narrowing to on/off/local/global modes by pressing =i/o/l/g SPC= + respectively. +- =consult-mode-command=: Run a command from the currently active minor or major + modes. Supports narrowing to local-minor/global-minor/major mode via the keys + =l/g/m=. + +** Org Mode +:properties: +:description: Org-specific commands +:end: + +#+findex: consult-org-heading +#+findex: consult-org-agenda +- =consult-org-heading=: Similar to =consult-outline=, for Org + buffers. Supports narrowing by heading level, priority and TODO + state, as well as live preview and recursive editing. +- =consult-org-agenda=: Jump to an agenda heading. Supports + narrowing by heading level, priority and TODO state, as well as + live preview and recursive editing. +** Help +:properties: +:description: Searching through help +:end: + +#+findex: consult-info +#+findex: consult-man +- =consult-man=: Find Unix man page, via Unix =apropos= or =man -k=. =consult-man= opens + the selected man page using the Emacs =man= command. +- =consult-info=: Full text search through info pages. If the command is invoked + from within an ~*info*~ buffer, it will search through the current manual. You + 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")) +#+end_src + +** Miscellaneous +:properties: +:description: Various other useful commands +:end: + +#+findex: consult-completion-in-region +#+findex: consult-theme +#+findex: consult-preview-at-point +#+findex: consult-preview-at-point-mode +- =consult-theme=: Select a theme and disable all currently enabled themes. + Supports live preview of the theme while scrolling through the candidates. +- =consult-preview-at-point= and =consult-preview-at-point-mode=: Command and minor + mode which previews the candidate at point in the =*Completions*= buffer. This + mode is relevant if you use [[https://git.sr.ht/~protesilaos/mct][Mct]] or the default =*Completions*= UI. +- =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. + #+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))) + #+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 + either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of + =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 + minibuffer, the server does not receive the updated input. LSP completion + works with Corfu or Company though, which perform the completion directly in + the original buffer. + +* Special features +:properties: +:description: Enhancements over built-in `completing-read' +:end: + +Consult enhances =completing-read= with live previews of candidates, additional +narrowing capabilities to candidate groups and asynchronously generated +candidate lists. The internal =consult--read= function, which is used by most +Consult commands, is a thin wrapper around =completing-read= and provides the +special functionality. In order to support multiple candidate sources there +exists the high-level function =consult--multi=. The architecture of Consult +allows it to work with different completion systems in the backend, while still +offering advanced features. + +** Live previews +:properties: +:description: Preview the currently selected candidate +:custom_id: live-previews +:end: +#+cindex: preview + +Some Consult commands support live previews. For example when you scroll through +the items of =consult-line=, the buffer will scroll to the corresponding position. +It is possible to jump back and forth between the minibuffer and the buffer to +perform recursive editing while the search is ongoing. + +Consult enables previews by default. You can disable them by adjusting the +=consult-preview-key= variable. Furthermore it is possible to specify keybindings +which trigger the preview manually as shown in the [[#use-package-example][example configuration]]. The +default setting of =consult-preview-key= is =any= which means that Consult triggers +the preview /immediately/ on any key press when the selected candidate changes. +You can configure each command individually with its own =:preview-key=. The +following settings are possible: + +- Automatic and immediate ='any= +- Automatic and delayed =(list :debounce 0.5 'any)= +- Manual and immediate ="M-."= +- Manual and delayed =(list :debounce 0.5 "M-.")= +- Disabled =nil= + +A safe recommendation is to leave automatic immediate previews enabled in +general and disable the automatic preview only for commands where the preview +may be expensive due to file loading. Internally, Consult uses the +value of =this-command= to determine the =:preview-key= +customized. This means that if you wrap a =consult-*= command within +your own function or command, you will also need to add the name of +/your custom command/ to the =consult-customize= call in order for it +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 +#+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. + +#+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 "" "" + :debounce 1 any)) +#+end_src + +** Narrowing and grouping +:properties: +:description: Restricting the completion to a candidate group +:custom_id: narrowing-and-grouping +:end: +#+cindex: narrowing + +Consult has special support for candidate groups. If the completion UI supports +the grouping functionality, the UI separates the groups with thin lines and +shows group titles. Grouping is useful if the list of candidates consists of +candidates of multiple types or candidates from [[#multiple-sources][multiple sources]], like the +=consult-buffer= command, which shows both buffers and recently opened files. Note +that you can disable the group titles by setting the =:group= property of the +corresponding command to nil using the =consult-customize= macro. + +By entering a narrowing prefix or by pressing a narrowing key it is possible to +restrict the completion candidates to a certain candidate group. When you use +the =consult-buffer= command, you can enter the prefix =b SPC= to restrict list of +candidates to buffers only. If you press =DEL= afterwards, the full candidate list +will be shown again. Furthermore a narrowing prefix key and a widening key can +be configured which can be pressed to achieve the same effect, see the +configuration variables =consult-narrow-key= and =consult-widen-key=. + +After pressing =consult-narrow-key=, the possible narrowing keys can be shown by +pressing =C-h=. When pressing =C-h= after some prefix key, the =prefix-help-command= +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 +configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically +shown in the which-key window after pressing the =consult-narrow-key=. + +** Asynchronous search +:properties: +:description: Filtering asynchronously generated candidate lists +:end: +#+cindex: asynchronous search + +Consult has support for asynchronous generation of candidate lists. This feature +is used for search commands like =consult-grep=, where the list of matches is +generated dynamically while the user is typing a regular expression. The grep +process is executed in the background. When modifying the regular expression, +the background process is terminated and a new process is started with the +modified regular expression. + +The matches, which have been found, can then be narrowed using the installed +Emacs completion-style. This can be powerful if you are using for example the +=orderless= completion style. + +This two-level filtering is possible by splitting the input string. Part of the +input string is treated as input to grep and part of the input is used for +filtering. There are multiple splitting styles available, configured in +~consult-async-split-styles-alist~: =nil=, =comma=, =semicolon= and =perl=. The default +splitting style is configured with the variable ~consult-async-split-style~. + +With the =comma= and =semicolon= splitting styles, the first word before the comma +or semicolon is passed to grep, the remaining string is used for filtering. The +=nil= splitting style does not perform any splitting, the whole input is passed to +grep. + +The =perl= splitting style splits the input string at a punctuation character, +using a similar syntax as Perl regular expressions. + +Examples: + +- =#defun=: Search for "defun" using grep. +- =#consult embark=: Search for both "consult" and "embark" using grep in any order. +- =#first.*second=: Search for "first" followed by "second" using grep. +- =#\(consult\|embark\)=: Search for "consult" or "embark" using grep. Note the + usage of Emacs-style regular expressions. +- =#defun#consult=: Search for "defun" using grep, filter with the word + "consult". +- =/defun/consult=: It is also possible to use other punctuation + characters. +- =#to#=: Force searching for "to" using grep, since the grep pattern + must be longer than =consult-async-min-input= characters by default. +- =#defun -- --invert-match#=: Pass argument =--invert-match= to grep. + +Asynchronous processes like =find= and =grep= create an error log buffer +=_*consult-async*= (note the leading space), which is useful for +troubleshooting. The prompt has a small indicator showing the process status: + +- =:= the usual prompt colon, before input is provided. +- =*= with warning face, the process is running. +- =:= with success face, success, process exited with an error code of zero. +- =!= with error face, failure, process exited with a nonzero error code. +- =;= with error face, interrupted, for example if more input is provided. + +** Multiple sources +:properties: +:description: Combining candidates from different sources +:custom_id: multiple-sources +:end: +#+cindex: multiple sources + +Multiple synchronous candidate sources can be combined. This feature is used by +the =consult-buffer= command to present buffer-like candidates in a single menu +for quick access. By default =consult-buffer= includes buffers, bookmarks, recent +files and project-specific buffers and files. It is possible to configure the +list of sources via the =consult-buffer-sources= variable. Arbitrary custom +sources can be defined. + +As an example, the bookmark source is defined as follows: + +#+begin_src emacs-lisp +(defvar consult--source-bookmark + `(:name "Bookmark" + :narrow ?m + :category bookmark + :face consult-bookmark + :history bookmark-history + :items ,#'bookmark-all-names + :action ,#'consult--bookmark-action)) +#+end_src + +Required source fields: +- =:category= Completion category. +- =:items= List of strings to select from or function returning list of strings. + A list of cons cells is not supported. + +Optional source fields: +- =:name= Name of the source, used for narrowing, group titles and annotations. +- =:narrow= Narrowing character or =(character . string)= pair. +- =:preview-key= Preview key or keys which trigger preview. +- =:enabled= Function which must return t if the source is enabled. +- =:hidden= When t candidates of this source are hidden by default. +- =:face= Face used for highlighting the candidates. +- =:annotate= Annotation function called for each candidate, returns string. +- =:history= Name of history variable to add selected candidate. +- =:default= Must be t if the first item of the source is the default value. +- =:action= Function called with the selected candidate. +- =:new= Function called with new candidate name, only if =:require-match= is nil. +- =:state= State constructor for the source, must return the state function. +- Other source fields can be added specifically to the use case. + +The =:state= and =:action= fields of the sources deserve a longer explanation. The +=:action= function takes a single argument and is only called after selection with +the selected candidate, if the selection has not been aborted. This +functionality is provided for convenience and easy definition of sources. The +=:state= field is more general. The =:state= function is a constructor function +without arguments, which can perform some setup necessary for the preview. It +must return a closure which takes an ACTION and a CANDIDATE argument. See the +docstring of =consult--with-preview= for more details about the ACTION argument. + +By default, =consult-buffer= previews buffers, bookmarks and files. Loading recent +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-.") +#+end_src + +Sources can be added directly to the =consult-buffer-source= list for convenience. +For example views/perspectives can be added to the list of virtual buffers from +a library like [[https://github.com/minad/bookmark-view/][bookmark-view]]. + +#+begin_src emacs-lisp +;; Configure new bookmark-view source +(add-to-list 'consult-buffer-sources + (list :name "View" + :narrow ?v + :category 'bookmark + :face 'font-lock-keyword-face + :history 'bookmark-view-history + :action #'consult--bookmark-action + :items #'bookmark-view-names) + 'append) + +;; Modify bookmark source, such that views are hidden +(setq consult--source-bookmark + (plist-put + consult--source-bookmark :items + (lambda () + (bookmark-maybe-load-default-file) + (mapcar #'car + (seq-remove (lambda (x) + (eq #'bookmark-view-handler + (alist-get 'handler (cdr x)))) + bookmark-alist))))) +#+end_src + +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) +#+end_src + +For more details, see the documentation of =consult-buffer= and of the +internal =consult--multi= API. The =consult--multi= function can be used to +create new multi-source commands, but is part of the internal API as of now, +since some details may still change. + +** Embark integration +:properties: +:description: Actions, Grep/Occur-buffer export +:custom_id: embark-integration +:end: +#+cindex: embark + +*NOTE*: Install the =embark-consult= package from MELPA, which provides +Consult-specific Embark actions and the Occur buffer export. + +Embark is a versatile package which offers context dependent actions, comparable +to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its +capabilities. + +Actions are commands which can operate on the currently selected candidate (or +target in Embark terminology). When completing files, for example the +=delete-file= command is offered. With Embark you can execute arbitrary commands +on the currently selected candidate via =M-x=. + +Furthermore Embark provides the =embark-collect= command, which collects +candidates and presents them in an Embark collect buffer, where further actions +can be applied to them. A related feature is the =embark-export= command, which +exports candidate lists to a buffer of a special type. For example in the case +of file completion, a Dired buffer is opened. + +In the context of Consult, particularly exciting is the possibility to export +the matching lines from =consult-line=, =consult-outline=, =consult-mark= and +=consult-global-mark=. The matching lines are exported to an Occur buffer where +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, +if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. + ++ =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. ++ =consult-find= -> =embark-export= to =dired-mode= buffer -> =wdired-change-to-wdired-mode= for editing. + +* Configuration +:properties: +:description: Example configuration and customization variables +:end: + +Consult can be installed from [[https://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package +manager. Alternatively it can be directly installed from the development +repository via other non-standard package managers. + +There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be +contributed. + +*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your +configuration. Consult relies on lambdas and lexical closures. For this reason +many Consult-related snippets require lexical binding. + +** Use-package example +:properties: +:description: Configuration example based on use-package +:custom_id: use-package-example +:end: +#+cindex: use-package + +The Consult package only provides commands and does not add any keybindings or +modes. Therefore the package is non-intrusive but requires a little setup +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. +The configuration shown here relies on the =use-package= macro, which is a +convenient tool to manage package configurations. + +*NOTE:* There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where you can contribute additional +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-" "S-")) + ;; 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 +:properties: +:description: Short description of all customization settings +:end: +#+cindex: customization + +*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET +^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. + +| Variable | Description | +|----------------------------------+-------------------------------------------------------| +| consult-after-jump-hook | Functions to call after jumping to a location | +| consult-async-input-debounce | Input debounce for asynchronous commands | +| consult-async-input-throttle | Input throttle for asynchronous commands | +| consult-async-min-input | Minimum numbers of letters needed for async process | +| consult-async-refresh-delay | Refresh delay for asynchronous commands | +| consult-async-split-style | Splitting style used for async commands | +| consult-async-split-styles-alist | Available splitting styles used for async commands | +| consult-bookmark-narrow | Narrowing configuration for =consult-bookmark= | +| consult-buffer-filter | Filter for =consult-buffer= | +| consult-buffer-sources | List of virtual buffer sources | +| consult-find-args | Command line arguments for find | +| consult-fontify-max-size | Buffers larger than this limit are not fontified | +| consult-fontify-preserve | Preserve fontification for line-based commands. | +| consult-git-grep-args | Command line arguments for git-grep | +| consult-goto-line-numbers | Show line numbers for =consult-goto-line= | +| consult-grep-max-columns | Maximal number of columns of the matching lines | +| consult-grep-args | Command line arguments for grep | +| consult-imenu-config | Mode-specific configuration for =consult-imenu= | +| consult-line-numbers-widen | Show absolute line numbers when narrowing is active. | +| consult-line-start-from-top | Start the =consult-line= search from the top | +| consult-locate-args | Command line arguments for locate | +| consult-man-args | Command line arguments for man | +| consult-mode-command-filter | Filter for =consult-mode-command= | +| consult-mode-histories | Mode-specific history variables | +| consult-narrow-key | Narrowing prefix key during completion | +| consult-point-placement | Placement of the point when jumping to matches | +| consult-preview-key | Keys which triggers preview | +| consult-preview-allowed-hooks | List of =find-file= hooks to enable during preview | +| consult-preview-excluded-files | Regexps matched against file names during preview | +| consult-preview-max-count | Maximum number of files to keep open during preview | +| consult-preview-max-size | Files larger than this size are not previewed | +| consult-preview-raw-size | Files larger than this size are previewed in raw form | +| consult-preview-variables | Alist of variables to bind during preview | +| consult-project-buffer-sources | List of virtual project buffer sources | +| consult-project-function | Function which returns current project root | +| consult-register-prefix | Prefix string for register keys during completion | +| consult-ripgrep-args | Command line arguments for ripgrep | +| consult-themes | List of themes to be presented for selection | +| consult-widen-key | Widening key during completion | +| consult-yank-rotate | Rotate kill ring | + +** Fine-tuning of individual commands +:properties: +:alt_title: Fine-tuning +:description: Fine-grained configuration for special requirements +:end: + +*NOTE:* Consult supports fine-grained customization of individual commands. This +configuration feature exists for experienced users with special requirements. +There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where we collect further configuration examples. + +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. + +Useful options are: +- =:prompt= set the prompt string +- =:preview-key= set the preview key, default is =consult-preview-key= +- =:initial= set the initial input +- =:default= set the default value +- =:history= set the history variable symbol +- =:add-history= add items to the future history, for example symbol at point +- =:sort= enable or disable sorting +- =:group= set to nil to disable candidate grouping and titles. +- =: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 and 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-" "S-")) +#+end_src + +The configuration values are evaluated at runtime, just before the completion +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))) + + (defalias 'consult-line-thing-at-point 'consult-line) + + (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 +following techniques: + +1. Use =consult-customize= in order to change the command or source settings. +2. Create your own wrapper function which passes modified arguments to the Consult functions. +3. Create your own buffer [[#multiple-sources][multi sources]] for =consult-buffer=. +4. Create advices to modify some internal behavior. +5. Write or propose a patch. + +* Recommended packages +:properties: +:description: Related packages recommended for installation +:end: + +I use and recommend this combination of packages: + +- consult: This package +- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system +- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates +- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates +- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering + +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 +you. + +- The builtin completion UI, which pops up the =*Completions*= buffer. +- The builtin =icomplete-vertical-mode= in Emacs 28. +- [[https://git.sr.ht/~protesilaos/mct][mct by Protesilaos Stavrou]]: Minibuffer and Completions in Tandem, which builds + on the default completion UI (development currently [[https://protesilaos.com/codelog/2022-04-14-emacs-discontinue-mct/][discontinued]]). + +Note that all packages are independent and can be exchanged with alternative +components, since there exist no hard dependencies. Furthermore it is possible +to get started with only default completion and Consult and add more components +later to the mix. For example you can omit Marginalia if you don't need +annotations. I highly recommend the Embark package, but in order to familiarize +yourself with the other components, you can first start without it - or you could +use with Embark right away and add the other components later on. + +* Auxiliary packages +:properties: +:description: Integrations with the wider ecosystem +:end: + +You can integrate Consult with special programs or with other packages in the +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/youngker/consult-codesearch.el][consult-codesearch]]: Integration with [[https://github.com/google/codesearch][Code Search]]. +- [[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://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. +- [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. +- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). +- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. +- [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. +- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. +- [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. +- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. +- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. +- [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. +- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. +- [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. + +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 [[https://github.com/company-mode/company-mode][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. +- [[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=. +- [[https://github.com/mhayashi1120/Emacs-wgrep][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. + +* Bug reports +:properties: +:description: How to create reproducible bug reports +:end: + +If you find a bug or suspect that there is a problem with Consult, please carry +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 + =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 + =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= + 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 + in the minimal configuration snippet. + +Minimal setup with Vertico for =emacs -Q=: +#+begin_src emacs-lisp +(package-initialize) +(require 'consult) +(require 'vertico) +(vertico-mode) +(setq completion-styles '(substring basic)) +#+end_src + +Minimal setup with the default completion system for =emacs -Q=: +#+begin_src emacs-lisp +(package-initialize) +(require 'consult) +(setq completion-styles '(substring basic)) +#+end_src + +Please provide the necessary important information with your bug report: + +- The minimal configuration snippet used to reproduce the issue. +- Your completion UI (Default completion, Vertico, Mct or Icomplete). +- A stack trace in case the bug triggers an exception. +- Your Emacs version, since bugs may be fixed or introduced in newer versions. +- Your operating system, since Emacs behavior varies between Linux, Mac and + Windows. +- The package manager, e.g., straight.el or package.el, used to install + the Emacs packages, in order to exclude update issues. Did you install + Consult as part of the Doom or Spacemacs Emacs distributions? +- Do you use Evil or other packages which apply deep changes? + 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]]. + +When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. +Consult often relies on lambdas and lexical closures. + +* Contributions +:properties: +:description: Feature requests and pull requests +:end: + +Consult is a community effort, please participate in the discussions. +Contributions are welcome, but you may want to discuss potential contributions +first. Since this package is part of [[https://elpa.gnu.org/packages/consult.html][GNU ELPA]] contributions require a copyright +assignment to the FSF. + +If you have a proposal, take a look at the [[https://github.com/consult/issues][Consult issue tracker]] and the [[https://github.com/minad/consult/issues/6][Consult +wishlist]]. There have been many prior feature discussions. Please search through +the issue tracker, maybe your issue or feature request has already been +discussed. You can contribute to the [[https://github.com/minad/consult/wiki][Consult wiki]], in case you want to share +small configuration or command snippets. + +* Acknowledgments +:properties: +:description: Contributors and Sources of Inspiration +:end: + +This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult +commands originated in the Counsel package or the wiki of the Selectrum package. +This package exists only thanks to the help of these great contributors and +thanks to the feedback of many users. Thank you! + +Code contributions: +- [[https://github.com/oantolin/][Omar Antolín Camarena]] +- [[https://github.com/s-kostyaev/][Sergey Kostyaev]] +- [[https://github.com/okamsn/][Earl Hyatt]] +- [[https://github.com/clemera/][Clemens Radermacher]] +- [[https://github.com/tomfitzhenry/][Tom Fitzhenry]] +- [[https://github.com/jakanakaevangeli][jakanakaevangeli]] +- [[https://hg.serna.eu][Iñigo Serna]] +- [[https://github.com/aspiers/][Adam Spiers]] +- [[https://github.com/omar-polo][Omar Polo]] +- [[https://github.com/astoff][Augusto Stoffel]] +- [[https://github.com/noctuid][Fox Kiester]] +- [[https://github.com/tecosaur][Tecosaur]] +- [[https://github.com/mohamed-abdelnour][Mohamed Abdelnour]] +- [[https://github.com/thisirs][Sylvain Rousseau]] +- [[https://github.com/jdtsmith][J.D. Smith]] +- [[https://github.com/mohkale][Mohsin Kaleem]] +- [[https://github.com/jyp][Jean-Philippe Bernardy]] +- [[https://github.com/aagon][Aymeric Agon-Rambosson]] +- [[https://github.com/geolessel][Geoffrey Lessel]] +- [[https://github.com/piotrkwiecinski][Piotr Kwiecinski]] + +Advice and useful discussions: +- [[https://github.com/clemera/][Clemens Radermacher]] +- [[https://github.com/oantolin/][Omar Antolín Camarena]] +- [[https://protesilaos.com][Protesilaos Stavrou]] +- [[https://github.com/purcell/][Steve Purcell]] +- [[https://github.com/alphapapa/][Adam Porter]] +- [[https://github.com/manuel-uberti/][Manuel Uberti]] +- [[https://github.com/tomfitzhenry/][Tom Fitzhenry]] +- [[https://github.com/hmelman/][Howard Melman]] +- [[https://github.com/monnier/][Stefan Monnier]] +- [[https://github.com/dgutov/][Dmitry Gutov]] +- [[https://github.com/iyefrat][Itai Y. Efrat]] +- [[https://github.com/bdarcus][Bruce d'Arcus]] +- [[https://github.com/jdtsmith][J.D. Smith]] +- [[https://github.com/Qkessler][Enrique Kessler Martínez]] +- [[https://github.com/raxod502][Radon Rosborough]] + +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://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]]) +- [[https://github.com/yadex205][Kanon Kakuno]] ([[https://github.com/yadex205/consult-ag][consult-ag]]) +- [[https://github.com/rcj][Robin Joy]] ([[https://github.com/rcj/consult-ls-git][consult-ls-git]]) +- [[https://codeberg.org/ravi][Ravi R Kiran]] [[https://codeberg.org/ravi/consult-dash][(consult-dash]]) +- [[https://github.com/mclearc][Colin McLear]] ([[https://github.com/mclear-tools/consult-notes][consult-notes]]) +- [[https://github.com/Nyoho][Yukinori Kitadai]] ([[https://github.com/Nyoho/consult-hatena-bookmark][consult-hatena-bookmark]]) +- [[https://github.com/ghosty141][ghosty141]] ([[https://github.com/ghosty141/consult-git-log-grep][consult-git-log-grep]]) +- [[https://github.com/youngker][YoungJoo Lee]] ([[https://github.com/youngker/consult-codesearch.el][consult-codesearch]]) + +#+html: diff --git a/consult-compile.el b/consult-compile.el new file mode 100644 index 0000000..4c585d5 --- /dev/null +++ b/consult-compile.el @@ -0,0 +1,127 @@ +;;; consult-compile.el --- Provides the command `consult-compile-error' -*- 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 . + +;;; Commentary: + +;; Provides the command `consult-compile-error'. This is an extra +;; package, to allow lazy loading of compile.el. The +;; `consult-compile-error' command is autoloaded. + +;;; Code: + +(require 'consult) +(require 'compile) + +(defvar consult-compile--history nil) + +(defconst consult-compile--narrow + '((?e . "Error") + (?w . "Warning") + (?i . "Info"))) + +(defun consult-compile--font-lock (str) + "Apply `font-lock' faces in STR, copy them to `face'." + (let ((pos 0) (len (length str))) + (while (< pos len) + (let* ((face (get-text-property pos 'font-lock-face str)) + (end (or (text-property-not-all pos len 'font-lock-face face str) len))) + (put-text-property pos end 'face face str) + (setq pos end))) + str)) + +(defun consult-compile--error-candidates (buffer) + "Return alist of errors and positions in BUFFER, a compilation buffer." + (with-current-buffer buffer + (let ((candidates) + (pos (point-min))) + (save-excursion + (while (setq pos (compilation-next-single-property-change pos 'compilation-message)) + (when-let (msg (get-text-property pos 'compilation-message)) + (goto-char pos) + (push (propertize + (consult-compile--font-lock (consult--buffer-substring pos (pos-eol))) + 'consult--type (pcase (compilation--message->type msg) + (0 ?i) + (1 ?w) + (_ ?e)) + 'consult--candidate (point-marker)) + candidates)))) + (nreverse candidates)))) + +(defun consult-compile--lookup (marker) + "Lookup error position given error MARKER." + (when-let (buffer (and marker (marker-buffer marker))) + (with-current-buffer buffer + (let ((next-error-highlight nil) + (compilation-current-error marker) + (overlay-arrow-position overlay-arrow-position)) + (ignore-errors + (save-window-excursion + (compilation-next-error-function 0) + (point-marker))))))) + +(defun consult-compile--compilation-buffers (file) + "Return a list of compilation buffers relevant to FILE." + (consult--buffer-query + :sort 'alpha :predicate + (lambda (buffer) + (with-current-buffer buffer + (and (compilation-buffer-internal-p) + (file-in-directory-p file default-directory)))))) + +(defun consult-compile--state () + "Like `consult--jump-state', also setting the current compilation error." + (let ((jump (consult--jump-state))) + (lambda (action marker) + (let ((pos (consult-compile--lookup marker))) + (when-let (buffer (and (eq action 'return) + marker + (marker-buffer marker))) + (with-current-buffer buffer + (setq compilation-current-error marker + overlay-arrow-position marker))) + (funcall jump action pos))))) + +;;;###autoload +(defun consult-compile-error () + "Jump to a compilation error in the current buffer. + +This command collects entries from compilation buffers and grep +buffers related to the current buffer. The command supports +preview of the currently selected error." + (interactive) + (consult--read + (or (mapcan #'consult-compile--error-candidates + (or (consult-compile--compilation-buffers + default-directory) + (user-error "No compilation buffers found for the current buffer"))) + (user-error "No compilation errors found")) + :prompt "Go to error: " + :category 'consult-compile-error + :sort nil + :require-match t + :history t ;; disable history + :lookup #'consult--lookup-candidate + :group (consult--type-group consult-compile--narrow) + :narrow (consult--type-narrow consult-compile--narrow) + :history '(:input consult-compile--history) + :state (consult-compile--state))) + +(provide 'consult-compile) +;;; consult-compile.el ends here diff --git a/consult-flymake.el b/consult-flymake.el new file mode 100644 index 0000000..ae47e55 --- /dev/null +++ b/consult-flymake.el @@ -0,0 +1,117 @@ +;;; consult-flymake.el --- Provides the command `consult-flymake' -*- 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 . + +;;; Commentary: + +;; Provides the command `consult-flymake'. This is an extra package, +;; to allow lazy loading of flymake.el. The `consult-flymake' command +;; is autoloaded. + +;;; Code: + +(require 'consult) +(require 'flymake) + +(defconst consult-flymake--narrow + '((?e . "Error") + (?w . "Warning") + (?n . "Note"))) + +(defun consult-flymake--candidates (diags) + "Return Flymake errors from DIAGS as formatted candidates. +DIAGS should be a list of diagnostics as returned from `flymake-diagnostics'." + (let* ((diags + (mapcar + (lambda (diag) + (let ((buffer (flymake-diagnostic-buffer diag)) + (type (flymake-diagnostic-type diag))) + (with-current-buffer buffer + (save-excursion + (save-restriction + (widen) + (goto-char (flymake-diagnostic-beg diag)) + (list (buffer-name buffer) + (line-number-at-pos) + type + (flymake-diagnostic-text diag) + (point-marker) + (flymake-diagnostic-end diag) + (pcase (flymake--lookup-type-property type 'flymake-category) + ('flymake-error ?e) + ('flymake-warning ?w) + (_ ?n)))))))) + (seq-filter (lambda (diag) + (buffer-live-p (flymake-diagnostic-buffer diag))) + diags))) + (buffer-width (apply #'max (mapcar (lambda (x) (length (nth 0 x))) diags))) + (line-width (apply #'max (mapcar (lambda (x) (length (number-to-string (nth 1 x)))) diags))) + (fmt (format "%%-%ds %%-%dd %%-7s %%s" buffer-width line-width))) + (mapcar + (pcase-lambda (`(,buffer ,line ,type ,text ,beg ,end ,narrow)) + (propertize (format fmt buffer line + (propertize (format "%s" (flymake--lookup-type-property + type 'flymake-type-name type)) + 'face (flymake--lookup-type-property + type 'mode-line-face 'flymake-error)) + text) + 'consult--candidate (list beg (cons 0 (- end beg))) + 'consult--type narrow)) + ;; Sort by buffer, severity and position. + (sort diags + (pcase-lambda (`(,b1 _ ,t1 _ ,m1 _) `(,b2 _ ,t2 _ ,m2 _)) + (let ((s1 (flymake--severity t1)) + (s2 (flymake--severity t2))) + (or + (string-lessp b1 b2) + (and (string-equal b1 b2) + (or + (> s1 s2) + (and (= s1 s2) + (< m1 m2))))))))))) + +;;;###autoload +(defun consult-flymake (&optional project) + "Jump to Flymake diagnostic. +When PROJECT is non-nil then prompt with diagnostics from all +buffers in the current project instead of just the current buffer." + (interactive "P") + (consult--forbid-minibuffer) + (consult--read + (consult-flymake--candidates + (or + (if-let (((and project (fboundp 'flymake--project-diagnostics))) + (project (project-current))) + (flymake--project-diagnostics project) + (flymake-diagnostics)) + (user-error "No flymake errors (Status: %s)" + (if (seq-difference (flymake-running-backends) + (flymake-reporting-backends)) + 'running 'finished)))) + :prompt "Flymake diagnostic: " + :category 'consult-flymake-error + :history t ;; disable history + :require-match t + :sort nil + :group (consult--type-group consult-flymake--narrow) + :narrow (consult--type-narrow consult-flymake--narrow) + :lookup #'consult--lookup-candidate + :state (consult--jump-state))) + +(provide 'consult-flymake) +;;; consult-flymake.el ends here diff --git a/consult-icomplete.el b/consult-icomplete.el new file mode 100644 index 0000000..4dcf2c1 --- /dev/null +++ b/consult-icomplete.el @@ -0,0 +1,55 @@ +;;; 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 . + +;;; 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-imenu.el b/consult-imenu.el new file mode 100644 index 0000000..53f65e5 --- /dev/null +++ b/consult-imenu.el @@ -0,0 +1,264 @@ +;;; consult-imenu.el --- Consult commands for imenu -*- 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 . + +;;; Commentary: + +;; Provides imenu-related Consult commands. + +;;; Code: + +(require 'consult) +(require 'imenu) + +(defcustom consult-imenu-config + '((emacs-lisp-mode :toplevel "Functions" + :types ((?f "Functions" font-lock-function-name-face) + (?m "Macros" font-lock-function-name-face) + (?p "Packages" font-lock-constant-face) + (?t "Types" font-lock-type-face) + (?v "Variables" font-lock-variable-name-face)))) + "Imenu configuration, faces and narrowing keys used by `consult-imenu'. + +For each type a narrowing key and a name must be specified. The +face is optional. The imenu representation provided by the +backend usually puts functions directly at the toplevel. +`consult-imenu' moves them instead under the type specified by +:toplevel." + :type '(repeat (cons symbol plist)) + :group 'consult) + +(defface consult-imenu-prefix + '((t :inherit consult-key)) + "Face used to highlight imenu prefix in `consult-imenu'." + :group 'consult-faces) + +(defvar consult-imenu--history nil) +(defvar-local consult-imenu--cache nil) + +(defun consult-imenu--switch-buffer (name pos buf fn &rest args) + "Switch buffer before invoking special menu items. +NAME is the item name. +POS is the position. +BUF is the buffer. +FN is the original special item function. +ARGS are the arguments to the special item function." + (funcall consult--buffer-display buf) + (apply fn name pos args)) + +(defun consult-imenu--normalize (pos) + "Return normalized imenu POS." + (pcase pos + ;; Simple marker item + ((pred markerp) nil) + ;; Simple integer item + ((pred integerp) (setq pos (copy-marker pos))) + ;; Semantic uses overlay for positions + ((pred overlayp) (setq pos (copy-marker (overlay-start pos)))) + ;; Wrap special item + (`(,pos ,fn . ,args) + (setq pos `(,pos ,#'consult-imenu--switch-buffer ,(current-buffer) + ,fn ,@args))) + (_ (error "Unknown imenu item: %S" pos))) + (if (or (consp pos) + (eq imenu-default-goto-function #'imenu-default-goto-function)) + pos + (list pos #'consult-imenu--switch-buffer (current-buffer) + imenu-default-goto-function))) + +(defun consult-imenu--flatten (prefix face list types) + "Flatten imenu LIST. +PREFIX is prepended in front of all items. +FACE is the item face. +TYPES is the mode-specific types configuration." + (mapcan + (lambda (item) + (if (imenu--subalist-p item) + (let* ((name (concat (car item))) + (next-prefix name) + (next-face face)) + (add-face-text-property 0 (length name) + 'consult-imenu-prefix 'append name) + (if prefix + (setq next-prefix (concat prefix "/" name)) + (when-let (type (cdr (assoc name types))) + (put-text-property 0 (length name) 'consult--type (car type) name) + (setq next-face (cadr type)))) + (consult-imenu--flatten next-prefix next-face (cdr item) types)) + (list (cons + (if prefix + (let ((key (concat prefix " " (car item)))) + (add-face-text-property (1+ (length prefix)) (length key) + face 'append key) + key) + (car item)) + (consult-imenu--normalize (cdr item)))))) + list)) + +(defun consult-imenu--compute () + "Compute imenu candidates." + (consult--forbid-minibuffer) + (let* ((imenu-use-markers t) + ;; Generate imenu, see `imenu--make-index-alist'. + (items (imenu--truncate-items + (save-excursion + (save-restriction + (widen) + (funcall imenu-create-index-function))))) + (config (cdr (seq-find (lambda (x) (derived-mode-p (car x))) consult-imenu-config)))) + ;; Fix toplevel items, e.g., emacs-lisp-mode toplevel items are functions + (when-let (toplevel (plist-get config :toplevel)) + (let ((tops (seq-remove (lambda (x) (listp (cdr x))) items)) + (rest (seq-filter (lambda (x) (listp (cdr x))) items))) + (setq items (nconc rest (and tops (list (cons toplevel tops))))))) + ;; Apply our flattening in order to ease searching the imenu. + (consult-imenu--flatten + nil nil items + (mapcar (pcase-lambda (`(,x ,y ,z)) (list y x z)) + (plist-get config :types))))) + +(defun consult-imenu--deduplicate (items) + "Deduplicate imenu ITEMS by appending a counter." + ;; Some imenu backends generate duplicate items (e.g. for overloaded methods in java) + (let ((ht (make-hash-table :test #'equal :size (length items)))) + (dolist (item items) + (if-let (count (gethash (car item) ht)) + (setcar item (format "%s (%s)" (car item) + (puthash (car item) (1+ count) ht))) + (puthash (car item) 0 ht))))) + +(defun consult-imenu--items () + "Return cached imenu candidates, may error." + (unless (equal (car consult-imenu--cache) (buffer-modified-tick)) + (setq consult-imenu--cache (cons (buffer-modified-tick) (consult-imenu--compute)))) + (cdr consult-imenu--cache)) + +(defun consult-imenu--items-safe () + "Return cached imenu candidates, will not error." + (condition-case err + (consult-imenu--items) + (t (message "Cannot create Imenu for buffer %s (%s)" + (buffer-name) (error-message-string err)) + nil))) + +(defun consult-imenu--multi-items (buffers) + "Return all imenu items from BUFFERS." + (consult--with-increased-gc + (let ((reporter (make-progress-reporter "Collecting" 0 (length buffers)))) + (prog1 + (apply #'append + (seq-map-indexed (lambda (buf idx) + (with-current-buffer buf + (prog1 (consult-imenu--items-safe) + (progress-reporter-update + reporter (1+ idx) (buffer-name))))) + buffers)) + (progress-reporter-done reporter))))) + +(defun consult-imenu--jump (item) + "Jump to imenu ITEM via `consult--jump'. +In contrast to the builtin `imenu' jump function, +this function can jump across buffers." + (pcase item + (`(,name ,pos ,fn . ,args) + (push-mark nil t) + (apply fn name pos args)) + (`(,_ . ,pos) + (consult--jump pos)) + (_ (error "Unknown imenu item: %S" item))) + (run-hooks 'imenu-after-jump-hook)) + +(defun consult-imenu--narrow () + "Return narrowing configuration for the current buffer." + (mapcar (lambda (x) (cons (car x) (cadr x))) + (plist-get (cdr (seq-find (lambda (x) (derived-mode-p (car x))) + consult-imenu-config)) + :types))) + +(defun consult-imenu--group () + "Create a imenu group function for the current buffer." + (when-let (narrow (consult-imenu--narrow)) + (lambda (cand transform) + (let ((type (get-text-property 0 'consult--type cand))) + (cond + ((and transform type) + (substring cand (1+ (next-single-property-change 0 'consult--type cand)))) + (transform cand) + (type (alist-get type narrow))))))) + +(defun consult-imenu--select (prompt items) + "Select from imenu ITEMS given PROMPT string." + (consult-imenu--deduplicate items) + (consult-imenu--jump + (consult--read + (or items (user-error "Imenu is empty")) + :state + (let ((preview (consult--jump-preview))) + (lambda (action cand) + ;; Only preview simple menu items which are markers, + ;; in order to avoid any bad side effects. + (funcall preview action (and (markerp (cdr cand)) (cdr cand))))) + :narrow + (when-let (narrow (consult-imenu--narrow)) + (list :predicate + (lambda (cand) + (eq (get-text-property 0 'consult--type (car cand)) consult--narrow)) + :keys narrow)) + :group (consult-imenu--group) + :prompt prompt + :require-match t + :category 'imenu + :lookup #'consult--lookup-cons + :history 'consult-imenu--history + :add-history (thing-at-point 'symbol) + :sort nil))) + +;;;###autoload +(defun consult-imenu () + "Select item from flattened `imenu' using `completing-read' with preview. + +The command supports preview and narrowing. See the variable +`consult-imenu-config', which configures the narrowing. +The symbol at point is added to the future history. + +See also `consult-imenu-multi'." + (interactive) + (consult-imenu--select + "Go to item: " + (consult--slow-operation "Building Imenu..." + (consult-imenu--items)))) + +;;;###autoload +(defun consult-imenu-multi (&optional query) + "Select item from the imenus of all buffers from the same project. + +In order to determine the buffers belonging to the same project, the +`consult-project-function' is used. Only the buffers with the +same major mode as the current buffer are used. See also +`consult-imenu' for more details. In order to search a subset of buffers, +QUERY can be set to a plist according to `consult--buffer-query'." + (interactive "P") + (unless (keywordp (car-safe query)) + (setq query (list :sort 'alpha :mode major-mode + :directory (and (not query) 'project)))) + (let ((buffers (consult--buffer-query-prompt "Go to item" query))) + (consult-imenu--select (car buffers) + (consult-imenu--multi-items (cdr buffers))))) + +(provide 'consult-imenu) +;;; consult-imenu.el ends here diff --git a/consult-info.el b/consult-info.el new file mode 100644 index 0000000..ef05f54 --- /dev/null +++ b/consult-info.el @@ -0,0 +1,181 @@ +;;; consult-info.el --- Search through the info manuals -*- 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 . + +;;; Commentary: + +;; Provides the command `consult-info'. This is an extra package, +;; to allow lazy loading of info.el. The `consult-info' command +;; is autoloaded. + +;;; Code: + +(require 'consult) +(require 'info) + +(defvar consult-info--history nil) + +(defun consult-info--candidates (manuals input) + "Dynamically find lines in MANUALS matching INPUT." + (pcase-let* ((`(,regexps . ,hl) + (funcall consult--regexp-compiler input 'emacs t)) + (re (concat "\\(\^_\n\\(?:.*Node:[ \t]*\\([^,\t\n]+\\)\\)?.*\n\\)\\|" (car regexps))) + (candidates nil) + (cand-idx 0) + (last-node nil) + (full-node nil)) + (pcase-dolist (`(,manual . ,buf) manuals) + (with-current-buffer buf + (setq last-node nil full-node nil) + (widen) + (goto-char (point-min)) + ;; TODO Info has support for subfiles, which is currently not supported + ;; by the `consult-info' search routine. Fortunately most (or all?) + ;; Emacs info files are generated with the --no-split option. See the + ;; comment in doc/emacs/Makefile.in. Given the computing powers these + ;; days split info files are probably also not necessary anymore. + ;; However it could happen that info files installed as part of the + ;; Linux distribution are split. + (while (and (not (eobp)) (re-search-forward re nil t)) + (if (match-end 1) + (progn + (if-let ((node (match-string 2))) + (unless (equal node last-node) + (setq full-node (concat "(" manual ")" node) + last-node node)) + (setq last-node nil full-node nil)) + (goto-char (1+ (pos-eol)))) + (let ((bol (pos-bol)) + (eol (pos-eol))) + (goto-char bol) + (when (and + full-node + ;; Information separator character + (>= (- (point) 2) (point-min)) + (not (eq (char-after (- (point) 2)) ?\^_)) + ;; Non-blank line, only printable characters on the line. + (not (looking-at-p "^\\s-*$")) + (looking-at-p "^[[:print:]]*$") + ;; Matches all regexps + (seq-every-p (lambda (r) + (goto-char bol) + (re-search-forward r eol t)) + (cdr regexps))) + (let ((cand (concat + (funcall hl (buffer-substring-no-properties bol eol)) + (consult--tofu-encode cand-idx)))) + (put-text-property 0 1 'consult--info (list full-node bol buf) cand) + (cl-incf cand-idx) + (push cand candidates))) + (goto-char (1+ eol))))))) + (nreverse candidates))) + +(defun consult-info--position (cand) + "Return position information for CAND." + (when-let ((pos (and cand (get-text-property 0 'consult--info cand))) + (matches (consult--point-placement cand 0)) + (dest (+ (cadr pos) (car matches)))) + `( ,(cdr matches) ,dest . ,pos))) + +(defun consult-info--action (cand) + "Jump to info CAND." + (pcase (consult-info--position cand) + (`( ,_matches ,pos ,node ,_bol ,_buf) + (info node) + (widen) + (goto-char pos) + (Info-select-node) + (run-hooks 'consult-after-jump-hook)))) + +(defun consult-info--state () + "Info manual preview state." + (let ((preview (consult--jump-preview))) + (lambda (action cand) + (pcase action + ('preview + (setq cand (consult-info--position cand)) + (funcall preview 'preview + (pcase cand + (`(,matches ,pos ,_node ,_bol ,buf) + (cons (set-marker (make-marker) pos buf) matches)))) + (let (Info-history Info-history-list Info-history-forward) + (when cand (ignore-errors (Info-select-node))))) + ('return + (consult-info--action cand)))))) + +(defun consult-info--group (cand transform) + "Return title for CAND or TRANSFORM the candidate." + (if transform cand + (car (get-text-property 0 'consult--info cand)))) + +(defun consult-info--prepare-buffers (manuals fun) + "Prepare buffers for MANUALS and call FUN with buffers." + (declare (indent 1)) + (let (buffers) + (unwind-protect + (let ((reporter (make-progress-reporter "Preparing" 0 (length manuals)))) + (consult--with-increased-gc + (seq-do-indexed + (lambda (manual idx) + (push (cons manual (generate-new-buffer (format "*info-preview-%s*" manual))) + buffers) + (with-current-buffer (cdar buffers) + (let (Info-history Info-history-list Info-history-forward) + (Info-mode) + (Info-find-node manual "Top"))) + (progress-reporter-update reporter (1+ idx) manual)) + manuals)) + (progress-reporter-done reporter) + (funcall fun (reverse buffers))) + (dolist (buf buffers) + (kill-buffer (cdr buf)))))) + +;;;###autoload +(defun consult-info (&rest manuals) + "Full text search through info MANUALS." + (interactive + (if Info-current-file + (list (file-name-base Info-current-file)) + (info-initialize) + (completing-read-multiple + "Info Manuals: " + (info--manual-names current-prefix-arg) + nil t))) + (consult-info--prepare-buffers manuals + (lambda (buffers) + (consult--read + (consult--dynamic-collection + (apply-partially #'consult-info--candidates buffers)) + :state (consult-info--state) + :prompt + (format "Info (%s): " + (string-join (if (length> manuals 3) + `(,@(seq-take manuals 3) ,"…") + manuals) + ", ")) + :require-match t + :sort nil + :category 'consult-info + :history '(:input consult-info--history) + :group #'consult-info--group + :initial (consult--async-split-initial "") + :add-history (consult--async-split-thingatpt 'symbol) + :lookup #'consult--lookup-member)))) + +(provide 'consult-info) +;;; consult-info.el ends here diff --git a/consult-kmacro.el b/consult-kmacro.el new file mode 100644 index 0000000..8c043e0 --- /dev/null +++ b/consult-kmacro.el @@ -0,0 +1,92 @@ +;;; consult-kmacro.el --- Provides the command `consult-kmacro' -*- 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 . + +;;; Commentary: + +;; Provides the command `consult-kmacro'. This is an extra package, +;; to allow lazy loading of kmacro.el. The `consult-kmacro' command +;; is autoloaded. + +;;; Code: + +(require 'consult) +(require 'kmacro) + +(defvar consult-kmacro--history nil) + +(defun consult-kmacro--candidates () + "Return alist of kmacros and indices." + (thread-last + ;; List of macros + (append (and last-kbd-macro (list (kmacro-ring-head))) kmacro-ring) + ;; Emacs 29 uses OClosures. I like OClosures but it would have been better + ;; if public APIs wouldn't change like that. + (mapcar (lambda (x) + (if (eval-when-compile (> emacs-major-version 28)) + (list (kmacro--keys x) (kmacro--counter x) (kmacro--format x) x) + `(,@x ,x)))) + ;; Filter mouse clicks + (seq-remove (lambda (x) (seq-some #'mouse-event-p (car x)))) + ;; Format macros + (mapcar (pcase-lambda (`(,keys ,counter ,format ,km)) + (propertize + (format-kbd-macro keys 1) + 'consult--candidate km + 'consult-kmacro--annotation + ;; If the counter is 0 and the counter format is its default, + ;; then there is a good chance that the counter isn't actually + ;; being used. This can only be wrong when a user + ;; intentionally starts the counter with a negative value and + ;; then increments it to 0. + (cond + ((not (equal format "%d")) ;; show counter for non-default format + (format " (counter=%d, format=%s) " counter format)) + ((/= counter 0) ;; show counter if non-zero + (format " (counter=%d)" counter)))))) + (delete-dups))) + +;;;###autoload +(defun consult-kmacro (arg) + "Run a chosen keyboard macro. + +With prefix ARG, run the macro that many times. +Macros containing mouse clicks are omitted." + (interactive "p") + (let ((km (consult--read + (or (consult-kmacro--candidates) + (user-error "No keyboard macros defined")) + :prompt "Keyboard macro: " + :category 'consult-kmacro + :require-match t + :sort nil + :history 'consult-kmacro--history + :annotate + (lambda (cand) + (get-text-property 0 'consult-kmacro--annotation cand)) + :lookup #'consult--lookup-candidate))) + (unless km (user-error "No kmacro selected")) + (funcall + ;; Kmacros are lambdas (oclosures) on Emacs 29 + (if (eval-when-compile (> emacs-major-version 28)) + km + (kmacro-lambda-form km)) + arg))) + +(provide 'consult-kmacro) +;;; consult-kmacro.el ends here diff --git a/consult-org.el b/consult-org.el new file mode 100644 index 0000000..6512c34 --- /dev/null +++ b/consult-org.el @@ -0,0 +1,129 @@ +;;; consult-org.el --- Consult commands for org-mode -*- 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 . + +;;; Commentary: + +;; Provides a `completing-read' interface for Org mode navigation. +;; This is an extra package, to allow lazy loading of Org. + +;;; Code: + +(require 'consult) +(require 'org) + +(defvar consult-org--history nil) + +(defun consult-org--narrow () + "Narrowing configuration for `consult-org' commands." + (let ((todo-kws + (seq-filter + (lambda (x) (<= ?a (car x) ?z)) + (mapcar (lambda (s) + (pcase-let ((`(,a ,b) (split-string s "("))) + (cons (downcase (string-to-char (or b a))) a))) + (apply #'append (mapcar #'cdr org-todo-keywords)))))) + (list :predicate + (lambda (cand) + (pcase-let ((`(,level ,todo . ,prio) + (get-text-property 0 'consult-org--heading cand))) + (cond + ((<= ?1 consult--narrow ?9) (<= level (- consult--narrow ?0))) + ((<= ?A consult--narrow ?Z) (eq prio consult--narrow)) + (t (equal todo (alist-get consult--narrow todo-kws)))))) + :keys + (nconc (mapcar (lambda (c) (cons c (format "Level %c" c))) + (number-sequence ?1 ?9)) + (mapcar (lambda (c) (cons c (format "Priority %c" c))) + (number-sequence (max ?A org-highest-priority) + (min ?Z org-lowest-priority))) + todo-kws)))) + +(defun consult-org--headings (prefix match scope &rest skip) + "Return a list of Org heading candidates. + +If PREFIX is non-nil, prefix the candidates with the buffer name. +MATCH, SCOPE and SKIP are as in `org-map-entries'." + (let (buffer) + (apply + #'org-map-entries + (lambda () + ;; 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))) + (when tags + (setq tags (concat " " tags)) + (put-text-property 1 (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))))) + (add-text-properties 0 1 + `(consult--candidate ,(point-marker) + consult-org--heading (,level ,todo . ,prio)) + cand) + cand)) + match scope skip))) + +;;;###autoload +(defun consult-org-heading (&optional match scope) + "Jump to an Org heading. + +MATCH and SCOPE are as in `org-map-entries' and determine which +entries are offered. By default, all entries of the current +buffer are offered." + (interactive (unless (derived-mode-p 'org-mode) + (user-error "Must be called from an Org buffer"))) + (let ((prefix (not (memq scope '(nil tree region region-start-level file))))) + (consult--read + (consult--slow-operation "Collecting headings..." + (or (consult-org--headings prefix match scope) + (user-error "No headings"))) + :prompt "Go to heading: " + :category 'consult-org-heading + :sort nil + :require-match t + :history '(:input consult-org--history) + :narrow (consult-org--narrow) + :state (consult--jump-state) + :group + (when prefix + (lambda (cand transform) + (let ((name (buffer-name + (marker-buffer + (get-text-property 0 'consult--candidate cand))))) + (if transform (substring cand (1+ (length name))) name)))) + :lookup #'consult--lookup-candidate))) + +;;;###autoload +(defun consult-org-agenda (&optional match) + "Jump to an Org agenda heading. + +By default, all agenda entries are offered. MATCH is as in +`org-map-entries' and can used to refine this." + (interactive) + (unless org-agenda-files + (user-error "No agenda files")) + (consult-org-heading match 'agenda)) + +(provide 'consult-org) +;;; consult-org.el ends here diff --git a/consult-register.el b/consult-register.el new file mode 100644 index 0000000..72f1867 --- /dev/null +++ b/consult-register.el @@ -0,0 +1,326 @@ +;;; consult-register.el --- Consult commands for registers -*- 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 . + +;;; Commentary: + +;; Provides register-related Consult commands. + +;;; Code: + +(require 'consult) +(require 'kmacro) + +(defcustom consult-register-prefix #("#" 0 1 (face consult-key)) + "Prepend prefix in front of register keys during completion." + :type '(choice (const nil) string) + :group 'consult) + +(defvar consult-register--narrow + '((?n . "Number") + (?s . "String") + (?p . "Point") + (?r . "Rectangle") + (?t . "Frameset") + (?k . "Kmacro") + (?f . "File") + (?b . "Buffer") + (?w . "Window")) + "Register type names. +Each element of the list must have the form (char . name).") + +(cl-defun consult-register--format-value (val) + "Format generic register VAL as string." + (with-output-to-string (register-val-describe val nil))) + +(cl-defgeneric consult-register--describe (val) + "Describe generic register VAL." + (list (consult-register--format-value val))) + +(cl-defmethod consult-register--describe ((val number)) + "Describe numeric register VAL." + (list (consult-register--format-value val) 'consult--type ?n)) + +(cl-defmethod consult-register--describe ((val string)) + "Describe string register VAL." + (list val 'consult--type + (if (eq (car (get-text-property 0 'yank-handler val)) + 'rectangle--insert-for-yank) + ?r ?s))) + +(cl-defmethod consult-register--describe ((val marker)) + "Describe marker register VAL." + (with-current-buffer (marker-buffer val) + (save-restriction + (save-excursion + (widen) + (goto-char val) + (let* ((line (line-number-at-pos)) + (str (propertize (consult--line-with-cursor 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)) + +(cl-defmethod consult-register--describe ((val (head file))) + "Describe file register VAL." + (list (propertize (abbreviate-file-name (cdr val)) 'face 'consult-file) + 'consult--type ?f 'multi-category `(file . ,(cdr val)))) + +(cl-defmethod consult-register--describe ((val (head buffer))) + "Describe buffer register VAL." + (list (propertize (cdr val) 'face 'consult-buffer) + 'consult--type ?f 'multi-category `(buffer . ,(cdr val)))) + +(cl-defmethod consult-register--describe ((val (head file-query))) + "Describe file-query register VAL." + (list (format "%s at position %d" + (propertize (abbreviate-file-name (cadr val)) + 'face 'consult-file) + (caddr val)) + 'consult--type ?f 'multi-category `(file . ,(cadr val)))) + +(cl-defmethod consult-register--describe ((val cons)) + "Describe rectangle or window-configuration register VAL." + (cond + ((stringp (car val)) + (list (string-join val "\n") 'consult--type ?r)) + ((window-configuration-p (car val)) + (list (consult-register--format-value val) + 'consult--type ?w)) + (t (list (consult-register--format-value val))))) + +(with-eval-after-load 'frameset + (cl-defmethod consult-register--describe ((val frameset-register)) + "Describe frameset register VAL." + (list (consult-register--format-value val) 'consult--type ?t))) + +;;;###autoload +(defun consult-register-window (buffer &optional show-empty) + "Enhanced drop-in replacement for `register-preview'. + +BUFFER is the window buffer. +SHOW-EMPTY must be t if the window should be shown for an empty register list." + (let ((regs (consult-register--alist 'noerror)) + (separator + (and (display-graphic-p) + (propertize #(" \n" 0 1 (display (space :align-to right))) + 'face '(:inherit consult-separator :height 1 :underline t))))) + (when (or show-empty regs) + (with-current-buffer-window buffer + (cons 'display-buffer-at-bottom + '((window-height . fit-window-to-buffer) + (preserve-size . (nil . t)))) + nil + (setq-local cursor-in-non-selected-windows nil + mode-line-format nil + truncate-lines t + window-min-height 1 + window-resize-pixelwise t) + (insert (mapconcat + (lambda (reg) + (concat (funcall register-preview-function reg) separator)) + regs nil)))))) + +;;;###autoload +(defun consult-register-format (reg &optional completion) + "Enhanced preview of register REG. +This function can be used as `register-preview-function'. +If COMPLETION is non-nil format the register for completion." + (pcase-let* ((`(,key . ,val) reg) + (key-str (propertize (single-key-description key) 'face 'consult-key)) + (key-len (max 3 (length key-str))) + (`(,str . ,props) (consult-register--describe val))) + (when (string-search "\n" str) + (let* ((lines (seq-take (seq-remove #'string-blank-p (split-string str "\n")) 3)) + (space (apply #'min most-positive-fixnum + (mapcar (lambda (x) (string-match-p "[^ ]" x)) lines)))) + (setq str (mapconcat (lambda (x) (substring x space)) + lines (concat "\n" (make-string (1+ key-len) ?\s)))))) + (setq str (concat + (and completion consult-register-prefix) + key-str (make-string (- key-len (length key-str)) ?\s) " " + str (and (not completion) "\n"))) + (when completion + (add-text-properties + 0 (length str) + `(consult--candidate ,(car reg) ,@props) + str)) + str)) + +(defun consult-register--alist (&optional noerror filter) + "Return register list, sorted and filtered with FILTER. +Raise an error if the list is empty and NOERROR is nil." + (or (sort (seq-filter + ;; Sometimes, registers are made without a `cdr'. + ;; Such registers don't do anything, and can be ignored. + (lambda (x) (and (cdr x) (or (not filter) (funcall filter x)))) + register-alist) + #'car-less-than-car) + (and (not noerror) (user-error "All registers are empty")))) + +(defun consult-register--candidates (&optional filter) + "Return formatted completion candidates, filtered with FILTER." + (mapcar (lambda (reg) (consult-register-format reg 'completion)) + (consult-register--alist nil filter))) + +;;;###autoload +(defun consult-register (&optional arg) + "Load register and either jump to location or insert the stored text. + +This command is useful to search the register contents. For quick access +to registers it is still recommended to use the register functions +`consult-register-load' and `consult-register-store' or the built-in +built-in register access functions. The command supports narrowing, see +`consult-register--narrow'. Marker positions are previewed. See +`jump-to-register' and `insert-register' for the meaning of prefix ARG." + (interactive "P") + (consult-register-load + (consult--read + (consult-register--candidates) + :prompt "Register: " + :category 'multi-category + :state + (let ((preview (consult--jump-preview))) + (lambda (action cand) + ;; Preview only markers + (funcall preview action + (when-let (reg (get-register cand)) + (and (markerp reg) reg))))) + :group (consult--type-group consult-register--narrow) + :narrow (consult--type-narrow consult-register--narrow) + :sort nil + :require-match t + :history t ;; disable history + :lookup #'consult--lookup-candidate) + arg)) + +;;;###autoload +(defun consult-register-load (reg &optional arg) + "Do what I mean with a REG. + +For a window configuration, restore it. For a number or text, insert it. +For a location, jump to it. See `jump-to-register' and `insert-register' +for the meaning of prefix ARG." + (interactive + (list + (and (consult-register--alist) + (register-read-with-preview "Load register: ")) + current-prefix-arg)) + (condition-case err + (jump-to-register reg arg) + (user-error + (unless (string-search "access aborted" (error-message-string err)) + (insert-register reg (not arg)))))) + +(defun consult-register--action (action-list) + "Read register key and execute action from ACTION-LIST. + +This function is derived from `register-read-with-preview'." + (let* ((buffer "*Register Preview*") + (prefix (car action-list)) + (action-list (cdr action-list)) + (action (car (nth 0 action-list))) + (preview + (lambda () + (unless (get-buffer-window buffer) + (register-preview buffer 'show-empty) + (when-let (win (get-buffer-window buffer)) + (with-selected-window win + (let ((inhibit-read-only t)) + (goto-char (point-max)) + (insert + (propertize (concat prefix ": ") 'face 'consult-help) + (mapconcat + (lambda (x) + (concat (propertize (format "M-%c" (car x)) 'face 'consult-key) + " " (propertize (cadr x) 'face 'consult-help))) + action-list " ")) + (fit-window-to-buffer))))))) + (timer (when (numberp register-preview-delay) + (run-at-time register-preview-delay nil preview))) + (help-chars (seq-remove #'get-register (cons help-char help-event-list))) + key reg) + (unwind-protect + (while (not reg) + (while (memq (setq key + (read-key (propertize (caddr (assq action action-list)) + 'face 'minibuffer-prompt))) + help-chars) + (funcall preview)) + (setq key (if (and (eql key ?\e) (characterp last-input-event)) + ;; in terminal Emacs M-letter is read as two keys, ESC and the letter, + ;; use what would have been read in graphical Emacs + (logior #x8000000 last-input-event) + last-input-event)) + (cond + ((or (eq ?\C-g key) + (eq 'escape key) + (eq ?\C-\[ key)) + (keyboard-quit)) + ((and (numberp key) (assq (logxor #x8000000 key) action-list)) + (setq action (logxor #x8000000 key))) + ((characterp key) + (setq reg key)) + (t (error "Non-character input")))) + (when (timerp timer) + (cancel-timer timer)) + (let ((w (get-buffer-window buffer))) + (when (window-live-p w) + (delete-window w))) + (when (get-buffer buffer) + (kill-buffer buffer))) + (when reg + (funcall (cadddr (assq action action-list)) reg)))) + +;;;###autoload +(defun consult-register-store (arg) + "Store register dependent on current context, showing an action menu. + +With an active region, store/append/prepend the contents, optionally +deleting the region when a prefix ARG is given. With a numeric prefix +ARG, store or add the number. Otherwise store point, frameset, window or +kmacro." + (interactive "P") + (consult-register--action + (cond + ((use-region-p) + (let ((beg (region-beginning)) + (end (region-end))) + `("Region" + (?c "copy" "Copy region to register: " ,(lambda (r) (copy-to-register r beg end arg t))) + (?a "append" "Append region to register: " ,(lambda (r) (append-to-register r beg end arg))) + (?p "prepend" "Prepend region to register: " ,(lambda (r) (prepend-to-register r beg end arg)))))) + ((numberp arg) + `(,(format "Number %s" arg) + (?s "store" ,(format "Store %s in register: " arg) ,(lambda (r) (number-to-register arg r))) + (?a "add" ,(format "Add %s to register: " arg) ,(lambda (r) (increment-register arg r))))) + (t + `("Store" + (?p "point" "Point to register: " ,#'point-to-register) + (?f "file" "File to register: " ,(lambda (r) (set-register r `(file . ,(buffer-file-name))))) + (?t "frameset" "Frameset to register: " ,#'frameset-to-register) + (?w "window" "Window to register: " ,#'window-configuration-to-register) + ,@(and last-kbd-macro `((?k "kmacro" "Kmacro to register: " ,#'kmacro-to-register)))))))) + +(provide 'consult-register) +;;; consult-register.el ends here diff --git a/consult-vertico.el b/consult-vertico.el new file mode 100644 index 0000000..79eb08f --- /dev/null +++ b/consult-vertico.el @@ -0,0 +1,63 @@ +;;; 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 . + +;;; 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-xref.el b/consult-xref.el new file mode 100644 index 0000000..306990f --- /dev/null +++ b/consult-xref.el @@ -0,0 +1,120 @@ +;;; consult-xref.el --- Xref 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 . + +;;; Commentary: + +;; Provides Xref integration for Consult. This is an extra package, to +;; allow lazy loading of xref.el. The `consult-xref' function is +;; autoloaded. + +;;; Code: + +(require 'consult) +(require 'xref) + +(defvar consult-xref--history nil) + +(defvar consult-xref--fetcher nil + "The current xref fetcher. +The fetch is stored globally such that it can be accessed by + Embark for `embark-export'.") + +(defun consult-xref--candidates () + "Return xref candidate list." + (let ((root (consult--project-root))) + (mapcar (lambda (xref) + (let* ((loc (xref-item-location xref)) + (group (if (fboundp 'xref--group-name-for-display) + ;; This function is available in xref 1.3.2 + (xref--group-name-for-display + (xref-location-group loc) root) + (xref-location-group loc))) + (cand (consult--format-file-line-match + group + (or (xref-location-line loc) 0) + (xref-item-summary xref)))) + (add-text-properties + 0 1 `(consult-xref ,xref consult--prefix-group ,group) cand) + cand)) + (funcall consult-xref--fetcher)))) + +(defun consult-xref--preview (display) + "Xref preview with DISPLAY function." + (let ((open (consult--temporary-files)) + (preview (consult--jump-preview))) + (lambda (action cand) + (unless cand + (funcall open)) + (let ((consult--buffer-display display)) + (funcall preview action + (when-let (loc (and cand (eq action 'preview) + (xref-item-location cand))) + (let ((type (type-of loc))) + ;; Only preview file and buffer markers + (pcase type + ('xref-buffer-location + (xref-location-marker loc)) + ((or 'xref-file-location 'xref-etags-location) + (consult--marker-from-line-column + (funcall open + ;; xref-location-group returns the file name + (let ((xref-file-name-display 'abs)) + (xref-location-group loc))) + (xref-location-line loc) + (if (eq type 'xref-file-location) + (xref-file-location-column loc) + 0))))))))))) + +;;;###autoload +(defun consult-xref (fetcher &optional alist) + "Show xrefs with preview in the minibuffer. + +This function can be used for `xref-show-xrefs-function'. +See `xref-show-xrefs-function' for the description of the +FETCHER and ALIST arguments." + (let* ((consult-xref--fetcher fetcher) + (candidates (consult-xref--candidates)) + (display (alist-get 'display-action alist))) + (xref-pop-to-location + (if (cdr candidates) + (apply + #'consult--read + candidates + (append + (consult--customize-get #'consult-xref) + (list + :prompt "Go to xref: " + :history 'consult-xref--history + :require-match t + :sort nil + :category 'consult-xref + :group #'consult--prefix-group + :state + ;; do not preview other frame + (when-let (fun (pcase-exhaustive display + ('frame nil) + ('window #'switch-to-buffer-other-window) + ('nil #'switch-to-buffer))) + (consult-xref--preview fun)) + :lookup (apply-partially #'consult--lookup-prop 'consult-xref)))) + (get-text-property 0 'consult-xref (car candidates))) + display))) + +(provide 'consult-xref) +;;; consult-xref.el ends here diff --git a/consult.el b/consult.el new file mode 100644 index 0000000..80cbb93 --- /dev/null +++ b/consult.el @@ -0,0 +1,5033 @@ +;;; consult.el --- Consulting completing-read -*- lexical-binding: t -*- + +;; Copyright (C) 2021-2023 Free Software Foundation, Inc. + +;; Author: Daniel Mendler and Consult contributors +;; Maintainer: Daniel Mendler +;; Created: 2020 +;; Version: 0.32 +;; Package-Requires: ((emacs "27.1") (compat "29.1.3.2")) +;; Homepage: https://github.com/minad/consult + +;; 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 . + +;;; Commentary: + +;; Consult implements a set of `consult-' commands, which aim to +;; improve the way you use Emacs. The commands are founded on +;; `completing-read', which selects from a list of candidate strings. +;; Consult provides an enhanced buffer switcher `consult-buffer' and +;; search and navigation commands like `consult-imenu' and +;; `consult-line'. Searching through multiple files is supported by the +;; asynchronous `consult-grep' command. Many Consult commands support +;; previewing candidates. If a candidate is selected in the completion +;; view, the buffer shows the candidate immediately. + +;; The Consult commands are compatible with multiple completion systems +;; based on the Emacs `completing-read' API, including the default +;; completion system, Vertico, Mct and Icomplete. + +;; See the README for an overview of the available Consult commands and +;; the documentation of the configuration and installation of the +;; package. + +;; The full list of contributors can be found in the acknowledgments +;; section of the README. + +;;; Code: + +(eval-when-compile + (require 'cl-lib) + (require 'subr-x)) +(require 'seq) +(require 'compat) +(require 'bookmark) + +(defgroup consult nil + "Consulting `completing-read'." + :link '(info-link :tag "Info Manual" "(consult)") + :link '(url-link :tag "Homepage" "https://github.com/minad/consult") + :link '(emacs-library-link :tag "Library Source" "consult.el") + :group 'files + :group 'outlines + :group 'minibuffer + :prefix "consult-") + +;;;; Customization + +(defcustom consult-narrow-key nil + "Prefix key for narrowing during completion. + +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))) + +(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))) + +(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'." + :type '(choice function (const nil))) + +(defcustom consult-async-refresh-delay 0.2 + "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'." + :type 'float) + +(defcustom consult-async-input-throttle 0.4 + "Input throttle for asynchronous commands. + +The asynchronous process is started only every +`consult-async-input-throttle' seconds. This applies to asynchronous +commands, e.g., `consult-grep'." + :type 'float) + +(defcustom consult-async-input-debounce 0.2 + "Input debounce for asynchronous commands. + +The asynchronous process is started only when there has not been new +input for `consult-async-input-debounce' seconds. This applies to +asynchronous commands, e.g., `consult-grep'." + :type 'float) + +(defcustom consult-async-min-input 3 + "Minimum number of letters needed, before asynchronous process is called. + +This applies to asynchronous commands, e.g., `consult-grep'." + :type 'integer) + +(defcustom consult-async-split-style 'perl + "Async splitting style, see `consult-async-split-styles-alist'." + :type '(choice (const :tag "No splitting" nil) + (const :tag "Comma" comma) + (const :tag "Semicolon" semicolon) + (const :tag "Perl" perl))) + +(defcustom consult-async-split-styles-alist + '((nil :function consult--split-nil) + (comma :separator ?, :function consult--split-separator) + (semicolon :separator ?\; :function consult--split-separator) + (perl :initial "#" :function consult--split-perl)) + "Async splitting styles." + :type '(alist :key-type symbol :value-type plist)) + +(defcustom consult-mode-histories + '((eshell-mode eshell-history-ring eshell-history-index eshell-bol) + (comint-mode comint-input-ring comint-input-ring-index comint-bol) + (term-mode term-input-ring term-input-ring-index term-bol)) + "Alist of mode histories (mode history index bol). +The histories can be rings or lists. Index, if provided, is a +variable to set to the index of the selection within the ring or +list. Bol, if provided is a function which jumps to the beginning +of the line after the prompt." + :type '(alist :key-type symbol + :value-type (group :tag "Include Index" + (symbol :tag "List/Ring") + (symbol :tag "Index Variable") + (symbol :tag "Bol Function")))) + +(defcustom consult-themes nil + "List of themes (symbols or regexps) to be presented for selection. +nil shows all `custom-available-themes'." + :type '(repeat (choice symbol regexp))) + +(defcustom consult-after-jump-hook '(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 +after selection." + :type 'hook) + +(defcustom consult-line-start-from-top nil + "Start search from the top if non-nil. +Otherwise start the search at the current line and wrap around." + :type 'boolean) + +(defcustom consult-point-placement 'match-beginning + "Where to leave point when jumping to a match. +This setting affects the command `consult-line' and the `consult-grep' variants." + :type '(choice (const :tag "Beginning of the line" line-beginning) + (const :tag "Beginning of the match" match-beginning) + (const :tag "End of the match" match-end))) + +(defcustom consult-line-numbers-widen t + "Show absolute line numbers when narrowing is active. + +See also `display-line-numbers-widen'." + :type 'boolean) + +(defcustom consult-goto-line-numbers t + "Show line numbers for `consult-goto-line'." + :type 'boolean) + +(defcustom consult-fontify-preserve t + "Preserve fontification for line-based commands." + :type 'boolean) + +(defcustom consult-fontify-max-size 1048576 + "Buffers larger than this byte limit are not fontified. + +This is necessary in order to prevent a large startup time +for navigation commands like `consult-line'." + :type 'integer) + +(defcustom consult-buffer-filter + '("\\` " + "\\`\\*Completions\\*\\'" + "\\`\\*Flymake log\\*\\'" + "\\`\\*Semantic SymRef\\*\\'" + "\\`\\*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." + :type '(repeat regexp)) + +(defcustom consult-buffer-sources + '(consult--source-hidden-buffer + consult--source-modified-buffer + consult--source-buffer + consult--source-recent-file + consult--source-file-register + consult--source-bookmark + consult--source-project-buffer + consult--source-project-recent-file) + "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 + "Sources used by `consult-project-buffer'. +See also `consult-buffer-sources'. +See `consult--multi' for a description of the source data structure." + :type '(repeat symbol)) + +(defcustom consult-mode-command-filter + '(;; Filter commands + "-mode\\'" "--" + ;; Filter whole features + simple mwheel time so-long recentf) + "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) + +(defconst consult--grep-match-regexp + "\\`\\(?:\\./\\)?\\([^\n\0]+\\)\0\\([0-9]+\\)\\([-:\0]\\)" + "Regexp used to match file and line of grep output.") + +(defcustom consult-grep-args + '("grep" (consult--grep-exclude-args) + "--null --line-buffered --color=never --ignore-case --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." + :type '(choice string (repeat (choice string expression)))) + +(defcustom consult-git-grep-args + "git --no-pager grep --null --color=never --ignore-case\ + --extended-regexp --line-number -I" + "Command line arguments for git-grep, see `consult-git-grep'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string expression)))) + +(defcustom consult-ripgrep-args + "rg --null --line-buffered --color=never --max-columns=1000 --path-separator /\ + --smart-case --no-heading --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." + :type '(choice string (repeat (choice string expression)))) + +(defcustom consult-find-args + "find . -not ( -wholename */.* -prune )" + "Command line arguments for find, see `consult-find'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string expression)))) + +(defcustom consult-locate-args + "locate --ignore-case" ;; --existing not supported by Debian plocate + "Command line arguments for locate, see `consult-locate'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string expression)))) + +(defcustom consult-man-args + "man -k" + "Command line arguments for man, see `consult-man'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string expression)))) + +(defcustom consult-preview-key 'any + "Preview trigger keys, can be nil, `any', a single key or a list of keys. +Debouncing can be specified via the `:debounce' attribute. The +individual keys must be strings accepted by `key-valid-p'." + :type '(choice (const :tag "Any key" any) + (list :tag "Debounced" + (const :debounce) + (float :tag "Seconds" 0.1) + (const any)) + (const :tag "No preview" nil) + (string :tag "Key") + (repeat :tag "List of keys" string))) + +(defcustom consult-preview-max-size 10485760 + "Files larger than this byte limit are not previewed." + :type 'integer) + +(defcustom consult-preview-raw-size 524288 + "Files larger than this byte limit are previewed in raw form." + :type 'integer) + +(defcustom consult-preview-max-count 10 + "Number of files to keep open at once during preview." + :type 'integer) + +(defcustom consult-preview-excluded-files nil + "List of regexps matched against names of files, which are not previewed." + :type '(repeat regexp)) + +(defcustom consult-preview-allowed-hooks + '(global-font-lock-mode-check-buffers + save-place-find-file-hook) + "List of `find-file' hooks, which should be executed during file preview." + :type '(repeat symbol)) + +(defcustom consult-preview-variables + '((inhibit-message . t) + (enable-dir-local-variables . nil) + (enable-local-variables . :safe) + (non-essential . t) + (delay-mode-hooks . t)) + "Variables which are bound for file preview." + :type '(alist :key-type symbol)) + +(defcustom consult-bookmark-narrow + `((?f "File" ,#'bookmark-default-handler) + (?h "Help" ,#'help-bookmark-jump) + (?i "Info" ,#'Info-bookmark-jump) + (?p "Picture" ,#'image-bookmark-jump) + (?d "Docview" ,#'doc-view-bookmark-jump) + (?m "Man" ,#'Man-bookmark-jump) + (?w "Woman" ,#'woman-bookmark-jump) + (?g "Gnus" ,#'gnus-summary-bookmark-jump) + ;; Introduced on Emacs 28 + (?s "Eshell" eshell-bookmark-jump) + (?e "Eww" eww-bookmark-jump) + (?v "VC Directory" vc-dir-bookmark-jump)) + "Bookmark narrowing configuration. + +Each element of the list must have the form (char name handler)." + :type '(repeat (list character string function))) + +(defcustom consult-yank-rotate + (if (boundp 'yank-from-kill-ring-rotate) + yank-from-kill-ring-rotate + t) + "Rotate the `kill-ring' in the `consult-yank' commands." + :type 'boolean) + +;;;; Faces + +(defgroup consult-faces nil + "Faces used by Consult." + :group 'consult + :group 'faces) + +(defface consult-preview-line + '((t :inherit consult-preview-insertion :extend t)) + "Face used for line previews.") + +(defface consult-highlight-match + '((t :inherit match)) + "Face used to highlight matches in the completion candidates. +Used for example in `consult-grep'.") + +(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. +Used by `consult-completion-in-region', `consult-yank' and `consult-history'.") + +(defface consult-narrow-indicator + '((t :inherit warning)) + "Face used for the narrowing indicator.") + +(defface consult-async-running + '((t :inherit consult-narrow-indicator)) + "Face used if asynchronous process is running.") + +(defface consult-async-finished + '((t :inherit success)) + "Face used if asynchronous process has finished.") + +(defface consult-async-failed + '((t :inherit error)) + "Face used if asynchronous process has failed.") + +(defface consult-async-split + '((t :inherit font-lock-negation-char-face)) + "Face used to highlight punctuation character.") + +(defface consult-help + '((t :inherit shadow)) + "Face used to highlight help, e.g., in `consult-register-store'.") + +(defface consult-key + '((t :inherit font-lock-keyword-face)) + "Face used to highlight keys, e.g., in `consult-register'.") + +(defface consult-line-number + '((t :inherit consult-key)) + "Face used to highlight location line in `consult-global-mark'.") + +(defface consult-file + '((t :inherit font-lock-function-name-face)) + "Face used to highlight files in `consult-buffer'.") + +(defface consult-grep-context + '((t :inherit shadow)) + "Face used to highlight grep context in `consult-grep'.") + +(defface consult-bookmark + '((t :inherit font-lock-constant-face)) + "Face used to highlight bookmarks in `consult-buffer'.") + +(defface consult-buffer + '((t)) + "Face used to highlight buffers in `consult-buffer'.") + +(defface consult-line-number-prefix + '((t :inherit line-number)) + "Face used to highlight line number prefixes.") + +(defface consult-line-number-wrapped + '((t :inherit consult-line-number-prefix :inherit font-lock-warning-face)) + "Face used to highlight line number prefixes after wrap around.") + +(defface consult-separator + '((((class color) (min-colors 88) (background light)) + :foreground "#ccc") + (((class color) (min-colors 88) (background dark)) + :foreground "#333")) + "Face used for thin line separators in `consult-register-window'.") + +;;;; History variables + +(defvar consult--keep-lines-history nil) +(defvar consult--grep-history nil) +(defvar consult--find-history nil) +(defvar consult--man-history nil) +(defvar consult--line-history nil) +(defvar consult--line-multi-history nil) +(defvar consult--theme-history nil) +(defvar consult--minor-mode-menu-history nil) +(defvar consult--buffer-history nil) + +;;;; Internal variables + +(defvar consult--regexp-compiler + #'consult--default-regexp-compiler + "Regular expression compiler used by `consult-grep' and other commands. +The function must return a list of regular expressions and a highlighter +function.") + +(defvar consult--customize-alist + ;; Disable preview in frames, since frames do not get up cleaned + ;; properly. Preview is only supported by `consult-buffer' and + ;; `consult-buffer-other-window'. + `((,#'consult-buffer-other-frame :preview-key nil)) + "Command configuration alist for fine-grained configuration. + +Each element of the list must have the form (command-name plist...). The +options set here will be evaluated and passed to `consult--read', when +called from the corresponding command. Note that the options depend on +the private `consult--read' API and should not be considered as stable +as the public API.") + +(defvar consult--buffer-display #'switch-to-buffer + "Buffer display function.") + +(defvar consult--completion-candidate-hook + (list #'consult--default-completion-minibuffer-candidate + #'consult--default-completion-list-candidate) + "Get candidate from completion system.") + +(defvar consult--completion-refresh-hook nil + "Refresh completion system.") + +(defvar-local consult--preview-function nil + "Minibuffer-local variable which exposes the current preview function. +This function can be called by custom completion systems from +outside the minibuffer.") + +(defconst consult--tofu-char #x200000 + "Special character used to encode line prefixes for disambiguation. +We use invalid characters outside the Unicode range.") + +(defconst consult--tofu-range #x100000 + "Special character range.") + +(defvar-local consult--narrow nil + "Current narrowing key.") + +(defvar-local consult--narrow-keys nil + "Narrowing prefixes of the current completion.") + +(defvar-local consult--narrow-predicate nil + "Narrowing predicate of the current completion.") + +(defvar-local consult--narrow-overlay nil + "Narrowing indicator overlay.") + +(defvar consult--gc-threshold (* 64 1024 1024) + "Large gc threshold for temporary increase.") + +(defvar consult--gc-percentage 0.5 + "Large gc percentage for temporary increase.") + +(defvar consult--process-chunk (* 1024 1024) + "Increase process output chunk size.") + +(defvar consult--async-log + " *consult-async*" + "Buffer for async logging output used by `consult--async-process'.") + +(defvar-local consult--focus-lines-overlays nil + "Overlays used by `consult-focus-lines'.") + +(defvar-local consult--org-fold-regions nil + "Stored regions for the org-fold API.") + +;;;; Miscellaneous helper functions + +(defun consult--in-buffer (fun &optional buffer) + "Ensure that FUN is executed inside BUFFER." + (unless buffer (setq buffer (current-buffer))) + (lambda (&rest args) + (with-current-buffer buffer + (apply fun args)))) + +(defun consult--completion-table-in-buffer (table &optional buffer) + "Ensure that completion TABLE is executed inside BUFFER." + (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))) + buffer) + table)) + +(defun consult--build-args (arg) + "Return ARG as a flat list of split strings. + +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))) + +(defun consult--command-split (str) + "Return command argument and options list given input STR." + (save-match-data + (let ((opts (when (string-match " +--\\( +\\|\\'\\)" str) + (prog1 (substring str (match-end 0)) + (setq str (substring str 0 (match-beginning 0))))))) + ;; split-string-and-unquote fails if the quotes are invalid. Ignore it. + (cons str (and opts (ignore-errors (split-string-and-unquote opts))))))) + +(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"))) + `(let* ((,head (cons nil ,list)) + (,prev ,head)) + (while (cdr ,prev) + (if-let (,result (let ((it (cadr ,prev))) ,form)) + (progn + (pop ,prev) + (setcar ,prev ,result)) + (setcdr ,prev (cddr ,prev)))) + (setq ,list (cdr ,head)) + nil))) + +;; Upstream bug#46326, Consult issue gh:minad/consult#193. +(defmacro consult--minibuffer-with-setup-hook (fun &rest body) + "Variant of `minibuffer-with-setup-hook' using a symbol and `fset'. + +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")) + (append)) + (when (eq (car-safe fun) :append) + (setq append '(t) fun (cadr fun))) + `(let ((,hook (make-symbol "consult--minibuffer-setup"))) + (fset ,hook (lambda () + (remove-hook 'minibuffer-setup-hook ,hook) + (funcall ,fun))) + (unwind-protect + (progn + (add-hook 'minibuffer-setup-hook ,hook ,@append) + ,@body) + (remove-hook 'minibuffer-setup-hook ,hook))))) + +(defun consult--completion-filter (pattern cands category _highlight) + "Filter CANDS with PATTERN. + +CATEGORY is the completion category, used to find the completion style via +`completion-category-defaults' and `completion-category-overrides'. +HIGHLIGHT must be non-nil if the resulting strings should be highlighted." + ;; completion-all-completions returns an improper list + ;; where the last link is not necessarily nil. + (nconc (completion-all-completions pattern cands nil (length pattern) + `(metadata (category . ,category))) + nil)) + +(defun consult--completion-filter-complement (pattern cands category _highlight) + "Filter CANDS with complement of PATTERN. +See `consult--completion-filter' for the arguments CATEGORY and HIGHLIGHT." + (let ((ht (consult--string-hash (consult--completion-filter pattern cands category nil)))) + (seq-remove (lambda (x) (gethash x ht)) cands))) + +(defun consult--completion-filter-dispatch (pattern cands category highlight) + "Filter CANDS with PATTERN with optional complement. +Either using `consult--completion-filter' or +`consult--completion-filter-complement', depending on if the pattern starts +with a bang. See `consult--completion-filter' for the arguments CATEGORY and +HIGHLIGHT." + (cond + ((string-match-p "\\`!? ?\\'" pattern) cands) ;; empty pattern + ((string-prefix-p "! " pattern) (consult--completion-filter-complement + (substring pattern 2) cands category nil)) + (t (consult--completion-filter pattern cands category highlight)))) + +(defmacro consult--each-line (beg end &rest body) + "Iterate over each line. + +The line beginning/ending BEG/END is bound in BODY." + (declare (indent 2)) + (let ((max (make-symbol "max"))) + `(save-excursion + (let ((,beg (point-min)) (,max (point-max)) end) + (while (< ,beg ,max) + (goto-char ,beg) + (setq ,end (pos-eol)) + ,@body + (setq ,beg (1+ ,end))))))) + +(defun consult--display-width (string) + "Compute width of STRING taking display and invisible properties into account." + (let ((pos 0) (width 0) (end (length string))) + (while (< pos end) + (let ((nextd (next-single-property-change pos 'display string end)) + (display (get-text-property pos 'display string))) + (if (stringp display) + (setq width (+ width (string-width display)) + pos nextd) + (while (< pos nextd) + (let ((nexti (next-single-property-change pos 'invisible string nextd))) + (unless (get-text-property pos 'invisible string) + (setq width (+ width (compat-call string-width string pos nexti)))) + (setq pos nexti)))))) + width)) + +(defun consult--string-hash (strings) + "Create hashtable from STRINGS." + (let ((ht (make-hash-table :test #'equal :size (length strings)))) + (dolist (str strings) + (puthash str t ht)) + ht)) + +(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 (current-buffer)) + ,@(mapcar (lambda (x) `(,(car x) (local-variable-p ',(cdr x)))) local)) + (unwind-protect + (progn + ,@(mapcar (lambda (x) `(make-local-variable ',(car x))) binds) + (let (,@binds) + ,@body)) + (when (buffer-live-p ,buffer) + (with-current-buffer ,buffer + ,@(mapcar (lambda (x) + `(unless ,(car x) + (kill-local-variable ',(cdr x)))) + local))))))) + +(defun consult--abbreviate-directory (dir) + "Return abbreviated directory DIR 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)))) + +(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)))) + (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 + (format "%s (%s): " prompt + (if (equal edir pdir) + (concat "Project " (consult--project-name pdir)) + (consult--abbreviate-directory dir))) + edir))) + +(defun consult--default-project-function (may-prompt) + "Return project root directory. +When no project is found and MAY-PROMPT is non-nil ask the user." + (when-let (proj (project-current may-prompt)) + (cond + ((fboundp 'project-root) (project-root proj)) + ((fboundp 'project-roots) (car (project-roots proj)))))) + +(defun consult--project-root (&optional may-prompt) + "Return project root as absolute path. +When no project is found and MAY-PROMPT is non-nil ask the user." + ;; Preserve this-command across project selection, + ;; such that `consult-customize' continues to work. + (let ((this-command this-command)) + (when-let (root (and consult-project-function + (funcall consult-project-function may-prompt))) + (expand-file-name root)))) + +(defun consult--project-name (dir) + "Return the project name for DIR." + (if (string-match "/\\([^/]+\\)/\\'" dir) + (match-string 1 dir) + dir)) + +(defun consult--format-file-line-match (file line &optional match) + "Format string FILE:LINE:MATCH with faces." + (setq line (number-to-string line) + match (concat file ":" line (and match ":") 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) + "Make consult overlay between BEG and END with PROPS." + (let ((ov (make-symbol "ov")) + (puts)) + (while props + (push `(overlay-put ,ov ,(car props) ,(cadr props)) puts) + (setq props (cddr props))) + `(let ((,ov (make-overlay ,beg ,end))) + ,@puts + ,ov))) + +(defun consult--remove-dups (list) + "Remove duplicate strings from LIST." + (delete-dups (copy-sequence list))) + +(defsubst consult--in-range-p (pos) + "Return t if position POS lies in range `point-min' to `point-max'." + (<= (point-min) pos (point-max))) + +(defun consult--completion-window-p () + "Return non-nil if the selected window belongs to the completion UI." + (or (eq (selected-window) (active-minibuffer-window)) + (eq #'completion-list-mode (buffer-local-value 'major-mode (window-buffer))))) + +(defun consult--forbid-minibuffer () + "Raise an error if executed from the minibuffer." + (when (minibufferp) + (user-error "`%s' called inside the minibuffer" this-command))) + +(defun consult--require-minibuffer () + "Raise an error if executed outside the minibuffer." + (unless (minibufferp) + (user-error "`%s' must be called inside the minibuffer" this-command))) + +(defun consult--fontify-all () + "Ensure that the whole buffer is fontified." + ;; Font-locking is lazy, i.e., if a line has not been looked at yet, the line + ;; is not font-locked. We would observe this if consulting an unfontified + ;; line. Therefore we have to enforce font-locking now, which is slow. In + ;; order to prevent is hang-up we check the buffer size against + ;; `consult-fontify-max-size'. + (when (and consult-fontify-preserve jit-lock-mode + (< (buffer-size) consult-fontify-max-size)) + (jit-lock-fontify-now))) + +(defun consult--fontify-region (start end) + "Ensure that region between START and END is fontified." + (when (and consult-fontify-preserve jit-lock-mode) + (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"))) + `(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))) + ,@body))) + +(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'." + (declare (indent 1)) + `(with-delayed-message (1 ,message) + (consult--with-increased-gc + ,@body))) + +(defun consult--count-lines (pos) + "Move to position POS and return number of lines." + (let ((line 1)) + (while (< (point) pos) + (forward-line) + (when (<= (point) pos) + (cl-incf line))) + (goto-char pos) + line)) + +(defun consult--marker-from-line-column (buffer line column) + "Get marker in BUFFER from LINE and COLUMN." + (when (buffer-live-p buffer) + (with-current-buffer buffer + (save-restriction + (save-excursion + (widen) + (goto-char (point-min)) + ;; Location data might be invalid by now! + (ignore-errors + (forward-line (1- line)) + (forward-char column)) + (point-marker)))))) + +(defun consult--line-prefix (&optional curr-line) + "Annotate `consult-location' candidates with line numbers. +CURR-LINE is the current line number." + (setq curr-line (or curr-line -1)) + (let* ((width (length (number-to-string (line-number-at-pos + (point-max) + consult-line-numbers-widen)))) + (before (format #("%%%dd " 0 6 (face consult-line-number-wrapped)) width)) + (after (format #("%%%dd " 0 6 (face consult-line-number-prefix)) width))) + (lambda (cand) + (let ((line (cdr (get-text-property 0 'consult-location cand)))) + (list cand (format (if (< line curr-line) before after) line) ""))))) + +(defsubst consult--location-candidate (cand marker line tofu &rest props) + "Add MARKER and LINE as `consult-location' text property to CAND. +Furthermore add the additional text properties PROPS, and append +TOFU suffix for disambiguation." + (setq cand (concat cand (consult--tofu-encode tofu))) + (add-text-properties 0 1 `(consult-location (,marker . ,line) ,@props) cand) + cand) + +;; There is a similar variable `yank-excluded-properties'. Unfortunately +;; we cannot use it here since it excludes too much (e.g., invisible) +;; and at the same time not enough (e.g., cursor-sensor-functions). +(defconst consult--remove-text-properties + '(category cursor cursor-intangible cursor-sensor-functions field follow-link + fontified front-sticky help-echo insert-behind-hooks insert-in-front-hooks + intangible keymap local-map modification-hooks mouse-face pointer read-only + rear-nonsticky yank-handler) + "List of text properties to remove from buffer strings.") + +(defsubst consult--buffer-substring (beg end &optional fontify) + "Return buffer substring between BEG and END. +If FONTIFY and `consult-fontify-preserve' are non-nil, first ensure that the +region has been fontified." + (if consult-fontify-preserve + (let (str) + (when fontify (consult--fontify-region beg end)) + (setq str (buffer-substring beg end)) + ;; TODO Propose the upstream addition of a function + ;; `preserve-list-of-text-properties', which should be as efficient as + ;; `remove-list-of-text-properties'. + (remove-list-of-text-properties + 0 (- end beg) consult--remove-text-properties str) + 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))) + (if (>= marker end) + (concat str #(" " 0 1 (face consult-preview-cursor))) + (put-text-property (- marker beg) (- (1+ marker) beg) + 'face 'consult-preview-cursor 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)) + +;;;; Regexp utilities + +(defun consult--find-highlights (str start &rest ignored-faces) + "Find highlighted regions in STR from position START. +Highlighted regions have a non-nil face property. +IGNORED-FACES are ignored when searching for matches." + (let (highlights + (end (length str)) + (beg start)) + (while (< beg end) + (let ((next (next-single-property-change beg 'face str end)) + (val (get-text-property beg 'face str))) + (when (and val + (not (memq val ignored-faces)) + (not (and (consp val) + (seq-some (lambda (x) (memq x ignored-faces)) val)))) + (push (cons (- beg start) (- next start)) highlights)) + (setq beg next))) + (nreverse highlights))) + +(defun consult--point-placement (str start &rest ignored-faces) + "Compute point placement from STR with START offset. +IGNORED-FACES are ignored when searching for matches. +Return cons of point position and a list of match begin/end pairs." + (let* ((matches (apply #'consult--find-highlights str start ignored-faces)) + (pos (pcase-exhaustive consult-point-placement + ('match-beginning (or (caar matches) 0)) + ('match-end (or (cdar (last matches)) 0)) + ('line-beginning 0)))) + (dolist (match matches) + (cl-decf (car match) pos) + (cl-decf (cdr match) pos)) + (cons pos matches))) + +(defun consult--highlight-regexps (regexps ignore-case str) + "Highlight REGEXPS in STR. +If a regular expression contains capturing groups, only these are highlighted. +If no capturing groups are used highlight the whole match. Case is ignored +if IGNORE-CASE is non-nil." + (dolist (re regexps) + (let ((i 0)) + (while (and (let ((case-fold-search ignore-case)) + (string-match re str i)) + ;; Ensure that regexp search made progress (edge case for .*) + (> (match-end 0) i)) + ;; Unfortunately there is no way to avoid the allocation of the match + ;; data, since the number of capturing groups is unknown. + (let ((m (match-data))) + (setq i (cadr m) m (or (cddr m) m)) + (while m + (when (car m) + (add-face-text-property (car m) (cadr m) + 'consult-highlight-match nil str)) + (setq m (cddr m))))))) + str) + +(defconst consult--convert-regexp-table + (append + ;; For simplicity, treat word beginning/end as word boundaries, + ;; since PCRE does not make this distinction. Usually the + ;; context determines if \b is the beginning or the end. + '(("\\<" . "\\b") ("\\>" . "\\b") + ("\\_<" . "\\b") ("\\_>" . "\\b")) + ;; Treat \` and \' as beginning and end of line. This is more + ;; widely supported and makes sense for line-based commands. + '(("\\`" . "^") ("\\'" . "$")) + ;; Historical: Unescaped *, +, ? are supported at the beginning + (mapcan (lambda (x) + (mapcar (lambda (y) + (cons (concat x y) + (concat (string-remove-prefix "\\" x) "\\" y))) + '("*" "+" "?"))) + '("" "\\(" "\\(?:" "\\|" "^")) + ;; Different escaping + (mapcan (lambda (x) `(,x (,(cdr x) . ,(car x)))) + '(("\\|" . "|") + ("\\(" . "(") ("\\)" . ")") + ("\\{" . "{") ("\\}" . "}")))) + "Regexp conversion table.") + +(defun consult--convert-regexp (regexp type) + "Convert Emacs REGEXP to regexp syntax TYPE." + (if (memq type '(emacs basic)) + regexp + ;; Support for Emacs regular expressions is fairly complete for basic + ;; usage. There are a few unsupported Emacs regexp features: + ;; - \= point matching + ;; - Syntax classes \sx \Sx + ;; - Character classes \cx \Cx + ;; - Explicitly numbered groups (?3:group) + (replace-regexp-in-string + (rx (or "\\\\" "\\^" ;; Pass through + (seq (or "\\(?:" "\\|") (any "*+?")) ;; Historical: \|+ or \(?:* etc + (seq "\\(" (any "*+")) ;; Historical: \(* or \(+ + (seq (or bos "^") (any "*+?")) ;; Historical: + or * at the beginning + (seq (opt "\\") (any "(){|}")) ;; Escape parens/braces/pipe + (seq "\\" (any "'<>`")) ;; Special escapes + (seq "\\_" (any "<>")))) ;; Beginning or end of symbol + (lambda (x) (or (cdr (assoc x consult--convert-regexp-table)) x)) + regexp 'fixedcase 'literal))) + +(defun consult--default-regexp-compiler (input type ignore-case) + "Compile the INPUT string to a list of regular expressions. +The function should return a pair, the list of regular expressions and a +highlight function. The highlight function should take a single +argument, the string to highlight given the INPUT. TYPE is the desired +type of regular expression, which can be `basic', `extended', `emacs' or +`pcre'. If IGNORE-CASE is non-nil return a highlight function which +matches case insensitively." + (setq input (consult--split-escaped input)) + (cons (mapcar (lambda (x) (consult--convert-regexp x type)) input) + (when-let (regexps (seq-filter #'consult--valid-regexp-p input)) + (apply-partially #'consult--highlight-regexps regexps ignore-case)))) + +(defun consult--split-escaped (str) + "Split STR at spaces, which can be escaped with backslash." + (mapcar + (lambda (x) (string-replace "\0" " " x)) + (split-string (replace-regexp-in-string + "\\\\\\\\\\|\\\\ " + (lambda (x) (if (equal x "\\ ") "\0" x)) + str 'fixedcase 'literal) + " +" t))) + +(defun consult--join-regexps (regexps type) + "Join REGEXPS of TYPE." + ;; Add lookahead wrapper only if there is more than one regular expression + (cond + ((and (eq type 'pcre) (cdr regexps)) + (concat "^" (mapconcat (lambda (x) (format "(?=.*%s)" x)) + regexps ""))) + ((eq type 'basic) + (string-join regexps ".*")) + (t + (when (length> regexps 3) + (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)) "\\"))))) + +(defun consult--regexp-join-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) + esc ")")) + regexps (concat esc "|"))))) + +(defun consult--valid-regexp-p (re) + "Return t if regexp RE is valid." + (condition-case nil + (progn (string-match-p re "") t) + (invalid-regexp nil))) + +(defun consult--regexp-filter (regexps) + "Create filter regexp from REGEXPS." + (if (stringp regexps) + regexps + (mapconcat (lambda (x) (concat "\\(?:" x "\\)")) regexps "\\|"))) + +;;;; Lookup functions + +(defun consult--lookup-member (selected candidates &rest _) + "Lookup SELECTED in CANDIDATES list, return original element." + (car (member selected candidates))) + +(defun consult--lookup-cons (selected candidates &rest _) + "Lookup SELECTED in CANDIDATES alist, return cons." + (assoc selected candidates)) + +(defun consult--lookup-cdr (selected candidates &rest _) + "Lookup SELECTED in CANDIDATES alist, return cdr of element." + (cdr (assoc selected candidates))) + +(defun consult--lookup-location (selected candidates &rest _) + "Lookup SELECTED in CANDIDATES list of `consult-location' category. +Return the location marker." + (when-let (found (member selected candidates)) + (setq found (car (consult--get-location (car found)))) + ;; Check that marker is alive + (and (or (not (markerp found)) (marker-buffer found)) found))) + +(defun consult--lookup-prop (prop selected candidates &rest _) + "Lookup SELECTED in CANDIDATES list and return PROP value." + (when-let (found (member selected candidates)) + (get-text-property 0 prop (car found)))) + +(defun consult--lookup-candidate (selected candidates &rest _) + "Lookup SELECTED in CANDIDATES list and return property `consult--candidate'." + (consult--lookup-prop 'consult--candidate selected candidates)) + +;;;; Preview support + +(defun consult--filter-find-file-hook (orig &rest hooks) + "Filter `find-file-hook' by `consult-preview-allowed-hooks'. +This function is an advice for `run-hooks'. +ORIG is the original function, HOOKS the arguments." + (if (memq 'find-file-hook hooks) + (cl-letf* (((default-value 'find-file-hook) + (seq-filter (lambda (x) + (memq x consult-preview-allowed-hooks)) + (default-value 'find-file-hook))) + (find-file-hook (default-value 'find-file-hook))) + (apply orig hooks)) + (apply orig hooks))) + +(defun consult--find-file-temporarily-1 (name) + "Open file NAME, helper function for `consult--find-file-temporarily'." + (when-let (((not (seq-find (lambda (x) (string-match-p x name)) + consult-preview-excluded-files))) + ;; file-attributes may throw permission denied error + (attrs (ignore-errors (file-attributes name))) + (size (file-attribute-size attrs))) + (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)))) + (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)) + ((ignore-errors (buffer-local-value 'so-long-detected-p buf)) + (kill-buffer buf) + (format "File `%s' with long lines not previewed" name)) + (t buf)))))) + +(defun consult--find-file-temporarily (name) + "Open file NAME temporarily for preview." + (let ((vars (delq nil + (mapcar + (pcase-lambda (`(,k . ,v)) + (if (boundp k) + (list k v (default-value k) (symbol-value k)) + (message "consult-preview-variables: The variable `%s' is not bound" k) + nil)) + consult-preview-variables))) + buf) + (unwind-protect + (progn + (advice-add #'run-hooks :around #'consult--filter-find-file-hook) + (pcase-dolist (`(,k ,v . ,_) vars) + (set-default k v) + (set k v)) + (setq buf (consult--find-file-temporarily-1 name))) + (advice-remove #'run-hooks #'consult--filter-find-file-hook) + (pcase-dolist (`(,k ,_ ,d ,v) vars) + (set-default k d) + (set k v))) + (if (stringp buf) (progn (message "%s" buf) nil) buf))) + +(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")) + (orig-buffers (buffer-list)) + temporary-buffers) + (fset hook + (lambda (_) + ;; Fully initialize previewed files and keep them alive. + (unless (consult--completion-window-p) + (let (live-files) + (pcase-dolist (`(,file . ,buf) temporary-buffers) + (when-let (wins (and (buffer-live-p buf) + (get-buffer-window-list buf))) + (push (cons file (mapcar + (lambda (win) + (cons win (window-state-get win t))) + wins)) + live-files))) + (pcase-dolist (`(,_ . ,buf) temporary-buffers) + (kill-buffer buf)) + (setq temporary-buffers nil) + (pcase-dolist (`(,file . ,wins) live-files) + (when-let (buf (find-file-noselect file)) + (push buf orig-buffers) + (pcase-dolist (`(,win . ,state) wins) + (setf (car (alist-get 'buffer state)) buf) + (window-state-put state win)))))))) + (lambda (&optional name) + (if name + (let ((default-directory dir)) + (setq name (abbreviate-file-name (expand-file-name name))) + (or + ;; Find existing fully initialized buffer (non-previewed). We have + ;; to check for fully initialized buffer before accessing the + ;; previewed buffers, since `embark-act' can open a buffer which is + ;; currently previewed, such that we end up with two buffers for + ;; the same file - one previewed and only partially initialized and + ;; one fully initialized. In this case we prefer the fully + ;; initialized buffer. For directories `get-file-buffer' returns nil, + ;; therefore we have to special case Dired. + (if (and (fboundp 'dired-find-buffer-nocreate) (file-directory-p name)) + (dired-find-buffer-nocreate name) + (get-file-buffer name)) + ;; Find existing previewed buffer. Previewed buffers are not fully + ;; initialized (hooks are delayed) in order to ensure fast preview. + (cdr (assoc name temporary-buffers)) + ;; Finally, if no existing buffer has been found, open the file for + ;; preview. + (when-let (buf (consult--find-file-temporarily name)) + ;; Only add new buffer if not already in the list + (unless (or (rassq buf temporary-buffers) (memq buf orig-buffers)) + (add-hook 'window-selection-change-functions hook) + (push (cons name buf) temporary-buffers) + ;; Disassociate buffer from file by setting `buffer-file-name' + ;; and `dired-directory' to nil and rename the buffer. This + ;; lets us open an already previewed buffer with the Embark + ;; default action C-. RET. + (with-current-buffer buf + (rename-buffer + (format " Preview:%s" + (file-name-nondirectory (directory-file-name name))) + 'unique)) + ;; The buffer disassociation is delayed to avoid breaking modes + ;; 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"))) + (fset hook (lambda () + (when (buffer-live-p buf) + (with-current-buffer buf + (remove-hook 'pre-command-hook hook) + (setq-local buffer-read-only t + dired-directory nil + buffer-file-name nil))))) + (add-hook 'pre-command-hook hook)) + ;; Only keep a few buffers alive + (while (length> temporary-buffers consult-preview-max-count) + (kill-buffer (cdar (last temporary-buffers))) + (setq temporary-buffers (nbutlast temporary-buffers)))) + buf))) + (remove-hook 'window-selection-change-functions hook) + (pcase-dolist (`(,_ . ,buf) temporary-buffers) + (kill-buffer buf)) + (setq temporary-buffers nil))))) + +(declare-function org-fold-core-region "org-fold-core") +(declare-function org-fold-core-get-regions "org-fold-core") + +(defun consult--invisible-open-permanently () + "Open overlays which hide the current line. +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) + (dolist (ov (overlays-in (pos-bol) (pos-eol))) + (when-let (fun (overlay-get ov 'isearch-open-invisible)) + (when (invisible-p (overlay-get ov 'invisible)) + (funcall fun ov)))))) + +(defun consult--invisible-open-temporarily () + "Temporarily open overlays which hide the current line. +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 + ;; TODO The provided Org API `org-fold-show-set-visibility' cannot be used + ;; efficiently. We obtain all regions in the whole buffer in order to + ;; restore them. A better show API would return all the applied + ;; modifications such that we can restore the ones which got modified. + (progn + (unless consult--org-fold-regions + (setq consult--org-fold-regions + (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) + (list (lambda () + (pcase-dolist (`(,beg ,end ,spec) consult--org-fold-regions) + (org-fold-core-region beg end t spec))))) + (let (restore) + (dolist (ov (overlays-in (pos-bol) (pos-eol))) + (let ((inv (overlay-get ov 'invisible))) + (when (and (invisible-p inv) (overlay-get ov 'isearch-open-invisible)) + (push (if-let (fun (overlay-get ov 'isearch-open-invisible-temporary)) + (progn + (funcall fun ov nil) + (lambda () (funcall fun ov t))) + (overlay-put ov 'invisible nil) + (lambda () (overlay-put ov 'invisible inv))) + restore)))) + restore))) + +(defun consult--jump-1 (pos) + "Go to POS and recenter." + (if (and (markerp pos) (not (marker-buffer pos))) + ;; Only print a message, no error in order to not mess + ;; with the minibuffer update hook. + (message "Buffer is dead") + ;; Switch to buffer if it is not visible + (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) + (unless (= (goto-char pos) (point)) + (widen) + (goto-char pos)))) + +(defun consult--jump (pos) + "Push current position to mark ring, go to POS and recenter." + (when pos + ;; Extract marker from list with with overlay positions, see `consult--line-match' + (when (consp pos) (setq pos (car pos))) + ;; When the marker is in the same buffer, record previous location + ;; such that the user can jump back quickly. + (when (or (not (markerp pos)) (eq (current-buffer) (marker-buffer pos))) + ;; push-mark mutates markers in the mark-ring and the mark-marker. + ;; Therefore we transform the marker to a number to be safe. + ;; We all love side effects! + (setq pos (+ pos 0)) + (push-mark (point) t)) + (consult--jump-1 pos) + (consult--invisible-open-permanently) + (run-hooks 'consult-after-jump-hook)) + nil) + +(defun consult--jump-preview () + "The preview function used if selecting from a list of candidate positions. +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) + (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) + (if (not cand) + ;; If position cannot be previewed, return to saved position + (let ((saved-buffer (marker-buffer saved-pos))) + (if (not saved-buffer) + (message "Buffer is dead") + (set-buffer saved-buffer) + (narrow-to-region saved-min saved-max) + (goto-char saved-pos))) + ;; Handle positions with overlay information + (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)) + (run-hooks 'consult-after-jump-hook)))))) + +(defun consult--jump-state () + "The state function used if selecting from a list of candidate positions." + (consult--state-with-return (consult--jump-preview) #'consult--jump)) + +(defun consult--get-location (cand) + "Return location from CAND." + (let ((loc (get-text-property 0 'consult-location cand))) + (when (consp (car loc)) + ;; Transform cheap marker to real marker + (setcar loc (set-marker (make-marker) (cdar loc) (caar loc)))) + loc)) + +(defun consult--location-state (candidates) + "Location state function. +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"))) + (fset hook + (lambda (_) + (unless (consult--completion-window-p) + (remove-hook 'window-selection-change-functions hook) + (mapc #'consult--get-location + (if (functionp candidates) (funcall candidates) candidates))))) + (lambda (action cand) + (pcase action + ('setup (add-hook 'window-selection-change-functions hook)) + ('exit (remove-hook 'window-selection-change-functions hook))) + (funcall jump action cand)))) + +(defun consult--state-with-return (state return) + "Compose STATE function with RETURN function." + (lambda (action cand) + (funcall state action cand) + (when (and cand (eq action 'return)) + (funcall return cand)))) + +(defmacro consult--define-state (type) + "Define state function for TYPE." + `(defun ,(intern (format "consult--%s-state" type)) () + ,(format "State function for %ss with preview. +The result can be passed as :state argument to `consult--read'." type) + (consult--state-with-return (,(intern (format "consult--%s-preview" type))) + #',(intern (format "consult--%s-action" type))))) + +(defun consult--preview-key-normalize (preview-key) + "Normalize PREVIEW-KEY, return alist of keys and debounce times." + (let ((keys) + (debounce 0)) + (setq preview-key (ensure-list preview-key)) + (while preview-key + (if (eq (car preview-key) :debounce) + (setq debounce (cadr preview-key) + 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))) + (push (cons key debounce) keys)) + (pop preview-key))) + keys)) + +(defun consult--preview-key-debounce (preview-key cand) + "Return debounce value of PREVIEW-KEY given the current candidate CAND." + (when (and (consp preview-key) (memq :keys preview-key)) + (setq preview-key (funcall (plist-get preview-key :predicate) cand))) + (let ((map (make-sparse-keymap)) + (keys (this-single-command-keys)) + any) + (pcase-dolist (`(,k . ,d) (consult--preview-key-normalize preview-key)) + (if (eq k 'any) + (setq any d) + (define-key map k `(lambda () ,d)))) + (setq keys (lookup-key map keys)) + (if (functionp keys) (funcall keys) any))) + +(defun consult--append-local-post-command-hook (fun) + "Append FUN to local `post-command-hook' list." + ;; Symbol indirection because of bug#46407. + (let ((hook (make-symbol "consult--preview-post-command"))) + (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) + (setq-local post-command-hook + (append + (remove t post-command-hook) + (list hook) + (and (memq t post-command-hook) '(t)))))) + +(defun consult--with-preview-1 (preview-key state transform candidate fun) + "Add preview support for FUN. +See `consult--with-preview' for the arguments +PREVIEW-KEY, STATE, TRANSFORM and CANDIDATE." + (let ((mb-input "") mb-narrow selected timer previewed) + (consult--minibuffer-with-setup-hook + (if (and state preview-key) + (lambda () + (let ((exit-hook (make-symbol "consult--preview-minibuffer-exit")) + (depth (recursion-depth))) + (fset exit-hook + (lambda () + (when (= (recursion-depth) depth) + (remove-hook 'minibuffer-exit-hook exit-hook) + (when timer + (cancel-timer timer) + (setq timer nil)) + (with-selected-window (or (minibuffer-selected-window) (next-window)) + ;; STEP 3: Reset preview + (when previewed + (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)) + ;; STEP 1: Setup the preview function + (with-selected-window (or (minibuffer-selected-window) (next-window)) + (funcall state 'setup nil)) + (setq consult--preview-function + (lambda () + (when-let ((cand (funcall candidate))) + ;; Drop properties to prevent bugs regarding candidate + ;; lookup, which must handle candidates without + ;; properties. Otherwise the arguments passed to the + ;; lookup function are confusing, since during preview + ;; the candidate has properties but for the final lookup + ;; after completion it does not. + (setq cand (substring-no-properties cand)) + (with-selected-window (active-minibuffer-window) + (let ((input (minibuffer-contents-no-properties)) + (narrow consult--narrow)) + (with-selected-window (or (minibuffer-selected-window) (next-window)) + (when-let ((transformed (funcall transform narrow input cand)) + (debounce (consult--preview-key-debounce preview-key transformed))) + (when timer + (cancel-timer timer) + (setq timer nil)) + ;; The transformed candidate may have text + ;; properties, which change the preview display. + ;; This matters for example for `consult-grep', + ;; where the current candidate and input may + ;; stay equal, but the highlighting of the + ;; candidate changes while the candidates list + ;; is lagging a bit behind and updates + ;; asynchronously. + ;; + ;; NOTE: In older Consult versions the input was + ;; compared instead, since I was worried that + ;; comparing the transformed candidates could be + ;; potentially expensive or problematic. However + ;; comparing the transformed candidates is more + ;; correct, since the transformed candidate is + ;; the thing which is actually previewed. + (unless (equal-including-properties previewed transformed) + (if (> debounce 0) + (let ((win (selected-window))) + (setq timer + (run-at-time + debounce nil + (lambda () + (when (window-live-p win) + (with-selected-window win + ;; STEP 2: Preview candidate + (funcall state 'preview (setq previewed transformed)))))))) + ;; STEP 2: Preview candidate + (funcall state 'preview (setq previewed transformed))))))))))) + (consult--append-local-post-command-hook + (lambda () + (setq mb-input (minibuffer-contents-no-properties) + mb-narrow consult--narrow) + (funcall consult--preview-function)))) + (lambda () + (consult--append-local-post-command-hook + (lambda () + (setq mb-input (minibuffer-contents-no-properties) + mb-narrow consult--narrow))))) + (unwind-protect + (cons (setq selected (when-let (result (funcall fun)) + (funcall transform mb-narrow mb-input result))) + mb-input) + (when state + ;; STEP 5: The preview function should perform its final action + (funcall state 'return selected)))))) + +(defmacro consult--with-preview (preview-key state transform candidate &rest body) + "Add preview support to BODY. + +STATE is the state function. +TRANSFORM is the transformation function. +CANDIDATE is the function returning the current candidate. +PREVIEW-KEY are the keys which triggers the preview. + +The state function takes two arguments, an action argument and the +selected candidate. The candidate argument can be nil if no candidate is +selected or if the selection was aborted. The function is called in +sequence with the following arguments: + + 1. \\='setup nil After entering the mb (minibuffer-setup-hook). +⎧ 2. \\='preview CAND/nil Preview candidate CAND or reset if CAND is nil. +⎪ \\='preview CAND/nil +⎪ \\='preview CAND/nil +⎪ ... +⎩ 3. \\='preview nil Reset preview. + 4. \\='exit nil Before exiting the mb (minibuffer-exit-hook). + 5. \\='return CAND/nil After leaving the mb, CAND has been selected. + +The state function is always executed with the original window selected, +see `minibuffer-selected-window'. The state function is called once in +the beginning of the minibuffer setup with the `setup' argument. This is +useful in order to perform certain setup operations which require that +the minibuffer is initialized. During completion candidates are +previewed. Then the function is called with the `preview' argument and a +candidate CAND or nil if no candidate is selected. Furthermore if nil is +passed for CAND, then the preview must be undone and the original state +must be restored. The call with the `exit' argument happens once at the +end of the completion process, just before exiting the minibuffer. The +minibuffer is still alive at that point. Both `setup' and `exit' are +only useful for setup and cleanup operations. They don't receive a +candidate as argument. After leaving the minibuffer, the selected +candidate or nil is passed to the state function with the action +argument `return'. At this point the state function can perform the +actual action on the candidate. The state function with the `return' +argument is the continuation of `consult--read'. Via `unwind-protect' it +is guaranteed, that if the `setup' action of a state function is +invoked, the state function will also be called with `exit' and +`return'." + (declare (indent 4)) + `(consult--with-preview-1 ,preview-key ,state ,transform ,candidate (lambda () ,@body))) + +;;;; Narrowing and grouping + +(defun consult--prefix-group (cand transform) + "Return title for CAND or TRANSFORM the candidate. +The candidate must have a `consult--prefix-group' property." + (if transform + (substring cand (1+ (length (get-text-property 0 'consult--prefix-group cand)))) + (get-text-property 0 'consult--prefix-group cand))) + +(defun consult--type-group (types) + "Return group function for TYPES." + (lambda (cand transform) + (if transform cand + (alist-get (get-text-property 0 'consult--type cand) types)))) + +(defun consult--type-narrow (types) + "Return narrowing configuration from TYPES." + (list :predicate + (lambda (cand) (eq (get-text-property 0 'consult--type cand) consult--narrow)) + :keys types)) + +(defun consult--widen-key () + "Return widening key, if `consult-widen-key' is not set. +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-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)) + (vconcat key key))))) + +(defun consult-narrow (key) + "Narrow current completion with KEY. + +This command is used internally by the narrowing system of `consult--read'." + (interactive + (list (unless (equal (this-single-command-keys) (consult--widen-key)) + last-command-event))) + (consult--require-minibuffer) + (setq consult--narrow key) + (when consult--narrow-predicate + (setq minibuffer-completion-predicate (and consult--narrow consult--narrow-predicate))) + (when consult--narrow-overlay + (delete-overlay consult--narrow-overlay)) + (when consult--narrow + (setq consult--narrow-overlay + (consult--overlay + (1- (minibuffer-prompt-end)) (minibuffer-prompt-end) + 'before-string + (propertize (format " [%s]" (alist-get consult--narrow + consult--narrow-keys)) + 'face 'consult-narrow-indicator)))) + (run-hooks 'consult--completion-refresh-hook)) + +(defconst consult--narrow-delete + `(menu-item + "" nil :filter + ,(lambda (&optional _) + (when (equal (minibuffer-contents-no-properties) "") + (lambda () + (interactive) + (consult-narrow nil)))))) + +(defconst consult--narrow-space + `(menu-item + "" nil :filter + ,(lambda (&optional _) + (let ((str (minibuffer-contents-no-properties))) + (when-let (pair (or (and (length= str 1) + (assoc (aref str 0) consult--narrow-keys)) + (and (equal str "") + (assoc 32 consult--narrow-keys)))) + (lambda () + (interactive) + (delete-minibuffer-contents) + (consult-narrow (car pair)))))))) + +(defun consult-narrow-help () + "Print narrowing help as a `minibuffer-message'. + +This command can be bound to a key in `consult-narrow-map', +to make it available for commands with narrowing." + (interactive) + (consult--require-minibuffer) + (let ((minibuffer-message-timeout 1000000)) + (minibuffer-message + (mapconcat (lambda (x) + (concat + (propertize (key-description (list (car x))) 'face 'consult-key) + " " + (propertize (cdr x) 'face 'consult-help))) + consult--narrow-keys + " ")))) + +(defun consult--narrow-setup (settings map) + "Setup narrowing with SETTINGS and keymap MAP." + (if (memq :keys settings) + (setq consult--narrow-predicate (plist-get settings :predicate) + consult--narrow-keys (plist-get settings :keys)) + (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)) + (dolist (pair consult--narrow-keys) + (define-key map (vconcat key (vector (car pair))) + (cons (cdr pair) #'consult-narrow)))) + (when-let ((widen (consult--widen-key))) + (define-key map widen (cons "All" #'consult-narrow)))) + +;; Emacs 28: hide in M-X +(put #'consult-narrow-help 'completion-predicate #'ignore) +(put #'consult-narrow 'completion-predicate #'ignore) + +;;;; Splitting completion style + +(defun consult--split-perl (str &optional _plist) + "Split input STR in async input and filtering part. + +The function returns a list with three elements: The async +string, the start position of the completion filter string and a +force flag. If the first character is a punctuation character it +determines the separator. Examples: \"/async/filter\", +\"#async#filter\"." + (if (string-match-p "^[[:punct:]]" str) + (save-match-data + (let ((q (regexp-quote (substring str 0 1)))) + (string-match (concat "^" q "\\([^" q "]*\\)\\(" q "\\)?") str) + `(,(match-string 1 str) + ,(match-end 0) + ;; Force update it two punctuation characters are entered. + ,(match-end 2) + ;; List of highlights + (0 . ,(match-beginning 1)) + ,@(and (match-end 2) `((,(match-beginning 2) . ,(match-end 2))))))) + `(,str ,(length str)))) + +(defun consult--split-nil (str &optional _plist) + "Treat the complete input STR as async input." + `(,str ,(length str))) + +(defun consult--split-separator (str plist) + "Split input STR in async input and filtering part at first separator. +PLIST is the splitter configuration, including the separator." + (let ((sep (regexp-quote (char-to-string (plist-get plist :separator))))) + (save-match-data + (if (string-match (format "^\\([^%s]+\\)\\(%s\\)?" sep sep) str) + `(,(match-string 1 str) + ,(match-end 0) + ;; Force update it space is entered. + ,(match-end 2) + ;; List of highlights + ,@(and (match-end 2) `((,(match-beginning 2) . ,(match-end 2))))) + `(,str ,(length str)))))) + +(defun consult--split-setup (split) + "Setup splitting completion style with splitter function SPLIT." + (let* ((styles completion-styles) + (catdef completion-category-defaults) + (catovr completion-category-overrides) + (try (lambda (str table pred point) + (let ((completion-styles styles) + (completion-category-defaults catdef) + (completion-category-overrides catovr) + (pos (cadr (funcall split str)))) + (pcase (completion-try-completion (substring str pos) table pred + (max 0 (- point pos))) + ('t t) + (`(,newstr . ,newpt) + (cons (concat (substring str 0 pos) newstr) + (+ pos newpt))))))) + (all (lambda (str table pred point) + (let ((completion-styles styles) + (completion-category-defaults catdef) + (completion-category-overrides catovr) + (pos (cadr (funcall split str)))) + (completion-all-completions (substring str pos) table pred + (max 0 (- point pos))))))) + (setq-local completion-styles-alist (cons `(consult--split ,try ,all "") + completion-styles-alist) + completion-styles '(consult--split) + completion-category-defaults nil + completion-category-overrides nil))) + +;;;; Asynchronous filtering functions + +(defmacro consult--with-async (bind &rest body) + "Setup asynchronous completion in BODY. + +BIND is the asynchronous function binding." + (declare (indent 1)) + (let ((async (car bind))) + `(let ((,async ,@(cdr bind)) + (new-chunk (max read-process-output-max consult--process-chunk)) + orig-chunk) + (consult--minibuffer-with-setup-hook + ;; Append such that we overwrite the completion style setting of + ;; `fido-mode'. See `consult--async-split' and + ;; `consult--split-setup'. + (:append + (lambda () + (when (functionp ,async) + (setq orig-chunk read-process-output-max + read-process-output-max new-chunk) + (funcall ,async 'setup) + (let* ((mb (current-buffer)) + (fun (lambda () + (when-let (win (active-minibuffer-window)) + (when (eq (window-buffer win) mb) + (with-current-buffer mb + (let ((inhibit-modification-hooks t)) + ;; Push input string to request refresh. + (funcall ,async (minibuffer-contents-no-properties)))))))) + ;; 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"))) + ;; 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)))) + (unwind-protect + ,(macroexp-progn body) + (funcall ,async 'destroy) + (when (and orig-chunk (eq read-process-output-max new-chunk)) + (setq read-process-output-max orig-chunk)))))))) + +(defun consult--async-sink () + "Create ASYNC sink function. + +An async function must accept a single action argument. For the +\\='setup action it is guaranteed that the call originates from +the minibuffer. For the other actions no assumption about the +context can be made. + +\\='setup Setup the internal closure state. Return nil. +\\='destroy Destroy the internal closure state. Return nil. +\\='flush Flush the list of candidates. Return nil. +\\='refresh Request UI refresh. Return nil. +nil Return the list of candidates. +list Append the list to the already existing candidates list and return it. +string Update with the current user input string. Return nil." + (let (candidates last buffer) + (lambda (action) + (pcase-exhaustive action + ('setup + (setq buffer (current-buffer)) + nil) + ((or (pred stringp) 'destroy) nil) + ('flush (setq candidates nil last nil)) + ('refresh + ;; Refresh the UI when the current minibuffer window belongs + ;; to the current asynchronous completion session. + (when-let (win (active-minibuffer-window)) + (when (eq (window-buffer win) buffer) + (with-selected-window win + (run-hooks 'consult--completion-refresh-hook) + ;; Interaction between asynchronous completion tables and + ;; preview: We have to trigger preview immediately when + ;; candidates arrive (gh:minad/consult#436). + (when (and consult--preview-function candidates) + (funcall consult--preview-function))))) + nil) + ('nil candidates) + ((pred consp) + (setq last (last (if last (setcdr last action) (setq candidates action)))) + candidates))))) + +(defun consult--async-split-style () + "Return the async splitting style function and initial string." + (or (alist-get consult-async-split-style consult-async-split-styles-alist) + (user-error "Splitting style `%s' not found" consult-async-split-style))) + +(defun consult--async-split-initial (initial) + "Return initial string for async command. +INITIAL is the additional initial string." + (concat (plist-get (consult--async-split-style) :initial) initial)) + +(defun consult--async-split-thingatpt (thing) + "Return THING at point with async initial prefix." + (when-let (str (thing-at-point thing)) + (consult--async-split-initial str))) + +(defun consult--async-split (async &optional split) + "Create async function, which splits the input string. +ASYNC is the async sink. +SPLIT is the splitting function." + (unless split + (let* ((style (consult--async-split-style)) + (fn (plist-get style :function))) + (setq split (lambda (str) (funcall fn str style))))) + (lambda (action) + (pcase action + ('setup + (consult--split-setup split) + (funcall async 'setup)) + ((pred stringp) + (pcase-let* ((`(,async-str ,_ ,force . ,highlights) + (funcall split action)) + (async-len (length async-str)) + (input-len (length action)) + (prompt (minibuffer-prompt-end)) + (field-beg prompt) + (field-idx 0)) + ;; Highlight punctuation characters + (remove-list-of-text-properties prompt (+ prompt input-len) '(face field)) + (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))) + (funcall async + ;; Pass through if the input is long enough! + (if (or force (>= async-len consult-async-min-input)) + async-str + ;; Pretend that there is no input + "")))) + (_ (funcall async action))))) + +(defun consult--async-indicator (async) + "Create async function with a state indicator overlay. +ASYNC is the async sink." + (let (ov) + (lambda (action &optional state) + (pcase action + ('indicator + (overlay-put ov 'display + (pcase-exhaustive state + ('running #("*" 0 1 (face consult-async-running))) + ('finished #(":" 0 1 (face consult-async-finished))) + ('killed #(";" 0 1 (face consult-async-failed))) + ('failed #("!" 0 1 (face consult-async-failed)))))) + ('setup + (setq ov (make-overlay (- (minibuffer-prompt-end) 2) + (- (minibuffer-prompt-end) 1))) + (funcall async 'setup)) + ('destroy + (delete-overlay ov) + (funcall async 'destroy)) + (_ (funcall async action)))))) + +(defun consult--async-log (formatted &rest args) + "Log FORMATTED ARGS to variable `consult--async-log'." + (with-current-buffer (get-buffer-create consult--async-log) + (goto-char (point-max)) + (insert (apply #'format formatted args)))) + +(defun consult--async-process (async builder &rest props) + "Create process source async function. + +ASYNC is the async function which receives the candidates. +BUILDER is the command line builder function. +PROPS are optional properties passed to `make-process'." + (setq async (consult--async-indicator async)) + (let (proc proc-buf last-args count) + (lambda (action) + (pcase action + ("" ;; If no input is provided kill current process + (when proc + (delete-process proc) + (kill-buffer proc-buf) + (setq proc nil proc-buf nil)) + (setq last-args nil)) + ((pred stringp) + (funcall async action) + (let* ((flush t) + (rest "") + (proc-filter + (lambda (_ out) + (when flush + (setq flush nil) + (funcall async 'flush)) + (let ((lines (split-string out "[\r\n]+"))) + (if (not (cdr lines)) + (setq rest (concat rest (car lines))) + (setcar lines (concat rest (car lines))) + (let* ((len (length lines)) + (last (nthcdr (- len 2) lines))) + (setq rest (cadr last) + count (+ count len -1)) + (setcdr last nil) + (funcall async lines)))))) + (proc-sentinel + (lambda (_ event) + (when flush + (setq flush nil) + (funcall async 'flush)) + (funcall async 'indicator + (cond + ((string-prefix-p "killed" event) 'killed) + ((string-prefix-p "finished" event) 'finished) + (t 'failed))) + (when (and (string-prefix-p "finished" event) (not (equal rest ""))) + (cl-incf count) + (funcall async (list rest))) + (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")))) + (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)))) + (unless (equal args last-args) + (setq last-args args) + (when proc + (delete-process proc) + (kill-buffer proc-buf) + (setq proc nil proc-buf nil)) + (when args + (funcall async 'indicator 'running) + (consult--async-log "consult--async-process started %S\n" args) + (setq count 0 + proc-buf (generate-new-buffer " *consult-async-stderr*") + proc (apply #'make-process + `(,@props + :connection-type pipe + :name ,(car args) + ;;; XXX tramp bug, the stderr buffer must be empty + :stderr ,proc-buf + :noquery t + :command ,args + :filter ,proc-filter + :sentinel ,proc-sentinel)))))) + nil) + ('destroy + (when proc + (delete-process proc) + (kill-buffer proc-buf) + (setq proc nil proc-buf nil)) + (funcall async 'destroy)) + (_ (funcall async action)))))) + +(defun consult--async-highlight (async builder) + "Return ASYNC function which highlightes the candidates. +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)))) + (funcall async action)) + ((and (consp action) highlight) + (dolist (str action) + (funcall highlight str)) + (funcall async action)) + (t (funcall async action)))))) + +(defun consult--async-throttle (async &optional throttle debounce) + "Create async function from ASYNC which throttles input. + +The THROTTLE delay defaults to `consult-async-input-throttle'. +The DEBOUNCE delay defaults to `consult-async-input-debounce'." + (setq throttle (or throttle consult-async-input-throttle) + debounce (or debounce consult-async-input-debounce)) + (let ((input "") last timer) + (lambda (action) + (pcase action + ((pred stringp) + (unless (equal action input) + (when timer + (cancel-timer timer) + (setq timer nil)) + (funcall async "") ;; cancel running process + (setq input action) + (unless (equal action "") + (setq timer + (run-at-time + (+ debounce + (if last + (min (- (float-time) last) throttle) + 0)) + nil + (lambda () + (setq last (float-time)) + (funcall async action)))))) + nil) + ('destroy + (when timer (cancel-timer timer)) + (funcall async 'destroy)) + (_ (funcall async action)))))) + +(defun consult--async-refresh-immediate (async) + "Create async function from ASYNC, which refreshes the display. + +The refresh happens immediately when candidates are pushed." + (lambda (action) + (pcase action + ((or (pred consp) 'flush) + (prog1 (funcall async action) + (funcall async 'refresh))) + (_ (funcall async action))))) + +(defun consult--async-refresh-timer (async &optional delay) + "Create async function from ASYNC, which refreshes the display. + +The refresh happens after a DELAY, defaulting to `consult-async-refresh-delay'." + (let ((timer) (refresh) (delay (or delay consult-async-refresh-delay))) + (lambda (action) + (prog1 (funcall async action) + (pcase action + ((or (pred consp) 'flush) + (setq refresh t) + (unless timer + (setq timer (run-at-time + nil delay + (lambda () + (when refresh + (setq refresh nil) + (funcall async 'refresh))))))) + ('destroy (when timer (cancel-timer timer)))))))) + +(defmacro consult--async-command (builder &rest args) + "Asynchronous command pipeline. +ARGS is a list of `make-process' properties and transforms. +BUILDER is the command line builder function, which takes the +input string and must either return a list of command line +arguments or a pair of the command line argument list and a +highlighting function." + (declare (indent 1)) + `(thread-first + (consult--async-sink) + (consult--async-refresh-timer) + ,@(seq-take-while (lambda (x) (not (keywordp x))) args) + (consult--async-process + ,builder + ,@(seq-drop-while (lambda (x) (not (keywordp x))) args)) + (consult--async-throttle) + (consult--async-split))) + +(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"))) + `(let ((,async-var ,async)) + (lambda (,action-var) + (funcall ,async-var (if (consp ,action-var) (,@transform ,action-var) ,action-var)))))) + +(defun consult--async-map (async fun) + "Map candidates of ASYNC by FUN." + (consult--async-transform async mapcar fun)) + +(defun consult--async-filter (async fun) + "Filter candidates of ASYNC by FUN." + (consult--async-transform async seq-filter fun)) + +;;;; Dynamic collections based + +(defun consult--dynamic-compute (async fun &optional debounce) + "Dynamic computation of candidates. +ASYNC is the sink. +FUN computes the candidates given the input. +DEBOUNCE is the time after which an interrupted computation +should be restarted." + (setq debounce (or debounce consult-async-input-debounce)) + (setq async (consult--async-indicator async)) + (let* ((request) (current) (timer) + (cancel (lambda () (when timer (cancel-timer timer) (setq timer nil)))) + (start (lambda (req) (setq request req) (funcall async 'refresh)))) + (lambda (action) + (pcase action + ((and 'nil (guard (not request))) + (funcall async nil)) + ('nil + (funcall cancel) + (let ((state 'killed)) + (unwind-protect + (progn + (funcall async 'indicator 'running) + (redisplay) + ;; Run computation + (let ((response (funcall fun request))) + ;; Flush and update candidate list + (funcall async 'flush) + (setq state 'finished current request) + (funcall async response))) + (funcall async 'indicator state) + ;; If the computation was killed, restart it after some time. + (when (eq state 'killed) + (setq timer (run-at-time debounce nil start request))) + (setq request nil)))) + ((pred stringp) + (funcall cancel) + (if (or (equal action "") (equal action current)) + (funcall async 'indicator 'finished) + (funcall start action))) + ('destroy + (funcall cancel) + (funcall async 'destroy)) + (_ (funcall async action)))))) + +(defun consult--dynamic-collection (fun) + "Dynamic collection with input splitting. +FUN computes the candidates given the input." + (thread-first + (consult--async-sink) + (consult--dynamic-compute fun) + (consult--async-throttle) + (consult--async-split))) + +;;;; Special keymaps + +(defvar-keymap consult-async-map + :doc "Keymap added for commands with asynchronous candidates." + ;; Overwriting some unusable defaults of default minibuffer completion. + " " #'self-insert-command + ;; Remap Emacs 29 history and default completion for now + ;; (gh:minad/consult#613). + " " #'ignore + " " #'consult-history) + +(defvar-keymap consult-narrow-map + :doc "Narrowing keymap which is added to the local minibuffer map. +Note that `consult-narrow-key' and `consult-widen-key' are bound dynamically." + "SPC" consult--narrow-space + "DEL" consult--narrow-delete) + +;;;; Internal API: consult--read + +(defun consult--add-history (async items) + "Add ITEMS to the minibuffer future history. +ASYNC must be non-nil for async completion functions." + (delete-dups + (append + ;; the defaults are at the beginning of the future history + (ensure-list minibuffer-default) + ;; then our custom items + (remove "" (remq nil (ensure-list items))) + ;; Add all the completions for non-async commands. For async commands this + ;; feature is not useful, since if one selects a completion candidate, the + ;; async search is restarted using that candidate string. This usually does + ;; not yield a desired result since the async input uses a special format, + ;; e.g., `#grep#filter'. + (unless async + (all-completions "" + minibuffer-completion-table + minibuffer-completion-predicate))))) + +(defun consult--setup-keymap (keymap async narrow preview-key) + "Setup minibuffer keymap. + +KEYMAP is a command-specific keymap. +ASYNC must be non-nil for async completion functions. +NARROW are the narrow settings. +PREVIEW-KEY are the preview keys." + (let ((old-map (current-local-map)) + (map (make-sparse-keymap))) + + ;; Add narrow keys + (when narrow + (consult--narrow-setup narrow map)) + + ;; Preview trigger keys + (when (and (consp preview-key) (memq :keys preview-key)) + (setq preview-key (plist-get preview-key :keys))) + (setq preview-key (mapcar #'car (consult--preview-key-normalize preview-key))) + (when preview-key + (dolist (key preview-key) + (unless (or (eq key 'any) (lookup-key old-map key)) + (define-key map key #'ignore)))) + + ;; Put the keymap together + (use-local-map + (make-composed-keymap + (delq nil (list keymap + (and async consult-async-map) + (and narrow consult-narrow-map) + 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)) + (max (point-max)) + (pos max)) + (while (and (> pos min) (consult--tofu-p (char-before pos))) + (cl-decf pos)) + (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) + (`(,_ ,_ ,suffix) suffix) + (ann ann))) + +(defun consult--read-affixate (fun cands) + "Affixate CANDS with annotation function FUN." + (mapcar (lambda (cand) + (let ((ann (funcall fun cand))) + (if (consp ann) + ann + (setq ann (or ann "")) + (list cand "" + ;; The default completion UI adds the + ;; `completions-annotations' face if no other faces are + ;; present. + (if (text-property-not-all 0 (length ann) 'face nil ann) + ann + (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) + "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) + (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 + ;; 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. + (let* ((metadata `(metadata + ,@(when category `((category . ,category))) + ,@(when group `((group-function . ,group))) + ,@(when annotate + `((affixation-function + . ,(apply-partially #'consult--read-affixate annotate)) + (annotation-function + . ,(apply-partially #'consult--read-annotate annotate)))) + ,@(unless sort '((cycle-sort-function . identity) + (display-sort-function . identity))))) + (result + (consult--with-preview + preview-key state + (lambda (narrow input cand) + (funcall lookup cand (funcall async nil) input narrow)) + (apply-partially #'run-hook-with-args-until-success + '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))) + predicate require-match initial + (if (symbolp history) history (cadr history)) + default + inherit-input-method)))) + (pcase-exhaustive history + (`(:input ,var) + (set var (cdr (symbol-value var))) + (add-to-history var (cdr result))) + ((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. + +The function is a thin wrapper around `completing-read'. Keyword +arguments are used instead of positional arguments for code +clarity. On top of `completing-read' it additionally supports +computing the candidate list asynchronously, candidate preview +and narrowing. + +Keyword OPTIONS: + +PROMPT is the string which is shown as prompt in the minibuffer. +PREDICATE is a filter function called for each candidate, returns +nil or t. +REQUIRE-MATCH equals t means that an exact match is required. +HISTORY is the symbol of the history variable. +DEFAULT is the default selected value. +ADD-HISTORY is a list of items to add to the history. +CATEGORY is the completion category symbol. +SORT should be set to nil if the candidates are already sorted. +This will disable sorting in the completion UI. +LOOKUP is a lookup function passed the selected candidate string, +the list of candidates, the current input string and the current +narrowing value. +ANNOTATE is a function passed a candidate string. The function +should either return an annotation string or a list of three +strings (candidate prefix postfix). +INITIAL is the initial input string. +STATE is the state function, see `consult--with-preview'. +GROUP is a completion metadata `group-function' as documented in +the Elisp manual. +PREVIEW-KEY are the preview keys. Can be nil, `any', a single +key or a list of keys. +NARROW is an alist of narrowing prefix strings and description. +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 + (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 + (append + (consult--customize-get) + options + (list :prompt "Select: " + :preview-key consult-preview-key + :sort t + :lookup (lambda (selected &rest _) selected))))) + +;;;; Internal API: consult--multi + +(defsubst consult--multi-source (sources cand) + "Lookup source for CAND in SOURCES list." + (aref sources (consult--tofu-get cand))) + +(defun consult--multi-predicate (sources cand) + "Predicate function called for each candidate CAND given SOURCES." + (let* ((src (consult--multi-source sources cand)) + (narrow (plist-get src :narrow)) + (type (or (car-safe narrow) narrow -1))) + (or (eq consult--narrow type) + (not (or consult--narrow (plist-get src :hidden)))))) + +(defun consult--multi-narrow (sources) + "Return narrow list from SOURCES." + (thread-last sources + (mapcar (lambda (src) + (when-let (narrow (plist-get src :narrow)) + (if (consp narrow) + narrow + (when-let (name (plist-get src :name)) + (cons narrow name)))))) + (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-group (sources cand transform) + "Return title of candidate CAND or TRANSFORM the candidate given SOURCES." + (if transform cand + (plist-get (consult--multi-source sources cand) :name))) + +(defun consult--multi-preview-key (sources) + "Return preview keys from SOURCES." + (list :predicate + (lambda (cand) + (if (plist-member (cdr cand) :preview-key) + (plist-get (cdr cand) :preview-key) + consult-preview-key)) + :keys + (delete-dups + (seq-mapcat (lambda (src) + (let ((key (if (plist-member src :preview-key) + (plist-get src :preview-key) + consult-preview-key))) + (ensure-list key))) + sources)))) + +(defun consult--multi-lookup (sources selected candidates _input narrow &rest _) + "Lookup SELECTED in CANDIDATES given SOURCES, with potential NARROW." + (if (or (string-blank-p selected) + (not (consult--tofu-p (aref selected (1- (length selected)))))) + ;; Non-existing candidate without Tofu or default submitted (empty string) + (let* ((src (cond + (narrow (seq-find (lambda (src) + (let ((n (plist-get src :narrow))) + (eq (or (car-safe n) n -1) narrow))) + sources)) + ((seq-find (lambda (src) (plist-get src :default)) sources)) + ((aref sources 0)))) + (idx (seq-position sources src)) + (def (and (string-blank-p selected) ;; default candidate + (seq-find (lambda (cand) (eq idx (consult--tofu-get cand))) candidates)))) + (if def + (cons (cdr (get-text-property 0 'multi-category def)) src) + `(,selected :match nil ,@src))) + (if-let (found (member selected candidates)) + ;; Existing candidate submitted + (cons (cdr (get-text-property 0 'multi-category (car found))) + (consult--multi-source sources selected)) + ;; Non-existing Tofu'ed candidate submitted, e.g., via Embark + `(,(substring selected 0 -1) :match nil ,@(consult--multi-source sources selected))))) + +(defun consult--multi-candidates (sources) + "Return `consult--multi' candidates from SOURCES." + (let ((idx 0) (max-width 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))) + ;; 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)))) + +(defun consult--multi-enabled-sources (sources) + "Return vector of enabled SOURCES." + (vconcat + (seq-filter (lambda (src) + (if-let (pred (plist-get src :enabled)) + (funcall pred) + t)) + (mapcar (lambda (src) + (if (symbolp src) (symbol-value src) src)) + sources)))) + +(defun consult--multi-state (sources) + "State function given SOURCES." + (when-let (states (delq nil (mapcar (lambda (src) + (when-let (fun (plist-get src :state)) + (cons src (funcall fun)))) + sources))) + (let (last-fun) + (pcase-lambda (action `(,cand . ,src)) + (pcase action + ('setup + (pcase-dolist (`(,_ . ,fun) states) + (funcall fun 'setup nil))) + ('exit + (pcase-dolist (`(,_ . ,fun) states) + (funcall fun 'exit nil))) + ('preview + (let ((selected-fun (cdr (assq src states)))) + ;; If the candidate source changed during preview communicate to + ;; the last source, that none of its candidates is previewed anymore. + (when (and last-fun (not (eq last-fun selected-fun))) + (funcall last-fun 'preview nil)) + (setq last-fun selected-fun) + (when selected-fun + (funcall selected-fun 'preview cand)))) + ('return + (let ((selected-fun (cdr (assq src states)))) + ;; Finish all the sources, except the selected one. + (pcase-dolist (`(,_ . ,fun) states) + (unless (eq fun selected-fun) + (funcall fun 'return nil))) + ;; Finish the source with the selected candidate + (when selected-fun + (funcall selected-fun 'return cand))))))))) + +(defun consult--multi (sources &rest options) + "Select from candidates taken from a list of SOURCES. + +OPTIONS is the plist of options passed to `consult--read'. The following +options are supported: :require-match, :history, :keymap, :initial, +:add-history, :sort and :inherit-input-method. The other options of +`consult--read' are used by the implementation of `consult--multi' and +should not be overwritten, except in in special scenarios. + +The function returns the selected candidate in the form (cons candidate +source-plist). The plist has the key :match with a value nil if the +candidate does not exist, t if the candidate exists and `new' if the +candidate has been created. The sources of the source list can either be +symbols of source variables or source values. Source values must be +plists with fields from the following list. + +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, + :action and :state functions. + +Optional source fields: +* :name - Name of the source as a string, used for narrowing, + group titles and annotations. +* :narrow - Narrowing character or (character . string) pair. +* :enabled - Function which must return t if the source is enabled. +* :hidden - When t candidates of this source are hidden by default. +* :face - Face used for highlighting the candidates. +* :annotate - Annotation function called for each candidate, returns string. +* :history - Name of history variable to add selected candidate. +* :default - Must be t if the first item of the source is the default value. +* :action - Function called with the selected candidate. +* :new - Function called with new candidate name, only if :require-match is nil. +* :state - State constructor for the source, must return the + state function. The state function is informed about state + changes of the UI and can be used to implement preview. +* Other custom source fields can be added depending on the use + case. Note that the source is returned by `consult--multi' + together with the selected candidate." + (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) + (append + options + (list + :category 'multi-category + :predicate (apply-partially #'consult--multi-predicate sources) + :annotate (apply-partially #'consult--multi-annotate sources align) + :group (apply-partially #'consult--multi-group sources) + :lookup (apply-partially #'consult--multi-lookup sources) + :preview-key (consult--multi-preview-key sources) + :narrow (consult--multi-narrow sources) + :state (consult--multi-state sources)))))) + (when-let (history (plist-get (cdr selected) :history)) + (add-to-history history (car selected))) + (if (plist-member (cdr selected) :match) + (when-let (fun (plist-get (cdr selected) :new)) + (funcall fun (car selected)) + (plist-put (cdr selected) :match 'new)) + (when-let (fun (plist-get (cdr selected) :action)) + (funcall fun (car selected))) + (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) + "Set property PROP to FORM of commands CMDS." + (dolist (cmd cmds) + (cond + ((and (boundp cmd) (consp (symbol-value cmd))) + (setf (plist-get (symbol-value cmd) prop) (eval form 'lexical))) + ((functionp cmd) + (setf (plist-get (alist-get cmd consult--customize-alist) prop) form)) + (t (user-error "%s is neither a Command command nor a source" cmd)))) + nil) + +(defmacro consult-customize (&rest args) + "Set properties of commands or sources. +ARGS is a list of commands or sources followed by the list of +keyword-value pairs. For `consult-customize' to succeed, the +customized sources and commands must exist. When a command is +invoked, the value of `this-command' is used to lookup the +corresponding customization options." + (let (setter) + (while args + (let ((cmds (seq-take-while (lambda (x) (not (keywordp x))) args))) + (setq args (seq-drop-while (lambda (x) (not (keywordp x))) args)) + (while (keywordp (car args)) + (push `(consult--customize-put ',cmds ,(car args) ',(cadr args)) setter) + (setq args (cddr args))))) + (macroexp-progn setter))) + +(defun consult--customize-get (&optional cmd) + "Get configuration from `consult--customize-alist' for CMD." + (mapcar (lambda (x) (eval x 'lexical)) + (alist-get (or cmd this-command) consult--customize-alist))) + +;;;; Commands + +;;;;; Command: consult-completion-in-region + +(defun consult--insertion-preview (start end) + "State function for previewing a candidate in a specific region. +The candidates are previewed in the region from START to END. This function is +used as the `:state' argument for `consult--read' in the `consult-yank' family +of functions and in `consult-completion-in-region'." + (unless (or (minibufferp) + ;; XXX Disable preview if anything odd is going on with the + ;; markers. Otherwise we get "Marker points into wrong buffer + ;; errors". See gh:minad/consult#375, where Org mode source + ;; blocks are completed in a different buffer than the original + ;; buffer. This completion is probably also problematic in my + ;; Corfu completion package. + (not (eq (window-buffer) (current-buffer))) + (and (markerp start) (not (eq (marker-buffer start) (current-buffer)))) + (and (markerp end) (not (eq (marker-buffer end) (current-buffer))))) + (let (ov) + (lambda (action cand) + (cond + ((and (not cand) ov) + (delete-overlay ov) + (setq ov nil)) + ((and (eq action 'preview) cand) + (unless ov + (setq ov (consult--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) + ;; Use the `before-string' property since the overlay might be empty. + (overlay-put ov 'before-string cand))))))) + +;;;###autoload +(defun consult-completion-in-region (start end collection &optional predicate) + "Use minibuffer completion as the UI for `completion-at-point'. + +The function is called with 4 arguments: START END COLLECTION PREDICATE. +The arguments and expected return value are as specified for +`completion-in-region'. Use as a value for `completion-in-region-function'. + +The function can be configured via `consult-customize'. + + (consult-customize consult-completion-in-region + :completion-styles (basic) + :cycle-threshold 3) + +These configuration options are supported: + + * :cycle-threshold - Cycling threshold (def: `completion-cycle-threshold') + * :completion-styles - Use completion styles (def: `completion-styles') + * :require-match - Require matches when completing (def: nil) + * :prompt - The prompt string shown in the minibuffer" + (barf-if-buffer-read-only) + (cl-letf* ((config (consult--customize-get #'consult-completion-in-region)) + ;; Overwrite both the local and global value of `completion-styles', such that the + ;; `completing-read' minibuffer sees the overwritten value in any case. This is + ;; necessary if `completion-styles' is buffer-local. + ;; NOTE: The completion-styles will be overwritten for recursive editing sessions! + (cs (or (plist-get config :completion-styles) completion-styles)) + (completion-styles cs) + ((default-value 'completion-styles) cs) + (prompt (or (plist-get config :prompt) "Completion: ")) + (require-match (plist-get config :require-match)) + (preview-key (if (plist-member config :preview-key) + (plist-get config :preview-key) + 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))) + (all (completion-all-completions initial collection predicate (length initial))) + ;; Wrap all annotation functions to ensure that they are executed + ;; in the original buffer. + (exit-fun (plist-get completion-extra-properties :exit-function)) + (ann-fun (plist-get completion-extra-properties :annotation-function)) + (aff-fun (plist-get completion-extra-properties :affixation-function)) + (docsig-fun (plist-get completion-extra-properties :company-docsig)) + (completion-extra-properties + `(,@(and ann-fun (list :annotation-function (consult--in-buffer ann-fun))) + ,@(and aff-fun (list :affixation-function (consult--in-buffer aff-fun))) + ;; Provide `:annotation-function' if `:company-docsig' is specified. + ,@(and docsig-fun (not ann-fun) (not aff-fun) + (list :annotation-function + (consult--in-buffer + (lambda (cand) + (concat (propertize " " 'display '(space :align-to center)) + (funcall docsig-fun cand))))))))) + ;; error if `threshold' is t or the improper list `all' is too short + (if (and threshold + (or (not (consp (ignore-errors (nthcdr threshold all)))) + (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) + ((and (consp all) (atom (cdr all))) + (concat (substring initial 0 limit) (car all))) + (t (car + (consult--with-preview + preview-key + ;; 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)) + ;; 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))))))))) + (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 (eq (try-completion completion collection predicate) t) + 'finished 'exact))) + t) + (message "No completion") + nil))))) + +;;;;; Command: consult-outline + +(defun consult--outline-candidates () + "Return alist of outline headings and positions." + (consult--forbid-minibuffer) + (let* ((line (line-number-at-pos (point-min) consult-line-numbers-widen)) + (heading-regexp (concat "^\\(?:" + ;; default definition from outline.el + (or (bound-and-true-p outline-regexp) "[*\^L]+") + "\\)")) + (heading-alist (bound-and-true-p outline-heading-alist)) + (level-fun (or (bound-and-true-p outline-level) + (lambda () ;; as in the default from outline.el + (or (cdr (assoc (match-string 0) heading-alist)) + (- (match-end 0) (match-beginning 0)))))) + (buffer (current-buffer)) + candidates) + (save-excursion + (goto-char (point-min)) + (while (save-excursion + (if-let (fun (bound-and-true-p outline-search-function)) + (funcall fun) + (re-search-forward heading-regexp nil t))) + (cl-incf line (consult--count-lines (match-beginning 0))) + (push (consult--location-candidate + (consult--buffer-substring (pos-bol) (pos-eol) 'fontify) + (cons buffer (point)) (1- line) (1- line) + 'consult--outline-level (funcall level-fun)) + candidates) + (goto-char (1+ (pos-eol))))) + (unless candidates + (user-error "No headings")) + (nreverse candidates))) + +;;;###autoload +(defun consult-outline () + "Jump to an outline heading, obtained by matching against `outline-regexp'. + +This command supports narrowing to a heading level and candidate preview. +The symbol at point is added to the future history." + (interactive) + (let* ((candidates (consult--slow-operation + "Collecting headings..." + (consult--outline-candidates))) + (min-level (- (apply #'min (mapcar + (lambda (cand) + (get-text-property 0 'consult--outline-level cand)) + candidates)) + ?1)) + (narrow-pred (lambda (cand) + (<= (get-text-property 0 'consult--outline-level cand) + (+ consult--narrow min-level)))) + (narrow-keys (mapcar (lambda (c) (cons c (format "Level %c" c))) + (number-sequence ?1 ?9)))) + (consult--read + candidates + :prompt "Go to heading: " + :annotate (consult--line-prefix) + :category 'consult-location + :sort nil + :require-match t + :lookup #'consult--line-match + :narrow `(:predicate ,narrow-pred :keys ,narrow-keys) + :history '(:input consult--line-history) + :add-history (thing-at-point 'symbol) + :state (consult--location-state candidates)))) + +;;;;; Command: consult-mark + +(defun consult--mark-candidates (markers) + "Return list of candidates strings for MARKERS." + (consult--forbid-minibuffer) + (let ((candidates) + (current-buf (current-buffer))) + (save-excursion + (dolist (marker markers) + (when-let ((pos (marker-position marker)) + (buf (marker-buffer marker))) + (when (and (eq buf current-buf) + (consult--in-range-p pos)) + (goto-char pos) + ;; `line-number-at-pos' is a very slow function, which should be + ;; replaced everywhere. However in this case the slow + ;; 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 + (line-number-at-pos pos consult-line-numbers-widen) + marker) + candidates))))) + (unless candidates + (user-error "No marks")) + (nreverse (delete-dups candidates)))) + +;;;###autoload +(defun consult-mark (&optional markers) + "Jump to a marker in MARKERS list (defaults to buffer-local `mark-ring'). + +The command supports preview of the currently selected marker position. +The symbol at point is added to the future history." + (interactive) + (consult--read + (consult--mark-candidates + (or markers (cons (mark-marker) mark-ring))) + :prompt "Go to mark: " + :annotate (consult--line-prefix) + :category 'consult-location + :sort nil + :require-match t + :lookup #'consult--lookup-location + :history '(:input consult--line-history) + :add-history (thing-at-point 'symbol) + :state (consult--jump-state))) + +;;;;; Command: consult-global-mark + +(defun consult--global-mark-candidates (markers) + "Return list of candidates strings for MARKERS." + (consult--forbid-minibuffer) + (let ((candidates)) + (save-excursion + (dolist (marker markers) + (when-let ((pos (marker-position marker)) + (buf (marker-buffer marker))) + (unless (minibufferp buf) + (with-current-buffer buf + (when (consult--in-range-p pos) + (goto-char pos) + ;; `line-number-at-pos' is slow, see comment in `consult--mark-candidates'. + (let ((line (line-number-at-pos pos consult-line-numbers-widen))) + (push (concat + (propertize + (consult--format-file-line-match (buffer-name buf) line "") + 'consult-location (cons marker line) + 'consult-strip t) + (consult--line-with-cursor marker) + (consult--tofu-encode marker)) + candidates)))))))) + (unless candidates + (user-error "No global marks")) + (nreverse (delete-dups candidates)))) + +;;;###autoload +(defun consult-global-mark (&optional markers) + "Jump to a marker in MARKERS list (defaults to `global-mark-ring'). + +The command supports preview of the currently selected marker position. +The symbol at point is added to the future history." + (interactive) + (consult--read + (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 + ;; have location markers attached. + :category 'consult-location + :sort nil + :require-match t + :lookup #'consult--lookup-location + :history '(:input consult--line-history) + :add-history (thing-at-point 'symbol) + :state (consult--jump-state))) + +;;;;; Command: consult-line + +(defun consult--line-candidates (top curr-line) + "Return list of line candidates. +Start from top if TOP non-nil. +CURR-LINE is the current line number." + (consult--forbid-minibuffer) + (consult--fontify-all) + (let* ((buffer (current-buffer)) + (line (line-number-at-pos (point-min) consult-line-numbers-widen)) + default-cand candidates) + (consult--each-line beg end + (unless (looking-at-p "^\\s-*$") + (push (consult--location-candidate + (consult--buffer-substring beg end) + (cons buffer beg) line line) + candidates) + (when (and (not default-cand) (>= line curr-line)) + (setq default-cand candidates))) + (cl-incf line)) + (unless candidates + (user-error "No lines")) + (nreverse + (if (or top (not default-cand)) + candidates + (let ((before (cdr default-cand))) + (setcdr default-cand nil) + (nconc before candidates)))))) + +(defun consult--line-point-placement (selected candidates highlighted &rest ignored-faces) + "Find point position on matching line. +SELECTED is the currently selected candidate. +CANDIDATES is the list of candidates. +HIGHLIGHTED is the highlighted string to determine the match position. +IGNORED-FACES are ignored when determining the match position." + (when-let (pos (consult--lookup-location selected candidates)) + (if highlighted + (let* ((matches (apply #'consult--point-placement highlighted 0 ignored-faces)) + (dest (+ pos (car matches)))) + ;; Only create a new marker when jumping across buffers (for example + ;; `consult-line-multi'). Avoid creating unnecessary markers, when + ;; scrolling through candidates, since creating markers is not free. + (when (and (markerp pos) (not (eq (marker-buffer pos) (current-buffer)))) + (setq dest (move-marker (make-marker) dest (marker-buffer pos)))) + (cons dest (cdr matches))) + pos))) + +(defun consult--line-match (selected candidates input &rest _) + "Lookup position of match. +SELECTED is the currently selected candidate. +CANDIDATES is the list of candidates. +INPUT is the input string entered by the user." + (consult--line-point-placement selected candidates + (and (not (string-blank-p input)) + (car (consult--completion-filter + input + (list (substring-no-properties selected)) + 'consult-location 'highlight))) + 'completions-first-difference)) + +;;;###autoload +(defun consult-line (&optional initial start) + "Search for a matching line. + +Depending on the setting `consult-point-placement' the command +jumps to the beginning or the end of the first match on the line +or the line beginning. The default candidate is the non-empty +line next to point. This command obeys narrowing. Optional +INITIAL input can be provided. The search starting point is +changed if the START prefix argument is set. The symbol at point +and the last `isearch-string' is added to the future history." + (interactive (list nil (not (not current-prefix-arg)))) + (let* ((curr-line (line-number-at-pos (point) consult-line-numbers-widen)) + (top (not (eq start consult-line-start-from-top))) + (candidates (consult--slow-operation "Collecting lines..." + (consult--line-candidates top curr-line)))) + (consult--read + candidates + :prompt (if top "Go to line from top: " "Go to line: ") + :annotate (consult--line-prefix curr-line) + :category 'consult-location + :sort nil + :require-match t + ;; 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 + :initial (or initial + (and isearch-mode + (prog1 isearch-string (isearch-done)))) + :state (consult--location-state candidates)))) + +;;;;; Command: consult-line-multi + +(defun consult--line-multi-match (selected candidates &rest _) + "Lookup position of match. +SELECTED is the currently selected candidate. +CANDIDATES is the list of candidates." + (consult--line-point-placement selected candidates + (car (member selected candidates)))) + +(defun consult--line-multi-group (cand transform) + "Group function used by `consult-line-multi'. +If TRANSFORM non-nil, return transformed CAND, otherwise return title." + (if transform cand + (let ((marker (car (get-text-property 0 'consult-location cand)))) + (buffer-name + ;; Handle cheap marker + (if (consp marker) + (car marker) + (marker-buffer marker)))))) + +(defun consult--line-multi-candidates (buffers input) + "Collect matching candidates from multiple buffers. +INPUT is the user input which should be matched. +BUFFERS is the list of buffers." + (pcase-let ((`(,regexps . ,hl) + (funcall consult--regexp-compiler + input 'emacs completion-ignore-case)) + (candidates nil) + (cand-idx 0)) + (save-match-data + (dolist (buf buffers (nreverse candidates)) + (with-current-buffer buf + (save-excursion + (let ((line (line-number-at-pos (point-min) consult-line-numbers-widen))) + (goto-char (point-min)) + (while (and (not (eobp)) + (save-excursion (re-search-forward (car regexps) nil t))) + (cl-incf line (consult--count-lines (match-beginning 0))) + (let ((bol (pos-bol)) + (eol (pos-eol))) + (goto-char bol) + (when (and (not (looking-at-p "^\\s-*$")) + (seq-every-p (lambda (r) + (goto-char bol) + (re-search-forward r eol t)) + (cdr regexps))) + (push (consult--location-candidate + (funcall hl (buffer-substring-no-properties bol eol)) + (cons buf bol) (1- line) cand-idx) + candidates) + (cl-incf cand-idx)) + (goto-char (1+ eol))))))))))) + +;;;###autoload +(defun consult-line-multi (query &optional initial) + "Search for a matching line in multiple buffers. + +By default search across all project buffers. If the prefix +argument QUERY is non-nil, all buffers are searched. Optional +INITIAL input can be provided. The symbol at point and the last +`isearch-string' is added to the future history.In order to +search a subset of buffers, QUERY can be set to a plist according +to `consult--buffer-query'." + (interactive "P") + (unless (keywordp (car-safe query)) + (setq query (list :sort 'alpha-current :directory (and (not query) 'project)))) + (pcase-let* ((`(,prompt . ,buffers) (consult--buffer-query-prompt "Go to line" query)) + (collection (consult--dynamic-collection + (apply-partially #'consult--line-multi-candidates + buffers)))) + (consult--read + collection + :prompt prompt + :annotate (consult--line-prefix) + :category 'consult-location + :sort nil + :require-match t + ;; 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 + :initial (consult--async-split-initial + (or initial + (and isearch-mode + (prog1 isearch-string (isearch-done))))) + :state (consult--location-state (lambda () (funcall collection nil))) + :group #'consult--line-multi-group))) + +;;;;; Command: consult-keep-lines + +(defun consult--keep-lines-state (filter) + "State function for `consult-keep-lines' with FILTER function." + (let ((font-lock-orig font-lock-mode) + (hl-line-orig (bound-and-true-p hl-line-mode)) + (point-orig (point)) + lines content-orig replace last-input) + (if (use-region-p) + (save-restriction + ;; Use the same behavior as `keep-lines'. + (let ((rbeg (region-beginning)) + (rend (save-excursion + (goto-char (region-end)) + (unless (or (bolp) (eobp)) + (forward-line 0)) + (point)))) + (consult--fontify-region rbeg rend) + (narrow-to-region rbeg rend) + (consult--each-line beg end + (push (consult--buffer-substring beg end) lines)) + (setq content-orig (buffer-string) + replace (lambda (content &optional pos) + (delete-region rbeg rend) + (insert-before-markers content) + (goto-char (or pos rbeg)) + (setq rend (+ rbeg (length content))) + (add-face-text-property rbeg rend 'region t))))) + (consult--fontify-all) + (setq content-orig (buffer-string) + replace (lambda (content &optional pos) + (delete-region (point-min) (point-max)) + (insert content) + (goto-char (or pos (point-min))))) + (consult--each-line beg end + (push (consult--buffer-substring beg end) lines))) + (setq lines (nreverse lines)) + (lambda (action input) + ;; Restoring content and point position + (when (and (eq action 'return) last-input) + ;; 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 + (or + ;; Committing, but not with empty input + (and (eq action 'return) (not (string-match-p "\\`!? ?\\'" input))) + ;; Input has changed + (not (equal input last-input)))) + (let ((filtered-content + (if (string-match-p "\\`!? ?\\'" input) + ;; Special case the empty input for performance. + ;; Otherwise it could happen that the minibuffer is empty, + ;; but the buffer has not been updated. + content-orig + (if (eq action 'return) + (apply #'concat (mapcan (lambda (x) (list x "\n")) + (funcall filter input lines))) + (while-no-input + ;; Heavy computation is interruptible if *not* committing! + ;; Allocate new string candidates since the matching function mutates! + (apply #'concat (mapcan (lambda (x) (list x "\n")) + (funcall filter input (mapcar #'copy-sequence lines))))))))) + (when (stringp filtered-content) + (when font-lock-mode (font-lock-mode -1)) + (when (bound-and-true-p hl-line-mode) (hl-line-mode -1)) + (if (eq action 'return) + (atomic-change-group + ;; Disable modification hooks for performance + (let ((inhibit-modification-hooks t)) + (funcall replace filtered-content))) + ;; No undo recording, modification hooks, buffer modified-status + (with-silent-modifications + (funcall replace filtered-content) + (setq last-input input)))))) + ;; Restore modes + (when (eq action 'return) + (when hl-line-orig (hl-line-mode 1)) + (when font-lock-orig (font-lock-mode 1)))))) + +;;;###autoload +(defun consult-keep-lines (&optional filter 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 +command obeys narrowing. + +FILTER is the filter function. +INITIAL is the initial input." + (interactive + (list (lambda (pattern cands) + ;; Use consult-location completion category when filtering lines + (consult--completion-filter-dispatch + pattern cands 'consult-location 'highlight)))) + (consult--forbid-minibuffer) + (let ((ro buffer-read-only)) + (unwind-protect + (consult--minibuffer-with-setup-hook + (lambda () + (when ro + (minibuffer-message + (substitute-command-keys + " [Unlocked read-only buffer. \\[minibuffer-keyboard-quit] to quit.]")))) + (setq buffer-read-only nil) + (consult--with-increased-gc + (consult--prompt + :prompt "Keep lines: " + :initial initial + :history 'consult--keep-lines-history + :state (consult--keep-lines-state filter)))) + (setq buffer-read-only ro)))) + +;;;;; Command: consult-focus-lines + +(defun consult--focus-lines-state (filter) + "State function for `consult-focus-lines' with FILTER function." + (let (lines overlays last-input pt-orig pt-min pt-max) + (save-excursion + (save-restriction + (if (not (use-region-p)) + (consult--fontify-all) + (consult--fontify-region (region-beginning) (region-end)) + (narrow-to-region + (region-beginning) + ;; Behave the same as `keep-lines'. + ;; Move to the next line. + (save-excursion + (goto-char (region-end)) + (unless (or (bolp) (eobp)) + (forward-line 0)) + (point)))) + (setq pt-orig (point) pt-min (point-min) pt-max (point-max)) + (let ((i 0)) + (consult--each-line beg end + ;; NOTE: Use "\n" for empty lines, since we need + ;; a string to attach the text property to. + (let ((line (if (eq beg end) (char-to-string ?\n) + (buffer-substring-no-properties beg end)))) + (put-text-property 0 1 'consult--focus-line (cons (cl-incf i) beg) line) + (push line lines))) + (setq lines (nreverse lines))))) + (lambda (action input) + ;; New input provided -> Update + (when (and input (not (equal input last-input))) + (let (new-overlays) + (pcase (while-no-input + (unless (string-match-p "\\`!? ?\\'" input) ;; empty input. + (let* ((inhibit-quit (eq action 'return)) ;; Non interruptible, when quitting! + (not (string-prefix-p "! " input)) + (stripped (string-remove-prefix "! " input)) + (matches (funcall filter stripped lines)) + (old-ind 0) + (block-beg pt-min) + (block-end pt-min)) + (while old-ind + (let ((match (pop matches)) (ind nil) (beg pt-max) (end pt-max) prop) + (when match + (setq prop (get-text-property 0 'consult--focus-line match) + ind (car prop) + beg (cdr prop) + ;; NOTE: Check for empty lines, see above! + end (+ 1 beg (if (equal match "\n") 0 (length match))))) + (unless (eq ind (1+ old-ind)) + (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))) + (setq block-beg beg)) + (setq block-end end old-ind ind))))) + 'commit) + ('commit + (mapc #'delete-overlay overlays) + (setq last-input input overlays new-overlays)) + (_ (mapc #'delete-overlay new-overlays))))) + (when (eq action 'return) + (cond + ((not input) + (mapc #'delete-overlay overlays) + (goto-char pt-orig)) + ((equal input "") + (consult-focus-lines 'show) + (goto-char pt-orig)) + (t + ;; Sucessfully terminated -> Remember invisible overlays + (setq consult--focus-lines-overlays + (nconc consult--focus-lines-overlays overlays)) + ;; move point past invisible + (goto-char (if-let (ov (and (invisible-p pt-orig) + (seq-find (lambda (ov) (overlay-get ov 'invisible)) + (overlays-at pt-orig)))) + (overlay-end ov) + pt-orig)))))))) + +;;;###autoload +(defun consult-focus-lines (&optional show filter 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 +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) + ;; Use consult-location completion category when filtering lines + (consult--completion-filter-dispatch + pattern cands 'consult-location nil)))) + (if show + (progn + (mapc #'delete-overlay consult--focus-lines-overlays) + (setq consult--focus-lines-overlays nil) + (message "All lines revealed")) + (consult--forbid-minibuffer) + (consult--with-increased-gc + (consult--prompt + :prompt + (if consult--focus-lines-overlays + "Focus on lines (RET to reveal): " + "Focus on lines: ") + :initial initial + :history 'consult--keep-lines-history + :state (consult--focus-lines-state filter))))) + +;;;;; Command: consult-goto-line + +(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)) + +;;;###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'." + (interactive "P") + (if arg + (call-interactively #'goto-line) + (consult--forbid-minibuffer) + (consult--local-let ((display-line-numbers consult-goto-line-numbers) + (display-line-numbers-widen consult-line-numbers-widen)) + (while (if-let (pos (consult--goto-line-position + (consult--prompt + :prompt "Go to line: " + :history 'goto-line-history + :state + (let ((preview (consult--jump-preview))) + (lambda (action str) + (funcall preview action + (consult--goto-line-position str #'ignore))))) + #'minibuffer-message)) + (consult--jump pos) + t))))) + +;;;;; Command: consult-recent-file + +(defun consult--file-preview () + "Create preview function for files." + (let ((open (consult--temporary-files)) + (preview (consult--buffer-preview))) + (lambda (action cand) + (unless cand + (funcall open)) + (funcall preview action + (and cand + (eq action 'preview) + (funcall open cand)))))) + +(defun consult--file-action (file) + "Open FILE via `consult--buffer-action'." + (consult--buffer-action (find-file-noselect file))) + +(consult--define-state file) + +;;;###autoload +(defun consult-recent-file () + "Find recent file using `completing-read'." + (interactive) + (find-file + (consult--read + (or + (let (file-name-handler-alist) ;; No Tramp slowdown please + (mapcar #'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: " + :sort nil + :require-match t + :category 'file + :state (consult--file-preview) + :history 'file-name-history))) + +;;;;; Command: consult-mode-command + +(defun consult--mode-name (mode) + "Return name part of MODE." + (replace-regexp-in-string + "global-\\(.*\\)-mode" "\\1" + (replace-regexp-in-string + "\\(-global\\)?-mode\\'" "" + (if (eq mode 'c-mode) + "cc" + (symbol-name mode)) + 'fixedcase) + 'fixedcase)) + +(defun consult--mode-command-candidates (modes) + "Extract commands from MODES. + +The list of features is searched for files belonging to the modes. +From these files, the commands are extracted." + (let* ((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)) + (minor-local-modes (seq-filter (lambda (m) + (and (gethash m minor-hash) + (local-variable-if-set-p m))) + modes)) + (minor-global-modes (seq-filter (lambda (m) + (and (gethash m minor-hash) + (not (local-variable-if-set-p m)))) + modes)) + (major-modes (seq-remove (lambda (m) + (gethash m minor-hash)) + modes)) + (major-paths-hash (consult--string-hash (mapcar #'symbol-file major-modes))) + (minor-local-paths-hash (consult--string-hash (mapcar #'symbol-file minor-local-modes))) + (minor-global-paths-hash (consult--string-hash (mapcar #'symbol-file minor-global-modes))) + (major-name-regexp (regexp-opt (mapcar #'consult--mode-name major-modes))) + (minor-local-name-regexp (regexp-opt (mapcar #'consult--mode-name minor-local-modes))) + (minor-global-name-regexp (regexp-opt (mapcar #'consult--mode-name minor-global-modes))) + (commands)) + (dolist (feature load-history commands) + (when-let (name (alist-get 'provide feature)) + (let* ((path (car feature)) + (file (file-name-nondirectory path)) + (key (cond + ((memq name feature-filter) nil) + ((or (gethash path major-paths-hash) + (string-match-p major-name-regexp file)) + ?m) + ((or (gethash path minor-local-paths-hash) + (string-match-p minor-local-name-regexp file)) + ?l) + ((or (gethash path minor-global-paths-hash) + (string-match-p minor-global-name-regexp file)) + ?g)))) + (when key + (dolist (cmd (cdr feature)) + (let ((sym (cdr-safe cmd))) + (when (and (consp cmd) + (eq (car cmd) 'defun) + (commandp sym) + (not (get sym 'byte-obsolete-info)) + ;; Emacs 28 has a `read-extended-command-predicate' + (if (bound-and-true-p read-extended-command-predicate) + (funcall read-extended-command-predicate sym buffer) + t)) + (let ((name (symbol-name sym))) + (unless (string-match-p command-filter name) + (push (propertize name + 'consult--candidate sym + 'consult--type key) + commands)))))))))))) + +;;;###autoload +(defun consult-mode-command (&rest modes) + "Run a command from any of the given MODES. + +If no MODES are specified, use currently active major and minor modes." + (interactive) + (unless modes + (setq modes (cons major-mode + (seq-filter (lambda (m) + (and (boundp m) (symbol-value m))) + minor-mode-list)))) + (let ((narrow `((?m . ,(format "Major: %s" major-mode)) + (?l . "Local Minor") + (?g . "Global Minor")))) + (command-execute + (consult--read + (consult--mode-command-candidates modes) + :prompt "Mode command: " + :predicate + (lambda (cand) + (let ((key (get-text-property 0 'consult--type cand))) + (if consult--narrow + (= key consult--narrow) + (/= key ?g)))) + :lookup #'consult--lookup-candidate + :group (consult--type-group narrow) + :narrow narrow + :require-match t + :history 'extended-command-history + :category 'command)))) + +;;;;; Command: consult-yank + +(defun consult--read-from-kill-ring () + "Open kill ring menu and return selected string." + ;; `current-kill' updates `kill-ring' with interprogram paste, see + ;; gh:minad/consult#443. + (current-kill 0) + ;; Do not specify a :lookup function in order to preserve completion-styles + ;; highlighting of the current candidate. We have to perform a final lookup to + ;; obtain the original candidate which may be propertized with yank-specific + ;; properties, like 'yank-handler. + (consult--lookup-member + (consult--read + (consult--remove-dups + (or (if consult-yank-rotate + (append kill-ring-yank-pointer + (butlast kill-ring (length kill-ring-yank-pointer))) + kill-ring) + (user-error "Kill ring is empty"))) + :prompt "Yank from kill-ring: " + :history t ;; disable history + :sort nil + :category 'kill-ring + :require-match t + :state + (consult--insertion-preview + (point) + ;; If previous command is yank, hide previously yanked string + (or (and (eq last-command 'yank) (mark t)) (point)))) + kill-ring)) + +;; Adapted from the Emacs `yank-from-kill-ring' function. +;;;###autoload +(defun consult-yank-from-kill-ring (string &optional arg) + "Select STRING from the kill ring and insert it. +With prefix ARG, put point at beginning, and mark at end, like `yank' does. + +This command behaves like `yank-from-kill-ring' in Emacs 28, which also offers +a `completing-read' interface to the `kill-ring'. Additionally the Consult +version supports preview of the selected string." + (interactive (list (consult--read-from-kill-ring) current-prefix-arg)) + (when string + (setq yank-window-start (window-start)) + (push-mark) + (insert-for-yank string) + (setq this-command 'yank) + (when consult-yank-rotate + (if-let (pos (seq-position kill-ring string)) + (setq kill-ring-yank-pointer (nthcdr pos kill-ring)) + (kill-new string))) + (when (consp arg) + ;; Swap point and mark like in `yank'. + (goto-char (prog1 (mark t) + (set-marker (mark-marker) (point) (current-buffer))))))) + +(put 'consult-yank-replace 'delete-selection 'yank) +(put 'consult-yank-pop 'delete-selection 'yank) +(put 'consult-yank-from-kill-ring 'delete-selection 'yank) + +;;;###autoload +(defun consult-yank-pop (&optional arg) + "If there is a recent yank act like `yank-pop'. + +Otherwise select string from the kill ring and insert it. +See `yank-pop' for the meaning of ARG. + +This command behaves like `yank-pop' in Emacs 28, which also offers a +`completing-read' interface to the `kill-ring'. Additionally the Consult +version supports preview of the selected string." + (interactive "*p") + (if (eq last-command 'yank) + (yank-pop (or arg 1)) + (call-interactively #'consult-yank-from-kill-ring))) + +;; Adapted from the Emacs yank-pop function. +;;;###autoload +(defun consult-yank-replace (string) + "Select STRING from the kill ring. + +If there was no recent yank, insert the string. +Otherwise replace the just-yanked string with the selected string. + +There exists no equivalent of this command in Emacs 28." + (interactive (list (consult--read-from-kill-ring))) + (when string + (if (not (eq last-command 'yank)) + (consult-yank-from-kill-ring string) + (let ((inhibit-read-only t) + (pt (point)) + (mk (mark t))) + (setq this-command 'yank) + (funcall (or yank-undo-function 'delete-region) (min pt mk) (max pt mk)) + (setq yank-undo-function nil) + (set-marker (mark-marker) pt (current-buffer)) + (insert-for-yank string) + (set-window-start (selected-window) yank-window-start t) + (if (< pt mk) + (goto-char (prog1 (mark t) + (set-marker (mark-marker) (point) (current-buffer))))))))) + +;;;;; Command: consult-bookmark + +(defun consult--bookmark-preview () + "Create preview function for bookmarks." + (let ((preview (consult--jump-preview)) + (open (consult--temporary-files))) + (lambda (action cand) + (unless cand + (funcall open)) + (funcall + 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))) + (pos (bookmark-get-position bm)) + (buf (funcall open file))) + (set-marker (make-marker) pos buf)))))) + +(defun consult--bookmark-action (bm) + "Open BM via `consult--buffer-action'." + (bookmark-jump bm consult--buffer-display)) + +(consult--define-state bookmark) + +(defun consult--bookmark-candidates () + "Return bookmark candidates." + (bookmark-maybe-load-default-file) + (let ((narrow (mapcar (pcase-lambda (`(,y ,_ ,x)) (cons x y)) + consult-bookmark-narrow))) + (mapcar (lambda (cand) + (propertize (car cand) + 'consult--type + (alist-get + (or (bookmark-get-handler cand) #'bookmark-default-handler) + narrow))) + bookmark-alist))) + +;;;###autoload +(defun consult-bookmark (name) + "If bookmark NAME exists, open it, otherwise create a new bookmark with NAME. + +The command supports preview of file bookmarks and narrowing. See the +variable `consult-bookmark-narrow' for the narrowing configuration." + (interactive + (list + (let ((narrow (mapcar (pcase-lambda (`(,x ,y ,_)) (cons x y)) + consult-bookmark-narrow))) + (consult--read + (consult--bookmark-candidates) + :prompt "Bookmark: " + :state (consult--bookmark-preview) + :category 'bookmark + :history 'bookmark-history + ;; Add default names to future history. + ;; Ignore errors such that `consult-bookmark' can be used in + ;; buffers which are not backed by a file. + :add-history (ignore-errors (bookmark-prop-get (bookmark-make-record) 'defaults)) + :group (consult--type-group narrow) + :narrow (consult--type-narrow narrow))))) + (bookmark-maybe-load-default-file) + (if (assoc name bookmark-alist) + (bookmark-jump name) + (bookmark-set name))) + +;;;;; Command: consult-complex-command + +;;;###autoload +(defun consult-complex-command () + "Select and evaluate command from the command history. + +This command can act as a drop-in replacement for `repeat-complex-command'." + (interactive) + (let* ((history (or (delete-dups (mapcar #'prin1-to-string command-history)) + (user-error "There are no previous complex commands"))) + (cmd (read (consult--read + history + :prompt "Command: " + :default (car history) + :sort nil + :history t ;; disable history + :category 'expression)))) + ;; Taken from `repeat-complex-command' + (add-to-history 'command-history cmd) + (apply #'funcall-interactively + (car cmd) + (mapcar (lambda (e) (eval e t)) (cdr cmd))))) + +;;;;; Command: consult-history + +(declare-function ring-elements "ring") + +(defun consult--current-history () + "Return the history and index variable relevant to the current buffer. +If the minibuffer is active, the minibuffer history is returned, +otherwise the history corresponding to the mode. There is a +special case for `repeat-complex-command', for which the command +history is used." + (cond + ;; In the minibuffer we use the current minibuffer history, + ;; which can be configured by setting `minibuffer-history-variable'. + ((minibufferp) + (when (eq minibuffer-history-variable t) + (user-error "Minibuffer history is disabled for `%s'" this-command)) + (list (mapcar #'consult--tofu-hide + (if (eq minibuffer-history-variable 'command-history) + ;; If pressing "C-x M-:", i.e., `repeat-complex-command', + ;; we are instead querying the `command-history' and get a + ;; full s-expression. Alternatively you might want to use + ;; `consult-complex-command', which can also be bound to + ;; "C-x M-:"! + (mapcar #'prin1-to-string command-history) + (symbol-value minibuffer-history-variable))))) + ;; Otherwise we use a mode-specific history, see `consult-mode-histories'. + (t (let ((found (seq-find (lambda (h) + (and (derived-mode-p (car h)) + (boundp (if (consp (cdr h)) (cadr h) (cdr h))))) + consult-mode-histories))) + (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 +(defun consult-history (&optional history index bol) + "Insert string from HISTORY of current buffer. +In order to select from a specific HISTORY, pass the history +variable as argument. INDEX is the name of the index variable to +update, if any. BOL is the function which jumps to the beginning +of the prompt. See also `cape-history' from the Cape package." + (interactive) + (pcase-let* ((`(,history ,index ,bol) (if history + (list history index bol) + (consult--current-history))) + (history (if (ring-p history) (ring-elements history) history)) + (`(,beg . ,end) + (if (minibufferp) + (cons (minibuffer-prompt-end) (point-max)) + (if bol + (save-excursion + (funcall bol) + (cons (point) (pos-eol))) + (cons (point) (point))))) + (str (consult--local-let ((enable-recursive-minibuffers t)) + (consult--read + (or (consult--remove-dups history) + (user-error "History is empty")) + :prompt "History: " + :history t ;; disable history + :category ;; Report category depending on history variable + (and (minibufferp) + (pcase minibuffer-history-variable + ('extended-command-history 'command) + ('buffer-name-history 'buffer) + ('face-name-history 'face) + ('read-envvar-name-history 'environment-variable) + ('bookmark-history 'bookmark) + ('file-name-history 'file))) + :sort nil + :initial (buffer-substring-no-properties beg end) + :state (consult--insertion-preview beg end))))) + (delete-region beg end) + (when index + (set index (seq-position history str))) + (insert (substring-no-properties str)))) + +;;;;; Command: consult-isearch-history + +(defun consult-isearch-forward (&optional 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." + (interactive) + (consult-isearch-forward (not reverse))) + +;; Emacs 28: hide in M-X +(put #'consult-isearch-backward 'completion-predicate #'ignore) +(put #'consult-isearch-forward 'completion-predicate #'ignore) + +(defvar-keymap consult-isearch-history-map + :doc "Additional keymap used by `consult-isearch-history'." + " " #'consult-isearch-forward + " " #'consult-isearch-backward) + +(defun consult--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)))) + +(defconst consult--isearch-history-narrow + '((?c . "Char") + (?u . "Custom") + (?l . "Literal") + (?r . "Regexp") + (?s . "Symbol") + (?w . "Word"))) + +;;;###autoload +(defun consult-isearch-history () + "Read a search string with completion from the Isearch history. + +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)))))) + (unless isearch-mode (isearch-mode t)) + (with-isearch-suspended + (setq isearch-new-string + (consult--read + (car candidates) + :prompt "I-search: " + :category 'consult-isearch + :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))) + :group + (lambda (cand transform) + (if transform + cand + (alist-get (consult--tofu-get cand) consult--isearch-history-narrow))) + :lookup + (lambda (selected candidates &rest _) + (if-let (found (member selected candidates)) + (substring (car found) 0 -1) + selected)) + :state + (lambda (action cand) + (when (and (eq action 'preview) cand) + (setq isearch-string cand) + (isearch-update-from-string-properties cand) + (isearch-update))) + :narrow + (list :predicate + (lambda (cand) (= (consult--tofu-get cand) consult--narrow)) + :keys consult--isearch-history-narrow)) + isearch-new-message + (mapconcat 'isearch-text-char-description isearch-new-string ""))) + ;; Setting `isearch-regexp' etc only works outside of `with-isearch-suspended'. + (unless (plist-member (text-properties-at 0 isearch-string) 'isearch-regexp-function) + (setq isearch-regexp t + isearch-regexp-function nil)))) + +;;;;; Command: consult-minor-mode-menu + +(defun consult--minor-mode-candidates () + "Return list of minor-mode candidate strings." + (mapcar + (pcase-lambda (`(,name . ,sym)) + (propertize + name + 'consult--candidate sym + 'consult--minor-mode-narrow + (logior + (ash (if (local-variable-if-set-p sym) ?l ?g) 8) + (if (and (boundp sym) (symbol-value sym)) ?i ?o)) + 'consult--minor-mode-group + (concat + (if (local-variable-if-set-p sym) "Local " "Global ") + (if (and (boundp sym) (symbol-value sym)) "On" "Off")))) + (nconc + ;; according to describe-minor-mode-completion-table-for-symbol + ;; the minor-mode-list contains *all* minor modes + (mapcar (lambda (sym) (cons (symbol-name sym) sym)) minor-mode-list) + ;; take the lighters from minor-mode-alist + (delq nil + (mapcar (pcase-lambda (`(,sym ,lighter)) + (when (and lighter (not (equal "" lighter))) + (setq lighter (string-trim (format-mode-line lighter))) + (unless (string-blank-p lighter) + (cons lighter sym)))) + minor-mode-alist))))) + +(defconst consult--minor-mode-menu-narrow + '((?l . "Local") + (?g . "Global") + (?i . "On") + (?o . "Off"))) + +;;;###autoload +(defun consult-minor-mode-menu () + "Enable or disable minor mode. + +This is an alternative to `minor-mode-menu-from-indicator'." + (interactive) + (call-interactively + (consult--read + (consult--minor-mode-candidates) + :prompt "Minor mode: " + :require-match t + :category 'minor-mode + :group + (lambda (cand transform) + (if transform cand (get-text-property 0 'consult--minor-mode-group cand))) + :narrow + (list :predicate + (lambda (cand) + (let ((narrow (get-text-property 0 'consult--minor-mode-narrow cand))) + (or (= (logand narrow 255) consult--narrow) + (= (ash narrow -8) consult--narrow)))) + :keys + consult--minor-mode-menu-narrow) + :lookup #'consult--lookup-candidate + :history 'consult--minor-mode-menu-history))) + +;;;;; Command: consult-theme + +;;;###autoload +(defun consult-theme (theme) + "Disable current themes and enable THEME from `consult-themes'. + +The command supports previewing the currently selected theme." + (interactive + (list + (let* ((regexp (consult--regexp-filter + (mapcar (lambda (x) (if (stringp x) x (format "\\`%s\\'" x))) + consult-themes))) + (avail-themes (seq-filter + (lambda (x) (string-match-p regexp (symbol-name x))) + (cons 'default (custom-available-themes)))) + (saved-theme (car custom-enabled-themes))) + (consult--read + (mapcar #'symbol-name avail-themes) + :prompt "Theme: " + :require-match t + :category 'theme + :history 'consult--theme-history + :lookup (lambda (selected &rest _) + (setq selected (and selected (intern-soft selected))) + (or (and selected (car (memq selected avail-themes))) + saved-theme)) + :state (lambda (action theme) + (pcase action + ('return (consult-theme (or theme saved-theme))) + ((and 'preview (guard theme)) (consult-theme theme)))) + :default (symbol-name (or saved-theme 'default)))))) + (when (eq theme 'default) (setq theme nil)) + (unless (eq theme (car custom-enabled-themes)) + (mapc #'disable-theme custom-enabled-themes) + (when theme + (if (custom-theme-p theme) + (enable-theme theme) + (load-theme theme :no-confirm))))) + +;;;;; Command: consult-buffer + +(defun consult--buffer-sort-alpha (buffers) + "Sort BUFFERS alphabetically, put starred buffers at the end." + (sort buffers + (lambda (x y) + (setq x (buffer-name x) y (buffer-name y)) + (let ((a (and (length> x 0) (eq (aref x 0) ?*))) + (b (and (length> y 0) (eq (aref y 0) ?*)))) + (if (eq a b) + (string< x y) + (not a)))))) + +(defun consult--buffer-sort-alpha-current (buffers) + "Sort BUFFERS alphabetically, put current at the beginning." + (let ((buffers (consult--buffer-sort-alpha buffers)) + (current (current-buffer))) + (if (memq current buffers) + (cons current (delq current buffers)) + buffers))) + +(defun consult--buffer-sort-visibility (buffers) + "Sort BUFFERS by visibility." + (let ((hidden) + (current (current-buffer))) + (consult--keep! buffers + (unless (eq it current) + (if (get-buffer-window it 'visible) + it + (push it hidden) + nil))) + (nconc (nreverse hidden) buffers (list (current-buffer))))) + +(defun consult--normalize-directory (dir) + "Normalize directory DIR. +DIR can be project, nil or a path." + (cond + ((eq dir 'project) (consult--project-root)) + (dir (expand-file-name dir)))) + +(defun consult--buffer-query-prompt (prompt query) + "Buffer query function returning a scope description. +PROMPT is the prompt format string. +QUERY is passed to `consult--buffer-query'." + (let* ((dir (plist-get query :directory)) + (ndir (consult--normalize-directory dir)) + (buffers (apply #'consult--buffer-query :directory ndir query)) + (count (length buffers))) + (cons (format "%s (%d buffer%s%s): " prompt count + (if (= count 1) "" "s") + (cond + ((and ndir (eq dir 'project)) + (format ", Project %s" (consult--project-name ndir))) + (ndir (concat ", " (consult--abbreviate-directory ndir))) + (t ""))) + buffers))) + +(cl-defun consult--buffer-query (&key sort directory mode as predicate (filter t) + include (exclude consult-buffer-filter)) + "Buffer query function. +DIRECTORY can either be project or a path. +SORT can be visibility, alpha or nil. +FILTER can be either t, nil or invert. +EXCLUDE is a list of regexps. +INCLUDE is a list of regexps. +MODE can be a mode or a list of modes to restrict the returned buffers. +PREDICATE is a predicate function. +AS is a conversion function." + ;; This function is the backbone of most `consult-buffer' source. The + ;; function supports filtering by various criteria which are used throughout + ;; Consult. + (let ((root (consult--normalize-directory directory)) + (buffers (buffer-list))) + (when sort + (setq buffers (funcall (intern (format "consult--buffer-sort-%s" sort)) buffers))) + (when (or filter mode as root) + (let ((mode (ensure-list mode)) + (exclude-re (consult--regexp-filter exclude)) + (include-re (consult--regexp-filter include))) + (consult--keep! buffers + (and + (or (not mode) + (apply #'provided-mode-derived-p + (buffer-local-value 'major-mode it) mode)) + (pcase-exhaustive filter + ('nil t) + ((or 't 'invert) + (eq (eq filter t) + (and + (or (not exclude) + (not (string-match-p exclude-re (buffer-name it)))) + (or (not include) + (not (not (string-match-p include-re (buffer-name it))))))))) + (or (not root) + (when-let (dir (buffer-local-value 'default-directory it)) + (string-prefix-p root + (if (and (/= 0 (length dir)) (eq (aref dir 0) ?/)) + dir + (expand-file-name dir))))) + (or (not predicate) (funcall predicate it)) + (if as (funcall as it) it))))) + buffers)) + +(defun consult--buffer-file-hash () + "Return hash table of all buffer file names." + (consult--string-hash (consult--buffer-query :as #'buffer-file-name))) + +(defun consult--buffer-preview () + "Buffer preview function." + (let ((orig-buf (current-buffer)) 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)))))))))) + +(defun consult--buffer-action (buffer &optional norecord) + "Switch to BUFFER via `consult--buffer-display' function. +If NORECORD is non-nil, do not record the buffer switch in the buffer list." + (funcall consult--buffer-display buffer norecord)) + +(consult--define-state buffer) + +(defvar consult--source-bookmark + `(:name "Bookmark" + :narrow ?m + :category bookmark + :face consult-bookmark + :history bookmark-history + :items ,#'bookmark-all-names + :state ,#'consult--bookmark-state) + "Bookmark candidate source for `consult-buffer'.") + +(defvar consult--source-project-buffer + `(:name "Project Buffer" + :narrow (?p . "Project") + :hidden t + :category buffer + :face consult-buffer + :history buffer-name-history + :state ,#'consult--buffer-state + :enabled ,(lambda () consult-project-function) + :items + ,(lambda () + (when-let (root (consult--project-root)) + (consult--buffer-query :sort 'visibility + :directory root + :as #'buffer-name)))) + "Project buffer candidate source for `consult-buffer'.") + +(defvar consult--source-project-recent-file + `(:name "Project File" + :narrow (?p . "Project") + :hidden t + :category file + :face consult-file + :history file-name-history + :state ,#'consult--file-state + :new + ,(lambda (file) + (consult--file-action + (expand-file-name file (consult--project-root)))) + :enabled + ,(lambda () + (and consult-project-function + 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)))))))) + "Project file candidate source for `consult-buffer'.") + +(defvar consult--source-hidden-buffer + `(:name "Hidden Buffer" + :narrow 32 + :hidden t + :category buffer + :face consult-buffer + :history buffer-name-history + :action ,#'consult--buffer-action + :items + ,(lambda () (consult--buffer-query :sort 'visibility + :filter 'invert + :as #'buffer-name))) + "Hidden buffer candidate source for `consult-buffer'.") + +(defvar consult--source-modified-buffer + `(:name "Modified Buffer" + :narrow ?* + :hidden t + :category buffer + :face consult-buffer + :history buffer-name-history + :state ,#'consult--buffer-state + :items + ,(lambda () (consult--buffer-query :sort 'visibility + :as #'buffer-name + :predicate + (lambda (buf) + (and (buffer-modified-p buf) + (buffer-file-name buf)))))) + "Modified buffer candidate source for `consult-buffer'.") + +(defvar consult--source-buffer + `(:name "Buffer" + :narrow ?b + :category buffer + :face consult-buffer + :history buffer-name-history + :state ,#'consult--buffer-state + :default t + :items + ,(lambda () (consult--buffer-query :sort 'visibility + :as #'buffer-name))) + "Buffer candidate source for `consult-buffer'.") + +(defun consult--file-register-p (reg) + "Return non-nil if REG is a file register." + (memq (car-safe (cdr reg)) '(file-query file))) + +(autoload 'consult-register--candidates "consult-register") +(defvar consult--source-file-register + `(:name "File Register" + :narrow (?r . "Register") + :category file + :state ,#'consult--file-state + :enabled ,(lambda () (seq-some #'consult--file-register-p register-alist)) + :items ,(lambda () (consult-register--candidates #'consult--file-register-p))) + "File register source.") + +(defvar consult--source-recent-file + `(:name "File" + :narrow ?f + :category file + :face consult-file + :history file-name-history + :state ,#'consult--file-state + :new ,#'consult--file-action + :enabled ,(lambda () recentf-mode) + :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'. + (unless (eq (aref file 0) ?/) + (setq file (expand-file-name file))) + (unless (gethash file ht) + (push (abbreviate-file-name file) items)))))) + "Recent file candidate source for `consult-buffer'.") + +;;;###autoload +(defun consult-buffer (&optional sources) + "Enhanced `switch-to-buffer' command with support for virtual buffers. + +The command supports recent files, bookmarks, views and project files as +virtual buffers. Buffers are previewed. Narrowing to buffers (b), files (f), +bookmarks (m) and project files (p) is supported via the corresponding +keys. In order to determine the project-specific files and buffers, the +`consult-project-function' is used. The virtual buffer SOURCES +default to `consult-buffer-sources'. See `consult--multi' for the +configuration of the virtual buffer sources." + (interactive) + (let ((selected (consult--multi (or sources consult-buffer-sources) + :require-match + (confirm-nonexistent-file-or-buffer) + :prompt "Switch to: " + :history 'consult--buffer-history + :sort nil))) + ;; For non-matching candidates, fall back to buffer creation. + (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 + ;; 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? + ;; You mustn't be afraid to dream a little bigger, darling. + `(let ((consult-project-function + (let ((root (or (consult--project-root t) (user-error "No project found"))) + (depth (recursion-depth)) + (orig consult-project-function)) + (lambda (may-prompt) + (if (= depth (recursion-depth)) + root + (funcall orig may-prompt)))))) + ,@body)) + +;;;###autoload +(defun consult-project-buffer () + "Enhanced `project-switch-to-buffer' command with support for virtual buffers. +The command may prompt you for a project directory if it is invoked from +outside a project. See `consult-buffer' for more details." + (interactive) + (consult--with-project + (consult-buffer consult-project-buffer-sources))) + +;;;###autoload +(defun consult-buffer-other-window () + "Variant of `consult-buffer' which opens in other window." + (interactive) + (let ((consult--buffer-display #'switch-to-buffer-other-window)) + (consult-buffer))) + +;;;###autoload +(defun consult-buffer-other-frame () + "Variant of `consult-buffer' which opens in other frame." + (interactive) + (let ((consult--buffer-display #'switch-to-buffer-other-frame)) + (consult-buffer))) + +;;;;; Command: consult-grep + +(defun consult--grep-format (async builder) + "Return ASYNC function highlighting grep match results. +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)))) + (funcall async action)) + ((consp action) + (let ((file "") (file-len 0) result) + (save-match-data + (dolist (str action) + (when (and (string-match consult--grep-match-regexp str) + ;; Filter out empty context lines + (or (/= (aref str (match-beginning 3)) ?-) + (/= (match-end 0) (length str)))) + ;; We share the file name across candidates to reduce + ;; the amount of allocated memory. + (unless (and (= file-len (- (match-end 1) (match-beginning 1))) + (eq t (compare-strings + file 0 file-len + str (match-beginning 1) (match-end 1) nil))) + (setq file (match-string 1 str) + file-len (length file))) + (let* ((line (match-string 2 str)) + (ctx (= (aref str (match-beginning 3)) ?-)) + (sep (if ctx "-" ":")) + (content (substring str (match-end 0))) + (line-len (length line))) + (when (length> content consult-grep-max-columns) + (setq content (substring content 0 consult-grep-max-columns))) + (when highlight + (funcall highlight content)) + (setq str (concat file sep line sep content)) + ;; Store file name in order to avoid allocations in `consult--prefix-group' + (add-text-properties 0 file-len `(face consult-file consult--prefix-group ,file) str) + (put-text-property (1+ file-len) (+ 1 file-len line-len) 'face 'consult-line-number str) + (when ctx + (add-face-text-property (+ 2 file-len line-len) (length str) 'consult-grep-context 'append str)) + (push str result))))) + (funcall async (nreverse result)))) + (t (funcall async action)))))) + +(defun consult--grep-position (cand &optional find-file) + "Return the grep position marker for CAND. +FIND-FILE is the file open function, defaulting to `find-file'." + (when cand + (let* ((file-end (next-single-property-change 0 'face cand)) + (line-end (next-single-property-change (1+ file-end) 'face cand)) + (matches (consult--point-placement cand (1+ line-end) 'consult-grep-context)) + (file (substring-no-properties cand 0 file-end)) + (line (string-to-number (substring-no-properties cand (+ 1 file-end) line-end)))) + (when-let (pos (consult--marker-from-line-column + (funcall (or find-file #'find-file) file) + line (or (car matches) 0))) + (cons pos (cdr matches)))))) + +(defun consult--grep-state () + "Grep state function." + (let ((open (consult--temporary-files)) + (jump (consult--jump-state))) + (lambda (action cand) + (unless cand + (funcall open)) + (funcall jump action (consult--grep-position + cand + (and (not (eq action 'return)) open)))))) + +(defun consult--grep-exclude-args () + "Produce grep exclude arguments. +Take the variables `grep-find-ignored-directories' and +`grep-find-ignored-files' into account." + (unless (boundp 'grep-find-ignored-files) (require 'grep)) + (nconc (mapcar (lambda (s) (concat "--exclude=" s)) + (bound-and-true-p grep-find-ignored-files)) + (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. + +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))) + (consult--read + (consult--async-command builder + (consult--grep-format builder) + :file-handler t) ;; allow tramp + :prompt (car prompt-dir) + :lookup #'consult--lookup-member + :state (consult--grep-state) + :initial (consult--async-split-initial initial) + :add-history (consult--async-split-thingatpt 'symbol) + :require-match t + :category 'consult-grep + :group #'consult--prefix-group + :history '(:input consult--grep-history) + :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." + (let* ((cmd (consult--build-args consult-grep-args)) + (type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended))) + (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) + (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 + (list (if (eq type 'pcre) "-P" "-E") ;; perl or extended + "-e" (consult--join-regexps re type)) + opts) + 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 +`#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. + +Here we give a few example inputs: + +#alpha beta : Search for alpha and beta in any order. +#alpha.*beta : Search for alpha before beta. +#\\(alpha\\|beta\\) : Search for alpha or beta (Note Emacs syntax!) +#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." + (interactive "P") + (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)))))) + +;;;###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." + (interactive "P") + (consult--grep "Git-grep" #'consult--git-grep-builder dir initial)) + +;;;;; Command: consult-ripgrep + +(defun consult--ripgrep-make-builder () + "Create ripgrep command line builder." + (let* ((cmd (consult--build-args consult-ripgrep-args)) + (type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended))) + (lambda (input) + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (flags (append cmd opts)) + (ignore-case (if (or (member "-S" flags) (member "--smart-case" flags)) + (let (case-fold-search) + ;; Case insensitive if there are no uppercase letters + (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) + (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) + 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." + (interactive "P") + (consult--grep "Ripgrep" (consult--ripgrep-make-builder) dir initial)) + +;;;;; Command: consult-find + +(defun consult--find (prompt builder initial) + "Run find command in current directory. + +The function returns the selected file. +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." + (consult--read + (consult--async-command builder + (consult--async-map (lambda (x) (string-remove-prefix "./" x))) + (consult--async-highlight builder) + :file-handler t) ;; allow tramp + :prompt prompt + :sort nil + :require-match t + :initial (consult--async-split-initial initial) + :add-history (consult--async-split-thingatpt 'filename) + :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 + (concat (car cmd) " -regextype emacs -version"))) + 'emacs 'basic))) + (lambda (input) + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + ;; ignore-case=t since -iregex is used below + (`(,re . ,hl) (funcall consult--regexp-compiler arg type t))) + (when re + (cons (append cmd + (cdr (mapcan + (lambda (x) + `("-and" "-iregex" + ,(format ".*%s.*" + ;; HACK Replace non-capturing groups with capturing groups. + ;; GNU find does not support non-capturing groups. + (replace-regexp-in-string + "\\\\(\\?:" "\\(" x 'fixedcase 'literal)))) + re)) + opts) + hl)))))) + +;;;###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." + (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)))) + +;;;;; Command: consult-locate + +(defun consult--locate-builder (input) + "Build command line given CONFIG and INPUT." + (pcase-let ((`(,arg . ,opts) (consult--command-split input))) + (unless (string-blank-p arg) + (cons (append (consult--build-args consult-locate-args) + (list arg) opts) + (cdr (consult--default-regexp-compiler input 'basic t)))))) + +;;;###autoload +(defun consult-locate (&optional initial) + "Search with `locate' for files which match input given INITIAL input. + +The input is treated literally such that locate can take advantage of +the locate database index. Regular expressions would often force a slow +linear search through the entire database. The locate process is started +asynchronously, similar to `consult-grep'. See `consult-grep' for more +details regarding the asynchronous search." + (interactive) + (find-file (consult--find "Locate: " #'consult--locate-builder initial))) + +;;;;; Command: consult-man + +(defun consult--man-builder (input) + "Build command line given CONFIG and INPUT." + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (`(,re . ,hl) (funcall consult--regexp-compiler arg 'basic t))) + (when re + (cons (append (consult--build-args consult-man-args) + (list (consult--join-regexps re 'basic)) + opts) + hl)))) + +(defun consult--man-format (lines) + "Format man candidates from LINES." + (let ((candidates)) + (save-match-data + (dolist (str lines) + (when (string-match "\\`\\(.*?\\([^ ]+\\) *(\\([^,)]+\\)[^)]*).*?\\) +- +\\(.*\\)\\'" str) + (let* ((names (match-string 1 str)) + (name (match-string 2 str)) + (section (match-string 3 str)) + (desc (match-string 4 str)) + (cand (format "%s - %s" names desc))) + (add-text-properties 0 (length names) + (list 'face 'consult-file + 'consult-man (concat section " " name)) + cand) + (push cand candidates))))) + (nreverse candidates))) + +;;;###autoload +(defun consult-man (&optional initial) + "Search for man page given INITIAL input. + +The input string is not preprocessed and passed literally to the +underlying man commands. The man process is started asynchronously, +similar to `consult-grep'. See `consult-grep' for more details regarding +the asynchronous search." + (interactive) + (man (consult--read + (consult--async-command #'consult--man-builder + (consult--async-transform consult--man-format) + (consult--async-highlight #'consult--man-builder)) + :prompt "Manual entry: " + :require-match t + :category 'consult-man + :lookup (apply-partially #'consult--lookup-prop 'consult-man) + :initial (consult--async-split-initial initial) + :add-history (consult--async-split-thingatpt 'symbol) + :history '(:input consult--man-history)))) + +;;;; Preview at point in completions buffers + +(define-minor-mode consult-preview-at-point-mode + "Preview minor mode for *Completions* buffers. +When moving around in the *Completions* buffer, the candidate at point is +automatically previewed." + :init-value nil :group 'consult + (if consult-preview-at-point-mode + (add-hook 'post-command-hook #'consult-preview-at-point nil 'local) + (remove-hook 'post-command-hook #'consult-preview-at-point 'local))) + +(defun consult-preview-at-point () + "Preview candidate at point in *Completions* buffer." + (interactive) + (when-let ((win (active-minibuffer-window)) + (buf (window-buffer win)) + (fun (buffer-local-value 'consult--preview-function buf))) + (funcall fun))) + +;;;; Integration with the default completion system + +(defun consult--default-completion-minibuffer-candidate () + "Return current minibuffer candidate from default completion system or Icomplete." + (when (and (minibufferp) + (eq completing-read-function #'completing-read-default)) + (let ((content (minibuffer-contents-no-properties))) + ;; When the current minibuffer content matches a candidate, return it! + (if (test-completion content + minibuffer-completion-table + minibuffer-completion-predicate) + content + ;; Return the full first candidate of the sorted completion list. + (when-let ((completions (completion-all-sorted-completions))) + (concat + (substring content 0 (or (cdr (last completions)) 0)) + (car completions))))))) + +(defun consult--default-completion-list-candidate () + "Return current candidate at point from completions buffer." + (let (beg end) + (when (and + (derived-mode-p 'completion-list-mode) + ;; Logic taken from `choose-completion'. + ;; TODO Upstream a `completion-list-get-candidate' function. + (cond + ((and (not (eobp)) (get-text-property (point) 'mouse-face)) + (setq end (point) beg (1+ (point)))) + ((and (not (bobp)) (get-text-property (1- (point)) 'mouse-face)) + (setq end (1- (point)) beg (point))))) + (setq beg (previous-single-property-change beg 'mouse-face) + end (or (next-single-property-change end 'mouse-face) (point-max))) + (or (get-text-property beg 'completion--string) + (buffer-substring-no-properties beg end))))) + +;; Announce now that consult has been loaded +(provide 'consult) + +;;;; 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))) + +;;; consult.el ends here -- cgit v1.2.3 From 247c240b89fe28658f0ce00da0d7be531f373c4a Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external images Forwarded: not-needed Gbp-Pq: Name remove-external-images.patch --- README.org | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.org b/README.org index 7caf5a5..2c640be 100644 --- a/README.org +++ b/README.org @@ -6,12 +6,6 @@ #+texinfo_dir_title: Consult: (consult). #+texinfo_dir_desc: Useful commands built on completing-read. -#+html: GNU Emacs -#+html: GNU ELPA -#+html: GNU-devel ELPA -#+html: MELPA -#+html: MELPA Stable - Consult provides search and navigation commands based on the Emacs completion function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers asynchronous and interactive =consult-grep= and -- cgit v1.2.3 From 5c9edb38f774aae9a9e793e7ac9b5acab004421b Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external pages and debianise Forwarded: not-needed Gbp-Pq: Name replace-external-references-when-possible.patch --- README.org | 74 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/README.org b/README.org index 2c640be..d000589 100644 --- a/README.org +++ b/README.org @@ -7,7 +7,7 @@ #+texinfo_dir_desc: Useful commands built on completing-read. Consult provides search and navigation commands based on the Emacs completion -function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a +function [[info:elisp#Minibuffer Completion][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers asynchronous and interactive =consult-grep= and =consult-ripgrep= commands, and the line-based search command =consult-line=. Furthermore Consult provides an advanced buffer switching command =consult-buffer= @@ -18,8 +18,8 @@ presents a flat list of the Imenu with [[#live-previews][live preview]], [[#narr Please take a look at the [[#available-commands][full list of commands]]. Consult is fully compatible with completion systems centered around the standard -Emacs =completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], -and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]]. +Emacs =completing-read= API, notably the default completion system, Vertico (~apt install elpa-vertico~), [[https://github.com/protesilaos/mct][Mct]], +and [[info:emacs#Icomplete][Icomplete]]. This package keeps the completion system specifics to a minimum. The ability of the Consult commands to work well with arbitrary completion systems is one of @@ -27,7 +27,7 @@ the main advantages of the package. Consult fits well into existing setups and it helps you to create a full completion environment out of small and independent components. -You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with +You can combine the complementary packages Marginalia (~apt install elpa-marginalia~), Embark (~apt install elpa-embark~) and Orderless (~apt install elpa-orderless~) with Consult. Marginalia enriches the completion display with annotations, e.g., documentation strings or file information. The versatile Embark package provides local actions, comparable to a context menu. These actions operate on the @@ -66,7 +66,7 @@ Many commands implement a little known but convenient Emacs feature called type =M-n= and typically Consult will insert the symbol or thing at point into the input. -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see +*TIP:* If you have Marginalia annotators activated, type =M-x ^consult= to see 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. #+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 - either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of + either the [[https://github.com/minad/corfu][Corfu]] or the Company (~apt install elpa-company~) package. There is a technical limitation of =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= after some prefix key, the =prefix-help-comm 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 -configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically +configuration]]. If which-key (~apt install elpa-which-key~) is installed, the narrowing keys are automatically shown in the which-key window after pressing the =consult-narrow-key=. ** Asynchronous search @@ -702,11 +702,11 @@ since some details may still change. :end: #+cindex: embark -*NOTE*: Install the =embark-consult= package from MELPA, which provides -Consult-specific Embark actions and the Occur buffer export. +*NOTE*: Install the embark-consult package (~apt install elpa-embark-consult~), +which provides Consult-specific Embark actions and the Occur buffer export. Embark is a versatile package which offers context dependent actions, comparable -to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its +to a context menu. See the [[info:embark][Embark manual]] for an extensive description of its capabilities. Actions are commands which can operate on the currently selected candidate (or @@ -726,7 +726,7 @@ the matching lines from =consult-line=, =consult-outline=, =consult-mark= and 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, -if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. +if the wgrep (~apt install elpa-wgrep~) package is installed. These three workflows are symmetric. + =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/Emacs-wgrep][wgrep]] package is install :description: Example configuration and customization variables :end: -Consult can be installed from [[https://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package -manager. Alternatively it can be directly installed from the development -repository via other non-standard package managers. +Consult can be installed via ~apt install elpa-consult~. There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be contributed. -*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your +*IMPORTANT:* It is strongly recommended that you enable [[info:elisp#Lexical Binding][lexical binding]] in your 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-intrusive but requires a little setup 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. -The configuration shown here relies on the =use-package= macro, which is a -convenient tool to manage package configurations. +The configuration shown here relies on the =use-package= macro (~apt install +elpa-use-package~), which is a convenient tool to manage package configurations. *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. :end: #+cindex: customization -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET +*TIP:* If you have Marginalia installed, type =M-x customize-variable RET ^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: I use and recommend this combination of packages: - consult: This package -- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system -- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates -- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates -- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering +- vertico (~apt install elpa-vertico~): Fast and minimal vertical completion system +- marginalia (~apt install elpa-marginalia~): Annotations for the completion candidates +- embark and embark-consult (~apt install elpa-embark elpa-embark-consult~): + Action commands, which can act on the completion candidates +- orderless (~apt install elpa-orderless~): Completion style which offers + flexible candidate filtering 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 programs or with other packages in the 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/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://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. - [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. -- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). -- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. +- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client, ~apt install elpa-lsp-mode~). +- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the Notmuch (~apt install notmuch~) email system using Consult. - [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. -- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. +- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with Org-roam (~apt install elpa-org-roam~). - [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. -- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. -- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. +- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional Projectile (~apt install elpa-projectile~) integration and buffer sources. +- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the Recoll (~apt install elpa-recoll~) desktop full-text search using Consult. - [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. -- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. +- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet (~apt install elpa-yasnippet elpa-yasnippet-snippets~). - [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. 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 [[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). - [[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. +- 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=. -- [[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. * Bug reports @@ -1137,7 +1137,7 @@ Please provide the necessary important information with your bug report: 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]]. -When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. +When evaluating Consult-related code snippets you should enable [[info:elisp#Lexical Binding][lexical binding]]. Consult often relies on lambdas and lexical closures. * Contributions @@ -1161,7 +1161,7 @@ small configuration or command snippets. :description: Contributors and Sources of Inspiration :end: -This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult +This package took inspiration from Counsel (~apt install elpa-counsel~) by Oleh Krehel. Some of the Consult commands originated in the Counsel package or the wiki of the Selectrum package. This package exists only thanks to the help of these great contributors and thanks to the feedback of many users. Thank you! -- cgit v1.2.3 From af6d7fe7abd14c6108c47e4546d71077f68c0f3a Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external images Forwarded: not-needed Gbp-Pq: Name remove-external-images.patch --- README.org | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.org b/README.org index 6b6c466..65f27bf 100644 --- a/README.org +++ b/README.org @@ -6,12 +6,6 @@ #+texinfo_dir_title: Consult: (consult). #+texinfo_dir_desc: Useful commands built on completing-read. -#+html: GNU Emacs -#+html: GNU ELPA -#+html: GNU-devel ELPA -#+html: MELPA -#+html: MELPA Stable - Consult provides search and navigation commands based on the Emacs completion function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers asynchronous and interactive =consult-grep= and -- cgit v1.2.3 From 1bd2ad236aab56541ab43aca2d640137c2d42b89 Mon Sep 17 00:00:00 2001 From: Aymeric Agon-Rambosson Date: Wed, 10 Aug 2022 04:55:32 +0200 Subject: Drop references to external pages and debianise Forwarded: not-needed Gbp-Pq: Name replace-external-references-when-possible.patch --- README.org | 74 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/README.org b/README.org index 65f27bf..c12f3b4 100644 --- a/README.org +++ b/README.org @@ -7,7 +7,7 @@ #+texinfo_dir_desc: Useful commands built on completing-read. Consult provides search and navigation commands based on the Emacs completion -function [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Minibuffer-Completion.html][completing-read]]. Completion allows you to quickly select an item from a +function [[info:elisp#Minibuffer Completion][completing-read]]. Completion allows you to quickly select an item from a list of candidates. Consult offers asynchronous and interactive =consult-grep= and =consult-ripgrep= commands, and the line-based search command =consult-line=. Furthermore Consult provides an advanced buffer switching command =consult-buffer= @@ -18,8 +18,8 @@ presents a flat list of the Imenu with [[#live-previews][live preview]], [[#narr Please take a look at the [[#available-commands][full list of commands]]. Consult is fully compatible with completion systems centered around the standard -Emacs =completing-read= API, notably the default completion system, [[https://github.com/minad/vertico][Vertico]], [[https://github.com/protesilaos/mct][Mct]], -and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html][Icomplete]]. +Emacs =completing-read= API, notably the default completion system, Vertico (~apt install elpa-vertico~), [[https://github.com/protesilaos/mct][Mct]], +and [[info:emacs#Icomplete][Icomplete]]. This package keeps the completion system specifics to a minimum. The ability of the Consult commands to work well with arbitrary completion systems is one of @@ -27,7 +27,7 @@ the main advantages of the package. Consult fits well into existing setups and it helps you to create a full completion environment out of small and independent components. -You can combine the complementary packages [[https://github.com/minad/marginalia/][Marginalia]], [[https://github.com/oantolin/embark/][Embark]] and [[https://github.com/oantolin/orderless][Orderless]] with +You can combine the complementary packages Marginalia (~apt install elpa-marginalia~), Embark (~apt install elpa-embark~) and Orderless (~apt install elpa-orderless~) with Consult. Marginalia enriches the completion display with annotations, e.g., documentation strings or file information. The versatile Embark package provides local actions, comparable to a context menu. These actions operate on the @@ -66,7 +66,7 @@ Many commands implement a little known but convenient Emacs feature called type =M-n= and typically Consult will insert the symbol or thing at point into the input. -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] annotators activated, type =M-x ^consult= to see +*TIP:* If you have Marginalia annotators activated, type =M-x ^consult= to see 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. @@ -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 - either the [[https://github.com/minad/corfu][Corfu]] or the [[https://github.com/company-mode/company-mode][Company]] package. There is a technical limitation of + either the [[https://github.com/minad/corfu][Corfu]] or the Company (~apt install elpa-company~) package. There is a technical limitation of =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 @@ -520,7 +520,7 @@ pressing =C-h=. When pressing =C-h= after some prefix key, the =prefix-help-comm 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 -configuration]]. If [[https://github.com/justbur/emacs-which-key][which-key]] is installed, the narrowing keys are automatically +configuration]]. If which-key (~apt install elpa-which-key~) is installed, the narrowing keys are automatically shown in the which-key window after pressing the =consult-narrow-key=. ** Asynchronous search @@ -715,11 +715,11 @@ since some details may still change. :end: #+cindex: embark -*NOTE*: Install the =embark-consult= package from MELPA, which provides -Consult-specific Embark actions and the Occur buffer export. +*NOTE*: Install the embark-consult package (~apt install elpa-embark-consult~), +which provides Consult-specific Embark actions and the Occur buffer export. Embark is a versatile package which offers context dependent actions, comparable -to a context menu. See the [[https://github.com/oantolin/embark][Embark manual]] for an extensive description of its +to a context menu. See the [[info:embark][Embark manual]] for an extensive description of its capabilities. Actions are commands which can operate on the currently selected candidate (or @@ -739,7 +739,7 @@ the matching lines from =consult-line=, =consult-outline=, =consult-mark= and 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, -if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is installed. These three workflows are symmetric. +if the wgrep (~apt install elpa-wgrep~) package is installed. These three workflows are symmetric. + =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. @@ -750,14 +750,12 @@ if the [[https://github.com/mhayashi1120/Emacs-wgrep][wgrep]] package is install :description: Example configuration and customization variables :end: -Consult can be installed from [[https://elpa.gnu.org/packages/consult.html][ELPA]] or [[https://melpa.org/#/consult][MELPA]] via the Emacs built-in package -manager. Alternatively it can be directly installed from the development -repository via other non-standard package managers. +Consult can be installed via ~apt install elpa-consult~. There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where additional configuration examples can be contributed. -*IMPORTANT:* It is strongly recommended that you enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]] in your +*IMPORTANT:* It is strongly recommended that you enable [[info:elisp#Lexical Binding][lexical binding]] in your configuration. Consult relies on lambdas and lexical closures. For this reason many Consult-related snippets require lexical binding. @@ -773,8 +771,8 @@ modes. Therefore the package is non-intrusive but requires a little setup 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. -The configuration shown here relies on the =use-package= macro, which is a -convenient tool to manage package configurations. +The configuration shown here relies on the =use-package= macro (~apt install +elpa-use-package~), which is a convenient tool to manage package configurations. *NOTE:* There is the [[https://github.com/minad/consult/wiki][Consult wiki]], where you can contribute additional configuration examples. @@ -906,7 +904,7 @@ configuration examples. :end: #+cindex: customization -*TIP:* If you have [[https://github.com/minad/marginalia][Marginalia]] installed, type =M-x customize-variable RET +*TIP:* If you have Marginalia installed, type =M-x customize-variable RET ^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. @@ -1027,10 +1025,12 @@ following techniques: I use and recommend this combination of packages: - consult: This package -- [[https://github.com/minad/vertico][vertico]]: Fast and minimal vertical completion system -- [[https://github.com/minad/marginalia][marginalia]]: Annotations for the completion candidates -- [[https://github.com/oantolin/embark][embark and embark-consult]]: Action commands, which can act on the completion candidates -- [[https://github.com/oantolin/orderless][orderless]]: Completion style which offers flexible candidate filtering +- vertico (~apt install elpa-vertico~): Fast and minimal vertical completion system +- marginalia (~apt install elpa-marginalia~): Annotations for the completion candidates +- embark and embark-consult (~apt install elpa-embark elpa-embark-consult~): + Action commands, which can act on the completion candidates +- orderless (~apt install elpa-orderless~): Completion style which offers + flexible candidate filtering 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 @@ -1058,40 +1058,40 @@ You can integrate Consult with special programs or with other packages in the 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/yadex205/consult-ag][consult-ag]]: Support for the Silver Searcher (~apt install silversearcher-ag~) in the style of =consult-grep=. - [[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 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. - [[https://github.com/rcj/consult-ls-git][consult-ls-git]]: List files from git via Consult. -- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client). -- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the [[https://notmuchmail.org/][Notmuch]] email system using Consult. +- [[https://github.com/gagbo/consult-lsp][consult-lsp]]: Integration with Lsp-mode (LSP client, ~apt install elpa-lsp-mode~). +- [[https://codeberg.org/jao/consult-notmuch][consult-notmuch]]: Access the Notmuch (~apt install notmuch~) email system using Consult. - [[https://github.com/mclear-tools/consult-notes][consult-notes]]: Searching notes with Consult. -- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with [[https://github.com/org-roam/org-roam][Org-roam]]. +- [[https://github.com/jgru/consult-org-roam][consult-org-roam]]: Integration with Org-roam (~apt install elpa-org-roam~). - [[https://github.com/Qkessler/consult-project-extra/][consult-project-extra]]: Additional project.el extras and buffer sources. -- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional [[https://github.com/bbatsov/projectile][Projectile]] integration and buffer sources. -- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the [[https://www.lesbonscomptes.com/recoll/][Recoll]] desktop full-text search using Consult. +- [[https://gitlab.com/OlMon/consult-projectile/][consult-projectile]]: Additional Projectile (~apt install elpa-projectile~) integration and buffer sources. +- [[https://codeberg.org/jao/consult-recoll][consult-recoll]]: Access the Recoll (~apt install elpa-recoll~) desktop full-text search using Consult. - [[https://codeberg.org/jao/espotify][consult-spotify]]: Access the Spotify API and control your local music player. -- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet. +- [[https://github.com/mohkale/consult-yasnippet][consult-yasnippet]]: Integration with Yasnippet (~apt install elpa-yasnippet elpa-yasnippet-snippets~). - [[https://github.com/minad/affe][affe]]: Asynchronous Fuzzy Finder for Emacs based on Consult. 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 [[https://github.com/company-mode/company-mode][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. +- 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=. -- [[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]], [[https://github.com/rainstormstudio/nerd-icons-completion][nerd-icons-completion]]: Icons for the completion UI. * Bug reports @@ -1152,7 +1152,7 @@ Please provide the necessary important information with your bug report: 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]]. -When evaluating Consult-related code snippets you should enable [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html][lexical binding]]. +When evaluating Consult-related code snippets you should enable [[info:elisp#Lexical Binding][lexical binding]]. Consult often relies on lambdas and lexical closures. * Contributions @@ -1176,7 +1176,7 @@ small configuration or command snippets. :description: Contributors and Sources of Inspiration :end: -This package took inspiration from [[https://github.com/abo-abo/swiper#counsel][Counsel]] by Oleh Krehel. Some of the Consult +This package took inspiration from Counsel (~apt install elpa-counsel~) by Oleh Krehel. Some of the Consult commands originated in the Counsel package or the wiki of the Selectrum package. This package exists only thanks to the help of these great contributors and thanks to the feedback of many users. Thank you! -- cgit v1.2.3