config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

commit d77ca84cedbb613c27c8ee31d8207f20b73f1974
parent 069c0598ea2aa00b4c6bf18578bf133455f42b7a
Author: dwrz <dwrz@dwrz.net>
Date:   Sun, 18 Aug 2024 16:21:39 +0000

Update Emacs packages

Diffstat:
Memacs/elpa/archives/gnu/archive-contents | 16++++++++--------
Memacs/elpa/archives/gnu/archive-contents.signed | 4++--
Memacs/elpa/archives/melpa/archive-contents | 142+++++++++++++++++++++++++++++++++++++++----------------------------------------
Memacs/elpa/archives/nongnu/archive-contents | 16++++++++--------
Memacs/elpa/archives/nongnu/archive-contents.signed | 4++--
Demacs/elpa/cape-20240724.918/cape-autoloads.el | 238-------------------------------------------------------------------------------
Demacs/elpa/cape-20240724.918/cape-pkg.el | 15---------------
Demacs/elpa/cape-20240724.918/cape.el | 1300-------------------------------------------------------------------------------
Demacs/elpa/cape-20240724.918/cape.elc | 0
Aemacs/elpa/cape-20240818.1414/cape-autoloads.el | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remacs/elpa/cape-20240724.918/cape-char.el -> emacs/elpa/cape-20240818.1414/cape-char.el | 0
Remacs/elpa/cape-20240724.918/cape-char.elc -> emacs/elpa/cape-20240818.1414/cape-char.elc | 0
Remacs/elpa/cape-20240724.918/cape-keyword.el -> emacs/elpa/cape-20240818.1414/cape-keyword.el | 0
Remacs/elpa/cape-20240724.918/cape-keyword.elc -> emacs/elpa/cape-20240818.1414/cape-keyword.elc | 0
Aemacs/elpa/cape-20240818.1414/cape-pkg.el | 15+++++++++++++++
Aemacs/elpa/cape-20240818.1414/cape.el | 1307+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/cape-20240818.1414/cape.elc | 0
Demacs/elpa/consult-20240811.1858/consult-autoloads.el | 445-------------------------------------------------------------------------------
Demacs/elpa/consult-20240811.1858/consult-pkg.el | 13-------------
Demacs/elpa/consult-20240811.1858/consult.el | 5274-------------------------------------------------------------------------------
Demacs/elpa/consult-20240811.1858/consult.elc | 0
Aemacs/elpa/consult-20240818.1112/consult-autoloads.el | 444+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remacs/elpa/consult-20240811.1858/consult-compile.el -> emacs/elpa/consult-20240818.1112/consult-compile.el | 0
Remacs/elpa/consult-20240811.1858/consult-compile.elc -> emacs/elpa/consult-20240818.1112/consult-compile.elc | 0
Remacs/elpa/consult-20240811.1858/consult-flymake.el -> emacs/elpa/consult-20240818.1112/consult-flymake.el | 0
Remacs/elpa/consult-20240811.1858/consult-flymake.elc -> emacs/elpa/consult-20240818.1112/consult-flymake.elc | 0
Remacs/elpa/consult-20240811.1858/consult-imenu.el -> emacs/elpa/consult-20240818.1112/consult-imenu.el | 0
Remacs/elpa/consult-20240811.1858/consult-imenu.elc -> emacs/elpa/consult-20240818.1112/consult-imenu.elc | 0
Remacs/elpa/consult-20240811.1858/consult-info.el -> emacs/elpa/consult-20240818.1112/consult-info.el | 0
Remacs/elpa/consult-20240811.1858/consult-info.elc -> emacs/elpa/consult-20240818.1112/consult-info.elc | 0
Remacs/elpa/consult-20240811.1858/consult-kmacro.el -> emacs/elpa/consult-20240818.1112/consult-kmacro.el | 0
Remacs/elpa/consult-20240811.1858/consult-kmacro.elc -> emacs/elpa/consult-20240818.1112/consult-kmacro.elc | 0
Remacs/elpa/consult-20240811.1858/consult-org.el -> emacs/elpa/consult-20240818.1112/consult-org.el | 0
Remacs/elpa/consult-20240811.1858/consult-org.elc -> emacs/elpa/consult-20240818.1112/consult-org.elc | 0
Aemacs/elpa/consult-20240818.1112/consult-pkg.el | 13+++++++++++++
Remacs/elpa/consult-20240811.1858/consult-register.el -> emacs/elpa/consult-20240818.1112/consult-register.el | 0
Remacs/elpa/consult-20240811.1858/consult-register.elc -> emacs/elpa/consult-20240818.1112/consult-register.elc | 0
Remacs/elpa/consult-20240811.1858/consult-xref.el -> emacs/elpa/consult-20240818.1112/consult-xref.el | 0
Remacs/elpa/consult-20240811.1858/consult-xref.elc -> emacs/elpa/consult-20240818.1112/consult-xref.elc | 0
Aemacs/elpa/consult-20240818.1112/consult.el | 5273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/consult-20240818.1112/consult.elc | 0
Demacs/elpa/doom-modeline-20240811.1437/doom-modeline-core.el | 1705-------------------------------------------------------------------------------
Demacs/elpa/doom-modeline-20240811.1437/doom-modeline-core.elc | 0
Demacs/elpa/doom-modeline-20240811.1437/doom-modeline-pkg.el | 17-----------------
Demacs/elpa/doom-modeline-20240811.1437/doom-modeline-segments.el | 3257-------------------------------------------------------------------------------
Demacs/elpa/doom-modeline-20240811.1437/doom-modeline-segments.elc | 0
Remacs/elpa/doom-modeline-20240811.1437/doom-modeline-autoloads.el -> emacs/elpa/doom-modeline-20240816.749/doom-modeline-autoloads.el | 0
Aemacs/elpa/doom-modeline-20240816.749/doom-modeline-core.el | 1718+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/doom-modeline-20240816.749/doom-modeline-core.elc | 0
Remacs/elpa/doom-modeline-20240811.1437/doom-modeline-env.el -> emacs/elpa/doom-modeline-20240816.749/doom-modeline-env.el | 0
Remacs/elpa/doom-modeline-20240811.1437/doom-modeline-env.elc -> emacs/elpa/doom-modeline-20240816.749/doom-modeline-env.elc | 0
Aemacs/elpa/doom-modeline-20240816.749/doom-modeline-pkg.el | 17+++++++++++++++++
Aemacs/elpa/doom-modeline-20240816.749/doom-modeline-segments.el | 3261+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/doom-modeline-20240816.749/doom-modeline-segments.elc | 0
Remacs/elpa/doom-modeline-20240811.1437/doom-modeline.el -> emacs/elpa/doom-modeline-20240816.749/doom-modeline.el | 0
Remacs/elpa/doom-modeline-20240811.1437/doom-modeline.elc -> emacs/elpa/doom-modeline-20240816.749/doom-modeline.elc | 0
Demacs/elpa/lsp-mode-20240801.2341/lsp-magik.el | 177-------------------------------------------------------------------------------
Demacs/elpa/lsp-mode-20240801.2341/lsp-magik.elc | 0
Demacs/elpa/lsp-mode-20240801.2341/lsp-mode-pkg.el | 15---------------
Demacs/elpa/lsp-mode-20240801.2341/lsp-rust.el | 1781-------------------------------------------------------------------------------
Demacs/elpa/lsp-mode-20240801.2341/lsp-rust.elc | 0
Demacs/elpa/lsp-mode-20240801.2341/lsp-terraform.elc | 0
Demacs/elpa/lsp-mode-20240801.2341/lsp-yaml.el | 242-------------------------------------------------------------------------------
Demacs/elpa/lsp-mode-20240801.2341/lsp-yaml.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-actionscript.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-actionscript.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-actionscript.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-actionscript.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ada.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ada.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ada.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ada.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-angular.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-angular.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-angular.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-angular.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ansible.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ansible.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ansible.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ansible.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-asm.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-asm.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-asm.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-asm.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-astro.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-astro.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-astro.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-astro.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-autotools.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-autotools.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-autotools.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-autotools.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-awk.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-awk.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-awk.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-awk.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-bash.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-bash.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-bash.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-bash.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-beancount.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-beancount.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-beancount.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-beancount.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-bufls.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-bufls.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-bufls.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-bufls.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-camel.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-camel.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-camel.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-camel.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-clangd.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-clangd.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-clangd.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-clangd.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-clojure.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-clojure.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-clojure.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-clojure.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cmake.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-cmake.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cmake.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-cmake.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cobol.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-cobol.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cobol.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-cobol.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-completion.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-completion.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-completion.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-completion.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-credo.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-credo.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-credo.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-credo.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-crystal.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-crystal.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-crystal.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-crystal.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-csharp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-csharp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-csharp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-csharp.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-css.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-css.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-css.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-css.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cucumber.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-cucumber.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cucumber.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-cucumber.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cypher.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-cypher.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-cypher.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-cypher.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-d.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-d.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-d.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-d.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dhall.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-dhall.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dhall.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-dhall.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-diagnostics.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-diagnostics.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-diagnostics.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-diagnostics.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dired.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-dired.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dired.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-dired.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dockerfile.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-dockerfile.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dockerfile.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-dockerfile.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dot.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-dot.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-dot.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-dot.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-earthly.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-earthly.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-earthly.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-earthly.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-elixir.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-elixir.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-elixir.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-elixir.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-elm.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-elm.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-elm.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-elm.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-emmet.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-emmet.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-emmet.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-emmet.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-erlang.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-erlang.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-erlang.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-erlang.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-eslint.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-eslint.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-eslint.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-eslint.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-fortran.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-fortran.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-fortran.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-fortran.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-fsharp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-fsharp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-fsharp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-fsharp.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-gdscript.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-gdscript.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-gdscript.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-gdscript.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-gleam.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-gleam.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-gleam.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-gleam.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-glsl.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-glsl.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-glsl.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-glsl.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-go.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-go.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-go.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-go.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-golangci-lint.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-golangci-lint.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-golangci-lint.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-golangci-lint.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-graphql.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-graphql.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-graphql.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-graphql.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-groovy.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-groovy.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-groovy.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-groovy.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-hack.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-hack.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-hack.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-hack.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-haxe.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-haxe.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-haxe.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-haxe.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-headerline.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-headerline.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-headerline.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-headerline.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-html.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-html.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-html.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-html.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-hy.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-hy.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-hy.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-hy.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-icons.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-icons.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-icons.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-icons.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ido.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ido.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ido.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ido.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-idris.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-idris.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-idris.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-idris.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-iedit.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-iedit.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-iedit.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-iedit.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-javascript.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-javascript.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-javascript.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-javascript.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-jq.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-jq.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-jq.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-jq.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-json.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-json.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-json.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-json.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-jsonnet.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-jsonnet.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-jsonnet.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-jsonnet.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-kotlin.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-kotlin.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-kotlin.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-kotlin.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-lens.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-lens.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-lens.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-lens.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-lisp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-lisp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-lisp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-lisp.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-lua.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-lua.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-lua.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-lua.elc | 0
Aemacs/elpa/lsp-mode-20240817.1400/lsp-magik.el | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/lsp-mode-20240817.1400/lsp-magik.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-markdown.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-markdown.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-markdown.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-markdown.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-marksman.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-marksman.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-marksman.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-marksman.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mdx.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-mdx.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mdx.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-mdx.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-meson.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-meson.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-meson.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-meson.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mint.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-mint.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mint.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-mint.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mode-autoloads.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-mode-autoloads.el | 0
Aemacs/elpa/lsp-mode-20240817.1400/lsp-mode-pkg.el | 15+++++++++++++++
Remacs/elpa/lsp-mode-20240801.2341/lsp-mode.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-mode.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mode.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-mode.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-modeline.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-modeline.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-modeline.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-modeline.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mojo.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-mojo.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-mojo.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-mojo.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-move.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-move.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-move.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-move.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nginx.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-nginx.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nginx.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-nginx.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nim.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-nim.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nim.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-nim.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nix.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-nix.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nix.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-nix.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nushell.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-nushell.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-nushell.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-nushell.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ocaml.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ocaml.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ocaml.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ocaml.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-openscad.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-openscad.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-openscad.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-openscad.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-perl.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-perl.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-perl.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-perl.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-perlnavigator.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-perlnavigator.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-perlnavigator.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-perlnavigator.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-php.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-php.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-php.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-php.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pls.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-pls.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pls.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-pls.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-prolog.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-prolog.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-prolog.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-prolog.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-protocol.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-protocol.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-protocol.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-protocol.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-purescript.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-purescript.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-purescript.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-purescript.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pwsh.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-pwsh.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pwsh.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-pwsh.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pyls.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-pyls.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pyls.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-pyls.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pylsp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-pylsp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-pylsp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-pylsp.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-qml.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-qml.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-qml.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-qml.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-r.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-r.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-r.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-r.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-racket.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-racket.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-racket.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-racket.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-remark.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-remark.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-remark.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-remark.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-rf.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-rf.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-rf.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-rf.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-roslyn.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-roslyn.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-roslyn.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-roslyn.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-rpm-spec.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-rpm-spec.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-rpm-spec.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-rpm-spec.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-rubocop.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-rubocop.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-rubocop.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-rubocop.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ruby-lsp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-lsp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ruby-lsp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-lsp.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ruby-syntax-tree.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-syntax-tree.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ruby-syntax-tree.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-syntax-tree.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ruff-lsp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ruff-lsp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ruff-lsp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ruff-lsp.elc | 0
Aemacs/elpa/lsp-mode-20240817.1400/lsp-rust.el | 1791+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/lsp-mode-20240817.1400/lsp-rust.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-semantic-tokens.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-semantic-tokens.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-semantic-tokens.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-semantic-tokens.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-semgrep.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-semgrep.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-semgrep.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-semgrep.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sml.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-sml.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sml.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-sml.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-solargraph.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-solargraph.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-solargraph.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-solargraph.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-solidity.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-solidity.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-solidity.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-solidity.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sorbet.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-sorbet.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sorbet.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-sorbet.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sql.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-sql.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sql.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-sql.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sqls.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-sqls.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-sqls.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-sqls.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-steep.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-steep.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-steep.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-steep.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-svelte.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-svelte.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-svelte.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-svelte.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-terraform.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-terraform.el | 0
Aemacs/elpa/lsp-mode-20240817.1400/lsp-terraform.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-tex.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-tex.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-tex.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-tex.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-tilt.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-tilt.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-tilt.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-tilt.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-toml.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-toml.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-toml.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-toml.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-trunk.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-trunk.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-trunk.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-trunk.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ttcn3.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-ttcn3.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-ttcn3.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-ttcn3.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-typeprof.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-typeprof.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-typeprof.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-typeprof.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-v.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-v.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-v.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-v.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vala.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-vala.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vala.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-vala.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-verilog.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-verilog.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-verilog.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-verilog.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vetur.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-vetur.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vetur.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-vetur.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vhdl.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-vhdl.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vhdl.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-vhdl.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vimscript.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-vimscript.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-vimscript.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-vimscript.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-volar.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-volar.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-volar.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-volar.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-wgsl.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-wgsl.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-wgsl.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-wgsl.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-xml.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-xml.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-xml.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-xml.elc | 0
Aemacs/elpa/lsp-mode-20240817.1400/lsp-yaml.el | 247+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/lsp-mode-20240817.1400/lsp-yaml.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-yang.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-yang.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-yang.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-yang.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-zig.el -> emacs/elpa/lsp-mode-20240817.1400/lsp-zig.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp-zig.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp-zig.elc | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp.el -> emacs/elpa/lsp-mode-20240817.1400/lsp.el | 0
Remacs/elpa/lsp-mode-20240801.2341/lsp.elc -> emacs/elpa/lsp-mode-20240817.1400/lsp.elc | 0
Demacs/elpa/magit-20240811.1419/magit-diff.elc | 0
Demacs/elpa/magit-20240811.1419/magit-log.elc | 0
Demacs/elpa/magit-20240811.1419/magit-pkg.el | 20--------------------
Demacs/elpa/magit-20240811.1419/magit.info | 11592-------------------------------------------------------------------------------
Remacs/elpa/magit-20240811.1419/AUTHORS.md -> emacs/elpa/magit-20240818.1037/AUTHORS.md | 0
Remacs/elpa/magit-20240811.1419/LICENSE -> emacs/elpa/magit-20240818.1037/LICENSE | 0
Remacs/elpa/magit-20240811.1419/dir -> emacs/elpa/magit-20240818.1037/dir | 0
Remacs/elpa/magit-20240811.1419/git-rebase.el -> emacs/elpa/magit-20240818.1037/git-rebase.el | 0
Remacs/elpa/magit-20240811.1419/git-rebase.elc -> emacs/elpa/magit-20240818.1037/git-rebase.elc | 0
Remacs/elpa/magit-20240811.1419/magit-apply.el -> emacs/elpa/magit-20240818.1037/magit-apply.el | 0
Remacs/elpa/magit-20240811.1419/magit-apply.elc -> emacs/elpa/magit-20240818.1037/magit-apply.elc | 0
Remacs/elpa/magit-20240811.1419/magit-autoloads.el -> emacs/elpa/magit-20240818.1037/magit-autoloads.el | 0
Remacs/elpa/magit-20240811.1419/magit-autorevert.el -> emacs/elpa/magit-20240818.1037/magit-autorevert.el | 0
Remacs/elpa/magit-20240811.1419/magit-autorevert.elc -> emacs/elpa/magit-20240818.1037/magit-autorevert.elc | 0
Remacs/elpa/magit-20240811.1419/magit-base.el -> emacs/elpa/magit-20240818.1037/magit-base.el | 0
Remacs/elpa/magit-20240811.1419/magit-base.elc -> emacs/elpa/magit-20240818.1037/magit-base.elc | 0
Remacs/elpa/magit-20240811.1419/magit-bisect.el -> emacs/elpa/magit-20240818.1037/magit-bisect.el | 0
Remacs/elpa/magit-20240811.1419/magit-bisect.elc -> emacs/elpa/magit-20240818.1037/magit-bisect.elc | 0
Remacs/elpa/magit-20240811.1419/magit-blame.el -> emacs/elpa/magit-20240818.1037/magit-blame.el | 0
Remacs/elpa/magit-20240811.1419/magit-blame.elc -> emacs/elpa/magit-20240818.1037/magit-blame.elc | 0
Remacs/elpa/magit-20240811.1419/magit-bookmark.el -> emacs/elpa/magit-20240818.1037/magit-bookmark.el | 0
Remacs/elpa/magit-20240811.1419/magit-bookmark.elc -> emacs/elpa/magit-20240818.1037/magit-bookmark.elc | 0
Remacs/elpa/magit-20240811.1419/magit-branch.el -> emacs/elpa/magit-20240818.1037/magit-branch.el | 0
Remacs/elpa/magit-20240811.1419/magit-branch.elc -> emacs/elpa/magit-20240818.1037/magit-branch.elc | 0
Remacs/elpa/magit-20240811.1419/magit-bundle.el -> emacs/elpa/magit-20240818.1037/magit-bundle.el | 0
Remacs/elpa/magit-20240811.1419/magit-bundle.elc -> emacs/elpa/magit-20240818.1037/magit-bundle.elc | 0
Remacs/elpa/magit-20240811.1419/magit-clone.el -> emacs/elpa/magit-20240818.1037/magit-clone.el | 0
Remacs/elpa/magit-20240811.1419/magit-clone.elc -> emacs/elpa/magit-20240818.1037/magit-clone.elc | 0
Remacs/elpa/magit-20240811.1419/magit-commit.el -> emacs/elpa/magit-20240818.1037/magit-commit.el | 0
Remacs/elpa/magit-20240811.1419/magit-commit.elc -> emacs/elpa/magit-20240818.1037/magit-commit.elc | 0
Remacs/elpa/magit-20240811.1419/magit-core.el -> emacs/elpa/magit-20240818.1037/magit-core.el | 0
Remacs/elpa/magit-20240811.1419/magit-core.elc -> emacs/elpa/magit-20240818.1037/magit-core.elc | 0
Remacs/elpa/magit-20240811.1419/magit-diff.el -> emacs/elpa/magit-20240818.1037/magit-diff.el | 0
Aemacs/elpa/magit-20240818.1037/magit-diff.elc | 0
Remacs/elpa/magit-20240811.1419/magit-ediff.el -> emacs/elpa/magit-20240818.1037/magit-ediff.el | 0
Remacs/elpa/magit-20240811.1419/magit-ediff.elc -> emacs/elpa/magit-20240818.1037/magit-ediff.elc | 0
Remacs/elpa/magit-20240811.1419/magit-extras.el -> emacs/elpa/magit-20240818.1037/magit-extras.el | 0
Remacs/elpa/magit-20240811.1419/magit-extras.elc -> emacs/elpa/magit-20240818.1037/magit-extras.elc | 0
Remacs/elpa/magit-20240811.1419/magit-fetch.el -> emacs/elpa/magit-20240818.1037/magit-fetch.el | 0
Remacs/elpa/magit-20240811.1419/magit-fetch.elc -> emacs/elpa/magit-20240818.1037/magit-fetch.elc | 0
Remacs/elpa/magit-20240811.1419/magit-files.el -> emacs/elpa/magit-20240818.1037/magit-files.el | 0
Remacs/elpa/magit-20240811.1419/magit-files.elc -> emacs/elpa/magit-20240818.1037/magit-files.elc | 0
Remacs/elpa/magit-20240811.1419/magit-git.el -> emacs/elpa/magit-20240818.1037/magit-git.el | 0
Remacs/elpa/magit-20240811.1419/magit-git.elc -> emacs/elpa/magit-20240818.1037/magit-git.elc | 0
Remacs/elpa/magit-20240811.1419/magit-gitignore.el -> emacs/elpa/magit-20240818.1037/magit-gitignore.el | 0
Remacs/elpa/magit-20240811.1419/magit-gitignore.elc -> emacs/elpa/magit-20240818.1037/magit-gitignore.elc | 0
Remacs/elpa/magit-20240811.1419/magit-log.el -> emacs/elpa/magit-20240818.1037/magit-log.el | 0
Aemacs/elpa/magit-20240818.1037/magit-log.elc | 0
Remacs/elpa/magit-20240811.1419/magit-margin.el -> emacs/elpa/magit-20240818.1037/magit-margin.el | 0
Remacs/elpa/magit-20240811.1419/magit-margin.elc -> emacs/elpa/magit-20240818.1037/magit-margin.elc | 0
Remacs/elpa/magit-20240811.1419/magit-merge.el -> emacs/elpa/magit-20240818.1037/magit-merge.el | 0
Remacs/elpa/magit-20240811.1419/magit-merge.elc -> emacs/elpa/magit-20240818.1037/magit-merge.elc | 0
Remacs/elpa/magit-20240811.1419/magit-mode.el -> emacs/elpa/magit-20240818.1037/magit-mode.el | 0
Remacs/elpa/magit-20240811.1419/magit-mode.elc -> emacs/elpa/magit-20240818.1037/magit-mode.elc | 0
Remacs/elpa/magit-20240811.1419/magit-notes.el -> emacs/elpa/magit-20240818.1037/magit-notes.el | 0
Remacs/elpa/magit-20240811.1419/magit-notes.elc -> emacs/elpa/magit-20240818.1037/magit-notes.elc | 0
Remacs/elpa/magit-20240811.1419/magit-patch.el -> emacs/elpa/magit-20240818.1037/magit-patch.el | 0
Remacs/elpa/magit-20240811.1419/magit-patch.elc -> emacs/elpa/magit-20240818.1037/magit-patch.elc | 0
Aemacs/elpa/magit-20240818.1037/magit-pkg.el | 20++++++++++++++++++++
Remacs/elpa/magit-20240811.1419/magit-process.el -> emacs/elpa/magit-20240818.1037/magit-process.el | 0
Remacs/elpa/magit-20240811.1419/magit-process.elc -> emacs/elpa/magit-20240818.1037/magit-process.elc | 0
Remacs/elpa/magit-20240811.1419/magit-pull.el -> emacs/elpa/magit-20240818.1037/magit-pull.el | 0
Remacs/elpa/magit-20240811.1419/magit-pull.elc -> emacs/elpa/magit-20240818.1037/magit-pull.elc | 0
Remacs/elpa/magit-20240811.1419/magit-push.el -> emacs/elpa/magit-20240818.1037/magit-push.el | 0
Remacs/elpa/magit-20240811.1419/magit-push.elc -> emacs/elpa/magit-20240818.1037/magit-push.elc | 0
Remacs/elpa/magit-20240811.1419/magit-reflog.el -> emacs/elpa/magit-20240818.1037/magit-reflog.el | 0
Remacs/elpa/magit-20240811.1419/magit-reflog.elc -> emacs/elpa/magit-20240818.1037/magit-reflog.elc | 0
Remacs/elpa/magit-20240811.1419/magit-refs.el -> emacs/elpa/magit-20240818.1037/magit-refs.el | 0
Remacs/elpa/magit-20240811.1419/magit-refs.elc -> emacs/elpa/magit-20240818.1037/magit-refs.elc | 0
Remacs/elpa/magit-20240811.1419/magit-remote.el -> emacs/elpa/magit-20240818.1037/magit-remote.el | 0
Remacs/elpa/magit-20240811.1419/magit-remote.elc -> emacs/elpa/magit-20240818.1037/magit-remote.elc | 0
Remacs/elpa/magit-20240811.1419/magit-repos.el -> emacs/elpa/magit-20240818.1037/magit-repos.el | 0
Remacs/elpa/magit-20240811.1419/magit-repos.elc -> emacs/elpa/magit-20240818.1037/magit-repos.elc | 0
Remacs/elpa/magit-20240811.1419/magit-reset.el -> emacs/elpa/magit-20240818.1037/magit-reset.el | 0
Remacs/elpa/magit-20240811.1419/magit-reset.elc -> emacs/elpa/magit-20240818.1037/magit-reset.elc | 0
Remacs/elpa/magit-20240811.1419/magit-sequence.el -> emacs/elpa/magit-20240818.1037/magit-sequence.el | 0
Remacs/elpa/magit-20240811.1419/magit-sequence.elc -> emacs/elpa/magit-20240818.1037/magit-sequence.elc | 0
Remacs/elpa/magit-20240811.1419/magit-sparse-checkout.el -> emacs/elpa/magit-20240818.1037/magit-sparse-checkout.el | 0
Remacs/elpa/magit-20240811.1419/magit-sparse-checkout.elc -> emacs/elpa/magit-20240818.1037/magit-sparse-checkout.elc | 0
Remacs/elpa/magit-20240811.1419/magit-stash.el -> emacs/elpa/magit-20240818.1037/magit-stash.el | 0
Remacs/elpa/magit-20240811.1419/magit-stash.elc -> emacs/elpa/magit-20240818.1037/magit-stash.elc | 0
Remacs/elpa/magit-20240811.1419/magit-status.el -> emacs/elpa/magit-20240818.1037/magit-status.el | 0
Remacs/elpa/magit-20240811.1419/magit-status.elc -> emacs/elpa/magit-20240818.1037/magit-status.elc | 0
Remacs/elpa/magit-20240811.1419/magit-submodule.el -> emacs/elpa/magit-20240818.1037/magit-submodule.el | 0
Remacs/elpa/magit-20240811.1419/magit-submodule.elc -> emacs/elpa/magit-20240818.1037/magit-submodule.elc | 0
Remacs/elpa/magit-20240811.1419/magit-subtree.el -> emacs/elpa/magit-20240818.1037/magit-subtree.el | 0
Remacs/elpa/magit-20240811.1419/magit-subtree.elc -> emacs/elpa/magit-20240818.1037/magit-subtree.elc | 0
Remacs/elpa/magit-20240811.1419/magit-tag.el -> emacs/elpa/magit-20240818.1037/magit-tag.el | 0
Remacs/elpa/magit-20240811.1419/magit-tag.elc -> emacs/elpa/magit-20240818.1037/magit-tag.elc | 0
Remacs/elpa/magit-20240811.1419/magit-transient.el -> emacs/elpa/magit-20240818.1037/magit-transient.el | 0
Remacs/elpa/magit-20240811.1419/magit-transient.elc -> emacs/elpa/magit-20240818.1037/magit-transient.elc | 0
Remacs/elpa/magit-20240811.1419/magit-wip.el -> emacs/elpa/magit-20240818.1037/magit-wip.el | 0
Remacs/elpa/magit-20240811.1419/magit-wip.elc -> emacs/elpa/magit-20240818.1037/magit-wip.elc | 0
Remacs/elpa/magit-20240811.1419/magit-worktree.el -> emacs/elpa/magit-20240818.1037/magit-worktree.el | 0
Remacs/elpa/magit-20240811.1419/magit-worktree.elc -> emacs/elpa/magit-20240818.1037/magit-worktree.elc | 0
Remacs/elpa/magit-20240811.1419/magit.el -> emacs/elpa/magit-20240818.1037/magit.el | 0
Remacs/elpa/magit-20240811.1419/magit.elc -> emacs/elpa/magit-20240818.1037/magit.elc | 0
Aemacs/elpa/magit-20240818.1037/magit.info | 11595+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Demacs/elpa/magit-section-20240811.1419/magit-section-pkg.el | 14--------------
Demacs/elpa/magit-section-20240811.1419/magit-section.info | 317-------------------------------------------------------------------------------
Remacs/elpa/magit-section-20240811.1419/dir -> emacs/elpa/magit-section-20240818.1037/dir | 0
Remacs/elpa/magit-section-20240811.1419/magit-section-autoloads.el -> emacs/elpa/magit-section-20240818.1037/magit-section-autoloads.el | 0
Aemacs/elpa/magit-section-20240818.1037/magit-section-pkg.el | 14++++++++++++++
Remacs/elpa/magit-section-20240811.1419/magit-section.el -> emacs/elpa/magit-section-20240818.1037/magit-section.el | 0
Remacs/elpa/magit-section-20240811.1419/magit-section.elc -> emacs/elpa/magit-section-20240818.1037/magit-section.elc | 0
Aemacs/elpa/magit-section-20240818.1037/magit-section.info | 317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Demacs/elpa/nerd-icons-20240808.625/nerd-icons-pkg.el | 16----------------
Demacs/elpa/nerd-icons-20240808.625/nerd-icons.el | 1316-------------------------------------------------------------------------------
Demacs/elpa/nerd-icons-20240808.625/nerd-icons.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-codicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-codicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-codicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-codicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-devicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-devicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-devicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-devicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-faicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-faicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-faicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-faicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-flicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-flicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-flicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-flicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-ipsicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-ipsicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-ipsicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-ipsicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-mdicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-mdicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-mdicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-mdicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-octicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-octicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-octicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-octicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-pomicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-pomicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-pomicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-pomicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-powerline.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-powerline.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-powerline.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-powerline.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-sucicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-sucicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-sucicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-sucicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-wicon.el -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-wicon.el | 0
Remacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-wicon.elc -> emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-wicon.elc | 0
Remacs/elpa/nerd-icons-20240808.625/nerd-icons-autoloads.el -> emacs/elpa/nerd-icons-20240816.1555/nerd-icons-autoloads.el | 0
Remacs/elpa/nerd-icons-20240808.625/nerd-icons-data.el -> emacs/elpa/nerd-icons-20240816.1555/nerd-icons-data.el | 0
Remacs/elpa/nerd-icons-20240808.625/nerd-icons-data.elc -> emacs/elpa/nerd-icons-20240816.1555/nerd-icons-data.elc | 0
Remacs/elpa/nerd-icons-20240808.625/nerd-icons-faces.el -> emacs/elpa/nerd-icons-20240816.1555/nerd-icons-faces.el | 0
Remacs/elpa/nerd-icons-20240808.625/nerd-icons-faces.elc -> emacs/elpa/nerd-icons-20240816.1555/nerd-icons-faces.elc | 0
Aemacs/elpa/nerd-icons-20240816.1555/nerd-icons-pkg.el | 16++++++++++++++++
Aemacs/elpa/nerd-icons-20240816.1555/nerd-icons.el | 1320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aemacs/elpa/nerd-icons-20240816.1555/nerd-icons.elc | 0
Demacs/elpa/notmuch-20240809.1318/notmuch-autoloads.el | 234-------------------------------------------------------------------------------
Demacs/elpa/notmuch-20240809.1318/notmuch-hello.elc | 0
Demacs/elpa/notmuch-20240809.1318/notmuch-maildir-fcc.elc | 0
Demacs/elpa/notmuch-20240809.1318/notmuch-message.elc | 0
Demacs/elpa/notmuch-20240809.1318/notmuch-mua.el | 679-------------------------------------------------------------------------------
Demacs/elpa/notmuch-20240809.1318/notmuch-pkg.el | 4----
Demacs/elpa/notmuch-20240809.1318/notmuch-tree.elc | 0
Remacs/elpa/notmuch-20240809.1318/coolj.el -> emacs/elpa/notmuch-20240816.2039/coolj.el | 0
Remacs/elpa/notmuch-20240809.1318/coolj.elc -> emacs/elpa/notmuch-20240816.2039/coolj.elc | 0
Remacs/elpa/notmuch-20240809.1318/make-deps.el -> emacs/elpa/notmuch-20240816.2039/make-deps.el | 0
Remacs/elpa/notmuch-20240809.1318/make-deps.elc -> emacs/elpa/notmuch-20240816.2039/make-deps.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-address.el -> emacs/elpa/notmuch-20240816.2039/notmuch-address.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-address.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-address.elc | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-autoloads.el | 254+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remacs/elpa/notmuch-20240809.1318/notmuch-company.el -> emacs/elpa/notmuch-20240816.2039/notmuch-company.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-company.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-company.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-compat.el -> emacs/elpa/notmuch-20240816.2039/notmuch-compat.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-compat.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-compat.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-crypto.el -> emacs/elpa/notmuch-20240816.2039/notmuch-crypto.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-crypto.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-crypto.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-draft.el -> emacs/elpa/notmuch-20240816.2039/notmuch-draft.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-draft.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-draft.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-hello.el -> emacs/elpa/notmuch-20240816.2039/notmuch-hello.el | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-hello.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-jump.el -> emacs/elpa/notmuch-20240816.2039/notmuch-jump.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-jump.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-jump.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-lib.el -> emacs/elpa/notmuch-20240816.2039/notmuch-lib.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-lib.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-lib.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-logo.svg -> emacs/elpa/notmuch-20240816.2039/notmuch-logo.svg | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-maildir-fcc.el -> emacs/elpa/notmuch-20240816.2039/notmuch-maildir-fcc.el | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-maildir-fcc.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-message.el -> emacs/elpa/notmuch-20240816.2039/notmuch-message.el | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-message.elc | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-mua.el | 679+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remacs/elpa/notmuch-20240809.1318/notmuch-mua.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-mua.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-parser.el -> emacs/elpa/notmuch-20240816.2039/notmuch-parser.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-parser.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-parser.elc | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-pkg.el | 4++++
Remacs/elpa/notmuch-20240809.1318/notmuch-print.el -> emacs/elpa/notmuch-20240816.2039/notmuch-print.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-print.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-print.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-query.el -> emacs/elpa/notmuch-20240816.2039/notmuch-query.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-query.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-query.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-show.el -> emacs/elpa/notmuch-20240816.2039/notmuch-show.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-show.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-show.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-tag.el -> emacs/elpa/notmuch-20240816.2039/notmuch-tag.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-tag.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-tag.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-tree.el -> emacs/elpa/notmuch-20240816.2039/notmuch-tree.el | 0
Aemacs/elpa/notmuch-20240816.2039/notmuch-tree.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-wash.el -> emacs/elpa/notmuch-20240816.2039/notmuch-wash.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch-wash.elc -> emacs/elpa/notmuch-20240816.2039/notmuch-wash.elc | 0
Remacs/elpa/notmuch-20240809.1318/notmuch.el -> emacs/elpa/notmuch-20240816.2039/notmuch.el | 0
Remacs/elpa/notmuch-20240809.1318/notmuch.elc -> emacs/elpa/notmuch-20240816.2039/notmuch.elc | 0
Remacs/elpa/notmuch-20240809.1318/rstdoc.el -> emacs/elpa/notmuch-20240816.2039/rstdoc.el | 0
Remacs/elpa/notmuch-20240809.1318/rstdoc.elc -> emacs/elpa/notmuch-20240816.2039/rstdoc.elc | 0
Demacs/elpa/transient-20240805.1231/transient-pkg.el | 16----------------
Demacs/elpa/transient-20240805.1231/transient.el | 4586-------------------------------------------------------------------------------
Demacs/elpa/transient-20240805.1231/transient.info | 3318-------------------------------------------------------------------------------
Remacs/elpa/transient-20240805.1231/dir -> emacs/elpa/transient-20240817.1959/dir | 0
Remacs/elpa/transient-20240805.1231/gpl.info -> emacs/elpa/transient-20240817.1959/gpl.info | 0
Remacs/elpa/transient-20240805.1231/transient-autoloads.el -> emacs/elpa/transient-20240817.1959/transient-autoloads.el | 0
Aemacs/elpa/transient-20240817.1959/transient-pkg.el | 16++++++++++++++++
Aemacs/elpa/transient-20240817.1959/transient.el | 4585+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remacs/elpa/transient-20240805.1231/transient.elc -> emacs/elpa/transient-20240817.1959/transient.elc | 0
Aemacs/elpa/transient-20240817.1959/transient.info | 3318+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Demacs/elpa/with-editor-20240806.1454/with-editor-pkg.el | 15---------------
Demacs/elpa/with-editor-20240806.1454/with-editor.info | 384-------------------------------------------------------------------------------
Remacs/elpa/with-editor-20240806.1454/dir -> emacs/elpa/with-editor-20240817.1959/dir | 0
Remacs/elpa/with-editor-20240806.1454/with-editor-autoloads.el -> emacs/elpa/with-editor-20240817.1959/with-editor-autoloads.el | 0
Aemacs/elpa/with-editor-20240817.1959/with-editor-pkg.el | 15+++++++++++++++
Remacs/elpa/with-editor-20240806.1454/with-editor.el -> emacs/elpa/with-editor-20240817.1959/with-editor.el | 0
Remacs/elpa/with-editor-20240806.1454/with-editor.elc -> emacs/elpa/with-editor-20240817.1959/with-editor.elc | 0
Aemacs/elpa/with-editor-20240817.1959/with-editor.info | 384+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
535 files changed, 37141 insertions(+), 37082 deletions(-)

diff --git a/emacs/elpa/archives/gnu/archive-contents b/emacs/elpa/archives/gnu/archive-contents @@ -2367,7 +2367,7 @@ (:url . "https://elpa.gnu.org/packages/kmb.html") (:commit . "4fee1c87e7e286d7ecd759fb74aa7a112bb51e3a"))]) (kubed . - [(0 3 1) + [(0 3 2) ((emacs (29 1))) "Kubernetes, Emacs, done!" tar @@ -2376,7 +2376,7 @@ (:maintainer "Eshel Yaron" . "~eshel/kubed-devel@lists.sr.ht") (:authors ("Eshel Yaron" . "me@eshelyaron.com")) - (:commit . "914b7df07d686c9d51329a1365930f3ced4c6f1e"))]) + (:commit . "0863c58f1a8aedbc935fa6bb18bbdf3f7c1e939c"))]) (landmark . [(1 0) nil "Neural-network robot that learns landmarks" tar @@ -3281,7 +3281,7 @@ (:url . "https://elpa.gnu.org/packages/pinentry.html") (:commit . "ef0d62bba29dfab07624d030032ec0f67d34e865"))]) (plz . - [(0 9) + [(0 9 1) ((emacs (27 1))) "HTTP library" tar @@ -3290,7 +3290,7 @@ (:maintainer "Adam Porter" . "adam@alphapapa.net") (:authors ("Adam Porter" . "adam@alphapapa.net")) - (:commit . "399ad3e1aafa7b86c1ce0cfab8bcf2e09cb0e956"))]) + (:commit . "c579f039ffdb52ff61775ff25510a9c26e25d0c5"))]) (plz-event-source . [(0 1 1) ((emacs @@ -4215,7 +4215,7 @@ ("Onnie Lynn Winebarger" . "owinebar@gmail.com")) (:commit . "c254ec9f646ef5527eb1f834a90e5897caa977cf"))]) (taxy . - [(0 10 1) + [(0 10 2) ((emacs (26 3))) "Programmable taxonomical grouping for arbitrary objects" tar @@ -4224,9 +4224,9 @@ (:maintainer "Adam Porter" . "adam@alphapapa.net") (:authors ("Adam Porter" . "adam@alphapapa.net")) - (:commit . "b27fa67ecf3f8954ce0d5c2747d1de4dc94ff09f"))]) + (:commit . "3099ae5cb27a34961e06a3af67555919c62c12d7"))]) (taxy-magit-section . - [(0 13) + [(0 14) ((emacs (26 3)) (magit-section @@ -4239,7 +4239,7 @@ (:maintainer "Adam Porter" . "adam@alphapapa.net") (:authors ("Adam Porter" . "adam@alphapapa.net")) - (:commit . "9d79793edaa98a8a06674723ad5a53ebc4fc237c"))]) + (:commit . "c4d8c1c5393807c41a5b20030a6347beb088b47e"))]) (temp-buffer-browse . [(1 5) ((emacs diff --git a/emacs/elpa/archives/gnu/archive-contents.signed b/emacs/elpa/archives/gnu/archive-contents.signed @@ -1 +1 @@ -Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2024-08-14T09:05:01+0000 using EDDSA -\ No newline at end of file +Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2024-08-18T09:05:02+0000 using EDDSA +\ No newline at end of file diff --git a/emacs/elpa/archives/melpa/archive-contents b/emacs/elpa/archives/melpa/archive-contents @@ -192,7 +192,7 @@ (async-backup . [(20230412 1534) ((emacs (24 4))) "Backup on each save without freezing Emacs" tar ((:commit . "d07a7bd4a5c3332a8a585680d67925385c595927") (:authors ("contrapunctus" . "xmpp:contrapunctus@jabjab.de")) (:maintainers ("contrapunctus" . "xmpp:contrapunctus@jabjab.de")) (:maintainer "contrapunctus" . "xmpp:contrapunctus@jabjab.de") (:keywords "files") (:url . "https://codeberg.org/contrapunctus/async-backup"))]) (async-job-queue . [(20230427 2122) ((async (1 4)) (emacs (25 1)) (queue (0 2))) "Dispatch queue of async jobs to a fixed number of slots" tar ((:commit . "eeafcce7f960305666b2a51aec55cc6333f6af1b") (:keywords "extensions" "lisp") (:url . "https://github.com/owinebar/emacs-async-job-queue"))]) (async-status . [(20230821 204) ((emacs (28 1)) (svg-lib (0 2 7)) (posframe (1 4 2))) "A package for indicator support" tar ((:commit . "d2f5becc9850c26aa71fb581f9fc389eac740f52") (:authors ("Jason Kim" . "sukbeom.kim@gmail.com")) (:maintainers ("Jason Kim" . "sukbeom.kim@gmail.com")) (:maintainer "Jason Kim" . "sukbeom.kim@gmail.com") (:keywords "tools" "async") (:url . "https://github.com/seokbeomkim/async-status"))]) - (asyncloop . [(20240407 1153) ((emacs (28))) "Non-blocking series of functions" tar ((:commit . "46e38388870b238221a4d96017874309aada7660") (:authors ("Martin Edström" . "meedstrom91@gmail.com")) (:maintainers ("Martin Edström" . "meedstrom91@gmail.com")) (:maintainer "Martin Edström" . "meedstrom91@gmail.com") (:keywords "tools") (:url . "https://github.com/meedstrom/asyncloop"))]) + (asyncloop . [(20240818 1247) ((emacs (28))) "Non-blocking series of functions" tar ((:commit . "7d60950d160098a879293e049b9863bc955f8666") (:authors ("Martin Edström" . "meedstrom91@gmail.com")) (:maintainers ("Martin Edström" . "meedstrom91@gmail.com")) (:maintainer "Martin Edström" . "meedstrom91@gmail.com") (:keywords "tools") (:url . "https://github.com/meedstrom/asyncloop"))]) (atcoder-tools . [(20200109 1236) ((emacs (26)) (f (0 20)) (s (1 12))) "An atcoder-tools client" tar ((:commit . "cfe61ed18ea9b3b1bfb6f9e7d80a47599680cd1f") (:authors ("Seong Yong-ju" . "sei40kr@gmail.com")) (:maintainers ("Seong Yong-ju" . "sei40kr@gmail.com")) (:maintainer "Seong Yong-ju" . "sei40kr@gmail.com") (:keywords "extensions" "tools") (:url . "https://github.com/sei40kr/atcoder-tools"))]) (atl-long-lines . [(20240101 929) ((emacs (24 3))) "Turn off truncate-lines when the line is long" tar ((:commit . "82cdd4edefba2d5b1d491bf3fcc487385819d713") (:authors ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainers ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainer "Jen-Chieh" . "jcs090218@gmail.com") (:keywords "convenience" "truncate" "lines" "auto" "long") (:url . "https://github.com/jcs-elpa/atl-long-lines"))]) (atl-markup . [(20240101 933) ((emacs (24 3))) "Automatically truncate lines for markup languages" tar ((:commit . "b616343ffe17060d521b214b8e90f5da1e880934") (:authors ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainers ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainer "Jen-Chieh" . "jcs090218@gmail.com") (:keywords "convenience" "automatic" "truncate" "visual" "lines") (:url . "https://github.com/jcs-elpa/atl-markup"))]) @@ -387,7 +387,7 @@ (bookmark-view . [(20240102 334) ((emacs (27 1))) "Bookmark views" tar ((:commit . "2d16b2f88a106e57c58ad2af1f7166a847996512") (:url . "https://github.com/minad/bookmark-view"))]) (bool-flip . [(20161215 1539) ((emacs (24 3))) "flip the boolean under the point" tar ((:commit . "0f7cc9b387429239fb929896511727d4e49a795b") (:authors ("Michael Brandt" . "michaelbrandt5@gmail.com")) (:maintainers ("Michael Brandt" . "michaelbrandt5@gmail.com")) (:maintainer "Michael Brandt" . "michaelbrandt5@gmail.com") (:keywords "boolean" "convenience" "usability") (:url . "http://github.com/michaeljb/bool-flip/"))]) (boon . [(20240628 703) ((emacs (26 1)) (dash (2 12 0)) (expand-region (0 10 0)) (multiple-cursors (1 3 0))) "Ergonomic Command Mode for Emacs." tar ((:commit . "19a7f76e75759f5266986b40c470edb1f70c43df"))]) - (borg . [(20240808 1953) ((emacs (27 1)) (epkg (4 0 0)) (magit (4 0 0))) "Assimilate Emacs packages as Git submodules" tar ((:commit . "e7a5a696d776f2b61c38335a8cec6108f4af2166") (:authors ("Jonas Bernoulli" . "emacs.borg@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.borg@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.borg@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/emacscollective/borg"))]) + (borg . [(20240817 1958) ((emacs (27 1)) (epkg (4 0 0)) (magit (4 0 0))) "Assimilate Emacs packages as Git submodules" tar ((:commit . "ad76a76424654d77b2b5d95472d86c03ce2c5410") (:authors ("Jonas Bernoulli" . "emacs.borg@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.borg@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.borg@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/emacscollective/borg"))]) (borland-blue-theme . [(20160117 1321) ((emacs (24 1))) "Blue/yellow theme based on old DOS Borland/Turbo C IDE" tar ((:commit . "db74eefebbc89d3c62575f8f50b319e87b4a3470") (:authors ("Alexey Veretennikov" . "alexeydotveretennikovatgmaildotcom")) (:maintainers ("Alexey Veretennikov" . "alexeydotveretennikovatgmaildotcom")) (:maintainer "Alexey Veretennikov" . "alexeydotveretennikovatgmaildotcom") (:keywords "themes") (:url . "http://github.com/fourier/borland-blue-theme"))]) (boron-theme . [(20170808 1308) ((emacs (24 0))) "an Emacs 24 theme based on Boron (tmTheme)" tar ((:commit . "87ae1a765e07429fec25d2f29b004f84b52d2e0a") (:url . "https://github.com/emacsfodder/tmtheme-to-deftheme"))]) (boxes . [(20240217 1143) ((emacs (24 3))) "ASCII boxes unlimited!" tar ((:commit . "75dfd61801b3ec23ec30c88640ea31bbca5b36b9") (:authors ("Jason L. Shiffer" . "jshiffer@zerotao.com")) (:maintainers ("Jason L. Shiffer" . "jshiffer@zerotao.com")) (:maintainer "Jason L. Shiffer" . "jshiffer@zerotao.com") (:keywords "extensions") (:url . "https://boxes.thomasjensen.com"))]) @@ -472,7 +472,7 @@ (camcorder . [(20190317 2138) ((emacs (24)) (names (20150000)) (cl-lib (0 5))) "Record screencasts in gif or other formats." tar ((:commit . "b11ca61491a27681bb3131b72b51c105fd996bed") (:authors ("Artur Malabarba" . "bruce.connor.am@gmail.com")) (:maintainers ("Artur Malabarba" . "bruce.connor.am@gmail.com")) (:maintainer "Artur Malabarba" . "bruce.connor.am@gmail.com") (:keywords "multimedia" "screencast") (:url . "http://github.com/Bruce-Connor/camcorder.el"))]) (caml . [(20231011 328) ((emacs (24 4))) "Caml mode for GNU Emacs" tar ((:commit . "47defafa2b08fb680e89bfee9cb9ce82bd9e3bcf") (:authors ("Jacques Garrigue" . "garrigue@kurims.kyoto-u.ac.jp") ("Ian T Zimmerman" . "itz@rahul.net") ("Damien Doligez" . "damien.doligez@inria.fr")) (:maintainers ("Christophe Troestler" . "Christophe.Troestler@umons.ac.be")) (:maintainer "Christophe Troestler" . "Christophe.Troestler@umons.ac.be") (:keywords "ocaml") (:url . "https://github.com/ocaml/caml-mode"))]) (cangjie . [(20230219 1150) ((emacs (24 4)) (s (1 12 0)) (dash (2 14 1)) (f (0 2 0))) "Retrieve cangjie code for han characters" tar ((:commit . "d6882e15f47fdde37e9f739dde604d77d25f11db") (:keywords "convenience" "writing") (:url . "https://github.com/kisaragi-hiu/cangjie.el"))]) - (cape . [(20240724 918) ((emacs (27 1)) (compat (30))) "Completion At Point Extensions" tar ((:commit . "5c468d6d657e8dc604ddf3feb80f70e1e05ac0a1") (:authors ("Daniel Mendler" . "mail@daniel-mendler.de")) (:maintainers ("Daniel Mendler" . "mail@daniel-mendler.de")) (:maintainer "Daniel Mendler" . "mail@daniel-mendler.de") (:keywords "abbrev" "convenience" "matching" "completion" "text") (:url . "https://github.com/minad/cape"))]) + (cape . [(20240818 1414) ((emacs (27 1)) (compat (30))) "Completion At Point Extensions" tar ((:commit . "944c60cc3ff81ceceeb239746f7dd9d8e7d0a663") (:authors ("Daniel Mendler" . "mail@daniel-mendler.de")) (:maintainers ("Daniel Mendler" . "mail@daniel-mendler.de")) (:maintainer "Daniel Mendler" . "mail@daniel-mendler.de") (:keywords "abbrev" "convenience" "matching" "completion" "text") (:url . "https://github.com/minad/cape"))]) (capnp-mode . [(20210707 2310) nil "Major mode for editing Capn' Proto Files" tar ((:commit . "f7fccad7d737f77896211bec1173117497634143") (:authors ("Brian Taylor" . "el.wubo@gmail.com")) (:maintainers ("Brian Taylor" . "el.wubo@gmail.com")) (:maintainer "Brian Taylor" . "el.wubo@gmail.com") (:url . "https://github.com/capnproto/capnproto"))]) (capture . [(20130828 1644) nil "screencasting with \"avconv\" or \"ffmpeg\"" tar ((:commit . "9140c207b48b3520a2f06674b3e1bee2fc92b80c") (:authors ("Sergey Pashinin" . "sergeyatpashinindotcom")) (:maintainers ("Sergey Pashinin" . "sergeyatpashinindotcom")) (:maintainer "Sergey Pashinin" . "sergeyatpashinindotcom"))]) (carbon-now-sh . [(20220701 332) ((emacs (24 4))) "https://carbon.now.sh integration." tar ((:commit . "e66f2e43e288f35ad9075f5fc84d59ad348efc88") (:keywords "convenience") (:url . "https://github.com/veelenga/carbon-now-sh.el"))]) @@ -495,11 +495,11 @@ (casual-ibuffer . [(20240730 329) ((emacs (29 1)) (casual-lib (1 1 0))) "Transient UI for IBuffer" tar ((:commit . "877bffe4e69f2715f5f84ad15ca54f4a14493b80") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "tools") (:url . "https://github.com/kickingvegas/casual-ibuffer"))]) (casual-info . [(20240711 712) ((emacs (29 1)) (casual-lib (1 1 0))) "Transient UI for Info" tar ((:commit . "23f970d58e5f3c2dc9fa291bdce5f9e560fb205c") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "tools") (:url . "https://github.com/kickingvegas/casual-info"))]) (casual-isearch . [(20240808 1638) ((emacs (29 1)) (casual-lib (1 1 0))) "Transient UI for I-Search" tar ((:commit . "812355ca972c81d9a31611572c490a2ea8ed8881") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "wp") (:url . "https://github.com/kickingvegas/casual-isearch"))]) - (casual-lib . [(20240716 2021) ((emacs (29 1)) (transient (0 6 0))) "Library routines for Casual porcelains" tar ((:commit . "74ae8cf0b88efefe9afc58605ccb1576ec1b035a") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "tools") (:url . "https://github.com/kickingvegas/casual-lib"))]) + (casual-lib . [(20240815 1946) ((emacs (29 1)) (transient (0 6 0))) "Library routines for Casual user interfaces" tar ((:commit . "db18e23ca60c9b0ba21644d54bb343a1099c6dbb") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "tools") (:url . "https://github.com/kickingvegas/casual-lib"))]) (casual-re-builder . [(20240730 49) ((emacs (29 1)) (casual-lib (1 1 0))) "Transient UI for RE-Builder" tar ((:commit . "f52e0f2ae1faee0d2988fe701880f13fda66ab86") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "tools") (:url . "https://github.com/kickingvegas/casual-re-builder"))]) (casual-suite . [(20240730 426) ((emacs (29 1)) (casual-calc (1 9 0)) (casual-isearch (1 7 0)) (casual-dired (1 4 0)) (casual-ibuffer (1 0 1)) (casual-avy (1 2 0)) (casual-info (1 2 0)) (casual-re-builder (1 0 2)) (casual-bookmarks (1 0 0))) "A suite of opinionated Transient UIs" tar ((:commit . "328c9a02af56d56fe794fb073c0b720cb7ff7efc") (:authors ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainers ("Charles Choi" . "kickingvegas@gmail.com")) (:maintainer "Charles Choi" . "kickingvegas@gmail.com") (:keywords "tools") (:url . "https://github.com/kickingvegas/casual-suite"))]) (catmacs . [(20170826 1157) ((emacs (24))) "Simple CAT interface for Yaesu Transceivers." tar ((:commit . "6ea9ee195661fe95355413856476c45dcc8e24e8") (:authors ("Frank Singleton" . "b17flyboy@gmail.com")) (:maintainers ("Frank Singleton" . "b17flyboy@gmail.com")) (:maintainer "Frank Singleton" . "b17flyboy@gmail.com") (:keywords "comm" "hardware") (:url . "https://bitbucket.org/pymaximus/catmacs"))]) - (catppuccin-theme . [(20240813 830) ((emacs (25 1))) "Catppuccin for Emacs - 🍄 Soothing pastel theme for Emacs" tar ((:commit . "177ecee1e5b8bbd05053cba5c93ebfae3b8fee8c") (:maintainers ("Jeremy Baxter" . "jeremy@baxters.nz")) (:maintainer "Jeremy Baxter" . "jeremy@baxters.nz") (:url . "https://github.com/catppuccin/emacs"))]) + (catppuccin-theme . [(20240818 734) ((emacs (25 1))) "Catppuccin for Emacs - 🍄 Soothing pastel theme for Emacs" tar ((:commit . "0b4a7e43b80aedcb7a8088ce0ab4928bd34d5f95") (:maintainers ("Jeremy Baxter" . "jeremy@baxters.nz")) (:maintainer "Jeremy Baxter" . "jeremy@baxters.nz") (:url . "https://github.com/catppuccin/emacs"))]) (cats . [(20230407 1316) ((emacs (26 1))) "Monads for Elisp" tar ((:commit . "7fc70db0eeb2c33ffba5c13c4cdc0f31c7b95537") (:authors ("Matúš Goljer" . "matus.goljer@gmail.com")) (:maintainers ("Matúš Goljer" . "matus.goljer@gmail.com")) (:maintainer "Matúš Goljer" . "matus.goljer@gmail.com") (:url . "https://github.com/Fuco1/emacs-cats"))]) (cbm . [(20171116 1240) ((cl-lib (0 5))) "Switch to similar buffers." tar ((:commit . "5b41c936ba9f6d170309a85ffebc9939c1050b31") (:authors ("Lukas Fürmetz" . "fuermetz@mailbox.org")) (:maintainers ("Lukas Fürmetz" . "fuermetz@mailbox.org")) (:maintainer "Lukas Fürmetz" . "fuermetz@mailbox.org") (:keywords "buffers") (:url . "http://github.com/akermu/cbm.el"))]) (cbor . [(20230810 1653) ((emacs (25 1))) "CBOR utilities" tar ((:commit . "ba624ad3f8b726bee1d8dcb0a2a9e2b658bb4c9b") (:authors ("Oscar Najera" . "https://oscarnajera.com")) (:maintainers ("Oscar Najera" . "hi@oscarnajera.com")) (:maintainer "Oscar Najera" . "hi@oscarnajera.com") (:url . "https://github.com/Titan-C/cardano.el"))]) @@ -535,7 +535,7 @@ (chapel-mode . [(20210513 457) ((emacs (25 1)) (hydra (0 15 0))) "A major mode for the Chapel programming language" tar ((:commit . "39fd24bb7cf44808200354ac0496be4fc4fddd9a") (:keywords "chapel" "chpl" "programming" "languages") (:url . "https://github.com/damon-kwok/chapel-mode"))]) (char-menu . [(20210321 1657) ((emacs (24 3)) (avy-menu (0 1))) "Create your own menu for fast insertion of arbitrary symbols" tar ((:commit . "d77c4d64fc8acc386a0fb9727d346c838e75f011") (:authors ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainers ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainer "Mark Karpov" . "markkarpov92@gmail.com") (:keywords "convenience" "editing") (:url . "https://github.com/mrkkrp/char-menu"))]) (charmap . [(20200616 1418) nil "Unicode table for Emacs" tar ((:commit . "feac50b87d2a596c5e5b7b82b79ddd65b6dedd8c") (:authors ("Anan Mikami" . "lateau@gmail.com")) (:maintainers ("Anan Mikami" . "lateau@gmail.com")) (:maintainer "Anan Mikami" . "lateau@gmail.com") (:keywords "unicode" "character" "ucs") (:url . "https://github.com/lateau/charmap"))]) - (chatgpt-shell . [(20240814 938) ((emacs (27 1)) (shell-maker (0 50 5))) "ChatGPT shell + buffer insert commands" tar ((:commit . "6fb85746bd0d316c97e375dcc14eb5314778e74d") (:url . "https://github.com/xenodium/chatgpt-shell"))]) + (chatgpt-shell . [(20240816 737) ((emacs (27 1)) (shell-maker (0 50 5))) "ChatGPT shell + buffer insert commands" tar ((:commit . "0efead292f053774bba3c0789370e8e383aa49ec") (:url . "https://github.com/xenodium/chatgpt-shell"))]) (chatu . [(20240518 615) ((org (9 6 6)) (emacs (29 1)) (plantuml-mode (1 2 9))) "Convert and insert any images to org-mode or markdown buffer" tar ((:commit . "f813f0bc926346fbd8151d2ae7079119d4657abb") (:authors ("Kimi Ma" . "kimi.im@outlook.com")) (:maintainers ("Kimi Ma" . "kimi.im@outlook.com")) (:maintainer "Kimi Ma" . "kimi.im@outlook.com") (:keywords "multimedia" "convenience") (:url . "https://github.com/kimim/chatu"))]) (chatwork . [(20170511 442) nil "ChatWork client for Emacs" tar ((:commit . "fea231d479f06bf40dbfcf45de143eecc9ed744c") (:authors ("Masayuki Ataka" . "masayuki.ataka@gmail.com")) (:maintainers ("Masayuki Ataka" . "masayuki.ataka@gmail.com")) (:maintainer "Masayuki Ataka" . "masayuki.ataka@gmail.com") (:keywords "web") (:url . "https://github.com/ataka/chatwork"))]) (cheat-sh . [(20210607 1307) ((emacs (25 1))) "Interact with cheat.sh" tar ((:commit . "33bae22feae8d3375739c6bdef08d0dcdf47ee42") (:authors ("Dave Pearson" . "davep@davep.org")) (:maintainers ("Dave Pearson" . "davep@davep.org")) (:maintainer "Dave Pearson" . "davep@davep.org") (:keywords "docs" "help") (:url . "https://github.com/davep/cheat-sh.el"))]) @@ -567,7 +567,7 @@ (chruby . [(20180114 1652) ((cl-lib (0 5))) "Emacs integration for chruby" tar ((:commit . "42bc6d521f832eca8e2ba210f30d03ad5529788f") (:authors ("Arne Brasseur" . "arne@arnebrasseur.net")) (:maintainers ("Arne Brasseur" . "arne@arnebrasseur.net")) (:maintainer "Arne Brasseur" . "arne@arnebrasseur.net") (:keywords "languages") (:url . "https://github.com/plexus/chruby.el"))]) (chyla-dark-theme . [(20240708 2033) ((emacs (24 1))) "Chyla.org - dark green color theme" tar ((:commit . "8d5c9a2eaaf04e0f1ad953a34b15e9777407b760") (:authors ("Adam Chyła https://chyla.org/" . "adam@chyla.org")) (:maintainers ("Adam Chyła https://chyla.org/" . "adam@chyla.org")) (:maintainer "Adam Chyła https://chyla.org/" . "adam@chyla.org") (:url . "https://github.com/chyla/ChylaDarkThemeForEmacs"))]) (chyla-theme . [(20240708 2017) ((emacs (24 1))) "Chyla.org - green color theme" tar ((:commit . "c2bb425eaff0975e0c7081f282d291f7853f8376") (:authors ("Adam Chyła https://chyla.org/" . "adam@chyla.org")) (:maintainers ("Adam Chyła https://chyla.org/" . "adam@chyla.org")) (:maintainer "Adam Chyła https://chyla.org/" . "adam@chyla.org") (:url . "https://github.com/chyla/ChylaThemeForEmacs"))]) - (cider . [(20240813 1832) ((emacs (26)) (clojure-mode (5 19)) (parseedn (1 2 1)) (queue (0 2)) (spinner (1 7)) (seq (2 22)) (sesman (0 3 2)) (transient (0 4 1))) "Clojure Interactive Development Environment that Rocks" tar ((:commit . "3c8af8b6787245e5dfd6dbb550a0ce8de1df4dcb") (:authors ("Tim King" . "kingtim@gmail.com") ("Phil Hagelberg" . "technomancy@gmail.com") ("Bozhidar Batsov" . "bozhidar@batsov.dev") ("Artur Malabarba" . "bruce.connor.am@gmail.com") ("Hugo Duncan" . "hugo@hugoduncan.org") ("Steve Purcell" . "steve@sanityinc.com")) (:maintainers ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainer "Bozhidar Batsov" . "bozhidar@batsov.dev") (:keywords "languages" "clojure" "cider") (:url . "https://www.github.com/clojure-emacs/cider"))]) + (cider . [(20240815 918) ((emacs (26)) (clojure-mode (5 19)) (parseedn (1 2 1)) (queue (0 2)) (spinner (1 7)) (seq (2 22)) (sesman (0 3 2)) (transient (0 4 1))) "Clojure Interactive Development Environment that Rocks" tar ((:commit . "144811a819b469cd797c88ec1f24119cfa8454af") (:authors ("Tim King" . "kingtim@gmail.com") ("Phil Hagelberg" . "technomancy@gmail.com") ("Bozhidar Batsov" . "bozhidar@batsov.dev") ("Artur Malabarba" . "bruce.connor.am@gmail.com") ("Hugo Duncan" . "hugo@hugoduncan.org") ("Steve Purcell" . "steve@sanityinc.com")) (:maintainers ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainer "Bozhidar Batsov" . "bozhidar@batsov.dev") (:keywords "languages" "clojure" "cider") (:url . "https://www.github.com/clojure-emacs/cider"))]) (cider-decompile . [(20151122 537) ((cider (0 3 0)) (javap-mode (9))) "decompilation extension for cider" tar ((:commit . "5d87035f3c3c14025e8f01c0c53d0ce2c8f56651") (:keywords "languages" "clojure" "cider") (:url . "http://www.github.com/clojure-emacs/cider-decompile"))]) (cider-eval-sexp-fu . [(20190311 2152) ((emacs (24)) (eval-sexp-fu (0 5 0))) "Briefly highlights an evaluated sexp." tar ((:commit . "7fd229f1441356866aedba611fd0cf4e89b50921") (:authors ("Sylvain Benner" . "sylvain.benner@gmail.com")) (:maintainers ("Sylvain Benner" . "sylvain.benner@gmail.com")) (:maintainer "Sylvain Benner" . "sylvain.benner@gmail.com") (:keywords "languages" "clojure" "cider"))]) (cider-hydra . [(20190816 1121) ((cider (0 22 0)) (hydra (0 13 0))) "Hydras for CIDER." tar ((:commit . "c3b8a15d72dddfbc390ab6a454bd7e4c765a2c95") (:authors ("Tianxiang Xiong" . "tianxiang.xiong@gmail.com")) (:maintainers ("Tianxiang Xiong" . "tianxiang.xiong@gmail.com")) (:maintainer "Tianxiang Xiong" . "tianxiang.xiong@gmail.com") (:keywords "convenience" "tools") (:url . "https://github.com/clojure-emacs/cider-hydra"))]) @@ -637,7 +637,7 @@ (cm-mode . [(20240422 725) ((emacs (25 1)) (cl-lib (0 5))) "Minor mode for CriticMarkup" tar ((:commit . "a9381f57f3005a9b26f81085ecb2accf680c6f6b") (:authors ("Joost Kremers" . "joostkremers@fastmail.fm")) (:maintainers ("Joost Kremers" . "joostkremers@fastmail.fm")) (:maintainer "Joost Kremers" . "joostkremers@fastmail.fm") (:keywords "text" "markdown"))]) (cmake-font-lock . [(20230304 2223) ((cmake-mode (0 0))) "Advanced, type aware, highlight support for CMake" tar ((:commit . "a6038e916bcca807ae695f7d7e5c300c3f38f415") (:keywords "faces" "languages") (:url . "https://github.com/Lindydancer/cmake-font-lock"))]) (cmake-ide . [(20210610 1525) ((emacs (24 4)) (cl-lib (0 5)) (seq (1 11)) (levenshtein (0)) (s (1 11 0))) "Calls CMake to find out include paths and other compiler flags" tar ((:commit . "28dc4ab5bd01d99553901b4efeb7234280928b18") (:authors ("Atila Neves" . "atila.neves@gmail.com")) (:maintainers ("Atila Neves" . "atila.neves@gmail.com")) (:maintainer "Atila Neves" . "atila.neves@gmail.com") (:keywords "languages") (:url . "http://github.com/atilaneves/cmake-ide"))]) - (cmake-mode . [(20240624 1425) ((emacs (24 1))) "major-mode for editing CMake sources" tar ((:commit . "4b874546fc3711bb24fcdba5718e6c85a17c740a"))]) + (cmake-mode . [(20240814 1725) ((emacs (24 1))) "major-mode for editing CMake sources" tar ((:commit . "cf1bc1b9371dc6063a1734a1cd80d6cb654ad53e"))]) (cmake-project . [(20171121 1115) nil "Integrates CMake build process with Emacs" tar ((:commit . "d3f408f226eff3f77f7e00dd519f4efc78fd292d") (:authors ("Alexander Lamaison" . "alexander.lamaison@gmail")) (:maintainers ("Alexander Lamaison" . "alexander.lamaison@gmail")) (:maintainer "Alexander Lamaison" . "alexander.lamaison@gmail") (:keywords "c" "cmake" "languages" "tools") (:url . "http://github.com/alamaison/emacs-cmake-project"))]) (cmd-to-echo . [(20161203 2133) ((emacs (24 4)) (s (1 11 0)) (shell-split-string (20151224 208))) "Show the output of long-running commands in the echo area" tar ((:commit . "e0e874fc0e1ad6d291e39ed76023445297ad438a") (:authors ("Tijs Mallaerts" . "tijs.mallaerts@gmail.com")) (:maintainers ("Tijs Mallaerts" . "tijs.mallaerts@gmail.com")) (:maintainer "Tijs Mallaerts" . "tijs.mallaerts@gmail.com"))]) (cmm-mode . [(20150225 746) nil "Major mode for C-- source code" tar ((:commit . "c3ad514dff3eb30434f6b20d953276d4c00de1ee"))]) @@ -776,9 +776,9 @@ (conkeror-minor-mode . [(20150114 1604) nil "Mode for editing conkeror javascript files." tar ((:commit . "476e81c27b056e21c192391fe674a2bf875466b0") (:authors ("Artur Malabarba" . "bruce.connor.am@gmail.com")) (:maintainers ("Artur Malabarba" . "bruce.connor.am@gmail.com")) (:maintainer "Artur Malabarba" . "bruce.connor.am@gmail.com") (:keywords "programming" "tools") (:url . "http://github.com/Bruce-Connor/conkeror-minor-mode"))]) (conllu-mode . [(20200501 2328) ((emacs (25)) (cl-lib (0 5)) (flycheck (30)) (hydra (0 13 0)) (s (1 0))) "editing mode for CoNLL-U files" tar ((:commit . "0db3063572b0de08874822e20570bb153747e6ed") (:authors ("bruno cuconato" . "bcclaro+emacs@gmail.com")) (:maintainers ("bruno cuconato" . "bcclaro+emacs@gmail.com")) (:maintainer "bruno cuconato" . "bcclaro+emacs@gmail.com") (:keywords "extensions") (:url . "https://github.com/odanoburu/conllu-mode"))]) (connection . [(20191111 446) nil "TCP-based client connection" tar ((:commit . "c9cad101100975e88873636bfd426b7a19304ebd") (:authors ("Torsten Hilbrich" . "torsten.hilbrich@gmx.net")) (:maintainers ("Torsten Hilbrich" . "torsten.hilbrich@gmx.net")) (:maintainer "Torsten Hilbrich" . "torsten.hilbrich@gmx.net") (:keywords "network"))]) - (conner . [(20240707 2220) ((emacs (29 1))) "Define and run project specific commands" tar ((:commit . "583d8288b07f4372b68e1c06917eb77c419c555d") (:keywords "tools") (:url . "https://github.com/tralph3/conner"))]) + (conner . [(20240816 2343) ((emacs (29 1))) "Define and run project specific commands" tar ((:commit . "7ea91fb4f1a067a3352ad66b70acfe86c76610da") (:keywords "tools") (:url . "https://github.com/tralph3/conner"))]) (constant-theme . [(20180921 1012) ((emacs (24 1))) "A calm, dark, almost monochrome color theme." tar ((:commit . "0feb9f99d708633d62fa548c953ebbe68fd70de0") (:authors ("Jannis Pohlmann" . "contact@jannispohlmann.de")) (:maintainers ("Jannis Pohlmann" . "contact@jannispohlmann.de")) (:maintainer "Jannis Pohlmann" . "contact@jannispohlmann.de") (:keywords "themes") (:url . "https://github.com/jannis/emacs-constant-theme"))]) - (consult . [(20240811 1858) ((emacs (27 1)) (compat (30))) "Consulting completing-read" tar ((:commit . "3d0fc6a8c6a74b21ca854b8632b3f58e0e513b85") (:maintainers ("Daniel Mendler" . "mail@daniel-mendler.de")) (:maintainer "Daniel Mendler" . "mail@daniel-mendler.de") (:keywords "matching" "files" "completion") (:url . "https://github.com/minad/consult"))]) + (consult . [(20240818 1112) ((emacs (27 1)) (compat (30))) "Consulting completing-read" tar ((:commit . "d403b8bd1b49922de5a8060e79f647db7988ace6") (:maintainers ("Daniel Mendler" . "mail@daniel-mendler.de")) (:maintainer "Daniel Mendler" . "mail@daniel-mendler.de") (:keywords "matching" "files" "completion") (:url . "https://github.com/minad/consult"))]) (consult-ag . [(20230227 406) ((emacs (27 1)) (consult (0 32))) "The silver searcher integration using Consult" tar ((:commit . "9eb4df265aedf2628a714610c2ade6d2f21de053") (:authors ("Kanon Kakuno and contributors" . "yadex205@outlook.jp")) (:maintainers ("Kanon Kakuno and contributors" . "yadex205@outlook.jp")) (:maintainer "Kanon Kakuno and contributors" . "yadex205@outlook.jp") (:url . "https://github.com/yadex205/consult-ag"))]) (consult-codesearch . [(20230315 1424) ((emacs (27 1)) (consult (0 20))) "Consult interface for codesearch" tar ((:commit . "51df545bb57b468058245950322ae15f6c3a0ce2") (:authors ("Youngjoo Lee" . "youngker@gmail.com")) (:maintainers ("Youngjoo Lee" . "youngker@gmail.com")) (:maintainer "Youngjoo Lee" . "youngker@gmail.com") (:keywords "tools") (:url . "https://github.com/youngker/consult-codesearch"))]) (consult-company . [(20230606 1824) ((emacs (27 1)) (company (0 9)) (consult (0 9))) "Consult frontend for company" tar ((:commit . "6e309fa9115c9ecd29aa27bff4e3b733979e5dbc") (:authors ("mohsin kaleem" . "mohkale@kisara.moe")) (:maintainers ("mohsin kaleem" . "mohkale@kisara.moe")) (:maintainer "mohsin kaleem" . "mohkale@kisara.moe") (:url . "https://github.com/mohkale/consult-company"))]) @@ -970,7 +970,7 @@ (decide . [(20230424 1647) nil "rolling dice and other random things" tar ((:commit . "9c0e4c4493f9af9a981627d0630ac6cb2d8c98f0") (:authors ("Pelle Nilsson" . "perni@lysator.liu.se")) (:maintainers ("Pelle Nilsson" . "perni@lysator.liu.se")) (:maintainer "Pelle Nilsson" . "perni@lysator.liu.se"))]) (decl . [(20221027 1823) ((dash (2 5 0)) (emacs (24 3)) (cl-lib (0 3))) "Library for organizing code declaratively" tar ((:commit . "1b11ee91c4b2a2d30b236debf65538fbe4bf10a9") (:url . "https://github.com/preetpalS/decl.el"))]) (declutter . [(20220310 2101) ((emacs (25 1))) "Read html content and (some) paywall sites without clutter" tar ((:commit . "0b2ca86fa716dfc2fb3bc3425019f049dd65eda2") (:authors ("Sanel Zukan" . "sanelz@gmail.com")) (:maintainers ("Sanel Zukan" . "sanelz@gmail.com")) (:maintainer "Sanel Zukan" . "sanelz@gmail.com") (:keywords "html" "hypermedia" "terminals") (:url . "http://www.github.com/sanel/declutter"))]) - (decor . [(20231210 1247) ((emacs (24 1))) "Modify visual decorations" tar ((:commit . "b0c8dfee69c9c5fe54c82cfcb2638377eb744464") (:authors ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainers ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainer "Peter Badida" . "keyweeusr@gmail.com") (:keywords "convenience" "window" "decoration" "distraction" "xprop" "xwayland") (:url . "https://github.com/KeyWeeUsr/decor"))]) + (decor . [(20240818 1100) ((emacs (24 1))) "Modify visual decorations" tar ((:commit . "f96828a9415f89eebe72a46b84aa047eb38279b9") (:authors ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainers ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainer "Peter Badida" . "keyweeusr@gmail.com") (:keywords "convenience" "window" "decoration" "distraction" "xprop" "xwayland") (:url . "https://github.com/KeyWeeUsr/decor"))]) (dedicated . [(20151202 110) nil "A very simple minor mode for dedicated buffers" tar ((:commit . "f47b504c0c56fa5ab9d1028417ca1f65a713a2f0") (:authors ("Eric Crampton" . "eric@atdesk.com")) (:maintainers ("Eric Crampton" . "eric@atdesk.com")) (:maintainer "Eric Crampton" . "eric@atdesk.com") (:keywords "dedicated" "buffer"))]) (dedukti-mode . [(20171103 1212) nil "Major mode for Dedukti files" tar ((:commit . "d7c3505a1046187de3c3aeb144455078d514594e") (:keywords "languages" "dedukti") (:url . "https://github.com/rafoo/dedukti-mode"))]) (default-font-presets . [(20240421 637) ((emacs (26 1))) "Support selecting fonts from a list of presets" tar ((:commit . "0087cbcbf78f107c0f908e4930f886a2d920eb90") (:authors ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainers ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainer "Campbell Barton" . "ideasman42@gmail.com") (:url . "https://codeberg.org/ideasman42/emacs-default-font-presets"))]) @@ -1021,7 +1021,7 @@ (diffscuss-mode . [(20141014 2357) nil "Major mode for diffscuss files." tar ((:commit . "bbc6dbed4b97d1eb9ae5dae021ed1e066129bd98") (:authors ("Edmund Jorgensen" . "edmund@hut8labs.com")) (:maintainers ("Edmund Jorgensen" . "edmund@hut8labs.com")) (:maintainer "Edmund Jorgensen" . "edmund@hut8labs.com") (:keywords "tools"))]) (difftastic . [(20240528 1657) ((emacs (28 1)) (compat (29 1 4 2)) (magit (20220326))) "Wrapper for difftastic" tar ((:commit . "79753bfec7c32f44dc0d5ed57a8bc6b370392a87") (:authors ("Przemyslaw Kryger" . "pkryger@gmail.com")) (:maintainers ("Przemyslaw Kryger" . "pkryger@gmail.com")) (:maintainer "Przemyslaw Kryger" . "pkryger@gmail.com") (:keywords "tools" "diff") (:url . "https://github.com/pkryger/difftastic.el"))]) (diffview . [(20230224 1916) nil "View diffs in side-by-side format" tar ((:commit . "8f07c0ff4a1acef990589df0d3e32288f19c9d71") (:authors ("Mitchel Humpherys" . "mitch.special@gmail.com")) (:maintainers ("Mitchel Humpherys" . "mitch.special@gmail.com")) (:maintainer "Mitchel Humpherys" . "mitch.special@gmail.com") (:keywords "convenience" "diff") (:url . "https://github.com/mgalgs/diffview-mode"))]) - (digistar-mode . [(20240731 1643) nil "major mode for Digistar scripts" tar ((:commit . "38aecbd07e52e36ed07e969c7a374fdef75def22") (:authors ("John Foerch" . "jjfoerch@gmail.com")) (:maintainers ("John Foerch" . "jjfoerch@gmail.com")) (:maintainer "John Foerch" . "jjfoerch@gmail.com") (:keywords "languages"))]) + (digistar-mode . [(20240814 1546) nil "major mode for Digistar scripts" tar ((:commit . "2d7e1a11304399f4a625053ffce8a3ad05f4ec7f") (:authors ("John Foerch" . "jjfoerch@gmail.com")) (:maintainers ("John Foerch" . "jjfoerch@gmail.com")) (:maintainer "John Foerch" . "jjfoerch@gmail.com") (:keywords "languages"))]) (digit-groups . [(20200506 37) ((dash (2 11 0))) "Highlight place-value positions in numbers" tar ((:commit . "7b81930cad19b8b7913b7eedbcb498964bfdcbdb") (:authors ("Michael D. Adams" . "http://michaeldadams.org")) (:maintainers ("Michael D. Adams" . "http://michaeldadams.org")) (:maintainer "Michael D. Adams" . "http://michaeldadams.org") (:url . "https://github.com/adamsmd/digit-groups/"))]) (digitalocean . [(20190607 726) ((request (2 5)) (emacs (24 4))) "Create and manipulate digitalocean droplets" tar ((:commit . "6c32d3593286e2a62d9afab0057c829407b0d1e8") (:authors ("Oliver Marks" . "oly@digitaloctave.com")) (:maintainers ("Oliver Marks" . "oly@digitaloctave.com")) (:maintainer "Oliver Marks" . "oly@digitaloctave.com") (:keywords "processes" "tools") (:url . "https://github.com/olymk2/emacs-digitalocean"))]) (digitalocean-helm . [(20180610 746) ((emacs (24 3)) (helm (2 5)) (digitalocean (0 1))) "Create and manipulate digitalocean droplets" tar ((:commit . "b125c9882eded7d73ec109d152b26625f333440b") (:authors ("Oliver Marks" . "oly@digitaloctave.com")) (:maintainers ("Oliver Marks" . "oly@digitaloctave.com")) (:maintainer "Oliver Marks" . "oly@digitaloctave.com") (:keywords "processes" "tools") (:url . "https://gitlab.com/olymk2/digitalocean-api"))]) @@ -1138,7 +1138,7 @@ (dokuwiki-mode . [(20170223 1301) nil "Major mode for DokuWiki document" tar ((:commit . "e4e116f6fcc373e3f5937c1a7daa5c2c9c6d3fa1") (:authors ("Tsunenobu Kai" . "kai2nenobu@gmail.com")) (:maintainers ("Tsunenobu Kai" . "kai2nenobu@gmail.com")) (:maintainer "Tsunenobu Kai" . "kai2nenobu@gmail.com") (:keywords "hypermedia" "text" "dokuwiki") (:url . "https://github.com/kai2nenobu/emacs-dokuwiki-mode"))]) (dollaro . [(20151123 1302) ((s (1 6 0))) "simple text templates" tar ((:commit . "500127f0172ac7a1eec627e026b59136580a74ac") (:authors ("Alessandro Piras" . "laynor@gmail.com")) (:maintainers ("Alessandro Piras" . "laynor@gmail.com")) (:maintainer "Alessandro Piras" . "laynor@gmail.com") (:keywords "tools" "convenience"))]) (doom . [(20180301 2308) ((cl-lib (0 5))) "DOM implementation and manipulation library" tar ((:commit . "e59040aefc92dd9b3134eb623624307fb9e4327b") (:authors ("Alex Schroeder" . "alex@gnu.org") ("Henrik.Motakef" . "elisp@henrik-motakef.de") ("Katherine Whitlock" . "toroidal-code@gmail.com") ("Syohei YOSHIDA" . "syohex@gmail.com")) (:keywords "xml" "dom") (:url . "http://www.github.com/kensanata/doom.el/"))]) - (doom-modeline . [(20240811 1437) ((emacs (25 1)) (compat (29 1 4 5)) (nerd-icons (0 1 0)) (shrink-path (0 3 1))) "A minimal and modern mode-line" tar ((:commit . "790e6817814a1fa893a91722861cba9424b0f004") (:authors ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainers ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Vincent Zhang" . "seagle0128@gmail.com") (:keywords "faces" "mode-line") (:url . "https://github.com/seagle0128/doom-modeline"))]) + (doom-modeline . [(20240816 749) ((emacs (25 1)) (compat (29 1 4 5)) (nerd-icons (0 1 0)) (shrink-path (0 3 1))) "A minimal and modern mode-line" tar ((:commit . "37fc5cfe4cc8487e82942cf8478c4e42eb0a95bd") (:authors ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainers ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Vincent Zhang" . "seagle0128@gmail.com") (:keywords "faces" "mode-line") (:url . "https://github.com/seagle0128/doom-modeline"))]) (doom-modeline-now-playing . [(20240522 1704) ((emacs (24 4)) (doom-modeline (3 0 0)) (async (1 9 3))) "Segment for Doom Modeline to show playerctl information" tar ((:commit . "1532f324f98a234aa14e12ebdfd17cebba978d6a") (:authors ("Ellis Kenyő" . "me@elken.dev")) (:maintainers ("Ellis Kenyő" . "me@elken.dev")) (:maintainer "Ellis Kenyő" . "me@elken.dev") (:url . "https://github.com/elken/doom-modeline-now-playing"))]) (doom-themes . [(20240809 2135) ((emacs (25 1)) (cl-lib (0 5))) "an opinionated pack of modern color-themes" tar ((:commit . "c589b245d643dcc5ec93054ea436efc5255f9b88") (:authors ("Henrik Lissner" . "contact@henrik.io")) (:maintainers ("Henrik Lissner" . "contact@henrik.io")) (:maintainer "Henrik Lissner" . "contact@henrik.io") (:keywords "themes" "faces") (:url . "https://github.com/doomemacs/themes"))]) (dot-env . [(20230820 2014) ((emacs (24 4)) (s (1 13 0))) "Dotenv functionality" tar ((:commit . "83ce690e8ef9175fc621c85d5fbef4f7ace7b7a8") (:keywords "convenience" "dotenv" "environment" "configuration") (:url . "https://github.com/amodelbello/dot-env.el"))]) @@ -1161,7 +1161,7 @@ (drill-instructor-AZIK-force . [(20151123 514) ((popup (0 5))) "Support AZIK input" tar ((:commit . "008cea202dc31d7d6fb1e7d8e6334d516403b7a5") (:authors ("Yuhei Maeda" . "yuhei.maeda_at_gmail.com")) (:keywords "convenience") (:url . "https://github.com/myuhe/drill-instructor-AZIK-force.el"))]) (drone . [(20161106 918) nil "Launch your drone test suite if drone.yml is present" tar ((:commit . "1d4ee037ad3208847a4235426edf0c4a3e7b1899") (:authors ("Oliver Marks" . "oly@digitaloctave.com")) (:maintainers ("Oliver Marks" . "oly@digitaloctave.com")) (:maintainer "Oliver Marks" . "oly@digitaloctave.com") (:keywords "drone" "tests" "ci") (:url . "https://github.com/olymk2/emacs-drone"))]) (dropbox . [(20220314 1638) ((request (0 3 0)) (json (1 2)) (oauth (1 0 3))) "Emacs backend for dropbox" tar ((:commit . "c048faad0be24e8fa31974f08b710a87cf5b668c") (:authors ("Pavel Panchekha" . "me@pavpanchekha.com")) (:maintainers ("Pavel Panchekha" . "me@pavpanchekha.com")) (:maintainer "Pavel Panchekha" . "me@pavpanchekha.com") (:keywords "dropbox"))]) - (drupal-mode . [(20220125 1044) ((php-mode (1 5 0))) "Advanced minor mode for Drupal development" tar ((:commit . "17927723adc5921e8058f7c29e5e50e88b975639") (:authors ("Arne Jørgensen" . "arne@arnested.dk")) (:maintainers ("Arne Jørgensen" . "arne@arnested.dk")) (:maintainer "Arne Jørgensen" . "arne@arnested.dk") (:keywords "programming" "php" "drupal") (:url . "https://github.com/arnested/drupal-mode"))]) + (drupal-mode . [(20240816 1236) ((php-mode (1 5 0))) "Advanced minor mode for Drupal development" tar ((:commit . "3f91d1d44df11ebd0137a896055fca6a1bb2f554") (:authors ("Arne Jørgensen" . "arne@arnested.dk")) (:maintainers ("Arne Jørgensen" . "arne@arnested.dk")) (:maintainer "Arne Jørgensen" . "arne@arnested.dk") (:keywords "programming" "php" "drupal") (:url . "https://github.com/arnested/drupal-mode"))]) (drupal-spell . [(20130520 1655) nil "Aspell extra dictionary for Drupal" tar ((:commit . "a69f5e3b62c4c0da74ce26c1d00d5b8f7395e4ae") (:authors ("Arne Jørgensen" . "arne@arnested.dk")) (:maintainers ("Arne Jørgensen" . "arne@arnested.dk")) (:maintainer "Arne Jørgensen" . "arne@arnested.dk") (:keywords "wp") (:url . "https://github.com/arnested/drupal-spell"))]) (dslide . [(20240703 1523) ((emacs (29 2))) "Domain Specific sLIDEs. A presentation framework" tar ((:commit . "2d8a9ac3e37157ce8b78880ebc1defc61303a44d") (:authors ("Positron" . "contact@positron.solutions")) (:maintainers ("Positron" . "contact@positron.solutions")) (:maintainer "Positron" . "contact@positron.solutions") (:keywords "convenience" "org-mode" "presentation" "narrowing") (:url . "https://github.com/positron-solutions/dslide"))]) (dsvn . [(20221102 1416) nil "Subversion interface" tar ((:commit . "36ecd5219584e46dcf6bd252e2ea1ec517d2fc05") (:authors ("David Kågedal" . "davidk@lysator.liu.se") ("Mattias Engdegård" . "mattiase@acm.org")) (:maintainers ("Mattias Engdegård" . "mattiase@acm.org")) (:maintainer "Mattias Engdegård" . "mattiase@acm.org") (:keywords "docs"))]) @@ -1182,7 +1182,7 @@ (dut-mode . [(20170729 2111) ((emacs (24))) "Major mode for the Dut programming language" tar ((:commit . "9235c7acaa6690942e9de8b7acd1e4be0c859dc1") (:keywords "languages" "gut") (:url . "https://github.com/dut-lang/dut-mode"))]) (dw . [(20210331 2311) ((emacs (25 1))) "Diceware passphrase generation commands" tar ((:commit . "61c5718ba64ace4c9e29de18aa2690ecc3f0f258") (:authors ("D. Williams" . "d.williams@posteo.net")) (:maintainers ("D. Williams" . "d.williams@posteo.net")) (:maintainer "D. Williams" . "d.williams@posteo.net") (:keywords "convenience" "games") (:url . "https://github.com/integral-dw/dw-passphrase-generator"))]) (dwim-coder-mode . [(20240712 1047) ((emacs (29))) "DWIM keybindings for C, Python, Rust, and more" tar ((:commit . "02f5fa0c3ae5cc17ca860c792d988705f41b0eee") (:authors ("Mohammed Sadiq" . "sadiq@sadiqpk.org")) (:maintainers ("Mohammed Sadiq" . "sadiq@sadiqpk.org")) (:maintainer "Mohammed Sadiq" . "sadiq@sadiqpk.org") (:keywords "convenience" "hacks") (:url . "https://sadiqpk.org/projects/dwim-coder-mode.html"))]) - (dwim-shell-command . [(20240808 1547) ((emacs (28 1))) "Shell commands with DWIM behaviour" tar ((:commit . "7d1c45aa2bc782c448cadd989dc776c2e5f83514") (:url . "https://github.com/xenodium/dwim-shell-command"))]) + (dwim-shell-command . [(20240817 2048) ((emacs (28 1))) "Shell commands with DWIM behaviour" tar ((:commit . "e704103e1cb946d80690d30c8842902b53151833") (:url . "https://github.com/xenodium/dwim-shell-command"))]) (dyalog-mode . [(20230214 1027) ((cl-lib (0 2)) (emacs (24 3))) "Major mode for editing Dyalog APL source code" tar ((:commit . "13c0d391aa878a1609259a89fe3e6db8d21935e8") (:authors ("Joakim Hårsman" . "joakim.harsman@gmail.com")) (:maintainers ("Joakim Hårsman" . "joakim.harsman@gmail.com")) (:maintainer "Joakim Hårsman" . "joakim.harsman@gmail.com") (:keywords "languages") (:url . "https://github.com/harsman/dyalog-mode.git"))]) (dylan . [(20220115 1804) ((emacs (25 1))) "Dylan editing modes" tar ((:commit . "9d2891e3e06405b75072d296f385fa795aeb9835") (:url . "https://opendylan.org/"))]) (dynamic-fonts . [(20140731 1226) ((font-utils (0 7 0)) (persistent-soft (0 8 8)) (pcache (0 2 3))) "Set faces based on available fonts" tar ((:commit . "004ee6014dc7dbff8f14d26015c91d9229f6eac0") (:authors ("Roland Walker" . "walker@pobox.com")) (:maintainers ("Roland Walker" . "walker@pobox.com")) (:maintainer "Roland Walker" . "walker@pobox.com") (:keywords "faces" "frames") (:url . "http://github.com/rolandwalker/dynamic-fonts"))]) @@ -1212,7 +1212,7 @@ (easy-kill . [(20220511 557) ((emacs (25)) (cl-lib (0 5))) "kill & mark things easily" tar ((:commit . "de7d66c3c864a4722a973ee9bc228a14be49ba0c") (:authors ("Leo Liu" . "sdl.web@gmail.com")) (:maintainers ("Leo Liu" . "sdl.web@gmail.com")) (:maintainer "Leo Liu" . "sdl.web@gmail.com") (:keywords "killing" "convenience") (:url . "https://github.com/leoliu/easy-kill"))]) (easy-kill-extras . [(20240122 1649) ((easy-kill (0 9 4))) "Extra functions for easy-kill." tar ((:commit . "6ec0a1ff47aee681f7aa7af4250ede75815385f2") (:authors ("Akinori MUSHA" . "knu@iDaemons.org")) (:maintainers ("Akinori MUSHA" . "knu@iDaemons.org")) (:maintainer "Akinori MUSHA" . "knu@iDaemons.org") (:keywords "killing" "convenience") (:url . "https://github.com/knu/easy-kill-extras.el"))]) (easy-repeat . [(20150516 848) ((emacs (24 4))) "Repeat easily" tar ((:commit . "060f0e6801c82c40c06961dc0528a00e18947a8c") (:authors ("Chunyang Xu" . "xuchunyang56@gmail.com")) (:maintainers ("Chunyang Xu" . "xuchunyang56@gmail.com")) (:maintainer "Chunyang Xu" . "xuchunyang56@gmail.com") (:keywords "repeat" "convenience") (:url . "https://github.com/xuchunyang/easy-repeat.el"))]) - (easysession . [(20240809 2239) ((emacs (25 1)) (f (0 18 2))) "Easily persist and restore your editing sessions" tar ((:commit . "c7d5b38fa82a54a6710fed01f00756764d78dd7a") (:keywords "convenience") (:url . "https://github.com/jamescherti/easysession.el"))]) + (easysession . [(20240814 1817) ((emacs (25 1)) (f (0 18 2))) "Easily persist and restore your editing sessions" tar ((:commit . "7bf893a307be84af43c00fa6b9eed2e4f9d920b8") (:keywords "convenience") (:url . "https://github.com/jamescherti/easysession.el"))]) (ebdb-mua-sidecar . [(20240428 1852) ((emacs (28 1)) (universal-sidecar (1 5 1)) (ebdb (0 8 20))) "EBDB Integration for Universal Sidecar" tar ((:commit . "4c78015d10caba9c700e6e6b582004ae1c1d5344") (:authors ("Samuel W. Flint" . "me@samuelwflint.com")) (:maintainers ("Samuel W. Flint" . "me@samuelwflint.com")) (:maintainer "Samuel W. Flint" . "me@samuelwflint.com") (:keywords "mail" "convenience") (:url . "https://git.sr.ht/~swflint/emacs-universal-sidecar"))]) (ebf . [(20210225 1211) ((dash (2 18 0)) (cl-lib (0 5))) "brainfuck language transpiler to Emacs Lisp" tar ((:commit . "6cbeb4d62416f4cfd5be8906667342af8ecc44a6") (:authors ("Alexey Kutepov" . "reximkut@gmail.com")) (:maintainers ("Alexey Kutepov" . "reximkut@gmail.com")) (:maintainer "Alexey Kutepov" . "reximkut@gmail.com") (:url . "http://github.com/rexim/ebf"))]) (ebib . [(20240723 1149) ((parsebib (4 0)) (emacs (27 1)) (compat (29 1 4 3))) "a BibTeX database manager" tar ((:commit . "5ea510a1e4ab17a442352d0212777da5f78d4be2") (:authors ("Joost Kremers" . "joostkremers@fastmail.fm")) (:maintainers ("Joost Kremers" . "joostkremers@fastmail.fm")) (:maintainer "Joost Kremers" . "joostkremers@fastmail.fm") (:keywords "text" "bibtex") (:url . "http://joostkremers.github.io/ebib/"))]) @@ -1270,7 +1270,7 @@ (eink-theme . [(20190219 858) nil "E Ink color theme" tar ((:commit . "326b07523dcb076d6209cdbc7fdbb73df296dbdb") (:authors ("Marian Schubert" . "marian.schubert@gmail.com")) (:maintainers ("Marian Schubert" . "marian.schubert@gmail.com")) (:maintainer "Marian Schubert" . "marian.schubert@gmail.com") (:url . "http://github.com/maio/eink-emacs"))]) (ejc-sql . [(20240106 1848) ((emacs (26 3)) (clomacs (0 0 5)) (dash (2 16 0)) (spinner (1 7 3))) "Emacs SQL client uses Clojure JDBC." tar ((:commit . "b80b773238719fa7160e598219f300dfbc4db06d") (:authors ("Kostafey" . "kostafey@gmail.com")) (:maintainers ("Kostafey" . "kostafey@gmail.com")) (:maintainer "Kostafey" . "kostafey@gmail.com") (:keywords "sql" "jdbc") (:url . "https://github.com/kostafey/ejc-sql"))]) (ejson-mode . [(20190720 2138) ((emacs (25))) "Major mode for editing ejson files." tar ((:commit . "9630dfac9549779711dbe89e621f516bb4b3a354") (:keywords "convenience" "languages" "tools") (:url . "https://github.com/dantecatalfamo/ejson-mode"))]) - (ekg . [(20240812 352) ((triples (0 3 5)) (emacs (28 1)) (llm (0 17 0))) "A system for recording and linking information" tar ((:commit . "00ae22d95ee7a006214589b905fc9b7e268141b2") (:authors ("Andrew Hyatt" . "ahyatt@gmail.com")) (:maintainers ("Andrew Hyatt" . "ahyatt@gmail.com")) (:maintainer "Andrew Hyatt" . "ahyatt@gmail.com") (:keywords "outlines" "hypermedia") (:url . "https://github.com/ahyatt/ekg"))]) + (ekg . [(20240818 437) ((triples (0 3 5)) (emacs (28 1)) (llm (0 17 0))) "A system for recording and linking information" tar ((:commit . "789cb6d954e0b31f8c25cc0bfa84ba812820f5cf") (:authors ("Andrew Hyatt" . "ahyatt@gmail.com")) (:maintainers ("Andrew Hyatt" . "ahyatt@gmail.com")) (:maintainer "Andrew Hyatt" . "ahyatt@gmail.com") (:keywords "outlines" "hypermedia") (:url . "https://github.com/ahyatt/ekg"))]) (el-autoyas . [(20120918 1317) nil "Automatically create Emacs-Lisp Yasnippets" tar ((:commit . "bde0251ecb504f585dfa27c205c8e312655310cc") (:keywords "emacs" "lisp" "mode" "yasnippet") (:url . "https://github.com/mlf176f2/el-autoyas.el"))]) (el-fetch . [(20230624 2) ((emacs (25 1))) "Show system information in Neofetch-like style (eg CPU, RAM)" tar ((:commit . "7907fd7829ca55b21a62d23c17066fdfde9cd07c") (:authors ("Maciej Barć" . "xgqt@riseup.net")) (:maintainers ("Maciej Barć" . "xgqt@riseup.net")) (:maintainer "Maciej Barć" . "xgqt@riseup.net") (:keywords "games") (:url . "https://gitlab.com/xgqt/emacs-el-fetch"))]) (el-fly-indent-mode . [(20180422 243) ((emacs (25))) "Indent Emacs Lisp on the fly" tar ((:commit . "1dd4b907ff4d9581c18b4e38e8719e83ba0dace1") (:authors ("Jiahao Li" . "jiahaowork@gmail.com")) (:maintainers ("Jiahao Li" . "jiahaowork@gmail.com")) (:maintainer "Jiahao Li" . "jiahaowork@gmail.com") (:keywords "lisp" "languages") (:url . "https://github.com/jiahaowork/el-fly-indent-mode.el"))]) @@ -1292,7 +1292,7 @@ (el2org . [(20200408 146) ((emacs (25 1))) "Convert elisp file to org file" tar ((:commit . "7db77fdd73f378d4e60e34c11bbdf00677adc32c") (:authors ("Feng Shu" . "tumashu@163.com")) (:maintainers ("Feng Shu" . "tumashu@163.com")) (:maintainer "Feng Shu" . "tumashu@163.com") (:keywords "convenience") (:url . "https://github.com/tumashu/el2org"))]) (elbank . [(20180316 1343) ((emacs (25)) (seq (2 16))) "Personal finances reporting application" tar ((:commit . "6dbd21e31fdf7cf62491f6d24b8198d4f91a031b") (:authors ("Nicolas Petton" . "nicolas@petton.fr")) (:maintainers ("Nicolas Petton" . "nicolas@petton.fr")) (:maintainer "Nicolas Petton" . "nicolas@petton.fr") (:keywords "tools" "personal-finances"))]) (elcontext . [(20210109 1238) ((ht (2 3)) (hydra (0 14 0)) (emacs (24 3)) (f (0 20 0)) (osx-location (0 4)) (uuidgen (0 3))) "Create context specific actions" tar ((:commit . "2efd3dd8c5176c4f071bb048be6cb069b05d6e9e") (:keywords "calendar" "convenience") (:url . "https://github.com/rollacaster/elcontext"))]) - (elcord . [(20240305 2138) ((emacs (25 1))) "Allows you to integrate Rich Presence from Discord" tar ((:commit . "e2775f40ec55dfdceea83d535dff77d60534b6bc") (:authors ("Wilfredo Velázquez-Rodríguez" . "zulu.inuoe@gmail.com")) (:maintainers ("Wilfredo Velázquez-Rodríguez" . "zulu.inuoe@gmail.com")) (:maintainer "Wilfredo Velázquez-Rodríguez" . "zulu.inuoe@gmail.com") (:keywords "games") (:url . "https://github.com/Mstrodl/elcord"))]) + (elcord . [(20240815 30) ((emacs (25 1))) "Allows you to integrate Rich Presence from Discord" tar ((:commit . "252019e21d7de9c06124f4ceddae324b477a64b8") (:authors ("Wilfredo Velázquez-Rodríguez" . "zulu.inuoe@gmail.com")) (:maintainers ("Wilfredo Velázquez-Rodríguez" . "zulu.inuoe@gmail.com")) (:maintainer "Wilfredo Velázquez-Rodríguez" . "zulu.inuoe@gmail.com") (:keywords "games") (:url . "https://github.com/Mstrodl/elcord"))]) (elcouch . [(20230903 750) ((emacs (25 1)) (json-mode (1 0 0)) (libelcouch (0 11 0)) (navigel (0 3 0))) "View and manipulate CouchDB databases" tar ((:commit . "a426e9bee9501284f4e1e84766621ca6b130c79a") (:authors ("Damien Cassou" . "damien@cassou.me")) (:maintainers ("Damien Cassou" . "damien@cassou.me")) (:maintainer "Damien Cassou" . "damien@cassou.me") (:keywords "data" "tools") (:url . "https://gitlab.petton.fr/DamienCassou/elcouch"))]) (elcute . [(20240724 2106) ((emacs (29 1))) "Commands for marking and killing lines electrically" tar ((:commit . "b604f934c0c919f5eb0155e38202875b796ac4de") (:keywords "convenience") (:url . "https://codeberg.org/vilij/slurpbarf-elcute"))]) (eldev . [(20240609 1211) ((emacs (24 4))) "Elisp development tool" tar ((:commit . "bb1938237ee85e477243cd45421330403df29390") (:authors ("Paul Pogonyshev" . "pogonyshev@gmail.com")) (:maintainers ("Paul Pogonyshev" . "pogonyshev@gmail.com")) (:maintainer "Paul Pogonyshev" . "pogonyshev@gmail.com") (:keywords "maint" "tools") (:url . "https://github.com/emacs-eldev/eldev"))]) @@ -1434,7 +1434,7 @@ (epc . [(20140610 534) ((concurrent (0 3 1)) (ctable (0 1 2))) "A RPC stack for the Emacs Lisp" tar ((:commit . "94cd36a3bec752263ac9b1b3a9dd2def329d2af7") (:authors ("SAKURAI Masashi" . "m.sakuraiatkiwanami.net")) (:maintainers ("SAKURAI Masashi" . "m.sakuraiatkiwanami.net")) (:maintainer "SAKURAI Masashi" . "m.sakuraiatkiwanami.net") (:keywords "lisp" "rpc") (:url . "https://github.com/kiwanami/emacs-epc"))]) (epic . [(20170210 23) ((htmlize (1 47))) "Evernote Picker for Cocoa Emacs" tar ((:commit . "a41826c330eb0ea061d58a08cc861b0c4ac8ec4e") (:authors ("Yoshinari Nomura" . "nom@quickhack.net")) (:maintainers ("Yoshinari Nomura" . "nom@quickhack.net")) (:maintainer "Yoshinari Nomura" . "nom@quickhack.net") (:keywords "evernote" "applescript") (:url . "https://github.com/yoshinari-nomura/epic"))]) (eping . [(20201027 2149) ((emacs (25 1))) "Ping websites to check internet connectivity" tar ((:commit . "004496ee06c0b8ead4a4f49e17109e8eb32eb49d") (:authors ("Sean Hutchings" . "seanhut@yandex.com")) (:maintainers ("Sean Hutchings" . "seanhut@yandex.com")) (:maintainer "Sean Hutchings" . "seanhut@yandex.com") (:keywords "comm" "processes" "terminals" "unix") (:url . "https://github.com/sean-hut/eping"))]) - (epkg . [(20240808 1949) ((emacs (26 1)) (compat (30 0 0 0)) (closql (2 0 0)) (emacsql (4 0 0)) (llama (0 3 1))) "Browse the Emacsmirror package database" tar ((:commit . "e14d2b4808631d37faac1ff1c7f962d60ec28825") (:authors ("Jonas Bernoulli" . "emacs.epkg@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.epkg@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.epkg@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/emacscollective/epkg"))]) + (epkg . [(20240817 1958) ((emacs (26 1)) (compat (30 0 0 0)) (closql (2 0 0)) (emacsql (4 0 0)) (llama (0 3 1))) "Browse the Emacsmirror package database" tar ((:commit . "5fcce562e9b169733b2fdaf0524f0d92f1bc47eb") (:authors ("Jonas Bernoulli" . "emacs.epkg@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.epkg@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.epkg@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/emacscollective/epkg"))]) (epkg-marginalia . [(20240808 1951) ((emacs (27 1)) (compat (30 0 0 0)) (epkg (4 0 0)) (llama (0 3 1)) (marginalia (1 7))) "Show Epkg information in completion annotations" tar ((:commit . "1e291facfbcce0d515a7a90b0bfd82d5b6358e92") (:authors ("Jonas Bernoulli" . "emacs.epkg-marginalia@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.epkg-marginalia@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.epkg-marginalia@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/emacscollective/epkg-marginalia"))]) (epl . [(20180205 2049) ((cl-lib (0 3))) "Emacs Package Library" tar ((:commit . "78ab7a85c08222cd15582a298a364774e3282ce6") (:authors ("Sebastian Wiesner" . "swiesner@lunaryorn.com")) (:maintainers ("Johan Andersson" . "johan.rejeep@gmail.com") ("Sebastian Wiesner" . "swiesner@lunaryorn.com")) (:maintainer "Johan Andersson" . "johan.rejeep@gmail.com") (:keywords "convenience") (:url . "http://github.com/cask/epl"))]) (epm . [(20190509 443) ((emacs (24 3)) (epl (0 8))) "Emacs Package Manager" tar ((:commit . "6375ddbf93c5f25647f6ebb25b54045b3c93a5be") (:authors ("Chunyang Xu" . "xuchunyang.me@gmail.com")) (:maintainers ("Chunyang Xu" . "xuchunyang.me@gmail.com")) (:maintainer "Chunyang Xu" . "xuchunyang.me@gmail.com") (:url . "https://github.com/xuchunyang/epm"))]) @@ -1544,7 +1544,7 @@ (evil-cleverparens . [(20240529 1025) ((evil (1 0)) (paredit (1)) (smartparens (1 6 1)) (emacs (24 4)) (dash (2 12 0))) "Evil friendly minor-mode for editing lisp." tar ((:commit . "6637717af0bdac55f97eef98433d53a10395cf77") (:authors ("Olli Piepponen" . "opieppo@gmail.com")) (:maintainers ("Olli Piepponen" . "opieppo@gmail.com")) (:maintainer "Olli Piepponen" . "opieppo@gmail.com") (:keywords "convenience" "emulations") (:url . "https://github.com/emacs-evil/evil-cleverparens"))]) (evil-colemak-basics . [(20221230 1443) ((emacs (24 3)) (evil (1 2 12)) (evil-snipe (2 0 3))) "Basic Colemak key bindings for evil-mode" tar ((:commit . "ea519b962f051cabced8aadaf6ed0134b861225c") (:authors ("Wouter Bolsterlee" . "wouter@bolsterl.ee")) (:maintainers ("Wouter Bolsterlee" . "wouter@bolsterl.ee")) (:maintainer "Wouter Bolsterlee" . "wouter@bolsterl.ee") (:keywords "convenience" "emulations" "colemak" "evil") (:url . "https://github.com/wbolster/evil-colemak-basics"))]) (evil-colemak-minimal . [(20171006 1317) ((emacs (24)) (evil (1 2 12))) "Minimal Colemak key bindings for evil-mode" tar ((:commit . "6d98b6da60f414524a0d718f76024c26dce742b3") (:authors ("Bryan Allred" . "bryan@revolvingcow.com")) (:maintainers ("Bryan Allred" . "bryan@revolvingcow.com")) (:maintainer "Bryan Allred" . "bryan@revolvingcow.com") (:keywords "colemak" "evil") (:url . "https://github.com/bmallred/evil-colemak-minimal"))]) - (evil-collection . [(20240813 1850) ((emacs (26 3)) (evil (1 2 13)) (annalist (1 0))) "A set of keybindings for Evil mode" tar ((:commit . "fd233059fba8daaab2bd9bb396fc756af56a296d") (:authors ("James Nguyen" . "james@jojojames.com")) (:maintainers ("James Nguyen" . "james@jojojames.com")) (:maintainer "James Nguyen" . "james@jojojames.com") (:keywords "evil" "tools") (:url . "https://github.com/emacs-evil/evil-collection"))]) + (evil-collection . [(20240817 2119) ((emacs (26 3)) (evil (1 2 13)) (annalist (1 0))) "A set of keybindings for Evil mode" tar ((:commit . "772571fc6762b6cd1d35cc869e266de9a5c6022b") (:authors ("James Nguyen" . "james@jojojames.com")) (:maintainers ("James Nguyen" . "james@jojojames.com")) (:maintainer "James Nguyen" . "james@jojojames.com") (:keywords "evil" "tools") (:url . "https://github.com/emacs-evil/evil-collection"))]) (evil-commentary . [(20230610 1006) ((evil (1 0 0))) "Comment stuff out. A port of vim-commentary." tar ((:commit . "c5945f28ce47644c828aac1f5f6ec335478d17fb") (:authors ("Quang Linh LE" . "linktohack@gmail.com")) (:maintainers ("Quang Linh LE" . "linktohack@gmail.com")) (:maintainer "Quang Linh LE" . "linktohack@gmail.com") (:keywords "evil" "comment" "commentary" "evil-commentary") (:url . "http://github.com/linktohack/evil-commentary"))]) (evil-dvorak . [(20160416 1841) ((evil (1 0 8))) "evil keybindings for that work with dvorak mode" tar ((:commit . "e7b80077d6f332452049eb3d7ea51f6c8fbf5947") (:keywords "dvorak" "evil" "vim"))]) (evil-easymotion . [(20200424 135) ((emacs (24)) (avy (0 3 0)) (cl-lib (0 5))) "A port of vim's easymotion to emacs" tar ((:commit . "f96c2ed38ddc07908db7c3c11bcd6285a3e8c2e9") (:authors ("PythonNut" . "pythonnut@pythonnut.com")) (:maintainers ("PythonNut" . "pythonnut@pythonnut.com")) (:maintainer "PythonNut" . "pythonnut@pythonnut.com") (:keywords "convenience" "evil") (:url . "https://github.com/pythonnut/evil-easymotion"))]) @@ -1638,7 +1638,7 @@ (exsqlaim-mode . [(20170607 1003) ((s (1 10 0))) "Use variables inside sql queries" tar ((:commit . "a2e0a62ec8b87193d8eaa695774bfd689324b06c") (:authors ("Ahmad Nazir Raja" . "ahmadnazir@gmail.com")) (:maintainers ("Ahmad Nazir Raja" . "ahmadnazir@gmail.com")) (:maintainer "Ahmad Nazir Raja" . "ahmadnazir@gmail.com") (:url . "https://github.com/ahmadnazir/exsqlaim-mode"))]) (extempore-mode . [(20220704 2241) ((emacs (24 4))) "Emacs major mode for Extempore source files" tar ((:commit . "92e0fff482a0a4dc2971c39581c5ea9e84ae5e1c") (:authors ("Ben Swift" . "ben@benswift.me")) (:maintainers ("Ben Swift" . "ben@benswift.me")) (:maintainer "Ben Swift" . "ben@benswift.me") (:keywords "extempore") (:url . "http://github.com/extemporelang/extempore-emacs-mode"))]) (extend-dnd . [(20151122 1850) nil "R drag and Drop" tar ((:commit . "80c966c93b82c9bb5c6225a432557c39144fc602") (:keywords "extend" "drag and drop") (:url . "https://github.com/mlf176f2/extend-dnd"))]) - (external-dict . [(20240813 1416) ((emacs (25 1))) "Query external dictionary like goldendict, Bob.app etc" tar ((:commit . "bfa4135c53306f1d57c721ae9ce37f1013052192") (:keywords "wp" "processes") (:url . "https://repo.or.cz/external-dict.el.git"))]) + (external-dict . [(20240817 149) ((emacs (25 1))) "Query external dictionary like goldendict, Bob.app etc" tar ((:commit . "0399b1c086417030f914bd26fff636dfdd55833a") (:keywords "wp" "processes") (:url . "https://repo.or.cz/external-dict.el.git"))]) (extmap . [(20230907 1959) ((emacs (24 4))) "Externally-stored constant mapping for Elisp" tar ((:commit . "3b0f898057082a1c01584ff2bbaf5fd4d22c1400") (:authors ("Paul Pogonyshev" . "pogonyshev@gmail.com")) (:maintainers ("Paul Pogonyshev" . "pogonyshev@gmail.com")) (:maintainer "Paul Pogonyshev" . "pogonyshev@gmail.com") (:keywords "lisp") (:url . "https://github.com/doublep/extmap"))]) (exunit . [(20240502 431) ((s (1 11 0)) (emacs (24 3)) (f (0 20 0)) (transient (0 3 6)) (project (0 9 8))) "ExUnit test runner" tar ((:commit . "b6134ce920a4bbc561f65fac1d1bf37206d97505") (:authors ("Anantha kumaran" . "ananthakumaran@gmail.com")) (:maintainers ("Anantha kumaran" . "ananthakumaran@gmail.com")) (:maintainer "Anantha kumaran" . "ananthakumaran@gmail.com") (:keywords "processes" "elixir" "exunit") (:url . "http://github.com/ananthakumaran/exunit.el"))]) (exwm-edit . [(20240418 2142) ((emacs (27 1))) "Edit mode for EXWM" tar ((:commit . "046b8c11f71bfd6c798df770c6b7708af2c187a2") (:keywords "convenience") (:url . "https://github.com/agzam/exwm-edit"))]) @@ -1711,7 +1711,7 @@ (find-things-fast . [(20150519 2226) nil "Find things fast, leveraging the power of git" tar ((:commit . "281dcb5a2e2db1013246dcac5111808352a8ea95") (:keywords "project" "convenience"))]) (findr . [(20130127 2032) nil "Breadth-first file-finding facility for (X)Emacs" tar ((:commit . "1ddbc0464bb05dcda392b62666ad17239a2152d3") (:authors ("David Bakhash" . "cadet@bu.edu")) (:maintainers ("David Bakhash" . "cadet@bu.edu")) (:maintainer "David Bakhash" . "cadet@bu.edu") (:keywords "files"))]) (fingers . [(20160817 829) nil "Modal editing with universal text manipulation helpers." tar ((:commit . "7de351448a6f5ea7aa7a25db6c90d5138f87eb16") (:authors ("Felix Geller" . "fgeller@gmail.com")) (:maintainers ("Felix Geller" . "fgeller@gmail.com")) (:maintainer "Felix Geller" . "fgeller@gmail.com") (:keywords "fingers" "modal" "editing" "workman") (:url . "http://github.com/fgeller/fingers.el"))]) - (finito . [(20240803 1549) ((emacs (27 1)) (dash (2 17 0)) (request (0 3 2)) (f (0 2 0)) (s (1 12 0)) (transient (0 3 0)) (graphql (0 1 1)) (async (1 9 3))) "View and collect books" tar ((:commit . "7441c73271fc44a33078f0d8d5f47c4e181804b1") (:keywords "outlines") (:url . "https://github.com/LaurenceWarne/finito.el"))]) + (finito . [(20240818 1003) ((emacs (27 1)) (dash (2 19 1)) (request (0 3 2)) (f (0 2 0)) (s (1 12 0)) (transient (0 3 0)) (graphql (0 1 1)) (async (1 9 3))) "View and collect books" tar ((:commit . "9ad22dbf34574c5d6070724eba0d22350b347e6b") (:keywords "outlines") (:url . "https://github.com/LaurenceWarne/finito.el"))]) (fiplr . [(20140724 645) ((grizzl (0 1 0)) (cl-lib (0 1))) "Fuzzy Search for Files in Projects" tar ((:commit . "bb6b90ba3c558988c195048c4c40140b2ee17530") (:authors ("Chris Corbyn" . "chris@w3style.co.uk")) (:maintainer "Chris Corbyn" . "chris@w3style.co.uk") (:keywords "convenience" "usability" "project") (:url . "https://github.com/d11wtq/fiplr"))]) (fira-code-mode . [(20240228 1728) ((emacs (24 4))) "Minor mode for Fira Code ligatures using prettify-symbols" tar ((:commit . "c48f3f16a4b497b9e455966561bbb6638efe4900") (:authors ("Jonathan Ming" . "jming422@gmail.com")) (:maintainers ("Jonathan Ming" . "jming422@gmail.com")) (:maintainer "Jonathan Ming" . "jming422@gmail.com") (:keywords "faces" "ligatures" "fonts" "programming-ligatures") (:url . "https://github.com/jming422/fira-code-mode"))]) (firebase-rules-mode . [(20240520 1326) ((emacs (24 3))) "Editing support for firebase.rules" tar ((:commit . "c88cb10251cdfce931e4fe48ce76eaa50cc7e791") (:authors ("Darrel Herbst" . "dherbst@gmail.com")) (:maintainers ("Darrel Herbst" . "dherbst@gmail.com")) (:maintainer "Darrel Herbst" . "dherbst@gmail.com") (:keywords "languages") (:url . "https://github.com/dherbst/firebase-rules-mode"))]) @@ -1847,7 +1847,7 @@ (flycheck-projectile . [(20201031 1952) ((emacs (25 1)) (flycheck (31)) (projectile (2 2))) "Project-wide errors" tar ((:commit . "ce6e9e8793a55dace13d5fa13badab2dca3b5ddb") (:authors ("Nikita Bloshchanevich" . "nikblos@outlook.com")) (:maintainers ("Nikita Bloshchanevich" . "nikblos@outlook.com")) (:maintainer "Nikita Bloshchanevich" . "nikblos@outlook.com") (:url . "https://github.com/nbfalcon/flycheck-projectile"))]) (flycheck-prospector . [(20180524 450) ((flycheck (0 22))) "Support prospector in flycheck" tar ((:commit . "d5b81adb5c8261b935baf0a614dd4b776280392e") (:authors ("Carlos Coelho" . "carlospecter@gmail.com")) (:maintainers ("Carlos Coelho" . "carlospecter@gmail.com")) (:maintainer "Carlos Coelho" . "carlospecter@gmail.com") (:url . "https://github.com/chocoelho/flycheck-prospector"))]) (flycheck-psalm . [(20211002 1555) ((emacs (24 3)) (flycheck (26)) (psalm (0 6 0))) "Flycheck integration for Psalm" tar ((:commit . "28d546a79cb865a78b94cd7e929d66d720505faa") (:authors ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainers ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:keywords "tools" "php") (:url . "https://github.com/emacs-php/psalm.el"))]) - (flycheck-pycheckers . [(20220923 2250) ((flycheck (0 18))) "multiple syntax checker for Python, using Flycheck" tar ((:commit . "897fba15787df94c1ce6a48551f1b149940ffc25") (:keywords "convenience" "tools" "languages") (:url . "https://github.com/msherry/flycheck-pycheckers"))]) + (flycheck-pycheckers . [(20240817 2) ((flycheck (0 18))) "multiple syntax checker for Python, using Flycheck" tar ((:commit . "1bd9b7a7d4009a81ebd34515a72a3a94c313ad76") (:keywords "convenience" "tools" "languages") (:url . "https://github.com/msherry/flycheck-pycheckers"))]) (flycheck-pyflakes . [(20240124 101) ((flycheck (0 18))) "Support pyflakes in flycheck" tar ((:commit . "60db5908747faf3831f055eddc6d3b5deafa7384") (:authors ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainers ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainer "Wilfred Hughes" . "me@wilfred.me.uk"))]) (flycheck-pyre . [(20190215 1222) ((emacs (24)) (flycheck (29)) (cl-lib (0 6))) "Support Pyre in flycheck" tar ((:commit . "0560122caae207d99d8af1ac2b4e5d6f6a1ce444") (:authors ("Vyacheslav Linnik" . "vyacheslav.linnik@gmail.com")) (:maintainers ("Vyacheslav Linnik" . "vyacheslav.linnik@gmail.com")) (:maintainer "Vyacheslav Linnik" . "vyacheslav.linnik@gmail.com") (:url . "https://github.com/linnik/flycheck-pyre"))]) (flycheck-raku . [(20220420 732) ((emacs (26 3)) (flycheck (0 22))) "Raku support in Flycheck" tar ((:commit . "4da1970a75396aff1957b07f7579c1de6b817e6b") (:authors ("Hinrik rn Sigurðsson" . "hinrik.sig@gmail.com") ("Johnathon Weare" . "jrweare@gmail.com") ("Siavash Askari Nasr" . "siavash.askari.nasr@gmail.com")) (:maintainers ("Hinrik rn Sigurðsson" . "hinrik.sig@gmail.com") ("Johnathon Weare" . "jrweare@gmail.com") ("Siavash Askari Nasr" . "siavash.askari.nasr@gmail.com")) (:maintainer "Hinrik rn Sigurðsson" . "hinrik.sig@gmail.com") (:keywords "tools" "convenience") (:url . "https://github.com/Raku/flycheck-raku"))]) @@ -1962,7 +1962,7 @@ (foreign-regexp . [(20200325 50) nil "search and replace by foreign regexp." tar ((:commit . "e2dd47f2160cadc194eb156e7c76c3c869e6706e") (:authors ("K-talo Miyazaki" . "KeitarodotMiyazakiatgmaildotcom")) (:maintainers ("K-talo Miyazaki" . "KeitarodotMiyazakiatgmaildotcom")) (:maintainer "K-talo Miyazaki" . "KeitarodotMiyazakiatgmaildotcom") (:keywords "convenience" "emulations" "matching" "tools" "unix" "wp"))]) (foreman-mode . [(20170725 1422) ((s (1 9 0)) (dash (2 10 0)) (dash-functional (1 2 0)) (f (0 17 2)) (emacs (24))) "View and manage Procfile-based applications" tar ((:commit . "22b3bb13134b617870ed1e888af739f4818be929") (:authors ("ZHOU Feng" . "zf.pascal@gmail.com")) (:maintainers ("ZHOU Feng" . "zf.pascal@gmail.com")) (:maintainer "ZHOU Feng" . "zf.pascal@gmail.com") (:keywords "foreman") (:url . "http://github.com/zweifisch/foreman-mode"))]) (forest-blue-theme . [(20160627 842) ((emacs (24))) "Emacs theme with a dark background." tar ((:commit . "58096ce1a25615d2bae806c3775bae3e2775019d"))]) - (forge . [(20240813 156) ((emacs (27 1)) (compat (30 0 0 0)) (closql (2 0 0)) (dash (2 19 1)) (emacsql (4 0 0)) (ghub (4 0 0)) (let-alist (1 0 6)) (magit (4 0 0)) (markdown-mode (2 6)) (seq (2 24)) (transient (0 7 4)) (yaml (0 5 5))) "Access Git forges from Magit." tar ((:commit . "2f5e03f18d604806dd6be090e419b11bceffdece") (:authors ("Jonas Bernoulli" . "emacs.forge@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.forge@jonas.bernoulli.dev") (:keywords "git" "tools" "vc") (:url . "https://github.com/magit/forge"))]) + (forge . [(20240818 1047) ((emacs (27 1)) (compat (30 0 0 0)) (closql (2 0 0)) (dash (2 19 1)) (emacsql (4 0 0)) (ghub (4 0 0)) (let-alist (1 0 6)) (magit (4 0 0)) (markdown-mode (2 6)) (seq (2 24)) (transient (0 7 4)) (yaml (0 5 5))) "Access Git forges from Magit." tar ((:commit . "6aebd0d3a5569fe1d8c797c83769fcaac549880d") (:authors ("Jonas Bernoulli" . "emacs.forge@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.forge@jonas.bernoulli.dev") (:keywords "git" "tools" "vc") (:url . "https://github.com/magit/forge"))]) (form-feed . [(20210508 1627) ((emacs (24 1))) "Display ^L glyphs as horizontal lines" tar ((:commit . "ac1f0ef30a11979f5dfe12d8c05a666739e486ff") (:authors ("Vasilij Schneidermann" . "mail@vasilij.de")) (:maintainers ("Vasilij Schneidermann" . "mail@vasilij.de")) (:maintainer "Vasilij Schneidermann" . "mail@vasilij.de") (:keywords "faces") (:url . "https://depp.brause.cc/form-feed"))]) (form-feed-st . [(20231002 2211) ((emacs (25 1))) "Display ^L glyphs as full-width horizontal lines" tar ((:commit . "f91c8daf35b7588e0aa24c8716c8cfd8ff0067c8") (:keywords "faces") (:url . "https://github.com/leodag/form-feed-st"))]) (format-all . [(20240511 1811) ((emacs (24 4)) (inheritenv (0 1)) (language-id (0 20))) "Auto-format C, C++, JS, Python, Ruby and 50 other languages" tar ((:commit . "c5ddfc5f3317eaa2a7541a818a0fce961e5e61dd") (:authors ("Lassi Kortela" . "lassi@lassi.io")) (:maintainers ("Lassi Kortela" . "lassi@lassi.io")) (:maintainer "Lassi Kortela" . "lassi@lassi.io") (:keywords "languages" "util") (:url . "https://github.com/lassik/emacs-format-all-the-code"))]) @@ -2023,7 +2023,7 @@ (gather . [(20141230 1338) nil "Gather string in buffer." tar ((:commit . "8909c886d72a682710bb79ccfcfe4df54a399b7e") (:authors ("Masahiro Hayashi" . "mhayashi1120@gmail.com")) (:maintainers ("Masahiro Hayashi" . "mhayashi1120@gmail.com")) (:maintainer "Masahiro Hayashi" . "mhayashi1120@gmail.com") (:keywords "matching" "convenience" "tools") (:url . "https://github.com/mhayashi1120/Emacs-gather/raw/master/gather.el"))]) (gcmh . [(20201116 2251) ((emacs (24))) "the Garbage Collector Magic Hack" tar ((:commit . "0089f9c3a6d4e9a310d0791cf6fa8f35642ecfd9") (:authors ("Andrea Corallo" . "akrl@sdf.org")) (:maintainers (nil . "akrl@sdf.org")) (:maintainer nil . "akrl@sdf.org") (:keywords "internal") (:url . "https://gitlab.com/koral/gcmh"))]) (gcode-mode . [(20230823 2141) ((emacs (24 4))) "Simple G-Code major mode" tar ((:commit . "4b54553a698d81e52dde14037df94774c7f30b95") (:authors ("Yuri D'Elia" . "wavexx@thregr.org")) (:maintainers ("Yuri D'Elia" . "wavexx@thregr.org")) (:maintainer "Yuri D'Elia" . "wavexx@thregr.org") (:keywords "gcode" "languages" "highlight" "syntax") (:url . "https://gitlab.com/wavexx/gcode-mode.el"))]) - (gdb-x . [(20240726 1306) ((emacs (29 1))) "Improve GDB-MI user interface" tar ((:commit . "6e1c8011b98bc32ef97e5c51d5306d7960d09065") (:authors ("Sergio Pastor Pérez" . "sergio.pastorperez@outlook.es")) (:maintainers ("Sergio Pastor Pérez" . "sergio.pastorperez@outlook.es")) (:maintainer "Sergio Pastor Pérez" . "sergio.pastorperez@outlook.es") (:keywords "extensions") (:url . "https://codeberg.org/shepherd/gdb-x"))]) + (gdb-x . [(20240814 2137) ((emacs (29 1))) "Improve GDB-MI user interface" tar ((:commit . "55dd7a427a83a9abd5719cd2920ab7d2c94ba558") (:authors ("Sergio Pastor Pérez" . "sergio.pastorperez@outlook.es")) (:maintainers ("Sergio Pastor Pérez" . "sergio.pastorperez@outlook.es")) (:maintainer "Sergio Pastor Pérez" . "sergio.pastorperez@outlook.es") (:keywords "extensions") (:url . "https://codeberg.org/shepherd/gdb-x"))]) (gdscript-mode . [(20240509 1523) ((emacs (26 3))) "Major mode for Godot's GDScript language" tar ((:commit . "32086df83335ce0e5120b21b80cf7996edb2232e") (:authors ("Nathan Lovato" . "nathan@gdquest.com") ("Fabián E. Gallina" . "fgallina@gnu.org")) (:maintainers (nil . "nathan@gdquest.com")) (:maintainer nil . "nathan@gdquest.com") (:keywords "languages") (:url . "https://github.com/godotengine/emacs-gdscript-mode/"))]) (geben . [(20220827 105) ((emacs (24 3)) (cl-lib (0 5))) "DBGp protocol frontend, a script debugger" tar ((:commit . "8df1ed2c8ff13b0ca4ef241c95c46f60a5a4fe3c") (:authors ("Matthew Carter" . "m@ahungry.com")) (:maintainers ("Matthew Carter" . "m@ahungry.com")) (:maintainer "Matthew Carter" . "m@ahungry.com") (:keywords "c" "comm" "tools") (:url . "https://github.com/ahungry/geben"))]) (geben-helm-projectile . [(20170524 334) ((emacs (24)) (geben (0 26)) (helm-projectile (0 13 0))) "Integrate helm-projectile with geben" tar ((:commit . "31ce0faca5dcc71924884f03fd5a7a25d00ccd9b") (:authors ("Matthew Carter" . "m@ahungry.com")) (:maintainers ("Matthew Carter" . "m@ahungry.com")) (:maintainer "Matthew Carter" . "m@ahungry.com") (:keywords "ahungry" "emacs" "geben" "helm" "projectile" "debug") (:url . "https://github.com/ahungry/geben-helm-projectile"))]) @@ -2061,7 +2061,7 @@ (gherkin-mode . [(20171224 1353) nil "An emacs major mode for editing gherkin files." tar ((:commit . "0313492e7da152f0aa73ddf96c0287ded8f51253") (:keywords "languages"))]) (ghost-blog . [(20171023 742) ((markdown-mode (1 0))) "A package to manage Ghost blog" tar ((:commit . "71b358643cc9a2db1bf752281ff94aba9b59e4cc") (:authors ("Javier Aguirre" . "hello@javaguirre.net")) (:maintainers ("Javier Aguirre" . "hello@javaguirre.net")) (:maintainer "Javier Aguirre" . "hello@javaguirre.net") (:keywords "ghost" "blog") (:url . "https://github.com/javaguirre/ghost-blog"))]) (ghq . [(20230510 332) ((emacs (26 1)) (dash (2 18 0)) (s (1 7 0))) "Ghq interface for emacs" tar ((:commit . "eb197c14e53ac57a136ea8d34eec7528487c3301") (:authors ("Roman Coedo" . "romancoedo@gmail.com")) (:maintainers ("Joseph LaFreniere" . "joseph@lafreniere.xyz")) (:maintainer "Joseph LaFreniere" . "joseph@lafreniere.xyz") (:keywords "convenience") (:url . "https://github.com/lafrenierejm/emacs-ghq"))]) - (ghub . [(20240808 1936) ((emacs (26 3)) (compat (30 0 0 0)) (let-alist (1 0 6)) (treepy (0 1 2))) "Client libraries for Git forge APIs." tar ((:commit . "c20bc86c70eb2f43df8674097db7847e172ef2c2") (:authors ("Jonas Bernoulli" . "emacs.ghub@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.ghub@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/magit/ghub"))]) + (ghub . [(20240817 2000) ((emacs (26 3)) (compat (30 0 0 0)) (let-alist (1 0 6)) (treepy (0 1 2))) "Client libraries for Git forge APIs." tar ((:commit . "32e579e47bbeb20b2e92950ca2b52d5ab0833403") (:authors ("Jonas Bernoulli" . "emacs.ghub@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.ghub@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/magit/ghub"))]) (ghub+ . [(20191229 1748) ((emacs (25)) (ghub (2 0)) (apiwrap (0 5))) "a thick GitHub API client built on ghub" tar ((:commit . "b1adef2402d7599911d4dd447a987a0cea04e6fe") (:authors ("Sean Allred" . "code@seanallred.com")) (:maintainers ("Sean Allred" . "code@seanallred.com")) (:maintainer "Sean Allred" . "code@seanallred.com") (:keywords "extensions" "multimedia" "tools") (:url . "https://github.com/vermiculus/ghub-plus"))]) (gif-screencast . [(20230728 1144) ((emacs (25 1))) "One-frame-per-action GIF recording" tar ((:commit . "6798656d3d3107d16e30cc26bc3928b00e50c1ca") (:authors ("Pierre Neidhardt" . "mail@ambrevar.xyz")) (:maintainers ("Pierre Neidhardt" . "mail@ambrevar.xyz")) (:maintainer "Pierre Neidhardt" . "mail@ambrevar.xyz") (:keywords "multimedia" "screencast") (:url . "https://gitlab.com/ambrevar/emacs-gif-screencast"))]) (gift-mode . [(20210528 1459) nil "major mode for editing GIFT format quizzes" tar ((:commit . "c93354e8fe1173b22f398f17b127875807f15b87") (:authors ("Christophe Rhodes" . "christophe@rhodes.io")) (:maintainers ("Christophe Rhodes" . "christophe@rhodes.io")) (:maintainer "Christophe Rhodes" . "christophe@rhodes.io") (:url . "https://github.com/csrhodes/gift-mode"))]) @@ -2213,7 +2213,7 @@ (gpt . [(20240721 1747) ((emacs (24 4))) "Run instruction-following language models" tar ((:commit . "06afbecccac8bf0d7a47b4c1b768a74ed66c5e84") (:authors ("Andreas Stuhlmueller" . "andreas@ought.org")) (:maintainers ("Andreas Stuhlmueller" . "andreas@ought.org")) (:maintainer "Andreas Stuhlmueller" . "andreas@ought.org") (:keywords "openai" "anthropic" "claude" "language" "copilot" "convenience" "tools") (:url . "https://github.com/stuhlmueller/gpt.el"))]) (gpt-commit . [(20230716 331) ((emacs (27 1)) (magit (2 90)) (request (0 3 2))) "Commit messages with GPT in Emacs" tar ((:commit . "8a8883be2051eed499c5bc3035a75ff56d64d5ff") (:authors ("Youngwook Kim" . "youngwook.kim@gmail.com")) (:maintainers ("Youngwook Kim" . "youngwook.kim@gmail.com")) (:maintainer "Youngwook Kim" . "youngwook.kim@gmail.com") (:url . "https://github.com/ywkim/gpt-commit"))]) (gptai . [(20230530 1853) ((emacs (24 1))) "Integrate with the OpenAI API" tar ((:commit . "e7b8b91b425986868e8bc0edcac384ba47d4d4b7") (:authors ("Anton Hibl" . "antonhibl11@gmail.com")) (:maintainers ("Anton Hibl" . "antonhibl11@gmail.com")) (:maintainer "Anton Hibl" . "antonhibl11@gmail.com") (:keywords "comm" "convenience") (:url . "https://github.com/antonhibl/gptai"))]) - (gptel . [(20240730 1931) ((emacs (27 1)) (transient (0 4 0)) (compat (29 1 4 1))) "Interact with ChatGPT or other LLMs" tar ((:commit . "73ec10831bf3ad85384ead962878b2437928def4") (:authors ("Karthik Chikmagalur" . "karthik.chikmagalur@gmail.com")) (:maintainers ("Karthik Chikmagalur" . "karthik.chikmagalur@gmail.com")) (:maintainer "Karthik Chikmagalur" . "karthik.chikmagalur@gmail.com") (:keywords "convenience") (:url . "https://github.com/karthink/gptel"))]) + (gptel . [(20240814 1558) ((emacs (27 1)) (transient (0 4 0)) (compat (29 1 4 1))) "Interact with ChatGPT or other LLMs" tar ((:commit . "17f39f6a8144496252eacc012ef7f1d6a2ac883a") (:authors ("Karthik Chikmagalur" . "karthik.chikmagalur@gmail.com")) (:maintainers ("Karthik Chikmagalur" . "karthik.chikmagalur@gmail.com")) (:maintainer "Karthik Chikmagalur" . "karthik.chikmagalur@gmail.com") (:keywords "convenience") (:url . "https://github.com/karthink/gptel"))]) (gpx . [(20240609 2200) ((emacs (27 1))) "Major mode for GPX files" tar ((:commit . "88aa5fed1b0987d90f442eb002ab0f2e4731e223") (:authors ("Michał Krzywkowski" . "k.michal@zoho.com")) (:maintainers ("Michał Krzywkowski" . "k.michal@zoho.com")) (:maintainer "Michał Krzywkowski" . "k.michal@zoho.com") (:keywords "data" "tools") (:url . "https://github.com/mkcms/gpx-mode"))]) (grab-mac-link . [(20210511 1303) ((emacs (24))) "Grab link from Mac Apps and insert it into Emacs" tar ((:commit . "5fdb03bf57bc4a530374b896e0f8b5139dc794e3") (:keywords "mac" "hyperlink") (:url . "https://github.com/xuchunyang/grab-mac-link.el"))]) (grab-x-link . [(20191113 848) ((emacs (24)) (cl-lib (0 5))) "Grab links from X11 apps and insert into Emacs" tar ((:commit . "d898db46e4864118359fdedfe915e180de3fe290") (:authors ("Xu Chunyang" . "mail@xuchunyang.me")) (:maintainers ("Xu Chunyang" . "mail@xuchunyang.me")) (:maintainer "Xu Chunyang" . "mail@xuchunyang.me") (:keywords "hyperlink") (:url . "https://github.com/xuchunyang/grab-x-link"))]) @@ -2241,7 +2241,7 @@ (grep-a-lot . [(20210618 1420) nil "manages multiple search results buffers for grep.el" tar ((:commit . "223819dbea049bdeb5f97f9849fce139a5f16a75") (:authors ("Avi Rozen" . "avi.rozen@gmail.com")) (:maintainers ("Avi Rozen" . "avi.rozen@gmail.com")) (:maintainer "Avi Rozen" . "avi.rozen@gmail.com") (:keywords "tools" "convenience" "search") (:url . "https://github.com/ZungBang/emacs-grep-a-lot"))]) (grey-paper-theme . [(20230415 1115) ((emacs (24 1))) "A greyscale theme with look-n-feel of an eink display" tar ((:commit . "4e5b8a31f586e2aa5c5d9bd939f0f518d919522e") (:authors ("Kang-min Liu" . "gugod@gugod.org")) (:maintainers ("Kang-min Liu" . "gugod@gugod.org")) (:maintainer "Kang-min Liu" . "gugod@gugod.org") (:keywords "faces") (:url . "https://github.com/gugod/grey-paper-theme"))]) (greymatters-theme . [(20150621 1123) ((emacs (24))) "Emacs 24 theme with a light background." tar ((:commit . "a7220a8c6cf18ccae2b76946b6f01188a7c9d5d1"))]) - (grip-mode . [(20230206 323) ((emacs (24 4))) "Instant GitHub-flavored Markdown/Org preview using grip." tar ((:commit . "bdee160db6ab8c988bb0de95ad306ff8b793ec67") (:authors ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainers ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Vincent Zhang" . "seagle0128@gmail.com") (:keywords "convenience" "markdown" "preview") (:url . "https://github.com/seagle0128/grip-mode"))]) + (grip-mode . [(20240817 1013) ((emacs (24 4))) "Instant GitHub-flavored Markdown/Org preview using grip." tar ((:commit . "378de9609614448ca29e2add91f2d0059f963d8c") (:authors ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainers ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Vincent Zhang" . "seagle0128@gmail.com") (:keywords "convenience" "markdown" "preview") (:url . "https://github.com/seagle0128/grip-mode"))]) (grizzl . [(20160818 737) ((cl-lib (0 5)) (emacs (24 3))) "Fast fuzzy search index for Emacs." tar ((:commit . "d554d93afa8519ee3a41340ec8aa6b4555065446") (:authors ("Chris Corbyn" . "chris@w3style.co.uk")) (:maintainers ("Bozhidar Batsov" . "bozhidar@batsov.com")) (:maintainer "Bozhidar Batsov" . "bozhidar@batsov.com") (:keywords "convenience" "usability") (:url . "https://github.com/grizzl/grizzl"))]) (groovy-imports . [(20210505 1807) ((emacs (24 4)) (s (1 10 0)) (pcache (0 3 2))) "Code for dealing with Groovy imports" tar ((:commit . "a60c3202973e3185091db623d960f71840a22205") (:keywords "groovy") (:url . "http://www.github.com/mbezjak/emacs-groovy-imports"))]) (groovy-mode . [(20230318 533) ((s (1 12 0)) (emacs (24 3)) (dash (2 13 0))) "Major mode for Groovy source files" tar ((:commit . "7b8520b2e2d3ab1d62b35c426e17ac25ed0120bb") (:authors ("Russel Winder" . "russel@winder.org.uk") ("Jim Morris" . "morris@wolfman.com") ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainers ("Russel Winder" . "russel@winder.org.uk")) (:maintainer "Russel Winder" . "russel@winder.org.uk") (:keywords "languages") (:url . "https://github.com/Groovy-Emacs-Modes/groovy-emacs-modes"))]) @@ -2308,8 +2308,8 @@ (headlong . [(20150417 1526) nil "reckless completion" tar ((:commit . "f6830f87f236eee88263cb6976125f72422abe72") (:authors ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainers ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainer "Oleh Krehel" . "ohwoeowho@gmail.com") (:keywords "completion") (:url . "https://github.com/abo-abo/headlong"))]) (heaven-and-hell . [(20190713 1830) ((emacs (24 4))) "easy toggle light/dark themes" tar ((:commit . "e1febfd60d060c110a1e43c5f093cd8537251308") (:authors ("Valentin Ignatev" . "valentignatev@gmail.com")) (:maintainers ("Valentin Ignatev" . "valentignatev@gmail.com")) (:maintainer "Valentin Ignatev" . "valentignatev@gmail.com") (:keywords "faces") (:url . "https://github.com/valignatev/heaven-and-hell"))]) (heex-ts-mode . [(20240113 1104) ((emacs (29 1))) "Major mode for Heex with tree-sitter support" tar ((:commit . "90142df2929956536dc1eaae3bb5ca04dc4232ab") (:keywords "heex" "languages" "tree-sitter") (:url . "https://github.com/wkirschbaum/elixir-ts-mode"))]) - (helix-theme . [(20240729 1203) nil "Color theme inspired by Helix editor's default colors" tar ((:commit . "fe1c95a93142020338a7de2a7984c5cd0018fbf4") (:keywords "faces") (:url . "https://github.com/ibakepunk/helix-theme"))]) - (helm . [(20240812 1744) ((helm-core (3 9 9)) (wfnames (1 2))) "Helm is an Emacs incremental and narrowing framework" tar ((:commit . "dc745dd55362471115f919bebc554f5c26da85f2") (:authors ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainers ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainer "Thierry Volpiatto" . "thievol@posteo.net") (:url . "https://emacs-helm.github.io/helm/"))]) + (helix-theme . [(20240814 1212) nil "Color theme inspired by Helix editor's default colors" tar ((:commit . "8c70b48fe5fbb392d237b6be2ae9da7b84236320") (:keywords "faces") (:url . "https://github.com/ibakepunk/helix-theme"))]) + (helm . [(20240818 1231) ((helm-core (3 9 9)) (wfnames (1 2))) "Helm is an Emacs incremental and narrowing framework" tar ((:commit . "eb5edc60be7294f9fa623c208bfdb681fbe2a3f1") (:authors ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainers ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainer "Thierry Volpiatto" . "thievol@posteo.net") (:url . "https://emacs-helm.github.io/helm/"))]) (helm-R . [(20120820 14) ((helm (20120517)) (ess (20120509))) "helm-sources and some utilities for GNU R." tar ((:commit . "b0eb9d5f6a483a9dbe6eb6cf1f2024d4f5938bc2") (:authors ("myuhe" . "yuhei.maeda_at_gmail.com")) (:keywords "convenience") (:url . "https://github.com/myuhe/helm-R.el"))]) (helm-ack . [(20141030 1226) ((helm (1 0)) (cl-lib (0 5))) "Ack command with helm interface" tar ((:commit . "5982f3cb6ec9f460ebbe06ec0ce7b3590bca3118") (:authors ("Syohei YOSHIDA" . "syohex@gmail.com")) (:maintainers ("Syohei YOSHIDA" . "syohex@gmail.com")) (:maintainer "Syohei YOSHIDA" . "syohex@gmail.com") (:url . "https://github.com/syohex/emacs-helm-ack"))]) (helm-ad . [(20151209 1015) ((dash (2 8 0)) (helm (1 6 2))) "helm source for Active Directory" tar ((:commit . "8ac044705d8620ee354a9cfa8cc1b865e83c0d55") (:authors ("Takahiro Noda" . "takahiro.noda+github@gmail.com")) (:maintainers ("Takahiro Noda" . "takahiro.noda+github@gmail.com")) (:maintainer "Takahiro Noda" . "takahiro.noda+github@gmail.com") (:keywords "comm"))]) @@ -2343,7 +2343,7 @@ (helm-comint . [(20231102 2029) ((emacs (25 1)) (helm (3 9 4))) "Comint prompt navigation for helm" tar ((:commit . "9215b2aa8f42f62cbda66a1503832abb7f491549") (:authors ("Pierre Neidhardt" . "mail@ambrevar.xyz")) (:maintainers ("Benedict Wang" . "foss@bhw.name")) (:maintainer "Benedict Wang" . "foss@bhw.name") (:keywords "processes" "matching") (:url . "https://github.com/benedicthw/helm-comint.git"))]) (helm-commandlinefu . [(20150611 545) ((emacs (24 1)) (helm (1 7 0)) (json (1 3)) (let-alist (1 0 3))) "Search and browse commandlinefu.com from helm" tar ((:commit . "9ee7e018c5db23ae9c8d1c8fa969876f15b7280d") (:authors ("Chunyang Xu" . "xuchunyang56@gmail.com")) (:maintainers ("Chunyang Xu" . "xuchunyang56@gmail.com")) (:maintainer "Chunyang Xu" . "xuchunyang56@gmail.com") (:keywords "commandlinefu.com") (:url . "https://github.com/xuchunyang/helm-commandlinefu"))]) (helm-company . [(20231113 701) ((helm (1 5 9)) (company (0 10 0))) "Helm interface for company-mode" tar ((:commit . "4622b82353220ee6cc33468f710fa5b6b253b7f1") (:authors ("Yasuyuki Oka" . "yasuyk@gmail.com")) (:maintainers ("Daniel Ralston" . "Sodel-the-Vociferous@users.noreply.github.com")) (:maintainer "Daniel Ralston" . "Sodel-the-Vociferous@users.noreply.github.com") (:url . "https://github.com/Sodel-the-Vociferous/helm-company"))]) - (helm-core . [(20240813 1920) ((emacs (25 1)) (async (1 9 8))) "Development files for Helm" tar ((:commit . "8eead4b760e5b5a14e917cd0a5103705164e1536") (:authors ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainers ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainer "Thierry Volpiatto" . "thievol@posteo.net") (:url . "https://emacs-helm.github.io/helm/"))]) + (helm-core . [(20240818 528) ((emacs (25 1)) (async (1 9 8))) "Development files for Helm" tar ((:commit . "36a6b50f325be94f30c6cf699ede042fa907c6b1") (:authors ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainers ("Thierry Volpiatto" . "thievol@posteo.net")) (:maintainer "Thierry Volpiatto" . "thievol@posteo.net") (:url . "https://emacs-helm.github.io/helm/"))]) (helm-cscope . [(20190615 41) ((xcscope (1 0)) (helm (1 6 7)) (cl-lib (0 5)) (emacs (24 1))) "Helm interface for xcscope.el." tar ((:commit . "af1d9e7f4460a88d7400b5a74d5da68084089ac1") (:authors ("alpha22jp" . "alpha22jp@gmail.com")) (:maintainers ("alpha22jp" . "alpha22jp@gmail.com")) (:maintainer "alpha22jp" . "alpha22jp@gmail.com") (:keywords "cscope" "helm") (:url . "https://github.com/alpha22jp/helm-cscope.el"))]) (helm-css-scss . [(20230522 1113) ((emacs (24 3)) (helm (1 0))) "CSS/SCSS/LESS Selectors with helm interface" tar ((:commit . "2169d83d8fdc661241df208cb3235112735d936e") (:keywords "convenience" "scss" "css" "less" "selector" "helm") (:url . "https://github.com/ShingoFukuyama/helm-css-scss"))]) (helm-ctest . [(20220721 400) ((s (1 9 0)) (dash (2 11 0)) (helm-core (3 6 0))) "Run ctest from within emacs" tar ((:commit . "48edc9fa862219da34feb423c06c33d8f6d43722") (:authors ("Dan LaManna" . "me@danlamanna.com")) (:maintainers ("Dan LaManna" . "me@danlamanna.com")) (:maintainer "Dan LaManna" . "me@danlamanna.com") (:keywords "helm" "ctest"))]) @@ -2595,8 +2595,8 @@ (hydandata-light-theme . [(20190809 1925) nil "A light color theme that is easy on your eyes" tar ((:commit . "812ffa4bee3163098ef66ee4506feed45018be4e") (:authors ("David Chkhikvadze" . "david@chkhd.net")) (:maintainers ("David Chkhikvadze" . "david@chkhd.net")) (:maintainer "David Chkhikvadze" . "david@chkhd.net") (:keywords "color-theme" "theme") (:url . "https://github.com/chkhd/hydandata-light-theme"))]) (hyde . [(20160508 308) nil "Major mode to help create and manage Jekyll blogs" tar ((:commit . "a8cd6ed00ecd8d7de0ded2f4867015b412b15b76"))]) (hydra . [(20220910 1206) ((cl-lib (0 5)) (lv (0))) "Make bindings that stick around." tar ((:commit . "317e1de33086637579a7aeb60f77ed0405bf359b") (:authors ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainers ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainer "Oleh Krehel" . "ohwoeowho@gmail.com") (:keywords "bindings") (:url . "https://github.com/abo-abo/hydra"))]) - (hyperbole . [(20240814 558) ((emacs (27 1))) "GNU Hyperbole: The Everyday Hypertextual Information Manager" tar ((:commit . "690126165df951912291c89fccf847756cda7620") (:authors ("Robert Weiner" . "rsw@gnu.org")) (:maintainers ("Mats Lidell" . "matsl@gnu.org")) (:maintainer "Mats Lidell" . "matsl@gnu.org") (:keywords "comm" "convenience" "files" "frames" "hypermedia" "languages" "mail" "matching" "mouse" "multimedia" "outlines" "tools" "wp") (:url . "http://www.gnu.org/software/hyperbole"))]) - (hyperdrive . [(20240812 1909) ((emacs (28 1)) (map (3 0)) (compat (30 0 0 0)) (org (9 7 6)) (plz (0 9 0)) (persist (0 6 1)) (taxy-magit-section (0 13)) (transient (0 7 4))) "P2P filesystem" tar ((:commit . "468cda16f0529e05a60570af18d5e1a9ef877cd5") (:authors ("Joseph Turner" . "joseph@ushin.org")) (:maintainers ("Joseph Turner" . "~ushin/ushin@lists.sr.ht")) (:maintainer "Joseph Turner" . "~ushin/ushin@lists.sr.ht") (:url . "https://git.sr.ht/~ushin/hyperdrive.el"))]) + (hyperbole . [(20240817 2202) ((emacs (27 1))) "GNU Hyperbole: The Everyday Hypertextual Information Manager" tar ((:commit . "f2fc8e5307b4cd0f42e76d36c0988c1b8f21de17") (:authors ("Robert Weiner" . "rsw@gnu.org")) (:maintainers ("Mats Lidell" . "matsl@gnu.org")) (:maintainer "Mats Lidell" . "matsl@gnu.org") (:keywords "comm" "convenience" "files" "frames" "hypermedia" "languages" "mail" "matching" "mouse" "multimedia" "outlines" "tools" "wp") (:url . "http://www.gnu.org/software/hyperbole"))]) + (hyperdrive . [(20240817 2227) ((emacs (28 1)) (map (3 0)) (compat (30 0 0 0)) (org (9 7 6)) (plz (0 9 1)) (persist (0 6 1)) (taxy-magit-section (0 14)) (transient (0 7 4))) "P2P filesystem" tar ((:commit . "43fec5b95a11dc37831d846cb0e2ae1af93ef72f") (:authors ("Joseph Turner" . "joseph@ushin.org")) (:maintainers ("Joseph Turner" . "~ushin/ushin@lists.sr.ht")) (:maintainer "Joseph Turner" . "~ushin/ushin@lists.sr.ht") (:url . "https://git.sr.ht/~ushin/hyperdrive.el"))]) (hyperkitty . [(20220226 1951) ((request (0 3 2)) (emacs (25 1))) "Emacs interface for Hyperkitty archives" tar ((:commit . "2c1d22ff017d096c359aa151e6a29f7214a58118") (:authors ("Abhilash Raj" . "maxking@asynchronous.in")) (:maintainers ("Abhilash Raj" . "maxking@asynchronous.in")) (:maintainer "Abhilash Raj" . "maxking@asynchronous.in") (:keywords "mail" "hyperkitty" "mailman") (:url . "https://github.com/maxking/hyperkitty.el"))]) (hyperlist-mode . [(20230119 28) ((emacs (24))) "A major-mode for viewing Hyperlists" tar ((:commit . "480dbf33ca72e7b5fade952aaf0d5a5eb43acb1d") (:keywords "outlines") (:url . "https://github.com/vifon/hyperlist-mode"))]) (hyperspace . [(20230518 442) ((emacs (25)) (s (1 12 0))) "Get there from here" tar ((:commit . "f574d07fd8715e806ba4f0487b73c699963baed3") (:authors ("Ian Eure" . "ian@retrospec.tv")) (:maintainers ("Ian Eure" . "ian@retrospec.tv")) (:maintainer "Ian Eure" . "ian@retrospec.tv") (:keywords "tools" "convenience") (:url . "https://github.com/ieure/hyperspace-el"))]) @@ -2737,7 +2737,7 @@ (ipp . [(20230714 1021) ((cl-lib (0 5)) (emacs (24 1))) "Implementation of the Internet Printing Protocol" tar ((:commit . "2b9359ca49acc558fe15622f63e2d31843cdc1f5") (:authors ("Eric Marsden" . "eric.marsden@risk-engineering.org")) (:maintainers ("Eric Marsden" . "eric.marsden@risk-engineering.org")) (:maintainer "Eric Marsden" . "eric.marsden@risk-engineering.org") (:keywords "printing" "hardware") (:url . "https://github.com/emarsden/ipp-el"))]) (ipretty . [(20180606 522) nil "Interactive Emacs Lisp pretty-printing" tar ((:commit . "042f5cc4e6f81d59115e8335c582bb5c571c2585") (:keywords "pretty-print" "elisp" "buffer") (:url . "https://framagit.org/steckerhalter/ipretty"))]) (ipython-shell-send . [(20190220 2246) ((emacs (24))) "Send code (including magics) to ipython shell" tar ((:commit . "0faed86faff02a361f23ce5fc923d0e9b09bb2da") (:authors ("Jack Kamm" . "jackkamm@gmail.com")) (:maintainers ("Jack Kamm" . "jackkamm@gmail.com")) (:maintainer "Jack Kamm" . "jackkamm@gmail.com") (:keywords "tools" "processes") (:url . "https://github.com/jackkamm/ipython-shell-send-el"))]) - (iqa . [(20200520 1137) ((emacs (24 3))) "Init file(and directory) Quick Access" tar ((:commit . "03f90a2f68b2f05d8a2509bf3612a337d3d5b67f") (:url . "https://github.com/a13/iqa.el"))]) + (iqa . [(20201113 849) ((emacs (24 3))) "Init file(and directory) Quick Access" tar ((:commit . "eed962679783133e1ff6ae63d19efaeae4dadb6b") (:url . "https://github.com/a13/iqa.el"))]) (ir-black-theme . [(20130303 755) nil "Port of ir-black theme" tar ((:commit . "ee6078bc67cbc15184e64e0f1fc8542d4079d55f") (:authors ("Jon-Michael Deldin" . "dev@jmdeldin.com")) (:maintainers ("Jon-Michael Deldin" . "dev@jmdeldin.com")) (:maintainer "Jon-Michael Deldin" . "dev@jmdeldin.com") (:keywords "faces"))]) (iregister . [(20150515 2107) nil "Interactive register commands for Emacs." tar ((:commit . "6a48c66187289de5f300492be11c83e98410c018") (:authors ("Andrey Tykhonov" . "atykhonov@gmail.com")) (:maintainers ("Andrey Tykhonov" . "atykhonov@gmail.com")) (:maintainer "Andrey Tykhonov" . "atykhonov@gmail.com") (:keywords "convenience") (:url . "https://github.com/atykhonov/iregister.el"))]) (irony . [(20231018 1915) ((cl-lib (0 5)) (json (1 2))) "C/C++ minor mode powered by libclang" tar ((:commit . "40e0ce19eb850bdf1f77225f11713cc816250d95") (:authors ("Guillaume Papin" . "guillaume.papin@epitech.eu")) (:maintainers ("Guillaume Papin" . "guillaume.papin@epitech.eu")) (:maintainer "Guillaume Papin" . "guillaume.papin@epitech.eu") (:keywords "c" "convenience" "tools") (:url . "https://github.com/Sarcasm/irony-mode"))]) @@ -2946,7 +2946,7 @@ (kfg . [(20140909 538) ((f (0 17 1))) "an emacs configuration system" tar ((:commit . "ffc35b77f227d4c64a1271ec30d31333ffeb0013") (:authors ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainers ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainer "Austin Bingham" . "austin.bingham@gmail.com") (:url . "https://github.com/abingham/kfg"))]) (khalel . [(20240527 527) ((emacs (27 1))) "Import, edit and create calendar events through khal" tar ((:commit . "14ef50352394cd1d62b80bc17ab14f4f801f47cd") (:authors ("Hanno Perrey" . "http://gitlab.com/hperrey")) (:maintainers ("Hanno Perrey" . "hanno@hoowl.se")) (:maintainer "Hanno Perrey" . "hanno@hoowl.se") (:keywords "event" "calendar" "ics" "khal") (:url . "https://gitlab.com/hperrey/khalel"))]) (khardel . [(20231126 1502) ((emacs (27 1)) (yaml-mode (0 0 13))) "Integrate with khard" tar ((:commit . "205e374b36252183a146a7a8f857bcf95a77edc3") (:authors ("Damien Cassou" . "damien@cassou.me")) (:maintainers ("Damien Cassou" . "damien@cassou.me")) (:maintainer "Damien Cassou" . "damien@cassou.me") (:url . "https://github.com/DamienCassou/khardel"))]) - (khoj . [(20240811 1030) ((emacs (27 1)) (transient (0 3 0)) (dash (2 19 1))) "Your Second Brain" tar ((:commit . "7815e02dd421b705461df6a97033dafd61ba6419") (:authors ("Debanjum Singh Solanky" . "debanjum@khoj.dev") ("Saba Imran" . "saba@khoj.dev")) (:maintainers ("Debanjum Singh Solanky" . "debanjum@khoj.dev") ("Saba Imran" . "saba@khoj.dev")) (:maintainer "Debanjum Singh Solanky" . "debanjum@khoj.dev") (:keywords "search" "chat" "ai" "org-mode" "outlines" "markdown" "pdf" "image") (:url . "https://github.com/khoj-ai/khoj/tree/master/src/interface/emacs"))]) + (khoj . [(20240816 1432) ((emacs (27 1)) (transient (0 3 0)) (dash (2 19 1))) "Your Second Brain" tar ((:commit . "2b1482d2b44efeface0aff6b7479e4c46aca72b1") (:authors ("Debanjum Singh Solanky" . "debanjum@khoj.dev") ("Saba Imran" . "saba@khoj.dev")) (:maintainers ("Debanjum Singh Solanky" . "debanjum@khoj.dev") ("Saba Imran" . "saba@khoj.dev")) (:maintainer "Debanjum Singh Solanky" . "debanjum@khoj.dev") (:keywords "search" "chat" "ai" "org-mode" "outlines" "markdown" "pdf" "image") (:url . "https://github.com/khoj-ai/khoj/tree/master/src/interface/emacs"))]) (kibit-helper . [(20150508 1533) ((s (0 8)) (emacs (24))) "Conveniently use the Kibit Leiningen plugin from Emacs" tar ((:commit . "ec5f154db3bb0c838e86f527353f08644cede926") (:authors ("James Elliott" . "james@brunchboy.com")) (:maintainers ("James Elliott" . "james@brunchboy.com")) (:maintainer "James Elliott" . "james@brunchboy.com") (:keywords "languages" "clojure" "kibit") (:url . "http://www.github.com/brunchboy/kibit-helper"))]) (kill-file-path . [(20230306 1041) ((emacs (26))) "Copy file name into kill ring" tar ((:commit . "5dcbce69cbae17665216a32dd20f27de54c62972") (:authors ("Adam Chyła" . "adam@chyla.org")) (:maintainers ("Adam Chyła" . "adam@chyla.org")) (:maintainer "Adam Chyła" . "adam@chyla.org") (:keywords "files") (:url . "https://github.com/chyla/kill-file-path/kill-file-path.el"))]) (kill-or-bury-alive . [(20230606 1503) ((emacs (24 4))) "Precise control over buffer killing" tar ((:commit . "16c393db6ad0c7e184af0a24d26b637e23543b1f") (:authors ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainers ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainer "Mark Karpov" . "markkarpov92@gmail.com") (:keywords "convenience") (:url . "https://github.com/mrkkrp/kill-or-bury-alive"))]) @@ -2958,7 +2958,7 @@ (kiwix . [(20220316 847) ((emacs (25 1)) (request (0 3 0))) "Searching offline Wikipedia through Kiwix." tar ((:commit . "444f686a7f75db788d54f544b923a3532732eb8b") (:authors ("stardiviner" . "numbchild@gmail.com")) (:maintainers ("stardiviner" . "numbchild@gmail.com")) (:maintainer "stardiviner" . "numbchild@gmail.com") (:keywords "kiwix" "wikipedia") (:url . "https://repo.or.cz/kiwix.el.git"))]) (kixtart-mode . [(20150611 1604) ((emacs (24))) "major mode for Kixtart scripting files" tar ((:commit . "1c2356797e7b766bbaaa2b341176a8b10499cd79") (:authors ("Ryrun" . "https://github.com/ryrun")) (:maintainers ("Ryrun" . "https://github.com/ryrun")) (:maintainer "Ryrun" . "https://github.com/ryrun") (:keywords "languages") (:url . "https://github.com/ryrun/kixtart-mode"))]) (kkp . [(20240227 1145) ((emacs (27 1)) (compat (29 1 3 4))) "Enable support for the Kitty Keyboard Protocol" tar ((:commit . "ed9214329f11b095fc7bad06feb329b9f232258d") (:authors ("Benjamin Orthen" . "contact@orthen.net")) (:maintainers ("Benjamin Orthen" . "contact@orthen.net")) (:maintainer "Benjamin Orthen" . "contact@orthen.net") (:keywords "terminals") (:url . "https://github.com/benjaminor/kkp"))]) - (klere-theme . [(20240123 124) ((emacs (24))) "A dark theme with lambent color highlights and incremental grays" tar ((:commit . "e73a01e69bf80f753a1603337fdc4b89e685219a") (:authors ("Wamm K. D." . "jaft.r@outlook.com")) (:maintainers ("Wamm K. D." . "jaft.r@outlook.com")) (:maintainer "Wamm K. D." . "jaft.r@outlook.com") (:url . "https://codeberg.org/WammKD/emacs-klere-theme"))]) + (klere-theme . [(20240815 454) ((emacs (24))) "A dark theme with lambent color highlights and incremental grays" tar ((:commit . "fec81fb9925cbcc4472f34ca9625ee310802cbf3") (:authors ("Wamm K. D." . "jaft.r@outlook.com")) (:maintainers ("Wamm K. D." . "jaft.r@outlook.com")) (:maintainer "Wamm K. D." . "jaft.r@outlook.com") (:url . "https://codeberg.org/WammKD/emacs-klere-theme"))]) (klondike . [(20240131 453) ((emacs (28 1))) "Klondike" tar ((:commit . "1cf14d7b6c14ebde741c36f6aa871dcd41e37cff") (:authors ("Wamm K. D." . "jaft.r@outlook.com")) (:maintainers ("Wamm K. D." . "jaft.r@outlook.com")) (:maintainer "Wamm K. D." . "jaft.r@outlook.com") (:keywords "games" "cards" "solitaire" "klondike") (:url . "https://codeberg.org/WammKD/Emacs-Klondike"))]) (kmacro-x . [(20240721 1103) ((emacs (27 2))) "Keyboard macro helpers and extensions" tar ((:commit . "3f58f5421b98b436122dba2514cf559a7359904d") (:keywords "convenience") (:url . "https://github.com/vifon/kmacro-x.el"))]) (know-your-http-well . [(20240726 1649) nil "Look up the meaning of HTTP headers, methods, relations, status codes" tar ((:commit . "2ff1548a6d59f2b59cfbdd2697fcf202625cc248"))]) @@ -3112,7 +3112,7 @@ (livescript-mode . [(20221015 1316) ((emacs (24 3))) "Major mode for editing LiveScript files" tar ((:commit . "e71a82a400e9d451c966c397bb8fa7887d35637b") (:authors ("Hisamatsu Yasuyuki" . "yas@null.net")) (:maintainers ("Hisamatsu Yasuyuki" . "yas@null.net")) (:maintainer "Hisamatsu Yasuyuki" . "yas@null.net") (:keywords "languages" "livescript") (:url . "https://github.com/yhisamatsu/livescript-mode"))]) (livid-mode . [(20131116 1344) ((skewer-mode (1 5 3)) (s (1 8 0))) "Live browser eval of JavaScript every time a buffer changes" tar ((:commit . "dfe5212fa64738bc4138bfebf349fbc8bc237c26") (:url . "https://github.com/pandeiro/livid-mode"))]) (ll-debug . [(20211002 1031) ((emacs (24 3))) "Low level debug tools" tar ((:commit . "a2cfeab46e5100c348b35987fae34f9ea76d7c0b") (:authors ("Claus Brunzema" . "mail@cbrunzema.de")) (:maintainers ("Claus Brunzema" . "mail@cbrunzema.de")) (:maintainer "Claus Brunzema" . "mail@cbrunzema.de") (:keywords "abbrev" "convenience" "tools" "c" "lisp") (:url . "https://github.com/replrep/ll-debug"))]) - (llama . [(20240811 23) (("emacs" (26 1))) "Compact syntax for short lambda" tar ((:commit . "d98debc6ca4c7cc86e9dd944b2393698802ef077") (:keywords "extensions") (:url . "https://github.com/tarsius/llama"))]) + (llama . [(20240817 1039) ((emacs (26 1))) "Compact syntax for short lambda" tar ((:commit . "732389e3886b510c2661d7d4fd65e01837211e8a") (:keywords "extensions") (:url . "https://github.com/tarsius/llama"))]) (llama-cpp . [(20240511 1039) ((emacs (27 1)) (dash (2 19 1))) "A client for llama-cpp server" tar ((:commit . "5cea3698aa63921b21888f126cae4f3ebc1baa39") (:authors ("Evgeny Kurnevsky" . "kurnevsky@gmail.com")) (:maintainers ("Evgeny Kurnevsky" . "kurnevsky@gmail.com")) (:maintainer "Evgeny Kurnevsky" . "kurnevsky@gmail.com") (:keywords "tools") (:url . "https://github.com/kurnevsky/llama.el"))]) (llvm-ts-mode . [(20231120 1251) ((emacs (29 1))) "LLVM major mode using tree-sitter" tar ((:commit . "9974601dcddbeffc4ad47598d63d3c1a83bb6fb9") (:authors ("Noah Peart" . "noah.v.peart@gmail.com")) (:maintainers ("Noah Peart" . "noah.v.peart@gmail.com")) (:maintainer "Noah Peart" . "noah.v.peart@gmail.com") (:keywords "languages" "tree-sitter" "llvm") (:url . "https://github.com/nverno/llvm-ts-mode"))]) (lms . [(20210820 2200) ((emacs (25 1))) "Squeezebox / Logitech Media Server frontend" tar ((:commit . "29593b4c18a570dfb2e60b196f24d407a1277daa") (:authors ("Iñigo Serna" . "inigoserna@gmx.com")) (:maintainers ("Iñigo Serna" . "inigoserna@gmx.com")) (:maintainer "Iñigo Serna" . "inigoserna@gmx.com") (:keywords "multimedia") (:url . "https://hg.serna.eu/emacs/lms"))]) @@ -3141,8 +3141,8 @@ (look-mode . [(20220626 641) nil "quick file viewer for image and text file browsing" tar ((:commit . "726c5b9098926278603a83e978b488371c0e9143") (:authors ("Peter H. Mao" . "petermao@jpl.nasa.gov")) (:maintainers ("Peter H. Mao" . "petermao@jpl.nasa.gov")) (:maintainer "Peter H. Mao" . "petermao@jpl.nasa.gov"))]) (loop . [(20160813 1407) nil "friendly imperative loop structures" tar ((:commit . "0ce77271d56b0fcdba4b3b38fed526081cd1f674") (:authors ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainers ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainer "Wilfred Hughes" . "me@wilfred.me.uk") (:keywords "loop" "while" "for each" "break" "continue"))]) (loophole . [(20221126 1556) ((emacs (27 1))) "Manage temporary key bindings" tar ((:commit . "dadc3fadc68b13501c4dbe89109f30deb0d3441a") (:authors ("0x60DF" . "0x60df@gmail.com")) (:maintainers ("0x60DF" . "0x60df@gmail.com")) (:maintainer "0x60DF" . "0x60df@gmail.com") (:keywords "convenience") (:url . "https://github.com/0x60df/loophole"))]) - (loopy . [(20240708 156) ((emacs (27 1)) (map (3 3 1)) (seq (2 22)) (compat (29 1 3)) (stream (2 3 0))) "A looping macro" tar ((:commit . "1c2a2164f24174a87194649f0286e0432594c84d") (:keywords "extensions") (:url . "https://github.com/okamsn/loopy"))]) - (loopy-dash . [(20240225 1740) ((emacs (25 1)) (loopy (0 12 3)) (dash (2 19))) "Dash destructuring for `loopy'" tar ((:commit . "eeebd2713d636b3cf08c6af22f46d23b9aa06592") (:keywords "extensions") (:url . "https://github.com/okamsn/loopy"))]) + (loopy . [(20240818 245) ((emacs (27 1)) (map (3 3 1)) (seq (2 22)) (compat (29 1 3)) (stream (2 3 0))) "A looping macro" tar ((:commit . "80a30903628bc8de36c51c966e6cf5b114001e47") (:keywords "extensions") (:url . "https://github.com/okamsn/loopy"))]) + (loopy-dash . [(20240818 245) ((emacs (25 1)) (loopy (0 13 0)) (dash (2 19))) "Dash destructuring for `loopy'" tar ((:commit . "80a30903628bc8de36c51c966e6cf5b114001e47") (:keywords "extensions") (:url . "https://github.com/okamsn/loopy"))]) (lorem-ipsum . [(20221214 1857) nil "Insert dummy pseudo Latin text" tar ((:commit . "4e87a899868e908a7a9e1812831d76c8d072f885") (:authors ("Jean-Philippe Theberge" . "(jphil21@sourceforge.net)")) (:maintainers ("Joe Schafer" . "(joe@jschaf.com)")) (:maintainer "Joe Schafer" . "(joe@jschaf.com)") (:keywords "tools" "language" "convenience") (:url . "https://github.com/jschaf/emacs-lorem-ipsum"))]) (lox-mode . [(20200619 1700) ((emacs (24 3))) "Major mode for the Lox programming language" tar ((:commit . "083a2299e188a516d1e46ef2dd1cbb89db1aec49") (:authors ("Timmy Jose" . "zoltan.jose@gmail.com")) (:maintainers ("Timmy Jose" . "zoltan.jose@gmail.com")) (:maintainer "Timmy Jose" . "zoltan.jose@gmail.com") (:keywords "languages" "lox") (:url . "https://github.com/timmyjose-projects/lox-mode"))]) (lpy . [(20231026 1525) ((emacs (25 1)) (lispy (0 27 0))) "A lispy interface to Python" tar ((:commit . "2c086ec162d4456b99a6095c3c335382a8304734") (:authors ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainers ("Oleh Krehel" . "ohwoeowho@gmail.com")) (:maintainer "Oleh Krehel" . "ohwoeowho@gmail.com") (:keywords "python" "lisp") (:url . "https://github.com/abo-abo/lpy"))]) @@ -3161,7 +3161,7 @@ (lsp-latex . [(20240803 1436) ((emacs (27 1)) (lsp-mode (6 0)) (consult (0 35))) "LSP-mode client for LaTeX, on texlab" tar ((:commit . "2f45606dce911ebc45a42cbbaa01973b8caff4ec") (:authors ("ROCKTAKEY" . "rocktakey@gmail.com")) (:maintainers ("ROCKTAKEY" . "rocktakey@gmail.com")) (:maintainer "ROCKTAKEY" . "rocktakey@gmail.com") (:keywords "languages" "tex") (:url . "https://github.com/ROCKTAKEY/lsp-latex"))]) (lsp-ltex . [(20240425 2049) ((emacs (27 1)) (lsp-mode (6 1))) "LSP Clients for LTEX" tar ((:commit . "c473ed37aa0f2769bb0b4c344cc28f95975dbc17") (:authors ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainers ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainer "Jen-Chieh" . "jcs090218@gmail.com") (:keywords "convenience" "lsp" "languagetool" "checker") (:url . "https://github.com/emacs-languagetool/lsp-ltex"))]) (lsp-metals . [(20240508 627) ((emacs (27 1)) (scala-mode (0 23)) (lsp-mode (7 0)) (lsp-treemacs (0 2)) (dap-mode (0 3)) (dash (2 18 0)) (f (0 20 0)) (ht (2 0)) (treemacs (3 1)) (posframe (1 4 1))) "Scala Client settings" tar ((:commit . "fa4072cbe7a7061cdb218b9a3619979f7facba0e") (:authors ("Ross A. Baker" . "ross@rossabaker.com") ("Evgeny Kurnevsky" . "kurnevsky@gmail.com")) (:maintainers ("Ross A. Baker" . "ross@rossabaker.com") ("Evgeny Kurnevsky" . "kurnevsky@gmail.com")) (:maintainer "Ross A. Baker" . "ross@rossabaker.com") (:keywords "languages" "extensions") (:url . "https://github.com/emacs-lsp/lsp-metals"))]) - (lsp-mode . [(20240801 2341) ((emacs (27 1)) (dash (2 18 0)) (f (0 20 0)) (ht (2 3)) (spinner (1 7 3)) (markdown-mode (2 3)) (lv (0)) (eldoc (1 11))) "LSP mode" tar ((:commit . "c8d8bd0f5c40123821bf7c90afa5b6abb05074cb") (:keywords "languages") (:url . "https://github.com/emacs-lsp/lsp-mode"))]) + (lsp-mode . [(20240817 1400) ((emacs (27 1)) (dash (2 18 0)) (f (0 20 0)) (ht (2 3)) (spinner (1 7 3)) (markdown-mode (2 3)) (lv (0)) (eldoc (1 11))) "LSP mode" tar ((:commit . "12befaabe4a1bf8a548bc820faa192be8ee89533") (:keywords "languages") (:url . "https://github.com/emacs-lsp/lsp-mode"))]) (lsp-mssql . [(20230510 1124) ((emacs (25 1)) (lsp-mode (6 2)) (dash (2 14 1)) (f (0 20 0)) (ht (2 0)) (lsp-treemacs (0 1))) "MSSQL LSP bindings" tar ((:commit . "a0dba8f86a2ace7e800a9dc8f814767625a509af") (:authors ("Ivan Yonchovski" . "yyoncho@gmail.com")) (:maintainers ("Ivan Yonchovski" . "yyoncho@gmail.com")) (:maintainer "Ivan Yonchovski" . "yyoncho@gmail.com") (:keywords "data" "languages") (:url . "https://github.com/emacs-lsp/lsp-mssql"))]) (lsp-origami . [(20230815 704) ((emacs (27 1)) (origami (1 0)) (lsp-mode (6 1))) "origami.el support for lsp-mode" tar ((:commit . "86aa06517910141c3d5054eea5f7723461fce6a6") (:keywords "languages" "lsp-mode") (:url . "https://github.com/emacs-lsp/lsp-origami"))]) (lsp-p4 . [(20190127 1049) ((lsp-mode (3 0))) "P4 support for lsp-mode" tar ((:commit . "084e33a5782f9153502d9b03e63d9cbbe81cdaeb") (:keywords "lsp" "p4") (:url . "https://github.com/dmakarov/p4ls"))]) @@ -3201,7 +3201,7 @@ (magic-filetype . [(20240130 1805) ((emacs (24 3)) (s (1 9 0))) "Enhance filetype major mode" tar ((:commit . "3979ddbd8066d7390e31bde2b35f997c5f5f4516") (:authors ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainers ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:keywords "emulations" "vim" "ft" "file" "magic-mode") (:url . "https://github.com/emacs-php/magic-filetype.el"))]) (magic-latex-buffer . [(20210306 422) ((cl-lib (0 5)) (emacs (25 1))) "Magically enhance LaTeX-mode font-locking for semi-WYSIWYG editing" tar ((:commit . "903ec91872760e47c0e5715795f8465173615098") (:url . "http://zk-phi.github.io/"))]) (magik-mode . [(20240814 914) ((emacs (24 4)) (compat (28 1))) "Emacs major mode for Smallworld Magik files" tar ((:commit . "e4b0ab1e97095973e7c40fed20e3acbfa1172823") (:keywords "languages") (:url . "https://github.com/roadrunner1776/magik"))]) - (magit . [(20240811 1419) ((emacs (26 1)) (compat (30 0 0 0)) (dash (20240510)) (git-commit (20240808)) (magit-section (20240808)) (seq (2 24)) (transient (20240805)) (with-editor (20240806))) "A Git porcelain inside Emacs." tar ((:commit . "a2739d7db1fdf19b95f36f6ddd15b0c1f523bd26") (:authors ("Marius Vollmer" . "marius.vollmer@gmail.com") ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") (:keywords "git" "tools" "vc") (:url . "https://github.com/magit/magit"))]) + (magit . [(20240818 1037) ((emacs (26 1)) (compat (30 0 0 0)) (dash (20240510)) (git-commit (20240808)) (magit-section (20240808)) (seq (2 24)) (transient (20240805)) (with-editor (20240806))) "A Git porcelain inside Emacs." tar ((:commit . "61f6a778ab5b0ca97069778a5955ae527996cd0f") (:authors ("Marius Vollmer" . "marius.vollmer@gmail.com") ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") (:keywords "git" "tools" "vc") (:url . "https://github.com/magit/magit"))]) (magit-annex . [(20240811 1850) ((emacs (26 1)) (magit (4 0 0))) "Control git-annex from Magit" tar ((:commit . "9db0bc61461f222106c7ae3d8cd6d3de1f1b143f") (:authors ("Kyle Meyer" . "kyle@kyleam.com") ("Rémi Vanicat" . "vanicat@debian.org")) (:maintainers ("Kyle Meyer" . "kyle@kyleam.com") ("Rémi Vanicat" . "vanicat@debian.org")) (:maintainer "Kyle Meyer" . "kyle@kyleam.com") (:keywords "vc" "tools") (:url . "https://github.com/magit/magit-annex"))]) (magit-commit-mark . [(20240421 931) ((emacs (29 1)) (magit (3 3 0))) "Support marking commits as read" tar ((:commit . "d09d0df6f8a697446e9fac77428b32997b94c59e") (:authors ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainers ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainer "Campbell Barton" . "ideasman42@gmail.com") (:url . "https://codeberg.org/ideasman42/emacs-magit-commit-mark"))]) (magit-delta . [(20220125 50) ((emacs (25 1)) (magit (20200426)) (xterm-color (2 0))) "Use Delta when displaying diffs in Magit" tar ((:commit . "5fc7dbddcfacfe46d3fd876172ad02a9ab6ac616") (:authors ("Dan Davison" . "dandavison7@gmail.com")) (:maintainers ("Dan Davison" . "dandavison7@gmail.com")) (:maintainer "Dan Davison" . "dandavison7@gmail.com") (:url . "https://github.com/dandavison/magit-delta"))]) @@ -3222,7 +3222,7 @@ (magit-popup . [(20200719 1015) ((emacs (24 4)) (dash (2 13 0))) "Define prefix-infix-suffix command combos" tar ((:commit . "d8585fa39f88956963d877b921322530257ba9f5") (:authors ("Jonas Bernoulli" . "jonas@bernoul.li")) (:maintainers ("Jonas Bernoulli" . "jonas@bernoul.li")) (:maintainer "Jonas Bernoulli" . "jonas@bernoul.li") (:keywords "bindings") (:url . "https://github.com/magit/magit-popup"))]) (magit-rbr . [(20181009 2016) ((magit (2 13 0)) (emacs (24 3))) "Support for git rbr in Magit" tar ((:commit . "029203b3e48537205052a058e964f058cd802c3c") (:authors ("Anatoly Fayngelerin" . "fanatoly+magitrbr@gmail.com")) (:maintainers ("Anatoly Fayngelerin" . "fanatoly+magitrbr@gmail.com")) (:maintainer "Anatoly Fayngelerin" . "fanatoly+magitrbr@gmail.com") (:keywords "git" "magit" "rbr" "tools") (:url . "https://github.com/fanatoly/magit-rbr"))]) (magit-reviewboard . [(20200727 1748) ((emacs (25 2)) (magit (2 13 0)) (s (1 12 0)) (request (0 3 0))) "Show open Reviewboard reviews in Magit" tar ((:commit . "aceedff88921f1dfef8a6b2fb18fe316fb7223a8") (:authors ("Jules Tamagnan" . "jtamagnan@gmail.com")) (:maintainers ("Jules Tamagnan" . "jtamagnan@gmail.com")) (:maintainer "Jules Tamagnan" . "jtamagnan@gmail.com") (:keywords "magit" "vc") (:url . "http://github.com/jtamagnan/magit-reviewboard"))]) - (magit-section . [(20240811 1419) ((emacs (26 1)) (compat (30 0 0 0)) (dash (20240510))) "Sections for read-only buffers." tar ((:commit . "a2739d7db1fdf19b95f36f6ddd15b0c1f523bd26") (:authors ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/magit/magit"))]) + (magit-section . [(20240818 1037) ((emacs (26 1)) (compat (30 0 0 0)) (dash (20240510))) "Sections for read-only buffers." tar ((:commit . "61f6a778ab5b0ca97069778a5955ae527996cd0f") (:authors ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") (:keywords "tools") (:url . "https://github.com/magit/magit"))]) (magit-stats . [(20230223 1819) ((emacs (25 1))) "Generates GIT Repo Statistics Report" tar ((:commit . "41b18e5fc664dba93981a7931f476632c5b54a7d") (:keywords "vc" "convenience") (:url . "https://github.com/LionyxML/magit-stats"))]) (magit-stgit . [(20231226 1514) ((emacs (24 4)) (magit (2 12 0)) (magit-popup (2 12 0))) "StGit extension for Magit" tar ((:commit . "59d1eb355caf4adbbdf1e351f5861de61b0b5efa") (:authors ("Lluís Vilanova" . "vilanova@ac.upc.edu")) (:maintainers ("Peter Grayson" . "pete@jpgrayson.net")) (:maintainer "Peter Grayson" . "pete@jpgrayson.net") (:keywords "git" "tools" "vc") (:url . "https://github.com/stacked-git/magit-stgit"))]) (magit-svn . [(20220314 1451) ((emacs (25 1)) (magit (2 90 1)) (transient (0 3 2))) "Git-Svn extension for Magit" tar ((:commit . "b8277081db90977247ae3900ea6afeb0ca644d36") (:authors ("Phil Jackson" . "phil@shellarchive.co.uk")) (:maintainers ("Phil Jackson" . "phil@shellarchive.co.uk")) (:maintainer "Phil Jackson" . "phil@shellarchive.co.uk") (:keywords "vc" "tools"))]) @@ -3276,7 +3276,7 @@ (marshal . [(20201223 1853) ((emacs (25 1)) (ht (2 0))) "eieio extension for automatic (un)marshalling" tar ((:commit . "490496d974d03906f784707ecc2e0ac36ed84b96") (:authors ("Yann Hodique" . "yann.hodique@gmail.com")) (:maintainers ("Yann Hodique" . "yann.hodique@gmail.com")) (:maintainer "Yann Hodique" . "yann.hodique@gmail.com") (:keywords "extensions") (:url . "https://github.com/sigma/marshal.el"))]) (maruo-macro-mode . [(20160616 1349) ((emacs (24 3))) "Major mode for editing Hidemaru/Maruo macro script" tar ((:commit . "8fc9a38ad051eafa8eb94038711acc52c5d1d8d5") (:authors ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainers ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:keywords "programming" "editor" "macro"))]) (masm-mode . [(20200308 1450) ((emacs (25 1))) "MASM x86 and x64 assembly major mode" tar ((:commit . "ab63524d195332ec9f703783704231606e69c292") (:authors ("YiGeeker" . "zyfchinese@yeah.net")) (:maintainers ("YiGeeker" . "zyfchinese@yeah.net")) (:maintainer "YiGeeker" . "zyfchinese@yeah.net") (:keywords "languages") (:url . "https://github.com/YiGeeker/masm-mode"))]) - (mastodon . [(20240804 751) ((emacs (27 1)) (request (0 3 0)) (persist (0 4))) "Client for fediverse services using the Mastodon API" tar ((:commit . "45903de823d3c6b46c4aa694112e9f5429e1a3f9") (:authors ("Johnson Denen" . "johnson.denen@gmail.com") ("Marty Hiatt" . "martianhiatus@riseup.net")) (:maintainers ("Marty Hiatt" . "martianhiatus@riseup.net")) (:maintainer "Marty Hiatt" . "martianhiatus@riseup.net") (:url . "https://codeberg.org/martianh/mastodon.el"))]) + (mastodon . [(20240816 709) ((emacs (27 1)) (request (0 3 0)) (persist (0 4))) "Client for fediverse services using the Mastodon API" tar ((:commit . "3443b49c55f65ae8e0b07e93e1e0299ce1bf8ed6") (:authors ("Johnson Denen" . "johnson.denen@gmail.com") ("Marty Hiatt" . "martianhiatus@riseup.net")) (:maintainers ("Marty Hiatt" . "martianhiatus@riseup.net")) (:maintainer "Marty Hiatt" . "martianhiatus@riseup.net") (:url . "https://codeberg.org/martianh/mastodon.el"))]) (material-theme . [(20210904 1226) ((emacs (24 1))) "A Theme based on the colors of the Google Material Design" tar ((:commit . "6823009bc92f82aa3a90e27e1009f7da8e87b648") (:authors ("Christoph Paulik" . "cpaulik@gmail.com")) (:maintainers ("Christoph Paulik" . "cpaulik@gmail.com")) (:maintainer "Christoph Paulik" . "cpaulik@gmail.com") (:keywords "themes") (:url . "http://github.com/cpaulik/emacs-material-theme"))]) (math-preview . [(20240801 513) ((emacs (26 1)) (json (1 4)) (dash (2 18 0)) (s (1 12 0))) "Preview TeX math equations inline" tar ((:commit . "a2ca3c175468ceaf02bab6cdfd8ef016bda2b98d") (:keywords "convenience") (:url . "https://gitlab.com/matsievskiysv/math-preview"))]) (math-symbol-lists . [(20220828 2047) nil "Lists of Unicode math symbols and latex commands" tar ((:commit . "ac3eb053d3b576fcdd192b0ac6ad5090ea3a7079") (:authors ("Vitalie Spinu" . "spinuvit@gmail.com")) (:maintainers ("Vitalie Spinu" . "spinuvit@gmail.com")) (:maintainer "Vitalie Spinu" . "spinuvit@gmail.com") (:keywords "unicode" "symbols" "mathematics") (:url . "https://github.com/vspinu/math-symbol-lists"))]) @@ -3298,7 +3298,7 @@ (media-progress . [(20230805 2231) ((emacs (28 1))) "Display position where media player stopped" tar ((:commit . "951742e9e741a71bf527a23bf56deeedb12af7bd") (:authors ("Dmitriy Pshonko" . "http://github.com/jumper047")) (:maintainers ("Dmitriy Pshonko" . "http://github.com/jumper047")) (:maintainer "Dmitriy Pshonko" . "http://github.com/jumper047") (:keywords "files" "convenience") (:url . "https://github.com/jumper047/media-progress"))]) (media-progress-dired . [(20230527 2209) ((emacs (28 1)) (media-progress (0 1 0))) "Display position where media player stopped in dired buffer" tar ((:commit . "438a37019383eef35e45875b3e4df3fca4eaf39f") (:authors ("Dmitriy Pshonko" . "http://github.com/jumper047")) (:maintainers ("Dmitriy Pshonko" . "http://github.com/jumper047")) (:maintainer "Dmitriy Pshonko" . "http://github.com/jumper047") (:keywords "files" "convenience") (:url . "https://github.com/jumper047/media-progress"))]) (media-progress-dirvish . [(20230520 1547) ((emacs (28 1)) (dirvish (2 0 0)) (media-progress (0 1 0))) "Display position where media player stopped in dirvish" tar ((:commit . "ec777d2d200ecb85795a225b482808f048c30a1c") (:authors ("Dmitriy Pshonko" . "http://github.com/jumper047")) (:maintainers ("Dmitriy Pshonko" . "http://github.com/jumper047")) (:maintainer "Dmitriy Pshonko" . "http://github.com/jumper047") (:keywords "files" "convenience") (:url . "https://github.com/jumper047/media-progress"))]) - (media-thumbnail . [(20220827 2325) ((emacs (28 1))) "Utility package to provide media icons" tar ((:commit . "14e626fe7ee714ab45c9e636d00a26e89aa2832a") (:authors ("James Nguyen" . "james@jojojames.com")) (:maintainers ("James Nguyen" . "james@jojojames.com")) (:maintainer "James Nguyen" . "james@jojojames.com") (:keywords "files" "tools") (:url . "https://github.com/jojojames/media-thumbnail"))]) + (media-thumbnail . [(20240816 458) ((emacs (28 1))) "Utility package to provide media icons" tar ((:commit . "190632c1d6cc2ab94031d57e0c24412a4698faf0") (:authors ("James Nguyen" . "james@jojojames.com")) (:maintainers ("James Nguyen" . "james@jojojames.com")) (:maintainer "James Nguyen" . "james@jojojames.com") (:keywords "files" "tools") (:url . "https://github.com/jojojames/media-thumbnail"))]) (mediawiki . [(20220923 1336) nil "mediawiki frontend" tar ((:commit . "c28cf78d4fe4969df3af8dcc2adaf71c4212e5ad") (:authors ("Mark A. Hershberger" . "mah@everybody.org")) (:maintainers ("Mark A. Hershberger" . "mah@everybody.org")) (:maintainer "Mark A. Hershberger" . "mah@everybody.org") (:keywords "mediawiki" "wikipedia" "network" "wiki") (:url . "https://github.com/hexmode/mediawiki-el"))]) (meghanada . [(20220101 505) ((emacs (24 3)) (yasnippet (0 6 1)) (company (0 9 0)) (flycheck (0 23))) "A better java development mode" tar ((:commit . "59c46cabb7eee715fe810ce59424934a1286df84") (:authors ("Yutaka Matsubara" . "(yutaka.matsubara@gmail.com)")) (:maintainers ("Yutaka Matsubara" . "(yutaka.matsubara@gmail.com)")) (:maintainer "Yutaka Matsubara" . "(yutaka.matsubara@gmail.com)") (:keywords "languages" "java") (:url . "https://github.com/mopemope/meghanada-emacs"))]) (melancholy-theme . [(20240417 136) ((emacs (27 1))) "A dark theme that's pretty sad -*- lexical-binding: t; -" tar ((:commit . "7ba2bb3f062e798236bfb589381691c5bd9a22be") (:authors ("@baaash" . "bleat@baaa.sh")) (:maintainers ("@baaash" . "bleat@baaa.sh")) (:maintainer "@baaash" . "bleat@baaa.sh") (:keywords "faces" "frames") (:url . "https://gitlab.com/baaash/melancholy-theme"))]) @@ -3348,7 +3348,7 @@ (mindstream . [(20240803 126) ((emacs (25 1)) (magit (3 3 0))) "Start writing, stay focused, don't worry" tar ((:commit . "6a7d7b4fe496ff6bec27d52addd23947f81cb843") (:authors ("Siddhartha Kasivajhula" . "sid@countvajhula.com")) (:maintainers ("Siddhartha Kasivajhula" . "sid@countvajhula.com")) (:maintainer "Siddhartha Kasivajhula" . "sid@countvajhula.com") (:keywords "convenience" "files" "languages" "outlines" "tools" "vc" "wp") (:url . "https://github.com/countvajhula/mindstream"))]) (minesweeper . [(20200416 2342) nil "play minesweeper in Emacs" tar ((:commit . "d4248e3c9b3e9e7277cb9e6d081330611898f334") (:authors ("Zachary Kanfer" . "zkanfer@gmail.com")) (:maintainers ("Zachary Kanfer" . "zkanfer@gmail.com")) (:maintainer "Zachary Kanfer" . "zkanfer@gmail.com") (:keywords "game" "fun" "minesweeper" "inane" "diversion") (:url . "https://hg.sr.ht/~zck/minesweeper"))]) (mingus . [(20230518 1726) ((libmpdee (2 2))) "MPD Interface" tar ((:commit . "3fa9b95552eb062eb245321abb7f442c458618dc") (:authors ("Niels Giesen" . "pfton#emacs")) (:maintainers ("Niels Giesen" . "pfton#emacs")) (:maintainer "Niels Giesen" . "pfton#emacs") (:keywords "multimedia" "elisp" "music" "mpd") (:url . "https://github.com/pft/mingus"))]) - (mini-echo . [(20240612 1328) ((emacs (29 1)) (dash (2 19 1)) (hide-mode-line (1 0 3))) "Echo buffer status in minibuffer window" tar ((:commit . "802321f0658b364d4e9d90a4ac43959d46048015") (:authors ("liuyinz" . "liuyinz95@gmail.com")) (:maintainers ("liuyinz" . "liuyinz95@gmail.com")) (:maintainer "liuyinz" . "liuyinz95@gmail.com") (:keywords "frames") (:url . "https://github.com/liuyinz/mini-echo.el"))]) + (mini-echo . [(20240816 2131) ((emacs (29 1)) (dash (2 19 1)) (hide-mode-line (1 0 3))) "Echo buffer status in minibuffer window" tar ((:commit . "3f97d443554a7e98b68e541e2886f8a64f54d8b2") (:authors ("liuyinz" . "liuyinz95@gmail.com")) (:maintainers ("liuyinz" . "liuyinz95@gmail.com")) (:maintainer "liuyinz" . "liuyinz95@gmail.com") (:keywords "frames") (:url . "https://github.com/liuyinz/mini-echo.el"))]) (mini-frame . [(20220627 2041) ((emacs (26 1))) "Show minibuffer in child frame on read-from-minibuffer" tar ((:commit . "60838f3cab438dcbda8eaa15ab3e5d1af88910e9") (:authors ("Andrii Kolomoiets" . "andreyk.mad@gmail.com")) (:maintainers ("Andrii Kolomoiets" . "andreyk.mad@gmail.com")) (:maintainer "Andrii Kolomoiets" . "andreyk.mad@gmail.com") (:keywords "frames") (:url . "https://github.com/muffinmad/emacs-mini-frame"))]) (mini-header-line . [(20170621 1221) ((emacs (24 4))) "a minimal header-line" tar ((:commit . "73b6724e0a26c4528d93768191c8aa59e6bce2e5") (:keywords "header-line" "mode-line") (:url . "https://github.com/ksjogo/mini-header-line"))]) (mini-modeline . [(20230306 1521) ((emacs (25 1)) (dash (2 12 0))) "Display modeline in minibuffer" tar ((:commit . "86e753b6c38a06b0fc80d7560aa6a25245fd4d38") (:authors ("Kien Nguyen" . "kien.n.quang@gmail.com")) (:maintainers ("Kien Nguyen" . "kien.n.quang@gmail.com")) (:maintainer "Kien Nguyen" . "kien.n.quang@gmail.com") (:keywords "convenience" "tools") (:url . "https://github.com/kiennq/emacs-mini-modeline"))]) @@ -3529,7 +3529,7 @@ (nemerle . [(20161029 2023) nil "major mode for editing nemerle programs" tar ((:commit . "8818c5af5598e16ea59189e1e3245f0a3d7c78f0") (:authors ("Jacek Sliwerski" . "rzyj@o2.pl")) (:maintainers ("Jacek Sliwerski" . "rzyj@o2.pl")) (:maintainer "Jacek Sliwerski" . "rzyj@o2.pl") (:keywords "nemerle" "mode" "languages"))]) (neon-mode . [(20180406 1156) nil "Simple major mode for editing neon files" tar ((:commit . "99d15e46beaf1e7d71e39a00cce810df1f33229d") (:authors ("Matúš Goljer" . "matus.goljer@gmail.com")) (:maintainers ("Matúš Goljer" . "matus.goljer@gmail.com")) (:maintainer "Matúš Goljer" . "matus.goljer@gmail.com") (:keywords "conf"))]) (neotree . [(20240721 233) ((cl-lib (0 5))) "A tree plugin like NerdTree for Vim" tar ((:commit . "599bd049a5d9cfab8a0d7ab7bec99d58b4581751") (:authors ("jaypei" . "jaypei97159@gmail.com")) (:maintainers ("jaypei" . "jaypei97159@gmail.com")) (:maintainer "jaypei" . "jaypei97159@gmail.com") (:url . "https://github.com/jaypei/emacs-neotree"))]) - (nerd-icons . [(20240808 625) ((emacs (24 3))) "Emacs Nerd Font Icons Library" tar ((:commit . "dcfc64152ada7514bcdd1c6ce45590c359445ec6") (:authors ("Hongyu Ding" . "rainstormstudio@yahoo.com") ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainers ("Hongyu Ding" . "rainstormstudio@yahoo.com") ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Hongyu Ding" . "rainstormstudio@yahoo.com") (:keywords "lisp") (:url . "https://github.com/rainstormstudio/nerd-icons.el"))]) + (nerd-icons . [(20240816 1555) ((emacs (24 3))) "Emacs Nerd Font Icons Library" tar ((:commit . "c3d641d8e14bd11b5f98372da34ee5313636e363") (:authors ("Hongyu Ding" . "rainstormstudio@yahoo.com") ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainers ("Hongyu Ding" . "rainstormstudio@yahoo.com") ("Vincent Zhang" . "seagle0128@gmail.com")) (:maintainer "Hongyu Ding" . "rainstormstudio@yahoo.com") (:keywords "lisp") (:url . "https://github.com/rainstormstudio/nerd-icons.el"))]) (nerd-icons-completion . [(20240731 1213) ((emacs (25 1)) (nerd-icons (0 0 1)) (compat (30))) "Add icons to completion candidates" tar ((:commit . "426a1d7c29a04ae8e6ae9b55b0559f11a1e8b420") (:authors ("Hongyu Ding" . "rainstormstudio@yahoo.com")) (:maintainers ("Hongyu Ding" . "rainstormstudio@yahoo.com")) (:maintainer "Hongyu Ding" . "rainstormstudio@yahoo.com") (:keywords "lisp") (:url . "https://github.com/rainstormstudio/nerd-icons-completion"))]) (nerd-icons-corfu . [(20231019 1618) ((emacs (27 1)) (nerd-icons (0 1 0))) "Icons for Corfu via nerd-icons" tar ((:commit . "7077bb76fefc15aed967476406a19dc5c2500b3c") (:authors ("Luigi Sartor Piucco" . "luigipiucco@gmail.com")) (:maintainers ("Luigi Sartor Piucco" . "luigipiucco@gmail.com")) (:maintainer "Luigi Sartor Piucco" . "luigipiucco@gmail.com") (:keywords "convenience" "files" "icons") (:url . "https://github.com/LuigiPiucco/nerd-icons-corfu"))]) (nerd-icons-dired . [(20231214 2155) ((emacs (24 4)) (nerd-icons (0 0 1))) "Shows icons for each file in dired mode" tar ((:commit . "c1c73488630cc1d19ce1677359f614122ae4c1b9") (:authors ("Hongyu Ding" . "rainstormstudio@yahoo.com")) (:maintainers ("Hongyu Ding" . "rainstormstudio@yahoo.com")) (:maintainer "Hongyu Ding" . "rainstormstudio@yahoo.com") (:keywords "lisp") (:url . "https://github.com/rainstormstudio/nerd-icons-dired"))]) @@ -3601,7 +3601,7 @@ (northcode-theme . [(20180423 1649) ((emacs (24))) "A dark theme focused on blue and orange colors." tar ((:commit . "4d3750461ba25ec45321318b5f1af4e8fdf16147") (:authors ("Andreas Larsen" . "andreas@northcode.no")) (:maintainers ("Andreas Larsen" . "andreas@northcode.no")) (:maintainer "Andreas Larsen" . "andreas@northcode.no") (:url . "https://github.com/Northcode/northcode-theme.el"))]) (nothing-theme . [(20200504 402) ((emacs (24 1))) "Monochrome theme" tar ((:commit . "17fc9ecc94af0c919a24c4fe92bb48890bb4c3b0") (:authors (nil . "jaredgorski6@gmail.com")) (:maintainers (nil . "jaredgorski6@gmail.com")) (:maintainer nil . "jaredgorski6@gmail.com") (:url . "https://github.com/jaredgorski/nothing.el"))]) (notink-theme . [(20240625 326) ((emacs (26 1))) "A custom theme inspired by e-ink displays" tar ((:commit . "d1e84622a491bb570d6a450706833fafaad74f39") (:authors ("MetroWind" . "chris.corsair@gmail.com")) (:maintainers ("MetroWind" . "chris.corsair@gmail.com")) (:maintainer "MetroWind" . "chris.corsair@gmail.com") (:keywords "faces") (:url . "https://github.com/MetroWind/notink-theme"))]) - (notmuch . [(20240809 1318) nil "run notmuch within emacs" tar ((:commit . "4e85abda157eac8888809b2dde885f60f312a5fb") (:url . "https://notmuchmail.org"))]) + (notmuch . [(20240816 2039) nil "run notmuch within emacs" tar ((:commit . "2355ff274d3694fc79c655bb45c61245fb9a9302") (:url . "https://notmuchmail.org"))]) (notmuch-addr . [(20240805 1915) ((emacs (27 1)) (compat (30 0 0 0)) (notmuch (0 38))) "Improved address completion for Notmuch" tar ((:commit . "0d07e6fc9aff0f632a0d8aa9bd91ffccbef34e3b") (:authors ("Jonas Bernoulli" . "emacs.notmuch-addr@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.notmuch-addr@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.notmuch-addr@jonas.bernoulli.dev") (:keywords "mail") (:url . "https://git.sr.ht/~tarsius/notmuch-addr"))]) (notmuch-bookmarks . [(20230727 1504) ((seq (2 20)) (emacs (26 1)) (notmuch (0 29 3))) "Add bookmark handling for notmuch buffers" tar ((:commit . "7c053fd2d278dc3a9f07f86975867bfbb4e7448d") (:authors ("Jörg Volbers" . "joerg@joergvolbers.de")) (:maintainers ("Jörg Volbers" . "joerg@joergvolbers.de")) (:maintainer "Jörg Volbers" . "joerg@joergvolbers.de") (:keywords "mail") (:url . "https://github.com/publicimageltd/notmuch-bookmarks"))]) (notmuch-labeler . [(20131230 1719) ((notmuch (0))) "Improve notmuch way of displaying labels" tar ((:commit . "d65d1129555d368243df4770ecc1e7ccb88efc58") (:authors ("Damien Cassou" . "damien.cassou@gmail.com")) (:maintainers ("Damien Cassou" . "damien.cassou@gmail.com")) (:maintainer "Damien Cassou" . "damien.cassou@gmail.com") (:keywords "emacs" "package" "elisp" "notmuch" "emails") (:url . "https://github.com/DamienCassou/notmuch-labeler"))]) @@ -3858,13 +3858,13 @@ (org-kindle . [(20220210 1408) ((emacs (25)) (cl-lib (0 5)) (seq (2 20))) "Send org link file to ebook reader." tar ((:commit . "fadcfd62e254d0c45e87d63128a82a08ae21869a") (:keywords "org" "link" "ebook" "kindle" "epub" "azw3" "mobi") (:url . "https://repo.or.cz/org-kindle.git"))]) (org-latex-impatient . [(20221111 623) ((emacs (26)) (s (1 8 0)) (posframe (0 8 0)) (org (9 3)) (dash (2 17 0))) "Preview org-latex Fragments Instantly via MathJax" tar ((:commit . "031025a8be9bf7255aa047388d027642cd2d6183") (:authors ("Sheng Yang" . "styang@fastmail.com")) (:maintainers ("Sheng Yang" . "styang@fastmail.com")) (:maintainer "Sheng Yang" . "styang@fastmail.com") (:keywords "tex" "tools") (:url . "https://github.com/yangsheng6810/org-latex-instant-preview"))]) (org-linenote . [(20240410 410) ((emacs (29 1)) (projectile (2 8 0)) (vertico (1 7))) "A package inspired by VSCode Linenote" tar ((:commit . "a015295ebf271c8b518238f7969a0b6e60429805") (:authors ("Jason Kim" . "sukbeom.kim@gmail.com")) (:maintainers ("Jason Kim" . "sukbeom.kim@gmail.com")) (:maintainer "Jason Kim" . "sukbeom.kim@gmail.com") (:keywords "tools" "note" "org") (:url . "https://github.com/seokbeomKim/org-linenote"))]) - (org-link-beautify . [(20240804 320) ((emacs (29 1)) (nerd-icons (0 0 1)) (fb2-reader (0 1 1)) (qrencode (1 2))) "Beautify Org Links" tar ((:commit . "c87fe4af31f9fdc8717762360355944458c0af0b") (:keywords "hypermedia") (:url . "https://repo.or.cz/org-link-beautify.git"))]) + (org-link-beautify . [(20240818 400) ((emacs (29 1)) (nerd-icons (0 0 1)) (fb2-reader (0 1 1)) (qrencode (1 2))) "Beautify Org Links" tar ((:commit . "950095639fdac279022464e1f1efc602e704d1f0") (:keywords "hypermedia") (:url . "https://repo.or.cz/org-link-beautify.git"))]) (org-link-travis . [(20140405 2327) ((org (7))) "Insert/Export the link of Travis CI on org-mode" tar ((:commit . "596615ad8373d9090bd4138da683524f0ad0bda5") (:authors ("Hiroaki Otsu" . "ootsuhiroaki@gmail.com")) (:maintainers ("Hiroaki Otsu" . "ootsuhiroaki@gmail.com")) (:maintainer "Hiroaki Otsu" . "ootsuhiroaki@gmail.com") (:keywords "org") (:url . "https://github.com/aki2o/org-link-travis"))]) (org-linkotron . [(20200112 2235) ((emacs (26 1)) (org (9 3))) "Org-mode link selector" tar ((:commit . "d0adc5247b205bc73d2f1a83d4a512d2be541eb5") (:authors ("Per Weijnitz" . "per.weijnitz@gmail.com")) (:maintainers ("Per Weijnitz" . "per.weijnitz@gmail.com")) (:maintainer "Per Weijnitz" . "per.weijnitz@gmail.com") (:keywords "hypermedia" "org") (:url . "https://gitlab.com/perweij/org-linkotron"))]) (org-listcruncher . [(20210706 1741) ((seq (2 3)) (emacs (26 1))) "Planning tool - Parse Org mode lists into table" tar ((:commit . "075e0e6d36eb50406a608bc8a2f0dd359ec63938") (:authors ("Derek Feichtinger" . "dfeich@gmail.com")) (:maintainers ("Derek Feichtinger" . "dfeich@gmail.com")) (:maintainer "Derek Feichtinger" . "dfeich@gmail.com") (:keywords "convenience") (:url . "https://github.com/dfeich/org-listcruncher"))]) (org-mac-link . [(20231016 2047) ((emacs (27 1))) "Insert org-mode links to items selected in various Mac apps" tar ((:commit . "e30171a6e98db90787ab8a23b3a7dc4fd13b10f9") (:authors ("Anthony Lander" . "anthony.lander@gmail.com") ("John Wiegley" . "johnw@gnu.org") ("Christopher Suckling" . "sucklingatgmaildotcom") ("Daniil Frumin" . "difrumin@gmail.com") ("Alan Schmitt" . "alan.schmitt@polytechnique.org") ("Mike McLean" . "mike.mclean@pobox.com")) (:maintainers ("Aimé Bertrand" . "aime.bertrand@macowners.club")) (:maintainer "Aimé Bertrand" . "aime.bertrand@macowners.club") (:keywords "files" "wp" "url" "org") (:url . "https://gitlab.com/aimebertrand/org-mac-link"))]) (org-make-toc . [(20240229 724) ((emacs (26 1)) (dash (2 12)) (s (1 10 0)) (org (9 3)) (compat (29 1))) "Automatic tables of contents for Org files" tar ((:commit . "3ac2024694a9f974a7d263748642182fc7e829d1") (:authors ("Adam Porter" . "adam@alphapapa.net")) (:maintainers ("Adam Porter" . "adam@alphapapa.net")) (:maintainer "Adam Porter" . "adam@alphapapa.net") (:keywords "org" "convenience") (:url . "http://github.com/alphapapa/org-make-toc"))]) - (org-mime . [(20240129 2327) ((emacs (25 1))) "org html export for text/html MIME emails" tar ((:commit . "9d4584651d89806b79d5993b286d32d6f70499a9") (:maintainers ("Chen Bin" . "chenbin.sh@gmail.com")) (:maintainer "Chen Bin" . "chenbin.sh@gmail.com") (:keywords "mime" "mail" "email" "html") (:url . "http://github.com/org-mime/org-mime"))]) + (org-mime . [(20240818 243) ((emacs (27 1))) "org html export for text/html MIME emails" tar ((:commit . "468604b8404d3c7d6148be83a4cf308ee95d2cfb") (:maintainers ("Chen Bin" . "chenbin.sh@gmail.com")) (:maintainer "Chen Bin" . "chenbin.sh@gmail.com") (:keywords "mime" "mail" "email" "html") (:url . "http://github.com/org-mime/org-mime"))]) (org-mind-map . [(20180826 2340) ((emacs (24)) (dash (1 8 0)) (org (8 2 10))) "Creates a directed graph from org-mode files" tar ((:commit . "41df4b2e30455494f1848b4e06cc9208aa9e902b") (:authors ("Ted Wiles" . "theodore.wiles@gmail.com")) (:maintainers ("Ted Wiles" . "theodore.wiles@gmail.com")) (:maintainer "Ted Wiles" . "theodore.wiles@gmail.com") (:keywords "orgmode" "extensions" "graphviz" "dot") (:url . "https://github.com/theodorewiles/org-mind-map"))]) (org-ml . [(20230410 30) ((emacs (27 1)) (org (9 3)) (dash (2 17)) (s (1 12))) "Functional Org Mode API" tar ((:commit . "f57336a9126a168ad32ccce017c072474555395a") (:authors ("Nathan Dwarshuis" . "ndwar@yavin4.ch")) (:maintainers ("Nathan Dwarshuis" . "ndwar@yavin4.ch")) (:maintainer "Nathan Dwarshuis" . "ndwar@yavin4.ch") (:keywords "org-mode" "outlines") (:url . "https://github.com/ndwarshuis/org-ml"))]) (org-mobile-sync . [(20180606 524) ((emacs (24 3 50)) (org (8 0))) "automatically sync org-mobile on changes" tar ((:commit . "06764b943a528827df1e2acc6bc7806cc2c1351f") (:keywords "org-mode" "org" "mobile" "sync" "todo") (:url . "https://framagit.org/steckerhalter/org-mobile-sync"))]) @@ -3991,7 +3991,7 @@ (orglue . [(20200411 311) ((org (9 3)) (epic (0 2))) "more functionality to org-mode." tar ((:commit . "9d5a8e24be9acb8c55bb4d6aa8b98e30e2677401") (:authors ("Yoshinari Nomura" . "nom@quickhack.net")) (:maintainers ("Yoshinari Nomura" . "nom@quickhack.net")) (:maintainer "Yoshinari Nomura" . "nom@quickhack.net") (:keywords "org"))]) (orgmdb . [(20231003 2144) ((emacs (27 1)) (dash (2 11 0)) (s (1 12 0)) (org (8 0 0))) "An OMDb API client with some convenience functions" tar ((:commit . "4338a0a34d500a214df8293590960011f761fe24") (:authors ("Isa Mert Gurbuz" . "isamert@protonmail.com")) (:maintainers ("Isa Mert Gurbuz" . "isamert@protonmail.com")) (:maintainer "Isa Mert Gurbuz" . "isamert@protonmail.com") (:url . "https://github.com/isamert/orgmdb"))]) (orgnav . [(20170608 1713) ((helm (2 7 0)) (s (1 11 0)) (dash (1 11 0)) (emacs (24))) "Org tree navigation using helm" tar ((:commit . "9e2cac9c1a67af5f0080e60022e821bf7b70312d") (:authors ("Facet Framer" . "(facet@facetframer.com)")) (:maintainers ("Facet Framer" . "(facet@facetframer.com)")) (:maintainer "Facet Framer" . "(facet@facetframer.com)") (:keywords "convenience" "outlines") (:url . "http://github.com/facetframer/orgnav"))]) - (orgnote . [(20240813 2022) ((emacs (27 1))) "Sync org-roam notes with OrgNote app" tar ((:commit . "ed9dae520af7560ce4235c9ce4847f257e32cf4e") (:authors ("Artur Yaroshenko" . "artawower@protonmail.com")) (:maintainers ("Artur Yaroshenko" . "artawower@protonmail.com")) (:maintainer "Artur Yaroshenko" . "artawower@protonmail.com") (:url . "https://github.com/Artawower/orgnote.el"))]) + (orgnote . [(20240814 2021) ((emacs (27 1))) "Sync org-roam notes with OrgNote app" tar ((:commit . "d2d0c8d16ea2dbcc29b79f9d4a48e03e90c3f57d") (:authors ("Artur Yaroshenko" . "artawower@protonmail.com")) (:maintainers ("Artur Yaroshenko" . "artawower@protonmail.com")) (:maintainer "Artur Yaroshenko" . "artawower@protonmail.com") (:url . "https://github.com/Artawower/orgnote.el"))]) (orgstrap . [(20230408 2232) ((emacs (24 4))) "Bootstrap an Org file using file local variables" tar ((:commit . "f35bccde556b0f82515e79ee69f4379469276356") (:keywords "lisp" "org" "org-mode" "bootstrap") (:url . "https://github.com/tgbugs/orgstrap"))]) (orgtbl-aggregate . [(20240616 506) ((emacs (26 1))) "Create an aggregated Org table from another one" tar ((:commit . "f343b6009d87630588d39dc3d92651008c1bad13") (:keywords "data" "extensions") (:url . "https://github.com/tbanel/orgaggregate/blob/master/README.org"))]) (orgtbl-ascii-plot . [(20230122 816) nil "ascii-art bar plots in org-mode tables" tar ((:commit . "4160128045b271bc1aef3d14dbf0c5b53ae58bd2") (:keywords "org" "table" "ascii" "plot"))]) @@ -4017,7 +4017,7 @@ (otama . [(20160404 1032) nil "Org-table Manipulator" tar ((:commit . "b69e0740846ace7885b0c0717f7abe8d0419eefd") (:authors ("Yoshinari Nomura" . "nom@quickhack.net")) (:maintainers ("Yoshinari Nomura" . "nom@quickhack.net")) (:maintainer "Yoshinari Nomura" . "nom@quickhack.net") (:keywords "database" "org-mode"))]) (other-emacs-eval . [(20180408 1348) ((emacs (25 1)) (async (1 9 2))) "Evaluate the Emacs Lisp expression in other Emacs" tar ((:commit . "8ace5acafef65daabf0c6619eff60733d7f5d792") (:authors ("Xu Chunyang" . "mail@xuchunyang.me")) (:maintainers ("Xu Chunyang" . "mail@xuchunyang.me")) (:maintainer "Xu Chunyang" . "mail@xuchunyang.me") (:keywords "tools") (:url . "https://github.com/xuchunyang/other-emacs-eval"))]) (ouroboros . [(20230606 1150) ((emacs (27 1)) (dash (2 19 0)) (cbor (0 2 5)) (bech32 (0 2 1))) "Ouroboros network mini-protocol" tar ((:commit . "cf85424b305e8f89debb756dc67eebc84639f711") (:authors ("Oscar Najera" . "https://oscarnajera.com")) (:maintainers ("Oscar Najera" . "hi@oscarnajera.com")) (:maintainer "Oscar Najera" . "hi@oscarnajera.com") (:url . "https://github.com/Titan-C/cardano.el"))]) - (outline-indent . [(20240805 312) ((emacs (25 1))) "Outline and fold text using indentation" tar ((:commit . "37c991a72af62c9db7a75c8ccc046f60a846a914") (:keywords "outlines") (:url . "https://github.com/jamescherti/outline-indent.el"))]) + (outline-indent . [(20240817 1840) ((emacs (26 1))) "Outline and fold text using indentation" tar ((:commit . "4cc2a57e1125104cd94430524d3b4e2b4701d78b") (:keywords "outlines") (:url . "https://github.com/jamescherti/outline-indent.el"))]) (outline-magic . [(20180619 1819) nil "outline mode extensions for Emacs" tar ((:commit . "2a5f07417b696cf7541d435c43bafcc64817636b") (:authors ("Carsten Dominik" . "dominik@science.uva.nl")) (:maintainers ("Thorsten Jolitz" . "tjolitzATgmailDOTcom")) (:maintainer "Thorsten Jolitz" . "tjolitzATgmailDOTcom") (:keywords "outlines"))]) (outline-minor-faces . [(20240809 2322) ((emacs (26 1)) (compat (30 0 0 0))) "Highlight only section headings" tar ((:commit . "5f227d165ca002d692fa80a71e727956b59568b6") (:authors ("Jonas Bernoulli" . "emacs.outline-minor-faces@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.outline-minor-faces@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.outline-minor-faces@jonas.bernoulli.dev") (:keywords "faces" "outlines") (:url . "https://github.com/tarsius/outline-minor-faces"))]) (outline-toc . [(20200401 1208) nil "Sidebar showing a \"table of contents\"." tar ((:commit . "81d373633b40628cc3a6b6fb534fd7730076bcdb") (:authors ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainers ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainer "Austin Bingham" . "austin.bingham@gmail.com") (:keywords "convenience" "outlines") (:url . "https://github.com/abingham/outline-toc.el"))]) @@ -4056,7 +4056,6 @@ (ox-minutes . [(20180202 1734) ((emacs (24 4))) "Plain text backend for Org for Meeting Minutes" tar ((:commit . "27c29f3fdb9181322ae56f8bace8d95e621230e5") (:authors ("Kaushal Modi" . "kaushal.modi@gmail.com")) (:maintainers ("Kaushal Modi" . "kaushal.modi@gmail.com")) (:maintainer "Kaushal Modi" . "kaushal.modi@gmail.com") (:keywords "org" "exporter" "notes") (:url . "https://github.com/kaushalmodi/ox-minutes"))]) (ox-nikola . [(20151114 1116) ((emacs (24 4)) (org (8 2 4)) (ox-rst (0 2))) "Export Nikola articles using org-mode." tar ((:commit . "5bcbc1a38f6619f62294194f13ca0cd4ca14dd48") (:authors ("IGARASHI Masanao" . "syoux2@gmail.com")) (:maintainers ("IGARASHI Masanao" . "syoux2@gmail.com")) (:maintainer "IGARASHI Masanao" . "syoux2@gmail.com") (:keywords "org" "nikola") (:url . "https://github.com/masayuko/ox-nikola"))]) (ox-pandoc . [(20240710 1424) ((org (8 2)) (emacs (24 4)) (dash (2 8)) (ht (2 0))) "An Org-mode exporter using pandoc" tar ((:commit . "34e6ea97b586e20529d07158a73af3cf33cdd1d5") (:authors ("Taichi" . "kawabata.taichi@gmail.com") ("Alex" . "a-fent@github")) (:maintainers ("Alex" . "a-fent@github")) (:maintainer "Alex" . "a-fent@github") (:keywords "tools") (:url . "https://github.com/a-fent/ox-pandoc"))]) - (ox-pukiwiki . [(20150124 1716) ((org (8 1))) "Pukiwiki Back-End for Org Export Engine" tar ((:commit . "b53920abf698fa6682623d671108393e92c68bd7") (:authors ("Yasushi SHOJI" . "yasushi.shoji@gmail.com")) (:maintainers ("Yasushi SHOJI" . "yasushi.shoji@gmail.com")) (:maintainer "Yasushi SHOJI" . "yasushi.shoji@gmail.com") (:keywords "org" "pukiwiki") (:url . "https://github.com/yashi/org-pukiwiki"))]) (ox-qmd . [(20230325 1315) ((emacs (27 2)) (request (0 3 3)) (mimetypes (1 0))) "Qiita Markdown Back-End for Org Export Engine" tar ((:commit . "0b5fa1e20aaa48d93600e1b8d09c3b6f55af3373") (:authors ("0x60DF" . "0x60DF@gmail.com")) (:maintainers ("0x60DF" . "0x60DF@gmail.com")) (:maintainer "0x60DF" . "0x60DF@gmail.com") (:keywords "wp") (:url . "https://github.com/0x60df/ox-qmd"))]) (ox-report . [(20231220 1625) ((emacs (24 4)) (org-msg (3 9))) "Export your org file to minutes report PDF file" tar ((:commit . "36e7f5e6e8cd836bbfcb0e85be01faab21f725fd") (:authors ("Matthias David" . "db@gnu.re")) (:maintainers ("Matthias David" . "db@gnu.re")) (:maintainer "Matthias David" . "db@gnu.re") (:keywords "org" "outlines" "report" "exporter" "meeting" "minutes") (:url . "https://github.com/DarkBuffalo/ox-report"))]) (ox-reveal . [(20221127 814) ((org (8 3))) "reveal.js Presentation Back-End for Org Export Engine" tar ((:commit . "f55c851bf6aeb1bb2a7f6cf0f2b7bd0e79c4a5a0") (:authors ("Yujie Wen" . "yjwen.tyatgmaildotcom")) (:maintainers ("Yujie Wen" . "yjwen.tyatgmaildotcom")) (:maintainer "Yujie Wen" . "yjwen.tyatgmaildotcom") (:keywords "outlines" "hypermedia" "slideshow" "presentation"))]) @@ -4183,7 +4182,7 @@ (pest-mode . [(20221231 15) ((emacs (26 3))) "Major mode for editing Pest files" tar ((:commit . "8023a92ce59c34dcd1587cbd85ed144f206ddb89") (:authors ("ksqsf" . "i@ksqsf.moe")) (:maintainers ("ksqsf" . "i@ksqsf.moe")) (:maintainer "ksqsf" . "i@ksqsf.moe") (:keywords "languages") (:url . "https://github.com/ksqsf/pest-mode"))]) (pet . [(20240715 1616) ((emacs (26 1)) (f (0 6 0)) (map (3 3 1)) (seq (2 24))) "Executable and virtualenv tracker for python-mode" tar ((:commit . "e5e3f9f0326ea1cc6edef017f0ee34cc42754b08") (:authors ("Jimmy Yuen Ho Wong" . "wyuenho@gmail.com")) (:maintainers ("Jimmy Yuen Ho Wong" . "wyuenho@gmail.com")) (:maintainer "Jimmy Yuen Ho Wong" . "wyuenho@gmail.com") (:keywords "tools") (:url . "https://github.com/wyuenho/emacs-pet/"))]) (pfuture . [(20220913 1401) ((emacs (25 2))) "a simple wrapper around asynchronous processes" tar ((:commit . "19b53aebbc0f2da31de6326c495038901bffb73c") (:authors ("Alexander Miller" . "alexanderm@web.de")) (:maintainers ("Alexander Miller" . "alexanderm@web.de")) (:maintainer "Alexander Miller" . "alexanderm@web.de") (:url . "https://github.com/Alexander-Miller/pfuture"))]) - (pg . [(20240729 1535) ((emacs (28 1)) (peg (1 0))) "Emacs Lisp socket-level interface to the PostgreSQL RDBMS" tar ((:commit . "69ca40a4206eff0b1c40e423ea8b815fdbcd438d") (:authors ("Eric Marsden" . "eric.marsden@risk-engineering.org")) (:maintainers ("Eric Marsden" . "eric.marsden@risk-engineering.org")) (:maintainer "Eric Marsden" . "eric.marsden@risk-engineering.org") (:keywords "data" "comm" "database" "postgresql") (:url . "https://github.com/emarsden/pg-el"))]) + (pg . [(20240814 1214) ((emacs (28 1)) (peg (1 0))) "Emacs Lisp socket-level interface to the PostgreSQL RDBMS" tar ((:commit . "93e3fe31c0cd5d31a046fa7c4feb4e3371ac4a8a") (:authors ("Eric Marsden" . "eric.marsden@risk-engineering.org")) (:maintainers ("Eric Marsden" . "eric.marsden@risk-engineering.org")) (:maintainer "Eric Marsden" . "eric.marsden@risk-engineering.org") (:keywords "data" "comm" "database" "postgresql") (:url . "https://github.com/emarsden/pg-el"))]) (pgdevenv . [(20150105 2236) nil "Manage your PostgreSQL development envs" tar ((:commit . "7f1d5bc734750aca98cf67a9491cdbd5615fd132") (:authors ("Dimitri Fontaine" . "dim@tapoueh.org")) (:maintainers ("Dimitri Fontaine" . "dim@tapoueh.org")) (:maintainer "Dimitri Fontaine" . "dim@tapoueh.org") (:keywords "emacs" "postgresql" "development" "environment" "shell" "debug" "gdb"))]) (ph . [(20161029 1522) ((emacs (24 3))) "A global minor mode for managing multiple projects." tar ((:commit . "a66e38637d1898b2ec31ee611033ac3f295fd97f") (:authors ("Alexander Gromnitsky" . "alexander.gromnitsky@gmail.com")) (:maintainer "Alexander Gromnitsky" . "alexander.gromnitsky@gmail.com"))]) (phabricator . [(20160510 1425) ((emacs (24 4)) (dash (1 0)) (projectile (0 13 0)) (s (1 10 0)) (f (0 17 2))) "Phabricator/Arcanist helpers for Emacs." tar ((:commit . "d09d6f059aea92d3b11c68664a5e80c901182ab8") (:keywords "phabricator" "arcanist" "diffusion") (:url . "https://github.com/ajtulloch/phabricator.el"))]) @@ -4199,7 +4198,7 @@ (phoenix-dark-pink-theme . [(20190821 48) nil "Originally a port of the Sublime Text 2 theme" tar ((:commit . "ddd98a45775be105984ec598384e68df3d3e8046") (:authors ("J Irving" . "j@lollyshouse.ca")) (:maintainers ("J Irving" . "j@lollyshouse.ca")) (:maintainer "J Irving" . "j@lollyshouse.ca") (:url . "http://github.com/j0ni/phoenix-dark-pink"))]) (php-boris . [(20130527 821) nil "Run boris php REPL" tar ((:commit . "4bb7e4d34d9906ddce688205eb24cafe634c6d06") (:maintainers ("Tom Regner" . "tom@goochesa.de")) (:maintainer "Tom Regner" . "tom@goochesa.de") (:keywords "php" "commint" "repl" "boris"))]) (php-boris-minor-mode . [(20140209 1835) ((php-boris (0 0 1)) (highlight (0))) "a minor mode to evaluate PHP code in the Boris repl" tar ((:commit . "8648eba604e4ff82ef6594a2c5ee4cb4825e6235") (:keywords "php" "repl" "eval") (:url . "https://github.com/steckerhalter/php-boris-minor-mode"))]) - (php-cs-fixer . [(20220516 1008) ((cl-lib (0 5))) "php-cs-fixer wrapper." tar ((:commit . "efe4368d891f1eec6311363cfd6be3e9eadb5e0a") (:keywords "languages" "php") (:url . "https://github.com/OVYA/php-cs-fixer"))]) + (php-cs-fixer . [(20240814 2249) ((cl-lib (0 5))) "php-cs-fixer wrapper." tar ((:commit . "e9db0576da25f8ebbae87cb2677ab8f694e14a61") (:keywords "languages" "php") (:url . "https://github.com/OVYA/php-cs-fixer"))]) (php-eldoc . [(20140202 1941) nil "eldoc backend for php" tar ((:commit . "df05064146b884d9081e10657e32dc480f070cfe") (:url . "https://github.com/sabof/php-eldoc"))]) (php-mode . [(20240621 742) ((emacs (26 1))) "Major mode for editing PHP code" tar ((:commit . "4792988a120d6ac515ba16605278d04cb8be0d69") (:maintainers ("USAMI Kenta" . "tadsan@zonu.me")) (:maintainer "USAMI Kenta" . "tadsan@zonu.me") (:keywords "languages" "php") (:url . "https://github.com/emacs-php/php-mode"))]) (php-quickhelp . [(20210819 2025) ((emacs (25 1))) "Quickhelp at point for php" tar ((:commit . "d5e11b7a6bad64550521e8822139a33218b8c9bb") (:url . "https://github.com/vpxyz/php-quickhelp"))]) @@ -4359,7 +4358,7 @@ (project-tab-groups . [(20231215 755) ((emacs (28 1))) "Support a \"one tab group per project\" workflow" tar ((:commit . "2658405d5f3c539fbd9ccf95297a016a2c91816a") (:authors ("Fritz Grabo" . "hello@fritzgrabo.com")) (:maintainers ("Fritz Grabo" . "hello@fritzgrabo.com")) (:maintainer "Fritz Grabo" . "hello@fritzgrabo.com") (:keywords "convenience") (:url . "https://github.com/fritzgrabo/project-tab-groups"))]) (project-tasks . [(20240408 611) ((emacs (26 1)) (project (0 6 0))) "Efficient task management for your project" tar ((:commit . "87852d5290154e21cbb07b2685fa46edc4963977") (:authors ("Giap Tran" . "txgvnn@gmail.com")) (:maintainers ("Giap Tran" . "txgvnn@gmail.com")) (:maintainer "Giap Tran" . "txgvnn@gmail.com") (:keywords "project" "workflow" "tools") (:url . "https://github.com/TxGVNN/project-tasks"))]) (project-treemacs . [(20230529 1207) ((emacs (28 1)) (treemacs (3 1))) "Simple treemacs backend for project.el" tar ((:commit . "36bec1109ba0498c2d1ef29756c841d2e23b063e") (:url . "https://github.com/cmccloud/project-treemacs"))]) - (projectile . [(20240212 1100) ((emacs (25 1))) "Manage and navigate projects in Emacs easily" tar ((:commit . "0163b335a18af0f077a474d4dc6b36e22b5e3274") (:authors ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainers ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainer "Bozhidar Batsov" . "bozhidar@batsov.dev") (:keywords "project" "convenience") (:url . "https://github.com/bbatsov/projectile"))]) + (projectile . [(20240814 1854) ((emacs (25 1))) "Manage and navigate projects in Emacs easily" tar ((:commit . "01fb6a5ef023bcfc52b209586dcb4fd13db00218") (:authors ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainers ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainer "Bozhidar Batsov" . "bozhidar@batsov.dev") (:keywords "project" "convenience") (:url . "https://github.com/bbatsov/projectile"))]) (projectile-codesearch . [(20180508 1522) ((codesearch (20171122 431)) (projectile (20150405 126))) "Integration of codesearch into projectile" tar ((:commit . "e40efc62e9333db0593bd81b5c78d08b19bfb193") (:authors ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainers ("Austin Bingham" . "austin.bingham@gmail.com")) (:maintainer "Austin Bingham" . "austin.bingham@gmail.com") (:keywords "tools" "development" "search") (:url . "https://github.com/abingham/emacs-codesearch"))]) (projectile-git-autofetch . [(20200820 2028) ((emacs (25 1)) (projectile (0 14 0))) "automatically fetch git repositories" tar ((:commit . "423ed5fa6508c4edc0a837bb585c7e77e99876be") (:authors ("Andreas Müller" . "code@0x7.ch")) (:maintainers ("Andreas Müller" . "code@0x7.ch")) (:maintainer "Andreas Müller" . "code@0x7.ch") (:keywords "tools" "vc") (:url . "https://github.com/andrmuel/projectile-git-autofetch"))]) (projectile-rails . [(20221231 1643) ((emacs (25 1)) (projectile (0 12 0)) (inflections (1 1)) (inf-ruby (2 2 6)) (f (0 13 0)) (rake (0 3 2)) (dash (2 18 1))) "Minor mode for Rails projects based on projectile-mode" tar ((:commit . "701784df7befe17b861f1b53fe9cbc59d0b94b9f") (:authors ("Adam Sokolnicki" . "adam.sokolnicki@gmail.com")) (:maintainers ("Adam Sokolnicki" . "adam.sokolnicki@gmail.com")) (:maintainer "Adam Sokolnicki" . "adam.sokolnicki@gmail.com") (:keywords "rails" "projectile") (:url . "https://github.com/asok/projectile-rails"))]) @@ -4487,7 +4486,7 @@ (qwen-chat-shell . [(20240612 343) ((emacs (27 1)) (shell-maker (0 50 1))) "Qwen-chat shell + buffer insert commands" tar ((:commit . "2d6562c8a75aebf7a59e554011571ba5883cf4fd") (:authors ("Pavinberg" . "pavin0702@gmail.com")) (:maintainers ("Pavinberg" . "pavin0702@gmail.com")) (:maintainer "Pavinberg" . "pavin0702@gmail.com") (:url . "https://github.com/Pavinberg/qwen-chat-shell"))]) (r-autoyas . [(20140101 1510) ((ess (0)) (yasnippet (0 8 0))) "Provides automatically created yasnippets for R function argument lists." tar ((:commit . "d321a7da0ef2e94668d53e0807277da7b70ea678") (:keywords "r" "yasnippet") (:url . "https://github.com/mlf176f2/r-autoyas.el"))]) (racer . [(20210307 243) ((emacs (25 1)) (rust-mode (0 2 0)) (dash (2 13 0)) (s (1 10 0)) (f (0 18 2)) (pos-tip (0 4 6))) "code completion, goto-definition and docs browsing for Rust via racer" tar ((:commit . "1e63e98626737ea9b662d4a9b1ffd6842b1c648c") (:keywords "abbrev" "convenience" "matching" "rust" "tools") (:url . "https://github.com/racer-rust/emacs-racer"))]) - (racket-mode . [(20240810 1326) ((emacs (25 1))) "Racket editing, REPL, and more" tar ((:commit . "7190f9c8634a5b06554d518b1835460a432dabbf") (:authors ("Greg Hendershott" . "racket-mode-author@greghendershott.com")) (:url . "https://www.racket-mode.com/"))]) + (racket-mode . [(20240813 1641) ((emacs (25 1))) "Racket editing, REPL, and more" tar ((:commit . "3cb49c513d56cc615e4b932bb08406dec93471a7") (:authors ("Greg Hendershott" . "racket-mode-author@greghendershott.com")) (:url . "https://www.racket-mode.com/"))]) (rails-i18n . [(20220126 1643) ((emacs (27 2)) (yaml (0 1 0)) (dash (2 19 1))) "Seach and insert i18n on ruby code" tar ((:commit . "8e87e4e48e31902b8259ded28a208c2e7efea6e9") (:authors ("Otávio Schwanck dos Santos" . "otavioschwanck@gmail.com")) (:maintainers ("Otávio Schwanck dos Santos" . "otavioschwanck@gmail.com")) (:maintainer "Otávio Schwanck dos Santos" . "otavioschwanck@gmail.com") (:keywords "tools" "languages") (:url . "https://github.com/otavioschwanck/rails-i18n.el"))]) (rails-log-mode . [(20140408 425) nil "Major mode for viewing Rails log files" tar ((:commit . "ff440003ad7d47cb0ac3300f2a632f4cfd36a446") (:authors ("Anantha kumaran" . "ananthakumaran@gmail.com")) (:maintainers ("Anantha kumaran" . "ananthakumaran@gmail.com")) (:maintainer "Anantha kumaran" . "ananthakumaran@gmail.com") (:keywords "rails" "log"))]) (rails-routes . [(20220126 1631) ((emacs (27 2)) (inflections (1 1))) "Search for and insert rails routes" tar ((:commit . "eab995a9297ca5bd9bd4f4c2737f2fecfc36def0") (:authors ("Otávio Schwanck" . "otavioschwanck@gmail.com")) (:maintainers ("Otávio Schwanck" . "otavioschwanck@gmail.com")) (:maintainer "Otávio Schwanck" . "otavioschwanck@gmail.com") (:keywords "tools" "languages") (:url . "https://github.com/otavioschwanck/rails-routes"))]) @@ -4523,7 +4522,7 @@ (read-only-cfg . [(20210717 205) ((emacs (24 3))) "Make files read-only based on user config" tar ((:commit . "fa16d6018a5a29f26adf6007b6b76ea1b3c0bfce") (:authors ("pfchen" . "pfchen31@gmail.com")) (:maintainers ("pfchen" . "pfchen31@gmail.com")) (:maintainer "pfchen" . "pfchen31@gmail.com") (:keywords "tools" "convenience") (:url . "https://github.com/pfchen/read-only-cfg"))]) (readable-numbers . [(20220711 911) ((emacs (24 1))) "Visually separate long integers" tar ((:commit . "a3ebdcdd91d32f044b68541a00e162396e4acb38") (:authors ("Oscar Najera" . "https://oscarnajera.com")) (:maintainers ("Oscar Najera" . "hi@oscarnajera.com")) (:maintainer "Oscar Najera" . "hi@oscarnajera.com") (:url . "https://github.com/Titan-C/cardano.el"))]) (readline-complete . [(20150708 1437) nil "offers completions in shell mode" tar ((:commit . "30c020c37b2741160cc37e656e13c85d826a0ebf") (:authors ("Christopher Monsanto" . "chris@monsan.to")) (:maintainers ("Christopher Monsanto" . "chris@monsan.to")) (:maintainer "Christopher Monsanto" . "chris@monsan.to"))]) - (ready-player . [(20240811 1854) ((emacs (28 1))) "Open media files in ready-player major mode" tar ((:commit . "a1fe64da99948ba79ce310552e0f1be64354969f") (:url . "https://github.com/xenodium/ready-player"))]) + (ready-player . [(20240818 1104) ((emacs (28 1))) "Open media files in ready-player major mode" tar ((:commit . "4da641ef345bf03ad4e2bd4c6b45d134ed96d08b") (:url . "https://github.com/xenodium/ready-player"))]) (real-auto-save . [(20200505 1537) ((emacs (24 4))) "Automatically save your buffers/files at regular intervals" tar ((:commit . "8e51241e5ba7b07b91d8188c14cf193017640292") (:authors ("Chaoji Li" . "lichaojiATgmailDOTcom") ("Anand Reddy Pandikunta" . "anand21nandaATgmailDOTcom")) (:maintainers ("Chaoji Li" . "lichaojiATgmailDOTcom") ("Anand Reddy Pandikunta" . "anand21nandaATgmailDOTcom")) (:maintainer "Chaoji Li" . "lichaojiATgmailDOTcom") (:url . "https://github.com/ChillarAnand/real-auto-save"))]) (realgud . [(20231113 1910) ((load-relative (1 3 1)) (loc-changes (1 2)) (test-simple (1 3 0)) (emacs (25))) "A modular front-end for interacting with external debuggers" tar ((:commit . "365063ea8ce8ec6a852cb388088d84147421c3c2") (:authors ("Rocky Bernstein" . "rocky@gnu.org")) (:maintainers ("Rocky Bernstein" . "rocky@gnu.org")) (:maintainer "Rocky Bernstein" . "rocky@gnu.org") (:keywords "debugger" "gdb" "python" "perl" "go" "bash" "zsh" "bashdb" "zshdb" "remake" "trepan" "perldb" "pdb") (:url . "https://github.com/realgud/realgud/"))]) (realgud-byebug . [(20190520 1140) ((realgud (1 4 5)) (load-relative (1 2)) (cl-lib (0 5)) (emacs (24))) "Realgud front-end to the Ruby byebug debugger" tar ((:commit . "f8f20b92c6b13f75cc9797921c0e28d3def48b1c") (:url . "http://github.com/rocky/realgud-byebug"))]) @@ -4606,7 +4605,7 @@ (revbufs . [(20200907 2223) nil "Reverts all out-of-date buffers safely" tar ((:commit . "df3c02d3063951582c693ae12547993cec8256e2") (:authors ("Neil Van Dyke" . "neil@neilvandyke.org")) (:maintainers ("Sam Kleinman" . "sam@tychoish.com")) (:maintainer "Sam Kleinman" . "sam@tychoish.com") (:keywords "convenience" "buffers") (:url . "http://www.neilvandyke.org/revbufs/"))]) (reveal-in-folder . [(20240226 37) ((emacs (24 3)) (f (0 20 0)) (s (1 12 0))) "Reveal current file/directory in folder" tar ((:commit . "ef1b86f745ff2e1d13dc57f6f9fe7e0c53fe26bd") (:authors ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainers ("Jen-Chieh" . "jcs090218@gmail.com")) (:maintainer "Jen-Chieh" . "jcs090218@gmail.com") (:keywords "convenience" "folder" "finder" "reveal" "file" "explorer") (:url . "https://github.com/jcs-elpa/reveal-in-folder"))]) (reveal-in-osx-finder . [(20150802 1657) nil "Reveal file associated with buffer in OS X Finder" tar ((:commit . "5710e5936e47139a610ec9a06899f72e77ddc7bc") (:keywords "os x" "finder") (:url . "https://github.com/kaz-yos/reveal-in-osx-finder"))]) - (reverse-im . [(20240315 1320) ((emacs (25 1)) (seq (2 23))) "Reverse mapping for non-default system layouts" tar ((:commit . "bcd70b49b16abab53165cb464d0a9a5f95bf946b") (:authors ("Juri Linkov" . "juri@jurta.org")) (:maintainers ("DK" . "a13@users.noreply.github.com")) (:maintainer "DK" . "a13@users.noreply.github.com") (:keywords "i18n") (:url . "https://github.com/a13/reverse-im.el"))]) + (reverse-im . [(20240815 1055) ((emacs (25 1)) (seq (2 23))) "Reverse mapping for non-default system layouts" tar ((:commit . "dfb169b08e09be6ab113a7d423f79b1775a9334f") (:authors ("Juri Linkov" . "juri@jurta.org")) (:maintainers ("DK" . "a13@users.noreply.github.com")) (:maintainer "DK" . "a13@users.noreply.github.com") (:keywords "i18n") (:url . "https://github.com/a13/reverse-im.el"))]) (reverse-theme . [(20141205 145) nil "Reverse theme for Emacs" tar ((:commit . "3105c950bcb51c662c79b59ca102ef662c2b0be0") (:authors ("Syohei YOSHIDA" . "syohex@gmail.com")) (:maintainers ("Syohei YOSHIDA" . "syohex@gmail.com")) (:maintainer "Syohei YOSHIDA" . "syohex@gmail.com") (:url . "https://github.com/syohex/emacs-reverse-theme"))]) (reverso . [(20240113 2128) ((emacs (27 1)) (transient (0 3 7)) (request (0 3 2))) "Translation, grammar checking, context search" tar ((:commit . "7ae99550cd6076009560c4c7a3e4cdf101826041") (:authors ("Korytov Pavel" . "thexcloud@gmail.com")) (:maintainers ("Korytov Pavel" . "thexcloud@gmail.com")) (:maintainer "Korytov Pavel" . "thexcloud@gmail.com") (:url . "https://github.com/SqrtMinusOne/reverso.el"))]) (revert-buffer-all . [(20240421 836) ((emacs (24 3))) "Revert all open buffers" tar ((:commit . "d49462047ebb442d7872f12007380797ee49473c") (:authors ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainers ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainer "Campbell Barton" . "ideasman42@gmail.com") (:url . "https://codeberg.org/ideasman42/emacs-buffer-revert-all"))]) @@ -4681,7 +4680,7 @@ (rust-auto-use . [(20200608 1359) nil "Utility to automatically insert Rust use statements" tar ((:commit . "d5205f7b9b9eae0f7d0893f87d3391464719f9c0") (:authors ("Rotem Yaari" . "rotemy@MBP.local")) (:maintainers ("Rotem Yaari" . "rotemy@MBP.local")) (:maintainer "Rotem Yaari" . "rotemy@MBP.local") (:keywords "languages"))]) (rust-mode . [(20240520 749) ((emacs (25 1))) "A major-mode for editing Rust source code" tar ((:commit . "d00d83d3a207a5b7c2994392b2781f627e3159ce") (:authors ("Mozilla" . "rust-mode@noreply.github.com")) (:maintainers ("Mozilla" . "rust-mode@noreply.github.com")) (:maintainer "Mozilla" . "rust-mode@noreply.github.com") (:keywords "languages") (:url . "https://github.com/rust-lang/rust-mode"))]) (rust-playground . [(20200116 1043) ((emacs (24 3))) "Local Rust playground for short code snippets." tar ((:commit . "5a117781dcb66065bea7830dd73618008fc34949") (:authors ("Alexander I.Grafov + all the contributors" . "grafov@gmail.com")) (:maintainers ("Alexander I.Grafov + all the contributors" . "grafov@gmail.com")) (:maintainer "Alexander I.Grafov + all the contributors" . "grafov@gmail.com") (:keywords "tools" "rust") (:url . "https://github.com/grafov/rust-playground"))]) - (rustic . [(20240813 1515) ((emacs (26 1)) (rust-mode (1 0 3)) (dash (2 13 0)) (f (0 18 2)) (let-alist (1 0 4)) (markdown-mode (2 3)) (project (0 3 0)) (s (1 10 0)) (spinner (1 7 3)) (xterm-color (1 6)) (flycheck (34 0))) "Rust development environment" tar ((:commit . "db1899f911886e2a6a6a522667ce3dbef3f019a9") (:keywords "languages"))]) + (rustic . [(20240817 1539) ((emacs (26 1)) (rust-mode (1 0 3)) (dash (2 13 0)) (f (0 18 2)) (let-alist (1 0 4)) (markdown-mode (2 3)) (project (0 3 0)) (s (1 10 0)) (spinner (1 7 3)) (xterm-color (1 6)) (flycheck (34 0))) "Rust development environment" tar ((:commit . "272115744c5b9a4838feb6b3c56a54d5993cbfda") (:keywords "languages"))]) (rutils . [(20220619 1421) ((emacs (26 1)) (ess (18 10 1)) (transient (0 3 0))) "R utilities with transient" tar ((:commit . "dd500ab8062ce40cb339ec8620bdfc63fdd28364") (:authors ("Shuguang Sun" . "shuguang79@qq.com")) (:maintainers ("Shuguang Sun" . "shuguang79@qq.com")) (:maintainer "Shuguang Sun" . "shuguang79@qq.com") (:keywords "convenience") (:url . "https://github.com/ShuguangSun/rutils.el"))]) (rvm . [(20220910 1558) nil "Emacs integration for rvm" tar ((:commit . "e1e83b5466c132c066142ac63729ba833c530c83") (:authors ("Yves Senn" . "yves.senn@gmx.ch")) (:maintainers ("Yves Senn" . "yves.senn@gmx.ch")) (:maintainer "Yves Senn" . "yves.senn@gmx.ch") (:keywords "ruby" "rvm") (:url . "http://www.emacswiki.org/emacs/RvmEl"))]) (ryo-modal . [(20221221 1355) ((emacs (25 1))) "Roll your own modal mode" tar ((:commit . "b9e6a0f33b9e2aeb6088accd23ed312083d8f707") (:authors ("Erik Sjöstrand" . "sjostrand.erik@gmail.com")) (:maintainers ("Erik Sjöstrand" . "sjostrand.erik@gmail.com")) (:maintainer "Erik Sjöstrand" . "sjostrand.erik@gmail.com") (:keywords "convenience" "modal" "keys") (:url . "http://github.com/Kungsgeten/ryo-modal"))]) @@ -4703,7 +4702,7 @@ (save-load-path . [(20140206 1214) nil "save load-path and reuse it to test" tar ((:commit . "6cb763a37e2b8af505bff2bcd11fd49c9ea04d66") (:authors ("rubikitch" . "rubikitch@ruby-lang.org")) (:maintainers ("rubikitch" . "rubikitch@ruby-lang.org")) (:maintainer "rubikitch" . "rubikitch@ruby-lang.org") (:keywords "lisp") (:url . "http://www.emacswiki.org/cgi-bin/wiki/download/save-load-path.el"))]) (save-visited-files . [(20200212 414) nil "save opened files across sessions" tar ((:commit . "8203a05a322324ec17b14437c8dfb38efdb53241") (:authors ("Nathaniel Flath" . "nflath@gmail.com")) (:maintainers ("Nathaniel Flath" . "nflath@gmail.com")) (:maintainer "Nathaniel Flath" . "nflath@gmail.com") (:url . "http://github.com/nflath/save-visited-files"))]) (savekill . [(20140418 229) nil "Save kill ring to disk" tar ((:commit . "67fc94e3d8fe8ce3ca16f90518f6a46479b63e34") (:authors ("rubikitch" . "rubikitch@ruby-lang.org")) (:maintainers ("rubikitch" . "rubikitch@ruby-lang.org")) (:maintainer "rubikitch" . "rubikitch@ruby-lang.org") (:keywords "tools") (:url . "http://www.emacswiki.org/cgi-bin/wiki/download/savekill.el"))]) - (saveplace-pdf-view . [(20240209 505) ((emacs (24 1))) "Save place in pdf-view buffers" tar ((:commit . "ee95460cd934080338f03a16f95b549577425216") (:authors ("Nicolai Singh" . "nicolaisinghatpm.me")) (:maintainers ("Nicolai Singh" . "nicolaisinghatpm.me")) (:maintainer "Nicolai Singh" . "nicolaisinghatpm.me") (:keywords "files" "convenience") (:url . "https://github.com/nicolaisingh/saveplace-pdf-view"))]) + (saveplace-pdf-view . [(20240816 1351) ((emacs (24 1))) "Save place in pdf-view buffers" tar ((:commit . "70e9ec40565021f4b5d51e4523f4c716183a8eef") (:authors ("Nicolai Singh" . "nicolaisinghatpm.me")) (:maintainers ("Nicolai Singh" . "nicolaisinghatpm.me")) (:maintainer "Nicolai Singh" . "nicolaisinghatpm.me") (:keywords "files" "convenience") (:url . "https://github.com/nicolaisingh/saveplace-pdf-view"))]) (say-what-im-doing . [(20160706 1931) nil "dictate what you're doing with text to speech" tar ((:commit . "5b2ce6783b02805bcac1107a149bfba3852cd9d5") (:keywords "text to speech" "dumb" "funny") (:url . "http://github.com/benaiah/say-what-im-doing"))]) (sayid . [(20220101 1357) ((cider (0 21 0))) "sayid nREPL middleware client" tar ((:commit . "879aff586336a0ec4d46c0ed4720fb1de22082bd") (:authors ("Bill Piel" . "bill@billpiel.com")) (:maintainers ("Bozhidar Batsov" . "bozhidar@batsov.dev")) (:maintainer "Bozhidar Batsov" . "bozhidar@batsov.dev") (:keywords "clojure" "cider" "debugger") (:url . "https://github.com/clojure-emacs/sayid"))]) (sbt-mode . [(20240404 1105) ((emacs (24 4))) "Interactive support for sbt projects" tar ((:commit . "cc68728a6ef0600aad369157b3a2d0ce56afba9b") (:keywords "languages") (:url . "https://github.com/hvesalai/emacs-sbt-mode"))]) @@ -4751,7 +4750,7 @@ (selcand . [(20240430 1408) ((emacs (25 1))) "Select a candidate from a tree of hint characters" tar ((:commit . "6baa1771eacbcfe7ec854362bed17baea865424e") (:maintainers ("concat \"erjoalgo\" \"@\" \"gmail\" \".com\"" . "")) (:maintainer "concat \"erjoalgo\" \"@\" \"gmail\" \".com\"" . "") (:keywords "lisp" "completing-read" "prompt" "combinations" "vimium") (:url . "https://github.com/erjoalgo/selcand"))]) (select-themes . [(20160221 106) nil "Color theme selection with completing-read" tar ((:commit . "236f54287519a3ea6dd7b3992d053e4f4ff5d0fe") (:authors ("Jason Milkins" . "jasonm23@gmail.com")) (:maintainers ("Jason Milkins" . "jasonm23@gmail.com")) (:maintainer "Jason Milkins" . "jasonm23@gmail.com") (:url . "https://github.com/jasonm23/emacs-select-themes"))]) (selected . [(20230219 1328) nil "Keymap for when region is active" tar ((:commit . "1ca6e12f456caa1dc97c3d68597598662eb5de9a") (:keywords "convenience") (:url . "http://github.com/Kungsgeten/selected.el"))]) - (selected-window-accent-mode . [(20240813 1915) ((emacs (28 1)) (transient (0 1 0))) "Accent Selected Window" tar ((:commit . "2affe5bc985fd75a158567b27d064df765c121f3") (:authors ("James Dyer" . "captainflasmr@gmail.com")) (:maintainers ("James Dyer" . "captainflasmr@gmail.com")) (:maintainer "James Dyer" . "captainflasmr@gmail.com") (:keywords "convenience") (:url . "https://github.com/captainflasmr/selected-window-accent-mode"))]) + (selected-window-accent-mode . [(20240815 1934) ((emacs (28 1)) (transient (0 1 0))) "Accent Selected Window" tar ((:commit . "8a49af37909779cb47d53ea41922deec2d87fe29") (:authors ("James Dyer" . "captainflasmr@gmail.com")) (:maintainers ("James Dyer" . "captainflasmr@gmail.com")) (:maintainer "James Dyer" . "captainflasmr@gmail.com") (:keywords "convenience") (:url . "https://github.com/captainflasmr/selected-window-accent-mode"))]) (selectric-mode . [(20200209 2107) nil "IBM Selectric mode for Emacs" tar ((:commit . "bb9e66678f34e9bc23624ff6292cf5e7857e8e5f") (:authors ("Ricardo Bánffy" . "rbanffy@gmail.com")) (:maintainers ("Ricardo Banffy" . "rbanffy@gmail.com")) (:maintainer "Ricardo Banffy" . "rbanffy@gmail.com") (:keywords "multimedia" "convenience" "typewriter" "selectric") (:url . "https://github.com/rbanffy/selectric-mode"))]) (selectrum . [(20220513 2106) ((emacs (26 1))) "Easily select item from list" tar ((:commit . "810ea697bdd559d97b86b795e01769cddfa3daf2") (:authors ("Radian LLC" . "contact+selectrum@radian.codes")) (:maintainers ("Radian LLC" . "contact+selectrum@radian.codes")) (:maintainer "Radian LLC" . "contact+selectrum@radian.codes") (:keywords "extensions") (:url . "https://github.com/radian-software/selectrum"))]) (selectrum-prescient . [(20240803 2320) ((emacs (25 1)) (prescient (6 1 0)) (selectrum (3 1))) "prescient.el + Selectrum" tar ((:commit . "2b8a8b41228bddb2e11eb1c200e98a9edd04797c") (:authors ("Radian LLC" . "contact+prescient@radian.codes")) (:maintainers ("Radian LLC" . "contact+prescient@radian.codes")) (:maintainer "Radian LLC" . "contact+prescient@radian.codes") (:keywords "extensions") (:url . "https://github.com/raxod502/prescient.el"))]) @@ -4979,14 +4978,14 @@ (spacegray-theme . [(20150719 1931) ((emacs (24 1))) "A Hyperminimal UI Theme" tar ((:commit . "7f70ee36297e5ccf9bc90b1f81472024f5a7a749") (:authors ("Bruce Williams" . "brwcodes@gmail.com")) (:maintainers ("Bruce Williams" . "brwcodes@gmail.com")) (:maintainer "Bruce Williams" . "brwcodes@gmail.com") (:keywords "themes") (:url . "http://github.com/bruce/emacs-spacegray-theme"))]) (spaceline . [(20230922 1127) ((emacs (24 4)) (cl-lib (0 5)) (powerline (2 3)) (dash (2 11 0)) (s (1 10 0))) "Modeline configuration library for powerline" tar ((:commit . "086420d16e526c79b67fc1edec4c2ae1e699f372") (:authors ("Eivind Fonn" . "evfonn@gmail.com")) (:maintainers ("Eivind Fonn" . "evfonn@gmail.com")) (:maintainer "Eivind Fonn" . "evfonn@gmail.com") (:keywords "mode-line" "powerline" "spacemacs") (:url . "https://github.com/TheBB/spaceline"))]) (spaceline-all-the-icons . [(20190325 1602) ((emacs (24 4)) (all-the-icons (2 6 0)) (spaceline (2 0 0)) (memoize (1 0 1))) "A Spaceline theme using All The Icons" tar ((:commit . "5afd48c10f1bd42d9b9648c5e64596b72f3e9042") (:authors ("Dominic Charlesworth" . "dgc336@gmail.com")) (:maintainers ("Dominic Charlesworth" . "dgc336@gmail.com")) (:maintainer "Dominic Charlesworth" . "dgc336@gmail.com") (:keywords "convenience" "lisp" "tools") (:url . "https://github.com/domtronn/spaceline-all-the-icons.el"))]) - (spacemacs-theme . [(20240715 1440) nil "Color theme with a dark and light versions" tar ((:commit . "3cc6919d63726e96653169a7846aa5eca06e9a8b") (:keywords "color" "theme") (:url . "https://github.com/nashamri/spacemacs-theme"))]) + (spacemacs-theme . [(20240815 2134) nil "Color theme with a dark and light versions" tar ((:commit . "d02edec79404e807445b62d0d2fc1a6fbcc10c71") (:keywords "color" "theme") (:url . "https://github.com/nashamri/spacemacs-theme"))]) (spaces . [(20170809 2208) nil "Create and switch between named window configurations." tar ((:commit . "6bdb51e9a346907d60a9625f6180bddd06be6674") (:keywords "frames" "convenience") (:url . "https://github.com/chumpage/chumpy-windows"))]) (spanish-holidays . [(20240302 1542) nil "Spain holidays for calendar" tar ((:commit . "81ef3733da0ab807570c7fad1bab613bf7f30acb") (:authors ("Carlos Pajuelo" . "carlospajuelo_@hotmail.com")) (:maintainers ("Carlos Pajuelo" . "carlospajuelo_@hotmail.com")) (:maintainer "Carlos Pajuelo" . "carlospajuelo_@hotmail.com") (:keywords "calendar") (:url . "https://gitlab.com/gnuhack/spanish-holidays"))]) (spark . [(20230406 2307) ((emacs (24 3))) "sparkline generation" tar ((:commit . "0e58e5122cbb46fb6d850e3b72487431a3696861") (:keywords "lisp" "data") (:url . "https://github.com/alvinfrancis/spark"))]) (sparkline . [(20150101 1319) ((cl-lib (0 3))) "Make sparkline images from a list of numbers" tar ((:commit . "a2b5d817d272d6363b67ed8f8cc75499a19fa8d2") (:authors ("Willem Rein Oudshoorn" . "woudshoo@xs4all.nl")) (:maintainers ("Willem Rein Oudshoorn" . "woudshoo@xs4all.nl")) (:maintainer "Willem Rein Oudshoorn" . "woudshoo@xs4all.nl") (:keywords "extensions"))]) (sparql-mode . [(20230104 1113) ((cl-lib (0 5)) (emacs (24 3))) "Edit and interactively evaluate SPARQL queries." tar ((:commit . "1f6196094ec6626722c6e03a13f6844c68f62703") (:authors ("Craig Andera" . "canderaatwangderadotcom")) (:maintainers ("Bjarte Johansen" . "BjartedotJohansenatgmaildotcom")) (:maintainer "Bjarte Johansen" . "BjartedotJohansenatgmaildotcom") (:url . "https://github.com/ljos/sparql-mode"))]) (spatial-navigate . [(20240421 908) ((emacs (29 1))) "Directional navigation between white-space blocks" tar ((:commit . "4f85fe3ae4d240a35d3d7edd8b865612024f9dda") (:authors ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainers ("Campbell Barton" . "ideasman42@gmail.com")) (:maintainer "Campbell Barton" . "ideasman42@gmail.com") (:url . "https://codeberg.org/ideasman42/emacs-spatial-navigate"))]) - (spdx . [(20240814 111) ((emacs (24 4))) "Insert SPDX license and copyright headers" tar ((:commit . "15ea8f7e4b08fd8322cfb2f33fb85a9736e92da3") (:authors ("Zhiwei Chen" . "condy0919@gmail.com")) (:maintainers ("Zhiwei Chen" . "condy0919@gmail.com")) (:maintainer "Zhiwei Chen" . "condy0919@gmail.com") (:keywords "license" "tools") (:url . "https://github.com/condy0919/spdx.el"))]) + (spdx . [(20240815 107) ((emacs (24 4))) "Insert SPDX license and copyright headers" tar ((:commit . "65f4459dc2368d037417247b380d03708f7b8fc0") (:authors ("Zhiwei Chen" . "condy0919@gmail.com")) (:maintainers ("Zhiwei Chen" . "condy0919@gmail.com")) (:maintainer "Zhiwei Chen" . "condy0919@gmail.com") (:keywords "license" "tools") (:url . "https://github.com/condy0919/spdx.el"))]) (speech-tagger . [(20170728 1829) ((cl-lib (0 5))) "tag parts of speech using coreNLP" tar ((:commit . "61955b40d4e8b09e66a3e8033e82893f81657c06") (:authors ("Danny McClanahan" . "danieldmcclanahan@gmail.com")) (:maintainers ("Danny McClanahan" . "danieldmcclanahan@gmail.com")) (:maintainer "Danny McClanahan" . "danieldmcclanahan@gmail.com") (:keywords "speech" "tag" "nlp" "language" "corenlp" "parsing" "natural") (:url . "https://github.com/cosmicexplorer/speech-tagger"))]) (speechd-el . [(20240513 1716) nil "Client to speech synthesizers and Braille displays." tar ((:commit . "ac7497e394bf7d46e0b2c27570f5507f6a50a157") (:authors ("Milan Zamazal" . "pdm@zamazal.org")) (:maintainer "Milan Zamazal" . "pdm@zamazal.org") (:url . "https://github.com/brailcom/speechd-el"))]) (speed-type . [(20230926 838) ((emacs (26 1)) (compat (29 1 3))) "Practice touch and speed typing" tar ((:commit . "28b8e8c1cc24511758168f30bcac18d8fb93706d") (:maintainers ("Daniel Kraus" . "daniel@kraus.my")) (:maintainer "Daniel Kraus" . "daniel@kraus.my") (:keywords "games") (:url . "https://github.com/dakra/speed-type"))]) @@ -5044,7 +5043,7 @@ (stem . [(20131102 1109) nil "Routines for stemming" tar ((:commit . "dd704c3447bd5d3f5ac0a4840f8987d4f855d87e") (:authors ("Tsuchiya Masatoshi" . "tsuchiya@pine.kuee.kyoto-u.ac.jp")) (:maintainers ("Tsuchiya Masatoshi" . "tsuchiya@pine.kuee.kyoto-u.ac.jp")) (:maintainer "Tsuchiya Masatoshi" . "tsuchiya@pine.kuee.kyoto-u.ac.jp") (:keywords "stemming") (:url . "https://github.com/yuutayamada/stem"))]) (stem-english . [(20180109 358) ((emacs (24 3))) "- routines for stemming English word" tar ((:commit . "c9fc4c6ed6bf82382e479dae80912f4ae17d31f4") (:authors ("Tsuchiya Masatoshi" . "tsuchiya@pine.kuee.kyoto-u.ac.jp")) (:maintainers ("Taichi" . "kawabata.taichi_at_gmail.com")) (:maintainer "Taichi" . "kawabata.taichi_at_gmail.com") (:keywords "text") (:url . "http://github.com/kawabata/stem-english"))]) (stem-reading-mode . [(20220522 1053) ((emacs (25 1))) "Highlight word stems for speed-reading" tar ((:commit . "6efc9962e3a19a452c7ab9636cf1e2566a51bd38") (:authors ("Yuri D'Elia" . "wavexx@thregr.org")) (:maintainers ("Yuri D'Elia" . "wavexx@thregr.org")) (:maintainer "Yuri D'Elia" . "wavexx@thregr.org") (:keywords "convenience" "wp") (:url . "https://gitlab.com/wavexx/stem-reading-mode.el"))]) - (stgit . [(20240728 2156) nil "major mode for StGit interaction" tar ((:commit . "1815dc80428218271b6954c27bcb72079770aa30") (:authors ("David Kågedal" . "davidk@lysator.liu.se")) (:maintainers ("David Kågedal" . "davidk@lysator.liu.se")) (:maintainer "David Kågedal" . "davidk@lysator.liu.se") (:url . "http://stacked-git.github.io"))]) + (stgit . [(20240817 2126) nil "major mode for StGit interaction" tar ((:commit . "e666bf88cff0706166dd6b086414913ecc1a8f21") (:authors ("David Kågedal" . "davidk@lysator.liu.se")) (:maintainers ("David Kågedal" . "davidk@lysator.liu.se")) (:maintainer "David Kågedal" . "davidk@lysator.liu.se") (:url . "http://stacked-git.github.io"))]) (sticky . [(20170926 36) nil "Sticky key for capital letters" tar ((:commit . "fec4e1af38f17f5cd80eca361d8e8ef8772db366") (:authors ("rubikitch" . "rubikitch@ruby-lang.org")) (:maintainers ("rubikitch" . "rubikitch@ruby-lang.org")) (:maintainer "rubikitch" . "rubikitch@ruby-lang.org") (:keywords "convenience") (:url . "http://www.emacswiki.org/cgi-bin/wiki/download/sticky.el"))]) (sticky-shell . [(20230207 1454) ((emacs (25 1))) "Minor mode to keep track of previous prompt in your shell" tar ((:commit . "030535451b7c12eea3a94dfc1a439b8baa96944b") (:authors ("Andrew De Angelis" . "bobodeangelis@gmail.com")) (:maintainers ("Andrew De Angelis" . "bobodeangelis@gmail.com")) (:maintainer "Andrew De Angelis" . "bobodeangelis@gmail.com") (:keywords "processes" "terminals" "tools") (:url . "https://github.com/andyjda/sticky-shell"))]) (stickyfunc-enhance . [(20150429 1814) ((emacs (24 3))) "An enhancement to stock `semantic-stickyfunc-mode'" tar ((:commit . "13bdba51fcd83ccbc3267959d23afc94d458dcb0") (:authors ("Do Hoang" . "tuhdo1710@gmail.com")) (:keywords "c" "languages" "tools") (:url . "https://github.com/tuhdo/semantic-stickyfunc-enhance"))]) @@ -5056,7 +5055,7 @@ (streamlink . [(20210811 1429) ((s (1 12 0))) "A major mode for streamlink output" tar ((:commit . "13dff15121ac0276f693696db9b04ae5820058d5") (:keywords "multimedia" "streamlink") (:url . "https://github.com/BenediktBroich/streamlink"))]) (strie . [(20160211 2222) ((cl-lib (0 5))) "A simple trie data structure implementation" tar ((:commit . "eb7efb0cccc127c414f6a64db11454869d9c10a8") (:authors ("James Atwood" . "jatwood@cs.umass.edu")) (:maintainers ("James Atwood" . "jatwood@cs.umass.edu")) (:maintainer "James Atwood" . "jatwood@cs.umass.edu"))]) (string-edit-at-point . [(20230118 1933) ((dash (1 2 0))) "Avoid escape nightmares by editing string in separate buffer" tar ((:commit . "87936d816ae24184dd83688136531b6b6f1943fe") (:authors ("Magnar Sveen" . "magnars@gmail.com")) (:maintainers ("Magnar Sveen" . "magnars@gmail.com")) (:maintainer "Magnar Sveen" . "magnars@gmail.com"))]) - (string-inflection . [(20240811 2252) nil "underscore -> UPCASE -> CamelCase -> lowerCamelCase conversion of names" tar ((:commit . "fa787ae106e0b4c6af4c3554108a4a4a7bf7f60e") (:authors ("akicho8" . "akicho8@gmail.com")) (:maintainers ("akicho8" . "akicho8@gmail.com")) (:maintainer "akicho8" . "akicho8@gmail.com") (:keywords "elisp"))]) + (string-inflection . [(20240816 523) nil "underscore -> UPCASE -> CamelCase -> lowerCamelCase conversion of names" tar ((:commit . "4cc92e1ecd3d165b55235b51ae65ac09a0364958") (:authors ("akicho8" . "akicho8@gmail.com")) (:maintainers ("akicho8" . "akicho8@gmail.com")) (:maintainer "akicho8" . "akicho8@gmail.com") (:keywords "elisp"))]) (string-utils . [(20140508 2041) ((list-utils (0 4 2))) "String-manipulation utilities" tar ((:commit . "8b56e1f79d2de46d1e9b5e24d889e9f4c3cc85d4") (:authors ("Roland Walker" . "walker@pobox.com")) (:maintainers ("Roland Walker" . "walker@pobox.com")) (:maintainer "Roland Walker" . "walker@pobox.com") (:keywords "extensions") (:url . "http://github.com/rolandwalker/string-utils"))]) (stripe-buffer . [(20141208 1508) ((cl-lib (1 0))) "Use a different background for even and odd lines" tar ((:commit . "c252080f55cb78c951b19ebab9687f6d00237baf") (:authors ("Andy Stewart" . "lazycat.manatee@gmail.com")) (:maintainers ("sabof" . "esabof@gmail.com")) (:maintainer "sabof" . "esabof@gmail.com") (:url . "https://github.com/sabof/stripe-buffer"))]) (stripes . [(20230402 1228) ((emacs (24 3))) "highlight alternating lines differently" tar ((:commit . "4683c9020da14bb1c1f74b90d27a4d9fdc7a9147") (:authors ("Michael Schierl" . "schierlm-public@gmx.de") ("těpán Němec" . "stepnem@smrk.net")) (:maintainers ("těpán Němec" . "stepnem@smrk.net")) (:maintainer "těpán Němec" . "stepnem@smrk.net") (:keywords "convenience" "faces") (:url . "http://git.smrk.net/stripes.el"))]) @@ -5171,7 +5170,7 @@ (tea-time . [(20120331 820) nil "Simple timer package, useful to make perfect tea." tar ((:commit . "1f6cf0bdd27c5eb3508989c5095427781f858eca") (:authors ("konsty" . "antipin.konstantin@googlemail.com")) (:maintainers ("Gabriel Saldana" . "gsaldana@gmail.com")) (:maintainer "Gabriel Saldana" . "gsaldana@gmail.com") (:keywords "timer" "tea-time"))]) (teacode-expand . [(20181231 640) ((emacs (24 4))) "Expansion of text by TeaCode program." tar ((:commit . "7df6f9ec95da1fb47bbae489bb3f2c27ed3a9b3a") (:authors ("Richard Guay" . "raguay@customct.com")) (:maintainers ("Richard Guay" . "raguay@customct.com")) (:maintainer "Richard Guay" . "raguay@customct.com") (:keywords "lisp") (:url . "https://github.com/raguay/TeaCode-Expand"))]) (teco . [(20200707 2309) nil "Teco interpreter" tar ((:commit . "2529eb0f7f35c526c1b6fca5250399718ff5138a") (:authors ("Dale R. Worley" . "worley@alum.mit.edu")) (:maintainers ("Mark T. Kennedy" . "mtk@acm.org")) (:maintainer "Mark T. Kennedy" . "mtk@acm.org") (:keywords "convenience" "emulations" "files") (:url . "https://github.com/mtk/teco.git"))]) - (telega . [(20240812 911) ((emacs (27 1)) (visual-fill-column (1 9)) (rainbow-identifiers (0 2 2)) (transient (0 3 0))) "Telegram client (unofficial)" tar ((:commit . "fdaa13c65045e61aed1deb3f90adea191131bc77") (:authors ("Zajcev Evgeny" . "zevlg@yandex.ru")) (:maintainers ("Zajcev Evgeny" . "zevlg@yandex.ru")) (:maintainer "Zajcev Evgeny" . "zevlg@yandex.ru") (:keywords "comm") (:url . "https://github.com/zevlg/telega.el"))]) + (telega . [(20240818 929) ((emacs (27 1)) (visual-fill-column (1 9)) (rainbow-identifiers (0 2 2)) (transient (0 3 0))) "Telegram client (unofficial)" tar ((:commit . "d86d943beca37b9270060e9acca65e8fe3f322f3") (:authors ("Zajcev Evgeny" . "zevlg@yandex.ru")) (:maintainers ("Zajcev Evgeny" . "zevlg@yandex.ru")) (:maintainer "Zajcev Evgeny" . "zevlg@yandex.ru") (:keywords "comm") (:url . "https://github.com/zevlg/telega.el"))]) (telepathy . [(20131209 1258) nil "Access Telepathy from Emacs" tar ((:commit . "211d785b02a29ddc254422fdcc3db45262582f8c") (:authors ("Nicolas Petton" . "petton.nicolas@gmail.com")) (:maintainers ("Nicolas Petton" . "petton.nicolas@gmail.com")) (:maintainer "Nicolas Petton" . "petton.nicolas@gmail.com") (:keywords "telepathy" "tools"))]) (telephone-line . [(20240109 2021) ((emacs (24 4)) (cl-lib (0 5)) (cl-generic (0 2)) (seq (1 8))) "Rewrite of Powerline" tar ((:commit . "6016418a5e1e8e006cc202eff50ff28b594eeca4") (:authors ("Daniel Bordak" . "dbordak@fastmail.fm")) (:maintainers ("Daniel Bordak" . "dbordak@fastmail.fm")) (:maintainer "Daniel Bordak" . "dbordak@fastmail.fm") (:keywords "mode-line") (:url . "https://github.com/dbordak/telephone-line"))]) (teleport . [(20240718 652) ((emacs (28 1)) (dash (2 18 0))) "Integration for tsh (goteleport.com)" tar ((:commit . "929f87990a6ee83dfcb7ebf9f8580828f1281ebb") (:authors ("Caramel Hooves" . "caramel.hooves@protonmail.com")) (:maintainers ("Caramel Hooves" . "caramel.hooves@protonmail.com")) (:maintainer "Caramel Hooves" . "caramel.hooves@protonmail.com") (:keywords "tools") (:url . "https://github.com/caramelhooves/teleport.el"))]) @@ -5195,7 +5194,6 @@ (term-projectile . [(20240602 2356) ((emacs (24)) (term-manager (0 1 0)) (projectile (0 13 0))) "projectile terminal management" tar ((:commit . "25353734c65cd5cc952e4893b552629ca1d0d37f") (:authors ("Ivan Malison" . "IvanMalison@gmail.com")) (:maintainers ("Ivan Malison" . "IvanMalison@gmail.com")) (:maintainer "Ivan Malison" . "IvanMalison@gmail.com") (:keywords "projectile" "tools" "terminals" "vc") (:url . "https://www.github.com/IvanMalison/term-manager"))]) (term-run . [(20200128 702) nil "Run arbitrary command in terminal buffer" tar ((:commit . "0fd135d55fcf864598b1fb8dd880833a1a322910") (:authors ("10sr" . "8slashes+el[at]gmail[dot]com")) (:maintainers ("10sr" . "8slashes+el[at]gmail[dot]com")) (:maintainer "10sr" . "8slashes+el[at]gmail[dot]com") (:keywords "utility" "shell" "command" "term-mode") (:url . "https://github.com/10sr/term-run-el"))]) (termbright-theme . [(20151031 235) ((emacs (24 1))) "a more usable theme for white-on-black terminals" tar ((:commit . "bec6ab14336c0611e85f45486276004f16d20607") (:authors ("Brian Mastenbrook" . "brian@mastenbrook.net")) (:maintainers ("Brian Mastenbrook" . "brian@mastenbrook.net")) (:maintainer "Brian Mastenbrook" . "brian@mastenbrook.net") (:keywords "themes") (:url . "https://github.com/bmastenbrook/termbright-theme-el"))]) - (terminal-focus-reporting . [(20180830 719) ((emacs (24 4))) "Minor mode for terminal focus reporting." tar ((:commit . "8b84bf18f4c5f1b59a11692eb706f13c3598d9a5") (:keywords "convenience") (:url . "https://github.com/veelenga/terminal-focus-reporting.el"))]) (terminal-here . [(20240227 2236) ((emacs (25 1))) "Run an external terminal in current directory" tar ((:commit . "c996304c1e873e561108a509129b9e4358d354d5") (:authors ("David Shepherd" . "davidshepherd7@gmail.com")) (:maintainers ("David Shepherd" . "davidshepherd7@gmail.com")) (:maintainer "David Shepherd" . "davidshepherd7@gmail.com") (:keywords "tools" "frames") (:url . "https://github.com/davidshepherd7/terminal-here"))]) (terminal-toggle . [(20190226 1510) ((emacs (24)) (popwin (1 0 0))) "simple pop-up terminal" tar ((:commit . "f824d634aef3600cb7a8e2ddf9e8444c6607c160") (:keywords "outlines") (:url . "https://github.com/mtekman/terminal-toggle.el"))]) (tern . [(20191227 950) ((json (1 2)) (cl-lib (0 5)) (emacs (24))) "Tern-powered JavaScript integration" tar ((:commit . "0d19800db70a6348c627a69f444b91d21ad89629") (:url . "http://ternjs.net/"))]) @@ -5301,7 +5299,7 @@ (tramp-term . [(20220725 1441) nil "Automatic setup of directory tracking in ssh sessions" tar ((:commit . "ed75189122737d301f716a30a8013205aa3736f1") (:authors ("Randy Morris" . "randy.morris@archlinux.us")) (:maintainers ("Randy Morris" . "randy.morris@archlinux.us")) (:maintainer "Randy Morris" . "randy.morris@archlinux.us") (:keywords "comm" "terminals") (:url . "https://github.com/randymorris/tramp-term.el"))]) (transducers . [(20240308 843) ((emacs (28 1))) "Ergonomic, efficient data processing" tar ((:commit . "2d452e4cdc3b5cfa29ee3d7a645ff53d4e993384") (:authors ("Colin Woodbury" . "colin@fosskers.ca")) (:maintainers ("Colin Woodbury" . "colin@fosskers.ca")) (:maintainer "Colin Woodbury" . "colin@fosskers.ca") (:keywords "lisp") (:url . "https://git.sr.ht/~fosskers/transducers.el"))]) (transfer-sh . [(20200601 1708) ((emacs (24 3)) (async (1 0))) "Simple interface for sending buffer contents to transfer.sh" tar ((:commit . "0621a66d00ec91a209a542c10b158095088bd44d") (:keywords "comm" "convenience" "files") (:url . "https://gitlab.com/tuedachu/transfer-sh.el"))]) - (transient . [(20240805 1231) ((emacs (26 1)) (compat (30 0 0 0)) (seq (2 24))) "Transient commands" tar ((:commit . "b2cb4e578f2362a0354c4a31a6bd89d6c4b63d63") (:authors ("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev") (:keywords "extensions") (:url . "https://github.com/magit/transient"))]) + (transient . [(20240817 1959) ((emacs (26 1)) (compat (30 0 0 0)) (seq (2 24))) "Transient commands" tar ((:commit . "3d3f8711d4f6a6ff7f53bc22e465ec82587c62ed") (:authors ("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev") (:keywords "extensions") (:url . "https://github.com/magit/transient"))]) (transient-dwim . [(20221225 1630) ((emacs (26 1)) (transient (0 1))) "Useful preset transient commands" tar ((:commit . "cb5e0d35729fc6448553b7a17fc5c843f00e8c1d") (:authors ("Naoya Yamashita" . "conao3@gmail.com")) (:maintainers ("Naoya Yamashita" . "conao3@gmail.com")) (:maintainer "Naoya Yamashita" . "conao3@gmail.com") (:keywords "tools") (:url . "https://github.com/conao3/transient-dwim.el"))]) (transient-extras . [(20230721 839) ((emacs (28 1))) "Extra features for transient" tar ((:commit . "ca0d5c597382615f0ee8300ff8718f54f8214359") (:authors ("Al Haji-Ali" . "abdo.haji.ali@gmail.com") ("Samuel W. Flint" . "swflint@flintfam.org")) (:maintainers ("Al Haji-Ali" . "abdo.haji.ali@gmail.com") ("Samuel W. Flint" . "swflint@flintfam.org")) (:maintainer "Al Haji-Ali" . "abdo.haji.ali@gmail.com") (:keywords "convenience") (:url . "https://github.com/haji-ali/transient-extras.git"))]) (transient-extras-a2ps . [(20230303 1511) ((emacs (28 1)) (transient-extras (1 0 0))) "A transient interface to a2ps" tar ((:commit . "e91a1cddb1f0cb8b99d2bd30db64d467e5fa7ea8") (:authors ("Samuel W. Flint" . "swflint@flintfam.org")) (:maintainers ("Samuel W. Flint" . "swflint@flintfam.org")) (:maintainer "Samuel W. Flint" . "swflint@flintfam.org") (:keywords "convenience") (:url . "https://git.sr.ht/~swflint/transient-extras-a2ps"))]) @@ -5324,7 +5322,7 @@ (tree-sitter-langs . [(20240811 908) ((emacs (25 1)) (tree-sitter (0 15 0))) "Grammar bundle for tree-sitter" tar ((:commit . "ac3aa507a8a5664159613834fe6568aa86cc16f1") (:authors ("Tuấn-Anh Nguyễn" . "ubolonton@gmail.com")) (:maintainers ("Tuấn-Anh Nguyễn" . "ubolonton@gmail.com")) (:maintainer "Tuấn-Anh Nguyễn" . "ubolonton@gmail.com") (:keywords "languages" "tools" "parsers" "tree-sitter") (:url . "https://github.com/emacs-tree-sitter/tree-sitter-langs"))]) (treebundel . [(20240531 2321) ((emacs (27 1)) (compat (29 1 4 2))) "Bundle related git-worktrees together" tar ((:commit . "b0a5d1bf924d8cadde5bae50b8d9ac131279b828") (:keywords "convenience" "vc") (:url . "https://github.com/purplg/treebundel"))]) (treefactor . [(20200516 1631) ((emacs (26 1)) (dash (2 16 0)) (f (0 20 0)) (org (9 2 6)) (avy (0 5 0))) "Restructure your messy Org documents" tar ((:commit . "75357757022a4399ab772ff0d92065bd114dabe9") (:authors ("Leo Littlebook" . "Leo.Littlebook@gmail.com")) (:maintainers ("Leo Littlebook" . "Leo.Littlebook@gmail.com")) (:maintainer "Leo Littlebook" . "Leo.Littlebook@gmail.com") (:keywords "outlines" "files" "convenience") (:url . "https://github.com/cyberthal/treefactor"))]) - (treemacs . [(20240813 1152) ((emacs (26 1)) (cl-lib (0 5)) (dash (2 11 0)) (s (1 12 0)) (ace-window (0 9 0)) (pfuture (1 7)) (hydra (0 13 2)) (ht (2 2)) (cfrs (1 3 2))) "A tree style file explorer package" tar ((:commit . "30919bbda612d7dc862ca23f998c8df66abd3861") (:authors ("Alexander Miller" . "alexanderm@web.de")) (:maintainers ("Alexander Miller" . "alexanderm@web.de")) (:maintainer "Alexander Miller" . "alexanderm@web.de") (:url . "https://github.com/Alexander-Miller/treemacs"))]) + (treemacs . [(20240815 1227) ((emacs (26 1)) (cl-lib (0 5)) (dash (2 11 0)) (s (1 12 0)) (ace-window (0 9 0)) (pfuture (1 7)) (hydra (0 13 2)) (ht (2 2)) (cfrs (1 3 2))) "A tree style file explorer package" tar ((:commit . "488dfc0a3aa7c1d35802d4f89be058e761578663") (:authors ("Alexander Miller" . "alexanderm@web.de")) (:maintainers ("Alexander Miller" . "alexanderm@web.de")) (:maintainer "Alexander Miller" . "alexanderm@web.de") (:url . "https://github.com/Alexander-Miller/treemacs"))]) (treemacs-all-the-icons . [(20240131 2042) ((emacs (26 1)) (all-the-icons (4 0 1)) (treemacs (0 0))) "all-the-icons integration for treemacs" tar ((:commit . "bcba09c1581c4bd93ff0217d464aead04f6d26d4") (:authors ("Eric Dallo" . "ercdll1337@gmail.com")) (:maintainers ("Eric Dallo" . "ercdll1337@gmail.com")) (:maintainer "Eric Dallo" . "ercdll1337@gmail.com") (:url . "https://github.com/Alexander-Miller/treemacs"))]) (treemacs-evil . [(20240131 2042) ((emacs (26 1)) (evil (1 2 12)) (treemacs (0 0))) "Evil mode integration for treemacs" tar ((:commit . "bcba09c1581c4bd93ff0217d464aead04f6d26d4") (:authors ("Alexander Miller" . "alexanderm@web.de")) (:maintainers ("Alexander Miller" . "alexanderm@web.de")) (:maintainer "Alexander Miller" . "alexanderm@web.de") (:url . "https://github.com/Alexander-Miller/treemacs"))]) (treemacs-icons-dired . [(20240131 2042) ((treemacs (0 0)) (emacs (26 1))) "Treemacs icons for dired" tar ((:commit . "bcba09c1581c4bd93ff0217d464aead04f6d26d4") (:authors ("Alexander Miller" . "alexanderm@web.de")) (:maintainers ("Alexander Miller" . "alexanderm@web.de")) (:maintainer "Alexander Miller" . "alexanderm@web.de") (:url . "https://github.com/Alexander-Miller/treemacs"))]) @@ -5336,7 +5334,7 @@ (treemacs-tab-bar . [(20240131 2042) ((emacs (27 1)) (treemacs (0 0)) (dash (2 11 0))) "Tab bar integration for treemacs" tar ((:commit . "bcba09c1581c4bd93ff0217d464aead04f6d26d4") (:authors ("Alexander Miller" . "alexanderm@web.de") ("Jason Dufair" . "jase@dufair.org") ("Aaron Jensen" . "aaronjensen@gmail.com")) (:maintainers ("Alexander Miller" . "alexanderm@web.de") ("Jason Dufair" . "jase@dufair.org") ("Aaron Jensen" . "aaronjensen@gmail.com")) (:maintainer "Alexander Miller" . "alexanderm@web.de") (:url . "https://github.com/Alexander-Miller/treemacs"))]) (treepy . [(20230715 2154) ((emacs (25 1))) "Generic tree traversal tools" tar ((:commit . "75fe3ec37e6f9b2bdfd6d0584efd984d0c00a43e") (:authors ("Daniel Barreto" . "daniel.barreto.n@gmail.com")) (:maintainers ("Daniel Barreto" . "daniel.barreto.n@gmail.com")) (:maintainer "Daniel Barreto" . "daniel.barreto.n@gmail.com") (:keywords "lisp" "maint" "tools") (:url . "https://github.com/volrath/treepy.el"))]) (treesit-auto . [(20240511 1425) ((emacs (29 0))) "Automatically use tree-sitter enhanced major modes" tar ((:commit . "016bd286a1ba4628f833a626f8b9d497882ecdf3") (:authors ("Robb Enzmann" . "robbenzmann@gmail.com")) (:maintainers ("Robb Enzmann" . "robbenzmann@gmail.com")) (:maintainer "Robb Enzmann" . "robbenzmann@gmail.com") (:keywords "treesitter" "auto" "automatic" "major" "mode" "fallback" "convenience") (:url . "https://github.com/renzmann/treesit-auto.git"))]) - (treesit-ispell . [(20240611 117) ((emacs (29 1))) "Run ispell on tree-sitter text nodes" tar ((:commit . "56740dccd5a72277fa05f19491e032e0c4701ad2") (:authors ("Erick Navarro" . "erick@navarro.io")) (:maintainers ("Erick Navarro" . "erick@navarro.io")) (:maintainer "Erick Navarro" . "erick@navarro.io") (:url . "https://github.com/erickgnavar/treesit-ispell.el"))]) + (treesit-ispell . [(20240816 145) ((emacs (29 1))) "Run ispell on tree-sitter text nodes" tar ((:commit . "9e06b5a37945f3ff96a5cfbb79ea3e4c2986bd6a") (:authors ("Erick Navarro" . "erick@navarro.io")) (:maintainers ("Erick Navarro" . "erick@navarro.io")) (:maintainer "Erick Navarro" . "erick@navarro.io") (:url . "https://github.com/erickgnavar/treesit-ispell.el"))]) (treeview . [(20230728 2343) ((emacs (24 4))) "A generic tree navigation library" tar ((:commit . "c6888e5f3aa0d72a7b4db625fcc2a847fd3bb1ce") (:authors ("Tilman Rassy" . "tilman.rassy@googlemail.com")) (:maintainers ("Tilman Rassy" . "tilman.rassy@googlemail.com")) (:maintainer "Tilman Rassy" . "tilman.rassy@googlemail.com") (:keywords "lisp" "tools" "internal" "convenience") (:url . "https://github.com/tilmanrassy/emacs-treeview"))]) (trident-mode . [(20190410 2036) ((emacs (24)) (slime (20130526)) (skewer-mode (1 5 0)) (dash (1 0 3))) "Live Parenscript interaction" tar ((:commit . "109a1bc10bd0c4b47679a6ca5c4cd27c7c8d4ccb") (:authors ("John Mastro" . "john.b.mastro@gmail.com")) (:maintainers ("John Mastro" . "john.b.mastro@gmail.com")) (:maintainer "John Mastro" . "john.b.mastro@gmail.com") (:keywords "languages" "lisp" "processes" "tools") (:url . "https://github.com/johnmastro/trident-mode.el"))]) (trimspace-mode . [(20240629 1843) ((emacs (24 3))) "A minor mode to trim trailing whitespace and newlines" tar ((:commit . "68fb627ba552644ddee0cf9048b2fefd722a59fb") (:authors ("Björn Lindström" . "bkhl@elektrubadur.se")) (:maintainers ("Björn Lindström" . "bkhl@elektrubadur.se")) (:maintainer "Björn Lindström" . "bkhl@elektrubadur.se") (:keywords "files" "convenience") (:url . "https://git.sr.ht/~bkhl/trimspace-mode"))]) @@ -5367,7 +5365,7 @@ (twittering-mode . [(20181121 1402) nil "Major mode for Twitter" tar ((:commit . "114891e8fdb4f06b1326a6cf795e49c205cf9e29") (:authors ("Tadashi MATSUO" . "tad@mymail.twin.ne.jp") ("Y. Hayamizu" . "y.hayamizu@gmail.com") ("Tsuyoshi CHO" . "Tsuyoshi.CHO+develop@Gmail.com") ("Alberto Garcia" . "agarcia@igalia.com") ("Xavier Maillard" . "xavier@maillard.im")) (:maintainers ("Tadashi MATSUO" . "tad@mymail.twin.ne.jp") ("Y. Hayamizu" . "y.hayamizu@gmail.com") ("Tsuyoshi CHO" . "Tsuyoshi.CHO+develop@Gmail.com") ("Alberto Garcia" . "agarcia@igalia.com") ("Xavier Maillard" . "xavier@maillard.im")) (:maintainer "Tadashi MATSUO" . "tad@mymail.twin.ne.jp") (:keywords "twitter" "web") (:url . "http://twmode.sf.net/"))]) (twtxt . [(20240730 151) ((emacs (25 1)) (request (0 2 0))) "A twtxt client for Emacs" tar ((:commit . "d6a0fc57bcc7dd4a4a76a0836beb33900878ea0b") (:authors ("DEADBLACKCLOVER" . "deadblackclover@protonmail.com")) (:maintainers ("DEADBLACKCLOVER" . "deadblackclover@protonmail.com")) (:maintainer "DEADBLACKCLOVER" . "deadblackclover@protonmail.com") (:url . "https://codeberg.org/deadblackclover/twtxt-el"))]) (typescript-mode . [(20240603 630) ((emacs (24 3))) "Major mode for editing typescript" tar ((:commit . "5bb294411ff06ad40186bb7ca141fdbfff902e09") (:keywords "typescript" "languages") (:url . "http://github.com/ananthakumaran/typescript.el"))]) - (typewriter-roll-mode . [(20240225 1412) ((emacs (24 1))) "Aid for distraction-free writing" tar ((:commit . "99afeb13bd0340a23176c4ebfdabc93117c04069") (:authors ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainers ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainer "Peter Badida" . "keyweeusr@gmail.com") (:keywords "convenience" "line" "carriage" "writing" "distraction" "cr" "rewind") (:url . "https://github.com/KeyWeeUsr/typewriter-roll-mode"))]) + (typewriter-roll-mode . [(20240817 928) ((emacs (24 1))) "Aid for distraction-free writing" tar ((:commit . "9ce34ea14616e478f10abc49727d9e9cee6c5dc3") (:authors ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainers ("Peter Badida" . "keyweeusr@gmail.com")) (:maintainer "Peter Badida" . "keyweeusr@gmail.com") (:keywords "convenience" "line" "carriage" "writing" "distraction" "cr" "rewind") (:url . "https://github.com/KeyWeeUsr/typewriter-roll-mode"))]) (typing . [(20180830 2203) nil "The Typing Of Emacs" tar ((:commit . "a2ef25dde2d8eb91bd9c0c6164cb5208208647fa") (:authors ("Alex Schroeder" . "alex@gnu.org")) (:maintainers ("Alex Schroeder" . "alex@gnu.org")) (:maintainer "Alex Schroeder" . "alex@gnu.org") (:keywords "games") (:url . "http://www.emacswiki.org/emacs/TypingOfEmacs"))]) (typing-game . [(20160426 1220) nil "a simple typing game" tar ((:commit . "616435a5270274f4c7b698697674dbb2039049a4") (:authors ("DarkSun" . "lujun9972@gmail.com")) (:maintainers ("DarkSun" . "lujun9972@gmail.com")) (:maintainer "DarkSun" . "lujun9972@gmail.com") (:keywords "lisp" "game"))]) (typit . [(20220909 1233) ((emacs (24 4)) (f (0 18)) (mmt (0 1 1))) "Typing game similar to tests on 10 fast fingers" tar ((:commit . "6ad0d5a106c4a4428fd131653bbe7c0aab4b5f60") (:authors ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainers ("Mark Karpov" . "markkarpov92@gmail.com")) (:maintainer "Mark Karpov" . "markkarpov92@gmail.com") (:keywords "games") (:url . "https://github.com/mrkkrp/typit"))]) @@ -5630,7 +5628,7 @@ (winum . [(20190911 1607) ((cl-lib (0 5)) (dash (2 13 0))) "Navigate windows and frames using numbers." tar ((:commit . "098249c65042ee0308b8236d1ee838c8da8fdf25") (:authors ("Thomas de Beauchêne" . "thomas.de.beauchene@gmail.com")) (:maintainers ("Thomas de Beauchêne" . "thomas.de.beauchene@gmail.com")) (:maintainer "Thomas de Beauchêne" . "thomas.de.beauchene@gmail.com") (:keywords "convenience" "frames" "windows" "multi-screen") (:url . "http://github.com/deb0ch/winum.el"))]) (wisp-mode . [(20220529 1522) ((emacs (24 4))) "Tools for wisp: the Whitespace-to-Lisp preprocessor" tar ((:commit . "1a01003d400db8a42838cabcb26c06d627246a17") (:authors ("Arne Babenhauserheide" . "arne_bab@web.de")) (:maintainers ("Arne Babenhauserheide" . "arne_bab@web.de")) (:maintainer "Arne Babenhauserheide" . "arne_bab@web.de") (:keywords "languages" "lisp" "scheme") (:url . "http://www.draketo.de/english/wisp"))]) (wispjs-mode . [(20170720 1919) ((clojure-mode (0))) "Major mode for Wisp code." tar ((:commit . "60f9f5fd9d1556e2d008939f67eb1b1d0f325fa8") (:authors ("Kris Jenkins" . "krisajenkins@gmail.com")) (:maintainers ("Kris Jenkins" . "krisajenkins@gmail.com")) (:maintainer "Kris Jenkins" . "krisajenkins@gmail.com") (:url . "https://github.com/krisajenkins/wispjs-mode"))]) - (with-editor . [(20240806 1454) ((emacs (26 1)) (compat (30 0 0 0))) "Use the Emacsclient as $EDITOR" tar ((:commit . "78c303a0181f2132e2254f965176b549044d74f2") (:authors ("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev") (:keywords "processes" "terminals") (:url . "https://github.com/magit/with-editor"))]) + (with-editor . [(20240817 1959) ((emacs (26 1)) (compat (30 0 0 0))) "Use the Emacsclient as $EDITOR" tar ((:commit . "8c550d9e799a0baedb2164471e7ed19fc15d9196") (:authors ("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) (:maintainers ("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) (:maintainer "Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev") (:keywords "processes" "terminals") (:url . "https://github.com/magit/with-editor"))]) (with-emacs . [(20220814 444) ((emacs (24 4))) "Evaluate Emacs Lisp expressions in a separate Emacs process" tar ((:commit . "fb9ef454a4bb2d6de3415807b4858a20a9cc0dad") (:authors ("Gong Qijian" . "gongqijian@gmail.com")) (:maintainers ("Gong Qijian" . "gongqijian@gmail.com")) (:maintainer "Gong Qijian" . "gongqijian@gmail.com") (:keywords "tools") (:url . "https://github.com/twlz0ne/with-emacs.el"))]) (with-namespace . [(20130407 1822) ((dash (1 1 0)) (loop (1 1))) "interoperable elisp namespaces" tar ((:commit . "36828a40428c8e53c117f2df830b2f7a59ddd306") (:authors ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainers ("Wilfred Hughes" . "me@wilfred.me.uk")) (:maintainer "Wilfred Hughes" . "me@wilfred.me.uk") (:keywords "namespaces"))]) (with-proxy . [(20200510 414) ((emacs (24 4))) "Evaluate expressions with proxy" tar ((:commit . "93b1ed2f3060f305009fa71f4fb5bb10173a10e3") (:authors ("Gong Qijian" . "gongqijian@gmail.com")) (:maintainers ("Gong Qijian" . "gongqijian@gmail.com")) (:maintainer "Gong Qijian" . "gongqijian@gmail.com") (:keywords "comm") (:url . "https://github.com/twlz0ne/with-proxy.el"))]) diff --git a/emacs/elpa/archives/nongnu/archive-contents b/emacs/elpa/archives/nongnu/archive-contents @@ -475,7 +475,7 @@ (:maintainer "tienne Deparis" . "etienne@depar.is") (:commit . "29d5180f7e34c0c858a520068fb650f705b8cfc2"))]) (drupal-mode . - [(0 7 4) + [(0 8 1) ((php-mode (1 5 0))) "Advanced minor mode for Drupal development" tar @@ -484,7 +484,7 @@ (:maintainer "Arne Jørgensen" . "arne@arnested.dk") (:authors ("Arne Jørgensen" . "arne@arnested.dk")) - (:commit . "ed90b0c4d808365e9ae9f16cc8a96eff17815621"))]) + (:commit . "f632fa5f140b04260fa23b15ffccbfe5a787b2e2"))]) (dslide . [(0 5 3) ((emacs @@ -1527,7 +1527,7 @@ ("Jason R. Blevins" . "jblevins@xbeta.org")) (:commit . "193b61605f44c85d261b8bd82e0a213fd8f1ff32"))]) (mastodon . - [(1 0 24) + [(1 0 26) ((emacs (27 1)) (request @@ -1540,7 +1540,7 @@ (:authors ("Johnson Denen" . "johnson.denen@gmail.com") ("Marty Hiatt" . "martianhiatus@riseup.net")) - (:commit . "d1baf1eed450b5dc5ddb8555d29eec3bb969a4fb"))]) + (:commit . "3443b49c55f65ae8e0b07e93e1e0299ce1bf8ed6"))]) (material-theme . [(2015) ((emacs @@ -1736,14 +1736,14 @@ ((:url . "http://github.com/bastibe/org-journal") (:commit . "18df4d5ae5e15580df42562c143d007c6d28d75f"))]) (org-mime . - [(0 3 2) + [(0 3 3) ((emacs - (25 1))) + (27 1))) "org html export for text/html MIME emails" tar ((:url . "http://github.com/org-mime/org-mime") (:keywords "mime" "mail" "email" "html") (:maintainer "Chen Bin" . "chenbin.sh@gmail.com") - (:commit . "cc00afcf0291633324364c1c83bfe2833cfdc1bf"))]) + (:commit . "468604b8404d3c7d6148be83a4cf308ee95d2cfb"))]) (org-present . [(0 1) ((org @@ -1988,7 +1988,7 @@ ("David Christiansen" . "david@davidchristiansen.dk")) (:commit . "1edda80e2e32b72e77f4f16ae5b83c312c68ee95"))]) (racket-mode . - [(1 0 20240810 92632) + [(1 0 20240813 124142) ((emacs (25 1))) "Racket editing, REPL, and more" tar diff --git a/emacs/elpa/archives/nongnu/archive-contents.signed b/emacs/elpa/archives/nongnu/archive-contents.signed @@ -1 +1 @@ -Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2024-08-14T09:10:04+0000 using EDDSA -\ No newline at end of file +Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasign@elpa.gnu.org> (trust undefined) created at 2024-08-18T09:10:05+0000 using EDDSA +\ No newline at end of file diff --git a/emacs/elpa/cape-20240724.918/cape-autoloads.el b/emacs/elpa/cape-20240724.918/cape-autoloads.el @@ -1,238 +0,0 @@ -;;; cape-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from cape.el - -(autoload 'cape-history "cape" "\ -Complete from Eshell, Comint or minibuffer history. -See also `consult-history' for a more flexible variant based on -`completing-read'. If INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-file "cape" "\ -Complete file name at point. -See the user option `cape-file-directory-must-exist'. -If INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-elisp-symbol "cape" "\ -Complete Elisp symbol at point. -If INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-elisp-block "cape" "\ -Complete Elisp in Org or Markdown code block. -This Capf is particularly useful for literate Emacs configurations. -If INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-dabbrev "cape" "\ -Complete with Dabbrev at point. - -If INTERACTIVE is nil the function acts like a Capf. In case you -observe a performance issue with auto-completion and `cape-dabbrev' -it is strongly recommended to disable scanning in other buffers. -See the user options `cape-dabbrev-min-length' and -`cape-dabbrev-check-other-buffers'. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-dict "cape" "\ -Complete word from dictionary at point. -This completion function works best if the dictionary is sorted -by frequency. See the custom option `cape-dict-file'. If -INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-abbrev "cape" "\ -Complete abbreviation at point. -If INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-line "cape" "\ -Complete current line from other lines. -The buffers returned by `cape-line-buffer-function' are scanned for lines. -If INTERACTIVE is nil the function acts like a Capf. - -(fn &optional INTERACTIVE)" t) -(autoload 'cape-company-to-capf "cape" "\ -Convert Company BACKEND function to Capf. -VALID is a function taking the old and new input string. It should -return nil if the cached candidates became invalid. The default value -for VALID is `string-prefix-p' such that the candidates are only fetched -again if the input prefix changed. - -(fn BACKEND &optional VALID)") -(autoload 'cape-interactive "cape" "\ -Complete interactively with the given CAPFS. - -(fn &rest CAPFS)") -(autoload 'cape-capf-interactive "cape" "\ -Create interactive completion function from CAPF. - -(fn CAPF)") -(autoload 'cape-wrap-super "cape" "\ -Call CAPFS and return merged completion result. -The CAPFS list can contain the keyword `:with' to mark the Capfs -afterwards as auxiliary One of the non-auxiliary Capfs before -`:with' must return non-nil for the super Capf to set in and -return a non-nil result. Such behavior is useful when listing -multiple super Capfs in the `completion-at-point-functions': - - (setq completion-at-point-functions - (list (cape-capf-super \\='eglot-completion-at-point - :with \\='tempel-complete) - (cape-capf-super \\='cape-dabbrev - :with \\='tempel-complete))) - -(fn &rest CAPFS)") -(autoload 'cape-wrap-debug "cape" "\ -Call CAPF and return a completion table which prints trace messages. -If CAPF is an anonymous lambda, pass the Capf NAME explicitly for -meaningful debugging output. - -(fn CAPF &optional NAME)") -(autoload 'cape-wrap-buster "cape" "\ -Call CAPF and return a completion table with cache busting. -This function can be used as an advice around an existing Capf. -The cache is busted when the input changes. The argument VALID -can be a function taking the old and new input string. It should -return nil if the new input requires that the completion table is -refreshed. The default value for VALID is `equal', such that the -completion table is refreshed on every input change. - -(fn CAPF &optional VALID)") -(autoload 'cape-wrap-passthrough "cape" "\ -Call CAPF and make sure that no completion style filtering takes place. - -(fn CAPF)") -(autoload 'cape-wrap-properties "cape" "\ -Call CAPF and add additional completion PROPERTIES. -Completion properties include for example :exclusive, :annotation-function and -the various :company-* extensions. Furthermore a boolean :sort flag and a -completion :category symbol can be specified. - -(fn CAPF &rest PROPERTIES)") -(autoload 'cape-wrap-nonexclusive "cape" "\ -Call CAPF and ensure that it is marked as non-exclusive. -This function can be used as an advice around an existing Capf. - -(fn CAPF)") -(autoload 'cape-wrap-predicate "cape" "\ -Call CAPF and add an additional candidate PREDICATE. -The PREDICATE is passed the candidate symbol or string. - -(fn CAPF PREDICATE)") -(autoload 'cape-wrap-silent "cape" "\ -Call CAPF and silence it (no messages, no errors). -This function can be used as an advice around an existing Capf. - -(fn CAPF)") -(autoload 'cape-wrap-case-fold "cape" "\ -Call CAPF and return a case-insensitive completion table. -If DONT-FOLD is non-nil return a case sensitive table instead. -This function can be used as an advice around an existing Capf. - -(fn CAPF &optional DONT-FOLD)") -(autoload 'cape-wrap-noninterruptible "cape" "\ -Call CAPF and return a non-interruptible completion table. -This function can be used as an advice around an existing Capf. - -(fn CAPF)") -(autoload 'cape-wrap-prefix-length "cape" "\ -Call CAPF and ensure that prefix length is greater or equal than LENGTH. -If the prefix is long enough, enforce auto completion. - -(fn CAPF LENGTH)") -(autoload 'cape-wrap-inside-faces "cape" "\ -Call CAPF only if inside FACES. -This function can be used as an advice around an existing Capf. - -(fn CAPF &rest FACES)") -(autoload 'cape-wrap-inside-code "cape" "\ -Call CAPF only if inside code, not inside a comment or string. -This function can be used as an advice around an existing Capf. - -(fn CAPF)") -(autoload 'cape-wrap-inside-comment "cape" "\ -Call CAPF only if inside comment. -This function can be used as an advice around an existing Capf. - -(fn CAPF)") -(autoload 'cape-wrap-inside-string "cape" "\ -Call CAPF only if inside string. -This function can be used as an advice around an existing Capf. - -(fn CAPF)") -(autoload 'cape-wrap-purify "cape" "\ -Call CAPF and ensure that it does not illegally modify the buffer. -This function can be used as an advice around an existing -Capf. It has been introduced mainly to fix the broken -`pcomplete-completions-at-point' function in Emacs versions < 29. - -(fn CAPF)") -(autoload 'cape-wrap-accept-all "cape" "\ -Call CAPF and return a completion table which accepts every input. -This function can be used as an advice around an existing Capf. - -(fn CAPF)") - (autoload 'cape-capf-accept-all "cape") - (autoload 'cape-capf-buster "cape") - (autoload 'cape-capf-case-fold "cape") - (autoload 'cape-capf-debug "cape") - (autoload 'cape-capf-inside-code "cape") - (autoload 'cape-capf-inside-comment "cape") - (autoload 'cape-capf-inside-faces "cape") - (autoload 'cape-capf-inside-string "cape") - (autoload 'cape-capf-nonexclusive "cape") - (autoload 'cape-capf-noninterruptible "cape") - (autoload 'cape-capf-passthrough "cape") - (autoload 'cape-capf-predicate "cape") - (autoload 'cape-capf-prefix-length "cape") - (autoload 'cape-capf-properties "cape") - (autoload 'cape-capf-purify "cape") - (autoload 'cape-capf-silent "cape") - (autoload 'cape-capf-super "cape") - (autoload 'cape-prefix-map "cape" nil t 'keymap) -(register-definition-prefixes "cape" '("cape-")) - - -;;; Generated autoloads from cape-char.el - - (autoload 'cape-tex "cape-char" nil t) - (autoload 'cape-sgml "cape-char" nil t) - (autoload 'cape-rfc1345 "cape-char" nil t) - (when (> emacs-major-version 28) (autoload 'cape-emoji "cape-char" nil t)) -(register-definition-prefixes "cape-char" '("cape-char--")) - - -;;; Generated autoloads from cape-keyword.el - -(autoload 'cape-keyword "cape-keyword" "\ -Complete programming language keyword at point. -See the variable `cape-keyword-list'. -If INTERACTIVE is nil the function acts like a capf. - -(fn &optional INTERACTIVE)" t) -(register-definition-prefixes "cape-keyword" '("cape-")) - -;;; End of scraped data - -(provide 'cape-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; cape-autoloads.el ends here diff --git a/emacs/elpa/cape-20240724.918/cape-pkg.el b/emacs/elpa/cape-20240724.918/cape-pkg.el @@ -1,15 +0,0 @@ -(define-package "cape" "20240724.918" "Completion At Point Extensions" - '((emacs "27.1") - (compat "30")) - :commit "5c468d6d657e8dc604ddf3feb80f70e1e05ac0a1" :authors - '(("Daniel Mendler" . "mail@daniel-mendler.de")) - :maintainers - '(("Daniel Mendler" . "mail@daniel-mendler.de")) - :maintainer - '("Daniel Mendler" . "mail@daniel-mendler.de") - :keywords - '("abbrev" "convenience" "matching" "completion" "text") - :url "https://github.com/minad/cape") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/cape-20240724.918/cape.el b/emacs/elpa/cape-20240724.918/cape.el @@ -1,1300 +0,0 @@ -;;; cape.el --- Completion At Point Extensions -*- lexical-binding: t -*- - -;; Copyright (C) 2021-2024 Free Software Foundation, Inc. - -;; Author: Daniel Mendler <mail@daniel-mendler.de> -;; Maintainer: Daniel Mendler <mail@daniel-mendler.de> -;; Created: 2021 -;; Version: 1.6 -;; Package-Requires: ((emacs "27.1") (compat "30")) -;; Homepage: https://github.com/minad/cape -;; Keywords: abbrev, convenience, matching, completion, text - -;; This file is part of GNU Emacs. - -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; Let your completions fly! This package provides additional completion -;; backends in the form of Capfs (completion-at-point-functions). -;; -;; `cape-abbrev': Complete abbreviation (add-global-abbrev, add-mode-abbrev). -;; `cape-dabbrev': Complete word from current buffers. -;; `cape-dict': Complete word from dictionary file. -;; `cape-elisp-block': Complete Elisp in Org or Markdown code block. -;; `cape-elisp-symbol': Complete Elisp symbol. -;; `cape-emoji': Complete Emoji. -;; `cape-file': Complete file name. -;; `cape-history': Complete from Eshell, Comint or minibuffer history. -;; `cape-keyword': Complete programming language keyword. -;; `cape-line': Complete entire line from file. -;; `cape-rfc1345': Complete Unicode char using RFC 1345 mnemonics. -;; `cape-sgml': Complete Unicode char from SGML entity, e.g., &alpha. -;; `cape-tex': Complete Unicode char from TeX command, e.g. \hbar. - -;;; Code: - -(require 'compat) -(eval-when-compile - (require 'cl-lib) - (require 'subr-x)) - -;;;; Customization - -(defgroup cape nil - "Completion At Point Extensions." - :link '(info-link :tag "Info Manual" "(cape)") - :link '(url-link :tag "Homepage" "https://github.com/minad/cape") - :link '(emacs-library-link :tag "Library Source" "cape.el") - :group 'convenience - :group 'tools - :group 'matching - :prefix "cape-") - -(defcustom cape-dict-limit 100 - "Maximal number of completion candidates returned by `cape-dict'." - :type '(choice (const nil) natnum)) - -(defcustom cape-dict-file "/usr/share/dict/words" - "Path to dictionary word list file. -This variable can also be a list of paths or -a function returning a single or more paths." - :type '(choice string (repeat string) function)) - -(defcustom cape-dict-case-replace 'case-replace - "Preserve case of input. -See `dabbrev-case-replace' for details." - :type '(choice (const :tag "off" nil) - (const :tag "use `case-replace'" case-replace) - (other :tag "on" t))) - -(defcustom cape-dict-case-fold 'case-fold-search - "Case fold search during search. -See `dabbrev-case-fold-search' for details." - :type '(choice (const :tag "off" nil) - (const :tag "use `case-fold-search'" case-fold-search) - (other :tag "on" t))) - -(defcustom cape-dabbrev-min-length 4 - "Minimum length of Dabbrev expansions. -This setting ensures that words which are too short -are not offered as completion candidates, such that -auto completion does not pop up too aggressively." - :type 'natnum) - -(defcustom cape-dabbrev-check-other-buffers t - "Buffers to check for Dabbrev. - -If t, check all other buffers, subject to Dabbrev ignore rules. -If a function, only search the buffers returned by this function. -Any other non-nil value only checks some other buffers, as per -`dabbrev-select-buffers-function'." - :type `(choice (const :tag "off" nil) - (const :tag "same-mode buffers" ,#'cape--buffers-major-mode) - (function :tag "function") - (const :tag "some" some) - (other :tag "all" t))) - -(defcustom cape-file-directory nil - "Base directory used by `cape-file." - :type '(choice (const nil) string function)) - -(defcustom cape-file-prefix "file:" - "File completion trigger prefixes. -The value can be a string or a list of strings. The default -`file:' is the prefix of Org file links which work in arbitrary -buffers via `org-open-at-point-global'." - :type '(choice string (repeat string))) - -(defcustom cape-file-directory-must-exist t - "The parent directory must exist for file completion." - :type 'boolean) - -(defcustom cape-line-buffer-function #'cape--buffers-major-mode - "Function which returns list of buffers. -The buffers are scanned for completion candidates by `cape-line'." - :type '(choice (const :tag "Current buffer" current-buffer) - (const :tag "All buffers" buffer-list) - (const :tag "Buffers with same major mode" cape--buffers-major-mode) - (function :tag "Custom function"))) - -(defcustom cape-elisp-symbol-wrapper - '((org-mode ?~ ?~) - (markdown-mode ?` ?`) - (rst-mode "``" "``") - (log-edit-mode "`" "'") - (change-log-mode "`" "'") - (message-mode "`" "'") - (rcirc-mode "`" "'")) - "Wrapper characters for symbols." - :type '(alist :key-type symbol :value-type (list (choice character string) - (choice character string)))) - -;;;; Helpers - -(defun cape--case-fold-p (fold) - "Return non-nil if case folding is enabled for FOLD." - (if (eq fold 'case-fold-search) case-fold-search fold)) - -(defun cape--case-replace-list (flag input strs) - "Replace case of STRS depending on INPUT and FLAG." - (if (and (if (eq flag 'case-replace) case-replace flag) - (let (case-fold-search) (string-match-p "\\`[[:upper:]]" input))) - (mapcar (apply-partially #'cape--case-replace flag input) strs) - strs)) - -(defun cape--case-replace (flag input str) - "Replace case of STR depending on INPUT and FLAG." - (or (and (if (eq flag 'case-replace) case-replace flag) - (string-prefix-p input str t) - (let (case-fold-search) (string-match-p "\\`[[:upper:]]" input)) - (save-match-data - ;; Ensure that single character uppercase input does not lead to an - ;; all uppercase result. - (when (and (= (length input) 1) (> (length str) 1)) - (setq input (concat input (substring str 1 2)))) - (and (string-match input input) - (replace-match str nil nil input)))) - str)) - -(defun cape--separator-p (str) - "Return non-nil if input STR has a separator character. -Separator characters are used by completion styles like Orderless -to split filter words. In Corfu, the separator is configurable -via the variable `corfu-separator'." - (string-search (string ;; Support `corfu-separator' and Orderless - (or (and (bound-and-true-p corfu-mode) - (bound-and-true-p corfu-separator)) - ?\s)) - str)) - -(defmacro cape--silent (&rest body) - "Silence BODY." - (declare (indent 0)) - `(cl-letf ((inhibit-message t) - (message-log-max nil) - ((symbol-function #'minibuffer-message) #'ignore)) - (ignore-errors ,@body))) - -(defun cape--bounds (thing) - "Return bounds of THING." - (or (bounds-of-thing-at-point thing) (cons (point) (point)))) - -(defmacro cape--wrapped-table (wrap body) - "Create wrapped completion table, handle `completion--unquote'. -WRAP is the wrapper function. -BODY is the wrapping expression." - (declare (indent 1)) - `(lambda (str pred action) - (,@body - (let ((result (complete-with-action action table str pred))) - (when (and (eq action 'completion--unquote) (functionp (cadr result))) - (cl-callf ,wrap (cadr result))) - result)))) - -(defun cape--accept-all-table (table) - "Create completion TABLE which accepts all input." - (cape--wrapped-table cape--accept-all-table - (or (eq action 'lambda)))) - -(defun cape--passthrough-table (table) - "Create completion TABLE disabling any filtering." - (cape--wrapped-table cape--passthrough-table - (let (completion-ignore-case completion-regexp-list (_ (setq str "")))))) - -(defun cape--noninterruptible-table (table) - "Create non-interruptible completion TABLE." - (cape--wrapped-table cape--noninterruptible-table - (let (throw-on-input)))) - -(defun cape--silent-table (table) - "Create a new completion TABLE which is silent (no messages, no errors)." - (cape--wrapped-table cape--silent-table - (cape--silent))) - -(defun cape--nonessential-table (table) - "Mark completion TABLE as `non-essential'." - (let ((dir default-directory)) - (cape--wrapped-table cape--nonessential-table - (let ((default-directory dir) - (non-essential t)))))) - -(defvar cape--debug-length 5 - "Length of printed lists in `cape--debug-print'.") - -(defvar cape--debug-id 0 - "Completion table identifier.") - -(defun cape--debug-message (&rest msg) - "Print debug MSG." - (let ((inhibit-message t)) - (apply #'message msg))) - -(defun cape--debug-print (obj &optional full) - "Print OBJ as string, truncate lists if FULL is nil." - (cond - ((symbolp obj) (symbol-name obj)) - ((functionp obj) "#<function>") - ((proper-list-p obj) - (concat - "(" - (string-join - (mapcar #'cape--debug-print - (if full obj (take cape--debug-length obj))) - " ") - (if (and (not full) (length> obj cape--debug-length)) " ...)" ")"))) - (t (let ((print-level 2)) - (prin1-to-string obj))))) - -(defun cape--debug-table (table name beg end) - "Create completion TABLE with debug messages. -NAME is the name of the Capf, BEG and END are the input markers." - (lambda (str pred action) - (let ((result (complete-with-action action table str pred))) - (if (and (eq action 'completion--unquote) (functionp (cadr result))) - ;; See `cape--wrapped-table' - (cl-callf cape--debug-table (cadr result) name beg end) - (cape--debug-message - "%s(action=%S input=%s:%s:%S prefix=%S ignore-case=%S%s%s) => %s" - name - (pcase action - ('nil 'try) - ('t 'all) - ('lambda 'test) - (_ action)) - (+ beg 0) (+ end 0) (buffer-substring-no-properties beg end) - str completion-ignore-case - (if completion-regexp-list - (format " regexp=%s" (cape--debug-print completion-regexp-list t)) - "") - (if pred - (format " predicate=%s" (cape--debug-print pred)) - "") - (cape--debug-print result))) - result))) - -(cl-defun cape--properties-table (table &key category (sort t) &allow-other-keys) - "Create completion TABLE with properties. -CATEGORY is the optional completion category. -SORT should be nil to disable sorting." - ;; The metadata will be overridden if the category is non-nil, if the table is - ;; a function table or if sorting should be disabled for a non-nil - ;; non-function table. - (if (or category (functionp table) (and (not sort) table)) - (let ((metadata `(metadata - ,@(and category `((category . ,category))) - ,@(and (not sort) '((display-sort-function . identity) - (cycle-sort-function . identity)))))) - (lambda (str pred action) - (if (eq action 'metadata) - metadata - (complete-with-action action table str pred)))) - table)) - -(defun cape--dynamic-table (beg end fun) - "Create dynamic completion table from FUN with caching. -BEG and END are the input bounds. FUN is the function which -computes the candidates. FUN must return a pair of a predicate -function function and the list of candidates. The predicate is -passed new input and must return non-nil if the candidates are -still valid. - -It is only necessary to use this function if the set of -candidates is computed dynamically based on the input and not -statically determined. The behavior is similar but slightly -different to `completion-table-dynamic'. - -The difference to the builtins `completion-table-dynamic' and -`completion-table-with-cache' is that this function does not use -the prefix argument of the completion table to compute the -candidates. Instead it uses the input in the buffer between BEG -and END to FUN to compute the candidates. This way the dynamic -candidate computation is compatible with non-prefix completion -styles like `substring' or `orderless', which pass the empty -string as first argument to the completion table." - (let ((beg (copy-marker beg)) - (end (copy-marker end t)) - valid table) - (lambda (str pred action) - ;; Bail out early for `metadata' and `boundaries'. This is a pointless - ;; move because of caching, but we do it anyway in the hope that the - ;; profiler report looks less confusing, since the weight of the expensive - ;; FUN computation is moved to the `all-completions' action. Computing - ;; `all-completions' must surely be most expensive, so nobody will suspect - ;; a thing. - (unless (or (eq action 'metadata) (eq (car-safe action) 'boundaries)) - (let ((input (buffer-substring-no-properties beg end))) - (unless (and valid - (or (cape--separator-p input) - (funcall valid input))) - (let* (;; Reset in case `all-completions' is used inside FUN - completion-ignore-case completion-regexp-list - ;; Retrieve new state by calling FUN - (new (funcall fun input)) - ;; No interrupt during state update - throw-on-input) - (setq valid (car new) table (cdr new))))) - (complete-with-action action table str pred))))) - -;;;; Capfs - -;;;;; cape-history - -(declare-function ring-elements "ring") -(declare-function eshell-bol "eshell") -(declare-function comint-line-beginning-position "comint") -(defvar eshell-history-ring) -(defvar comint-input-ring) - -(defvar cape--history-properties - (list :company-kind (lambda (_) 'text) - :exclusive 'no) - "Completion extra properties for `cape-history'.") - -;;;###autoload -(defun cape-history (&optional interactive) - "Complete from Eshell, Comint or minibuffer history. -See also `consult-history' for a more flexible variant based on -`completing-read'. If INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (if interactive - (cape-interactive #'cape-history) - (let (history bol) - (cond - ((derived-mode-p 'eshell-mode) - (setq history eshell-history-ring - bol (static-if (< emacs-major-version 30) - (save-excursion (eshell-bol) (point)) - (line-beginning-position)))) - ((derived-mode-p 'comint-mode) - (setq history comint-input-ring - bol (comint-line-beginning-position))) - ((and (minibufferp) (not (eq minibuffer-history-variable t))) - (setq history (symbol-value minibuffer-history-variable) - bol (line-beginning-position)))) - (when (ring-p history) - (setq history (ring-elements history))) - (when history - `(,bol ,(point) - ,(cape--properties-table history :sort nil) - ,@cape--history-properties))))) - -;;;;; cape-file - -(defvar comint-unquote-function) -(defvar comint-requote-function) - -(defvar cape--file-properties - (list :annotation-function (lambda (s) (if (string-suffix-p "/" s) " Dir" " File")) - :company-kind (lambda (s) (if (string-suffix-p "/" s) 'folder 'file)) - :exclusive 'no) - "Completion extra properties for `cape-file'.") - -;;;###autoload -(defun cape-file (&optional interactive) - "Complete file name at point. -See the user option `cape-file-directory-must-exist'. -If INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (if interactive - (cape-interactive '(cape-file-directory-must-exist) #'cape-file) - (pcase-let* ((default-directory (pcase cape-file-directory - ('nil default-directory) - ((pred stringp) cape-file-directory) - (_ (funcall cape-file-directory)))) - (prefix (and cape-file-prefix - (looking-back - (concat - (regexp-opt (ensure-list cape-file-prefix) t) - "[^ \n\t]*") - (pos-bol)) - (match-end 1))) - (`(,beg . ,end) (if prefix - (cons prefix (point)) - (cape--bounds 'filename))) - (non-essential t) - (file (buffer-substring-no-properties beg end))) - (when (or prefix - (not cape-file-directory-must-exist) - (and (string-search "/" file) - (file-exists-p (file-name-directory file)))) - `(,beg ,end - ,(cape--nonessential-table - (if (or (derived-mode-p 'comint-mode) (derived-mode-p 'eshell-mode)) - (completion-table-with-quoting - #'read-file-name-internal - comint-unquote-function - comint-requote-function) - #'read-file-name-internal)) - ,@(when (or prefix (string-match-p "./" file)) - '(:company-prefix-length t)) - ,@cape--file-properties))))) - -;;;;; cape-elisp-symbol - -(defvar cape--symbol-properties - (append - (list :annotation-function #'cape--symbol-annotation - :exit-function #'cape--symbol-exit - :predicate #'cape--symbol-predicate - :exclusive 'no) - (when (eval-when-compile (>= emacs-major-version 28)) - (autoload 'elisp--company-kind "elisp-mode") - (autoload 'elisp--company-doc-buffer "elisp-mode") - (autoload 'elisp--company-doc-string "elisp-mode") - (autoload 'elisp--company-location "elisp-mode") - (list :company-kind 'elisp--company-kind - :company-doc-buffer 'elisp--company-doc-buffer - :company-docsig 'elisp--company-doc-string - :company-location 'elisp--company-location))) - "Completion extra properties for `cape-elisp-symbol'.") - -(defun cape--symbol-predicate (sym) - "Return t if SYM is bound, fbound or propertized." - (or (fboundp sym) (boundp sym) (symbol-plist sym))) - -(defun cape--symbol-exit (name status) - "Wrap symbol NAME with `cape-elisp-symbol-wrapper' buffers. -STATUS is the exit status." - (when-let (((not (eq status 'exact))) - (c (cl-loop for (m . c) in cape-elisp-symbol-wrapper - if (derived-mode-p m) return c))) - (save-excursion - (backward-char (length name)) - (insert (car c))) - (insert (cadr c)))) - -(defun cape--symbol-annotation (sym) - "Return kind of SYM." - (setq sym (intern-soft sym)) - (cond - ((special-form-p sym) " Special") - ((macrop sym) " Macro") - ((commandp sym) " Command") - ((fboundp sym) " Function") - ((custom-variable-p sym) " Custom") - ((boundp sym) " Variable") - ((featurep sym) " Feature") - ((facep sym) " Face") - (t " Symbol"))) - -;;;###autoload -(defun cape-elisp-symbol (&optional interactive) - "Complete Elisp symbol at point. -If INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (if interactive - ;; No cycling since it breaks the :exit-function. - (let (completion-cycle-threshold) - (cape-interactive #'cape-elisp-symbol)) - (pcase-let ((`(,beg . ,end) (cape--bounds 'symbol))) - (when (eq (char-after beg) ?') - (setq beg (1+ beg) end (max beg end))) - `(,beg ,end - ,(cape--properties-table obarray :category 'symbol) - ,@cape--symbol-properties)))) - -;;;;; cape-elisp-block - -(declare-function org-element-context "org-element") -(declare-function markdown-code-block-lang "ext:markdown-mode") - -(defun cape--inside-block-p (&rest langs) - "Return non-nil if inside LANGS code block." - (when-let ((face (get-text-property (point) 'face)) - (lang (or (and (if (listp face) - (memq 'org-block face) - (eq 'org-block face)) - (plist-get (cadr (org-element-context)) :language)) - (and (if (listp face) - (memq 'markdown-code-face face) - (eq 'markdown-code-face face)) - (save-excursion - (markdown-code-block-lang)))))) - (member lang langs))) - -;;;###autoload -(defun cape-elisp-block (&optional interactive) - "Complete Elisp in Org or Markdown code block. -This Capf is particularly useful for literate Emacs configurations. -If INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (cond - (interactive - ;; No code block check. Always complete Elisp when command was - ;; explicitly invoked interactively. - (cape-interactive #'elisp-completion-at-point)) - ((cape--inside-block-p "elisp" "emacs-lisp") - (elisp-completion-at-point)))) - -;;;;; cape-dabbrev - -(defvar cape--dabbrev-properties - (list :annotation-function (lambda (_) " Dabbrev") - :company-kind (lambda (_) 'text) - :exclusive 'no) - "Completion extra properties for `cape-dabbrev'.") - -(defvar dabbrev-case-replace) -(defvar dabbrev-case-fold-search) -(defvar dabbrev-abbrev-char-regexp) -(defvar dabbrev-abbrev-skip-leading-regexp) -(declare-function dabbrev--find-all-expansions "dabbrev") -(declare-function dabbrev--reset-global-variables "dabbrev") - -(defun cape--dabbrev-list (input) - "Find all Dabbrev expansions for INPUT." - (cape--silent - (dlet ((dabbrev-check-other-buffers - (and cape-dabbrev-check-other-buffers - (not (functionp cape-dabbrev-check-other-buffers)))) - (dabbrev-check-all-buffers - (eq cape-dabbrev-check-other-buffers t)) - (dabbrev-search-these-buffers-only - (and (functionp cape-dabbrev-check-other-buffers) - (funcall cape-dabbrev-check-other-buffers)))) - (dabbrev--reset-global-variables) - (cons - (apply-partially #'string-prefix-p input) - (cl-loop with min-len = (+ cape-dabbrev-min-length (length input)) - with ic = (cape--case-fold-p dabbrev-case-fold-search) - for w in (dabbrev--find-all-expansions input ic) - if (>= (length w) min-len) collect - (cape--case-replace (and ic dabbrev-case-replace) input w)))))) - -(defun cape--dabbrev-bounds () - "Return bounds of abbreviation." - (unless (boundp 'dabbrev-abbrev-char-regexp) - (require 'dabbrev)) - (let ((re (or dabbrev-abbrev-char-regexp "\\sw\\|\\s_")) - (limit (minibuffer-prompt-end))) - (when (or (looking-at re) - (and (> (point) limit) - (save-excursion (forward-char -1) (looking-at re)))) - (cons (save-excursion - (while (and (> (point) limit) - (save-excursion (forward-char -1) (looking-at re))) - (forward-char -1)) - (when dabbrev-abbrev-skip-leading-regexp - (while (looking-at dabbrev-abbrev-skip-leading-regexp) - (forward-char 1))) - (point)) - (save-excursion - (while (looking-at re) - (forward-char 1)) - (point)))))) - -;;;###autoload -(defun cape-dabbrev (&optional interactive) - "Complete with Dabbrev at point. - -If INTERACTIVE is nil the function acts like a Capf. In case you -observe a performance issue with auto-completion and `cape-dabbrev' -it is strongly recommended to disable scanning in other buffers. -See the user options `cape-dabbrev-min-length' and -`cape-dabbrev-check-other-buffers'." - (interactive (list t)) - (if interactive - (cape-interactive '((cape-dabbrev-min-length 0)) #'cape-dabbrev) - (when-let ((bounds (cape--dabbrev-bounds))) - `(,(car bounds) ,(cdr bounds) - ,(cape--properties-table - (completion-table-case-fold - (cape--dynamic-table (car bounds) (cdr bounds) #'cape--dabbrev-list) - (not (cape--case-fold-p dabbrev-case-fold-search))) - :category 'cape-dabbrev) - ,@cape--dabbrev-properties)))) - -;;;;; cape-dict - -(defvar cape--dict-properties - (list :annotation-function (lambda (_) " Dict") - :company-kind (lambda (_) 'text) - :exclusive 'no) - "Completion extra properties for `cape-dict'.") - -(defun cape--dict-list (input) - "Return all words from `cape-dict-file' matching INPUT." - (unless (equal input "") - (let* ((inhibit-message t) - (message-log-max nil) - (default-directory - (if (and (not (file-remote-p default-directory)) - (file-directory-p default-directory)) - default-directory - user-emacs-directory)) - (files (mapcar #'expand-file-name - (ensure-list - (if (functionp cape-dict-file) - (funcall cape-dict-file) - cape-dict-file)))) - (words - (apply #'process-lines-ignore-status - "grep" - (concat "-Fh" - (and (cape--case-fold-p cape-dict-case-fold) "i") - (and cape-dict-limit (format "m%d" cape-dict-limit))) - input files))) - (cons - (apply-partially - (if (and cape-dict-limit (length= words cape-dict-limit)) - #'equal #'string-search) - input) - (cape--case-replace-list cape-dict-case-replace input words))))) - -;;;###autoload -(defun cape-dict (&optional interactive) - "Complete word from dictionary at point. -This completion function works best if the dictionary is sorted -by frequency. See the custom option `cape-dict-file'. If -INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (if interactive - (cape-interactive #'cape-dict) - (pcase-let ((`(,beg . ,end) (cape--bounds 'word))) - `(,beg ,end - ,(cape--properties-table - (completion-table-case-fold - (cape--dynamic-table beg end #'cape--dict-list) - (not (cape--case-fold-p cape-dict-case-fold))) - :sort nil ;; Presorted word list (by frequency) - :category 'cape-dict) - ,@cape--dict-properties)))) - -;;;;; cape-abbrev - -(defun cape--abbrev-tables () - "Return list of all active abbrev tables, including parents." - ;; Emacs 28: See abbrev--suggest-get-active-tables-including-parents. - (let ((tables (abbrev--active-tables))) - (append tables (cl-loop for table in tables - append (abbrev-table-get table :parents))))) - -(defun cape--abbrev-list () - "Abbreviation list." - (delete "" (cl-loop for table in (cape--abbrev-tables) - nconc (all-completions "" table)))) - -(defun cape--abbrev-annotation (abbrev) - "Annotate ABBREV with expansion." - (concat " " - (truncate-string-to-width - (format - "%s" - (symbol-value - (cl-loop for table in (cape--abbrev-tables) - thereis (abbrev--symbol abbrev table)))) - 30 0 nil t))) - -(defun cape--abbrev-exit (_str status) - "Expand expansion if STATUS is not exact." - (unless (eq status 'exact) - (expand-abbrev))) - -(defvar cape--abbrev-properties - (list :annotation-function #'cape--abbrev-annotation - :exit-function #'cape--abbrev-exit - :company-kind (lambda (_) 'snippet) - :exclusive 'no) - "Completion extra properties for `cape-abbrev'.") - -;;;###autoload -(defun cape-abbrev (&optional interactive) - "Complete abbreviation at point. -If INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (if interactive - ;; No cycling since it breaks the :exit-function. - (let (completion-cycle-threshold) - (cape-interactive #'cape-abbrev)) - (when-let (abbrevs (cape--abbrev-list)) - (let ((bounds (cape--bounds 'symbol))) - `(,(car bounds) ,(cdr bounds) - ,(cape--properties-table abbrevs :category 'cape-abbrev) - ,@cape--abbrev-properties))))) - -;;;;; cape-line - -(defvar cape--line-properties nil - "Completion extra properties for `cape-line'.") - -(defun cape--buffers-major-mode () - "Return buffers with same major mode as current buffer." - (cl-loop for buf in (buffer-list) - if (eq major-mode (buffer-local-value 'major-mode buf)) - collect buf)) - -(defun cape--line-list () - "Return all lines from buffer." - (let ((ht (make-hash-table :test #'equal)) - (curr-buf (current-buffer)) - (buffers (funcall cape-line-buffer-function)) - lines) - (dolist (buf (ensure-list buffers)) - (with-current-buffer buf - (let ((beg (point-min)) - (max (point-max)) - (pt (if (eq curr-buf buf) (point) -1)) - end) - (save-excursion - (while (< beg max) - (goto-char beg) - (setq end (pos-eol)) - (unless (<= beg pt end) - (let ((line (buffer-substring-no-properties beg end))) - (unless (or (string-blank-p line) (gethash line ht)) - (puthash line t ht) - (push line lines)))) - (setq beg (1+ end))))))) - (nreverse lines))) - -;;;###autoload -(defun cape-line (&optional interactive) - "Complete current line from other lines. -The buffers returned by `cape-line-buffer-function' are scanned for lines. -If INTERACTIVE is nil the function acts like a Capf." - (interactive (list t)) - (if interactive - (cape-interactive #'cape-line) - `(,(pos-bol) ,(point) - ,(cape--properties-table (cape--line-list) :sort nil) - ,@cape--line-properties))) - -;;;; Capf combinators - -(defun cape--company-call (&rest app) - "Apply APP and handle future return values." - ;; Backends are non-interruptible. Disable interrupts! - (let ((toi throw-on-input) - (throw-on-input nil)) - (pcase (apply app) - ;; Handle async future return values. - (`(:async . ,fetch) - (let ((res 'cape--waiting)) - (if toi - (unwind-protect - (progn - (funcall fetch - (lambda (arg) - (when (eq res 'cape--waiting) - (push 'cape--done unread-command-events) - (setq res arg)))) - (when (eq res 'cape--waiting) - (let ((ev (let ((input-method-function nil) - (echo-keystrokes 0)) - (read-event nil t)))) - (unless (eq ev 'cape--done) - (push (cons t ev) unread-command-events) - (setq res 'cape--cancelled) - (throw toi t))))) - (setq unread-command-events - (delq 'cape--done unread-command-events))) - (funcall fetch (lambda (arg) (setq res arg))) - ;; Force synchronization, not interruptible! We use polling - ;; here and ignore pending input since we don't use - ;; `sit-for'. This is the same method used by Company itself. - (while (eq res 'cape--waiting) - (sleep-for 0.01))) - res)) - ;; Plain old synchronous return value. - (res res)))) - -(defvar-local cape--company-init nil) - -;;;###autoload -(defun cape-company-to-capf (backend &optional valid) - "Convert Company BACKEND function to Capf. -VALID is a function taking the old and new input string. It should -return nil if the cached candidates became invalid. The default value -for VALID is `string-prefix-p' such that the candidates are only fetched -again if the input prefix changed." - (lambda () - (when (and (symbolp backend) (not (fboundp backend))) - (ignore-errors (require backend nil t))) - (when (bound-and-true-p company-mode) - (error "`cape-company-to-capf' should not be used with `company-mode', use the Company backend directly instead")) - (when (and (symbolp backend) (not (alist-get backend cape--company-init))) - (funcall backend 'init) - (put backend 'company-init t) - (setf (alist-get backend cape--company-init) t)) - (when-let ((prefix (cape--company-call backend 'prefix)) - (initial-input (if (stringp prefix) prefix (car-safe prefix)))) - (let* ((end (point)) (beg (- end (length initial-input))) - (valid (if (cape--company-call backend 'no-cache initial-input) - #'equal (or valid #'string-prefix-p))) - restore-props) - (list beg end - (funcall - (if (cape--company-call backend 'ignore-case) - #'completion-table-case-fold - #'identity) - (cape--properties-table - (cape--dynamic-table - beg end - (lambda (input) - (let ((cands (cape--company-call backend 'candidates input))) - ;; The candidate string including text properties should be - ;; restored in the :exit-function, if the UI does not - ;; guarantee this itself. Restoration is not necessary for - ;; Corfu since the introduction of `corfu--exit-function'. - (unless (and (bound-and-true-p corfu-mode) (fboundp 'corfu--exit-function)) - (setq restore-props cands)) - (cons (apply-partially valid input) cands)))) - :category backend - :sort (not (cape--company-call backend 'sorted)))) - :exclusive 'no - :company-prefix-length (cdr-safe prefix) - :company-doc-buffer (lambda (x) (cape--company-call backend 'doc-buffer x)) - :company-location (lambda (x) (cape--company-call backend 'location x)) - :company-docsig (lambda (x) (cape--company-call backend 'meta x)) - :company-deprecated (lambda (x) (cape--company-call backend 'deprecated x)) - :company-kind (lambda (x) (cape--company-call backend 'kind x)) - :annotation-function (lambda (x) - (when-let (ann (cape--company-call backend 'annotation x)) - (concat " " (string-trim ann)))) - :exit-function (lambda (x _status) - ;; Restore the candidate string including - ;; properties if restore-props is non-nil. See - ;; the comment above. - (setq x (or (car (member x restore-props)) x)) - (cape--company-call backend 'post-completion x))))))) - -;;;###autoload -(defun cape-interactive (&rest capfs) - "Complete interactively with the given CAPFS." - (let* ((ctx (and (consp (car capfs)) (car capfs))) - (capfs (if ctx (cdr capfs) capfs)) - (completion-at-point-functions - (if ctx - (mapcar (lambda (f) `(lambda () (let ,ctx (funcall ',f)))) capfs) - capfs))) - (unless (completion-at-point) - (user-error "%s: No completions" - (mapconcat (lambda (fun) - (if (symbolp fun) - (symbol-name fun) - "anonymous-capf")) - capfs ", "))))) - -;;;###autoload -(defun cape-capf-interactive (capf) - "Create interactive completion function from CAPF." - (lambda (&optional interactive) - (interactive (list t)) - (if interactive (cape-interactive capf) (funcall capf)))) - -;;;###autoload -(defun cape-wrap-super (&rest capfs) - "Call CAPFS and return merged completion result. -The CAPFS list can contain the keyword `:with' to mark the Capfs -afterwards as auxiliary One of the non-auxiliary Capfs before -`:with' must return non-nil for the super Capf to set in and -return a non-nil result. Such behavior is useful when listing -multiple super Capfs in the `completion-at-point-functions': - - (setq completion-at-point-functions - (list (cape-capf-super \\='eglot-completion-at-point - :with \\='tempel-complete) - (cape-capf-super \\='cape-dabbrev - :with \\='tempel-complete)))" - (when-let ((results (cl-loop for capf in capfs until (eq capf :with) - for res = (funcall capf) - if res collect (cons t res)))) - (pcase-let* ((results (nconc results - (cl-loop for capf in (cdr (memq :with capfs)) - for res = (funcall capf) - if res collect (cons nil res)))) - (`((,_main ,beg ,end . ,_)) results) - (cand-ht nil) - (tables nil) - (exclusive nil) - (prefix-len nil) - (cand-functions - '(:company-docsig :company-location :company-kind - :company-doc-buffer :company-deprecated - :annotation-function :exit-function))) - (cl-loop for (main beg2 end2 table . plist) in results do - ;; TODO `cape-capf-super' currently cannot merge Capfs which - ;; trigger at different beginning positions. In order to support - ;; this, take the smallest BEG value and then normalize all - ;; candidates by prefixing them such that they all start at the - ;; smallest BEG position. - (when (= beg beg2) - (push (list main (plist-get plist :predicate) table - ;; Plist attached to the candidates - (mapcan (lambda (f) - (when-let ((v (plist-get plist f))) - (list f v))) - cand-functions)) - tables) - ;; The resulting merged Capf is exclusive if one of the main - ;; Capfs is exclusive. - (when (and main (not (eq (plist-get plist :exclusive) 'no))) - (setq exclusive t)) - (setq end (max end end2)) - (let ((plen (plist-get plist :company-prefix-length))) - (cond - ((eq plen t) - (setq prefix-len t)) - ((and (not prefix-len) (integerp plen)) - (setq prefix-len plen)) - ((and (integerp prefix-len) (integerp plen)) - (setq prefix-len (max prefix-len plen))))))) - (setq tables (nreverse tables)) - `(,beg ,end - ,(lambda (str pred action) - (pcase action - (`(boundaries . ,_) nil) - ('metadata - '(metadata (category . cape-super) - (display-sort-function . identity) - (cycle-sort-function . identity))) - ('t ;; all-completions - (let ((ht (make-hash-table :test #'equal)) - (candidates nil)) - (cl-loop for (main table-pred table cand-plist) in tables do - (let* ((pr (if (and table-pred pred) - (lambda (x) (and (funcall table-pred x) (funcall pred x))) - (or table-pred pred))) - (md (completion-metadata "" table pr)) - (sort (or (completion-metadata-get md 'display-sort-function) - #'identity)) - ;; Always compute candidates of the main Capf - ;; tables, which come first in the tables - ;; list. For the :with Capfs only compute - ;; candidates if we've already determined that - ;; main candidates are available. - (cands (when (or main (or exclusive cand-ht candidates)) - (funcall sort (all-completions str table pr))))) - ;; Handle duplicates with a hash table. - (cl-loop - for cand in-ref cands - for dup = (gethash cand ht t) do - (cond - ((eq dup t) - ;; Candidate does not yet exist. - (puthash cand cand-plist ht)) - ((not (equal dup cand-plist)) - ;; Duplicate candidate. Candidate plist is - ;; different, therefore disambiguate the - ;; candidates. - (setf cand (propertize cand 'cape-capf-super - (cons cand cand-plist)))))) - (when cands (push cands candidates)))) - (when (or cand-ht candidates) - (setq candidates (apply #'nconc (nreverse candidates)) - cand-ht ht) - candidates))) - (_ ;; try-completion and test-completion - (cl-loop for (_main table-pred table _cand-plist) in tables thereis - (complete-with-action - action table str - (if (and table-pred pred) - (lambda (x) (and (funcall table-pred x) (funcall pred x))) - (or table-pred pred))))))) - :company-prefix-length ,prefix-len - ,@(and (not exclusive) '(:exclusive no)) - ,@(mapcan - (lambda (prop) - (list prop - (lambda (cand &rest args) - (if-let ((ref (get-text-property 0 'cape-capf-super cand))) - (when-let ((fun (plist-get (cdr ref) prop))) - (apply fun (car ref) args)) - (when-let ((plist (and cand-ht (gethash cand cand-ht))) - (fun (plist-get plist prop))) - (apply fun cand args)))))) - cand-functions))))) - -;;;###autoload -(defun cape-wrap-debug (capf &optional name) - "Call CAPF and return a completion table which prints trace messages. -If CAPF is an anonymous lambda, pass the Capf NAME explicitly for -meaningful debugging output." - (unless name - (setq name (if (symbolp capf) capf "capf"))) - (setq name (format "%s@%s" name (cl-incf cape--debug-id))) - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - (let* ((limit (1+ cape--debug-length)) - (pred (plist-get plist :predicate)) - (cands - ;; Reset regexps for `all-completions' - (let (completion-ignore-case completion-regexp-list) - (all-completions - "" table - (lambda (&rest args) - (and (or (not pred) (apply pred args)) (>= (cl-decf limit) 0)))))) - (plist-str "") - (plist-elt plist)) - (while (cdr plist-elt) - (setq plist-str (format "%s %s=%s" plist-str - (substring (symbol-name (car plist-elt)) 1) - (cape--debug-print (cadr plist-elt))) - plist-elt (cddr plist-elt))) - (cape--debug-message - "%s => input=%s:%s:%S table=%s%s" - name (+ beg 0) (+ end 0) (buffer-substring-no-properties beg end) - (cape--debug-print cands) - plist-str)) - `(,beg ,end ,(cape--debug-table - table name (copy-marker beg) (copy-marker end t)) - ,@(when-let ((exit (plist-get plist :exit-function))) - (list :exit-function - (lambda (cand status) - (cape--debug-message "%s:exit(candidate=%S status=%s)" - name cand status) - (funcall exit cand status)))) - . ,plist)) - (result - (cape--debug-message "%s() => %s (No completion)" - name (cape--debug-print result))))) - -;;;###autoload -(defun cape-wrap-buster (capf &optional valid) - "Call CAPF and return a completion table with cache busting. -This function can be used as an advice around an existing Capf. -The cache is busted when the input changes. The argument VALID -can be a function taking the old and new input string. It should -return nil if the new input requires that the completion table is -refreshed. The default value for VALID is `equal', such that the -completion table is refreshed on every input change." - (setq valid (or valid #'equal)) - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - (setq plist `(:cape--buster t . ,plist)) - `(,beg ,end - ,(let* ((beg (copy-marker beg)) - (end (copy-marker end t)) - (input (buffer-substring-no-properties beg end))) - (lambda (str pred action) - (let ((new-input (buffer-substring-no-properties beg end))) - (unless (or (not (eq action t)) - (cape--separator-p new-input) - (funcall valid input new-input)) - (pcase - ;; Reset in case `all-completions' is used inside CAPF - (let (completion-ignore-case completion-regexp-list) - (funcall capf)) - ((and `(,new-beg ,new-end ,new-table . ,new-plist) - (guard (and (= beg new-beg) (= end new-end)))) - (let (throw-on-input) ;; No interrupt during state update - (setf table new-table - input new-input - (cddr plist) new-plist)))))) - (complete-with-action action table str pred))) - ,@plist)))) - -;;;###autoload -(defun cape-wrap-passthrough (capf) - "Call CAPF and make sure that no completion style filtering takes place." - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - `(,beg ,end ,(cape--passthrough-table table) ,@plist)))) - -;;;###autoload -(defun cape-wrap-properties (capf &rest properties) - "Call CAPF and add additional completion PROPERTIES. -Completion properties include for example :exclusive, :annotation-function and -the various :company-* extensions. Furthermore a boolean :sort flag and a -completion :category symbol can be specified." - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - `(,beg ,end - ,(apply #'cape--properties-table table properties) - ,@properties ,@plist)))) - -;;;###autoload -(defun cape-wrap-nonexclusive (capf) - "Call CAPF and ensure that it is marked as non-exclusive. -This function can be used as an advice around an existing Capf." - (cape-wrap-properties capf :exclusive 'no)) - -;;;###autoload -(defun cape-wrap-predicate (capf predicate) - "Call CAPF and add an additional candidate PREDICATE. -The PREDICATE is passed the candidate symbol or string." - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - `(,beg ,end ,table - :predicate - ,(if-let (pred (plist-get plist :predicate)) - ;; First argument is key, second is value for hash tables. - ;; The first argument can be a cons cell for alists. Then - ;; the candidate itself is either a string or a symbol. We - ;; normalize the calling convention here such that PREDICATE - ;; always receives a string or a symbol. - (lambda (&rest args) - (when (apply pred args) - (setq args (car args)) - (funcall predicate (if (consp args) (car args) args)))) - (lambda (key &optional _val) - (funcall predicate (if (consp key) (car key) key)))) - ,@plist)))) - -;;;###autoload -(defun cape-wrap-silent (capf) - "Call CAPF and silence it (no messages, no errors). -This function can be used as an advice around an existing Capf." - (pcase (cape--silent (funcall capf)) - (`(,beg ,end ,table . ,plist) - `(,beg ,end ,(cape--silent-table table) ,@plist)))) - -;;;###autoload -(defun cape-wrap-case-fold (capf &optional dont-fold) - "Call CAPF and return a case-insensitive completion table. -If DONT-FOLD is non-nil return a case sensitive table instead. -This function can be used as an advice around an existing Capf." - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - `(,beg ,end ,(completion-table-case-fold table dont-fold) ,@plist)))) - -;;;###autoload -(defun cape-wrap-noninterruptible (capf) - "Call CAPF and return a non-interruptible completion table. -This function can be used as an advice around an existing Capf." - (pcase (let (throw-on-input) (funcall capf)) - (`(,beg ,end ,table . ,plist) - `(,beg ,end ,(cape--noninterruptible-table table) ,@plist)))) - -;;;###autoload -(defun cape-wrap-prefix-length (capf length) - "Call CAPF and ensure that prefix length is greater or equal than LENGTH. -If the prefix is long enough, enforce auto completion." - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - (when (>= (- end beg) length) - `(,beg ,end ,table - :company-prefix-length t - ,@plist))))) - -;;;###autoload -(defun cape-wrap-inside-faces (capf &rest faces) - "Call CAPF only if inside FACES. -This function can be used as an advice around an existing Capf." - (when-let (((> (point) (point-min))) - (fs (get-text-property (1- (point)) 'face)) - ((if (listp fs) - (cl-loop for f in fs thereis (memq f faces)) - (memq fs faces)))) - (funcall capf))) - -;;;###autoload -(defun cape-wrap-inside-code (capf) - "Call CAPF only if inside code, not inside a comment or string. -This function can be used as an advice around an existing Capf." - (let ((s (syntax-ppss))) - (and (not (nth 3 s)) (not (nth 4 s)) (funcall capf)))) - -;;;###autoload -(defun cape-wrap-inside-comment (capf) - "Call CAPF only if inside comment. -This function can be used as an advice around an existing Capf." - (and (nth 4 (syntax-ppss)) (funcall capf))) - -;;;###autoload -(defun cape-wrap-inside-string (capf) - "Call CAPF only if inside string. -This function can be used as an advice around an existing Capf." - (and (nth 3 (syntax-ppss)) (funcall capf))) - -;;;###autoload -(defun cape-wrap-purify (capf) - "Call CAPF and ensure that it does not illegally modify the buffer. -This function can be used as an advice around an existing -Capf. It has been introduced mainly to fix the broken -`pcomplete-completions-at-point' function in Emacs versions < 29." - ;; bug#50470: Fix Capfs which illegally modify the buffer or which illegally - ;; call `completion-in-region'. The workaround here was proposed by - ;; @jakanakaevangeli and is used in his capf-autosuggest package. In Emacs 29 - ;; the purity bug of Pcomplete has been fixed, such that make - ;; `cape-wrap-purify' is not necessary anymore. - (catch 'cape--illegal-completion-in-region - (condition-case nil - (let ((buffer-read-only t) - (inhibit-read-only nil) - (completion-in-region-function - (lambda (beg end coll pred) - (throw 'cape--illegal-completion-in-region - (list beg end coll :predicate pred))))) - (funcall capf)) - (buffer-read-only nil)))) - -;;;###autoload -(defun cape-wrap-accept-all (capf) - "Call CAPF and return a completion table which accepts every input. -This function can be used as an advice around an existing Capf." - (pcase (funcall capf) - (`(,beg ,end ,table . ,plist) - `(,beg ,end ,(cape--accept-all-table table) . ,plist)))) - -;;;###autoload (autoload 'cape-capf-accept-all "cape") -;;;###autoload (autoload 'cape-capf-buster "cape") -;;;###autoload (autoload 'cape-capf-case-fold "cape") -;;;###autoload (autoload 'cape-capf-debug "cape") -;;;###autoload (autoload 'cape-capf-inside-code "cape") -;;;###autoload (autoload 'cape-capf-inside-comment "cape") -;;;###autoload (autoload 'cape-capf-inside-faces "cape") -;;;###autoload (autoload 'cape-capf-inside-string "cape") -;;;###autoload (autoload 'cape-capf-nonexclusive "cape") -;;;###autoload (autoload 'cape-capf-noninterruptible "cape") -;;;###autoload (autoload 'cape-capf-passthrough "cape") -;;;###autoload (autoload 'cape-capf-predicate "cape") -;;;###autoload (autoload 'cape-capf-prefix-length "cape") -;;;###autoload (autoload 'cape-capf-properties "cape") -;;;###autoload (autoload 'cape-capf-purify "cape") -;;;###autoload (autoload 'cape-capf-silent "cape") -;;;###autoload (autoload 'cape-capf-super "cape") - -(dolist (wrapper (list #'cape-wrap-accept-all #'cape-wrap-buster - #'cape-wrap-case-fold #'cape-wrap-debug - #'cape-wrap-inside-code #'cape-wrap-inside-comment - #'cape-wrap-inside-faces #'cape-wrap-inside-string - #'cape-wrap-nonexclusive #'cape-wrap-noninterruptible - #'cape-wrap-passthrough #'cape-wrap-predicate - #'cape-wrap-prefix-length #'cape-wrap-properties - #'cape-wrap-purify #'cape-wrap-silent #'cape-wrap-super)) - (let ((name (string-remove-prefix "cape-wrap-" (symbol-name wrapper)))) - (defalias (intern (format "cape-capf-%s" name)) - (lambda (capf &rest args) (lambda () (apply wrapper capf args))) - (format "Create a %s Capf from CAPF. -The Capf calls `%s' with CAPF and ARGS as arguments." name wrapper)))) - -(defvar-keymap cape-prefix-map - :doc "Keymap used as completion entry point. -The keymap should be installed globally under a prefix." - "p" #'completion-at-point - "t" #'complete-tag - "d" #'cape-dabbrev - "h" #'cape-history - "f" #'cape-file - "s" #'cape-elisp-symbol - "e" #'cape-elisp-block - "a" #'cape-abbrev - "l" #'cape-line - "w" #'cape-dict - "k" 'cape-keyword - ":" 'cape-emoji - "\\" 'cape-tex - "_" 'cape-tex - "^" 'cape-tex - "&" 'cape-sgml - "r" 'cape-rfc1345) - -;;;###autoload (autoload 'cape-prefix-map "cape" nil t 'keymap) -(defalias 'cape-prefix-map cape-prefix-map) - -(provide 'cape) -;;; cape.el ends here diff --git a/emacs/elpa/cape-20240724.918/cape.elc b/emacs/elpa/cape-20240724.918/cape.elc Binary files differ. diff --git a/emacs/elpa/cape-20240818.1414/cape-autoloads.el b/emacs/elpa/cape-20240818.1414/cape-autoloads.el @@ -0,0 +1,238 @@ +;;; cape-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from cape.el + +(autoload 'cape-history "cape" "\ +Complete from Eshell, Comint or minibuffer history. +See also `consult-history' for a more flexible variant based on +`completing-read'. If INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-file "cape" "\ +Complete file name at point. +See the user option `cape-file-directory-must-exist'. +If INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-elisp-symbol "cape" "\ +Complete Elisp symbol at point. +If INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-elisp-block "cape" "\ +Complete Elisp in Org or Markdown code block. +This Capf is particularly useful for literate Emacs configurations. +If INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-dabbrev "cape" "\ +Complete with Dabbrev at point. + +If INTERACTIVE is nil the function acts like a Capf. In case you +observe a performance issue with auto-completion and `cape-dabbrev' +it is strongly recommended to disable scanning in other buffers. +See the user options `cape-dabbrev-min-length' and +`cape-dabbrev-check-other-buffers'. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-dict "cape" "\ +Complete word from dictionary at point. +This completion function works best if the dictionary is sorted +by frequency. See the custom option `cape-dict-file'. If +INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-abbrev "cape" "\ +Complete abbreviation at point. +If INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-line "cape" "\ +Complete current line from other lines. +The buffers returned by `cape-line-buffer-function' are scanned for lines. +If INTERACTIVE is nil the function acts like a Capf. + +(fn &optional INTERACTIVE)" t) +(autoload 'cape-company-to-capf "cape" "\ +Convert Company BACKEND function to Capf. +VALID is a function taking the old and new input string. It should +return nil if the cached candidates became invalid. The default value +for VALID is `string-prefix-p' such that the candidates are only fetched +again if the input prefix changed. + +(fn BACKEND &optional VALID)") +(autoload 'cape-interactive "cape" "\ +Complete interactively with the given CAPFS. + +(fn &rest CAPFS)") +(autoload 'cape-capf-interactive "cape" "\ +Create interactive completion function from CAPF. + +(fn CAPF)") +(autoload 'cape-wrap-super "cape" "\ +Call CAPFS and return merged completion result. +The CAPFS list can contain the keyword `:with' to mark the Capfs +afterwards as auxiliary One of the non-auxiliary Capfs before +`:with' must return non-nil for the super Capf to set in and +return a non-nil result. Such behavior is useful when listing +multiple super Capfs in the `completion-at-point-functions': + + (setq completion-at-point-functions + (list (cape-capf-super \\='eglot-completion-at-point + :with \\='tempel-complete) + (cape-capf-super \\='cape-dabbrev + :with \\='tempel-complete))) + +(fn &rest CAPFS)") +(autoload 'cape-wrap-debug "cape" "\ +Call CAPF and return a completion table which prints trace messages. +If CAPF is an anonymous lambda, pass the Capf NAME explicitly for +meaningful debugging output. + +(fn CAPF &optional NAME)") +(autoload 'cape-wrap-buster "cape" "\ +Call CAPF and return a completion table with cache busting. +This function can be used as an advice around an existing Capf. +The cache is busted when the input changes. The argument VALID +can be a function taking the old and new input string. It should +return nil if the new input requires that the completion table is +refreshed. The default value for VALID is `equal', such that the +completion table is refreshed on every input change. + +(fn CAPF &optional VALID)") +(autoload 'cape-wrap-passthrough "cape" "\ +Call CAPF and make sure that no completion style filtering takes place. + +(fn CAPF)") +(autoload 'cape-wrap-properties "cape" "\ +Call CAPF and add additional completion PROPERTIES. +Completion properties include for example :exclusive, :annotation-function and +the various :company-* extensions. Furthermore a boolean :sort flag and a +completion :category symbol can be specified. + +(fn CAPF &rest PROPERTIES)") +(autoload 'cape-wrap-nonexclusive "cape" "\ +Call CAPF and ensure that it is marked as non-exclusive. +This function can be used as an advice around an existing Capf. + +(fn CAPF)") +(autoload 'cape-wrap-predicate "cape" "\ +Call CAPF and add an additional candidate PREDICATE. +The PREDICATE is passed the candidate symbol or string. + +(fn CAPF PREDICATE)") +(autoload 'cape-wrap-silent "cape" "\ +Call CAPF and silence it (no messages, no errors). +This function can be used as an advice around an existing Capf. + +(fn CAPF)") +(autoload 'cape-wrap-case-fold "cape" "\ +Call CAPF and return a case-insensitive completion table. +If NOFOLD is non-nil return a case sensitive table instead. This +function can be used as an advice around an existing Capf. + +(fn CAPF &optional NOFOLD)") +(autoload 'cape-wrap-noninterruptible "cape" "\ +Call CAPF and return a non-interruptible completion table. +This function can be used as an advice around an existing Capf. + +(fn CAPF)") +(autoload 'cape-wrap-prefix-length "cape" "\ +Call CAPF and ensure that prefix length is greater or equal than LENGTH. +If the prefix is long enough, enforce auto completion. + +(fn CAPF LENGTH)") +(autoload 'cape-wrap-inside-faces "cape" "\ +Call CAPF only if inside FACES. +This function can be used as an advice around an existing Capf. + +(fn CAPF &rest FACES)") +(autoload 'cape-wrap-inside-code "cape" "\ +Call CAPF only if inside code, not inside a comment or string. +This function can be used as an advice around an existing Capf. + +(fn CAPF)") +(autoload 'cape-wrap-inside-comment "cape" "\ +Call CAPF only if inside comment. +This function can be used as an advice around an existing Capf. + +(fn CAPF)") +(autoload 'cape-wrap-inside-string "cape" "\ +Call CAPF only if inside string. +This function can be used as an advice around an existing Capf. + +(fn CAPF)") +(autoload 'cape-wrap-purify "cape" "\ +Call CAPF and ensure that it does not illegally modify the buffer. +This function can be used as an advice around an existing +Capf. It has been introduced mainly to fix the broken +`pcomplete-completions-at-point' function in Emacs versions < 29. + +(fn CAPF)") +(autoload 'cape-wrap-accept-all "cape" "\ +Call CAPF and return a completion table which accepts every input. +This function can be used as an advice around an existing Capf. + +(fn CAPF)") + (autoload 'cape-capf-accept-all "cape") + (autoload 'cape-capf-buster "cape") + (autoload 'cape-capf-case-fold "cape") + (autoload 'cape-capf-debug "cape") + (autoload 'cape-capf-inside-code "cape") + (autoload 'cape-capf-inside-comment "cape") + (autoload 'cape-capf-inside-faces "cape") + (autoload 'cape-capf-inside-string "cape") + (autoload 'cape-capf-nonexclusive "cape") + (autoload 'cape-capf-noninterruptible "cape") + (autoload 'cape-capf-passthrough "cape") + (autoload 'cape-capf-predicate "cape") + (autoload 'cape-capf-prefix-length "cape") + (autoload 'cape-capf-properties "cape") + (autoload 'cape-capf-purify "cape") + (autoload 'cape-capf-silent "cape") + (autoload 'cape-capf-super "cape") + (autoload 'cape-prefix-map "cape" nil t 'keymap) +(register-definition-prefixes "cape" '("cape-")) + + +;;; Generated autoloads from cape-char.el + + (autoload 'cape-tex "cape-char" nil t) + (autoload 'cape-sgml "cape-char" nil t) + (autoload 'cape-rfc1345 "cape-char" nil t) + (when (> emacs-major-version 28) (autoload 'cape-emoji "cape-char" nil t)) +(register-definition-prefixes "cape-char" '("cape-char--")) + + +;;; Generated autoloads from cape-keyword.el + +(autoload 'cape-keyword "cape-keyword" "\ +Complete programming language keyword at point. +See the variable `cape-keyword-list'. +If INTERACTIVE is nil the function acts like a capf. + +(fn &optional INTERACTIVE)" t) +(register-definition-prefixes "cape-keyword" '("cape-")) + +;;; End of scraped data + +(provide 'cape-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; cape-autoloads.el ends here diff --git a/emacs/elpa/cape-20240724.918/cape-char.el b/emacs/elpa/cape-20240818.1414/cape-char.el diff --git a/emacs/elpa/cape-20240724.918/cape-char.elc b/emacs/elpa/cape-20240818.1414/cape-char.elc Binary files differ. diff --git a/emacs/elpa/cape-20240724.918/cape-keyword.el b/emacs/elpa/cape-20240818.1414/cape-keyword.el diff --git a/emacs/elpa/cape-20240724.918/cape-keyword.elc b/emacs/elpa/cape-20240818.1414/cape-keyword.elc Binary files differ. diff --git a/emacs/elpa/cape-20240818.1414/cape-pkg.el b/emacs/elpa/cape-20240818.1414/cape-pkg.el @@ -0,0 +1,15 @@ +(define-package "cape" "20240818.1414" "Completion At Point Extensions" + '((emacs "27.1") + (compat "30")) + :commit "944c60cc3ff81ceceeb239746f7dd9d8e7d0a663" :authors + '(("Daniel Mendler" . "mail@daniel-mendler.de")) + :maintainers + '(("Daniel Mendler" . "mail@daniel-mendler.de")) + :maintainer + '("Daniel Mendler" . "mail@daniel-mendler.de") + :keywords + '("abbrev" "convenience" "matching" "completion" "text") + :url "https://github.com/minad/cape") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/cape-20240818.1414/cape.el b/emacs/elpa/cape-20240818.1414/cape.el @@ -0,0 +1,1307 @@ +;;; cape.el --- Completion At Point Extensions -*- lexical-binding: t -*- + +;; Copyright (C) 2021-2024 Free Software Foundation, Inc. + +;; Author: Daniel Mendler <mail@daniel-mendler.de> +;; Maintainer: Daniel Mendler <mail@daniel-mendler.de> +;; Created: 2021 +;; Version: 1.6 +;; Package-Requires: ((emacs "27.1") (compat "30")) +;; Homepage: https://github.com/minad/cape +;; Keywords: abbrev, convenience, matching, completion, text + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Let your completions fly! This package provides additional completion +;; backends in the form of Capfs (completion-at-point-functions). +;; +;; `cape-abbrev': Complete abbreviation (add-global-abbrev, add-mode-abbrev). +;; `cape-dabbrev': Complete word from current buffers. +;; `cape-dict': Complete word from dictionary file. +;; `cape-elisp-block': Complete Elisp in Org or Markdown code block. +;; `cape-elisp-symbol': Complete Elisp symbol. +;; `cape-emoji': Complete Emoji. +;; `cape-file': Complete file name. +;; `cape-history': Complete from Eshell, Comint or minibuffer history. +;; `cape-keyword': Complete programming language keyword. +;; `cape-line': Complete entire line from file. +;; `cape-rfc1345': Complete Unicode char using RFC 1345 mnemonics. +;; `cape-sgml': Complete Unicode char from SGML entity, e.g., &alpha. +;; `cape-tex': Complete Unicode char from TeX command, e.g. \hbar. + +;;; Code: + +(require 'compat) +(eval-when-compile + (require 'cl-lib) + (require 'subr-x)) + +;;;; Customization + +(defgroup cape nil + "Completion At Point Extensions." + :link '(info-link :tag "Info Manual" "(cape)") + :link '(url-link :tag "Homepage" "https://github.com/minad/cape") + :link '(emacs-library-link :tag "Library Source" "cape.el") + :group 'convenience + :group 'tools + :group 'matching + :prefix "cape-") + +(defcustom cape-dict-limit 100 + "Maximal number of completion candidates returned by `cape-dict'." + :type '(choice (const nil) natnum)) + +(defcustom cape-dict-file "/usr/share/dict/words" + "Path to dictionary word list file. +This variable can also be a list of paths or +a function returning a single or more paths." + :type '(choice string (repeat string) function)) + +(defcustom cape-dict-case-replace 'case-replace + "Preserve case of input. +See `dabbrev-case-replace' for details." + :type '(choice (const :tag "off" nil) + (const :tag "use `case-replace'" case-replace) + (other :tag "on" t))) + +(defcustom cape-dict-case-fold 'case-fold-search + "Case fold search during search. +See `dabbrev-case-fold-search' for details." + :type '(choice (const :tag "off" nil) + (const :tag "use `case-fold-search'" case-fold-search) + (other :tag "on" t))) + +(defcustom cape-dabbrev-min-length 4 + "Minimum length of Dabbrev expansions. +This setting ensures that words which are too short +are not offered as completion candidates, such that +auto completion does not pop up too aggressively." + :type 'natnum) + +(defcustom cape-dabbrev-check-other-buffers t + "Buffers to check for Dabbrev. + +If t, check all other buffers, subject to Dabbrev ignore rules. +If a function, only search the buffers returned by this function. +Any other non-nil value only checks some other buffers, as per +`dabbrev-select-buffers-function'." + :type `(choice (const :tag "off" nil) + (const :tag "same-mode buffers" ,#'cape--buffers-major-mode) + (function :tag "function") + (const :tag "some" some) + (other :tag "all" t))) + +(defcustom cape-file-directory nil + "Base directory used by `cape-file." + :type '(choice (const nil) string function)) + +(defcustom cape-file-prefix "file:" + "File completion trigger prefixes. +The value can be a string or a list of strings. The default +`file:' is the prefix of Org file links which work in arbitrary +buffers via `org-open-at-point-global'." + :type '(choice string (repeat string))) + +(defcustom cape-file-directory-must-exist t + "The parent directory must exist for file completion." + :type 'boolean) + +(defcustom cape-line-buffer-function #'cape--buffers-major-mode + "Function which returns list of buffers. +The buffers are scanned for completion candidates by `cape-line'." + :type '(choice (const :tag "Current buffer" current-buffer) + (const :tag "All buffers" buffer-list) + (const :tag "Buffers with same major mode" cape--buffers-major-mode) + (function :tag "Custom function"))) + +(defcustom cape-elisp-symbol-wrapper + '((org-mode ?~ ?~) + (markdown-mode ?` ?`) + (emacs-lisp-mode ?` ?') + (rst-mode "``" "``") + (log-edit-mode "`" "'") + (change-log-mode "`" "'") + (message-mode "`" "'") + (rcirc-mode "`" "'")) + "Wrapper characters for symbols." + :type '(alist :key-type symbol :value-type (list (choice character string) + (choice character string)))) + +;;;; Helpers + +(defun cape--case-fold-p (fold) + "Return non-nil if case folding is enabled for FOLD." + (if (eq fold 'case-fold-search) case-fold-search fold)) + +(defun cape--case-replace-list (flag input strs) + "Replace case of STRS depending on INPUT and FLAG." + (if (and (if (eq flag 'case-replace) case-replace flag) + (let (case-fold-search) (string-match-p "\\`[[:upper:]]" input))) + (mapcar (apply-partially #'cape--case-replace flag input) strs) + strs)) + +(defun cape--case-replace (flag input str) + "Replace case of STR depending on INPUT and FLAG." + (or (and (if (eq flag 'case-replace) case-replace flag) + (string-prefix-p input str t) + (let (case-fold-search) (string-match-p "\\`[[:upper:]]" input)) + (save-match-data + ;; Ensure that single character uppercase input does not lead to an + ;; all uppercase result. + (when (and (= (length input) 1) (> (length str) 1)) + (setq input (concat input (substring str 1 2)))) + (and (string-match input input) + (replace-match str nil nil input)))) + str)) + +(defun cape--separator-p (str) + "Return non-nil if input STR has a separator character. +Separator characters are used by completion styles like Orderless +to split filter words. In Corfu, the separator is configurable +via the variable `corfu-separator'." + (string-search (string ;; Support `corfu-separator' and Orderless + (or (and (bound-and-true-p corfu-mode) + (bound-and-true-p corfu-separator)) + ?\s)) + str)) + +(defmacro cape--silent (&rest body) + "Silence BODY." + (declare (indent 0)) + `(cl-letf ((inhibit-message t) + (message-log-max nil) + ((symbol-function #'minibuffer-message) #'ignore)) + (ignore-errors ,@body))) + +(defun cape--bounds (thing) + "Return bounds of THING." + (or (bounds-of-thing-at-point thing) (cons (point) (point)))) + +(defmacro cape--wrapped-table (wrap body) + "Create wrapped completion table, handle `completion--unquote'. +WRAP is the wrapper function. +BODY is the wrapping expression." + (declare (indent 1)) + `(lambda (str pred action) + (,@body + (let ((result (complete-with-action action table str pred))) + (when (and (eq action 'completion--unquote) (functionp (cadr result))) + (cl-callf ,wrap (cadr result))) + result)))) + +(defun cape--accept-all-table (table) + "Create completion TABLE which accepts all input." + (cape--wrapped-table cape--accept-all-table + (or (eq action 'lambda)))) + +(defun cape--passthrough-table (table) + "Create completion TABLE disabling any filtering." + (cape--wrapped-table cape--passthrough-table + (let (completion-ignore-case completion-regexp-list (_ (setq str "")))))) + +(defun cape--noninterruptible-table (table) + "Create non-interruptible completion TABLE." + (cape--wrapped-table cape--noninterruptible-table + (let (throw-on-input)))) + +(defun cape--silent-table (table) + "Create a new completion TABLE which is silent (no messages, no errors)." + (cape--wrapped-table cape--silent-table + (cape--silent))) + +(defun cape--nonessential-table (table) + "Mark completion TABLE as `non-essential'." + (let ((dir default-directory)) + (cape--wrapped-table cape--nonessential-table + (let ((default-directory dir) + (non-essential t)))))) + +(defvar cape--debug-length 5 + "Length of printed lists in `cape--debug-print'.") + +(defvar cape--debug-id 0 + "Completion table identifier.") + +(defun cape--debug-message (&rest msg) + "Print debug MSG." + (let ((inhibit-message t)) + (apply #'message msg))) + +(defun cape--debug-print (obj &optional full) + "Print OBJ as string, truncate lists if FULL is nil." + (cond + ((symbolp obj) (symbol-name obj)) + ((functionp obj) "#<function>") + ((proper-list-p obj) + (concat + "(" + (string-join + (mapcar #'cape--debug-print + (if full obj (take cape--debug-length obj))) + " ") + (if (and (not full) (length> obj cape--debug-length)) " ...)" ")"))) + (t (let ((print-level 2)) + (prin1-to-string obj))))) + +(defun cape--debug-table (table name beg end) + "Create completion TABLE with debug messages. +NAME is the name of the Capf, BEG and END are the input markers." + (lambda (str pred action) + (let ((result (complete-with-action action table str pred))) + (if (and (eq action 'completion--unquote) (functionp (cadr result))) + ;; See `cape--wrapped-table' + (cl-callf cape--debug-table (cadr result) name beg end) + (cape--debug-message + "%s(action=%S input=%s:%s:%S prefix=%S ignore-case=%S%s%s) => %s" + name + (pcase action + ('nil 'try) + ('t 'all) + ('lambda 'test) + (_ action)) + (+ beg 0) (+ end 0) (buffer-substring-no-properties beg end) + str completion-ignore-case + (if completion-regexp-list + (format " regexp=%s" (cape--debug-print completion-regexp-list t)) + "") + (if pred + (format " predicate=%s" (cape--debug-print pred)) + "") + (cape--debug-print result))) + result))) + +(cl-defun cape--properties-table (table &key category (sort t) &allow-other-keys) + "Create completion TABLE with properties. +CATEGORY is the optional completion category. +SORT should be nil to disable sorting." + ;; The metadata will be overridden if the category is non-nil, if the table is + ;; a function table or if sorting should be disabled for a non-nil + ;; non-function table. + (if (or category (functionp table) (and (not sort) table)) + (let ((metadata `(metadata + ,@(and category `((category . ,category))) + ,@(and (not sort) '((display-sort-function . identity) + (cycle-sort-function . identity)))))) + (lambda (str pred action) + (if (eq action 'metadata) + metadata + (complete-with-action action table str pred)))) + table)) + +(defun cape--dynamic-table (beg end fun) + "Create dynamic completion table from FUN with caching. +BEG and END are the input bounds. FUN is the function which +computes the candidates. FUN must return a pair of a predicate +function function and the list of candidates. The predicate is +passed new input and must return non-nil if the candidates are +still valid. + +It is only necessary to use this function if the set of +candidates is computed dynamically based on the input and not +statically determined. The behavior is similar but slightly +different to `completion-table-dynamic'. + +The difference to the builtins `completion-table-dynamic' and +`completion-table-with-cache' is that this function does not use +the prefix argument of the completion table to compute the +candidates. Instead it uses the input in the buffer between BEG +and END to FUN to compute the candidates. This way the dynamic +candidate computation is compatible with non-prefix completion +styles like `substring' or `orderless', which pass the empty +string as first argument to the completion table." + (let ((beg (copy-marker beg)) + (end (copy-marker end t)) + valid table) + (lambda (str pred action) + ;; Bail out early for `metadata' and `boundaries'. This is a pointless + ;; move because of caching, but we do it anyway in the hope that the + ;; profiler report looks less confusing, since the weight of the expensive + ;; FUN computation is moved to the `all-completions' action. Computing + ;; `all-completions' must surely be most expensive, so nobody will suspect + ;; a thing. + (unless (or (eq action 'metadata) (eq (car-safe action) 'boundaries)) + (let ((input (buffer-substring-no-properties beg end))) + (unless (and valid + (or (cape--separator-p input) + (funcall valid input))) + (let* (;; Reset in case `all-completions' is used inside FUN + completion-ignore-case completion-regexp-list + ;; Retrieve new state by calling FUN + (new (funcall fun input)) + ;; No interrupt during state update + throw-on-input) + (setq valid (car new) table (cdr new))))) + (complete-with-action action table str pred))))) + +;;;; Capfs + +;;;;; cape-history + +(declare-function ring-elements "ring") +(declare-function eshell-bol "eshell") +(declare-function comint-line-beginning-position "comint") +(defvar eshell-history-ring) +(defvar comint-input-ring) + +(defvar cape--history-properties + (list :company-kind (lambda (_) 'text) + :exclusive 'no) + "Completion extra properties for `cape-history'.") + +;;;###autoload +(defun cape-history (&optional interactive) + "Complete from Eshell, Comint or minibuffer history. +See also `consult-history' for a more flexible variant based on +`completing-read'. If INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (if interactive + (cape-interactive #'cape-history) + (let (history bol) + (cond + ((derived-mode-p 'eshell-mode) + (setq history eshell-history-ring + bol (static-if (< emacs-major-version 30) + (save-excursion (eshell-bol) (point)) + (line-beginning-position)))) + ((derived-mode-p 'comint-mode) + (setq history comint-input-ring + bol (comint-line-beginning-position))) + ((and (minibufferp) (not (eq minibuffer-history-variable t))) + (setq history (symbol-value minibuffer-history-variable) + bol (line-beginning-position)))) + (when (ring-p history) + (setq history (ring-elements history))) + (when history + `(,bol ,(point) + ,(cape--properties-table history :sort nil) + ,@cape--history-properties))))) + +;;;;; cape-file + +(defvar comint-unquote-function) +(defvar comint-requote-function) + +(defvar cape--file-properties + (list :annotation-function (lambda (s) (if (string-suffix-p "/" s) " Dir" " File")) + :company-kind (lambda (s) (if (string-suffix-p "/" s) 'folder 'file)) + :exclusive 'no) + "Completion extra properties for `cape-file'.") + +;;;###autoload +(defun cape-file (&optional interactive) + "Complete file name at point. +See the user option `cape-file-directory-must-exist'. +If INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (if interactive + (cape-interactive '(cape-file-directory-must-exist) #'cape-file) + (pcase-let* ((default-directory (pcase cape-file-directory + ('nil default-directory) + ((pred stringp) cape-file-directory) + (_ (funcall cape-file-directory)))) + (prefix (and cape-file-prefix + (looking-back + (concat + (regexp-opt (ensure-list cape-file-prefix) t) + "[^ \n\t]*") + (pos-bol)) + (match-end 1))) + (`(,beg . ,end) (if prefix + (cons prefix (point)) + (cape--bounds 'filename))) + (non-essential t) + (file (buffer-substring-no-properties beg end))) + (when (or prefix + (not cape-file-directory-must-exist) + (and (string-search "/" file) + (file-exists-p (file-name-directory file)))) + `(,beg ,end + ,(cape--nonessential-table + (if (or (derived-mode-p 'comint-mode) (derived-mode-p 'eshell-mode)) + (completion-table-with-quoting + #'read-file-name-internal + comint-unquote-function + comint-requote-function) + #'read-file-name-internal)) + ,@(when (or prefix (string-match-p "./" file)) + '(:company-prefix-length t)) + ,@cape--file-properties))))) + +;;;;; cape-elisp-symbol + +(defvar cape--symbol-properties + (append + (list :annotation-function #'cape--symbol-annotation + :exit-function #'cape--symbol-exit + :predicate #'cape--symbol-predicate + :exclusive 'no) + (when (eval-when-compile (>= emacs-major-version 28)) + (autoload 'elisp--company-kind "elisp-mode") + (autoload 'elisp--company-doc-buffer "elisp-mode") + (autoload 'elisp--company-doc-string "elisp-mode") + (autoload 'elisp--company-location "elisp-mode") + (list :company-kind 'elisp--company-kind + :company-doc-buffer 'elisp--company-doc-buffer + :company-docsig 'elisp--company-doc-string + :company-location 'elisp--company-location))) + "Completion extra properties for `cape-elisp-symbol'.") + +(defun cape--symbol-predicate (sym) + "Return t if SYM is bound, fbound or propertized." + (or (fboundp sym) (boundp sym) (symbol-plist sym))) + +(defun cape--symbol-exit (sym status) + "Wrap symbol SYM with `cape-elisp-symbol-wrapper' buffers. +STATUS is the exit status." + (when-let (((not (eq status 'exact))) + (c (cl-loop for (m . c) in cape-elisp-symbol-wrapper + if (derived-mode-p m) return c)) + ((or (not (derived-mode-p 'emacs-lisp-mode)) + ;; Inside comment or string + (let ((s (syntax-ppss))) (or (nth 3 s) (nth 4 s))))) + (x (if (stringp (car c)) (car c) (string (car c)))) + (y (if (stringp (cadr c)) (cadr c) (string (cadr c))))) + (save-excursion + (backward-char (length sym)) + (unless (save-excursion + (and (ignore-errors (or (backward-char (length x)) t)) + (looking-at-p (regexp-quote x)))) + (insert x))) + (unless (looking-at-p (regexp-quote y)) + (insert y)))) + +(defun cape--symbol-annotation (sym) + "Return kind of SYM." + (setq sym (intern-soft sym)) + (cond + ((special-form-p sym) " Special") + ((macrop sym) " Macro") + ((commandp sym) " Command") + ((fboundp sym) " Function") + ((custom-variable-p sym) " Custom") + ((boundp sym) " Variable") + ((featurep sym) " Feature") + ((facep sym) " Face") + (t " Symbol"))) + +;;;###autoload +(defun cape-elisp-symbol (&optional interactive) + "Complete Elisp symbol at point. +If INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (if interactive + ;; No cycling since it breaks the :exit-function. + (let (completion-cycle-threshold) + (cape-interactive #'cape-elisp-symbol)) + (pcase-let ((`(,beg . ,end) (cape--bounds 'symbol))) + (when (eq (char-after beg) ?') + (setq beg (1+ beg) end (max beg end))) + `(,beg ,end + ,(cape--properties-table obarray :category 'symbol) + ,@cape--symbol-properties)))) + +;;;;; cape-elisp-block + +(declare-function org-element-context "org-element") +(declare-function markdown-code-block-lang "ext:markdown-mode") + +(defun cape--inside-block-p (&rest langs) + "Return non-nil if inside LANGS code block." + (when-let ((face (get-text-property (point) 'face)) + (lang (or (and (if (listp face) + (memq 'org-block face) + (eq 'org-block face)) + (plist-get (cadr (org-element-context)) :language)) + (and (if (listp face) + (memq 'markdown-code-face face) + (eq 'markdown-code-face face)) + (save-excursion + (markdown-code-block-lang)))))) + (member lang langs))) + +;;;###autoload +(defun cape-elisp-block (&optional interactive) + "Complete Elisp in Org or Markdown code block. +This Capf is particularly useful for literate Emacs configurations. +If INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (cond + (interactive + ;; No code block check. Always complete Elisp when command was + ;; explicitly invoked interactively. + (cape-interactive #'elisp-completion-at-point)) + ((cape--inside-block-p "elisp" "emacs-lisp") + (elisp-completion-at-point)))) + +;;;;; cape-dabbrev + +(defvar cape--dabbrev-properties + (list :annotation-function (lambda (_) " Dabbrev") + :company-kind (lambda (_) 'text) + :exclusive 'no) + "Completion extra properties for `cape-dabbrev'.") + +(defvar dabbrev-case-replace) +(defvar dabbrev-case-fold-search) +(defvar dabbrev-abbrev-char-regexp) +(defvar dabbrev-abbrev-skip-leading-regexp) +(declare-function dabbrev--find-all-expansions "dabbrev") +(declare-function dabbrev--reset-global-variables "dabbrev") + +(defun cape--dabbrev-list (input) + "Find all Dabbrev expansions for INPUT." + (cape--silent + (let* ((chk cape-dabbrev-check-other-buffers) + (funp (and (not (memq chk '(nil t some))) (functionp chk)))) + (dlet ((dabbrev-check-other-buffers (and chk (not funp))) + (dabbrev-check-all-buffers (eq chk t)) + (dabbrev-search-these-buffers-only (and funp (funcall chk)))) + (dabbrev--reset-global-variables) + (cons + (apply-partially #'string-prefix-p input) + (cl-loop with min-len = (+ cape-dabbrev-min-length (length input)) + with ic = (cape--case-fold-p dabbrev-case-fold-search) + for w in (dabbrev--find-all-expansions input ic) + if (>= (length w) min-len) collect + (cape--case-replace (and ic dabbrev-case-replace) input w))))))) + +(defun cape--dabbrev-bounds () + "Return bounds of abbreviation." + (unless (boundp 'dabbrev-abbrev-char-regexp) + (require 'dabbrev)) + (let ((re (or dabbrev-abbrev-char-regexp "\\sw\\|\\s_")) + (limit (minibuffer-prompt-end))) + (when (or (looking-at re) + (and (> (point) limit) + (save-excursion (forward-char -1) (looking-at re)))) + (cons (save-excursion + (while (and (> (point) limit) + (save-excursion (forward-char -1) (looking-at re))) + (forward-char -1)) + (when dabbrev-abbrev-skip-leading-regexp + (while (looking-at dabbrev-abbrev-skip-leading-regexp) + (forward-char 1))) + (point)) + (save-excursion + (while (looking-at re) + (forward-char 1)) + (point)))))) + +;;;###autoload +(defun cape-dabbrev (&optional interactive) + "Complete with Dabbrev at point. + +If INTERACTIVE is nil the function acts like a Capf. In case you +observe a performance issue with auto-completion and `cape-dabbrev' +it is strongly recommended to disable scanning in other buffers. +See the user options `cape-dabbrev-min-length' and +`cape-dabbrev-check-other-buffers'." + (interactive (list t)) + (if interactive + (cape-interactive '((cape-dabbrev-min-length 0)) #'cape-dabbrev) + (when-let ((bounds (cape--dabbrev-bounds))) + `(,(car bounds) ,(cdr bounds) + ,(cape--properties-table + (completion-table-case-fold + (cape--dynamic-table (car bounds) (cdr bounds) #'cape--dabbrev-list) + (not (cape--case-fold-p dabbrev-case-fold-search))) + :category 'cape-dabbrev) + ,@cape--dabbrev-properties)))) + +;;;;; cape-dict + +(defvar cape--dict-properties + (list :annotation-function (lambda (_) " Dict") + :company-kind (lambda (_) 'text) + :exclusive 'no) + "Completion extra properties for `cape-dict'.") + +(defun cape--dict-list (input) + "Return all words from `cape-dict-file' matching INPUT." + (unless (equal input "") + (let* ((inhibit-message t) + (message-log-max nil) + (default-directory + (if (and (not (file-remote-p default-directory)) + (file-directory-p default-directory)) + default-directory + user-emacs-directory)) + (files (mapcar #'expand-file-name + (ensure-list + (if (functionp cape-dict-file) + (funcall cape-dict-file) + cape-dict-file)))) + (words + (apply #'process-lines-ignore-status + "grep" + (concat "-Fh" + (and (cape--case-fold-p cape-dict-case-fold) "i") + (and cape-dict-limit (format "m%d" cape-dict-limit))) + input files))) + (cons + (apply-partially + (if (and cape-dict-limit (length= words cape-dict-limit)) + #'equal #'string-search) + input) + (cape--case-replace-list cape-dict-case-replace input words))))) + +;;;###autoload +(defun cape-dict (&optional interactive) + "Complete word from dictionary at point. +This completion function works best if the dictionary is sorted +by frequency. See the custom option `cape-dict-file'. If +INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (if interactive + (cape-interactive #'cape-dict) + (pcase-let ((`(,beg . ,end) (cape--bounds 'word))) + `(,beg ,end + ,(cape--properties-table + (completion-table-case-fold + (cape--dynamic-table beg end #'cape--dict-list) + (not (cape--case-fold-p cape-dict-case-fold))) + :sort nil ;; Presorted word list (by frequency) + :category 'cape-dict) + ,@cape--dict-properties)))) + +;;;;; cape-abbrev + +(defun cape--abbrev-tables () + "Return list of all active abbrev tables, including parents." + ;; Emacs 28: See abbrev--suggest-get-active-tables-including-parents. + (let ((tables (abbrev--active-tables))) + (append tables (cl-loop for table in tables + append (abbrev-table-get table :parents))))) + +(defun cape--abbrev-list () + "Abbreviation list." + (delete "" (cl-loop for table in (cape--abbrev-tables) + nconc (all-completions "" table)))) + +(defun cape--abbrev-annotation (abbrev) + "Annotate ABBREV with expansion." + (concat " " + (truncate-string-to-width + (format + "%s" + (symbol-value + (cl-loop for table in (cape--abbrev-tables) + thereis (abbrev--symbol abbrev table)))) + 30 0 nil t))) + +(defun cape--abbrev-exit (_str status) + "Expand expansion if STATUS is not exact." + (unless (eq status 'exact) + (expand-abbrev))) + +(defvar cape--abbrev-properties + (list :annotation-function #'cape--abbrev-annotation + :exit-function #'cape--abbrev-exit + :company-kind (lambda (_) 'snippet) + :exclusive 'no) + "Completion extra properties for `cape-abbrev'.") + +;;;###autoload +(defun cape-abbrev (&optional interactive) + "Complete abbreviation at point. +If INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (if interactive + ;; No cycling since it breaks the :exit-function. + (let (completion-cycle-threshold) + (cape-interactive #'cape-abbrev)) + (when-let (abbrevs (cape--abbrev-list)) + (let ((bounds (cape--bounds 'symbol))) + `(,(car bounds) ,(cdr bounds) + ,(cape--properties-table abbrevs :category 'cape-abbrev) + ,@cape--abbrev-properties))))) + +;;;;; cape-line + +(defvar cape--line-properties nil + "Completion extra properties for `cape-line'.") + +(defun cape--buffers-major-mode () + "Return buffers with same major mode as current buffer." + (cl-loop for buf in (buffer-list) + if (eq major-mode (buffer-local-value 'major-mode buf)) + collect buf)) + +(defun cape--line-list () + "Return all lines from buffer." + (let ((ht (make-hash-table :test #'equal)) + (curr-buf (current-buffer)) + (buffers (funcall cape-line-buffer-function)) + lines) + (dolist (buf (ensure-list buffers)) + (with-current-buffer buf + (let ((beg (point-min)) + (max (point-max)) + (pt (if (eq curr-buf buf) (point) -1)) + end) + (save-excursion + (while (< beg max) + (goto-char beg) + (setq end (pos-eol)) + (unless (<= beg pt end) + (let ((line (buffer-substring-no-properties beg end))) + (unless (or (string-blank-p line) (gethash line ht)) + (puthash line t ht) + (push line lines)))) + (setq beg (1+ end))))))) + (nreverse lines))) + +;;;###autoload +(defun cape-line (&optional interactive) + "Complete current line from other lines. +The buffers returned by `cape-line-buffer-function' are scanned for lines. +If INTERACTIVE is nil the function acts like a Capf." + (interactive (list t)) + (if interactive + (cape-interactive #'cape-line) + `(,(pos-bol) ,(point) + ,(cape--properties-table (cape--line-list) :sort nil) + ,@cape--line-properties))) + +;;;; Capf combinators + +(defun cape--company-call (&rest app) + "Apply APP and handle future return values." + ;; Backends are non-interruptible. Disable interrupts! + (let ((toi throw-on-input) + (throw-on-input nil)) + (pcase (apply app) + ;; Handle async future return values. + (`(:async . ,fetch) + (let ((res 'cape--waiting)) + (if toi + (unwind-protect + (progn + (funcall fetch + (lambda (arg) + (when (eq res 'cape--waiting) + (push 'cape--done unread-command-events) + (setq res arg)))) + (when (eq res 'cape--waiting) + (let ((ev (let ((input-method-function nil) + (echo-keystrokes 0)) + (read-event nil t)))) + (unless (eq ev 'cape--done) + (push (cons t ev) unread-command-events) + (setq res 'cape--cancelled) + (throw toi t))))) + (setq unread-command-events + (delq 'cape--done unread-command-events))) + (funcall fetch (lambda (arg) (setq res arg))) + ;; Force synchronization, not interruptible! We use polling + ;; here and ignore pending input since we don't use + ;; `sit-for'. This is the same method used by Company itself. + (while (eq res 'cape--waiting) + (sleep-for 0.01))) + res)) + ;; Plain old synchronous return value. + (res res)))) + +(defvar-local cape--company-init nil) + +;;;###autoload +(defun cape-company-to-capf (backend &optional valid) + "Convert Company BACKEND function to Capf. +VALID is a function taking the old and new input string. It should +return nil if the cached candidates became invalid. The default value +for VALID is `string-prefix-p' such that the candidates are only fetched +again if the input prefix changed." + (lambda () + (when (and (symbolp backend) (not (fboundp backend))) + (ignore-errors (require backend nil t))) + (when (bound-and-true-p company-mode) + (error "`cape-company-to-capf' should not be used with `company-mode', use the Company backend directly instead")) + (when (and (symbolp backend) (not (alist-get backend cape--company-init))) + (funcall backend 'init) + (put backend 'company-init t) + (setf (alist-get backend cape--company-init) t)) + (when-let ((prefix (cape--company-call backend 'prefix)) + (initial-input (if (stringp prefix) prefix (car-safe prefix)))) + (let* ((end (point)) (beg (- end (length initial-input))) + (valid (if (cape--company-call backend 'no-cache initial-input) + #'equal (or valid #'string-prefix-p))) + restore-props) + (list beg end + (funcall + (if (cape--company-call backend 'ignore-case) + #'completion-table-case-fold + #'identity) + (cape--properties-table + (cape--dynamic-table + beg end + (lambda (input) + (let ((cands (cape--company-call backend 'candidates input))) + ;; The candidate string including text properties should be + ;; restored in the :exit-function, if the UI does not + ;; guarantee this itself. Restoration is not necessary for + ;; Corfu since the introduction of `corfu--exit-function'. + (unless (and (bound-and-true-p corfu-mode) (fboundp 'corfu--exit-function)) + (setq restore-props cands)) + (cons (apply-partially valid input) cands)))) + :category backend + :sort (not (cape--company-call backend 'sorted)))) + :exclusive 'no + :company-prefix-length (cdr-safe prefix) + :company-doc-buffer (lambda (x) (cape--company-call backend 'doc-buffer x)) + :company-location (lambda (x) (cape--company-call backend 'location x)) + :company-docsig (lambda (x) (cape--company-call backend 'meta x)) + :company-deprecated (lambda (x) (cape--company-call backend 'deprecated x)) + :company-kind (lambda (x) (cape--company-call backend 'kind x)) + :annotation-function (lambda (x) + (when-let (ann (cape--company-call backend 'annotation x)) + (concat " " (string-trim ann)))) + :exit-function (lambda (x _status) + ;; Restore the candidate string including + ;; properties if restore-props is non-nil. See + ;; the comment above. + (setq x (or (car (member x restore-props)) x)) + (cape--company-call backend 'post-completion x))))))) + +;;;###autoload +(defun cape-interactive (&rest capfs) + "Complete interactively with the given CAPFS." + (let* ((ctx (and (consp (car capfs)) (car capfs))) + (capfs (if ctx (cdr capfs) capfs)) + (completion-at-point-functions + (if ctx + (mapcar (lambda (f) `(lambda () (let ,ctx (funcall ',f)))) capfs) + capfs))) + (unless (completion-at-point) + (user-error "%s: No completions" + (mapconcat (lambda (fun) + (if (symbolp fun) + (symbol-name fun) + "anonymous-capf")) + capfs ", "))))) + +;;;###autoload +(defun cape-capf-interactive (capf) + "Create interactive completion function from CAPF." + (lambda (&optional interactive) + (interactive (list t)) + (if interactive (cape-interactive capf) (funcall capf)))) + +;;;###autoload +(defun cape-wrap-super (&rest capfs) + "Call CAPFS and return merged completion result. +The CAPFS list can contain the keyword `:with' to mark the Capfs +afterwards as auxiliary One of the non-auxiliary Capfs before +`:with' must return non-nil for the super Capf to set in and +return a non-nil result. Such behavior is useful when listing +multiple super Capfs in the `completion-at-point-functions': + + (setq completion-at-point-functions + (list (cape-capf-super \\='eglot-completion-at-point + :with \\='tempel-complete) + (cape-capf-super \\='cape-dabbrev + :with \\='tempel-complete)))" + (when-let ((results (cl-loop for capf in capfs until (eq capf :with) + for res = (funcall capf) + if res collect (cons t res)))) + (pcase-let* ((results (nconc results + (cl-loop for capf in (cdr (memq :with capfs)) + for res = (funcall capf) + if res collect (cons nil res)))) + (`((,_main ,beg ,end . ,_)) results) + (cand-ht nil) + (tables nil) + (exclusive nil) + (prefix-len nil) + (cand-functions + '(:company-docsig :company-location :company-kind + :company-doc-buffer :company-deprecated + :annotation-function :exit-function))) + (cl-loop for (main beg2 end2 table . plist) in results do + ;; Note: `cape-capf-super' currently cannot merge Capfs which + ;; trigger at different beginning positions. In order to support + ;; this, take the smallest BEG value and then normalize all + ;; candidates by prefixing them such that they all start at the + ;; smallest BEG position. + (when (= beg beg2) + (push (list main (plist-get plist :predicate) table + ;; Plist attached to the candidates + (mapcan (lambda (f) + (when-let ((v (plist-get plist f))) + (list f v))) + cand-functions)) + tables) + ;; The resulting merged Capf is exclusive if one of the main + ;; Capfs is exclusive. + (when (and main (not (eq (plist-get plist :exclusive) 'no))) + (setq exclusive t)) + (setq end (max end end2)) + (let ((plen (plist-get plist :company-prefix-length))) + (cond + ((eq plen t) + (setq prefix-len t)) + ((and (not prefix-len) (integerp plen)) + (setq prefix-len plen)) + ((and (integerp prefix-len) (integerp plen)) + (setq prefix-len (max prefix-len plen))))))) + (setq tables (nreverse tables)) + `(,beg ,end + ,(lambda (str pred action) + (pcase action + (`(boundaries . ,_) nil) + ('metadata + '(metadata (category . cape-super) + (display-sort-function . identity) + (cycle-sort-function . identity))) + ('t ;; all-completions + (let ((ht (make-hash-table :test #'equal)) + (candidates nil)) + (cl-loop for (main table-pred table cand-plist) in tables do + (let* ((pr (if (and table-pred pred) + (lambda (x) (and (funcall table-pred x) (funcall pred x))) + (or table-pred pred))) + (md (completion-metadata "" table pr)) + (sort (or (completion-metadata-get md 'display-sort-function) + #'identity)) + ;; Always compute candidates of the main Capf + ;; tables, which come first in the tables + ;; list. For the :with Capfs only compute + ;; candidates if we've already determined that + ;; main candidates are available. + (cands (when (or main (or exclusive cand-ht candidates)) + (funcall sort (all-completions str table pr))))) + ;; Handle duplicates with a hash table. + (cl-loop + for cand in-ref cands + for dup = (gethash cand ht t) do + (cond + ((eq dup t) + ;; Candidate does not yet exist. + (puthash cand cand-plist ht)) + ((not (equal dup cand-plist)) + ;; Duplicate candidate. Candidate plist is + ;; different, therefore disambiguate the + ;; candidates. + (setf cand (propertize cand 'cape-capf-super + (cons cand cand-plist)))))) + (when cands (push cands candidates)))) + (when (or cand-ht candidates) + (setq candidates (apply #'nconc (nreverse candidates)) + cand-ht ht) + candidates))) + (_ ;; try-completion and test-completion + (cl-loop for (_main table-pred table _cand-plist) in tables thereis + (complete-with-action + action table str + (if (and table-pred pred) + (lambda (x) (and (funcall table-pred x) (funcall pred x))) + (or table-pred pred))))))) + :company-prefix-length ,prefix-len + ,@(and (not exclusive) '(:exclusive no)) + ,@(mapcan + (lambda (prop) + (list prop + (lambda (cand &rest args) + (if-let ((ref (get-text-property 0 'cape-capf-super cand))) + (when-let ((fun (plist-get (cdr ref) prop))) + (apply fun (car ref) args)) + (when-let ((plist (and cand-ht (gethash cand cand-ht))) + (fun (plist-get plist prop))) + (apply fun cand args)))))) + cand-functions))))) + +;;;###autoload +(defun cape-wrap-debug (capf &optional name) + "Call CAPF and return a completion table which prints trace messages. +If CAPF is an anonymous lambda, pass the Capf NAME explicitly for +meaningful debugging output." + (unless name + (setq name (if (symbolp capf) capf "capf"))) + (setq name (format "%s@%s" name (cl-incf cape--debug-id))) + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + (let* ((limit (1+ cape--debug-length)) + (pred (plist-get plist :predicate)) + (cands + ;; Reset regexps for `all-completions' + (let (completion-ignore-case completion-regexp-list) + (all-completions + "" table + (lambda (&rest args) + (and (or (not pred) (apply pred args)) (>= (cl-decf limit) 0)))))) + (plist-str "") + (plist-elt plist)) + (while (cdr plist-elt) + (setq plist-str (format "%s %s=%s" plist-str + (substring (symbol-name (car plist-elt)) 1) + (cape--debug-print (cadr plist-elt))) + plist-elt (cddr plist-elt))) + (cape--debug-message + "%s => input=%s:%s:%S table=%s%s" + name (+ beg 0) (+ end 0) (buffer-substring-no-properties beg end) + (cape--debug-print cands) + plist-str)) + `(,beg ,end ,(cape--debug-table + table name (copy-marker beg) (copy-marker end t)) + ,@(when-let ((exit (plist-get plist :exit-function))) + (list :exit-function + (lambda (cand status) + (cape--debug-message "%s:exit(candidate=%S status=%s)" + name cand status) + (funcall exit cand status)))) + . ,plist)) + (result + (cape--debug-message "%s() => %s (No completion)" + name (cape--debug-print result))))) + +;;;###autoload +(defun cape-wrap-buster (capf &optional valid) + "Call CAPF and return a completion table with cache busting. +This function can be used as an advice around an existing Capf. +The cache is busted when the input changes. The argument VALID +can be a function taking the old and new input string. It should +return nil if the new input requires that the completion table is +refreshed. The default value for VALID is `equal', such that the +completion table is refreshed on every input change." + (setq valid (or valid #'equal)) + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + (setq plist `(:cape--buster t . ,plist)) + `(,beg ,end + ,(let* ((beg (copy-marker beg)) + (end (copy-marker end t)) + (input (buffer-substring-no-properties beg end))) + (lambda (str pred action) + (let ((new-input (buffer-substring-no-properties beg end))) + (unless (or (not (eq action t)) + (cape--separator-p new-input) + (funcall valid input new-input)) + (pcase + ;; Reset in case `all-completions' is used inside CAPF + (let (completion-ignore-case completion-regexp-list) + (funcall capf)) + ((and `(,new-beg ,new-end ,new-table . ,new-plist) + (guard (and (= beg new-beg) (= end new-end)))) + (let (throw-on-input) ;; No interrupt during state update + (setf table new-table + input new-input + (cddr plist) new-plist)))))) + (complete-with-action action table str pred))) + ,@plist)))) + +;;;###autoload +(defun cape-wrap-passthrough (capf) + "Call CAPF and make sure that no completion style filtering takes place." + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + `(,beg ,end ,(cape--passthrough-table table) ,@plist)))) + +;;;###autoload +(defun cape-wrap-properties (capf &rest properties) + "Call CAPF and add additional completion PROPERTIES. +Completion properties include for example :exclusive, :annotation-function and +the various :company-* extensions. Furthermore a boolean :sort flag and a +completion :category symbol can be specified." + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + `(,beg ,end + ,(apply #'cape--properties-table table properties) + ,@properties ,@plist)))) + +;;;###autoload +(defun cape-wrap-nonexclusive (capf) + "Call CAPF and ensure that it is marked as non-exclusive. +This function can be used as an advice around an existing Capf." + (cape-wrap-properties capf :exclusive 'no)) + +;;;###autoload +(defun cape-wrap-predicate (capf predicate) + "Call CAPF and add an additional candidate PREDICATE. +The PREDICATE is passed the candidate symbol or string." + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + `(,beg ,end ,table + :predicate + ,(if-let (pred (plist-get plist :predicate)) + ;; First argument is key, second is value for hash tables. + ;; The first argument can be a cons cell for alists. Then + ;; the candidate itself is either a string or a symbol. We + ;; normalize the calling convention here such that PREDICATE + ;; always receives a string or a symbol. + (lambda (&rest args) + (when (apply pred args) + (setq args (car args)) + (funcall predicate (if (consp args) (car args) args)))) + (lambda (key &optional _val) + (funcall predicate (if (consp key) (car key) key)))) + ,@plist)))) + +;;;###autoload +(defun cape-wrap-silent (capf) + "Call CAPF and silence it (no messages, no errors). +This function can be used as an advice around an existing Capf." + (pcase (cape--silent (funcall capf)) + (`(,beg ,end ,table . ,plist) + `(,beg ,end ,(cape--silent-table table) ,@plist)))) + +;;;###autoload +(defun cape-wrap-case-fold (capf &optional nofold) + "Call CAPF and return a case-insensitive completion table. +If NOFOLD is non-nil return a case sensitive table instead. This +function can be used as an advice around an existing Capf." + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + `(,beg ,end ,(completion-table-case-fold table nofold) ,@plist)))) + +;;;###autoload +(defun cape-wrap-noninterruptible (capf) + "Call CAPF and return a non-interruptible completion table. +This function can be used as an advice around an existing Capf." + (pcase (let (throw-on-input) (funcall capf)) + (`(,beg ,end ,table . ,plist) + `(,beg ,end ,(cape--noninterruptible-table table) ,@plist)))) + +;;;###autoload +(defun cape-wrap-prefix-length (capf length) + "Call CAPF and ensure that prefix length is greater or equal than LENGTH. +If the prefix is long enough, enforce auto completion." + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + (when (>= (- end beg) length) + `(,beg ,end ,table + :company-prefix-length t + ,@plist))))) + +;;;###autoload +(defun cape-wrap-inside-faces (capf &rest faces) + "Call CAPF only if inside FACES. +This function can be used as an advice around an existing Capf." + (when-let (((> (point) (point-min))) + (fs (get-text-property (1- (point)) 'face)) + ((if (listp fs) + (cl-loop for f in fs thereis (memq f faces)) + (memq fs faces)))) + (funcall capf))) + +;;;###autoload +(defun cape-wrap-inside-code (capf) + "Call CAPF only if inside code, not inside a comment or string. +This function can be used as an advice around an existing Capf." + (let ((s (syntax-ppss))) + (and (not (nth 3 s)) (not (nth 4 s)) (funcall capf)))) + +;;;###autoload +(defun cape-wrap-inside-comment (capf) + "Call CAPF only if inside comment. +This function can be used as an advice around an existing Capf." + (and (nth 4 (syntax-ppss)) (funcall capf))) + +;;;###autoload +(defun cape-wrap-inside-string (capf) + "Call CAPF only if inside string. +This function can be used as an advice around an existing Capf." + (and (nth 3 (syntax-ppss)) (funcall capf))) + +;;;###autoload +(defun cape-wrap-purify (capf) + "Call CAPF and ensure that it does not illegally modify the buffer. +This function can be used as an advice around an existing +Capf. It has been introduced mainly to fix the broken +`pcomplete-completions-at-point' function in Emacs versions < 29." + ;; bug#50470: Fix Capfs which illegally modify the buffer or which illegally + ;; call `completion-in-region'. The workaround here was proposed by + ;; @jakanakaevangeli and is used in his capf-autosuggest package. In Emacs 29 + ;; the purity bug of Pcomplete has been fixed, such that make + ;; `cape-wrap-purify' is not necessary anymore. + (catch 'cape--illegal-completion-in-region + (condition-case nil + (let ((buffer-read-only t) + (inhibit-read-only nil) + (completion-in-region-function + (lambda (beg end coll pred) + (throw 'cape--illegal-completion-in-region + (list beg end coll :predicate pred))))) + (funcall capf)) + (buffer-read-only nil)))) + +;;;###autoload +(defun cape-wrap-accept-all (capf) + "Call CAPF and return a completion table which accepts every input. +This function can be used as an advice around an existing Capf." + (pcase (funcall capf) + (`(,beg ,end ,table . ,plist) + `(,beg ,end ,(cape--accept-all-table table) . ,plist)))) + +;;;###autoload (autoload 'cape-capf-accept-all "cape") +;;;###autoload (autoload 'cape-capf-buster "cape") +;;;###autoload (autoload 'cape-capf-case-fold "cape") +;;;###autoload (autoload 'cape-capf-debug "cape") +;;;###autoload (autoload 'cape-capf-inside-code "cape") +;;;###autoload (autoload 'cape-capf-inside-comment "cape") +;;;###autoload (autoload 'cape-capf-inside-faces "cape") +;;;###autoload (autoload 'cape-capf-inside-string "cape") +;;;###autoload (autoload 'cape-capf-nonexclusive "cape") +;;;###autoload (autoload 'cape-capf-noninterruptible "cape") +;;;###autoload (autoload 'cape-capf-passthrough "cape") +;;;###autoload (autoload 'cape-capf-predicate "cape") +;;;###autoload (autoload 'cape-capf-prefix-length "cape") +;;;###autoload (autoload 'cape-capf-properties "cape") +;;;###autoload (autoload 'cape-capf-purify "cape") +;;;###autoload (autoload 'cape-capf-silent "cape") +;;;###autoload (autoload 'cape-capf-super "cape") + +(dolist (wrapper (list #'cape-wrap-accept-all #'cape-wrap-buster + #'cape-wrap-case-fold #'cape-wrap-debug + #'cape-wrap-inside-code #'cape-wrap-inside-comment + #'cape-wrap-inside-faces #'cape-wrap-inside-string + #'cape-wrap-nonexclusive #'cape-wrap-noninterruptible + #'cape-wrap-passthrough #'cape-wrap-predicate + #'cape-wrap-prefix-length #'cape-wrap-properties + #'cape-wrap-purify #'cape-wrap-silent #'cape-wrap-super)) + (let ((name (string-remove-prefix "cape-wrap-" (symbol-name wrapper)))) + (defalias (intern (format "cape-capf-%s" name)) + (lambda (capf &rest args) (lambda () (apply wrapper capf args))) + (format "Create a %s Capf from CAPF. +The Capf calls `%s' with CAPF and ARGS as arguments." name wrapper)))) + +(defvar-keymap cape-prefix-map + :doc "Keymap used as completion entry point. +The keymap should be installed globally under a prefix." + "p" #'completion-at-point + "t" #'complete-tag + "d" #'cape-dabbrev + "h" #'cape-history + "f" #'cape-file + "s" #'cape-elisp-symbol + "e" #'cape-elisp-block + "a" #'cape-abbrev + "l" #'cape-line + "w" #'cape-dict + "k" 'cape-keyword + ":" 'cape-emoji + "\\" 'cape-tex + "_" 'cape-tex + "^" 'cape-tex + "&" 'cape-sgml + "r" 'cape-rfc1345) + +;;;###autoload (autoload 'cape-prefix-map "cape" nil t 'keymap) +(defalias 'cape-prefix-map cape-prefix-map) + +(provide 'cape) +;;; cape.el ends here diff --git a/emacs/elpa/cape-20240818.1414/cape.elc b/emacs/elpa/cape-20240818.1414/cape.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-autoloads.el b/emacs/elpa/consult-20240811.1858/consult-autoloads.el @@ -1,445 +0,0 @@ -;;; consult-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from consult.el - -(autoload 'consult-completion-in-region "consult" "\ -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 this function as a -value for `completion-in-region-function'. - -(fn START END COLLECTION &optional PREDICATE)") -(autoload 'consult-outline "consult" "\ -Jump to an outline heading, obtained by matching against `outline-regexp'. - -This command supports narrowing to a heading level and candidate -preview. The initial narrowing LEVEL can be given as prefix -argument. The symbol at point is added to the future history. - -(fn &optional LEVEL)" t) -(autoload 'consult-mark "consult" "\ -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. - -(fn &optional MARKERS)" t) -(autoload 'consult-global-mark "consult" "\ -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. - -(fn &optional MARKERS)" t) -(autoload 'consult-line "consult" "\ -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. - -(fn &optional INITIAL START)" t) -(autoload 'consult-line-multi "consult" "\ -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'. - -(fn QUERY &optional INITIAL)" t) -(autoload 'consult-keep-lines "consult" "\ -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. - -(fn FILTER &optional INITIAL)" t) -(autoload 'consult-focus-lines "consult" "\ -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. - -(fn FILTER &optional SHOW INITIAL)" t) -(autoload 'consult-goto-line "consult" "\ -Read line number and jump to the line with preview. - -Enter either a line number to jump to the first column of the -given line or line:column in order to jump to a specific column. -Jump directly if a line number is given as prefix ARG. The -command respects narrowing and the settings -`consult-goto-line-numbers' and `consult-line-numbers-widen'. - -(fn &optional ARG)" t) -(autoload 'consult-recent-file "consult" "\ -Find recent file using `completing-read'." t) -(autoload 'consult-mode-command "consult" "\ -Run a command from any of the given MODES. - -If no MODES are specified, use currently active major and minor modes. - -(fn &rest MODES)" t) -(autoload 'consult-yank-from-kill-ring "consult" "\ -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. - -(fn STRING &optional ARG)" t) -(autoload 'consult-yank-pop "consult" "\ -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. - -(fn &optional ARG)" t) -(autoload 'consult-yank-replace "consult" "\ -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. - -(fn STRING)" t) -(autoload 'consult-bookmark "consult" "\ -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. - -(fn NAME)" t) -(autoload 'consult-complex-command "consult" "\ -Select and evaluate command from the command history. - -This command can act as a drop-in replacement for `repeat-complex-command'." t) -(autoload 'consult-history "consult" "\ -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. - -(fn &optional HISTORY INDEX BOL)" t) -(autoload 'consult-isearch-history "consult" "\ -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." t) -(autoload 'consult-minor-mode-menu "consult" "\ -Enable or disable minor mode. - -This is an alternative to `minor-mode-menu-from-indicator'." t) -(autoload 'consult-theme "consult" "\ -Disable current themes and enable THEME from `consult-themes'. - -The command supports previewing the currently selected theme. - -(fn THEME)" t) -(autoload 'consult-buffer "consult" "\ -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. - -(fn &optional SOURCES)" t) -(autoload 'consult-project-buffer "consult" "\ -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." t) -(autoload 'consult-buffer-other-window "consult" "\ -Variant of `consult-buffer', switching to a buffer in another window." t) -(autoload 'consult-buffer-other-frame "consult" "\ -Variant of `consult-buffer', switching to a buffer in another frame." t) -(autoload 'consult-buffer-other-tab "consult" "\ -Variant of `consult-buffer', switching to a buffer in another tab." t) -(autoload 'consult-grep "consult" "\ -Search with `grep' for files in DIR where the content matches a regexp. - -The initial input is given by the INITIAL argument. DIR can be -nil, a directory string or a list of file/directory paths. If -`consult-grep' is called interactively with a prefix argument, -the user can specify the directories or files to search in. -Multiple directories must be separated by comma in the -minibuffer, since they are read via `completing-read-multiple'. -By default the project directory is used if -`consult-project-function' is defined and returns non-nil. -Otherwise the `default-directory' is searched. - -The input string is split, the first part of the string (grep -input) is passed to the asynchronous grep process and the second -part of the string is passed to the completion-style filtering. - -The input string is split at a punctuation character, which is -given as the first character of the input string. The format is -similar to Perl-style regular expressions, e.g., /regexp/. -Furthermore command line options can be passed to grep, specified -behind --. The overall prompt input has the form -`#async-input -- grep-opts#filter-string'. - -Note that the grep input string is transformed from Emacs regular -expressions to Posix regular expressions. Always enter Emacs -regular expressions at the prompt. `consult-grep' behaves like -builtin Emacs search commands, e.g., Isearch, which take Emacs -regular expressions. Furthermore the asynchronous input split -into words, each word must match separately and in any order. -See `consult--regexp-compiler' for the inner workings. In order -to disable transformations of the grep input, adjust -`consult--regexp-compiler' accordingly. - -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. - -(fn &optional DIR INITIAL)" t) -(autoload 'consult-git-grep "consult" "\ -Search with `git grep' for files in DIR with INITIAL input. -See `consult-grep' for details. - -(fn &optional DIR INITIAL)" t) -(autoload 'consult-ripgrep "consult" "\ -Search with `rg' for files in DIR with INITIAL input. -See `consult-grep' for details. - -(fn &optional DIR INITIAL)" t) -(autoload 'consult-find "consult" "\ -Search for files with `find' in DIR. -The file names must match the input regexp. INITIAL is the -initial minibuffer input. See `consult-grep' for details -regarding the asynchronous search and the arguments. - -(fn &optional DIR INITIAL)" t) -(autoload 'consult-fd "consult" "\ -Search for files with `fd' in DIR. -The file names must match the input regexp. INITIAL is the -initial minibuffer input. See `consult-grep' for details -regarding the asynchronous search and the arguments. - -(fn &optional DIR INITIAL)" t) -(autoload 'consult-locate "consult" "\ -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. - -(fn &optional INITIAL)" t) -(autoload 'consult-man "consult" "\ -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. - -(fn &optional INITIAL)" t) -(register-definition-prefixes "consult" '("consult-")) - - -;;; Generated autoloads from consult-compile.el - -(autoload 'consult-compile-error "consult-compile" "\ -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." t) -(register-definition-prefixes "consult-compile" '("consult-compile--")) - - -;;; Generated autoloads from consult-flymake.el - -(autoload 'consult-flymake "consult-flymake" "\ -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. - -(fn &optional PROJECT)" t) -(register-definition-prefixes "consult-flymake" '("consult-flymake--")) - - -;;; Generated autoloads from consult-imenu.el - -(autoload 'consult-imenu "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'." t) -(autoload 'consult-imenu-multi "consult-imenu" "\ -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'. - -(fn &optional QUERY)" t) -(register-definition-prefixes "consult-imenu" '("consult-imenu-")) - - -;;; Generated autoloads from consult-info.el - -(autoload 'consult-info "consult-info" "\ -Full text search through info MANUALS. - -(fn &rest MANUALS)" t) -(register-definition-prefixes "consult-info" '("consult-info--")) - - -;;; Generated autoloads from consult-kmacro.el - -(autoload 'consult-kmacro "consult-kmacro" "\ -Run a chosen keyboard macro. - -With prefix ARG, run the macro that many times. -Macros containing mouse clicks are omitted. - -(fn ARG)" t) -(register-definition-prefixes "consult-kmacro" '("consult-kmacro--")) - - -;;; Generated autoloads from consult-org.el - -(autoload 'consult-org-heading "consult-org" "\ -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. - -(fn &optional MATCH SCOPE)" t) -(autoload 'consult-org-agenda "consult-org" "\ -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. - -(fn &optional MATCH)" t) -(register-definition-prefixes "consult-org" '("consult-org--")) - - -;;; Generated autoloads from consult-register.el - -(autoload 'consult-register-window "consult-register" "\ -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. - -(fn BUFFER &optional SHOW-EMPTY)") -(autoload 'consult-register-format "consult-register" "\ -Enhanced preview of register REG. -This function can be used as `register-preview-function'. -If COMPLETION is non-nil format the register for completion. - -(fn REG &optional COMPLETION)") -(autoload 'consult-register "consult-register" "\ -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. - -(fn &optional ARG)" t) -(autoload 'consult-register-load "consult-register" "\ -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. - -(fn REG &optional ARG)" t) -(autoload 'consult-register-store "consult-register" "\ -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. - -(fn ARG)" t) -(register-definition-prefixes "consult-register" '("consult-register-")) - - -;;; Generated autoloads from consult-xref.el - -(autoload 'consult-xref "consult-xref" "\ -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. - -(fn FETCHER &optional ALIST)") -(register-definition-prefixes "consult-xref" '("consult-xref--")) - -;;; End of scraped data - -(provide 'consult-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; consult-autoloads.el ends here diff --git a/emacs/elpa/consult-20240811.1858/consult-pkg.el b/emacs/elpa/consult-20240811.1858/consult-pkg.el @@ -1,13 +0,0 @@ -(define-package "consult" "20240811.1858" "Consulting completing-read" - '((emacs "27.1") - (compat "30")) - :commit "3d0fc6a8c6a74b21ca854b8632b3f58e0e513b85" :maintainers - '(("Daniel Mendler" . "mail@daniel-mendler.de")) - :maintainer - '("Daniel Mendler" . "mail@daniel-mendler.de") - :keywords - '("matching" "files" "completion") - :url "https://github.com/minad/consult") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/consult-20240811.1858/consult.el b/emacs/elpa/consult-20240811.1858/consult.el @@ -1,5274 +0,0 @@ -;;; consult.el --- Consulting completing-read -*- lexical-binding: t -*- - -;; Copyright (C) 2021-2024 Free Software Foundation, Inc. - -;; Author: Daniel Mendler and Consult contributors -;; Maintainer: Daniel Mendler <mail@daniel-mendler.de> -;; Created: 2020 -;; Version: 1.8 -;; Package-Requires: ((emacs "27.1") (compat "30")) -;; Homepage: https://github.com/minad/consult -;; Keywords: matching, files, completion - -;; This file is part of GNU Emacs. - -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; Consult implements a set of `consult-<thing>' 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 '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 key (const :tag "None" 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 key (const :tag "None" nil))) - -(defcustom consult-project-function - #'consult--default-project-function - "Function which returns project root directory. -The function takes one boolean argument MAY-PROMPT. If -MAY-PROMPT is non-nil, the function may ask the prompt the user -for a project directory. The root directory is used by -`consult-buffer' and `consult-grep'." - :type `(choice - (const :tag "Default project function" ,#'consult--default-project-function) - (function :tag "Custom function") - (const :tag "No project integration" 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 :tag "Delay in seconds")) - -(defcustom consult-async-input-throttle 0.5 - "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 :tag "Delay in seconds")) - -(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 :tag "Delay in seconds")) - -(defcustom consult-async-min-input 3 - "Minimum number of characters needed, before asynchronous process is called. - -This applies to asynchronous commands, e.g., `consult-grep'." - :type '(natnum :tag "Number of characters")) - -(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 (list #'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 '(natnum :tag "Buffer size in bytes")) - -(defcustom consult-buffer-filter - '("\\` " - "\\`\\*Completions\\*\\'" - "\\`\\*Flymake log\\*\\'" - "\\`\\*Semantic SymRef\\*\\'" - "\\`\\*vc\\*\\'" - "\\`newsrc-dribble\\'" ;; Gnus - "\\`\\*tramp/.*\\*\\'") - "Filter regexps for `consult-buffer'. - -The default setting is to filter ephemeral buffer names beginning -with a space character, the *Completions* buffer and a few log -buffers. The regular expressions are matched case sensitively." - :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-hidden - consult--source-project-recent-file-hidden) - "Sources used by `consult-buffer'. -See also `consult-project-buffer-sources'. -See `consult--multi' for a description of the source data structure." - :type '(repeat symbol)) - -(defcustom consult-project-buffer-sources - '(consult--source-project-buffer - consult--source-project-recent-file) - "Sources used by `consult-project-buffer'. -See also `consult-buffer-sources'. -See `consult--multi' for a description of the source data structure." - :type '(repeat symbol)) - -(defcustom consult-mode-command-filter - '(;; Filter commands - "-mode\\'" "--" - ;; Filter whole features - simple mwheel time so-long recentf tab-bar tab-line) - "Filter commands for `consult-mode-command'." - :type '(repeat (choice symbol regexp))) - -(defcustom consult-grep-max-columns 300 - "Maximal number of columns of grep output." - :type 'natnum) - -(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\ - --with-filename --line-number -I -r") - "Command line arguments for grep, see `consult-grep'. -The dynamically computed arguments are appended. -Can be either a string, or a list of strings or expressions." - :type '(choice string (repeat (choice string sexp)))) - -(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 sexp)))) - -(defcustom consult-ripgrep-args - "rg --null --line-buffered --color=never --max-columns=1000 --path-separator /\ - --smart-case --no-heading --with-filename --line-number --search-zip" - "Command line arguments for ripgrep, see `consult-ripgrep'. -The dynamically computed arguments are appended. -Can be either a string, or a list of strings or expressions." - :type '(choice string (repeat (choice string sexp)))) - -(defcustom consult-find-args - "find . -not ( -path */.[A-Za-z]* -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 sexp)))) - -(defcustom consult-fd-args - '((if (executable-find "fdfind" 'remote) "fdfind" "fd") - "--full-path --color=never") - "Command line arguments for fd, see `consult-fd'. -The dynamically computed arguments are appended. -Can be either a string, or a list of strings or expressions." - :type '(choice string (repeat (choice string sexp)))) - -(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 sexp)))) - -(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 sexp)))) - -(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) - (key :tag "Key") - (repeat :tag "List of keys" key))) - -(defcustom consult-preview-partial-size 1048576 - "Files larger than this byte limit are previewed partially." - :type '(natnum :tag "File size in bytes")) - -(defcustom consult-preview-partial-chunk 102400 - "Partial preview chunk size in bytes. -If a file is larger than `consult-preview-partial-size' only the -chunk from the beginning of the file is previewed." - :type '(natnum :tag "Chunk size in bytes")) - -(defcustom consult-preview-max-count 10 - "Number of file buffers to keep open temporarily during preview." - :type '(natnum :tag "Number of buffers")) - -(defcustom consult-preview-excluded-buffers nil - "Buffers excluded from preview. -The value should conform to the predicate format demanded by the -function `buffer-match-p'." - :type 'sexp) - -(defcustom consult-preview-excluded-files - '("\\`/[^/|:]+:") ;; Do not preview remote files - "List of regexps matched against names of files, which are not previewed." - :type '(repeat regexp)) - -(defcustom consult-preview-allowed-hooks - '(global-font-lock-mode - save-place-find-file-hook) - "List of hooks, which should be executed during file preview. -This variable applies to `find-file-hook', `change-major-mode-hook' and -mode hooks, e.g., `prog-mode-hook'." - :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 Info-bookmark-jump - Man-bookmark-jump woman-bookmark-jump) - (?p "Picture" image-bookmark-jump) - (?d "Docview" doc-view-bookmark-jump) - (?m "Mail" gnus-summary-bookmark-jump) - (?s "Eshell" eshell-bookmark-jump) - (?w "Web" eww-bookmark-jump xwidget-webkit-bookmark-jump-handler) - (?v "VC Directory" vc-dir-bookmark-jump) - (nil "Other")) - "Bookmark narrowing configuration. - -Each element of the list must have the form (char name handlers...)." - :type '(alist :key-type character :value-type (cons string (repeat 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 by `consult-grep'.") - -(defface consult-highlight-mark - '((t :inherit consult-highlight-match)) - "Face used for mark positions in completion candidates. -Used for example by `consult-mark'. The face should be different -than the `cursor' face to avoid confusion.") - -(defface consult-preview-match - '((t :inherit isearch)) - "Face used for match previews, e.g., in `consult-line'.") - -(defface consult-preview-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'.") - -;;;; Input history variables - -(defvar consult--path-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 `consult--jump-preview' does not properly - ;; clean up. See gh:minad/consult#593. This issue should better be fixed in - ;; `consult--jump-preview'. - `((,#'consult-buffer-other-frame :preview-key nil) - (,#'consult-buffer-other-tab :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.") - -(defvar consult--annotate-align-step 10 - "Round candidate width.") - -(defvar consult--annotate-align-width 0 - "Maximum candidate width used for annotation alignment.") - -(defconst consult--tofu-char #x200000 - "Special character used to encode line prefixes for disambiguation. -We use invalid characters outside the Unicode range.") - -(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--key-parse (key) - "Parse KEY or signal error if invalid." - (unless (key-valid-p key) - (error "%S is not a valid key definition; see `key-valid-p'" key)) - (key-parse key)) - -(defun consult--in-buffer (fun &optional buffer) - "Ensure that FUN is executed inside BUFFER." - (unless buffer (setq buffer (current-buffer))) - (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) - (let ((result (funcall table str pred action))) - (pcase action - ('metadata - (setq result - (mapcar - (lambda (x) - (if (and (string-suffix-p "-function" (symbol-name (car-safe x))) (cdr x)) - (cons (car x) (consult--in-buffer (cdr x))) - x)) - result))) - ((and 'completion--unquote (guard (functionp (cadr result)))) - (cl-callf consult--in-buffer (cadr result) buffer) - (cl-callf consult--in-buffer (cadddr result) buffer))) - result)) - buffer) - table)) - -(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." - (seq-mapcat (lambda (x) - (if (stringp x) - (split-string-and-unquote x) - (ensure-list (eval x 'lexical)))) - (ensure-list arg))) - -(defun consult--command-split (str) - "Return command argument and options list given input STR." - (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)) - (cl-with-gensyms (head prev 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 (gensym "hook")) - (append)) - (when (eq (car-safe fun) :append) - (setq append '(t) fun (cadr fun))) - `(let ((,hook (make-symbol "consult--minibuffer-setup-hook"))) - (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)) - (cl-with-gensyms (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 hash table 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 (gensym "buffer")) - (local (mapcar (lambda (x) (cons (gensym "local") (car x))) binds))) - `(let ((,buffer (current-buffer)) - ,@(mapcar (lambda (x) `(,(car x) (local-variable-p ',(cdr x)))) local)) - (unwind-protect - (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))))))) - -(defvar consult--fast-abbreviate-file-name nil) -(defun consult--fast-abbreviate-file-name (name) - "Return abbreviate file NAME. -This function is a pure variant of `abbreviate-file-name', which -does not access the file system. This is important if we require -that the operation is fast, even for remote paths or paths on -network file systems." - (save-match-data - (let (case-fold-search) ;; Assume that file system is case sensitive. - (setq name (directory-abbrev-apply name)) - (if (string-match (with-memoization consult--fast-abbreviate-file-name - (directory-abbrev-make-regexp (expand-file-name "~"))) - name) - (concat "~" (substring name (match-beginning 1))) - name)))) - -(defun consult--left-truncate-file (file) - "Return abbreviated file name of FILE for use in `completing-read' prompt." - (save-match-data - (let ((afile (abbreviate-file-name file))) - (if (string-match "/\\([^/]+\\)/\\([^/]+/?\\)\\'" afile) - (propertize (format "…/%s/%s" (match-string 1 afile) (match-string 2 afile)) - 'help-echo afile) - afile)))) - -(defun consult--directory-prompt (prompt dir) - "Return prompt, paths and default directory. - -PROMPT is the prompt prefix. The directory is appended to the -prompt prefix. For projects only the project name is shown. The -`default-directory' is not shown. Other directories are -abbreviated and only the last two path components are shown. - -If DIR is a string, it is returned as default directory. If DIR -is a list of strings, the list is returned as search paths. If -DIR is nil the `consult-project-function' is tried to retrieve -the default directory. If no project is found the -`default-directory' is returned as is. Otherwise the user is -asked for the directories or files to search via -`completing-read-multiple'." - (let* ((paths nil) - (dir - (pcase dir - ((pred stringp) dir) - ('nil (or (consult--project-root) default-directory)) - (_ - (pcase (if (stringp (car-safe dir)) - dir - ;; Preserve this-command across `completing-read-multiple' call, - ;; such that `consult-customize' continues to work. - (let ((this-command this-command) - (def (abbreviate-file-name default-directory)) - ;; TODO: `minibuffer-completing-file-name' is - ;; mostly deprecated, but still in use. Packages - ;; should instead use the completion metadata. - (minibuffer-completing-file-name t) - (ignore-case read-file-name-completion-ignore-case)) - (consult--minibuffer-with-setup-hook - (lambda () - (setq-local completion-ignore-case ignore-case) - (set-syntax-table minibuffer-local-filename-syntax)) - (mapcar #'substitute-in-file-name - (completing-read-multiple "Directories or files: " - #'read-file-name-internal - nil t def 'consult--path-history def))))) - ((and `(,p) (guard (file-directory-p p))) p) - (ps (setq paths (mapcar (lambda (p) - (file-relative-name (expand-file-name p))) - ps)) - default-directory))))) - (edir (file-name-as-directory (expand-file-name dir))) - (pdir (let ((default-directory edir)) - ;; Bind default-directory in order to find the project - (consult--project-root)))) - (list - (format "%s (%s): " prompt - (pcase paths - (`(,p) (consult--left-truncate-file p)) - (`(,p . ,_) - (format "%d paths, %s, …" (length paths) (consult--left-truncate-file p))) - ((guard (equal edir pdir)) (concat "Project " (consult--project-name pdir))) - (_ (consult--left-truncate-file edir)))) - (or paths '(".")) - edir))) - -(defun consult--default-project-function (may-prompt) - "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) - (propertize (match-string 1 dir) 'help-echo (abbreviate-file-name dir)) - dir)) - -(defun consult--format-file-line-match (file line match) - "Format string FILE:LINE:MATCH with faces." - (setq line (number-to-string line) - match (concat file ":" line ":" 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) - -(defun consult--make-overlay (beg end &rest props) - "Make consult overlay between BEG and END with PROPS." - (let ((ov (make-overlay beg end))) - (while props - (overlay-put ov (car props) (cadr props)) - (setq props (cddr props))) - 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--original-window () - "Return window which was just selected just before the minibuffer was entered. -In contrast to `minibuffer-selected-window' never return nil and -always return an appropriate non-minibuffer window." - (or (minibuffer-selected-window) - (if (window-minibuffer-p (selected-window)) - (next-window) - (selected-window)))) - -(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." - (cl-with-gensyms (overwrite) - `(let* ((,overwrite (> consult--gc-threshold gc-cons-threshold)) - (gc-cons-threshold (if ,overwrite consult--gc-threshold gc-cons-threshold)) - (gc-cons-percentage (if ,overwrite consult--gc-percentage gc-cons-percentage))) - ,@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)) - `(let (set-message-function) ;; bug#63253: Broken `with-delayed-message' - (with-delayed-message (1 ,message) - (consult--with-increased-gc - ,@body)))) - -(defun consult--count-lines (pos) - "Move to position POS and return number of lines." - (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-excursion - (without-restriction - (goto-char (point-min)) - ;; Location data might be invalid by now! - (ignore-errors - (forward-line (1- line)) - (goto-char (min (+ (point) column) (pos-eol)))) - (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--line-with-mark (marker) - "Current line string where the MARKER position is highlighted." - (let* ((beg (pos-bol)) - (end (pos-eol)) - (str (consult--buffer-substring beg end 'fontify))) - (if (>= marker end) - (concat str #(" " 0 1 (face consult-highlight-mark))) - (put-text-property (- marker beg) (- (1+ marker) beg) - 'face 'consult-highlight-mark str) - str))) - -;;;; Tofu cooks - -(defsubst consult--tofu-p (char) - "Return non-nil if CHAR is a tofu." - (<= consult--tofu-char char (+ consult--tofu-char consult--tofu-range -1))) - -(defun consult--tofu-hide (str) - "Hide the tofus in STR." - (let* ((max (length str)) - (end max)) - (while (and (> end 0) (consult--tofu-p (aref str (1- end)))) - (cl-decf end)) - (when (< end max) - (setq str (copy-sequence str)) - (put-text-property end max 'invisible t str)) - str)) - -(defsubst consult--tofu-append (cand id) - "Append tofu-encoded ID to CAND. -The ID must fit within a single character. It must be smaller -than `consult--tofu-range'." - (setq id (char-to-string (+ consult--tofu-char id))) - (add-text-properties 0 1 '(invisible t consult-strip t) id) - (concat cand id)) - -(defsubst consult--tofu-get (cand) - "Extract tofu-encoded ID from CAND. -See `consult--tofu-append'." - (- (aref cand (1- (length cand))) consult--tofu-char)) - -;; We must disambiguate the lines by adding a prefix such that two lines with -;; the same text can be distinguished. In order to avoid matching the line -;; number, such that the user can search for numbers with `consult-line', we -;; encode the line number as characters outside the Unicode range. By doing -;; that, no accidental matching can occur. -(defun consult--tofu-encode (n) - "Return tofu-encoded number N as a string. -Large numbers are encoded as multiple tofu characters." - (let (str tofu) - (while (progn - (setq tofu (char-to-string - (+ consult--tofu-char (% n consult--tofu-range))) - str (if str (concat tofu str) tofu)) - (and (>= n consult--tofu-range) - (setq n (/ n consult--tofu-range))))) - (add-text-properties 0 (length str) '(invisible t consult-strip t) str) - str)) - -;;;; Regexp utilities - -(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 look-ahead wrapper only if there is more than one regular expression - (cond - ((and (eq type 'pcre) (cdr regexps)) - (concat "^" (mapconcat (lambda (x) (format "(?=.*%s)" x)) - 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--join-regexps-permutations regexps (and (eq type 'emacs) "\\"))))) - -(defun consult--join-regexps-permutations (regexps esc) - "Join all permutations of REGEXPS. -ESC is the escaping string for choice and groups." - (pcase regexps - ('nil "") - (`(,r) r) - (_ (mapconcat - (lambda (r) - (concat esc "(" r esc ").*" esc "(" - (consult--join-regexps-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--preview-allowed-p (fun) - "Return non-nil if FUN is an allowed preview mode hook." - (or (memq fun consult-preview-allowed-hooks) - (when-let (((symbolp fun)) - (name (symbol-name fun)) - ;; Global modes in Emacs 29 are activated via a - ;; `find-file-hook' ending with `-check-buffers'. This has been - ;; changed in Emacs 30. Now a `change-major-mode-hook' is used - ;; instead with the suffix `-check-buffers'. - (suffix (static-if (>= emacs-major-version 30) - "-enable-in-buffer" - "-check-buffers")) - ((string-suffix-p suffix name))) - (memq (intern (string-remove-suffix suffix name)) - consult-preview-allowed-hooks)))) - -(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 #'consult--preview-allowed-p - (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))) - (let* ((partial (>= size consult-preview-partial-size)) - (buffer (if partial - (generate-new-buffer (format "consult-partial-preview-%s" name)) - (find-file-noselect name 'nowarn))) - (success nil)) - (unwind-protect - (with-current-buffer buffer - (if (not partial) - (when (or (eq major-mode 'hexl-mode) - (and (eq major-mode 'fundamental-mode) - (save-excursion (search-forward "\0" nil 'noerror)))) - (error "No preview of binary file `%s'" - (file-name-nondirectory name))) - (with-silent-modifications - (setq buffer-read-only t) - (insert-file-contents name nil 0 consult-preview-partial-chunk) - (goto-char (point-max)) - (insert "\nFile truncated. End of partial preview.\n") - (goto-char (point-min))) - (when (save-excursion (search-forward "\0" nil 'noerror)) - (error "No partial preview of binary file `%s'" - (file-name-nondirectory name))) - ;; Auto detect major mode and hope for the best, given that the - ;; file is only previewed partially. If an error is thrown the - ;; buffer will be killed and preview is aborted. - (set-auto-mode) - (font-lock-mode 1)) - (when (bound-and-true-p so-long-detected-p) - (error "No preview of file `%s' with long lines" - (file-name-nondirectory name))) - ;; Run delayed hooks listed in `consult-preview-allowed-hooks'. - (dolist (hook (reverse (cons 'after-change-major-mode-hook delayed-mode-hooks))) - (run-hook-wrapped hook (lambda (fun) - (when (consult--preview-allowed-p fun) - (funcall fun)) - nil))) - (setq success (current-buffer))) - (unless success - (kill-buffer buffer)))))) - -(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)))) - (condition-case err - (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)) - (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))) - (error - (message "%s" (error-message-string err)) - nil)))) - -(defun consult--temporary-files () - "Return a function to open files temporarily for preview." - (let ((dir default-directory) - (hook (make-symbol "consult--temporary-files-upgrade-hook")) - (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 (consult--file-action 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-hook"))) - (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))))) - -(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 - (let ((inhibit-redisplay t)) ;; HACK: Prevent flicker due to premature redisplay - (org-fold-show-set-visibility 'canonical)) - (dolist (ov (overlays-in (pos-bol) (pos-eol))) - (when-let (fun (overlay-get ov 'isearch-open-invisible)) - (when (invisible-p (overlay-get ov 'invisible)) - (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) - (fboundp 'org-fold-core-get-regions) - (fboundp 'org-fold-core-region)) - ;; 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-hook")) - (buffer (current-buffer)) - (depth (recursion-depth))) - (fset hook - (lambda () - (when (= (recursion-depth) depth) - (remove-hook 'minibuffer-exit-hook hook) - (run-at-time - 0 nil - (lambda () - (when (buffer-live-p buffer) - (with-current-buffer buffer - (pcase-dolist (`(,beg ,end ,_) consult--org-fold-regions) - (when (markerp beg) (set-marker beg nil)) - (when (markerp end) (set-marker end nil))) - (kill-local-variable 'consult--org-fold-regions)))))))) - (add-hook 'minibuffer-exit-hook hook)))) - (let ((inhibit-redisplay t)) ;; HACK: Prevent flicker due to premature redisplay - (org-fold-show-set-visibility 'canonical)) - (list (lambda () - (pcase-dolist (`(,beg ,end ,spec) consult--org-fold-regions) - (org-fold-core-region beg end t spec))))) - (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-ensure-buffer (pos) - "Ensure that buffer of marker POS is displayed, return t if successful." - (or (not (markerp pos)) - ;; Switch to buffer if it is not visible - (when-let ((buf (marker-buffer pos))) - (or (and (eq (current-buffer) buf) (eq (window-buffer) buf)) - (consult--buffer-action buf 'norecord) - t)))) - -(defun consult--jump (pos) - "Jump to POS. -First push current position to mark ring, then move to new -position and run `consult-after-jump-hook'." - (when pos - ;; Extract marker from list with with overlay positions, see `consult--line-match' - (when (consp pos) (setq pos (car pos))) - ;; 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)) - (when (consult--jump-ensure-buffer pos) - (unless (= (goto-char pos) (point)) ;; Widen if jump failed - (widen) - (goto-char 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 (restore) - (lambda (action cand) - (when (eq action 'preview) - (mapc #'funcall restore) - (setq restore nil) - ;; TODO Better buffer preview support - ;; 1. Use consult--buffer-preview instead of consult--jump-ensure-buffer - ;; 2. Remove function consult--jump-ensure-buffer - ;; 3. Remove consult-buffer-other-* from consult-customize-alist - (when-let ((pos (or (car-safe cand) cand)) ;; Candidate can be previewed - ((consult--jump-ensure-buffer pos))) - (let ((saved-min (point-min-marker)) - (saved-max (point-max-marker)) - (saved-pos (point-marker))) - (set-marker-insertion-type saved-max t) ;; Grow when text is inserted - (push (lambda () - (when-let ((buf (marker-buffer saved-pos))) - (with-current-buffer buf - (narrow-to-region saved-min saved-max) - (goto-char saved-pos) - (set-marker saved-pos nil) - (set-marker saved-min nil) - (set-marker saved-max nil)))) - restore)) - (unless (= (goto-char pos) (point)) ;; Widen if jump failed - (widen) - (goto-char pos)) - (setq restore (nconc (consult--invisible-open-temporarily) restore)) - ;; Ensure that cursor is properly previewed (gh:minad/consult#764) - (unless (eq cursor-in-non-selected-windows 'box) - (let ((orig cursor-in-non-selected-windows) - (buf (current-buffer))) - (push - (if (local-variable-p 'cursor-in-non-selected-windows) - (lambda () - (when (buffer-live-p buf) - (with-current-buffer buf - (setq-local cursor-in-non-selected-windows orig)))) - (lambda () - (when (buffer-live-p buf) - (with-current-buffer buf - (kill-local-variable 'cursor-in-non-selected-windows))))) - restore) - (setq-local cursor-in-non-selected-windows 'box))) - ;; Match previews - (let ((overlays - (list (save-excursion - (let ((vbeg (progn (beginning-of-visual-line) (point))) - (vend (progn (end-of-visual-line) (point))) - (end (pos-eol))) - (consult--make-overlay vbeg (if (= vend end) (1+ end) vend) - 'face 'consult-preview-line - 'window (selected-window) - 'priority 1)))))) - (dolist (match (cdr-safe cand)) - (push (consult--make-overlay (+ (point) (car match)) - (+ (point) (cdr match)) - 'face 'consult-preview-match - 'window (selected-window) - 'priority 2) - overlays)) - (push (lambda () (mapc #'delete-overlay overlays)) restore)) - (run-hooks 'consult-after-jump-hook)))))) - -(defun consult--jump-state () - "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-hook"))) - (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) - (setq key (consult--key-parse 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--preview-append-local-pch (fun) - "Append FUN to local `post-command-hook' list." - ;; Symbol indirection because of bug#46407. - (let ((hook (make-symbol "consult--preview-post-command-hook"))) - (fset hook fun) - ;; TODO Emacs 28 has a bug, where the hook--depth-alist is not cleaned up properly - ;; Do not use the broken add-hook here. - ;;(add-hook 'post-command-hook hook '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 save-input fun) - "Add preview support for FUN. -See `consult--with-preview' for the arguments -PREVIEW-KEY, STATE, TRANSFORM, CANDIDATE and SAVE-INPUT." - (let ((mb-input "") mb-narrow selected timer previewed) - (consult--minibuffer-with-setup-hook - (if (and state preview-key) - (lambda () - (let ((hook (make-symbol "consult--preview-minibuffer-exit-hook")) - (depth (recursion-depth))) - (fset hook - (lambda () - (when (= (recursion-depth) depth) - (remove-hook 'minibuffer-exit-hook hook) - (when timer - (cancel-timer timer) - (setq timer nil)) - (with-selected-window (consult--original-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 hook)) - ;; STEP 1: Setup the preview function - (with-selected-window (consult--original-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) - (win (consult--original-window))) - (with-selected-window win - (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. - ;; - ;; In older Consult versions we instead compared - ;; the input without properties, since I worried - ;; that comparing the transformed candidates - ;; could be potentially expensive. However - ;; comparing the transformed candidates is more - ;; correct. The transformed candidate is the - ;; thing which is actually previewed. - (unless (equal-including-properties previewed transformed) - (if (> debounce 0) - (setq timer - (run-at-time - debounce nil - (lambda () - ;; Preview only when a completion - ;; window is selected and when - ;; the preview window is alive. - (when (and (consult--completion-window-p) - (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--preview-append-local-pch - (lambda () - (setq mb-input (minibuffer-contents-no-properties) - mb-narrow consult--narrow) - (funcall consult--preview-function)))) - (lambda () - (consult--preview-append-local-pch - (lambda () - (setq mb-input (minibuffer-contents-no-properties) - mb-narrow consult--narrow))))) - (unwind-protect - (setq selected (when-let (result (funcall fun)) - (when-let ((save-input) - (list (symbol-value save-input)) - ((equal (car list) result))) - (set save-input (cdr list))) - (funcall transform mb-narrow mb-input result))) - (when save-input - (add-to-history save-input 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 save-input &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. -SAVE-INPUT can be a history variable symbol to save the input. - -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 `consult--original-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 5)) - `(consult--with-preview-1 ,preview-key ,state ,transform ,candidate ,save-input (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 - (consult--key-parse consult-widen-key)) - (consult-narrow-key - (let ((key (consult--key-parse consult-narrow-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--make-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 ?\s 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)) - (setq key (consult--key-parse 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))) - (when-let ((init (and (memq :keys settings) (plist-get settings :initial)))) - (consult-narrow init))) - -;; 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 - -(defun consult--async-p (fun) - "Return t if FUN is an asynchronous completion function." - (and (functionp fun) - (condition-case nil - (progn (funcall fun "" nil 'metadata) nil) - (wrong-number-of-arguments t)))) - -(defmacro consult--with-async (bind &rest body) - "Setup asynchronous completion in BODY. - -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 (consult--async-p ,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. - (hook (make-symbol "consult--async-after-change-hook"))) - ;; Delay modification hook to ensure that minibuffer is still - ;; alive after the change, such that we don't restart a new - ;; asynchronous search right before exiting the minibuffer. - (fset hook (lambda (&rest _) (run-at-time 0 nil fun))) - (add-hook 'after-change-functions hook nil 'local) - (funcall hook))))) - (let ((,async (if (consult--async-p ,async) ,async (lambda (_) ,async)))) - (unwind-protect - ,(macroexp-progn body) - (funcall ,async 'destroy) - (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 functions 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)) - (end (minibuffer-prompt-end))) - ;; Highlight punctuation characters - (remove-list-of-text-properties end (+ end input-len) '(face)) - (dolist (hl highlights) - (put-text-property (+ end (car hl)) (+ end (cdr hl)) - 'face 'consult-async-split)) - (funcall async - ;; Pass through if the input is long enough! - (if (or force (>= async-len consult-async-min-input)) - 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* ((args (funcall builder action))) - (unless (stringp (car args)) - (setq args (car args))) - (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 - (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) - (when (> (buffer-size proc-buf) 0) - (with-current-buffer (get-buffer-create consult--async-log) - (goto-char (point-max)) - (insert ">>>>> stderr >>>>>\n") - (let ((beg (point))) - (insert-buffer-substring proc-buf) - (save-excursion - (goto-char beg) - (message #("%s" 0 2 (face error)) - (buffer-substring-no-properties (pos-bol) (pos-eol))))) - (insert "<<<<< stderr <<<<<\n"))))) - (process-adaptive-read-buffering nil)) - (funcall async 'indicator 'running) - (consult--async-log "consult--async-process started: args=%S default-directory=%S\n" - args default-directory) - (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 a new ASYNC function with candidate highlighting. -BUILDER is the command line builder function." - (let (highlight) - (lambda (action) - (cond - ((stringp action) - (setq highlight (cdr (funcall builder action))) - (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 "") (timer (timer-create)) (last 0)) - (lambda (action) - (pcase action - ((pred stringp) - (unless (equal action input) - (cancel-timer timer) - (funcall async "") ;; cancel running process - (setq input action) - (unless (equal action "") - (timer-set-function timer (lambda () - (setq last (float-time)) - (funcall async action))) - (timer-set-time - timer - (timer-relative-time - nil (max debounce (- (+ last throttle) (float-time))))) - (timer-activate timer))) - nil) - ('destroy - (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 ((delay (or delay consult-async-refresh-delay)) - (timer (timer-create))) - (timer-set-function timer async '(refresh)) - (lambda (action) - (prog1 (funcall async action) - (pcase action - ((or (pred consp) 'flush) - (unless (memq timer timer-list) - (timer-set-time timer (timer-relative-time nil delay)) - (timer-activate timer))) - ('destroy - (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." - (cl-with-gensyms (async-var action-var) - `(let ((,async-var ,async)) - (lambda (,action-var) - (funcall ,async-var (if (consp ,action-var) (,@transform ,action-var) ,action-var)))))) - -(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. - "<remap> <minibuffer-complete-word>" #'self-insert-command - ;; Remap Emacs 29 history and default completion for now - ;; (gh:minad/consult#613). - "<remap> <minibuffer-complete-defaults>" #'ignore - "<remap> <minibuffer-complete-history>" #'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--annotate-align (cand ann) - "Align annotation ANN by computing the maximum CAND width." - (setq consult--annotate-align-width - (max consult--annotate-align-width - (* (ceiling (consult--display-width cand) - consult--annotate-align-step) - consult--annotate-align-step))) - (when ann - (concat - #(" " 0 1 (display (space :align-to (+ left consult--annotate-align-width)))) - ann))) - -(defun consult--add-history (async items) - "Add ITEMS to the minibuffer future history. -ASYNC must be non-nil for async completion functions." - (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)))) - -(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))))) - -(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 (table &key - prompt predicate require-match history default - keymap category initial narrow add-history annotate - state preview-key sort lookup group inherit-input-method) - "See `consult--read' for the documentation of the arguments." - (consult--minibuffer-with-setup-hook - (:append (lambda () - (add-hook 'after-change-functions #'consult--tofu-hide-in-minibuffer nil 'local) - (consult--setup-keymap keymap (consult--async-p table) narrow preview-key) - (setq-local minibuffer-default-add-function - (apply-partially #'consult--add-history (consult--async-p table) add-history)))) - (consult--with-async (async table) - (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) - (pcase-exhaustive history - (`(:input ,var) var) - ((pred symbolp))) - ;; Do not unnecessarily let-bind the lambdas to avoid over-capturing in - ;; the interpreter. This will make closures and the lambda string - ;; representation larger, which makes debugging much worse. Fortunately - ;; the over-capturing problem does not affect the bytecode interpreter - ;; which does a proper scope analysis. - (let* ((metadata `(metadata - ,@(when category `((category . ,category))) - ,@(when group `((group-function . ,group))) - ,@(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))))) - (consult--annotate-align-width 0) - (selected - (completing-read - prompt - (lambda (str pred action) - (let ((result (complete-with-action action (funcall async nil) str pred))) - (if (eq action 'metadata) - (if (and (eq (car result) 'metadata) (cdr result)) - ;; Merge metadata - `(metadata ,@(cdr metadata) ,@(cdr result)) - metadata) - result))) - predicate require-match initial - (if (symbolp history) history (cadr history)) - default - inherit-input-method))) - ;; Repair the null completion semantics. `completing-read' may return - ;; an empty string even if REQUIRE-MATCH is non-nil. One can always - ;; opt-in to null completion by passing the empty string for DEFAULT. - (when (and (eq require-match t) (not default) (equal selected "")) - (user-error "No selection")) - selected))))) - -(cl-defun consult--read (table &rest options &key - prompt predicate require-match history default - keymap category initial narrow add-history annotate - state preview-key sort lookup group inherit-input-method) - "Enhanced completing read function to select from TABLE. - -The function is a thin wrapper around `completing-read'. Keyword -arguments are used instead of positional arguments for code -clarity. On top of `completing-read' it additionally supports -computing the candidate list asynchronously, candidate preview -and narrowing. You should use `completing-read' instead of -`consult--read' if you don't use asynchronous candidate -computation or candidate preview. - -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 table) ;; dynamic table or asynchronous function - (obarrayp table) ;; obarray - (hash-table-p table) ;; hash table - (not table) ;; empty list - (stringp (car table)) ;; string list - (and (consp (car table)) (stringp (caar table))) ;; string alist - (and (consp (car table)) (symbolp (caar table))))) ;; symbol alist - (ignore prompt predicate require-match history default - keymap category initial narrow add-history annotate - state preview-key sort lookup group inherit-input-method) - (apply #'consult--read-1 table - (append - (consult--customize-get) - options - (list :prompt "Select: " - :preview-key consult-preview-key - :sort t - :lookup (lambda (selected &rest _) selected))))) - -;;;; Internal API: consult--prompt - -(cl-defun consult--prompt-1 (&key prompt history add-history initial default - keymap state preview-key transform inherit-input-method) - "See `consult--prompt' for documentation." - (consult--minibuffer-with-setup-hook - (:append (lambda () - (consult--setup-keymap keymap nil nil preview-key) - (setq-local minibuffer-default-add-function - (apply-partially #'consult--add-history nil add-history)))) - (consult--with-preview - preview-key state - (lambda (_narrow inp _cand) (funcall transform inp)) - (lambda () "") - history - (read-from-minibuffer prompt initial nil nil history default inherit-input-method)))) - -(cl-defun consult--prompt (&rest options &key prompt history add-history initial default - keymap state preview-key transform inherit-input-method) - "Read from minibuffer. - -Keyword OPTIONS: - -PROMPT is the string to prompt with. -TRANSFORM is a function which is applied to the current input string. -HISTORY is the symbol of the history variable. -INITIAL is initial input. -DEFAULT is the default selected value. -ADD-HISTORY is a list of items to add to the history. -STATE is the state function, see `consult--with-preview'. -PREVIEW-KEY are the preview keys (nil, `any', a single key or a list of keys). -KEYMAP is a command-specific keymap." - (ignore prompt history add-history initial default - keymap state preview-key transform inherit-input-method) - (apply #'consult--prompt-1 - (append - (consult--customize-get) - options - (list :prompt "Input: " - :preview-key consult-preview-key - :transform #'identity)))) - -;;;; Internal API: consult--multi - -(defsubst consult--multi-source (sources cand) - "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 cand) - "Annotate candidate CAND from multi SOURCES." - (consult--annotate-align - cand - (let ((src (consult--multi-source sources cand))) - (if-let ((fun (plist-get src :annotate))) - (funcall fun (cdr (get-text-property 0 'multi-category cand))) - (plist-get src :name))))) - -(defun consult--multi-group (sources cand transform) - "Return title of candidate CAND or TRANSFORM the candidate given SOURCES." - (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)) - ((seq-find (lambda (src) (not (plist-get src :hidden))) 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) 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* ((str (or (car-safe item) item)) - (cand (consult--tofu-append str idx))) - ;; Preserve existing `multi-category' datum of the candidate. - (if (and (eq str item) (get-text-property 0 'multi-category str)) - (when face (add-text-properties 0 (length str) face cand)) - ;; Attach `multi-category' datum and face. - (add-text-properties - 0 (length str) - `(multi-category (,cat . ,(or (cdr-safe item) item)) ,@face) cand)) - (push cand candidates)))) - (cl-incf idx)) - (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 metadata, 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))) - (selected - (apply #'consult--read - candidates - (append - options - (list - :category 'multi-category - :predicate (apply-partially #'consult--multi-predicate sources) - :annotate (apply-partially #'consult--multi-annotate sources) - :group (apply-partially #'consult--multi-group sources) - :lookup (apply-partially #'consult--multi-lookup sources) - :preview-key (consult--multi-preview-key sources) - :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)) - -;;;; 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 () - "Get configuration from `consult--customize-alist' for `this-command'." - (mapcar (lambda (x) (eval x 'lexical)) - (alist-get 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) - ;; 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--make-overlay start end - 'invisible t - 'window (selected-window)))) - ;; Use `add-face-text-property' on a copy of "cand in order to merge face properties - (setq cand (copy-sequence cand)) - (add-face-text-property 0 (length cand) 'consult-preview-insertion t cand) - ;; 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 this function as a -value for `completion-in-region-function'." - (barf-if-buffer-read-only) - (let* ((initial (buffer-substring-no-properties start end)) - (metadata (completion-metadata initial collection predicate)) - ;; TODO: `minibuffer-completing-file-name' is mostly deprecated, but - ;; still in use. Packages should instead use the completion metadata. - (minibuffer-completing-file-name - (eq 'file (completion-metadata-get metadata 'category))) - (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 ""))) - (this-command #'consult-completion-in-region) - (completion - (cond - ((atom all) nil) - ((and (consp all) (atom (cdr all))) - (concat (substring initial 0 limit) (car all))) - (t - (consult--local-let ((enable-recursive-minibuffers t)) - ;; 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. - (consult--read (consult--completion-table-in-buffer collection) - :prompt "Completion: " - :state (consult--insertion-preview start end) - :predicate predicate - :initial 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 (&optional level) - "Jump to an outline heading, obtained by matching against `outline-regexp'. - -This command supports narrowing to a heading level and candidate -preview. The initial narrowing LEVEL can be given as prefix -argument. The symbol at point is added to the future history." - (interactive - (list (and current-prefix-arg (prefix-numeric-value current-prefix-arg)))) - (let* ((candidates (consult--slow-operation - "Collecting headings..." - (consult--outline-candidates))) - (min-level (- (cl-loop for cand in candidates minimize - (get-text-property 0 'consult--outline-level cand)) - ?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))) - (narrow-init (and level (max ?1 (min ?9 (+ level ?0)))))) - (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 :initial ,narrow-init) - :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-mark 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)) - (prefix (consult--format-file-line-match (buffer-name buf) line "")) - (cand (concat prefix (consult--line-with-mark marker) (consult--tofu-encode marker)))) - (put-text-property 0 (length prefix) 'consult-strip t cand) - (put-text-property 0 (length cand) 'consult-location (cons marker line) cand) - (push cand 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' formatting the candidates in grep-like - ;; style, we are not using the `consult-grep' category, since the candidates - ;; have location markers attached. - :category 'consult-location - :sort nil - :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))) - (buf (if (consp marker) - (car marker) ;; Handle cheap marker - (marker-buffer marker)))) - (if buf (buffer-name buf) "Dead buffer")))) - -(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) - (whitespace-orig (bound-and-true-p whitespace-mode)) - (hl-line-orig (bound-and-true-p hl-line-mode)) - (point-orig (point)) - lines content-orig replace last-input) - (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 provided - (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 whitespace-mode) (whitespace-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 whitespace-orig (whitespace-mode 1)) - (when font-lock-orig (font-lock-mode 1)))))) - -;;;###autoload -(defun consult-keep-lines (filter &optional initial) - "Select a subset of the lines in the current buffer with live preview. - -The selected lines are kept and the other lines are deleted. When called -interactively, the lines selected are those that match the minibuffer input. In -order to match the inverse of the input, prefix the input with `! '. When -called from Elisp, the filtering is performed by a FILTER function. This -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--line-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 - ;; Use "\n" for empty lines, since we need a non-empty 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) - ;; 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--make-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 nil 'show) - (goto-char pt-orig)) - (t - ;; Successfully 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 (filter &optional show initial) - "Hide or show lines using overlays. - -The selected lines are shown and the other lines hidden. When called -interactively, the lines selected are those that match the minibuffer input. In -order to match the inverse of the input, prefix the input with `! '. With -optional prefix argument SHOW reveal the hidden lines. Alternatively the -command can be restarted to reveal the lines. When called from Elisp, the -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 nil)) - current-prefix-arg)) - (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--line-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." - (save-match-data - (if (and str (string-match "\\`\\([[:digit:]]+\\):?\\([[:digit:]]*\\)\\'" str)) - (let ((line (string-to-number (match-string 1 str))) - (col (string-to-number (match-string 2 str)))) - (save-excursion - (save-restriction - (when consult-line-numbers-widen - (widen)) - (goto-char (point-min)) - (forward-line (1- line)) - (goto-char (min (+ (point) col) (pos-eol))) - (point)))) - (when (and str (not (equal str ""))) - (funcall msg "Please enter a number.")) - nil))) - -;;;###autoload -(defun consult-goto-line (&optional arg) - "Read line number and jump to the line with preview. - -Enter either a line number to jump to the first column of the -given line or line:column in order to jump to a specific column. -Jump directly if a line number is given as prefix ARG. The -command respects narrowing and the settings -`consult-goto-line-numbers' and `consult-line-numbers-widen'." - (interactive "P") - (if arg - (call-interactively #'goto-line) - (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'." - ;; Try to preserve the buffer as is, if it has already been opened, for - ;; example in literal or raw mode. - (setq file (abbreviate-file-name (expand-file-name file))) - (consult--buffer-action (or (get-file-buffer file) (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 - (mapcar #'consult--fast-abbreviate-file-name (bound-and-true-p recentf-list)) - (user-error "No recent files, `recentf-mode' is %s" - (if recentf-mode "enabled" "disabled"))) - :prompt "Find recent file: " - :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* ((case-fold-search) - (buffer (current-buffer)) - (command-filter (consult--regexp-filter (seq-filter #'stringp consult-mode-command-filter))) - (feature-filter (seq-filter #'symbolp consult-mode-command-filter)) - (minor-hash (consult--string-hash minor-mode-list)) - (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 (or (bookmark-get-handler bm) #'bookmark-default-handler)) - ((eq handler #'bookmark-default-handler)) - (file (bookmark-get-filename bm)) - (pos (bookmark-get-position bm)) - (buf (funcall open file))) - (set-marker (make-marker) pos buf)))))) - -(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 (cl-loop for (y _ . xs) in consult-bookmark-narrow nconc - (cl-loop for x in xs collect (cons x y))))) - (cl-loop for bm in bookmark-alist collect - (propertize (car bm) - 'consult--type - (alist-get - (or (bookmark-get-handler bm) #'bookmark-default-handler) - narrow))))) - -;;;###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 (cl-loop for (x y . _) in consult-bookmark-narrow collect (cons x y)))) - (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)) - (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'." - "<remap> <isearch-forward>" #'consult-isearch-forward - "<remap> <isearch-backward>" #'consult-isearch-backward) - -(defun consult--isearch-history-candidates () - "Return Isearch history candidates." - ;; 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)))) - (delete-dups - (mapcar - (lambda (cand) - ;; The search type can be distinguished via text properties. - (let* ((props (plist-member (text-properties-at 0 cand) - 'isearch-regexp-function)) - (type (pcase (cadr props) - ((and 'nil (guard (not props))) ?r) - ('nil ?l) - ('word-search-regexp ?w) - ('isearch-symbol-regexp ?s) - ('char-fold-to-regexp ?c) - (_ ?u)))) - ;; Disambiguate history items. The same string could - ;; occur with different search types. - (consult--tofu-append cand type))) - history)))) - -(defconst consult--isearch-history-narrow - '((?c . "Char") - (?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) - (cursor-in-echo-area t) ;; Avoid cursor flickering - (candidates (consult--isearch-history-candidates))) - (unless isearch-mode (isearch-mode t)) - (with-isearch-suspended - (setq isearch-new-string - (consult--read - candidates - :prompt "I-search: " - :category 'consult-isearch-history - :history t ;; disable history - :sort nil - :initial isearch-string - :keymap consult-isearch-history-map - :annotate - (lambda (cand) - (consult--annotate-align - cand - (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))) - (let (message-log-max) - (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 (car (memq (current-buffer) buffers)))) - (consult--keep! buffers - (unless (eq it current) - (if (get-buffer-window it 'visible) - it - (push it hidden) - nil))) - (nconc (nreverse hidden) buffers (and current (list current))))) - -(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) - "Return a list of buffers and create an appropriate prompt string. -Return a pair of a prompt string and a list of buffers. PROMPT -is the prefix of the prompt string. QUERY specifies the buffers -to search and 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--left-truncate-file ndir))) - (t ""))) - buffers))) - -(cl-defun consult--buffer-query (&key sort directory mode as predicate (filter t) - include (exclude consult-buffer-filter) - (buffer-list t)) - "Query for a list of matching buffers. -The function supports filtering by various criteria which are -used throughout Consult. In particular it is the backbone of -most `consult-buffer-sources'. -DIRECTORY can either be the symbol project or a file name. -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. -BUFFER-LIST is the unfiltered list of buffers. -AS is a conversion function." - (let ((root (consult--normalize-directory directory))) - (setq buffer-list (if (eq buffer-list t) (buffer-list) (copy-sequence buffer-list))) - (when sort - (setq buffer-list (funcall (intern (format "consult--buffer-sort-%s" sort)) buffer-list))) - (when (or filter mode as root) - (let ((exclude-re (consult--regexp-filter exclude)) - (include-re (consult--regexp-filter include)) - (case-fold-search)) - (consult--keep! buffer-list - (and - (or (not mode) - (let ((mm (buffer-local-value 'major-mode it))) - (if (consp mode) - (seq-some (lambda (m) (provided-mode-derived-p mm m)) mode) - (provided-mode-derived-p mm 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))))) - buffer-list)) - -(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-pair (buffer) - "Return a pair of name of BUFFER and BUFFER." - (cons (buffer-name buffer) buffer)) - -(defun consult--buffer-preview () - "Buffer preview function." - (let ((orig-buf (window-buffer (consult--original-window))) - (orig-prev (copy-sequence (window-prev-buffers))) - (orig-next (copy-sequence (window-next-buffers))) - other-win) - (lambda (action cand) - (pcase action - ('exit - (set-window-prev-buffers other-win orig-prev) - (set-window-next-buffers other-win orig-next)) - ('preview - (when (and (eq consult--buffer-display #'switch-to-buffer-other-window) - (not other-win)) - (switch-to-buffer-other-window orig-buf 'norecord) - (setq other-win (selected-window))) - (let ((win (or other-win (selected-window))) - (buf (or (and cand (get-buffer cand)) orig-buf))) - (when (and (window-live-p win) (buffer-live-p buf) - (not (buffer-match-p consult-preview-excluded-buffers buf))) - (with-selected-window win - (unless (or orig-prev orig-next) - (setq orig-prev (copy-sequence (window-prev-buffers)) - orig-next (copy-sequence (window-next-buffers)))) - (switch-to-buffer buf 'norecord))))))))) - -(defun consult--buffer-action (buffer &optional norecord) - "Switch to BUFFER via `consult--buffer-display' function. -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 ?b - :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 #'consult--buffer-pair)))) - "Project buffer candidate source for `consult-buffer'.") - -(defvar consult--source-project-recent-file - `(:name "Project File" - :narrow ?f - :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)) - items) - (dolist (file (bound-and-true-p recentf-list) (nreverse items)) - ;; Emacs 29 abbreviates file paths by default, see - ;; `recentf-filename-handlers'. I recommend to set - ;; `recentf-filename-handlers' to nil to avoid any slow down. - (unless (eq (aref file 0) ?/) - (let (file-name-handler-alist) ;; No Tramp slowdown please. - (setq file (expand-file-name file)))) - (when (and (not (gethash file ht)) (string-prefix-p root file)) - (let ((part (substring file len))) - (when (equal part "") (setq part "./")) - (put-text-property 0 1 'multi-category `(file . ,file) part) - (push part items)))))))) - "Project file candidate source for `consult-buffer'.") - -(defvar consult--source-project-buffer-hidden - `(:hidden t :narrow (?p . "Project") ,@consult--source-project-buffer) - "Like `consult--source-project-buffer' but hidden by default.") - -(defvar consult--source-project-recent-file-hidden - `(:hidden t :narrow (?p . "Project") ,@consult--source-project-recent-file) - "Like `consult--source-project-recent-file' but hidden by default.") - -(defvar consult--source-hidden-buffer - `(:name "Hidden Buffer" - :narrow ?\s - :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 #'consult--buffer-pair))) - "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 #'consult--buffer-pair - :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 #'consult--buffer-pair))) - "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)) - items) - (dolist (file (bound-and-true-p recentf-list) (nreverse items)) - ;; Emacs 29 abbreviates file paths by default, see - ;; `recentf-filename-handlers'. I recommend to set - ;; `recentf-filename-handlers' to nil to avoid any slow down. - (unless (eq (aref file 0) ?/) - (let (file-name-handler-alist) ;; No Tramp slowdown please. - (setq file (expand-file-name file)))) - (unless (gethash file ht) - (push (consult--fast-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))))) - -(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 overridden at the current recursion level. When entering a - ;; recursive minibuffer session, we should be able to still switch the - ;; project. But who does that? Working on the first level on project A - ;; and on the second level on project B and on the third level on project C? - ;; 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', switching to a buffer in another window." - (interactive) - (let ((consult--buffer-display #'switch-to-buffer-other-window)) - (consult-buffer))) - -;;;###autoload -(defun consult-buffer-other-frame () - "Variant of `consult-buffer', switching to a buffer in another frame." - (interactive) - (let ((consult--buffer-display #'switch-to-buffer-other-frame)) - (consult-buffer))) - -;;;###autoload -(defun consult-buffer-other-tab () - "Variant of `consult-buffer', switching to a buffer in another tab." - (interactive) - (let ((consult--buffer-display #'switch-to-buffer-other-tab)) - (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) - (setq highlight (cdr (funcall builder action))) - (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-noselect'." - (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 #'consult--file-action) 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 make-builder dir initial) - "Run asynchronous grep. - -MAKE-BUILDER is the function that returns the command line -builder function. DIR is a directory or a list of file or -directories. PROMPT is the prompt string. INITIAL is initial -input." - (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt prompt dir)) - (default-directory dir) - (builder (funcall make-builder paths))) - (consult--read - (consult--async-command builder - (consult--grep-format builder) - :file-handler t) ;; allow tramp - :prompt prompt - :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 look-ahead." - (eq 0 (process-file-shell-command - (concat "echo xaxbx | " - (mapconcat #'shell-quote-argument `(,@cmd "^(?=.*b)(?=.*a)") " "))))) - -(defun consult--grep-make-builder (paths) - "Build grep command line and grep across PATHS." - (let* ((cmd (consult--build-args consult-grep-args)) - (type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended))) - (lambda (input) - (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) - (flags (append cmd opts)) - (ignore-case (or (member "-i" flags) (member "--ignore-case" flags)))) - (if (or (member "-F" flags) (member "--fixed-strings" flags)) - (cons (append cmd (list "-e" arg) opts paths) - (apply-partially #'consult--highlight-regexps - (list (regexp-quote arg)) ignore-case)) - (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 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 paths) - hl)))))))) - -;;;###autoload -(defun consult-grep (&optional dir initial) - "Search with `grep' for files in DIR where the content matches a regexp. - -The initial input is given by the INITIAL argument. DIR can be -nil, a directory string or a list of file/directory paths. If -`consult-grep' is called interactively with a prefix argument, -the user can specify the directories or files to search in. -Multiple directories must be separated by comma in the -minibuffer, since they are read via `completing-read-multiple'. -By default the project directory is used if -`consult-project-function' is defined and returns non-nil. -Otherwise the `default-directory' is searched. - -The input string is split, the first part of the string (grep -input) is passed to the asynchronous grep process and the second -part of the string is passed to the completion-style filtering. - -The input string is split at a punctuation character, which is -given as the first character of the input string. The format is -similar to Perl-style regular expressions, e.g., /regexp/. -Furthermore command line options can be passed to grep, specified -behind --. The overall prompt input has the form -`#async-input -- grep-opts#filter-string'. - -Note that the grep input string is transformed from Emacs regular -expressions to Posix regular expressions. Always enter Emacs -regular expressions at the prompt. `consult-grep' behaves like -builtin Emacs search commands, e.g., Isearch, which take Emacs -regular expressions. Furthermore the asynchronous input split -into words, each word must match separately and in any order. -See `consult--regexp-compiler' for the inner workings. In order -to disable transformations of the grep input, adjust -`consult--regexp-compiler' accordingly. - -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." - (interactive "P") - (consult--grep "Grep" #'consult--grep-make-builder dir initial)) - -;;;;; Command: consult-git-grep - -(defun consult--git-grep-make-builder (paths) - "Create grep command line builder given PATHS." - (let ((cmd (consult--build-args consult-git-grep-args))) - (lambda (input) - (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) - (flags (append cmd opts)) - (ignore-case (or (member "-i" flags) (member "--ignore-case" flags)))) - (if (or (member "-F" flags) (member "--fixed-strings" flags)) - (cons (append cmd (list "-e" arg) opts paths) - (apply-partially #'consult--highlight-regexps - (list (regexp-quote arg)) ignore-case)) - (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended ignore-case))) - (when re - (cons (append cmd - (cdr (mapcan (lambda (x) (list "--and" "-e" x)) re)) - opts paths) - hl)))))))) - -;;;###autoload -(defun consult-git-grep (&optional dir initial) - "Search with `git grep' for files in DIR with INITIAL input. -See `consult-grep' for details." - (interactive "P") - (consult--grep "Git-grep" #'consult--git-grep-make-builder dir initial)) - -;;;;; Command: consult-ripgrep - -(defun consult--ripgrep-make-builder (paths) - "Create ripgrep command line builder given PATHS." - (let* ((cmd (consult--build-args consult-ripgrep-args)) - (type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended))) - (lambda (input) - (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) - (flags (append cmd opts)) - (ignore-case - (and (not (or (member "-s" flags) (member "--case-sensitive" flags))) - (or (member "-i" flags) (member "--ignore-case" flags) - (and (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)))))))) - (if (or (member "-F" flags) (member "--fixed-strings" flags)) - (cons (append cmd (list "-e" arg) opts paths) - (apply-partially #'consult--highlight-regexps - (list (regexp-quote arg)) ignore-case)) - (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg type ignore-case))) - (when re - (cons (append cmd (and (eq type 'pcre) '("-P")) - (list "-e" (consult--join-regexps re type)) - opts paths) - hl)))))))) - -;;;###autoload -(defun consult-ripgrep (&optional dir initial) - "Search with `rg' for files in DIR with INITIAL input. -See `consult-grep' for details." - (interactive "P") - (consult--grep "Ripgrep" #'consult--ripgrep-make-builder dir initial)) - -;;;;; 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 initial 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 (paths) - "Build find command line, finding across PATHS." - (let* ((cmd (seq-mapcat (lambda (x) - (if (equal x ".") paths (list x))) - (consult--build-args consult-find-args))) - (type (if (eq 0 (process-file-shell-command - (concat (car cmd) " -regextype emacs -version"))) - 'emacs 'basic))) - (lambda (input) - (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.*" - ;; 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 with `find' in DIR. -The file names must match the input regexp. INITIAL is the -initial minibuffer input. See `consult-grep' for details -regarding the asynchronous search and the arguments." - (interactive "P") - (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt "Find" dir)) - (default-directory dir) - (builder (consult--find-make-builder paths))) - (find-file (consult--find prompt builder initial)))) - -;;;;; Command: consult-fd - -(defun consult--fd-make-builder (paths) - "Build find command line, finding across PATHS." - (let ((cmd (consult--build-args consult-fd-args))) - (lambda (input) - (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) - (flags (append cmd opts)) - (ignore-case - (and (not (or (member "-s" flags) (member "--case-sensitive" flags))) - (or (member "-i" flags) (member "--ignore-case" flags) - (let (case-fold-search) - ;; Case insensitive if there are no uppercase letters - (not (string-match-p "[[:upper:]]" arg))))))) - (if (or (member "-F" flags) (member "--fixed-strings" flags)) - (cons (append cmd (list arg) opts paths) - (apply-partially #'consult--highlight-regexps - (list (regexp-quote arg)) ignore-case)) - (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'pcre ignore-case))) - (when re - (cons (append cmd - (mapcan (lambda (x) `("--and" ,x)) re) - opts - (mapcan (lambda (x) `("--search-path" ,x)) paths)) - hl)))))))) - -;;;###autoload -(defun consult-fd (&optional dir initial) - "Search for files with `fd' in DIR. -The file names must match the input regexp. INITIAL is the -initial minibuffer input. See `consult-grep' for details -regarding the asynchronous search and the arguments." - (interactive "P") - (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt "Fd" dir)) - (default-directory dir) - (builder (consult--fd-make-builder paths))) - (find-file (consult--find prompt builder initial)))) - -;;;;; Command: consult-locate - -(defun consult--locate-builder (input) - "Build command line from INPUT." - (pcase-let ((`(,arg . ,opts) (consult--command-split input))) - (unless (string-blank-p arg) - (cons (append (consult--build-args consult-locate-args) - (consult--split-escaped 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 from INPUT." - (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) - (`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended t))) - (when re - (cons (append (consult--build-args consult-man-args) - (list (consult--join-regexps re 'extended)) - 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." - :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 completion systems - -;;;;; Integration: Default *Completions* - -(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))))) - -;;;;; Integration: Vertico - -(defvar vertico--input) -(declare-function vertico--exhibit "ext:vertico") -(declare-function vertico--candidate "ext:vertico") -(declare-function vertico--filter-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 (not highlight) (bound-and-true-p vertico-mode)) - ;; Optimize `consult--completion-filter' using the deferred highlighting - ;; from Vertico. The advice is not necessary - it is a pure optimization. - (nconc (car (vertico--filter-completions pattern cands nil (length pattern) - `(metadata (category . ,category)))) - nil) - (funcall orig pattern cands category highlight))) - -(with-eval-after-load 'vertico - (advice-add #'consult--completion-filter :around #'consult--vertico-filter-adv) - (add-hook 'consult--completion-candidate-hook #'consult--vertico-candidate) - (add-hook 'consult--completion-refresh-hook #'consult--vertico-refresh) - (define-key consult-async-map [remap vertico-insert] 'vertico-next-group)) - -;;;;; Integration: Mct - -(with-eval-after-load 'mct (add-hook 'consult--completion-refresh-hook - 'mct--live-completions-refresh)) - -;;;;; Integration: Icomplete - -(defvar icomplete-mode) -(declare-function icomplete-exhibit "icomplete") - -(defun consult--icomplete-refresh () - "Refresh icomplete view." - (when icomplete-mode - (let ((top (car completion-all-sorted-completions))) - (completion--flush-all-sorted-completions) - ;; force flushing, otherwise narrowing is broken! - (setq completion-all-sorted-completions nil) - (when top - (let* ((completions (completion-all-sorted-completions)) - (last (last completions)) - (before)) ;; completions before top - ;; warning: completions is an improper list - (while (consp completions) - (if (equal (car completions) top) - (progn - (setcdr last (append (nreverse before) (cdr last))) - (setq completion-all-sorted-completions completions - completions nil)) - (push (car completions) before) - (setq completions (cdr completions))))))) - (icomplete-exhibit))) - -(with-eval-after-load 'icomplete - (add-hook 'consult--completion-refresh-hook #'consult--icomplete-refresh)) - -(provide 'consult) -;;; consult.el ends here diff --git a/emacs/elpa/consult-20240811.1858/consult.elc b/emacs/elpa/consult-20240811.1858/consult.elc Binary files differ. diff --git a/emacs/elpa/consult-20240818.1112/consult-autoloads.el b/emacs/elpa/consult-20240818.1112/consult-autoloads.el @@ -0,0 +1,444 @@ +;;; consult-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from consult.el + +(autoload 'consult-completion-in-region "consult" "\ +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 this function as a +value for `completion-in-region-function'. + +(fn START END COLLECTION &optional PREDICATE)") +(autoload 'consult-outline "consult" "\ +Jump to an outline heading, obtained by matching against `outline-regexp'. + +This command supports narrowing to a heading level and candidate +preview. The initial narrowing LEVEL can be given as prefix +argument. The symbol at point is added to the future history. + +(fn &optional LEVEL)" t) +(autoload 'consult-mark "consult" "\ +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. + +(fn &optional MARKERS)" t) +(autoload 'consult-global-mark "consult" "\ +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. + +(fn &optional MARKERS)" t) +(autoload 'consult-line "consult" "\ +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. + +(fn &optional INITIAL START)" t) +(autoload 'consult-line-multi "consult" "\ +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'. + +(fn QUERY &optional INITIAL)" t) +(autoload 'consult-keep-lines "consult" "\ +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. + +(fn FILTER &optional INITIAL)" t) +(autoload 'consult-focus-lines "consult" "\ +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. + +(fn FILTER &optional SHOW INITIAL)" t) +(autoload 'consult-goto-line "consult" "\ +Read line number and jump to the line with preview. + +Enter either a line number to jump to the first column of the +given line or line:column in order to jump to a specific column. +Jump directly if a line number is given as prefix ARG. The +command respects narrowing and the settings +`consult-goto-line-numbers' and `consult-line-numbers-widen'. + +(fn &optional ARG)" t) +(autoload 'consult-recent-file "consult" "\ +Find recent file using `completing-read'." t) +(autoload 'consult-mode-command "consult" "\ +Run a command from any of the given MODES. + +If no MODES are specified, use currently active major and minor modes. + +(fn &rest MODES)" t) +(autoload 'consult-yank-from-kill-ring "consult" "\ +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. + +(fn STRING &optional ARG)" t) +(autoload 'consult-yank-pop "consult" "\ +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. + +(fn &optional ARG)" t) +(autoload 'consult-yank-replace "consult" "\ +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. + +(fn STRING)" t) +(autoload 'consult-bookmark "consult" "\ +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. + +(fn NAME)" t) +(autoload 'consult-complex-command "consult" "\ +Select and evaluate command from the command history. + +This command can act as a drop-in replacement for `repeat-complex-command'." t) +(autoload 'consult-history "consult" "\ +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. + +(fn &optional HISTORY INDEX BOL)" t) +(autoload 'consult-isearch-history "consult" "\ +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." t) +(autoload 'consult-minor-mode-menu "consult" "\ +Enable or disable minor mode. + +This is an alternative to `minor-mode-menu-from-indicator'." t) +(autoload 'consult-theme "consult" "\ +Disable current themes and enable THEME from `consult-themes'. + +The command supports previewing the currently selected theme. + +(fn THEME)" t) +(autoload 'consult-buffer "consult" "\ +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. + +(fn &optional SOURCES)" t) +(autoload 'consult-project-buffer "consult" "\ +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." t) +(autoload 'consult-buffer-other-window "consult" "\ +Variant of `consult-buffer', switching to a buffer in another window." t) +(autoload 'consult-buffer-other-frame "consult" "\ +Variant of `consult-buffer', switching to a buffer in another frame." t) +(autoload 'consult-buffer-other-tab "consult" "\ +Variant of `consult-buffer', switching to a buffer in another tab." t) +(autoload 'consult-grep "consult" "\ +Search with `grep' for files in DIR where the content matches a regexp. + +The initial input is given by the INITIAL argument. DIR can be nil, a +directory string or a list of file/directory paths. If `consult-grep' +is called interactively with a prefix argument, the user can specify the +directories or files to search in. Multiple directories or files must +be separated by comma in the minibuffer, since they are read via +`completing-read-multiple'. By default the project directory is used if +`consult-project-function' is defined and returns non-nil. Otherwise +the `default-directory' is searched. If the command is invoked with a +double prefix argument (twice `C-u') the user is asked for a project, if +not yet inside a project, or the current project is searched. + +The input string is split, the first part of the string (grep input) is +passed to the asynchronous grep process and the second part of the +string is passed to the completion-style filtering. + +The input string is split at a punctuation character, which is given as +the first character of the input string. The format is similar to +Perl-style regular expressions, e.g., /regexp/. Furthermore command +line options can be passed to grep, specified behind --. The overall +prompt input has the form `#async-input -- grep-opts#filter-string'. + +Note that the grep input string is transformed from Emacs regular +expressions to Posix regular expressions. Always enter Emacs regular +expressions at the prompt. `consult-grep' behaves like builtin Emacs +search commands, e.g., Isearch, which take Emacs regular expressions. +Furthermore the asynchronous input split into words, each word must +match separately and in any order. See `consult--regexp-compiler' for +the inner workings. In order to disable transformations of the grep +input, adjust `consult--regexp-compiler' accordingly. + +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. + +(fn &optional DIR INITIAL)" t) +(autoload 'consult-git-grep "consult" "\ +Search with `git grep' for files in DIR with INITIAL input. +See `consult-grep' for details. + +(fn &optional DIR INITIAL)" t) +(autoload 'consult-ripgrep "consult" "\ +Search with `rg' for files in DIR with INITIAL input. +See `consult-grep' for details. + +(fn &optional DIR INITIAL)" t) +(autoload 'consult-find "consult" "\ +Search for files with `find' in DIR. +The file names must match the input regexp. INITIAL is the +initial minibuffer input. See `consult-grep' for details +regarding the asynchronous search and the arguments. + +(fn &optional DIR INITIAL)" t) +(autoload 'consult-fd "consult" "\ +Search for files with `fd' in DIR. +The file names must match the input regexp. INITIAL is the +initial minibuffer input. See `consult-grep' for details +regarding the asynchronous search and the arguments. + +(fn &optional DIR INITIAL)" t) +(autoload 'consult-locate "consult" "\ +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. + +(fn &optional INITIAL)" t) +(autoload 'consult-man "consult" "\ +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. + +(fn &optional INITIAL)" t) +(register-definition-prefixes "consult" '("consult-")) + + +;;; Generated autoloads from consult-compile.el + +(autoload 'consult-compile-error "consult-compile" "\ +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." t) +(register-definition-prefixes "consult-compile" '("consult-compile--")) + + +;;; Generated autoloads from consult-flymake.el + +(autoload 'consult-flymake "consult-flymake" "\ +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. + +(fn &optional PROJECT)" t) +(register-definition-prefixes "consult-flymake" '("consult-flymake--")) + + +;;; Generated autoloads from consult-imenu.el + +(autoload 'consult-imenu "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'." t) +(autoload 'consult-imenu-multi "consult-imenu" "\ +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'. + +(fn &optional QUERY)" t) +(register-definition-prefixes "consult-imenu" '("consult-imenu-")) + + +;;; Generated autoloads from consult-info.el + +(autoload 'consult-info "consult-info" "\ +Full text search through info MANUALS. + +(fn &rest MANUALS)" t) +(register-definition-prefixes "consult-info" '("consult-info--")) + + +;;; Generated autoloads from consult-kmacro.el + +(autoload 'consult-kmacro "consult-kmacro" "\ +Run a chosen keyboard macro. + +With prefix ARG, run the macro that many times. +Macros containing mouse clicks are omitted. + +(fn ARG)" t) +(register-definition-prefixes "consult-kmacro" '("consult-kmacro--")) + + +;;; Generated autoloads from consult-org.el + +(autoload 'consult-org-heading "consult-org" "\ +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. + +(fn &optional MATCH SCOPE)" t) +(autoload 'consult-org-agenda "consult-org" "\ +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. + +(fn &optional MATCH)" t) +(register-definition-prefixes "consult-org" '("consult-org--")) + + +;;; Generated autoloads from consult-register.el + +(autoload 'consult-register-window "consult-register" "\ +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. + +(fn BUFFER &optional SHOW-EMPTY)") +(autoload 'consult-register-format "consult-register" "\ +Enhanced preview of register REG. +This function can be used as `register-preview-function'. +If COMPLETION is non-nil format the register for completion. + +(fn REG &optional COMPLETION)") +(autoload 'consult-register "consult-register" "\ +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. + +(fn &optional ARG)" t) +(autoload 'consult-register-load "consult-register" "\ +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. + +(fn REG &optional ARG)" t) +(autoload 'consult-register-store "consult-register" "\ +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. + +(fn ARG)" t) +(register-definition-prefixes "consult-register" '("consult-register-")) + + +;;; Generated autoloads from consult-xref.el + +(autoload 'consult-xref "consult-xref" "\ +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. + +(fn FETCHER &optional ALIST)") +(register-definition-prefixes "consult-xref" '("consult-xref--")) + +;;; End of scraped data + +(provide 'consult-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; consult-autoloads.el ends here diff --git a/emacs/elpa/consult-20240811.1858/consult-compile.el b/emacs/elpa/consult-20240818.1112/consult-compile.el diff --git a/emacs/elpa/consult-20240811.1858/consult-compile.elc b/emacs/elpa/consult-20240818.1112/consult-compile.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-flymake.el b/emacs/elpa/consult-20240818.1112/consult-flymake.el diff --git a/emacs/elpa/consult-20240811.1858/consult-flymake.elc b/emacs/elpa/consult-20240818.1112/consult-flymake.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-imenu.el b/emacs/elpa/consult-20240818.1112/consult-imenu.el diff --git a/emacs/elpa/consult-20240811.1858/consult-imenu.elc b/emacs/elpa/consult-20240818.1112/consult-imenu.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-info.el b/emacs/elpa/consult-20240818.1112/consult-info.el diff --git a/emacs/elpa/consult-20240811.1858/consult-info.elc b/emacs/elpa/consult-20240818.1112/consult-info.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-kmacro.el b/emacs/elpa/consult-20240818.1112/consult-kmacro.el diff --git a/emacs/elpa/consult-20240811.1858/consult-kmacro.elc b/emacs/elpa/consult-20240818.1112/consult-kmacro.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-org.el b/emacs/elpa/consult-20240818.1112/consult-org.el diff --git a/emacs/elpa/consult-20240811.1858/consult-org.elc b/emacs/elpa/consult-20240818.1112/consult-org.elc Binary files differ. diff --git a/emacs/elpa/consult-20240818.1112/consult-pkg.el b/emacs/elpa/consult-20240818.1112/consult-pkg.el @@ -0,0 +1,13 @@ +(define-package "consult" "20240818.1112" "Consulting completing-read" + '((emacs "27.1") + (compat "30")) + :commit "d403b8bd1b49922de5a8060e79f647db7988ace6" :maintainers + '(("Daniel Mendler" . "mail@daniel-mendler.de")) + :maintainer + '("Daniel Mendler" . "mail@daniel-mendler.de") + :keywords + '("matching" "files" "completion") + :url "https://github.com/minad/consult") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/consult-20240811.1858/consult-register.el b/emacs/elpa/consult-20240818.1112/consult-register.el diff --git a/emacs/elpa/consult-20240811.1858/consult-register.elc b/emacs/elpa/consult-20240818.1112/consult-register.elc Binary files differ. diff --git a/emacs/elpa/consult-20240811.1858/consult-xref.el b/emacs/elpa/consult-20240818.1112/consult-xref.el diff --git a/emacs/elpa/consult-20240811.1858/consult-xref.elc b/emacs/elpa/consult-20240818.1112/consult-xref.elc Binary files differ. diff --git a/emacs/elpa/consult-20240818.1112/consult.el b/emacs/elpa/consult-20240818.1112/consult.el @@ -0,0 +1,5273 @@ +;;; consult.el --- Consulting completing-read -*- lexical-binding: t -*- + +;; Copyright (C) 2021-2024 Free Software Foundation, Inc. + +;; Author: Daniel Mendler and Consult contributors +;; Maintainer: Daniel Mendler <mail@daniel-mendler.de> +;; Created: 2020 +;; Version: 1.8 +;; Package-Requires: ((emacs "27.1") (compat "30")) +;; Homepage: https://github.com/minad/consult +;; Keywords: matching, files, completion + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Consult implements a set of `consult-<thing>' 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 '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 key (const :tag "None" 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 key (const :tag "None" nil))) + +(defcustom consult-project-function + #'consult--default-project-function + "Function which returns project root directory. +The function takes one boolean argument MAY-PROMPT. If +MAY-PROMPT is non-nil, the function may ask the prompt the user +for a project directory. The root directory is used by +`consult-buffer' and `consult-grep'." + :type `(choice + (const :tag "Default project function" ,#'consult--default-project-function) + (function :tag "Custom function") + (const :tag "No project integration" 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 :tag "Delay in seconds")) + +(defcustom consult-async-input-throttle 0.5 + "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 :tag "Delay in seconds")) + +(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 :tag "Delay in seconds")) + +(defcustom consult-async-min-input 3 + "Minimum number of characters needed, before asynchronous process is called. + +This applies to asynchronous commands, e.g., `consult-grep'." + :type '(natnum :tag "Number of characters")) + +(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 (list #'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 '(natnum :tag "Buffer size in bytes")) + +(defcustom consult-buffer-filter + '("\\` " + "\\`\\*Completions\\*\\'" + "\\`\\*Flymake log\\*\\'" + "\\`\\*Semantic SymRef\\*\\'" + "\\`\\*vc\\*\\'" + "\\`newsrc-dribble\\'" ;; Gnus + "\\`\\*tramp/.*\\*\\'") + "Filter regexps for `consult-buffer'. + +The default setting is to filter ephemeral buffer names beginning +with a space character, the *Completions* buffer and a few log +buffers. The regular expressions are matched case sensitively." + :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-hidden + consult--source-project-recent-file-hidden) + "Sources used by `consult-buffer'. +See also `consult-project-buffer-sources'. +See `consult--multi' for a description of the source data structure." + :type '(repeat symbol)) + +(defcustom consult-project-buffer-sources + '(consult--source-project-buffer + consult--source-project-recent-file) + "Sources used by `consult-project-buffer'. +See also `consult-buffer-sources'. +See `consult--multi' for a description of the source data structure." + :type '(repeat symbol)) + +(defcustom consult-mode-command-filter + '(;; Filter commands + "-mode\\'" "--" + ;; Filter whole features + simple mwheel time so-long recentf tab-bar tab-line) + "Filter commands for `consult-mode-command'." + :type '(repeat (choice symbol regexp))) + +(defcustom consult-grep-max-columns 300 + "Maximal number of columns of grep output." + :type 'natnum) + +(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\ + --with-filename --line-number -I -r") + "Command line arguments for grep, see `consult-grep'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string sexp)))) + +(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 sexp)))) + +(defcustom consult-ripgrep-args + "rg --null --line-buffered --color=never --max-columns=1000 --path-separator /\ + --smart-case --no-heading --with-filename --line-number --search-zip" + "Command line arguments for ripgrep, see `consult-ripgrep'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string sexp)))) + +(defcustom consult-find-args + "find . -not ( -path */.[A-Za-z]* -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 sexp)))) + +(defcustom consult-fd-args + '((if (executable-find "fdfind" 'remote) "fdfind" "fd") + "--full-path --color=never") + "Command line arguments for fd, see `consult-fd'. +The dynamically computed arguments are appended. +Can be either a string, or a list of strings or expressions." + :type '(choice string (repeat (choice string sexp)))) + +(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 sexp)))) + +(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 sexp)))) + +(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) + (key :tag "Key") + (repeat :tag "List of keys" key))) + +(defcustom consult-preview-partial-size 1048576 + "Files larger than this byte limit are previewed partially." + :type '(natnum :tag "File size in bytes")) + +(defcustom consult-preview-partial-chunk 102400 + "Partial preview chunk size in bytes. +If a file is larger than `consult-preview-partial-size' only the +chunk from the beginning of the file is previewed." + :type '(natnum :tag "Chunk size in bytes")) + +(defcustom consult-preview-max-count 10 + "Number of file buffers to keep open temporarily during preview." + :type '(natnum :tag "Number of buffers")) + +(defcustom consult-preview-excluded-buffers nil + "Buffers excluded from preview. +The value should conform to the predicate format demanded by the +function `buffer-match-p'." + :type 'sexp) + +(defcustom consult-preview-excluded-files + '("\\`/[^/|:]+:") ;; Do not preview remote files + "List of regexps matched against names of files, which are not previewed." + :type '(repeat regexp)) + +(defcustom consult-preview-allowed-hooks + '(global-font-lock-mode + save-place-find-file-hook) + "List of hooks, which should be executed during file preview. +This variable applies to `find-file-hook', `change-major-mode-hook' and +mode hooks, e.g., `prog-mode-hook'." + :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 Info-bookmark-jump + Man-bookmark-jump woman-bookmark-jump) + (?p "Picture" image-bookmark-jump) + (?d "Docview" doc-view-bookmark-jump) + (?m "Mail" gnus-summary-bookmark-jump) + (?s "Eshell" eshell-bookmark-jump) + (?w "Web" eww-bookmark-jump xwidget-webkit-bookmark-jump-handler) + (?v "VC Directory" vc-dir-bookmark-jump) + (nil "Other")) + "Bookmark narrowing configuration. + +Each element of the list must have the form (char name handlers...)." + :type '(alist :key-type character :value-type (cons string (repeat 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 by `consult-grep'.") + +(defface consult-highlight-mark + '((t :inherit consult-highlight-match)) + "Face used for mark positions in completion candidates. +Used for example by `consult-mark'. The face should be different +than the `cursor' face to avoid confusion.") + +(defface consult-preview-match + '((t :inherit isearch)) + "Face used for match previews, e.g., in `consult-line'.") + +(defface consult-preview-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'.") + +;;;; Input history variables + +(defvar consult--path-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 `consult--jump-preview' does not properly + ;; clean up. See gh:minad/consult#593. This issue should better be fixed in + ;; `consult--jump-preview'. + `((,#'consult-buffer-other-frame :preview-key nil) + (,#'consult-buffer-other-tab :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.") + +(defvar consult--annotate-align-step 10 + "Round candidate width.") + +(defvar consult--annotate-align-width 0 + "Maximum candidate width used for annotation alignment.") + +(defconst consult--tofu-char #x200000 + "Special character used to encode line prefixes for disambiguation. +We use invalid characters outside the Unicode range.") + +(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--key-parse (key) + "Parse KEY or signal error if invalid." + (unless (key-valid-p key) + (error "%S is not a valid key definition; see `key-valid-p'" key)) + (key-parse key)) + +(defun consult--in-buffer (fun &optional buffer) + "Ensure that FUN is executed inside BUFFER." + (unless buffer (setq buffer (current-buffer))) + (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) + (let ((result (funcall table str pred action))) + (pcase action + ('metadata + (setq result + (mapcar + (lambda (x) + (if (and (string-suffix-p "-function" (symbol-name (car-safe x))) (cdr x)) + (cons (car x) (consult--in-buffer (cdr x))) + x)) + result))) + ((and 'completion--unquote (guard (functionp (cadr result)))) + (cl-callf consult--in-buffer (cadr result) buffer) + (cl-callf consult--in-buffer (cadddr result) buffer))) + result)) + buffer) + table)) + +(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." + (seq-mapcat (lambda (x) + (if (stringp x) + (split-string-and-unquote x) + (ensure-list (eval x 'lexical)))) + (ensure-list arg))) + +(defun consult--command-split (str) + "Return command argument and options list given input STR." + (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)) + (cl-with-gensyms (head prev 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 (gensym "hook")) + (append)) + (when (eq (car-safe fun) :append) + (setq append '(t) fun (cadr fun))) + `(let ((,hook (make-symbol "consult--minibuffer-setup-hook"))) + (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)) + (cl-with-gensyms (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 hash table 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 (gensym "buffer")) + (local (mapcar (lambda (x) (cons (gensym "local") (car x))) binds))) + `(let ((,buffer (current-buffer)) + ,@(mapcar (lambda (x) `(,(car x) (local-variable-p ',(cdr x)))) local)) + (unwind-protect + (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))))))) + +(defvar consult--fast-abbreviate-file-name nil) +(defun consult--fast-abbreviate-file-name (name) + "Return abbreviate file NAME. +This function is a pure variant of `abbreviate-file-name', which +does not access the file system. This is important if we require +that the operation is fast, even for remote paths or paths on +network file systems." + (save-match-data + (let (case-fold-search) ;; Assume that file system is case sensitive. + (setq name (directory-abbrev-apply name)) + (if (string-match (with-memoization consult--fast-abbreviate-file-name + (directory-abbrev-make-regexp (expand-file-name "~"))) + name) + (concat "~" (substring name (match-beginning 1))) + name)))) + +(defun consult--left-truncate-file (file) + "Return abbreviated file name of FILE for use in `completing-read' prompt." + (save-match-data + (let ((afile (abbreviate-file-name file))) + (if (string-match "/\\([^/]+\\)/\\([^/]+/?\\)\\'" afile) + (propertize (format "…/%s/%s" (match-string 1 afile) (match-string 2 afile)) + 'help-echo afile) + afile)))) + +(defun consult--directory-prompt (prompt dir) + "Return prompt, paths and default directory. + +PROMPT is the prompt prefix. The directory is appended to the +prompt prefix. For projects only the project name is shown. The +`default-directory' is not shown. Other directories are +abbreviated and only the last two path components are shown. + +If DIR is a string, it is returned as default directory. If DIR +is a list of strings, the list is returned as search paths. If +DIR is nil the `consult-project-function' is tried to retrieve +the default directory. If no project is found the +`default-directory' is returned as is. Otherwise the user is +asked for the directories or files to search via +`completing-read-multiple'." + (let* ((paths nil) + (dir + (pcase dir + ((pred stringp) dir) + ((or 'nil '(16)) (or (consult--project-root dir) default-directory)) + (_ + (pcase (if (stringp (car-safe dir)) + dir + ;; Preserve this-command across `completing-read-multiple' call, + ;; such that `consult-customize' continues to work. + (let ((this-command this-command) + (def (abbreviate-file-name default-directory)) + ;; TODO: `minibuffer-completing-file-name' is + ;; mostly deprecated, but still in use. Packages + ;; should instead use the completion metadata. + (minibuffer-completing-file-name t) + (ignore-case read-file-name-completion-ignore-case)) + (consult--minibuffer-with-setup-hook + (lambda () + (setq-local completion-ignore-case ignore-case) + (set-syntax-table minibuffer-local-filename-syntax)) + (mapcar #'substitute-in-file-name + (completing-read-multiple "Directories or files: " + #'read-file-name-internal + nil t def 'consult--path-history def))))) + ((and `(,p) (guard (file-directory-p p))) p) + (ps (setq paths (mapcar (lambda (p) + (file-relative-name (expand-file-name p))) + ps)) + default-directory))))) + (edir (file-name-as-directory (expand-file-name dir))) + (pdir (let ((default-directory edir)) + ;; Bind default-directory in order to find the project + (consult--project-root)))) + (list + (format "%s (%s): " prompt + (pcase paths + (`(,p) (consult--left-truncate-file p)) + (`(,p . ,_) + (format "%d paths, %s, …" (length paths) (consult--left-truncate-file p))) + ((guard (equal edir pdir)) (concat "Project " (consult--project-name pdir))) + (_ (consult--left-truncate-file edir)))) + (or paths '(".")) + edir))) + +(defun consult--default-project-function (may-prompt) + "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) + (propertize (match-string 1 dir) 'help-echo (abbreviate-file-name dir)) + dir)) + +(defun consult--format-file-line-match (file line match) + "Format string FILE:LINE:MATCH with faces." + (setq line (number-to-string line) + match (concat file ":" line ":" 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) + +(defun consult--make-overlay (beg end &rest props) + "Make consult overlay between BEG and END with PROPS." + (let ((ov (make-overlay beg end))) + (while props + (overlay-put ov (car props) (cadr props)) + (setq props (cddr props))) + 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--original-window () + "Return window which was just selected just before the minibuffer was entered. +In contrast to `minibuffer-selected-window' never return nil and +always return an appropriate non-minibuffer window." + (or (minibuffer-selected-window) + (if (window-minibuffer-p (selected-window)) + (next-window) + (selected-window)))) + +(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." + (cl-with-gensyms (overwrite) + `(let* ((,overwrite (> consult--gc-threshold gc-cons-threshold)) + (gc-cons-threshold (if ,overwrite consult--gc-threshold gc-cons-threshold)) + (gc-cons-percentage (if ,overwrite consult--gc-percentage gc-cons-percentage))) + ,@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)) + `(let (set-message-function) ;; bug#63253: Broken `with-delayed-message' + (with-delayed-message (1 ,message) + (consult--with-increased-gc + ,@body)))) + +(defun consult--count-lines (pos) + "Move to position POS and return number of lines." + (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-excursion + (without-restriction + (goto-char (point-min)) + ;; Location data might be invalid by now! + (ignore-errors + (forward-line (1- line)) + (goto-char (min (+ (point) column) (pos-eol)))) + (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--line-with-mark (marker) + "Current line string where the MARKER position is highlighted." + (let* ((beg (pos-bol)) + (end (pos-eol)) + (str (consult--buffer-substring beg end 'fontify))) + (if (>= marker end) + (concat str #(" " 0 1 (face consult-highlight-mark))) + (put-text-property (- marker beg) (- (1+ marker) beg) + 'face 'consult-highlight-mark str) + str))) + +;;;; Tofu cooks + +(defsubst consult--tofu-p (char) + "Return non-nil if CHAR is a tofu." + (<= consult--tofu-char char (+ consult--tofu-char consult--tofu-range -1))) + +(defun consult--tofu-hide (str) + "Hide the tofus in STR." + (let* ((max (length str)) + (end max)) + (while (and (> end 0) (consult--tofu-p (aref str (1- end)))) + (cl-decf end)) + (when (< end max) + (setq str (copy-sequence str)) + (put-text-property end max 'invisible t str)) + str)) + +(defsubst consult--tofu-append (cand id) + "Append tofu-encoded ID to CAND. +The ID must fit within a single character. It must be smaller +than `consult--tofu-range'." + (setq id (char-to-string (+ consult--tofu-char id))) + (add-text-properties 0 1 '(invisible t consult-strip t) id) + (concat cand id)) + +(defsubst consult--tofu-get (cand) + "Extract tofu-encoded ID from CAND. +See `consult--tofu-append'." + (- (aref cand (1- (length cand))) consult--tofu-char)) + +;; We must disambiguate the lines by adding a prefix such that two lines with +;; the same text can be distinguished. In order to avoid matching the line +;; number, such that the user can search for numbers with `consult-line', we +;; encode the line number as characters outside the Unicode range. By doing +;; that, no accidental matching can occur. +(defun consult--tofu-encode (n) + "Return tofu-encoded number N as a string. +Large numbers are encoded as multiple tofu characters." + (let (str tofu) + (while (progn + (setq tofu (char-to-string + (+ consult--tofu-char (% n consult--tofu-range))) + str (if str (concat tofu str) tofu)) + (and (>= n consult--tofu-range) + (setq n (/ n consult--tofu-range))))) + (add-text-properties 0 (length str) '(invisible t consult-strip t) str) + str)) + +;;;; Regexp utilities + +(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 look-ahead wrapper only if there is more than one regular expression + (cond + ((and (eq type 'pcre) (cdr regexps)) + (concat "^" (mapconcat (lambda (x) (format "(?=.*%s)" x)) + 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--join-regexps-permutations regexps (and (eq type 'emacs) "\\"))))) + +(defun consult--join-regexps-permutations (regexps esc) + "Join all permutations of REGEXPS. +ESC is the escaping string for choice and groups." + (pcase regexps + ('nil "") + (`(,r) r) + (_ (mapconcat + (lambda (r) + (concat esc "(" r esc ").*" esc "(" + (consult--join-regexps-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--preview-allowed-p (fun) + "Return non-nil if FUN is an allowed preview mode hook." + (or (memq fun consult-preview-allowed-hooks) + (when-let (((symbolp fun)) + (name (symbol-name fun)) + ;; Global modes in Emacs 29 are activated via a + ;; `find-file-hook' ending with `-check-buffers'. This has been + ;; changed in Emacs 30. Now a `change-major-mode-hook' is used + ;; instead with the suffix `-check-buffers'. + (suffix (static-if (>= emacs-major-version 30) + "-enable-in-buffer" + "-check-buffers")) + ((string-suffix-p suffix name))) + (memq (intern (string-remove-suffix suffix name)) + consult-preview-allowed-hooks)))) + +(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 #'consult--preview-allowed-p + (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))) + (let* ((partial (>= size consult-preview-partial-size)) + (buffer (if partial + (generate-new-buffer (format "consult-partial-preview-%s" name)) + (find-file-noselect name 'nowarn))) + (success nil)) + (unwind-protect + (with-current-buffer buffer + (if (not partial) + (when (or (eq major-mode 'hexl-mode) + (and (eq major-mode 'fundamental-mode) + (save-excursion (search-forward "\0" nil 'noerror)))) + (error "No preview of binary file `%s'" + (file-name-nondirectory name))) + (with-silent-modifications + (setq buffer-read-only t) + (insert-file-contents name nil 0 consult-preview-partial-chunk) + (goto-char (point-max)) + (insert "\nFile truncated. End of partial preview.\n") + (goto-char (point-min))) + (when (save-excursion (search-forward "\0" nil 'noerror)) + (error "No partial preview of binary file `%s'" + (file-name-nondirectory name))) + ;; Auto detect major mode and hope for the best, given that the + ;; file is only previewed partially. If an error is thrown the + ;; buffer will be killed and preview is aborted. + (set-auto-mode) + (font-lock-mode 1)) + (when (bound-and-true-p so-long-detected-p) + (error "No preview of file `%s' with long lines" + (file-name-nondirectory name))) + ;; Run delayed hooks listed in `consult-preview-allowed-hooks'. + (dolist (hook (reverse (cons 'after-change-major-mode-hook delayed-mode-hooks))) + (run-hook-wrapped hook (lambda (fun) + (when (consult--preview-allowed-p fun) + (funcall fun)) + nil))) + (setq success (current-buffer))) + (unless success + (kill-buffer buffer)))))) + +(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)))) + (condition-case err + (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)) + (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))) + (error + (message "%s" (error-message-string err)) + nil)))) + +(defun consult--temporary-files () + "Return a function to open files temporarily for preview." + (let ((dir default-directory) + (hook (make-symbol "consult--temporary-files-upgrade-hook")) + (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 (consult--file-action 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-hook"))) + (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))))) + +(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 + (let ((inhibit-redisplay t)) ;; HACK: Prevent flicker due to premature redisplay + (org-fold-show-set-visibility 'canonical)) + (dolist (ov (overlays-in (pos-bol) (pos-eol))) + (when-let (fun (overlay-get ov 'isearch-open-invisible)) + (when (invisible-p (overlay-get ov 'invisible)) + (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) + (fboundp 'org-fold-core-get-regions) + (fboundp 'org-fold-core-region)) + ;; 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-hook")) + (buffer (current-buffer)) + (depth (recursion-depth))) + (fset hook + (lambda () + (when (= (recursion-depth) depth) + (remove-hook 'minibuffer-exit-hook hook) + (run-at-time + 0 nil + (lambda () + (when (buffer-live-p buffer) + (with-current-buffer buffer + (pcase-dolist (`(,beg ,end ,_) consult--org-fold-regions) + (when (markerp beg) (set-marker beg nil)) + (when (markerp end) (set-marker end nil))) + (kill-local-variable 'consult--org-fold-regions)))))))) + (add-hook 'minibuffer-exit-hook hook)))) + (let ((inhibit-redisplay t)) ;; HACK: Prevent flicker due to premature redisplay + (org-fold-show-set-visibility 'canonical)) + (list (lambda () + (pcase-dolist (`(,beg ,end ,spec) consult--org-fold-regions) + (org-fold-core-region beg end t spec))))) + (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-ensure-buffer (pos) + "Ensure that buffer of marker POS is displayed, return t if successful." + (or (not (markerp pos)) + ;; Switch to buffer if it is not visible + (when-let ((buf (marker-buffer pos))) + (or (and (eq (current-buffer) buf) (eq (window-buffer) buf)) + (consult--buffer-action buf 'norecord) + t)))) + +(defun consult--jump (pos) + "Jump to POS. +First push current position to mark ring, then move to new +position and run `consult-after-jump-hook'." + (when pos + ;; Extract marker from list with with overlay positions, see `consult--line-match' + (when (consp pos) (setq pos (car pos))) + ;; 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)) + (when (consult--jump-ensure-buffer pos) + (unless (= (goto-char pos) (point)) ;; Widen if jump failed + (widen) + (goto-char 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 (restore) + (lambda (action cand) + (when (eq action 'preview) + (mapc #'funcall restore) + (setq restore nil) + ;; TODO Better buffer preview support + ;; 1. Use consult--buffer-preview instead of consult--jump-ensure-buffer + ;; 2. Remove function consult--jump-ensure-buffer + ;; 3. Remove consult-buffer-other-* from consult-customize-alist + (when-let ((pos (or (car-safe cand) cand)) ;; Candidate can be previewed + ((consult--jump-ensure-buffer pos))) + (let ((saved-min (point-min-marker)) + (saved-max (point-max-marker)) + (saved-pos (point-marker))) + (set-marker-insertion-type saved-max t) ;; Grow when text is inserted + (push (lambda () + (when-let ((buf (marker-buffer saved-pos))) + (with-current-buffer buf + (narrow-to-region saved-min saved-max) + (goto-char saved-pos) + (set-marker saved-pos nil) + (set-marker saved-min nil) + (set-marker saved-max nil)))) + restore)) + (unless (= (goto-char pos) (point)) ;; Widen if jump failed + (widen) + (goto-char pos)) + (setq restore (nconc (consult--invisible-open-temporarily) restore)) + ;; Ensure that cursor is properly previewed (gh:minad/consult#764) + (unless (eq cursor-in-non-selected-windows 'box) + (let ((orig cursor-in-non-selected-windows) + (buf (current-buffer))) + (push + (if (local-variable-p 'cursor-in-non-selected-windows) + (lambda () + (when (buffer-live-p buf) + (with-current-buffer buf + (setq-local cursor-in-non-selected-windows orig)))) + (lambda () + (when (buffer-live-p buf) + (with-current-buffer buf + (kill-local-variable 'cursor-in-non-selected-windows))))) + restore) + (setq-local cursor-in-non-selected-windows 'box))) + ;; Match previews + (let ((overlays + (list (save-excursion + (let ((vbeg (progn (beginning-of-visual-line) (point))) + (vend (progn (end-of-visual-line) (point))) + (end (pos-eol))) + (consult--make-overlay vbeg (if (= vend end) (1+ end) vend) + 'face 'consult-preview-line + 'window (selected-window) + 'priority 1)))))) + (dolist (match (cdr-safe cand)) + (push (consult--make-overlay (+ (point) (car match)) + (+ (point) (cdr match)) + 'face 'consult-preview-match + 'window (selected-window) + 'priority 2) + overlays)) + (push (lambda () (mapc #'delete-overlay overlays)) restore)) + (run-hooks 'consult-after-jump-hook)))))) + +(defun consult--jump-state () + "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-hook"))) + (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) + (setq key (consult--key-parse 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--preview-append-local-pch (fun) + "Append FUN to local `post-command-hook' list." + ;; Symbol indirection because of bug#46407. + (let ((hook (make-symbol "consult--preview-post-command-hook"))) + (fset hook fun) + ;; TODO Emacs 28 has a bug, where the hook--depth-alist is not cleaned up properly + ;; Do not use the broken add-hook here. + ;;(add-hook 'post-command-hook hook '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 save-input fun) + "Add preview support for FUN. +See `consult--with-preview' for the arguments +PREVIEW-KEY, STATE, TRANSFORM, CANDIDATE and SAVE-INPUT." + (let ((mb-input "") mb-narrow selected timer previewed) + (consult--minibuffer-with-setup-hook + (if (and state preview-key) + (lambda () + (let ((hook (make-symbol "consult--preview-minibuffer-exit-hook")) + (depth (recursion-depth))) + (fset hook + (lambda () + (when (= (recursion-depth) depth) + (remove-hook 'minibuffer-exit-hook hook) + (when timer + (cancel-timer timer) + (setq timer nil)) + (with-selected-window (consult--original-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 hook)) + ;; STEP 1: Setup the preview function + (with-selected-window (consult--original-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) + (win (consult--original-window))) + (with-selected-window win + (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. + ;; + ;; In older Consult versions we instead compared + ;; the input without properties, since I worried + ;; that comparing the transformed candidates + ;; could be potentially expensive. However + ;; comparing the transformed candidates is more + ;; correct. The transformed candidate is the + ;; thing which is actually previewed. + (unless (equal-including-properties previewed transformed) + (if (> debounce 0) + (setq timer + (run-at-time + debounce nil + (lambda () + ;; Preview only when a completion + ;; window is selected and when + ;; the preview window is alive. + (when (and (consult--completion-window-p) + (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--preview-append-local-pch + (lambda () + (setq mb-input (minibuffer-contents-no-properties) + mb-narrow consult--narrow) + (funcall consult--preview-function)))) + (lambda () + (consult--preview-append-local-pch + (lambda () + (setq mb-input (minibuffer-contents-no-properties) + mb-narrow consult--narrow))))) + (unwind-protect + (setq selected (when-let (result (funcall fun)) + (when-let ((save-input) + (list (symbol-value save-input)) + ((equal (car list) result))) + (set save-input (cdr list))) + (funcall transform mb-narrow mb-input result))) + (when save-input + (add-to-history save-input 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 save-input &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. +SAVE-INPUT can be a history variable symbol to save the input. + +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 `consult--original-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 5)) + `(consult--with-preview-1 ,preview-key ,state ,transform ,candidate ,save-input (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 + (consult--key-parse consult-widen-key)) + (consult-narrow-key + (let ((key (consult--key-parse consult-narrow-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--make-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 ?\s 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)) + (setq key (consult--key-parse 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))) + (when-let ((init (and (memq :keys settings) (plist-get settings :initial)))) + (consult-narrow init))) + +;; 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 + +(defun consult--async-p (fun) + "Return t if FUN is an asynchronous completion function." + (and (functionp fun) + (condition-case nil + (progn (funcall fun "" nil 'metadata) nil) + (wrong-number-of-arguments t)))) + +(defmacro consult--with-async (bind &rest body) + "Setup asynchronous completion in BODY. + +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 (consult--async-p ,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. + (hook (make-symbol "consult--async-after-change-hook"))) + ;; Delay modification hook to ensure that minibuffer is still + ;; alive after the change, such that we don't restart a new + ;; asynchronous search right before exiting the minibuffer. + (fset hook (lambda (&rest _) (run-at-time 0 nil fun))) + (add-hook 'after-change-functions hook nil 'local) + (funcall hook))))) + (let ((,async (if (consult--async-p ,async) ,async (lambda (_) ,async)))) + (unwind-protect + ,(macroexp-progn body) + (funcall ,async 'destroy) + (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 functions 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)) + (end (minibuffer-prompt-end))) + ;; Highlight punctuation characters + (remove-list-of-text-properties end (+ end input-len) '(face)) + (dolist (hl highlights) + (put-text-property (+ end (car hl)) (+ end (cdr hl)) + 'face 'consult-async-split)) + (funcall async + ;; Pass through if the input is long enough! + (if (or force (>= async-len consult-async-min-input)) + 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* ((args (funcall builder action))) + (unless (stringp (car args)) + (setq args (car args))) + (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 + (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) + (when (> (buffer-size proc-buf) 0) + (with-current-buffer (get-buffer-create consult--async-log) + (goto-char (point-max)) + (insert ">>>>> stderr >>>>>\n") + (let ((beg (point))) + (insert-buffer-substring proc-buf) + (save-excursion + (goto-char beg) + (message #("%s" 0 2 (face error)) + (buffer-substring-no-properties (pos-bol) (pos-eol))))) + (insert "<<<<< stderr <<<<<\n"))))) + (process-adaptive-read-buffering nil)) + (funcall async 'indicator 'running) + (consult--async-log "consult--async-process started: args=%S default-directory=%S\n" + args default-directory) + (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 a new ASYNC function with candidate highlighting. +BUILDER is the command line builder function." + (let (highlight) + (lambda (action) + (cond + ((stringp action) + (setq highlight (cdr (funcall builder action))) + (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 "") (timer (timer-create)) (last 0)) + (lambda (action) + (pcase action + ((pred stringp) + (unless (equal action input) + (cancel-timer timer) + (funcall async "") ;; cancel running process + (setq input action) + (unless (equal action "") + (timer-set-function timer (lambda () + (setq last (float-time)) + (funcall async action))) + (timer-set-time + timer + (timer-relative-time + nil (max debounce (- (+ last throttle) (float-time))))) + (timer-activate timer))) + nil) + ('destroy + (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 ((delay (or delay consult-async-refresh-delay)) + (timer (timer-create))) + (timer-set-function timer async '(refresh)) + (lambda (action) + (prog1 (funcall async action) + (pcase action + ((or (pred consp) 'flush) + (unless (memq timer timer-list) + (timer-set-time timer (timer-relative-time nil delay)) + (timer-activate timer))) + ('destroy + (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." + (cl-with-gensyms (async-var action-var) + `(let ((,async-var ,async)) + (lambda (,action-var) + (funcall ,async-var (if (consp ,action-var) (,@transform ,action-var) ,action-var)))))) + +(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. + "<remap> <minibuffer-complete-word>" #'self-insert-command + ;; Remap Emacs 29 history and default completion for now + ;; (gh:minad/consult#613). + "<remap> <minibuffer-complete-defaults>" #'ignore + "<remap> <minibuffer-complete-history>" #'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--annotate-align (cand ann) + "Align annotation ANN by computing the maximum CAND width." + (setq consult--annotate-align-width + (max consult--annotate-align-width + (* (ceiling (consult--display-width cand) + consult--annotate-align-step) + consult--annotate-align-step))) + (when ann + (concat + #(" " 0 1 (display (space :align-to (+ left consult--annotate-align-width)))) + ann))) + +(defun consult--add-history (async items) + "Add ITEMS to the minibuffer future history. +ASYNC must be non-nil for async completion functions." + (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)))) + +(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))))) + +(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 (table &key + prompt predicate require-match history default + keymap category initial narrow add-history annotate + state preview-key sort lookup group inherit-input-method) + "See `consult--read' for the documentation of the arguments." + (consult--minibuffer-with-setup-hook + (:append (lambda () + (add-hook 'after-change-functions #'consult--tofu-hide-in-minibuffer nil 'local) + (consult--setup-keymap keymap (consult--async-p table) narrow preview-key) + (setq-local minibuffer-default-add-function + (apply-partially #'consult--add-history (consult--async-p table) add-history)))) + (consult--with-async (async table) + (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) + (pcase-exhaustive history + (`(:input ,var) var) + ((pred symbolp))) + ;; Do not unnecessarily let-bind the lambdas to avoid over-capturing in + ;; the interpreter. This will make closures and the lambda string + ;; representation larger, which makes debugging much worse. Fortunately + ;; the over-capturing problem does not affect the bytecode interpreter + ;; which does a proper scope analysis. + (let* ((metadata `(metadata + ,@(when category `((category . ,category))) + ,@(when group `((group-function . ,group))) + ,@(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))))) + (consult--annotate-align-width 0) + (selected + (completing-read + prompt + (lambda (str pred action) + (let ((result (complete-with-action action (funcall async nil) str pred))) + (if (eq action 'metadata) + (if (and (eq (car result) 'metadata) (cdr result)) + ;; Merge metadata + `(metadata ,@(cdr metadata) ,@(cdr result)) + metadata) + result))) + predicate require-match initial + (if (symbolp history) history (cadr history)) + default + inherit-input-method))) + ;; Repair the null completion semantics. `completing-read' may return + ;; an empty string even if REQUIRE-MATCH is non-nil. One can always + ;; opt-in to null completion by passing the empty string for DEFAULT. + (when (and (eq require-match t) (not default) (equal selected "")) + (user-error "No selection")) + selected))))) + +(cl-defun consult--read (table &rest options &key + prompt predicate require-match history default + keymap category initial narrow add-history annotate + state preview-key sort lookup group inherit-input-method) + "Enhanced completing read function to select from TABLE. + +The function is a thin wrapper around `completing-read'. Keyword +arguments are used instead of positional arguments for code +clarity. On top of `completing-read' it additionally supports +computing the candidate list asynchronously, candidate preview +and narrowing. You should use `completing-read' instead of +`consult--read' if you don't use asynchronous candidate +computation or candidate preview. + +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 table) ;; dynamic table or asynchronous function + (obarrayp table) ;; obarray + (hash-table-p table) ;; hash table + (not table) ;; empty list + (stringp (car table)) ;; string list + (and (consp (car table)) (stringp (caar table))) ;; string alist + (and (consp (car table)) (symbolp (caar table))))) ;; symbol alist + (ignore prompt predicate require-match history default + keymap category initial narrow add-history annotate + state preview-key sort lookup group inherit-input-method) + (apply #'consult--read-1 table + (append + (consult--customize-get) + options + (list :prompt "Select: " + :preview-key consult-preview-key + :sort t + :lookup (lambda (selected &rest _) selected))))) + +;;;; Internal API: consult--prompt + +(cl-defun consult--prompt-1 (&key prompt history add-history initial default + keymap state preview-key transform inherit-input-method) + "See `consult--prompt' for documentation." + (consult--minibuffer-with-setup-hook + (:append (lambda () + (consult--setup-keymap keymap nil nil preview-key) + (setq-local minibuffer-default-add-function + (apply-partially #'consult--add-history nil add-history)))) + (consult--with-preview + preview-key state + (lambda (_narrow inp _cand) (funcall transform inp)) + (lambda () "") + history + (read-from-minibuffer prompt initial nil nil history default inherit-input-method)))) + +(cl-defun consult--prompt (&rest options &key prompt history add-history initial default + keymap state preview-key transform inherit-input-method) + "Read from minibuffer. + +Keyword OPTIONS: + +PROMPT is the string to prompt with. +TRANSFORM is a function which is applied to the current input string. +HISTORY is the symbol of the history variable. +INITIAL is initial input. +DEFAULT is the default selected value. +ADD-HISTORY is a list of items to add to the history. +STATE is the state function, see `consult--with-preview'. +PREVIEW-KEY are the preview keys (nil, `any', a single key or a list of keys). +KEYMAP is a command-specific keymap." + (ignore prompt history add-history initial default + keymap state preview-key transform inherit-input-method) + (apply #'consult--prompt-1 + (append + (consult--customize-get) + options + (list :prompt "Input: " + :preview-key consult-preview-key + :transform #'identity)))) + +;;;; Internal API: consult--multi + +(defsubst consult--multi-source (sources cand) + "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 cand) + "Annotate candidate CAND from multi SOURCES." + (consult--annotate-align + cand + (let ((src (consult--multi-source sources cand))) + (if-let ((fun (plist-get src :annotate))) + (funcall fun (cdr (get-text-property 0 'multi-category cand))) + (plist-get src :name))))) + +(defun consult--multi-group (sources cand transform) + "Return title of candidate CAND or TRANSFORM the candidate given SOURCES." + (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)) + ((seq-find (lambda (src) (not (plist-get src :hidden))) 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) 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* ((str (or (car-safe item) item)) + (cand (consult--tofu-append str idx))) + ;; Preserve existing `multi-category' datum of the candidate. + (if (and (eq str item) (get-text-property 0 'multi-category str)) + (when face (add-text-properties 0 (length str) face cand)) + ;; Attach `multi-category' datum and face. + (add-text-properties + 0 (length str) + `(multi-category (,cat . ,(or (cdr-safe item) item)) ,@face) cand)) + (push cand candidates)))) + (cl-incf idx)) + (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 metadata, 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))) + (selected + (apply #'consult--read + candidates + (append + options + (list + :category 'multi-category + :predicate (apply-partially #'consult--multi-predicate sources) + :annotate (apply-partially #'consult--multi-annotate sources) + :group (apply-partially #'consult--multi-group sources) + :lookup (apply-partially #'consult--multi-lookup sources) + :preview-key (consult--multi-preview-key sources) + :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)) + +;;;; 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 () + "Get configuration from `consult--customize-alist' for `this-command'." + (mapcar (lambda (x) (eval x 'lexical)) + (alist-get 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) + ;; 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--make-overlay start end + 'invisible t + 'window (selected-window)))) + ;; Use `add-face-text-property' on a copy of "cand in order to merge face properties + (setq cand (copy-sequence cand)) + (add-face-text-property 0 (length cand) 'consult-preview-insertion t cand) + ;; 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 this function as a +value for `completion-in-region-function'." + (barf-if-buffer-read-only) + (let* ((initial (buffer-substring-no-properties start end)) + (metadata (completion-metadata initial collection predicate)) + ;; TODO: `minibuffer-completing-file-name' is mostly deprecated, but + ;; still in use. Packages should instead use the completion metadata. + (minibuffer-completing-file-name + (eq 'file (completion-metadata-get metadata 'category))) + (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 ""))) + (this-command #'consult-completion-in-region) + (completion + (cond + ((atom all) nil) + ((and (consp all) (atom (cdr all))) + (concat (substring initial 0 limit) (car all))) + (t + (consult--local-let ((enable-recursive-minibuffers t)) + ;; 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. + (consult--read (consult--completion-table-in-buffer collection) + :prompt "Completion: " + :state (consult--insertion-preview start end) + :predicate predicate + :initial 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 (&optional level) + "Jump to an outline heading, obtained by matching against `outline-regexp'. + +This command supports narrowing to a heading level and candidate +preview. The initial narrowing LEVEL can be given as prefix +argument. The symbol at point is added to the future history." + (interactive + (list (and current-prefix-arg (prefix-numeric-value current-prefix-arg)))) + (let* ((candidates (consult--slow-operation + "Collecting headings..." + (consult--outline-candidates))) + (min-level (- (cl-loop for cand in candidates minimize + (get-text-property 0 'consult--outline-level cand)) + ?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))) + (narrow-init (and level (max ?1 (min ?9 (+ level ?0)))))) + (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 :initial ,narrow-init) + :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-mark 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)) + (prefix (consult--format-file-line-match (buffer-name buf) line "")) + (cand (concat prefix (consult--line-with-mark marker) (consult--tofu-encode marker)))) + (put-text-property 0 (length prefix) 'consult-strip t cand) + (put-text-property 0 (length cand) 'consult-location (cons marker line) cand) + (push cand 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' formatting the candidates in grep-like + ;; style, we are not using the `consult-grep' category, since the candidates + ;; have location markers attached. + :category 'consult-location + :sort nil + :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))) + (buf (if (consp marker) + (car marker) ;; Handle cheap marker + (marker-buffer marker)))) + (if buf (buffer-name buf) "Dead buffer")))) + +(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) + (whitespace-orig (bound-and-true-p whitespace-mode)) + (hl-line-orig (bound-and-true-p hl-line-mode)) + (point-orig (point)) + lines content-orig replace last-input) + (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 provided + (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 whitespace-mode) (whitespace-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 whitespace-orig (whitespace-mode 1)) + (when font-lock-orig (font-lock-mode 1)))))) + +;;;###autoload +(defun consult-keep-lines (filter &optional initial) + "Select a subset of the lines in the current buffer with live preview. + +The selected lines are kept and the other lines are deleted. When called +interactively, the lines selected are those that match the minibuffer input. In +order to match the inverse of the input, prefix the input with `! '. When +called from Elisp, the filtering is performed by a FILTER function. This +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--line-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 + ;; Use "\n" for empty lines, since we need a non-empty 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) + ;; 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--make-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 nil 'show) + (goto-char pt-orig)) + (t + ;; Successfully 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 (filter &optional show initial) + "Hide or show lines using overlays. + +The selected lines are shown and the other lines hidden. When called +interactively, the lines selected are those that match the minibuffer input. In +order to match the inverse of the input, prefix the input with `! '. With +optional prefix argument SHOW reveal the hidden lines. Alternatively the +command can be restarted to reveal the lines. When called from Elisp, the +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 nil)) + current-prefix-arg)) + (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--line-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." + (save-match-data + (if (and str (string-match "\\`\\([[:digit:]]+\\):?\\([[:digit:]]*\\)\\'" str)) + (let ((line (string-to-number (match-string 1 str))) + (col (string-to-number (match-string 2 str)))) + (save-excursion + (save-restriction + (when consult-line-numbers-widen + (widen)) + (goto-char (point-min)) + (forward-line (1- line)) + (goto-char (min (+ (point) col) (pos-eol))) + (point)))) + (when (and str (not (equal str ""))) + (funcall msg "Please enter a number.")) + nil))) + +;;;###autoload +(defun consult-goto-line (&optional arg) + "Read line number and jump to the line with preview. + +Enter either a line number to jump to the first column of the +given line or line:column in order to jump to a specific column. +Jump directly if a line number is given as prefix ARG. The +command respects narrowing and the settings +`consult-goto-line-numbers' and `consult-line-numbers-widen'." + (interactive "P") + (if arg + (call-interactively #'goto-line) + (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'." + ;; Try to preserve the buffer as is, if it has already been opened, for + ;; example in literal or raw mode. + (setq file (abbreviate-file-name (expand-file-name file))) + (consult--buffer-action (or (get-file-buffer file) (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 + (mapcar #'consult--fast-abbreviate-file-name (bound-and-true-p recentf-list)) + (user-error "No recent files, `recentf-mode' is %s" + (if recentf-mode "enabled" "disabled"))) + :prompt "Find recent file: " + :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* ((case-fold-search) + (buffer (current-buffer)) + (command-filter (consult--regexp-filter (seq-filter #'stringp consult-mode-command-filter))) + (feature-filter (seq-filter #'symbolp consult-mode-command-filter)) + (minor-hash (consult--string-hash minor-mode-list)) + (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 (or (bookmark-get-handler bm) #'bookmark-default-handler)) + ((eq handler #'bookmark-default-handler)) + (file (bookmark-get-filename bm)) + (pos (bookmark-get-position bm)) + (buf (funcall open file))) + (set-marker (make-marker) pos buf)))))) + +(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 (cl-loop for (y _ . xs) in consult-bookmark-narrow nconc + (cl-loop for x in xs collect (cons x y))))) + (cl-loop for bm in bookmark-alist collect + (propertize (car bm) + 'consult--type + (alist-get + (or (bookmark-get-handler bm) #'bookmark-default-handler) + narrow))))) + +;;;###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 (cl-loop for (x y . _) in consult-bookmark-narrow collect (cons x y)))) + (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)) + (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'." + "<remap> <isearch-forward>" #'consult-isearch-forward + "<remap> <isearch-backward>" #'consult-isearch-backward) + +(defun consult--isearch-history-candidates () + "Return Isearch history candidates." + ;; 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)))) + (delete-dups + (mapcar + (lambda (cand) + ;; The search type can be distinguished via text properties. + (let* ((props (plist-member (text-properties-at 0 cand) + 'isearch-regexp-function)) + (type (pcase (cadr props) + ((and 'nil (guard (not props))) ?r) + ('nil ?l) + ('word-search-regexp ?w) + ('isearch-symbol-regexp ?s) + ('char-fold-to-regexp ?c) + (_ ?u)))) + ;; Disambiguate history items. The same string could + ;; occur with different search types. + (consult--tofu-append cand type))) + history)))) + +(defconst consult--isearch-history-narrow + '((?c . "Char") + (?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) + (cursor-in-echo-area t) ;; Avoid cursor flickering + (candidates (consult--isearch-history-candidates))) + (unless isearch-mode (isearch-mode t)) + (with-isearch-suspended + (setq isearch-new-string + (consult--read + candidates + :prompt "I-search: " + :category 'consult-isearch-history + :history t ;; disable history + :sort nil + :initial isearch-string + :keymap consult-isearch-history-map + :annotate + (lambda (cand) + (consult--annotate-align + cand + (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))) + (let (message-log-max) + (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 (car (memq (current-buffer) buffers)))) + (consult--keep! buffers + (unless (eq it current) + (if (get-buffer-window it 'visible) + it + (push it hidden) + nil))) + (nconc (nreverse hidden) buffers (and current (list current))))) + +(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) + "Return a list of buffers and create an appropriate prompt string. +Return a pair of a prompt string and a list of buffers. PROMPT +is the prefix of the prompt string. QUERY specifies the buffers +to search and 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--left-truncate-file ndir))) + (t ""))) + buffers))) + +(cl-defun consult--buffer-query (&key sort directory mode as predicate (filter t) + include (exclude consult-buffer-filter) + (buffer-list t)) + "Query for a list of matching buffers. +The function supports filtering by various criteria which are +used throughout Consult. In particular it is the backbone of +most `consult-buffer-sources'. +DIRECTORY can either be the symbol project or a file name. +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. +BUFFER-LIST is the unfiltered list of buffers. +AS is a conversion function." + (let ((root (consult--normalize-directory directory))) + (setq buffer-list (if (eq buffer-list t) (buffer-list) (copy-sequence buffer-list))) + (when sort + (setq buffer-list (funcall (intern (format "consult--buffer-sort-%s" sort)) buffer-list))) + (when (or filter mode as root) + (let ((exclude-re (consult--regexp-filter exclude)) + (include-re (consult--regexp-filter include)) + (case-fold-search)) + (consult--keep! buffer-list + (and + (or (not mode) + (let ((mm (buffer-local-value 'major-mode it))) + (if (consp mode) + (seq-some (lambda (m) (provided-mode-derived-p mm m)) mode) + (provided-mode-derived-p mm 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))))) + buffer-list)) + +(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-pair (buffer) + "Return a pair of name of BUFFER and BUFFER." + (cons (buffer-name buffer) buffer)) + +(defun consult--buffer-preview () + "Buffer preview function." + (let ((orig-buf (window-buffer (consult--original-window))) + (orig-prev (copy-sequence (window-prev-buffers))) + (orig-next (copy-sequence (window-next-buffers))) + other-win) + (lambda (action cand) + (pcase action + ('exit + (set-window-prev-buffers other-win orig-prev) + (set-window-next-buffers other-win orig-next)) + ('preview + (when (and (eq consult--buffer-display #'switch-to-buffer-other-window) + (not other-win)) + (switch-to-buffer-other-window orig-buf 'norecord) + (setq other-win (selected-window))) + (let ((win (or other-win (selected-window))) + (buf (or (and cand (get-buffer cand)) orig-buf))) + (when (and (window-live-p win) (buffer-live-p buf) + (not (buffer-match-p consult-preview-excluded-buffers buf))) + (with-selected-window win + (unless (or orig-prev orig-next) + (setq orig-prev (copy-sequence (window-prev-buffers)) + orig-next (copy-sequence (window-next-buffers)))) + (switch-to-buffer buf 'norecord))))))))) + +(defun consult--buffer-action (buffer &optional norecord) + "Switch to BUFFER via `consult--buffer-display' function. +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 ?b + :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 #'consult--buffer-pair)))) + "Project buffer candidate source for `consult-buffer'.") + +(defvar consult--source-project-recent-file + `(:name "Project File" + :narrow ?f + :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)) + items) + (dolist (file (bound-and-true-p recentf-list) (nreverse items)) + ;; Emacs 29 abbreviates file paths by default, see + ;; `recentf-filename-handlers'. I recommend to set + ;; `recentf-filename-handlers' to nil to avoid any slow down. + (unless (eq (aref file 0) ?/) + (let (file-name-handler-alist) ;; No Tramp slowdown please. + (setq file (expand-file-name file)))) + (when (and (not (gethash file ht)) (string-prefix-p root file)) + (let ((part (substring file len))) + (when (equal part "") (setq part "./")) + (put-text-property 0 1 'multi-category `(file . ,file) part) + (push part items)))))))) + "Project file candidate source for `consult-buffer'.") + +(defvar consult--source-project-buffer-hidden + `(:hidden t :narrow (?p . "Project") ,@consult--source-project-buffer) + "Like `consult--source-project-buffer' but hidden by default.") + +(defvar consult--source-project-recent-file-hidden + `(:hidden t :narrow (?p . "Project") ,@consult--source-project-recent-file) + "Like `consult--source-project-recent-file' but hidden by default.") + +(defvar consult--source-hidden-buffer + `(:name "Hidden Buffer" + :narrow ?\s + :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 #'consult--buffer-pair))) + "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 #'consult--buffer-pair + :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 #'consult--buffer-pair))) + "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)) + items) + (dolist (file (bound-and-true-p recentf-list) (nreverse items)) + ;; Emacs 29 abbreviates file paths by default, see + ;; `recentf-filename-handlers'. I recommend to set + ;; `recentf-filename-handlers' to nil to avoid any slow down. + (unless (eq (aref file 0) ?/) + (let (file-name-handler-alist) ;; No Tramp slowdown please. + (setq file (expand-file-name file)))) + (unless (gethash file ht) + (push (consult--fast-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))))) + +(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 overridden at the current recursion level. When entering a + ;; recursive minibuffer session, we should be able to still switch the + ;; project. But who does that? Working on the first level on project A + ;; and on the second level on project B and on the third level on project C? + ;; 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', switching to a buffer in another window." + (interactive) + (let ((consult--buffer-display #'switch-to-buffer-other-window)) + (consult-buffer))) + +;;;###autoload +(defun consult-buffer-other-frame () + "Variant of `consult-buffer', switching to a buffer in another frame." + (interactive) + (let ((consult--buffer-display #'switch-to-buffer-other-frame)) + (consult-buffer))) + +;;;###autoload +(defun consult-buffer-other-tab () + "Variant of `consult-buffer', switching to a buffer in another tab." + (interactive) + (let ((consult--buffer-display #'switch-to-buffer-other-tab)) + (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) + (setq highlight (cdr (funcall builder action))) + (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-noselect'." + (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 #'consult--file-action) 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 make-builder dir initial) + "Run asynchronous grep. + +MAKE-BUILDER is the function that returns the command line +builder function. DIR is a directory or a list of file or +directories. PROMPT is the prompt string. INITIAL is initial +input." + (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt prompt dir)) + (default-directory dir) + (builder (funcall make-builder paths))) + (consult--read + (consult--async-command builder + (consult--grep-format builder) + :file-handler t) ;; allow tramp + :prompt prompt + :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 look-ahead." + (eq 0 (process-file-shell-command + (concat "echo xaxbx | " + (mapconcat #'shell-quote-argument `(,@cmd "^(?=.*b)(?=.*a)") " "))))) + +(defun consult--grep-make-builder (paths) + "Build grep command line and grep across PATHS." + (let* ((cmd (consult--build-args consult-grep-args)) + (type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended))) + (lambda (input) + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (flags (append cmd opts)) + (ignore-case (or (member "-i" flags) (member "--ignore-case" flags)))) + (if (or (member "-F" flags) (member "--fixed-strings" flags)) + (cons (append cmd (list "-e" arg) opts paths) + (apply-partially #'consult--highlight-regexps + (list (regexp-quote arg)) ignore-case)) + (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 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 paths) + hl)))))))) + +;;;###autoload +(defun consult-grep (&optional dir initial) + "Search with `grep' for files in DIR where the content matches a regexp. + +The initial input is given by the INITIAL argument. DIR can be nil, a +directory string or a list of file/directory paths. If `consult-grep' +is called interactively with a prefix argument, the user can specify the +directories or files to search in. Multiple directories or files must +be separated by comma in the minibuffer, since they are read via +`completing-read-multiple'. By default the project directory is used if +`consult-project-function' is defined and returns non-nil. Otherwise +the `default-directory' is searched. If the command is invoked with a +double prefix argument (twice `C-u') the user is asked for a project, if +not yet inside a project, or the current project is searched. + +The input string is split, the first part of the string (grep input) is +passed to the asynchronous grep process and the second part of the +string is passed to the completion-style filtering. + +The input string is split at a punctuation character, which is given as +the first character of the input string. The format is similar to +Perl-style regular expressions, e.g., /regexp/. Furthermore command +line options can be passed to grep, specified behind --. The overall +prompt input has the form `#async-input -- grep-opts#filter-string'. + +Note that the grep input string is transformed from Emacs regular +expressions to Posix regular expressions. Always enter Emacs regular +expressions at the prompt. `consult-grep' behaves like builtin Emacs +search commands, e.g., Isearch, which take Emacs regular expressions. +Furthermore the asynchronous input split into words, each word must +match separately and in any order. See `consult--regexp-compiler' for +the inner workings. In order to disable transformations of the grep +input, adjust `consult--regexp-compiler' accordingly. + +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." + (interactive "P") + (consult--grep "Grep" #'consult--grep-make-builder dir initial)) + +;;;;; Command: consult-git-grep + +(defun consult--git-grep-make-builder (paths) + "Create grep command line builder given PATHS." + (let ((cmd (consult--build-args consult-git-grep-args))) + (lambda (input) + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (flags (append cmd opts)) + (ignore-case (or (member "-i" flags) (member "--ignore-case" flags)))) + (if (or (member "-F" flags) (member "--fixed-strings" flags)) + (cons (append cmd (list "-e" arg) opts paths) + (apply-partially #'consult--highlight-regexps + (list (regexp-quote arg)) ignore-case)) + (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended ignore-case))) + (when re + (cons (append cmd + (cdr (mapcan (lambda (x) (list "--and" "-e" x)) re)) + opts paths) + hl)))))))) + +;;;###autoload +(defun consult-git-grep (&optional dir initial) + "Search with `git grep' for files in DIR with INITIAL input. +See `consult-grep' for details." + (interactive "P") + (consult--grep "Git-grep" #'consult--git-grep-make-builder dir initial)) + +;;;;; Command: consult-ripgrep + +(defun consult--ripgrep-make-builder (paths) + "Create ripgrep command line builder given PATHS." + (let* ((cmd (consult--build-args consult-ripgrep-args)) + (type (if (consult--grep-lookahead-p (car cmd) "-P") 'pcre 'extended))) + (lambda (input) + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (flags (append cmd opts)) + (ignore-case + (and (not (or (member "-s" flags) (member "--case-sensitive" flags))) + (or (member "-i" flags) (member "--ignore-case" flags) + (and (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)))))))) + (if (or (member "-F" flags) (member "--fixed-strings" flags)) + (cons (append cmd (list "-e" arg) opts paths) + (apply-partially #'consult--highlight-regexps + (list (regexp-quote arg)) ignore-case)) + (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg type ignore-case))) + (when re + (cons (append cmd (and (eq type 'pcre) '("-P")) + (list "-e" (consult--join-regexps re type)) + opts paths) + hl)))))))) + +;;;###autoload +(defun consult-ripgrep (&optional dir initial) + "Search with `rg' for files in DIR with INITIAL input. +See `consult-grep' for details." + (interactive "P") + (consult--grep "Ripgrep" #'consult--ripgrep-make-builder dir initial)) + +;;;;; 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 initial 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 (paths) + "Build find command line, finding across PATHS." + (let* ((cmd (seq-mapcat (lambda (x) + (if (equal x ".") paths (list x))) + (consult--build-args consult-find-args))) + (type (if (eq 0 (process-file-shell-command + (concat (car cmd) " -regextype emacs -version"))) + 'emacs 'basic))) + (lambda (input) + (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.*" + ;; 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 with `find' in DIR. +The file names must match the input regexp. INITIAL is the +initial minibuffer input. See `consult-grep' for details +regarding the asynchronous search and the arguments." + (interactive "P") + (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt "Find" dir)) + (default-directory dir) + (builder (consult--find-make-builder paths))) + (find-file (consult--find prompt builder initial)))) + +;;;;; Command: consult-fd + +(defun consult--fd-make-builder (paths) + "Build find command line, finding across PATHS." + (let ((cmd (consult--build-args consult-fd-args))) + (lambda (input) + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (flags (append cmd opts)) + (ignore-case + (and (not (or (member "-s" flags) (member "--case-sensitive" flags))) + (or (member "-i" flags) (member "--ignore-case" flags) + (let (case-fold-search) + ;; Case insensitive if there are no uppercase letters + (not (string-match-p "[[:upper:]]" arg))))))) + (if (or (member "-F" flags) (member "--fixed-strings" flags)) + (cons (append cmd (list arg) opts paths) + (apply-partially #'consult--highlight-regexps + (list (regexp-quote arg)) ignore-case)) + (pcase-let ((`(,re . ,hl) (funcall consult--regexp-compiler arg 'pcre ignore-case))) + (when re + (cons (append cmd + (mapcan (lambda (x) `("--and" ,x)) re) + opts + (mapcan (lambda (x) `("--search-path" ,x)) paths)) + hl)))))))) + +;;;###autoload +(defun consult-fd (&optional dir initial) + "Search for files with `fd' in DIR. +The file names must match the input regexp. INITIAL is the +initial minibuffer input. See `consult-grep' for details +regarding the asynchronous search and the arguments." + (interactive "P") + (pcase-let* ((`(,prompt ,paths ,dir) (consult--directory-prompt "Fd" dir)) + (default-directory dir) + (builder (consult--fd-make-builder paths))) + (find-file (consult--find prompt builder initial)))) + +;;;;; Command: consult-locate + +(defun consult--locate-builder (input) + "Build command line from INPUT." + (pcase-let ((`(,arg . ,opts) (consult--command-split input))) + (unless (string-blank-p arg) + (cons (append (consult--build-args consult-locate-args) + (consult--split-escaped 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 from INPUT." + (pcase-let* ((`(,arg . ,opts) (consult--command-split input)) + (`(,re . ,hl) (funcall consult--regexp-compiler arg 'extended t))) + (when re + (cons (append (consult--build-args consult-man-args) + (list (consult--join-regexps re 'extended)) + 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." + :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 completion systems + +;;;;; Integration: Default *Completions* + +(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))))) + +;;;;; Integration: Vertico + +(defvar vertico--input) +(declare-function vertico--exhibit "ext:vertico") +(declare-function vertico--candidate "ext:vertico") +(declare-function vertico--filter-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 (not highlight) (bound-and-true-p vertico-mode)) + ;; Optimize `consult--completion-filter' using the deferred highlighting + ;; from Vertico. The advice is not necessary - it is a pure optimization. + (nconc (car (vertico--filter-completions pattern cands nil (length pattern) + `(metadata (category . ,category)))) + nil) + (funcall orig pattern cands category highlight))) + +(with-eval-after-load 'vertico + (advice-add #'consult--completion-filter :around #'consult--vertico-filter-adv) + (add-hook 'consult--completion-candidate-hook #'consult--vertico-candidate) + (add-hook 'consult--completion-refresh-hook #'consult--vertico-refresh) + (define-key consult-async-map [remap vertico-insert] 'vertico-next-group)) + +;;;;; Integration: Mct + +(with-eval-after-load 'mct (add-hook 'consult--completion-refresh-hook + 'mct--live-completions-refresh)) + +;;;;; Integration: Icomplete + +(defvar icomplete-mode) +(declare-function icomplete-exhibit "icomplete") + +(defun consult--icomplete-refresh () + "Refresh icomplete view." + (when icomplete-mode + (let ((top (car completion-all-sorted-completions))) + (completion--flush-all-sorted-completions) + ;; force flushing, otherwise narrowing is broken! + (setq completion-all-sorted-completions nil) + (when top + (let* ((completions (completion-all-sorted-completions)) + (last (last completions)) + (before)) ;; completions before top + ;; warning: completions is an improper list + (while (consp completions) + (if (equal (car completions) top) + (progn + (setcdr last (append (nreverse before) (cdr last))) + (setq completion-all-sorted-completions completions + completions nil)) + (push (car completions) before) + (setq completions (cdr completions))))))) + (icomplete-exhibit))) + +(with-eval-after-load 'icomplete + (add-hook 'consult--completion-refresh-hook #'consult--icomplete-refresh)) + +(provide 'consult) +;;; consult.el ends here diff --git a/emacs/elpa/consult-20240818.1112/consult.elc b/emacs/elpa/consult-20240818.1112/consult.elc Binary files differ. diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-core.el b/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-core.el @@ -1,1705 +0,0 @@ -;;; doom-modeline-core.el --- The core libraries for doom-modeline -*- lexical-binding: t; -*- - -;; Copyright (C) 2018-2024 Vincent Zhang - -;; This file is not part of GNU Emacs. - -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. -;; - -;;; Commentary: -;; -;; The core libraries for doom-modeline. -;; - -;;; Code: - -(require 'compat) -(eval-when-compile - (require 'cl-lib) - (require 'subr-x)) -(require 'nerd-icons) -(require 'shrink-path) - - -;; -;; Compatibility -;; - -(unless (boundp 'mode-line-right-align-edge) - (defcustom mode-line-right-align-edge 'window - "Where mode-line should align to. -Internally, that function uses `:align-to' in a display property, -so aligns to the left edge of the given area. See info node -`(elisp)Pixel Specification'. - -Must be set to a symbol. Acceptable values are: -- `window': align to extreme right of window, regardless of margins - or fringes -- `right-fringe': align to right-fringe -- `right-margin': align to right-margin" - :type '(choice (const right-margin) - (const right-fringe) - (const window)) - :group 'mode-line)) - - -;; -;; Optimization -;; - -;; Don’t compact font caches during GC. -(when (eq system-type 'windows-nt) - (setq inhibit-compacting-font-caches t)) - - -;; -;; Customization -;; - -(defgroup doom-modeline nil - "A minimal and modern mode-line." - :group 'mode-line - :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) - -(defcustom doom-modeline-support-imenu nil - "If non-nil, cause imenu to see `doom-modeline' declarations. -This is done by adjusting `lisp-imenu-generic-expression' to -include support for finding `doom-modeline-def-*' forms. - -Must be set before loading `doom-modeline'." - :type 'boolean - :set (lambda (_sym val) - (if val - (add-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu) - (remove-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu))) - :group 'doom-modeline) - -(defcustom doom-modeline-height (+ (frame-char-height) 4) - "How tall the mode-line should be. It's only respected in GUI. -If the actual char height is larger, it respects the actual char height." - :type 'integer - :group 'doom-modeline) - -(defcustom doom-modeline-bar-width 4 - "How wide the mode-line bar should be. It's only respected in GUI." - :type 'integer - :set (lambda (sym val) - (set sym (if (> val 0) val 1))) - :group 'doom-modeline) - -(defcustom doom-modeline-hud nil - "Whether to use hud instead of default bar. It's only respected in GUI." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-hud-min-height 2 - "Minimum height in pixels of the \"thumb\" of the hud. -Only respected in GUI." - :type 'integer - :set (lambda (sym val) - (set sym (if (> val 1) val 1))) - :group 'doom-modeline) - -(defcustom doom-modeline-window-width-limit 85 - "The limit of the window width. - -If `window-width' is smaller than the limit, some information won't be -displayed. It can be an integer or a float number. nil means no limit." - :type '(choice integer - float - (const :tag "Disable" nil)) - :group 'doom-modeline) - -(defcustom doom-modeline-project-detection 'auto - "How to detect the project root. - -nil means to use `default-directory'. - -The project management packages have some issues on detecting project root. -e.g. `projectile' doesn't handle symlink folders well, while `project' is -unable to handle sub-projects. -Specify another one if you encounter the issue." - :type '(choice (const :tag "Auto-detect" auto) - (const :tag "Find File in Project" ffip) - (const :tag "Projectile" projectile) - (const :tag "Built-in Project" project) - (const :tag "Disable" nil)) - :group 'doom-modeline) - -(defcustom doom-modeline-buffer-file-name-style 'auto - "Determines the style used by `doom-modeline-buffer-file-name'. - -Given ~/Projects/FOSS/emacs/lisp/comint.el - auto => emacs/l/comint.el (in a project) or comint.el - truncate-upto-project => ~/P/F/emacs/lisp/comint.el - truncate-from-project => ~/Projects/FOSS/emacs/l/comint.el - truncate-with-project => emacs/l/comint.el - truncate-except-project => ~/P/F/emacs/l/comint.el - truncate-upto-root => ~/P/F/e/lisp/comint.el - truncate-all => ~/P/F/e/l/comint.el - truncate-nil => ~/Projects/FOSS/emacs/lisp/comint.el - relative-from-project => emacs/lisp/comint.el - relative-to-project => lisp/comint.el - file-name => comint.el - file-name-with-project => FOSS|comint.el - buffer-name => comint.el<2> (uniquify buffer name)" - :type '(choice (const auto) - (const truncate-upto-project) - (const truncate-from-project) - (const truncate-with-project) - (const truncate-except-project) - (const truncate-upto-root) - (const truncate-all) - (const truncate-nil) - (const relative-from-project) - (const relative-to-project) - (const file-name) - (const file-name-with-project) - (const buffer-name)) - :group'doom-modeline) - -(defcustom doom-modeline-buffer-file-true-name nil - "Use `file-truename' on buffer file name. - -Project detection(projectile.el) may uses `file-truename' on directory path. -Turn on this to provide right relative path for buffer file name." - :type 'boolean - :group'doom-modeline) - -(defcustom doom-modeline-icon t - "Whether display the icons in the mode-line. - -While using the server mode in GUI, should set the value explicitly." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-major-mode-icon t - "Whether display the icon for `major-mode'. - -It respects option `doom-modeline-icon'." - :type 'boolean - :group'doom-modeline) - -(defcustom doom-modeline-major-mode-color-icon t - "Whether display the colorful icon for `major-mode'. - -It respects option `nerd-icons-color-icons'." - :type 'boolean - :group'doom-modeline) - -(defcustom doom-modeline-buffer-state-icon t - "Whether display the icon for the buffer state. - -It respects option `doom-modeline-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-buffer-modification-icon t - "Whether display the modification icon for the buffer. - -It respects option `doom-modeline-icon' and `doom-modeline-buffer-state-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-lsp-icon t - "Whether display the icon of lsp client. - -It respects option `doom-modeline-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-time-icon t - "Whether display the icon of time. - -It respects option `doom-modeline-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-time-live-icon t - "Whether display the live icons of time. - -It respects option `doom-modeline-icon' and option `doom-modeline-time-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-time-analogue-clock t - "Whether to draw an analogue clock SVG as the live time icon. -It respects the option `doom-modeline-icon', option `doom-modeline-time-icon', -and option `doom-modeline-time-live-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-time-clock-minute-resolution 1 - "The clock will be updated every this many minutes, truncated. -See `doom-modeline-time-analogue-clock'." - :type 'natnum - :group 'doom-modeline) - -(defcustom doom-modeline-time-clock-size 0.7 - "Size of the analogue clock drawn, either in pixels or as a proportional height. -An integer value is used as the diameter of clock in pixels. -A floating point value sets the diameter of the clock realtive to -`doom-modeline-height'. - -Only relevant when `doom-modeline-time-analogue-clock' is non-nil, which see." - :type 'number - :group 'doom-modeline) - -(defcustom doom-modeline-unicode-fallback nil - "Whether to use unicode as a fallback (instead of ASCII) when not using icons." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-buffer-name t - "Whether display the buffer name." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-highlight-modified-buffer-name t - "Whether highlight the modified buffer name." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-column-zero-based t - "When non-nil, mode line displays column numbers zero-based. -See `column-number-indicator-zero-based'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-percent-position '(-3 "%p") - "Specification of \"percentage offset\" of window through buffer. -See `mode-line-percent-position'." - :type '(radio - (const :tag "nil: No offset is displayed" nil) - (const :tag "\"%o\": Proportion of \"travel\" of the window through the buffer" - (-3 "%o")) - (const :tag "\"%p\": Percentage offset of top of window" - (-3 "%p")) - (const :tag "\"%P\": Percentage offset of bottom of window" - (-3 "%P")) - (const :tag "\"%q\": Offsets of both top and bottom of window" - (6 "%q"))) - :group 'doom-modeline) - -(defcustom doom-modeline-position-line-format '("L%l") - "Format used to display line numbers in the mode line. -See `mode-line-position-line-format'." - :type '(list string) - :group 'doom-modeline) - -(defcustom doom-modeline-position-column-format '("C%c") - "Format used to display column numbers in the mode line. -See `mode-line-position-column-format'." - :type '(list string) - :group 'doom-modeline) - -(defcustom doom-modeline-position-column-line-format '("%l:%c") - "Format used to display combined line/column numbers in the mode line. -See `mode-line-position-column-line-format'." - :type '(list string) - :group 'doom-modeline) - -(defcustom doom-modeline-minor-modes nil - "Whether display the minor modes in the mode-line." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-enable-word-count nil - "If non-nil, a word count will be added to the selection-info modeline segment." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-continuous-word-count-modes - '(markdown-mode gfm-mode org-mode) - "Major modes in which to display word count continuously. - -It respects `doom-modeline-enable-word-count'." - :type '(repeat (symbol :tag "Major-Mode") ) - :group 'doom-modeline) - -(defcustom doom-modeline-buffer-encoding t - "Whether display the buffer encoding." - :type '(choice (const :tag "Always" t) - (const :tag "When non-default" nondefault) - (const :tag "Never" nil)) - :group 'doom-modeline) - -(defcustom doom-modeline-default-coding-system 'utf-8 - "Default coding system for `doom-modeline-buffer-encoding' `nondefault'." - :type 'coding-system - :group 'doom-modeline) - -(defcustom doom-modeline-default-eol-type 0 - "Default EOL type for `doom-modeline-buffer-encoding' `nondefault'." - :type '(choice (const :tag "Unix-style LF" 0) - (const :tag "DOS-style CRLF" 1) - (const :tag "Mac-style CR" 2)) - :group 'doom-modeline) - -(defcustom doom-modeline-indent-info nil - "Whether display the indentation information." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-total-line-number nil - "Whether display the total line number." - :type 'boolean - :group 'doom-modeline) - -;; It is based upon `editorconfig-indentation-alist' but is used to read indentation levels instead -;; of setting them. (https://github.com/editorconfig/editorconfig-emacs) -(defcustom doom-modeline-indent-alist - '((apache-mode apache-indent-level) - (awk-mode c-basic-offset) - (bpftrace-mode c-basic-offset) - (c++-mode c-basic-offset) - (c-mode c-basic-offset) - (cmake-mode cmake-tab-width) - (coffee-mode coffee-tab-width) - (cperl-mode cperl-indent-level) - (crystal-mode crystal-indent-level) - (csharp-mode c-basic-offset) - (css-mode css-indent-offset) - (d-mode c-basic-offset) - (emacs-lisp-mode lisp-indent-offset) - (enh-ruby-mode enh-ruby-indent-level) - (erlang-mode erlang-indent-level) - (ess-mode ess-indent-offset) - (f90-mode f90-associate-indent - f90-continuation-indent - f90-critical-indent - f90-do-indent - f90-if-indent - f90-program-indent - f90-type-indent) - (feature-mode feature-indent-offset - feature-indent-level) - (fsharp-mode fsharp-continuation-offset - fsharp-indent-level - fsharp-indent-offset) - (groovy-mode groovy-indent-offset) - (haskell-mode haskell-indent-spaces - haskell-indent-offset - haskell-indentation-layout-offset - haskell-indentation-left-offset - haskell-indentation-starter-offset - haskell-indentation-where-post-offset - haskell-indentation-where-pre-offset - shm-indent-spaces) - (haxor-mode haxor-tab-width) - (idl-mode c-basic-offset) - (jade-mode jade-tab-width) - (java-mode c-basic-offset) - (js-mode js-indent-level) - (js-jsx-mode js-indent-level - sgml-basic-offset) - (js2-mode js2-basic-offset) - (js2-jsx-mode js2-basic-offset - sgml-basic-offset) - (js3-mode js3-indent-level) - (json-mode js-indent-level) - (julia-mode julia-indent-offset) - (kotlin-mode kotlin-tab-width) - (latex-mode tex-indent-basic) - (lisp-mode lisp-indent-offset) - (livescript-mode livescript-tab-width) - (lua-mode lua-indent-level) - (matlab-mode matlab-indent-level) - (mips-mode mips-tab-width) - (mustache-mode mustache-basic-offset) - (nasm-mode nasm-basic-offset) - (nginx-mode nginx-indent-level) - (nxml-mode nxml-child-indent) - (objc-mode c-basic-offset) - (octave-mode octave-block-offset) - (perl-mode perl-indent-level) - (php-mode c-basic-offset) - (pike-mode c-basic-offset) - (ps-mode ps-mode-tab) - (pug-mode pug-tab-width) - (puppet-mode puppet-indent-level) - (python-mode python-indent-offset) - (ruby-mode ruby-indent-level) - (rust-mode rust-indent-offset) - (rustic-mode rustic-indent-offset) - (scala-mode scala-indent:step) - (scss-mode css-indent-offset) - (sgml-mode sgml-basic-offset) - (sh-mode sh-basic-offset - sh-indentation) - (slim-mode slim-indent-offset) - (sml-mode sml-indent-level) - (tcl-mode tcl-indent-level - tcl-continued-indent-level) - (terra-mode terra-indent-level) - (typescript-mode typescript-indent-level) - (verilog-mode verilog-indent-level - verilog-indent-level-behavioral - verilog-indent-level-declaration - verilog-indent-level-module - verilog-cexp-indent - verilog-case-indent) - (web-mode web-mode-attr-indent-offset - web-mode-attr-value-indent-offset - web-mode-code-indent-offset - web-mode-css-indent-offset - web-mode-markup-indent-offset - web-mode-sql-indent-offset - web-mode-block-padding - web-mode-script-padding - web-mode-style-padding) - (yaml-mode yaml-indent-offset)) - "Indentation retrieving variables matched to major modes. - -Which is used when `doom-modeline-indent-info' is non-nil. -When multiple variables are specified for a mode, they will be tried resolved -in the given order." - :type '(alist :key-type symbol :value-type sexp) - :group 'doom-modeline) - -(defcustom doom-modeline-vcs-icon t - "Whether display the icon of vcs segment. - -It respects option `doom-modeline-icon'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-vcs-max-length 15 - "The maximum displayed length of the branch name of version control." - :type 'integer - :group 'doom-modeline) - -(defcustom doom-modeline-vcs-display-function #'doom-modeline-vcs-name - "The function to display the branch name." - :type 'function - :group 'doom-modeline) - -(defcustom doom-modeline-check-icon t - "Whether display the icon of check segment. - -It respects option `doom-modeline-icon'." - :type 'boolean - :group 'doom-modeline) - -(define-obsolete-variable-alias - 'doom-modeline-checker-simple-format - 'doom-modeline-check-simple-format - "4.2.0") - -(defcustom doom-modeline-check-simple-format nil - "If non-nil, only display one number for check information if applicable." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-number-limit 99 - "The maximum number displayed for notifications." - :type 'integer - :group 'doom-modeline) - -(defcustom doom-modeline-workspace-name t - "Whether display the workspace name. - -Non-nil to display in the mode-line." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-persp-name t - "Whether display the perspective name. - -Non-nil to display in the mode-line." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-display-default-persp-name nil - "If non nil the default perspective name is displayed in the mode-line." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-persp-icon t - "If non nil the perspective name is displayed alongside a folder icon." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-repl t - "Whether display the `repl' state. - -Non-nil to display in the mode-line." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-lsp t - "Whether display the `lsp' state. - -Non-nil to display in the mode-line." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-github nil - "Whether display the GitHub notifications. - -It requires `ghub' and `async' packages. Additionally, your GitHub personal -access token must have `notifications' permissions. - -If you use `pass' to manage your secrets, you also need to add this hook: - (add-hook \\='doom-modeline-before-github-fetch-notification-hook - #\\='auth-source-pass-enable)" - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-github-interval 1800 ; (* 30 60) - "The interval of checking GitHub." - :type 'integer - :group 'doom-modeline) - -(defcustom doom-modeline-env-version t - "Whether display the environment version." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-modal t - "Whether display the modal state. - -Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-modal-icon t - "Whether display the modal state icon. - -Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-modal-modern-icon t - "Whether display the modern icons for modals." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-always-show-macro-register nil - "When non-nil, always show the register name when recording an evil macro." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-mu4e nil - "Whether display the mu4e notifications. - -It requires `mu4e-alert' package." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-gnus nil - "Whether to display notifications from gnus. - -It requires `gnus' to be setup" - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-gnus-timer 2 - "The wait time in minutes before gnus fetches mail. - -If nil, don't set up a hook." - :type 'integer - :group 'doom-modeline) - -(defcustom doom-modeline-gnus-idle nil - "Whether to wait an idle time to scan for news. - -When t, sets `doom-modeline-gnus-timer' as an idle timer. If a -number, Emacs must have been idle this given time, checked after -reach the defined timer, to fetch news. The time step can be -configured in `gnus-demon-timestep'." - :type '(choice - (boolean :tag "Set `doom-modeline-gnus-timer' as an idle timer") - (number :tag "Set a custom idle timer")) - :group 'doom-modeline) - -(defcustom doom-modeline-gnus-excluded-groups nil - "A list of groups to be excluded from the unread count. -Groups' names list in `gnus-newsrc-alist'`" - :type '(repeat string) - :group 'doom-modeline) - -(defcustom doom-modeline-irc t - "Whether display the irc notifications. - -It requires `circe' or `erc' package." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-irc-buffers nil - "Whether display the unread irc buffers." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-irc-stylize #'doom-modeline-shorten-irc - "Function to stylize the irc buffer names." - :type 'function - :group 'doom-modeline) - -(defcustom doom-modeline-battery t - "Whether display the battery status. - -It respects `display-battery-mode'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-time t - "Whether display the time. - -It respects `display-time-mode'." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-display-misc-in-all-mode-lines t - "Whether display the misc segment on all mode lines. - -If nil, display only if the mode line is active." - :type 'boolean - :group 'doom-modeline) - -(defcustom doom-modeline-always-visible-segments nil - "A list of segments that should be visible even in inactive windows." - :type '(repeat symbol) - :group 'doom-modeline) - -(defcustom doom-modeline-buffer-file-name-function #'identity - "The function to handle variable `buffer-file-name'." - :type 'function - :group 'doom-modeline) - -(defcustom doom-modeline-buffer-file-truename-function #'identity - "The function to handle `buffer-file-truename'." - :type 'function - :group 'doom-modeline) - -(defcustom doom-modeline-k8s-show-namespace t - "Whether to show the current Kubernetes context's default namespace." - :type 'boolean - :group 'doom-modeline) - - -;; -;; Faces -;; - -(defgroup doom-modeline-faces nil - "The faces of `doom-modeline'." - :group 'doom-modeline - :group 'faces - :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) - -(defface doom-modeline - '((t ())) - "Default face." - :group 'doom-modeline-faces) - -(defface doom-modeline-emphasis - '((t (:inherit (doom-modeline mode-line-emphasis)))) - "Face used for emphasis." - :group 'doom-modeline-faces) - -(defface doom-modeline-highlight - '((t (:inherit (doom-modeline mode-line-highlight)))) - "Face used for highlighting." - :group 'doom-modeline-faces) - -(defface doom-modeline-buffer-path - '((t (:inherit (doom-modeline-emphasis bold)))) - "Face used for the dirname part of the buffer path." - :group 'doom-modeline-faces) - -(defface doom-modeline-buffer-file - '((t (:inherit (doom-modeline mode-line-buffer-id bold)))) - "Face used for the filename part of the mode-line buffer path." - :group 'doom-modeline-faces) - -(defface doom-modeline-buffer-modified - '((t (:inherit (doom-modeline warning bold) :background unspecified))) - "Face used for the \\='unsaved\\=' symbol in the mode-line." - :group 'doom-modeline-faces) - -(defface doom-modeline-buffer-major-mode - '((t (:inherit (doom-modeline-emphasis bold)))) - "Face used for the major-mode segment in the mode-line." - :group 'doom-modeline-faces) - -(defface doom-modeline-buffer-minor-mode - '((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal))) - "Face used for the minor-modes segment in the mode-line." - :group 'doom-modeline-faces) - -(defface doom-modeline-project-parent-dir - '((t (:inherit (doom-modeline font-lock-comment-face bold)))) - "Face used for the project parent directory of the mode-line buffer path." - :group 'doom-modeline-faces) - -(defface doom-modeline-project-dir - '((t (:inherit (doom-modeline font-lock-string-face bold)))) - "Face used for the project directory of the mode-line buffer path." - :group 'doom-modeline-faces) - -(defface doom-modeline-project-root-dir - '((t (:inherit (doom-modeline-emphasis bold)))) - "Face used for the project part of the mode-line buffer path." - :group 'doom-modeline-faces) - -(defface doom-modeline-panel - '((t (:inherit doom-modeline-highlight))) - "Face for \\='X out of Y\\=' segments. -This applies to `anzu', `evil-substitute', `iedit' etc." - :group 'doom-modeline-faces) - -(defface doom-modeline-host - '((t (:inherit (doom-modeline italic)))) - "Face for remote hosts in the mode-line." - :group 'doom-modeline-faces) - -(defface doom-modeline-input-method - '((t (:inherit (doom-modeline-emphasis)))) - "Face for input method in the mode-line." - :group 'doom-modeline-faces) - -(defface doom-modeline-input-method-alt - '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) - "Alternative face for input method in the mode-line." - :group 'doom-modeline-faces) - -(defface doom-modeline-debug - '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) - "Face for debug-level messages in the mode-line. Used by vcs, check, etc." - :group 'doom-modeline-faces) - -(defface doom-modeline-info - '((t (:inherit (doom-modeline success)))) - "Face for info-level messages in the mode-line. Used by vcs, check, etc." - :group 'doom-modeline-faces) - -(defface doom-modeline-warning - '((t (:inherit (doom-modeline warning)))) - "Face for warnings in the mode-line. Used by vcs, check, etc." - :group 'doom-modeline-faces) - -(defface doom-modeline-urgent - '((t (:inherit (doom-modeline error)))) - "Face for errors in the mode-line. Used by vcs, check, etc." - :group 'doom-modeline-faces) - -(defface doom-modeline-notification - '((t (:inherit doom-modeline-warning))) - "Face for notifications in the mode-line. Used by GitHub, mu4e, etc. -Also see the face `doom-modeline-unread-number'." - :group 'doom-modeline-faces) - -(defface doom-modeline-unread-number - '((t (:inherit doom-modeline :slant italic))) - "Face for unread number in the mode-line. Used by GitHub, mu4e, etc." - :group 'doom-modeline-faces) - -(defface doom-modeline-bar - '((t (:inherit doom-modeline-highlight))) - "The face used for the left-most bar in the mode-line of an active window." - :group 'doom-modeline-faces) - -(defface doom-modeline-bar-inactive - `((t (:inherit doom-modeline))) - "The face used for the left-most bar in the mode-line of an inactive window." - :group 'doom-modeline-faces) - -(defface doom-modeline-debug-visual - '((((background light)) :foreground "#D4843E" :inherit doom-modeline) - (((background dark)) :foreground "#915B2D" :inherit doom-modeline)) - "Face to use for the mode-line while debugging." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-emacs-state - '((t (:inherit (doom-modeline font-lock-builtin-face)))) - "Face for the Emacs state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-insert-state - '((t (:inherit (doom-modeline font-lock-keyword-face)))) - "Face for the insert state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-motion-state - '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) - "Face for the motion state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-normal-state - '((t (:inherit doom-modeline-info))) - "Face for the normal state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-operator-state - '((t (:inherit (doom-modeline mode-line)))) - "Face for the operator state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-visual-state - '((t (:inherit doom-modeline-warning))) - "Face for the visual state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-replace-state - '((t (:inherit doom-modeline-urgent))) - "Face for the replace state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-evil-user-state - '((t (:inherit doom-modeline-warning))) - "Face for the replace state tag in evil indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-overwrite - '((t (:inherit doom-modeline-urgent))) - "Face for overwrite indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-god - '((t (:inherit doom-modeline-info))) - "Face for god-mode indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-ryo - '((t (:inherit doom-modeline-info))) - "Face for RYO indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-fly-insert-state - '((t (:inherit (doom-modeline font-lock-keyword-face)))) - "Face for the insert state in xah-fly-keys indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-fly-normal-state - '((t (:inherit doom-modeline-info))) - "Face for the normal state in xah-fly-keys indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-boon-command-state - '((t (:inherit doom-modeline-info))) - "Face for the command state tag in boon indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-boon-insert-state - '((t (:inherit (doom-modeline font-lock-keyword-face)))) - "Face for the insert state tag in boon indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-boon-special-state - '((t (:inherit (doom-modeline font-lock-builtin-face)))) - "Face for the special state tag in boon indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-boon-off-state - '((t (:inherit (doom-modeline mode-line)))) - "Face for the off state tag in boon indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-meow-normal-state - '((t (:inherit doom-modeline-evil-normal-state))) - "Face for the normal state in meow-edit indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-meow-insert-state - '((t (:inherit doom-modeline-evil-insert-state))) - "Face for the insert state in meow-edit indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-meow-beacon-state - '((t (:inherit doom-modeline-evil-visual-state))) - "Face for the beacon state in meow-edit indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-meow-motion-state - '((t (:inherit doom-modeline-evil-motion-state))) - "Face for the motion state in meow-edit indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-meow-keypad-state - '((t (:inherit doom-modeline-evil-operator-state))) - "Face for the keypad state in meow-edit indicator." - :group 'doom-modeline-faces) - -(defface doom-modeline-persp-name - '((t (:inherit (doom-modeline font-lock-comment-face italic)))) - "Face for the persp name." - :group 'doom-modeline-faces) - -(defface doom-modeline-persp-buffer-not-in-persp - '((t (:inherit (doom-modeline font-lock-doc-face italic)))) - "Face for the buffers which are not in the persp." - :group 'doom-modeline-faces) - -(defface doom-modeline-repl-success - '((t (:inherit doom-modeline-info))) - "Face for REPL success state." - :group 'doom-modeline-faces) - -(defface doom-modeline-repl-warning - '((t (:inherit doom-modeline-warning))) - "Face for REPL warning state." - :group 'doom-modeline-faces) - -(defface doom-modeline-lsp-success - '((t (:inherit doom-modeline-info))) - "Face for LSP success state." - :group 'doom-modeline-faces) - -(defface doom-modeline-lsp-warning - '((t (:inherit doom-modeline-warning))) - "Face for LSP warning state." - :group 'doom-modeline-faces) - -(defface doom-modeline-lsp-error - '((t (:inherit doom-modeline-urgent))) - "Face for LSP error state." - :group 'doom-modeline-faces) - -(defface doom-modeline-lsp-running - '((t (:inherit (doom-modeline compilation-mode-line-run) :weight normal :slant normal))) - "Face for LSP running state." - :group 'doom-modeline-faces) - -(defface doom-modeline-battery-charging - '((t (:inherit doom-modeline-info))) - "Face for battery charging status." - :group 'doom-modeline-faces) - -(defface doom-modeline-battery-full - '((t (:inherit doom-modeline-info))) - "Face for battery full status." - :group 'doom-modeline-faces) - -(defface doom-modeline-battery-normal - '((t (:inherit (doom-modeline mode-line)))) - "Face for battery normal status." - :group 'doom-modeline-faces) - -(defface doom-modeline-battery-warning - '((t (:inherit doom-modeline-warning))) - "Face for battery warning status." - :group 'doom-modeline-faces) - -(defface doom-modeline-battery-critical - '((t (:inherit doom-modeline-urgent))) - "Face for battery critical status." - :group 'doom-modeline-faces) - -(defface doom-modeline-battery-error - '((t (:inherit doom-modeline-urgent))) - "Face for battery error status." - :group 'doom-modeline-faces) - -(defface doom-modeline-buffer-timemachine - '((t (:inherit doom-modeline-buffer-file :slant italic))) - "Face for timemachine status." - :group 'doom-modeline-faces) - -(defface doom-modeline-time - '((t (:inherit doom-modeline))) - "Face for display time." - :group 'doom-modeline-faces) - -(defface doom-modeline-compilation - '((t (:inherit doom-modeline-warning :slant italic :height 0.9))) - "Face for compilation progress." - :group 'doom-modeline-faces) - -;; -;; Externals -;; - -(defvar mode-line-right-align-edge) - -(declare-function doom-modeline-shorten-irc "doom-modeline-segments") -(declare-function face-remap-remove-relative "face-remap") -(declare-function ffip-project-root "ext:find-file-in-project") -(declare-function project-root "project") -(declare-function projectile-project-root "ext:projectile") - - -;; -;; Utilities -;; - -(defun doom-modeline-add-font-lock () - "Fontify `doom-modeline-def-*' statements." - (font-lock-add-keywords - 'emacs-lisp-mode - '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" - (1 font-lock-keyword-face) - (2 font-lock-constant-face))))) -(doom-modeline-add-font-lock) - -(defun doom-modeline-add-imenu () - "Add to `imenu' index." - (add-to-list - 'imenu-generic-expression - '("Modelines" - "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" - 2)) - (add-to-list - 'imenu-generic-expression - '("Segments" - "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" - 2)) - (add-to-list - 'imenu-generic-expression - '("Envs" - "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" - 2))) - - -;; -;; Core helpers -;; - -;; FIXME #183: Force to calculate mode-line height -;; @see https://github.com/seagle0128/doom-modeline/issues/183 -;; @see https://github.com/seagle0128/doom-modeline/issues/483 -(unless (>= emacs-major-version 29) - (eval-and-compile - (defun doom-modeline-redisplay (&rest _) - "Call `redisplay' to trigger mode-line height calculations. - -Certain functions, including e.g. `fit-window-to-buffer', base -their size calculations on values which are incorrect if the -mode-line has a height different from that of the `default' face -and certain other calculations have not yet taken place for the -window in question. - -These calculations can be triggered by calling `redisplay' -explicitly at the appropriate time and this functions purpose -is to make it easier to do so. - -This function is like `redisplay' with non-nil FORCE argument, -but it will only trigger a redisplay when there is a non nil -`mode-line-format' and the height of the mode-line is different -from that of the `default' face. This function is intended to be -used as an advice to window creation functions." - (when (and (bound-and-true-p doom-modeline-mode) - mode-line-format - (/= (frame-char-height) (window-mode-line-height))) - (redisplay t)))) - (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) - -;; For `flycheck-color-mode-line' -(with-eval-after-load 'flycheck-color-mode-line - (defvar flycheck-color-mode-line-face-to-color) - (setq flycheck-color-mode-line-face-to-color 'doom-modeline)) - -(defun doom-modeline-icon-displayable-p () - "Return non-nil if icons are displayable." - (and doom-modeline-icon (featurep 'nerd-icons))) - -(defun doom-modeline-mwheel-available-p () - "Whether mouse wheel is available." - (and (featurep 'mwheel) (bound-and-true-p mouse-wheel-mode))) - -;; Keep `doom-modeline-current-window' up-to-date -(defun doom-modeline--selected-window () - "Get the selected window." - (frame-selected-window)) - -(defvar doom-modeline-current-window (doom-modeline--selected-window) - "Current window.") - -(defun doom-modeline--active () - "Whether is an active window." - (unless (and (bound-and-true-p mini-frame-frame) - (and (frame-live-p mini-frame-frame) - (frame-visible-p mini-frame-frame))) - (and doom-modeline-current-window - (eq (doom-modeline--selected-window) doom-modeline-current-window)))) - -(defvar-local doom-modeline--limited-width-p nil) - -(defun doom-modeline--segment-visible (name) - "Whether the segment NAME should be displayed." - (and - (or (doom-modeline--active) - (member name doom-modeline-always-visible-segments)) - (not doom-modeline--limited-width-p))) - -(defun doom-modeline-set-selected-window (&rest _) - "Set `doom-modeline-current-window' appropriately." - (let ((win (doom-modeline--selected-window))) - (setq doom-modeline-current-window - (if (minibuffer-window-active-p win) - (minibuffer-selected-window) - win)))) - -(defun doom-modeline-unset-selected-window () - "Unset `doom-modeline-current-window' appropriately." - (setq doom-modeline-current-window nil)) - -(add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) - -;; Ensure modeline is inactive when Emacs is unfocused -(defvar doom-modeline--remap-faces '(mode-line - mode-line-active - mode-line-emphasis - mode-line-highlight - mode-line-buffer-id - doom-modeline - solaire-mode-line-face - solaire-mode-line-active-face - paradox-mode-line-face - flycheck-color-mode-line-error-face - flycheck-color-mode-line-warning-face - flycheck-color-mode-line-info-face - flycheck-color-mode-line-success-face)) - -(defvar doom-modeline--remap-face-cookie-alist nil) -(defun doom-modeline-focus () - "Focus mode-line." - (mapc #'face-remap-remove-relative doom-modeline--remap-face-cookie-alist)) - -(defun doom-modeline-unfocus () - "Unfocus mode-line." - (dolist (face doom-modeline--remap-faces) - (add-to-list 'doom-modeline--remap-face-cookie-alist - (face-remap-add-relative face 'mode-line-inactive)))) - -(with-no-warnings - (if (boundp 'after-focus-change-function) - (progn - (defun doom-modeline-focus-change (&rest _) - (if (frame-focus-state (frame-parent)) - (progn - (doom-modeline-focus) - ;; HACK: pulse after focusing in the frame to refresh the buffer name. - ;; @see https://github.com/seagle0128/doom-modeline/issues/591 - (when (fboundp 'pulse-momentary-highlight-region) - (pulse-momentary-highlight-region 0 0))) - (doom-modeline-unfocus))) - (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) - (add-function :after after-focus-change-function #'doom-modeline-focus-change)) - (progn - (add-hook 'focus-in-hook #'doom-modeline-focus) - (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) - - -;; -;; Core -;; - -(defvar doom-modeline-fn-alist ()) -(defvar doom-modeline-var-alist ()) - -(defmacro doom-modeline-def-segment (name &rest body) - "Define a modeline segment NAME with BODY and byte compiles it." - (declare (indent defun) (doc-string 2)) - (let ((sym (intern (format "doom-modeline-segment--%s" name))) - (docstring (if (stringp (car body)) - (pop body) - (format "%s modeline segment" name)))) - (cond ((and (symbolp (car body)) - (not (cdr body))) - `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) - (t - `(progn - (defun ,sym () ,docstring ,@body) - (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) - ,(unless (bound-and-true-p byte-compile-current-file) - `(let (byte-compile-warnings) - (unless (and (fboundp 'subr-native-elisp-p) - (subr-native-elisp-p (symbol-function #',sym))) - (byte-compile #',sym))))))))) - -(defun doom-modeline--prepare-segments (segments) - "Prepare mode-line `SEGMENTS'." - (let (forms it) - (dolist (seg segments) - (cond ((stringp seg) - (push seg forms)) - ((symbolp seg) - (cond ((setq it (alist-get seg doom-modeline-fn-alist)) - (push (list :eval (list it)) forms)) - ((setq it (alist-get seg doom-modeline-var-alist)) - (push it forms)) - ((error "%s is not a defined segment" seg)))) - ((error "%s is not a valid segment" seg)))) - (nreverse forms))) - -(defun doom-modeline-def-modeline (name lhs &optional rhs) - "Define a modeline format and byte-compiles it. -NAME is a symbol to identify it (used by `doom-modeline' for retrieval). -LHS and RHS are lists of symbols of modeline segments defined with -`doom-modeline-def-segment'. - -Example: - (doom-modeline-def-modeline \\='minimal - \\='(bar matches \" \" buffer-info) - \\='(media-info major-mode)) - (doom-modeline-set-modeline \\='minimal t)" - (let ((sym (intern (format "doom-modeline-format--%s" name))) - (lhs-forms (doom-modeline--prepare-segments lhs)) - (rhs-forms (doom-modeline--prepare-segments rhs))) - (defalias sym - (lambda () - (list lhs-forms - (let* ((rhs-str (format-mode-line (cons "" rhs-forms))) - (rhs-width (progn - (add-face-text-property - 0 (length rhs-str) 'mode-line t rhs-str) - (doom-modeline-string-pixel-width rhs-str)))) - (propertize - " " - 'face (doom-modeline-face) - 'display - ;; Backport from `mode-line-right-align-edge' in 30 - (if (and (display-graphic-p) - (not (eq mode-line-right-align-edge 'window))) - `(space :align-to (- ,mode-line-right-align-edge - (,rhs-width))) - `(space :align-to (,(- (window-pixel-width) - (window-scroll-bar-width) - (window-right-divider-width) - (* (or (cdr (window-margins)) 1) - (frame-char-width)) - (pcase mode-line-right-align-edge - ('right-margin - (or (cdr (window-margins)) 0)) - ('right-fringe - (or (cadr (window-fringes)) 0)) - (_ 0)) - rhs-width)))))) - rhs-forms)) - (concat "Modeline:\n" - (format " %s\n %s" - (prin1-to-string lhs) - (prin1-to-string rhs)))))) -(put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) - -(defun doom-modeline (key) - "Return a mode-line configuration associated with KEY (a symbol). -Throws an error if it doesn't exist." - (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) - (when (functionp fn) - `(:eval (,fn))))) - -(defun doom-modeline-set-modeline (key &optional default) - "Set the modeline format. Does nothing if the modeline KEY doesn't exist. -If DEFAULT is non-nil, set the default mode-line for all buffers." - (when-let ((modeline (doom-modeline key))) - (setf (if default - (default-value 'mode-line-format) - mode-line-format) - (list "%e" modeline)))) - -;; -;; Helpers -;; - -(defconst doom-modeline-ellipsis - (if (char-displayable-p ?…) "…" "...") - "Ellipsis.") - -(defsubst doom-modeline-spc () - "Whitespace." - (propertize " " 'face (doom-modeline-face))) - -(defsubst doom-modeline-wspc () - "Wide Whitespace." - (propertize " " 'face (doom-modeline-face))) - -(defsubst doom-modeline-vspc () - "Thin whitespace." - (propertize " " - 'face (doom-modeline-face) - 'display '((space :relative-width 0.5)))) - -(defun doom-modeline-face (&optional face inactive-face) - "Display FACE in active window, and INACTIVE-FACE in inactive window. -IF FACE is nil, `mode-line' face will be used. -If INACTIVE-FACE is nil, `mode-line-inactive' face will be used." - (if (doom-modeline--active) - (or (and (facep face) `(:inherit (doom-modeline ,face))) - (and (facep 'mode-line-active) '(:inherit (doom-modeline mode-line-active))) - '(:inherit (doom-modeline mode-line))) - (or (and (facep face) `(:inherit (doom-modeline mode-line-inactive ,face))) - (and (facep inactive-face) `(:inherit (doom-modeline ,inactive-face))) - '(:inherit (doom-modeline mode-line-inactive))))) - -(defun doom-modeline-string-pixel-width (str) - "Return the width of STR in pixels." - (if (fboundp 'string-pixel-width) - (string-pixel-width str) - (* (string-width str) (window-font-width nil 'mode-line) - (if (display-graphic-p) 1.05 1.0)))) - -(defun doom-modeline--font-height () - "Calculate the actual char height of the mode-line." - (let ((height (face-attribute 'mode-line :height)) - (char-height (window-font-height nil 'mode-line))) - (round - (* 1.0 (cond ((integerp height) (/ height 10)) - ((floatp height) (* height char-height)) - (t char-height)))))) - -(defun doom-modeline--original-value (sym) - "Return the original value for SYM, if any. - -If SYM has an original value, return it in a list. Return nil -otherwise." - (let* ((orig-val-expr (get sym 'standard-value))) - (when (consp orig-val-expr) - (ignore-errors - (list - (eval (car orig-val-expr))))))) - -(defun doom-modeline-add-variable-watcher (symbol watch-function) - "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. - -See docs of `add-variable-watcher'." - (when (fboundp 'add-variable-watcher) - (add-variable-watcher symbol watch-function))) - -(defun doom-modeline-propertize-icon (icon &optional face) - "Propertize the ICON with the specified FACE. - -The face should be the first attribute, or the font family may be overridden. -So convert the face \":family XXX :height XXX :inherit XXX\" to -\":inherit XXX :family XXX :height XXX\". -See https://github.com/seagle0128/doom-modeline/issues/301." - (when icon - (if (doom-modeline-icon-displayable-p) - (when-let ((props (get-text-property 0 'face icon))) - (when (listp props) - (cl-destructuring-bind (&key family height inherit &allow-other-keys) props - (propertize icon 'face `(:inherit (doom-modeline ,(or face inherit props)) - :family ,(or family "") - :height ,(or height 1.0)))))) - (propertize icon 'face `(:inherit (doom-modeline ,face)))))) - -(defun doom-modeline-icon (icon-set icon-name unicode text &rest args) - "Display icon of ICON-NAME with ARGS in mode-line. - -ICON-SET includes `ipsicon', `octicon', `pomicon', `powerline', `faicon', -`wicon', `sucicon', `devicon', `codicon', `flicon' and `mdicon', etc. -UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. -ARGS is same as `nerd-icons-octicon' and others." - (let ((face `(:inherit (doom-modeline - ,(or (plist-get args :face) 'mode-line))))) - (cond - ;; Icon - ((and (doom-modeline-icon-displayable-p) - icon-name - (not (string-empty-p icon-name))) - (if-let* ((func (nerd-icons--function-name icon-set)) - (icon (and (fboundp func) - (apply func icon-name args)))) - (doom-modeline-propertize-icon icon face) - "")) - ;; Unicode fallback - ((and doom-modeline-unicode-fallback - unicode - (not (string-empty-p unicode)) - (char-displayable-p (string-to-char unicode))) - (propertize unicode 'face face)) - ;; ASCII text - (text - (propertize text 'face face)) - ;; Fallback - (t "")))) - -(defun doom-modeline-icon-for-buffer () - "Get the formatted icon for the current buffer." - (nerd-icons-icon-for-buffer)) - -(defun doom-modeline-display-icon (icon) - "Display ICON in mode-line." - (if (doom-modeline--active) - icon - (doom-modeline-propertize-icon icon 'mode-line-inactive))) - -(defun doom-modeline-display-text (text) - "Display TEXT in mode-line." - (if (doom-modeline--active) - text - (propertize text 'face `(:inherit (mode-line-inactive - ,(get-text-property 0 'face text)))))) - -(defun doom-modeline-vcs-name () - "Display the vcs name." - (and vc-mode (cadr (split-string (string-trim vc-mode) "^[A-Z]+[-:]+")))) - -(defun doom-modeline--create-bar-image (face width height) - "Create the bar image. - -Use FACE for the bar, WIDTH and HEIGHT are the image size in pixels." - (when (and (image-type-available-p 'pbm) - (numberp width) (> width 0) - (numberp height) (> height 0)) - (propertize - " " 'display - (let ((color (or (face-background face nil t) "None"))) - (ignore-errors - (create-image - (concat (format "P1\n%i %i\n" width height) - (make-string (* width height) ?1) - "\n") - 'pbm t :scale 1 :foreground color :ascent 'center)))))) - -(defun doom-modeline--create-hud-image - (face1 face2 width height top-margin bottom-margin) - "Create the hud image. - -Use FACE1 for the bar, FACE2 for the background. -WIDTH and HEIGHT are the image size in pixels. -TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, -respectively." - (when (and (display-graphic-p) - (image-type-available-p 'pbm) - (numberp width) (> width 0) - (numberp height) (> height 0)) - (let ((min-height (min height doom-modeline-hud-min-height))) - (unless (> (- height top-margin bottom-margin) min-height) - (let ((margin (- height min-height))) - (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) - bottom-margin (- margin top-margin))))) - (propertize - " " 'display - (let ((color1 (or (face-background face1 nil t) "None")) - (color2 (or (face-background face2 nil t) "None"))) - (create-image - (concat - (format "P1\n%i %i\n" width height) - (make-string (* top-margin width) ?0) - (make-string (* (- height top-margin bottom-margin) width) ?1) - (make-string (* bottom-margin width) ?0) - "\n") - 'pbm t :foreground color1 :background color2 :ascent 'center))))) - -;; Check whether `window-total-width' is smaller than the limit -(defun doom-modeline-window-size-change-function (&rest _) - "Function for `window-size-change-functions'." - (setq doom-modeline--limited-width-p - (cond - ((integerp doom-modeline-window-width-limit) - (<= (window-total-width) doom-modeline-window-width-limit)) - ((floatp doom-modeline-window-width-limit) - (<= (/ (window-total-width) (frame-width) 1.0) - doom-modeline-window-width-limit))))) - -(add-hook 'after-revert-hook #'doom-modeline-window-size-change-function) -(add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) -(add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) - -(defvar-local doom-modeline--project-root nil) -(defun doom-modeline--project-root () - "Get the path to the project root. -Return nil if no project was found." - (or doom-modeline--project-root - (setq doom-modeline--project-root - (cond - ((and (memq doom-modeline-project-detection '(auto ffip)) - (fboundp 'ffip-project-root)) - (let ((inhibit-message t)) - (ffip-project-root))) - ((and (memq doom-modeline-project-detection '(auto projectile)) - (bound-and-true-p projectile-mode)) - (projectile-project-root)) - ((and (memq doom-modeline-project-detection '(auto project)) - (fboundp 'project-current)) - (when-let ((project (project-current))) - (expand-file-name - (if (fboundp 'project-root) - (project-root project) - (car (with-no-warnings - (project-roots project))))))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-project-detection - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-project-detection val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (setq doom-modeline--project-root nil) - (and buffer-file-name (revert-buffer t t))))))) - -(defun doom-modeline-project-p () - "Check if the file is in a project." - (doom-modeline--project-root)) - -(defun doom-modeline-project-root () - "Get the path to the root of your project. -Return `default-directory' if no project was found." - (abbreviate-file-name - (or (doom-modeline--project-root) default-directory))) - -(defun doom-modeline--format-buffer-file-name () - "Get and format the buffer file name." - (let ((buffer-file-name (file-local-name - (or (buffer-file-name (buffer-base-buffer)) "")))) - (or (and doom-modeline-buffer-file-name-function - (funcall doom-modeline-buffer-file-name-function buffer-file-name)) - buffer-file-name))) - -(defun doom-modeline--format-buffer-file-truename (b-f-n) - "Get and format buffer file truename via B-F-N." - (let ((buffer-file-truename (file-local-name - (or (file-truename b-f-n) "")))) - (or (and doom-modeline-buffer-file-truename-function - (funcall doom-modeline-buffer-file-truename-function buffer-file-truename)) - buffer-file-truename))) - -(defun doom-modeline-buffer-file-name () - "Propertize file name based on `doom-modeline-buffer-file-name-style'." - (let* ((buffer-file-name (doom-modeline--format-buffer-file-name)) - (buffer-file-truename (doom-modeline--format-buffer-file-truename buffer-file-name)) - (file-name - (pcase doom-modeline-buffer-file-name-style - ('auto - (if (doom-modeline-project-p) - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide) - (propertize "%b" 'face 'doom-modeline-buffer-file))) - ('truncate-upto-project - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) - ('truncate-from-project - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) - ('truncate-with-project - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide)) - ('truncate-except-project - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink)) - ('truncate-upto-root - (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) - ('truncate-all - (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) - ('truncate-nil - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) - ('relative-to-project - (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) - ('relative-from-project - (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) - ('file-name - (propertize (file-name-nondirectory buffer-file-name) - 'face 'doom-modeline-buffer-file)) - ('file-name-with-project - (format "%s|%s" - (propertize (file-name-nondirectory - (directory-file-name (file-local-name (doom-modeline-project-root)))) - 'face 'doom-modeline-project-dir) - (propertize (file-name-nondirectory buffer-file-name) - 'face 'doom-modeline-buffer-file))) - ((or 'buffer-name _) - (propertize "%b" 'face 'doom-modeline-buffer-file))))) - (propertize (if (string-empty-p file-name) - (propertize "%b" 'face 'doom-modeline-buffer-file) - file-name) - 'mouse-face 'mode-line-highlight - 'help-echo (concat buffer-file-truename - (unless (string= (file-name-nondirectory buffer-file-truename) - (buffer-name)) - (concat "\n" (buffer-name))) - "\nmouse-1: Previous buffer\nmouse-3: Next buffer") - 'local-map mode-line-buffer-identification-keymap))) - -(defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) - "Propertize file name that truncates every dir along path. - -If TRUNCATE-TAIL is t also truncate the parent directory of the file." - (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) - (if (null dirs) - (propertize "%b" 'face 'doom-modeline-buffer-file) - (let ((dirname (car dirs)) - (basename (cdr dirs))) - (concat (propertize (concat dirname - (if truncate-tail (substring basename 0 1) basename) - "/") - 'face 'doom-modeline-project-root-dir) - (propertize (file-name-nondirectory file-path) - 'face 'doom-modeline-buffer-file)))))) - -(defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) - "Propertize file name showing directories relative to project's root only. - -If INCLUDE-PROJECT is non-nil, the project path will be included." - (let ((root (file-local-name (doom-modeline-project-root)))) - (if (null root) - (propertize "%b" 'face 'doom-modeline-buffer-file) - (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) - (if include-project (concat root "../") root)))) - (and (equal "./" relative-dirs) (setq relative-dirs "")) - (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) - (propertize (file-name-nondirectory true-file-path) - 'face 'doom-modeline-buffer-file)))))) - -(defun doom-modeline--buffer-file-name (file-path - true-file-path - &optional - truncate-project-root-parent - truncate-project-relative-path - hide-project-root-parent) - "Propertize buffer name given by FILE-PATH or TRUE-FILE-PATH. - -If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project -root parent down fish-shell style. - -Example: - ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el - -If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project -relative path down fish-shell style. - -Example: - ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el - -If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. - -Example: - ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" - (let ((project-root (file-local-name (doom-modeline-project-root)))) - (concat - ;; Project root parent - (unless hide-project-root-parent - (when-let (root-path-parent - (file-name-directory (directory-file-name project-root))) - (propertize - (if (and truncate-project-root-parent - (not (string-empty-p root-path-parent)) - (not (string= root-path-parent "/"))) - (shrink-path--dirs-internal root-path-parent t) - (abbreviate-file-name root-path-parent)) - 'face 'doom-modeline-project-parent-dir))) - ;; Project directory - (propertize - (concat (file-name-nondirectory (directory-file-name project-root)) "/") - 'face 'doom-modeline-project-dir) - ;; relative path - (propertize - (when-let (relative-path (file-relative-name - (or (file-name-directory - (if doom-modeline-buffer-file-true-name - true-file-path file-path)) - "./") - project-root)) - (if (string= relative-path "./") - "" - (if truncate-project-relative-path - (substring (shrink-path--dirs-internal relative-path t) 1) - relative-path))) - 'face 'doom-modeline-buffer-path) - ;; File name - (propertize (file-name-nondirectory file-path) - 'face 'doom-modeline-buffer-file)))) - -(provide 'doom-modeline-core) - -;;; doom-modeline-core.el ends here diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-core.elc b/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-core.elc Binary files differ. diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-pkg.el b/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-pkg.el @@ -1,17 +0,0 @@ -(define-package "doom-modeline" "20240811.1437" "A minimal and modern mode-line" - '((emacs "25.1") - (compat "29.1.4.5") - (nerd-icons "0.1.0") - (shrink-path "0.3.1")) - :commit "790e6817814a1fa893a91722861cba9424b0f004" :authors - '(("Vincent Zhang" . "seagle0128@gmail.com")) - :maintainers - '(("Vincent Zhang" . "seagle0128@gmail.com")) - :maintainer - '("Vincent Zhang" . "seagle0128@gmail.com") - :keywords - '("faces" "mode-line") - :url "https://github.com/seagle0128/doom-modeline") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-segments.el b/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-segments.el @@ -1,3257 +0,0 @@ -;;; doom-modeline-segments.el --- The segments for doom-modeline -*- lexical-binding: t; -*- - -;; Copyright (C) 2018-2024 Vincent Zhang - -;; This file is not part of GNU Emacs. - -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. -;; - -;;; Commentary: -;; -;; The segments for doom-modeline. -;; Use `doom-modeline-def-segment' to create a new segment. -;; - -;;; Code: - -(require 'doom-modeline-core) -(require 'doom-modeline-env) -(eval-when-compile - (require 'cl-lib) - (require 'seq) - (require 'subr-x)) - - -;; -;; Externals -;; - -(defvar Info-current-file) -(defvar Info-current-node) -(defvar Info-mode-line-node-keymap) -(defvar anzu--cached-count) -(defvar anzu--current-position) -(defvar anzu--overflow-p) -(defvar anzu--state) -(defvar anzu--total-matched) -(defvar anzu-cons-mode-line-p) -(defvar aw-keys) -(defvar battery-echo-area-format) -(defvar battery-load-critical) -(defvar battery-mode-line-format) -(defvar battery-mode-line-limit) -(defvar battery-status-function) -(defvar boon-command-state) -(defvar boon-insert-state) -(defvar boon-off-state) -(defvar boon-special-state) -(defvar display-time-string) -(defvar edebug-execution-mode) -(defvar eglot--managed-mode) -(defvar erc-modified-channels-alist) -(defvar evil-ex-active-highlights-alist) -(defvar evil-ex-argument) -(defvar evil-ex-range) -(defvar evil-mc-frozen) -(defvar evil-state) -(defvar evil-visual-beginning) -(defvar evil-visual-end) -(defvar evil-visual-selection) -(defvar flycheck--automatically-enabled-checkers) -(defvar flycheck-current-errors) -(defvar flycheck-mode-menu-map) -(defvar flymake--mode-line-format) -(defvar flymake--state) -(defvar flymake-menu) -(defvar gnus-newsrc-alist) -(defvar gnus-newsrc-hashtb) -(defvar grip--process) -(defvar helm--mode-line-display-prefarg) -(defvar iedit-occurrences-overlays) -(defvar kele-menu-map) -(defvar meow--indicator) -(defvar minions-mode-line-lighter) -(defvar minions-mode-line-minor-modes-map) -(defvar mlscroll-minimum-current-width) -(defvar mlscroll-right-align) -(defvar mu4e--modeline-item) -(defvar mu4e-alert-mode-line) -(defvar mu4e-alert-modeline-formatter) -(defvar mu4e-modeline-mode) -(defvar nyan-minimum-window-width) -(defvar objed--obj-state) -(defvar objed--object) -(defvar objed-modeline-setup-func) -(defvar persp-nil-name) -(defvar phi-replace--mode-line-format) -(defvar phi-search--overlays) -(defvar phi-search--selection) -(defvar phi-search-mode-line-format) -(defvar poke-line-minimum-window-width) -(defvar rcirc-activity) -(defvar sml-modeline-len) -(defvar symbol-overlay-keywords-alist) -(defvar symbol-overlay-temp-symbol) -(defvar text-scale-mode-amount) -(defvar tracking-buffers) -(defvar winum-auto-setup-mode-line) -(defvar xah-fly-insert-state-p) - -(declare-function anzu--reset-status "ext:anzu") -(declare-function anzu--where-is-here "ext:anzu") -(declare-function async-inject-variables "ext:async") -(declare-function async-start "ext:async") -(declare-function avy-traverse "ext:avy") -(declare-function avy-tree "ext:avy") -(declare-function aw-update "ext:ace-window") -(declare-function aw-window-list "ext:ace-window") -(declare-function battery-format "battery") -(declare-function battery-update "battery") -(declare-function boon-modeline-string "ext:boon") -(declare-function boon-state-string "ext:boon") -(declare-function cider--connection-info "ext:cider") -(declare-function cider-connected-p "ext:cider") -(declare-function cider-current-repl "ext:cider") -(declare-function cider-jack-in "ext:cider") -(declare-function cider-quit "ext:cider") -(declare-function citre-mode "ext:citre-basic-tools") -(declare-function compilation-goto-in-progress-buffer "compile") -(declare-function dap--cur-session "ext:dap-mode") -(declare-function dap--debug-session-name "ext:dap-mode") -(declare-function dap--debug-session-state "ext:dap-mode") -(declare-function dap--session-running "ext:dap-mode") -(declare-function dap-debug-recent "ext:dap-mode") -(declare-function dap-disconnect "ext:dap-mode") -(declare-function dap-hydra "ext:dap-hydra") -(declare-function edebug-help "edebug") -(declare-function edebug-next-mode "edebug") -(declare-function edebug-stop "edebug") -(declare-function eglot "ext:eglot") -(declare-function eglot--major-modes "ext:eglot" t t) -(declare-function eglot--project-nickname "ext:eglot" t t) -(declare-function eglot-clear-status "ext:eglot") -(declare-function eglot-current-server "ext:eglot") -(declare-function eglot-events-buffer "ext:eglot") -(declare-function eglot-forget-pending-continuations "ext:eglot") -(declare-function eglot-managed-p "ext:glot") -(declare-function eglot-reconnect "ext:eglot") -(declare-function eglot-shutdown "ext:eglot") -(declare-function eglot-stderr-buffer "ext:eglot") -(declare-function erc-switch-to-buffer "erc") -(declare-function erc-track-switch-buffer "erc-track") -(declare-function evil-delimited-arguments "ext:evil-common") -(declare-function evil-emacs-state-p "ext:evil-states" t t) -(declare-function evil-force-normal-state "ext:evil-commands" t t) -(declare-function evil-insert-state-p "ext:evil-states" t t) -(declare-function evil-motion-state-p "ext:evil-states" t t) -(declare-function evil-normal-state-p "ext:evil-states" t t) -(declare-function evil-operator-state-p "ext:evil-states" t t) -(declare-function evil-replace-state-p "ext:evil-states" t t) -(declare-function evil-state-property "ext:evil-common") -(declare-function evil-visual-state-p "ext:evil-states" t t) -(declare-function eyebrowse--get "ext:eyebrowse") -(declare-function face-remap-remove-relative "face-remap") -(declare-function fancy-narrow-active-p "ext:fancy-narrow") -(declare-function flycheck-buffer "ext:flycheck") -(declare-function flycheck-count-errors "ext:flycheck") -(declare-function flycheck-error-level-compilation-level "ext:flycheck") -(declare-function flycheck-list-errors "ext:flycheck") -(declare-function flycheck-next-error "ext:flycheck") -(declare-function flycheck-previous-error "ext:flycheck") -(declare-function flymake--diag-type "ext:flymake" t t) -(declare-function flymake--handle-report "ext:flymake") -(declare-function flymake--lookup-type-property "ext:flymake") -(declare-function flymake--state-diags "ext:flymake" t t) -(declare-function flymake-disabled-backends "ext:flymake") -(declare-function flymake-goto-next-error "ext:flymake") -(declare-function flymake-goto-prev-error "ext:flymake") -(declare-function flymake-reporting-backends "ext:flymake") -(declare-function flymake-running-backends "ext:flymake") -(declare-function flymake-show-buffer-diagnostics "ext:flymake") -(declare-function flymake-show-buffer-diagnostics "ext:flymake") -(declare-function flymake-start "ext:flymake") -(declare-function follow-all-followers "follow") -(declare-function gnus-demon-add-handler "gnus-demon") -(declare-function grip--preview-url "ext:grip-mode") -(declare-function grip-browse-preview "ext:grip-mode") -(declare-function grip-restart-preview "ext:grip-mode") -(declare-function grip-stop-preview "ext:grip-mode") -(declare-function helm-candidate-number-at-point "ext:helm-core") -(declare-function helm-get-candidate-number "ext:helm-core") -(declare-function iedit-find-current-occurrence-overlay "ext:iedit-lib") -(declare-function iedit-prev-occurrence "ext:iedit-lib") -(declare-function image-get-display-property "image-mode") -(declare-function jsonrpc--request-continuations "ext:jsonrpc" t t) -(declare-function jsonrpc-last-error "ext:jsonrpc" t t) -(declare-function kele-current-context-name "ext:kele") -(declare-function kele-current-namespace "ext:kele") -(declare-function lsp--workspace-print "ext:lsp-mode") -(declare-function lsp-describe-session "ext:lsp-mode") -(declare-function lsp-workspace-folders-open "ext:lsp-mode") -(declare-function lsp-workspace-restart "ext:lsp-mode") -(declare-function lsp-workspace-shutdown "ext:lsp-mode") -(declare-function lsp-workspaces "ext:lsp-mode") -(declare-function lv-message "ext:lv") -(declare-function mc/num-cursors "ext:multiple-cursors-core") -(declare-function meow--current-state "ext:meow") -(declare-function meow-beacon-mode-p "ext:meow") -(declare-function meow-insert-mode-p "ext:meow") -(declare-function meow-keypad-mode-p "ext:meow") -(declare-function meow-motion-mode-p "ext:meow") -(declare-function meow-normal-mode-p "ext:meow") -(declare-function minions--prominent-modes "ext:minions") -(declare-function mlscroll-mode-line "ext:mlscroll") -(declare-function mu4e--modeline-string "ext:mu4e-modeline") -(declare-function mu4e-alert-default-mode-line-formatter "ext:mu4e-alert") -(declare-function mu4e-alert-enable-mode-line-display "ext:mu4e-alert") -(declare-function nyan-create "ext:nyan-mode") -(declare-function org-edit-src-save "ext:org-src") -(declare-function parrot-create "ext:parrot") -(declare-function pdf-cache-number-of-pages "ext:pdf-cache" t t) -(declare-function persp-add-buffer "ext:persp-mode") -(declare-function persp-contain-buffer-p "ext:persp-mode") -(declare-function persp-switch "ext:persp-mode") -(declare-function phi-search--initialize "ext:phi-search") -(declare-function poke-line-create "ext:poke-line") -(declare-function popup-create "ext:popup") -(declare-function popup-delete "ext:popup") -(declare-function rcirc-next-active-buffer "rcirc") -(declare-function rcirc-short-buffer-name "rcirc") -(declare-function rcirc-switch-to-server-buffer "rcirc") -(declare-function rcirc-window-configuration-change "rcirc") -(declare-function rime--should-enable-p "ext:rime") -(declare-function rime--should-inline-ascii-p "ext:rime") -(declare-function sml-modeline-create "ext:sml-modeline") -(declare-function svg-circle "svg") -(declare-function svg-create "svg") -(declare-function svg-image "svg") -(declare-function svg-line "svg") -(declare-function symbol-overlay-assoc "ext:symbol-overlay") -(declare-function symbol-overlay-get-list "ext:symbol-overlay") -(declare-function symbol-overlay-get-symbol "ext:symbol-overlay") -(declare-function symbol-overlay-rename "ext:symbol-overlay") -(declare-function tab-bar--current-tab "tab-bar") -(declare-function tab-bar--current-tab-index "tab-bar") -(declare-function tracking-next-buffer "ext:tracking") -(declare-function tracking-previous-buffer "ext:tracking") -(declare-function tracking-shorten "ext:tracking") -(declare-function undo-tree-redo-1 "ext:undo-tree") -(declare-function undo-tree-undo-1 "ext:undo-tree") -(declare-function warning-numeric-level "warnings") -(declare-function window-numbering-clear-mode-line "ext:window-numbering") -(declare-function window-numbering-get-number-string "ext:window-numbering") -(declare-function window-numbering-install-mode-line "ext:window-numbering") -(declare-function winum--clear-mode-line "ext:winum") -(declare-function winum--install-mode-line "ext:winum") -(declare-function winum-get-number-string "ext:winum") - - - -;; -;; Buffer information -;; - -(defvar-local doom-modeline--buffer-file-icon nil) -(defun doom-modeline-update-buffer-file-icon (&rest _) - "Update file icon in mode-line." - (setq doom-modeline--buffer-file-icon - (when (and doom-modeline-major-mode-icon - (doom-modeline-icon-displayable-p)) - (let ((icon (doom-modeline-icon-for-buffer))) - (propertize (if (or (null icon) (symbolp icon)) - (doom-modeline-icon 'faicon "nf-fa-file_o" nil nil - :face 'nerd-icons-dsilver) - (doom-modeline-propertize-icon icon)) - 'help-echo (format "Major-mode: %s" (format-mode-line mode-name))))))) -(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-icon) -(add-hook 'after-change-major-mode-hook #'doom-modeline-update-buffer-file-icon) -(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-icon) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-buffer-file-icon)))))) - -(defun doom-modeline-buffer-file-state-icon (icon unicode text face) - "Displays an ICON of buffer state with FACE. -UNICODE and TEXT are the alternatives if it is not applicable. -Uses `nerd-icons-mdicon' to fetch the icon." - (doom-modeline-icon 'mdicon icon unicode text :face face)) - -(defvar-local doom-modeline--buffer-file-state-icon nil) -(defun doom-modeline-update-buffer-file-state-icon (&rest _) - "Update the buffer or file state in mode-line." - (setq doom-modeline--buffer-file-state-icon - (when doom-modeline-buffer-state-icon - (ignore-errors - (concat - (cond (buffer-read-only - (doom-modeline-buffer-file-state-icon - "nf-md-lock" "🔒" "%1*" - 'doom-modeline-warning)) - ((and buffer-file-name (buffer-modified-p) - doom-modeline-buffer-modification-icon) - (doom-modeline-buffer-file-state-icon - "nf-md-content_save_edit" "💾" "%1*" - 'doom-modeline-warning)) - ((and buffer-file-name - ;; Avoid freezing while connection is lost - (not (file-remote-p buffer-file-name)) - (not (file-exists-p buffer-file-name))) - (doom-modeline-buffer-file-state-icon - "nf-md-cancel" "🚫" "!" - 'doom-modeline-urgent)) - (t "")) - (when (or (buffer-narrowed-p) - (and (bound-and-true-p fancy-narrow-mode) - (fancy-narrow-active-p)) - (bound-and-true-p dired-narrow-mode)) - (doom-modeline-buffer-file-state-icon - "nf-md-unfold_less_horizontal" "↕" "><" - 'doom-modeline-warning))))))) - -(defvar-local doom-modeline--buffer-file-name nil) -(defun doom-modeline-update-buffer-file-name (&rest _) - "Update buffer file name in mode-line." - (setq doom-modeline--buffer-file-name - (ignore-errors - (save-match-data - (if buffer-file-name - (doom-modeline-buffer-file-name) - (propertize "%b" - 'face 'doom-modeline-buffer-file - 'mouse-face 'doom-modeline-highlight - 'help-echo "Buffer name -mouse-1: Previous buffer\nmouse-3: Next buffer" - 'local-map mode-line-buffer-identification-keymap)))))) -(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-name) -(add-hook 'after-save-hook #'doom-modeline-update-buffer-file-name) -(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-name) -(add-hook 'evil-insert-state-exit-hook #'doom-modeline-update-buffer-file-name) -(add-hook 'Info-selection-hook #'doom-modeline-update-buffer-file-name) -(advice-add #'rename-buffer :after #'doom-modeline-update-buffer-file-name) -(advice-add #'set-visited-file-name :after #'doom-modeline-update-buffer-file-name) -(advice-add #'pop-to-buffer :after #'doom-modeline-update-buffer-file-name) -(advice-add #'popup-create :after #'doom-modeline-update-buffer-file-name) -(advice-add #'popup-delete :after #'doom-modeline-update-buffer-file-name) -;; (advice-add #'primitive-undo :after #'doom-modeline-update-buffer-file-name) -;; (advice-add #'set-buffer-modified-p :after #'doom-modeline-update-buffer-file-name) - -(with-no-warnings - (if (boundp 'after-focus-change-function) - (progn - (advice-add #'handle-switch-frame :after #'doom-modeline-update-buffer-file-name) - (add-function :after after-focus-change-function #'doom-modeline-update-buffer-file-name)) - (progn - (add-hook 'focus-in-hook #'doom-modeline-update-buffer-file-name) - (add-hook 'focus-out-hook #'doom-modeline-update-buffer-file-name)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-buffer-file-name-style - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-buffer-file-name-style val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when buffer-file-name - (doom-modeline-update-buffer-file-name))))))) - -(defsubst doom-modeline--buffer-mode-icon () - "The icon of the current major mode." - (when (and doom-modeline-icon doom-modeline-major-mode-icon) - (when-let ((icon (or doom-modeline--buffer-file-icon - (doom-modeline-update-buffer-file-icon)))) - (unless (string-empty-p icon) - (concat - (if doom-modeline-major-mode-color-icon - (doom-modeline-display-icon icon) - (doom-modeline-propertize-icon - icon - (doom-modeline-face))) - (doom-modeline-vspc)))))) - -(defsubst doom-modeline--buffer-state-icon () - "The icon of the current buffer state." - (when doom-modeline-buffer-state-icon - (when-let ((icon (doom-modeline-update-buffer-file-state-icon))) - (unless (string-empty-p icon) - (concat - (doom-modeline-display-icon icon) - (doom-modeline-vspc)))))) - -(defsubst doom-modeline--buffer-simple-name () - "The buffer simple name." - (propertize "%b" - 'face (doom-modeline-face - (if (and doom-modeline-highlight-modified-buffer-name - (buffer-modified-p)) - 'doom-modeline-buffer-modified - 'doom-modeline-buffer-file)) - 'mouse-face 'doom-modeline-highlight - 'help-echo "Buffer name -mouse-1: Previous buffer\nmouse-3: Next buffer" - 'local-map mode-line-buffer-identification-keymap)) - -(defsubst doom-modeline--buffer-name () - "The current buffer name." - (when doom-modeline-buffer-name - (if (and (not (eq doom-modeline-buffer-file-name-style 'file-name)) - doom-modeline--limited-width-p) - ;; Only display the buffer name if the window is small, and doesn't - ;; need to respect file-name style. - (doom-modeline--buffer-simple-name) - (when-let ((name (or doom-modeline--buffer-file-name - (doom-modeline-update-buffer-file-name)))) - ;; Check if the buffer is modified - (if (and doom-modeline-highlight-modified-buffer-name - (buffer-modified-p)) - (propertize name 'face (doom-modeline-face 'doom-modeline-buffer-modified)) - (doom-modeline-display-text name)))))) - -(doom-modeline-def-segment buffer-info - "Combined information about the current buffer. - -Including the current working directory, the file name, and its state (modified, -read-only or non-existent)." - (concat - (doom-modeline-spc) - (doom-modeline--buffer-mode-icon) - (doom-modeline--buffer-state-icon) - (doom-modeline--buffer-name))) - -(doom-modeline-def-segment buffer-info-simple - "Display only the current buffer's name, but with fontification." - (concat - (doom-modeline-spc) - (doom-modeline--buffer-mode-icon) - (doom-modeline--buffer-state-icon) - (doom-modeline--buffer-simple-name))) - -(doom-modeline-def-segment calc - "Display calculator icons and info." - (concat - (doom-modeline-spc) - (when-let ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "🖩" ""))) - (concat - (doom-modeline-display-icon icon) - (doom-modeline-vspc))) - (doom-modeline--buffer-simple-name))) - -(doom-modeline-def-segment buffer-default-directory - "Displays `default-directory' with the icon and state. - -This is for special buffers like the scratch buffer where knowing the current -project directory is important." - (let ((face (doom-modeline-face - (if (and buffer-file-name (buffer-modified-p)) - 'doom-modeline-buffer-modified - 'doom-modeline-buffer-path)))) - (concat - (doom-modeline-spc) - (and doom-modeline-major-mode-icon - (concat - (doom-modeline-icon - 'octicon "nf-oct-file_directory_fill" "🖿" "" :face face) - (doom-modeline-vspc))) - (doom-modeline--buffer-state-icon) - (propertize (abbreviate-file-name default-directory) 'face face)))) - -(doom-modeline-def-segment buffer-default-directory-simple - "Displays `default-directory'. - -This is for special buffers like the scratch buffer where knowing the current -project directory is important." - (let ((face (doom-modeline-face 'doom-modeline-buffer-path))) - (concat - (doom-modeline-spc) - (and doom-modeline-major-mode-icon - (concat - (doom-modeline-icon - 'octicon "nf-oct-file_directory_fill" "🖿" "" :face face) - (doom-modeline-vspc))) - (propertize (abbreviate-file-name default-directory) 'face face)))) - - -;; -;; Encoding -;; - -(doom-modeline-def-segment buffer-encoding - "Displays the eol and the encoding style of the buffer." - (when doom-modeline-buffer-encoding - (let ((sep (doom-modeline-spc)) - (face (doom-modeline-face)) - (mouse-face 'doom-modeline-highlight)) - (concat - sep - - ;; eol type - (let ((eol (coding-system-eol-type buffer-file-coding-system))) - (when (or (eq doom-modeline-buffer-encoding t) - (and (eq doom-modeline-buffer-encoding 'nondefault) - (not (equal eol doom-modeline-default-eol-type)))) - (propertize - (pcase eol - (0 "LF ") - (1 "CRLF ") - (2 "CR ") - (_ "")) - 'face face - 'mouse-face mouse-face - 'help-echo (format "End-of-line style: %s\nmouse-1: Cycle" - (pcase eol - (0 "Unix-style LF") - (1 "DOS-style CRLF") - (2 "Mac-style CR") - (_ "Undecided"))) - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line mouse-1] 'mode-line-change-eol) - map)))) - - ;; coding system - (let* ((sys (coding-system-plist buffer-file-coding-system)) - (cat (plist-get sys :category)) - (sym (if (memq cat - '(coding-category-undecided coding-category-utf-8)) - 'utf-8 - (plist-get sys :name)))) - (when (or (eq doom-modeline-buffer-encoding t) - (and (eq doom-modeline-buffer-encoding 'nondefault) - (not (eq cat 'coding-category-undecided)) - (not (eq sym doom-modeline-default-coding-system)))) - (propertize - (upcase (symbol-name sym)) - 'face face - 'mouse-face mouse-face - 'help-echo 'mode-line-mule-info-help-echo - 'local-map mode-line-coding-system-map))) - - sep)))) - - -;; -;; Indentation -;; - -(doom-modeline-def-segment indent-info - "Displays the indentation information." - (when doom-modeline-indent-info - (let ((do-propertize - (lambda (mode size) - (propertize - (format " %s %d " mode size) - 'face (doom-modeline-face))))) - (if indent-tabs-mode - (funcall do-propertize "TAB" tab-width) - (let ((lookup-var - (seq-find (lambda (var) - (and var (boundp var) (symbol-value var))) - (cdr (assoc major-mode doom-modeline-indent-alist)) nil))) - (funcall do-propertize "SPC" - (if lookup-var - (symbol-value lookup-var) - tab-width))))))) - -;; -;; Remote host -;; - -(doom-modeline-def-segment remote-host - "Hostname for remote buffers." - (when default-directory - (when-let ((host (file-remote-p default-directory 'host))) - (propertize - (concat "@" host) - 'face (doom-modeline-face 'doom-modeline-host))))) - - -;; -;; Major mode -;; - -(doom-modeline-def-segment major-mode - "The major mode, including environment and text-scale info." - (let ((sep (doom-modeline-spc)) - (face (doom-modeline-face 'doom-modeline-buffer-major-mode))) - (concat - sep - (propertize (concat - (format-mode-line - (or (and (boundp 'delighted-modes) - (cadr (assq major-mode delighted-modes))) - mode-name)) - (when (and doom-modeline-env-version doom-modeline-env--version) - (format " %s" doom-modeline-env--version))) - 'help-echo "Major mode\n\ -mouse-1: Display major mode menu\n\ -mouse-2: Show help for major mode\n\ -mouse-3: Toggle minor modes" - 'face face - 'mouse-face 'doom-modeline-highlight - 'local-map mode-line-major-mode-keymap) - (and (boundp 'text-scale-mode-amount) - (/= text-scale-mode-amount 0) - (propertize - (format - (if (> text-scale-mode-amount 0) " (%+d)" " (%-d)") - text-scale-mode-amount) - 'face face)) - sep))) - - -;; -;; Process -;; - -(doom-modeline-def-segment process - "The process info." - (doom-modeline-display-text - (format-mode-line mode-line-process))) - - -;; -;; Minor modes -;; - -(doom-modeline-def-segment minor-modes - (when doom-modeline-minor-modes - (let ((sep (doom-modeline-spc)) - (face (doom-modeline-face 'doom-modeline-buffer-minor-mode)) - (mouse-face 'doom-modeline-highlight) - (help-echo "Minor mode - mouse-1: Display minor mode menu - mouse-2: Show help for minor mode - mouse-3: Toggle minor modes")) - (if (bound-and-true-p minions-mode) - `((:propertize ("" ,(minions--prominent-modes)) - face ,face - mouse-face ,mouse-face - help-echo ,help-echo - local-map ,mode-line-minor-mode-keymap) - ,sep - (:propertize ("" ,(doom-modeline-icon 'octicon "nf-oct-gear" "⚙" - minions-mode-line-lighter - :face face)) - mouse-face ,mouse-face - help-echo "Minions -mouse-1: Display minor modes menu" - local-map ,minions-mode-line-minor-modes-map) - ,sep) - `((:propertize ("" minor-mode-alist) - face ,face - mouse-face ,mouse-face - help-echo ,help-echo - local-map ,mode-line-minor-mode-keymap) - ,sep))))) - - -;; -;; VCS -;; - -(defun doom-modeline-vcs-icon (icon &optional unicode text face) - "Displays the vcs ICON with FACE and VOFFSET. - -UNICODE and TEXT are fallbacks. -Uses `nerd-icons-octicon' to fetch the icon." - (doom-modeline-icon 'devicon (and doom-modeline-vcs-icon icon) - unicode text :face face)) - -(defvar-local doom-modeline--vcs nil) -(defun doom-modeline-update-vcs (&rest _) - "Update vcs state in mode-line." - (setq doom-modeline--vcs - (when (and vc-mode buffer-file-name) - (let* ((backend (vc-backend buffer-file-name)) - (state (vc-state buffer-file-name backend)) - (icon (cond ((memq state '(edited added)) - (doom-modeline-vcs-icon "nf-dev-git_compare" "🔃" "*" 'doom-modeline-info)) - ((eq state 'needs-merge) - (doom-modeline-vcs-icon "nf-dev-git_merge" "🔀" "?" 'doom-modeline-info)) - ((eq state 'needs-update) - (doom-modeline-vcs-icon "nf-dev-git_pull_request" "⬇" "!" 'doom-modeline-warning)) - ((memq state '(removed conflict unregistered)) - (doom-modeline-icon 'octicon "nf-oct-alert" "⚠" "!" :face 'doom-modeline-urgent)) - (t (doom-modeline-vcs-icon "nf-dev-git_branch" "" "@" 'doom-modeline-info)))) - (str (or (and vc-display-status - (functionp #'doom-modeline-vcs-name) - (funcall #'doom-modeline-vcs-name)) - "")) - (face (cond ((eq state 'needs-update) - '(doom-modeline-warning bold)) - ((memq state '(removed conflict unregistered)) - '(doom-modeline-urgent bold)) - (t '(doom-modeline-info bold)))) - (text (propertize (if (length> str doom-modeline-vcs-max-length) - (concat - (substring str 0 (- doom-modeline-vcs-max-length 3)) - doom-modeline-ellipsis) - str) - 'face face))) - `((icon . ,icon) (text . ,text)))))) -(add-hook 'find-file-hook #'doom-modeline-update-vcs) -(add-hook 'after-save-hook #'doom-modeline-update-vcs) -(advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-vcs)))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-unicode-fallback - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-unicode-fallback val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-vcs)))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-vcs-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-vcs-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-vcs)))))) - -(doom-modeline-add-variable-watcher - 'vc-display-status - (lambda (_sym val op _where) - (when (eq op 'set) - (setq vc-display-status val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-vcs)))))) - -(doom-modeline-def-segment vcs - "Displays the current branch, colored based on its state." - (when doom-modeline--vcs - (let-alist doom-modeline--vcs - (let ((sep (doom-modeline-spc)) - (vsep (doom-modeline-vspc))) - (concat sep - (propertize (concat - (doom-modeline-display-icon .icon) - vsep - (doom-modeline-display-text .text)) - 'help-echo (get-text-property 1 'help-echo vc-mode) - 'mouse-face 'doom-modeline-highlight - 'local-map (get-text-property 1 'local-map vc-mode)) - sep))))) - - -;; -;; Check -;; - -(defun doom-modeline-check-icon (icon unicode text face) - "Displays the check ICON with FACE. - -UNICODE and TEXT are fallbacks. -Uses `nerd-icons-mdicon' to fetch the icon." - (doom-modeline-icon 'mdicon (and doom-modeline-check-icon icon) - unicode text :face face)) - -(defun doom-modeline-check-text (text &optional face) - "Displays the check TEXT with FACE." - (propertize text 'face (or face 'mode-line))) - -;; Flycheck - -(defun doom-modeline--flycheck-count-errors () - "Count the number of ERRORS, grouped by level. - -Return an alist, where each ITEM is a cons cell whose `car' is an -error level, and whose `cdr' is the number of errors of that -level." - (let ((info 0) (warning 0) (error 0)) - (mapc - (lambda (item) - (let ((count (cdr item))) - (pcase (flycheck-error-level-compilation-level (car item)) - (0 (cl-incf info count)) - (1 (cl-incf warning count)) - (2 (cl-incf error count))))) - (flycheck-count-errors flycheck-current-errors)) - `((info . ,info) (warning . ,warning) (error . ,error)))) - -(defvar-local doom-modeline--flycheck nil) -(defun doom-modeline-update-flycheck (&optional status) - "Update flycheck via STATUS." - (setq doom-modeline--flycheck - (let-alist (doom-modeline--flycheck-count-errors) - (let* ((vsep (doom-modeline-vspc)) - (seg (if doom-modeline-check-simple-format - (let ((count (+ .error .warning .info))) - (pcase status - ('finished (if (> count 0) - (let ((face (if (> .error 0) 'doom-modeline-urgent 'doom-modeline-warning))) - (concat - (doom-modeline-check-icon "nf-md-alert_circle_outline" "⚠" "!" face) - vsep - (doom-modeline-check-text (number-to-string count) face))) - (doom-modeline-check-icon "nf-md-check_circle_outline" "✔" "*" 'doom-modeline-info))) - ('running (concat - (doom-modeline-check-icon "nf-md-timer_sand" "⏳" "*" 'doom-modeline-debug) - (when (> count 0) - (concat - vsep - (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug))))) - ('no-checker (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "-" 'doom-modeline-debug)) - ('errored (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-urgent)) - ('interrupted (doom-modeline-check-icon "nf-md-pause_circle_outline" "⦷" "." 'doom-modeline-debug)) - ('suspicious (doom-modeline-check-icon "nf-md-file_question_outline" "❓" "?" 'doom-modeline-debug)) - (_ ""))) - (concat (doom-modeline-check-icon "nf-md-close_circle_outline" "⮾" "!" 'doom-modeline-urgent) - vsep - (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent) - vsep - (doom-modeline-check-icon "nf-md-alert_outline" "⚠" "!" 'doom-modeline-warning) - vsep - (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning) - vsep - (doom-modeline-check-icon "nf-md-information_outline" "🛈" "!" 'doom-modeline-info) - vsep - (doom-modeline-check-text (number-to-string .info) 'doom-modeline-info))))) - (propertize seg - 'help-echo (concat "Flycheck\n" - (pcase status - ('finished (format "error: %d, warning: %d, info: %d" .error .warning .info)) - ('running "Checking...") - ('no-checker "No Checker") - ('errored "Error") - ('interrupted "Interrupted") - ('suspicious "Suspicious")) - "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode") - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line down-mouse-1] - flycheck-mode-menu-map) - (define-key map [mode-line mouse-2] - (lambda () - (interactive) - (describe-function 'flycheck-mode))) - map)))))) -(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck) -(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flycheck-mode) - (doom-modeline-update-flycheck))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-check-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-check-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flycheck-mode) - (doom-modeline-update-flycheck))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-unicode-fallback - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-unicode-fallback val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flycheck-mode) - (doom-modeline-update-flycheck))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-check-simple-format - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-check-simple-format val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flycheck-mode) - (doom-modeline-update-flycheck))))))) - -;; Flymake - -;; Compatibility -;; @see https://github.com/emacs-mirror/emacs/commit/6e100869012da9244679696634cab6b9cac96303. -(with-eval-after-load 'flymake - (unless (boundp 'flymake--state) - (defvaralias 'flymake--state 'flymake--backend-state)) - (unless (fboundp 'flymake--state-diags) - (defalias 'flymake--state-diags 'flymake--backend-state-diags))) - -(defun doom-modeline--flymake-count-errors () - "Count the number of ERRORS, grouped by level." - (let ((warning-level (warning-numeric-level :warning)) - (note-level (warning-numeric-level :debug)) - (note 0) (warning 0) (error 0)) - (maphash (lambda (_b state) - (cl-loop - with diags = (flymake--state-diags state) - for diag in diags do - (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity - (warning-numeric-level :error)))) - (cond ((> severity warning-level) (cl-incf error)) - ((> severity note-level) (cl-incf warning)) - (t (cl-incf note)))))) - flymake--state) - `((note . ,note) (warning . ,warning) (error . ,error)))) - -(defvar-local doom-modeline--flymake nil) -(defun doom-modeline-update-flymake (&rest _) - "Update flymake." - (setq doom-modeline--flymake - (let* ((known (hash-table-keys flymake--state)) - (running (flymake-running-backends)) - (disabled (flymake-disabled-backends)) - (reported (flymake-reporting-backends)) - (all-disabled (and disabled (null running))) - (some-waiting (cl-set-difference running reported))) - (let-alist (doom-modeline--flymake-count-errors) - (let* ((vsep (doom-modeline-vspc)) - (seg (if doom-modeline-check-simple-format - (let ((count (+ .error .warning .note))) - (cond - (some-waiting (concat - (doom-modeline-check-icon "nf-md-timer_sand" "⏳" "*" 'doom-modeline-debug) - (when (> count 0) - (concat - vsep - (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug))))) - ((null known) (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-urgent)) - (all-disabled (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-warning)) - (t (if (> count 0) - (let ((face (cond ((> .error 0) 'doom-modeline-urgent) - ((> .warning 0) 'doom-modeline-warning) - (t 'doom-modeline-info)))) - (concat - (doom-modeline-check-icon "nf-md-alert_circle_outline" "⚠" "!" face) - vsep - (doom-modeline-check-text (number-to-string count) face))) - (doom-modeline-check-icon "nf-md-check_circle_outline" "✔" "*" 'doom-modeline-info))))) - (concat - (doom-modeline-check-icon "nf-md-close_circle_outline" "⮾" "!" 'doom-modeline-urgent) - vsep - (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent) - vsep - (doom-modeline-check-icon "nf-md-alert_outline" "⚠" "!" 'doom-modeline-warning) - vsep - (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning) - vsep - (doom-modeline-check-icon "nf-md-information_outline" "🛈" "!" 'doom-modeline-info) - vsep - (doom-modeline-check-text (number-to-string .note) 'doom-modeline-info))))) - (propertize - seg - 'help-echo (concat - "Flymake\n" - (cond (some-waiting "Checking...") - ((null known) "No Checker") - (all-disabled "All Checkers Disabled") - (t (format "%d/%d backends running\nerror: %d, warning: %d, note: %d" - (length running) (length known) .error .warning .note))) - "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode") - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line down-mouse-1] - flymake-menu) - (define-key map [mode-line mouse-2] - (lambda () - (interactive) - (describe-function 'flymake-mode))) - map))))))) -(advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flymake-mode) - (doom-modeline-update-flymake))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-check-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-check-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flymake-mode) - (doom-modeline-update-flymake))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-unicode-fallback - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-unicode-fallback val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flymake-mode) - (doom-modeline-update-flymake))))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-check-simple-format - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-check-simple-format val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (when (bound-and-true-p flymake-mode) - (doom-modeline-update-flymake))))))) - -(doom-modeline-def-segment check - "Displays color-coded error status in the current buffer with pretty icons." - (when-let ((sep (doom-modeline-spc)) - (vsep (doom-modeline-vspc)) - (seg (cond - ((and (bound-and-true-p flymake-mode) - (bound-and-true-p flymake--state)) ; only support 26+ - doom-modeline--flymake) - ((and (bound-and-true-p flycheck-mode) - (bound-and-true-p flycheck--automatically-enabled-checkers)) - doom-modeline--flycheck)))) - (concat - sep - (let ((str)) - (dolist (s (split-string seg " ")) - (setq str - (concat str - (if (string-match-p "^[0-9]+$" s) - (concat vsep - (doom-modeline-display-text s) - vsep) - (doom-modeline-display-icon s))))) - (propertize str - 'help-echo (get-text-property 0 'help-echo seg) - 'mouse-face 'doom-modeline-highlight - 'local-map (get-text-property 0 'local-map seg))) - sep))) - - -;; -;; Word Count -;; - -(doom-modeline-def-segment word-count - "The buffer word count. -Displayed when in a major mode in `doom-modeline-continuous-word-count-modes'. -Respects `doom-modeline-enable-word-count'." - (when (and doom-modeline-enable-word-count - (member major-mode doom-modeline-continuous-word-count-modes)) - (propertize (format " %dW" (count-words (point-min) (point-max))) - 'face (doom-modeline-face)))) - - -;; -;; Selection -;; - -(defsubst doom-modeline-column (pos) - "Get the column of the position `POS'." - (save-excursion (goto-char pos) - (current-column))) - -(doom-modeline-def-segment selection-info - "Information about the current selection. - -Such as how many characters and lines are selected, or the NxM dimensions of a -block selection." - (when (and (or mark-active (and (bound-and-true-p evil-local-mode) - (eq evil-state 'visual))) - (doom-modeline--active)) - (cl-destructuring-bind (beg . end) - (if (and (bound-and-true-p evil-local-mode) (eq evil-state 'visual)) - (cons evil-visual-beginning evil-visual-end) - (cons (region-beginning) (region-end))) - (propertize - (let ((lines (count-lines beg (min end (point-max))))) - (concat - " " - (cond ((or (bound-and-true-p rectangle-mark-mode) - (and (bound-and-true-p evil-visual-selection) - (eq 'block evil-visual-selection))) - (let ((cols (abs (- (doom-modeline-column end) - (doom-modeline-column beg))))) - (format "%dx%dB" lines cols))) - ((and (bound-and-true-p evil-visual-selection) - (eq evil-visual-selection 'line)) - (format "%dL" lines)) - ((> lines 1) - (format "%dC %dL" (- end beg) lines)) - (t - (format "%dC" (- end beg)))) - (when doom-modeline-enable-word-count - (format " %dW" (count-words beg end))) - " ")) - 'face 'doom-modeline-emphasis)))) - - -;; -;; Matches (macro, anzu, evil-substitute, iedit, symbol-overlay and multi-cursors) -;; - -(defsubst doom-modeline--macro-recording () - "Display current Emacs or evil macro being recorded." - (when (and (doom-modeline--active) - (or defining-kbd-macro executing-kbd-macro)) - (let ((sep (propertize " " 'face 'doom-modeline-panel)) - (vsep (propertize " " 'face - '(:inherit (doom-modeline-panel variable-pitch)))) - (macro-name (if (bound-and-true-p evil-this-macro) - (format " @%s " - (char-to-string evil-this-macro)) - "Macro"))) - (concat - sep - (if doom-modeline-always-show-macro-register - (propertize macro-name 'face 'doom-modeline-panel) - (concat - (doom-modeline-icon 'mdicon "nf-md-record" "●" - macro-name - :face '(:inherit (doom-modeline-urgent doom-modeline-panel)) - :v-adjust 0.15) - vsep - (doom-modeline-icon 'mdicon "nf-md-menu_right" "▶" ">" - :face 'doom-modeline-panel - :v-adjust 0.15))) - sep)))) - -;; `anzu' and `evil-anzu' expose current/total state that can be displayed in the -;; mode-line. -(defun doom-modeline-fix-anzu-count (positions here) - "Calulate anzu count via POSITIONS and HERE." - (cl-loop with i = 0 - for (start . end) in positions - do (cl-incf i) - when (and (>= here start) (<= here end)) - return i - finally return 0)) - -(advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count) - -(setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves -;; Ensure anzu state is cleared when searches & iedit are done -(with-eval-after-load 'anzu - (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) - (add-hook 'iedit-mode-end-hook #'anzu--reset-status) - (advice-add #'evil-force-normal-state :after #'anzu--reset-status) - ;; Fix matches segment mirroring across all buffers - (mapc #'make-variable-buffer-local - '(anzu--total-matched - anzu--current-position anzu--state anzu--cached-count - anzu--cached-positions anzu--last-command - anzu--last-isearch-string anzu--overflow-p))) - -(defsubst doom-modeline--anzu () - "Show the match index and total number thereof. -Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with -`evil-search'." - (when (and (bound-and-true-p anzu--state) - (not (bound-and-true-p iedit-mode))) - (propertize - (let ((here anzu--current-position) - (total anzu--total-matched)) - (cond ((eq anzu--state 'replace-query) - (format " %d replace " anzu--cached-count)) - ((eq anzu--state 'replace) - (format " %d/%d " here total)) - (anzu--overflow-p - (format " %s+ " total)) - (t - (format " %s/%d " here total)))) - 'face (doom-modeline-face 'doom-modeline-panel)))) - -(defsubst doom-modeline--evil-substitute () - "Show number of matches for `evil-ex' in real time. -The number of matches contains substitutions and highlightings." - (when (and (bound-and-true-p evil-local-mode) - (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist) - (assq 'evil-ex-global-match evil-ex-active-highlights-alist) - (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist))) - (propertize - (let ((range (if evil-ex-range - (cons (car evil-ex-range) (cadr evil-ex-range)) - (cons (line-beginning-position) (line-end-position)))) - (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2)))) - (if pattern - (format " %s matches " (how-many pattern (car range) (cdr range))) - " - ")) - 'face (doom-modeline-face 'doom-modeline-panel)))) - -(defun doom-modeline-themes--overlay-sort (a b) - "Sort overlay A and B." - (< (overlay-start a) (overlay-start b))) - -(defsubst doom-modeline--iedit () - "Show the number of iedit regions matches + what match you're on." - (when (and (bound-and-true-p iedit-mode) - (bound-and-true-p iedit-occurrences-overlays)) - (propertize - (let ((this-oc (or (let ((inhibit-message t)) - (iedit-find-current-occurrence-overlay)) - (save-excursion (iedit-prev-occurrence) - (iedit-find-current-occurrence-overlay)))) - (length (length iedit-occurrences-overlays))) - (format " %s/%d " - (if this-oc - (- length - (length (memq this-oc (sort (append iedit-occurrences-overlays nil) - #'doom-modeline-themes--overlay-sort))) - -1) - "-") - length)) - 'face (doom-modeline-face 'doom-modeline-panel)))) - -(defsubst doom-modeline--symbol-overlay () - "Show the number of matches for symbol overlay." - (when (and (doom-modeline--active) - (bound-and-true-p symbol-overlay-keywords-alist) - (not (bound-and-true-p symbol-overlay-temp-symbol)) - (not (bound-and-true-p iedit-mode))) - (let* ((keyword (symbol-overlay-assoc (symbol-overlay-get-symbol t))) - (symbol (car keyword)) - (before (symbol-overlay-get-list -1 symbol)) - (after (symbol-overlay-get-list 1 symbol)) - (count (length before))) - (if (symbol-overlay-assoc symbol) - (propertize - (format (concat " %d/%d " (and (cadr keyword) "in scope ")) - (+ count 1) - (+ count (length after))) - 'face (doom-modeline-face 'doom-modeline-panel)))))) - -(defsubst doom-modeline--multiple-cursors () - "Show the number of multiple cursors." - (cl-destructuring-bind (count . face) - (cond ((bound-and-true-p multiple-cursors-mode) - (cons (mc/num-cursors) - (doom-modeline-face 'doom-modeline-panel))) - ((bound-and-true-p evil-mc-cursor-list) - (cons (length evil-mc-cursor-list) - (doom-modeline-face (if evil-mc-frozen - 'doom-modeline-bar - 'doom-modeline-panel)))) - ((cons nil nil))) - (when count - (concat (propertize " " 'face face) - (if (doom-modeline-icon-displayable-p) - (doom-modeline-icon 'faicon "nf-fa-i_cursor" "" "" :face face) - (propertize "I" - 'face `(:inherit ,face :height 1.4 :weight normal) - 'display '(raise -0.1))) - (propertize " " - 'face `(:inherit (variable-pitch ,face))) - (propertize (format "%d " count) - 'face face))))) - -(defsubst doom-modeline--phi-search () - "Show the number of matches for `phi-search' and `phi-replace'." - (when (and (doom-modeline--active) - (bound-and-true-p phi-search--overlays)) - (let ((total (length phi-search--overlays)) - (selection phi-search--selection)) - (when selection - (propertize - (format " %d/%d " (1+ selection) total) - 'face (doom-modeline-face 'doom-modeline-panel)))))) - -(defun doom-modeline--override-phi-search (orig-fun &rest args) - "Override the mode-line of `phi-search' and `phi-replace'. -Apply ORIG-FUN with ARGS." - (if (bound-and-true-p doom-modeline-mode) - (apply orig-fun mode-line-format (cdr args)) - (apply orig-fun args))) -(advice-add #'phi-search--initialize :around #'doom-modeline--override-phi-search) - -(defsubst doom-modeline--buffer-size () - "Show buffer size." - (when size-indication-mode - (let ((sep (doom-modeline-spc))) - (concat sep - (propertize "%I" - 'face (doom-modeline-face) - 'help-echo "Buffer size -mouse-1: Display Line and Column Mode Menu" - 'mouse-face 'doom-modeline-highlight - 'local-map mode-line-column-line-number-mode-map) - sep)))) - -(doom-modeline-def-segment matches - "Displays matches. - -Including: -1. the currently recording macro, 2. A current/total for the -current search term (with `anzu'), 3. The number of substitutions being -conducted with `evil-ex-substitute', and/or 4. The number of active `iedit' -regions, 5. The current/total for the highlight term (with `symbol-overlay'), -6. The number of active `multiple-cursors'." - (let ((meta (concat (doom-modeline--macro-recording) - (doom-modeline--anzu) - (doom-modeline--phi-search) - (doom-modeline--evil-substitute) - (doom-modeline--iedit) - (doom-modeline--symbol-overlay) - (doom-modeline--multiple-cursors)))) - (or (and (not (string-empty-p meta)) meta) - (doom-modeline--buffer-size)))) - -(doom-modeline-def-segment buffer-size - "Display buffer size." - (doom-modeline--buffer-size)) - -;; -;; Media -;; - -(doom-modeline-def-segment media-info - "Metadata regarding the current file, such as dimensions for images." - ;; TODO: Include other information - (cond ((eq major-mode 'image-mode) - (cl-destructuring-bind (width . height) - (when (fboundp 'image-size) - (image-size (image-get-display-property) :pixels)) - (format " %dx%d " width height))))) - - -;; -;; Bars -;; - -(defvar doom-modeline--bar-active nil) -(defvar doom-modeline--bar-inactive nil) - -(defsubst doom-modeline--bar () - "The default bar regulates the height of the mode-line in GUI." - (unless (and doom-modeline--bar-active doom-modeline--bar-inactive) - (let ((width doom-modeline-bar-width) - (height (max doom-modeline-height (doom-modeline--font-height)))) - (setq doom-modeline--bar-active - (doom-modeline--create-bar-image 'doom-modeline-bar width height) - doom-modeline--bar-inactive - (doom-modeline--create-bar-image - 'doom-modeline-bar-inactive width height)))) - (if (doom-modeline--active) - doom-modeline--bar-active - doom-modeline--bar-inactive)) - -(defun doom-modeline-refresh-bars () - "Refresh mode-line bars on next redraw." - (setq doom-modeline--bar-active nil - doom-modeline--bar-inactive nil)) - -(cl-defstruct doom-modeline--hud-cache active inactive top-margin bottom-margin) - -(defsubst doom-modeline--hud () - "Powerline's hud segment reimplemented in the style of Doom's bar segment." - (let* ((ws (window-start)) - (we (window-end)) - (bs (buffer-size)) - (height (max doom-modeline-height (doom-modeline--font-height))) - (top-margin (if (zerop bs) - 0 - (/ (* height (1- ws)) bs))) - (bottom-margin (if (zerop bs) - 0 - (max 0 (/ (* height (- bs we 1)) bs)))) - (cache (or (window-parameter nil 'doom-modeline--hud-cache) - (set-window-parameter - nil - 'doom-modeline--hud-cache - (make-doom-modeline--hud-cache))))) - (unless (and (doom-modeline--hud-cache-active cache) - (doom-modeline--hud-cache-inactive cache) - (= top-margin (doom-modeline--hud-cache-top-margin cache)) - (= bottom-margin - (doom-modeline--hud-cache-bottom-margin cache))) - (setf (doom-modeline--hud-cache-active cache) - (doom-modeline--create-hud-image - 'doom-modeline-bar 'default doom-modeline-bar-width - height top-margin bottom-margin) - (doom-modeline--hud-cache-inactive cache) - (doom-modeline--create-hud-image - 'doom-modeline-bar-inactive 'default doom-modeline-bar-width - height top-margin bottom-margin) - (doom-modeline--hud-cache-top-margin cache) top-margin - (doom-modeline--hud-cache-bottom-margin cache) bottom-margin)) - (if (doom-modeline--active) - (doom-modeline--hud-cache-active cache) - (doom-modeline--hud-cache-inactive cache)))) - -(defun doom-modeline-invalidate-huds () - "Invalidate all cached hud images." - (dolist (frame (frame-list)) - (dolist (window (window-list frame)) - (set-window-parameter window 'doom-modeline--hud-cache nil)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-height - (lambda (_sym val op _where) - (when (and (eq op 'set) (integerp val)) - (doom-modeline-refresh-bars) - (doom-modeline-invalidate-huds)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-bar-width - (lambda (_sym val op _where) - (when (and (eq op 'set) (integerp val)) - (doom-modeline-refresh-bars) - (doom-modeline-invalidate-huds)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym _val op _where) - (when (eq op 'set) - (doom-modeline-refresh-bars) - (doom-modeline-invalidate-huds)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-unicode-fallback - (lambda (_sym _val op _where) - (when (eq op 'set) - (doom-modeline-refresh-bars) - (doom-modeline-invalidate-huds)))) - -(add-hook 'window-configuration-change-hook #'doom-modeline-refresh-bars) -(add-hook 'window-configuration-change-hook #'doom-modeline-invalidate-huds) - -(doom-modeline-def-segment bar - "The bar regulates the height of the `doom-modeline' in GUI." - (when (display-graphic-p) - (concat - (if doom-modeline-hud - (doom-modeline--hud) - (doom-modeline--bar)) - (doom-modeline-spc)))) - -(doom-modeline-def-segment hud - "Powerline's hud segment reimplemented in the style of bar segment." - (when (display-graphic-p) - (concat - (doom-modeline--hud) - (doom-modeline-spc)))) - - -;; -;; Window number -;; - -;; HACK: `ace-window-display-mode' should respect the ignore buffers. -(defun doom-modeline-aw-update () - "Update ace-window-path window parameter for all windows. -Ensure all windows are labeled so the user can select a specific -one. The ignored buffers are excluded unless `aw-ignore-on' is nil." - (let ((ignore-window-parameters t)) - (avy-traverse - (avy-tree (aw-window-list) aw-keys) - (lambda (path leaf) - (set-window-parameter - leaf 'ace-window-path - (propertize - (apply #'string (reverse path)) - 'face 'aw-mode-line-face)))))) -(advice-add #'aw-update :override #'doom-modeline-aw-update) - -;; Remove original window number of `ace-window-display-mode'. -(add-hook 'ace-window-display-mode-hook - (lambda () - (setq-default mode-line-format - (assq-delete-all 'ace-window-display-mode - (default-value 'mode-line-format))))) - -(advice-add #'window-numbering-install-mode-line :override #'ignore) -(advice-add #'window-numbering-clear-mode-line :override #'ignore) -(advice-add #'winum--install-mode-line :override #'ignore) -(advice-add #'winum--clear-mode-line :override #'ignore) - -(doom-modeline-def-segment window-number - "The current window number." - (let ((num (cond - ((bound-and-true-p ace-window-display-mode) - (aw-update) - (window-parameter (selected-window) 'ace-window-path)) - ((bound-and-true-p winum-mode) - (setq winum-auto-setup-mode-line nil) - (winum-get-number-string)) - ((bound-and-true-p window-numbering-mode) - (window-numbering-get-number-string)) - (t "")))) - (when (and (length> num 0) - (length> (cl-mapcan - (lambda (frame) - ;; Exclude minibuffer, tooltip and child frames - (unless (or (and (fboundp 'frame-parent) (frame-parent frame)) - (string= (frame-parameter frame 'name) - (alist-get 'name (bound-and-true-p tooltip-frame-parameters)))) - (window-list frame 'never))) - (visible-frame-list)) - 1)) - (propertize (format " %s " num) - 'face (doom-modeline-face 'doom-modeline-buffer-major-mode))))) - - -;; -;; Workspace -;; - -(doom-modeline-def-segment workspace-name - "The current workspace name or number. -Requires `eyebrowse-mode' to be enabled or `tab-bar-mode' tabs to be created." - (when doom-modeline-workspace-name - (when-let - ((name (cond - ((and (bound-and-true-p eyebrowse-mode) - (length> (eyebrowse--get 'window-configs) 1)) - (setq mode-line-misc-info - (assq-delete-all 'eyebrowse-mode mode-line-misc-info)) - (when-let* - ((num (eyebrowse--get 'current-slot)) - (tag (nth 2 (assoc num (eyebrowse--get 'window-configs))))) - (if (length> tag 0) tag (int-to-string num)))) - ((and (fboundp 'tab-bar-mode) - (length> (frame-parameter nil 'tabs) 1)) - (let* ((current-tab (tab-bar--current-tab)) - (tab-index (tab-bar--current-tab-index)) - (explicit-name (alist-get 'explicit-name current-tab)) - (tab-name (alist-get 'name current-tab))) - (if explicit-name tab-name (+ 1 tab-index))))))) - (propertize (format " %s " name) - 'face (doom-modeline-face 'doom-modeline-buffer-major-mode))))) - - -;; -;; Perspective -;; - -(defvar-local doom-modeline--persp-name nil) -(defun doom-modeline-update-persp-name (&rest _) - "Update perspective name in mode-line." - (setq doom-modeline--persp-name - ;; Support `persp-mode', while not support `perspective' - (when (and doom-modeline-persp-name - (bound-and-true-p persp-mode) - (fboundp 'safe-persp-name) - (fboundp 'get-current-persp)) - (let* ((persp (get-current-persp)) - (name (safe-persp-name persp)) - (face (if (and persp - (not (persp-contain-buffer-p (current-buffer) persp))) - 'doom-modeline-persp-buffer-not-in-persp - 'doom-modeline-persp-name)) - (icon (doom-modeline-icon 'octicon "nf-oct-repo" "🖿" "#" - :face `(:inherit ,face :slant normal)))) - (when (or doom-modeline-display-default-persp-name - (not (string-equal persp-nil-name name))) - (concat " " - (propertize (concat (and doom-modeline-persp-icon - (concat icon - (propertize - " " - 'display '((space :relative-width 0.5))))) - (propertize name 'face face)) - 'help-echo "mouse-1: Switch perspective -mouse-2: Show help for minor mode" - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line mouse-1] - #'persp-switch) - (define-key map [mode-line mouse-2] - (lambda () - (interactive) - (describe-function 'persp-mode))) - map)) - " ")))))) - -(add-hook 'buffer-list-update-hook #'doom-modeline-update-persp-name) -(add-hook 'find-file-hook #'doom-modeline-update-persp-name) -(add-hook 'persp-activated-functions #'doom-modeline-update-persp-name) -(add-hook 'persp-renamed-functions #'doom-modeline-update-persp-name) -(advice-add #'lv-message :after #'doom-modeline-update-persp-name) - -(doom-modeline-def-segment persp-name - "The current perspective name." - (when (doom-modeline--segment-visible 'persp-name) - doom-modeline--persp-name)) - - -;; -;; Misc info -;; - -(doom-modeline-def-segment misc-info - "Mode line construct for miscellaneous information. -By default, this shows the information specified by `global-mode-string'." - (when (and (doom-modeline--segment-visible 'misc-info) - (or doom-modeline-display-misc-in-all-mode-lines - (doom-modeline--active))) - (doom-modeline-display-text - (format-mode-line mode-line-misc-info)))) - - -;; -;; Position -;; - -(doom-modeline-def-segment buffer-position - "The buffer position information." - (let ((visible (doom-modeline--segment-visible 'buffer-position)) - (sep (doom-modeline-spc)) - (wsep (doom-modeline-wspc)) - (face (doom-modeline-face)) - (help-echo "Buffer percentage\n\ -mouse-1: Display Line and Column Mode Menu") - (mouse-face 'doom-modeline-highlight) - (local-map mode-line-column-line-number-mode-map)) - `(,wsep - - ;; Line and column - (:propertize - ((line-number-mode - (column-number-mode - (doom-modeline-column-zero-based - doom-modeline-position-column-line-format - ,(string-replace - "%c" "%C" (car doom-modeline-position-column-line-format))) - doom-modeline-position-line-format) - (column-number-mode - (doom-modeline-column-zero-based - doom-modeline-position-column-format - ,(string-replace - "%c" "%C" (car doom-modeline-position-column-format))))) - (doom-modeline-total-line-number - ,(format "/%d" (line-number-at-pos (point-max))))) - face ,face - help-echo ,help-echo - mouse-face ,mouse-face - local-map ,local-map) - - ((or line-number-mode column-number-mode) - ,sep) - - ;; Position - (,visible - ,(cond - ((and (bound-and-true-p nyan-mode) - (>= (window-width) nyan-minimum-window-width)) - (concat sep (nyan-create) sep)) - ((and (bound-and-true-p poke-line-mode) - (>= (window-width) poke-line-minimum-window-width)) - (concat sep (poke-line-create) sep)) - ((and (bound-and-true-p mlscroll-mode) - (>= (window-width) mlscroll-minimum-current-width)) - (concat - sep - (let ((mlscroll-right-align nil)) - (format-mode-line (mlscroll-mode-line))) - sep)) - ((and (bound-and-true-p sml-modeline-mode) - (>= (window-width) sml-modeline-len)) - (concat sep (sml-modeline-create) sep)) - (t ""))) - - ;; Percent position - (doom-modeline-percent-position - ((:propertize ("" doom-modeline-percent-position) - face ,face - help-echo ,help-echo - mouse-face ,mouse-face - local-map ,local-map) - ,sep))))) - -;; -;; Party parrot -;; -(doom-modeline-def-segment parrot - "The party parrot animated icon. Requires `parrot-mode' to be enabled." - (when (and (doom-modeline--segment-visible 'parrot) - (bound-and-true-p parrot-mode)) - (concat (doom-modeline-wspc) - (parrot-create) - (doom-modeline-spc)))) - -;; -;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.) -;; - -(defun doom-modeline--modal-icon (text face help-echo &optional icon unicode) - "Display the model icon with FACE and HELP-ECHO. -TEXT is alternative if icon is not available." - (propertize (doom-modeline-icon - 'mdicon - (and doom-modeline-modal-icon - (or (and doom-modeline-modal-modern-icon icon) - "nf-md-record")) - (or (and doom-modeline-modal-modern-icon unicode) "●") - text - :face (doom-modeline-face face)) - 'help-echo help-echo)) - -(defsubst doom-modeline--evil () - "The current evil state. Requires `evil-mode' to be enabled." - (when (bound-and-true-p evil-local-mode) - (doom-modeline--modal-icon - (let ((tag (evil-state-property evil-state :tag t))) - (if (stringp tag) tag (funcall tag))) - (cond - ((evil-normal-state-p) 'doom-modeline-evil-normal-state) - ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state) - ((evil-insert-state-p) 'doom-modeline-evil-insert-state) - ((evil-motion-state-p) 'doom-modeline-evil-motion-state) - ((evil-visual-state-p) 'doom-modeline-evil-visual-state) - ((evil-operator-state-p) 'doom-modeline-evil-operator-state) - ((evil-replace-state-p) 'doom-modeline-evil-replace-state) - (t 'doom-modeline-evil-user-state)) - (evil-state-property evil-state :name t) - (cond - ((evil-normal-state-p) "nf-md-alpha_n_circle") - ((evil-emacs-state-p) "nf-md-alpha_e_circle") - ((evil-insert-state-p) "nf-md-alpha_i_circle") - ((evil-motion-state-p) "nf-md-alpha_m_circle") - ((evil-visual-state-p) "nf-md-alpha_v_circle") - ((evil-operator-state-p) "nf-md-alpha_o_circle") - ((evil-replace-state-p) "nf-md-alpha_r_circle") - (t "nf-md-alpha_u_circle")) - (cond - ((evil-normal-state-p) "🅝") - ((evil-emacs-state-p) "🅔") - ((evil-insert-state-p) "🅘") - ((evil-motion-state-p) "🅜") - ((evil-visual-state-p) "🅥") - ((evil-operator-state-p) "🅞") - ((evil-replace-state-p) "🅡") - (t "🅤"))))) - -(defsubst doom-modeline--overwrite () - "The current overwrite state which is enabled by command `overwrite-mode'." - (when (and (bound-and-true-p overwrite-mode) - (not (bound-and-true-p evil-local-mode))) - (doom-modeline--modal-icon - "<W>" 'doom-modeline-overwrite "Overwrite mode" - "nf-md-marker" "🅦"))) - -(defsubst doom-modeline--god () - "The current god state which is enabled by the command `god-mode'." - (when (bound-and-true-p god-local-mode) - (doom-modeline--modal-icon - "<G>" 'doom-modeline-god "God mode" - "nf-md-account_circle" "🅖"))) - -(defsubst doom-modeline--ryo () - "The current ryo-modal state which is enabled by the command `ryo-modal-mode'." - (when (bound-and-true-p ryo-modal-mode) - (doom-modeline--modal-icon - "<R>" 'doom-modeline-ryo "Ryo modal" - "nf-md-star_circle" "✪"))) - -(defsubst doom-modeline--xah-fly-keys () - "The current `xah-fly-keys' state." - (when (bound-and-true-p xah-fly-keys) - (if xah-fly-insert-state-p - (doom-modeline--modal-icon - "<I>" 'doom-modeline-fly-insert-state "Xah-fly insert mode" - "nf-md-airplane_edit" "🛧") - (doom-modeline--modal-icon - "<C>" 'doom-modeline-fly-normal-state "Xah-fly command mode" - "nf-md-airplane_cog" "🛧")))) - -(defsubst doom-modeline--boon () - "The current Boon state. Requires `boon-mode' to be enabled." - (when (bound-and-true-p boon-local-mode) - (doom-modeline--modal-icon - (boon-state-string) - (cond - (boon-command-state 'doom-modeline-boon-command-state) - (boon-insert-state 'doom-modeline-boon-insert-state) - (boon-special-state 'doom-modeline-boon-special-state) - (boon-off-state 'doom-modeline-boon-off-state) - (t 'doom-modeline-boon-off-state)) - (boon-modeline-string) - "nf-md-coffee" "🍵"))) - -(defsubst doom-modeline--meow () - "The current Meow state. Requires `meow-mode' to be enabled." - (when (bound-and-true-p meow-mode) - (doom-modeline--modal-icon - (substring-no-properties meow--indicator) - (cond - ((meow-normal-mode-p) 'doom-modeline-meow-normal-state) - ((meow-insert-mode-p) 'doom-modeline-meow-insert-state) - ((meow-beacon-mode-p) 'doom-modeline-meow-beacon-state) - ((meow-motion-mode-p) 'doom-modeline-meow-motion-state) - ((meow-keypad-mode-p) 'doom-modeline-meow-keypad-state) - (t 'doom-modeline-meow-normal-state)) - (symbol-name (meow--current-state)) - (cond - ((meow-normal-mode-p) "nf-md-alpha_n_circle") - ((meow-insert-mode-p) "nf-md-alpha_i_circle") - ((meow-beacon-mode-p) "nf-md-alpha_b_circle") - ((meow-motion-mode-p) "nf-md-alpha_m_circle") - ((meow-keypad-mode-p) "nf-md-alpha_k_circle") - (t "nf-md-alpha_n_circle")) - (cond - ((meow-normal-mode-p) "🅝") - ((meow-insert-mode-p) "🅘") - ((meow-beacon-mode-p) "🅑") - ((meow-motion-mode-p) "🅜") - ((meow-keypad-mode-p) "🅚") - (t "🅝"))))) - -(doom-modeline-def-segment modals - "Displays modal editing states. - -Including `evil', `overwrite', `god', `ryo' and `xha-fly-kyes', etc." - (when doom-modeline-modal - (let* ((evil (doom-modeline--evil)) - (ow (doom-modeline--overwrite)) - (god (doom-modeline--god)) - (ryo (doom-modeline--ryo)) - (xf (doom-modeline--xah-fly-keys)) - (boon (doom-modeline--boon)) - (vsep (doom-modeline-vspc)) - (meow (doom-modeline--meow)) - (sep (and (or evil ow god ryo xf boon) (doom-modeline-spc)))) - (concat sep - (and evil (concat evil (and (or ow god ryo xf boon meow) vsep))) - (and ow (concat ow (and (or god ryo xf boon meow) vsep))) - (and god (concat god (and (or ryo xf boon meow) vsep))) - (and ryo (concat ryo (and (or xf boon meow) vsep))) - (and xf (concat xf (and (or boon meow) vsep))) - (and boon (concat boon (and meow vsep))) - meow - sep)))) - -;; -;; Objed state -;; - -(defvar doom-modeline--objed-active nil) - -(defun doom-modeline-update-objed (_ &optional reset) - "Update `objed' status, inactive when RESET is true." - (setq doom-modeline--objed-active (not reset))) - -(setq objed-modeline-setup-func #'doom-modeline-update-objed) - -(doom-modeline-def-segment objed-state () - "The current objed state." - (when (and doom-modeline--objed-active - (doom-modeline--active)) - (propertize (format " %s(%s) " - (symbol-name objed--object) - (char-to-string (aref (symbol-name objed--obj-state) 0))) - 'face 'doom-modeline-evil-emacs-state - 'help-echo (format "Objed object: %s (%s)" - (symbol-name objed--object) - (symbol-name objed--obj-state))))) - - -;; -;; Input method -;; - -(doom-modeline-def-segment input-method - "The current input method." - (when-let ((im (cond - (current-input-method - current-input-method-title) - ((and (bound-and-true-p evil-local-mode) - (bound-and-true-p evil-input-method)) - (nth 3 (assoc default-input-method input-method-alist))) - (t nil))) - (sep (doom-modeline-spc))) - (concat - sep - (propertize im - 'face (doom-modeline-face - (if (and (bound-and-true-p rime-mode) - (equal current-input-method "rime")) - (if (and (rime--should-enable-p) - (not (rime--should-inline-ascii-p))) - 'doom-modeline-input-method - 'doom-modeline-input-method-alt) - 'doom-modeline-input-method)) - 'help-echo (concat - "Current input method: " - current-input-method - "\n\ -mouse-2: Disable input method\n\ -mouse-3: Describe current input method") - 'mouse-face 'doom-modeline-highlight - 'local-map mode-line-input-method-map) - sep))) - - -;; -;; Info -;; - -(doom-modeline-def-segment info-nodes - "The topic and nodes in the Info buffer." - (concat - " (" - ;; topic - (propertize (if (stringp Info-current-file) - (replace-regexp-in-string - "%" "%%" - (file-name-sans-extension - (file-name-nondirectory Info-current-file))) - (format "*%S*" Info-current-file)) - 'face (doom-modeline-face 'doom-modeline-info)) - ") " - ;; node - (when Info-current-node - (propertize (replace-regexp-in-string - "%" "%%" Info-current-node) - 'face (doom-modeline-face 'doom-modeline-buffer-path) - 'help-echo - "mouse-1: scroll forward, mouse-3: scroll back" - 'mouse-face 'doom-modeline-highlight - 'local-map Info-mode-line-node-keymap)))) - - -;; -;; REPL -;; - -(defun doom-modeline-repl-icon (text face) - "Display REPL icon (or TEXT in terminal) with FACE." - (doom-modeline-icon 'faicon "nf-fa-terminal" "$" text :face face)) - -(defvar doom-modeline--cider nil) - -(defun doom-modeline-update-cider () - "Update cider repl state." - (setq doom-modeline--cider - (let* ((connected (cider-connected-p)) - (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning)) - (repl-buffer (cider-current-repl nil nil)) - (cider-info (when repl-buffer - (cider--connection-info repl-buffer t))) - (icon (doom-modeline-repl-icon "REPL" face))) - (propertize icon - 'help-echo - (if connected - (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info) - "CIDER Disconnected\nmouse-1: CIDER jack-in") - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (if connected - (define-key map [mode-line mouse-2] - #'cider-quit) - (define-key map [mode-line mouse-1] - #'cider-jack-in)) - map))))) - -(add-hook 'cider-connected-hook #'doom-modeline-update-cider) -(add-hook 'cider-disconnected-hook #'doom-modeline-update-cider) -(add-hook 'cider-mode-hook #'doom-modeline-update-cider) - -(doom-modeline-def-segment repl - "The REPL state." - (when doom-modeline-repl - (when-let ((icon (when (bound-and-true-p cider-mode) - doom-modeline--cider)) - (sep (doom-modeline-spc))) - (concat - sep - (doom-modeline-display-icon icon) - sep)))) - - -;; -;; LSP -;; - -(defun doom-modeline-lsp-icon (text face) - "Display LSP icon (or TEXT in terminal) with FACE." - (if doom-modeline-lsp-icon - (doom-modeline-icon 'octicon "nf-oct-rocket" "🚀" text :face face) - (propertize text 'face face))) - -(defvar-local doom-modeline--lsp nil) -(defun doom-modeline-update-lsp (&rest _) - "Update `lsp-mode' state." - (setq doom-modeline--lsp - (let* ((workspaces (lsp-workspaces)) - (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning)) - (icon (doom-modeline-lsp-icon "LSP" face))) - (propertize icon - 'help-echo - (if workspaces - (concat "LSP Connected " - (string-join - (mapcar (lambda (w) - (format "[%s]\n" (lsp--workspace-print w))) - workspaces)) - "C-mouse-1: Switch to another workspace folder -mouse-1: Describe current session -mouse-2: Quit server -mouse-3: Reconnect to server") - "LSP Disconnected -mouse-1: Reload to start server") - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (if workspaces - (progn - (define-key map [mode-line C-mouse-1] - #'lsp-workspace-folders-open) - (define-key map [mode-line mouse-1] - #'lsp-describe-session) - (define-key map [mode-line mouse-2] - #'lsp-workspace-shutdown) - (define-key map [mode-line mouse-3] - #'lsp-workspace-restart)) - (progn - (define-key map [mode-line mouse-1] - (lambda () - (interactive) - (ignore-errors (revert-buffer t t)))))) - map))))) -(add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp) -(add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp) -(add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp) -(add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp) -(add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp) - -(defun doom-modeline--eglot-pending-count (server) - "Get count of pending eglot requests to SERVER." - (if (fboundp 'jsonrpc-continuation-count) - (jsonrpc-continuation-count server) - (hash-table-count (jsonrpc--request-continuations server)))) - -(defvar-local doom-modeline--eglot nil) -(defun doom-modeline-update-eglot () - "Update `eglot' state." - (setq doom-modeline--eglot - (pcase-let* ((server (and (eglot-managed-p) (eglot-current-server))) - (nick (and server (eglot--project-nickname server))) - (pending (and server (doom-modeline--eglot-pending-count server))) - (last-error (and server (jsonrpc-last-error server))) - (face (cond (last-error 'doom-modeline-lsp-error) - ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning) - (nick 'doom-modeline-lsp-success) - (t 'doom-modeline-lsp-warning))) - (icon (doom-modeline-lsp-icon "EGLOT" face))) - (propertize icon - 'help-echo (cond - (last-error - (format "EGLOT\nAn error occured: %s -mouse-3: Clear this status" (plist-get last-error :message))) - ((and pending (cl-plusp pending)) - (format "EGLOT\n%d outstanding requests" pending)) - (nick (format "EGLOT Connected (%s/%s) -C-mouse-1: Go to server errors -mouse-1: Go to server events -mouse-2: Quit server -mouse-3: Reconnect to server" nick (eglot--major-modes server))) - (t "EGLOT Disconnected -mouse-1: Start server")) - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (cond (last-error - (define-key map [mode-line mouse-3] - #'eglot-clear-status)) - ((and pending (cl-plusp pending)) - (define-key map [mode-line mouse-3] - #'eglot-forget-pending-continuations)) - (nick - (define-key map [mode-line C-mouse-1] - #'eglot-stderr-buffer) - (define-key map [mode-line mouse-1] - #'eglot-events-buffer) - (define-key map [mode-line mouse-2] - #'eglot-shutdown) - (define-key map [mode-line mouse-3] - #'eglot-reconnect)) - (t (define-key map [mode-line mouse-1] - #'eglot))) - map))))) -(add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot) - -(defvar-local doom-modeline--tags nil) -(defun doom-modeline-update-tags () - "Update tags state." - (setq doom-modeline--tags - (propertize - (doom-modeline-lsp-icon "TAGS" 'doom-modeline-lsp-success) - 'help-echo "TAGS: Citre mode -mouse-1: Toggle citre mode" - 'mouse-face 'doom-modeline-highlight - 'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode)))) -(add-hook 'citre-mode-hook #'doom-modeline-update-tags) - -(defun doom-modeline-update-lsp-icon () - "Update lsp icon." - (cond ((bound-and-true-p lsp-mode) - (doom-modeline-update-lsp)) - ((bound-and-true-p eglot--managed-mode) - (doom-modeline-update-eglot)) - ((bound-and-true-p citre-mode) - (doom-modeline-update-tags)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-lsp-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-lsp-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-lsp-icon)))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-icon val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-lsp-icon)))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-unicode-fallback - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-unicode-fallback val) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (doom-modeline-update-lsp-icon)))))) - -(doom-modeline-def-segment lsp - "The LSP server state." - (when doom-modeline-lsp - (when-let ((icon (cond ((bound-and-true-p lsp-mode) - doom-modeline--lsp) - ((bound-and-true-p eglot--managed-mode) - doom-modeline--eglot) - ((bound-and-true-p citre-mode) - doom-modeline--tags))) - (sep (doom-modeline-spc))) - (concat - sep - (doom-modeline-display-icon icon) - sep)))) - -(defun doom-modeline-override-eglot () - "Override `eglot' mode-line." - (if (and doom-modeline-lsp - (bound-and-true-p doom-modeline-mode)) - (setq mode-line-misc-info - (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info)) - (add-to-list 'mode-line-misc-info - `(eglot--managed-mode (" [" eglot--mode-line-format "] "))))) -(add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot) -(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot) - -(doom-modeline-add-variable-watcher - 'doom-modeline-battery - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-lsp val) - (doom-modeline-override-eglot)))) - - -;; -;; GitHub -;; - -(defvar doom-modeline--github-notification-number 0) -(defvar doom-modeline-before-github-fetch-notification-hook nil - "Hooks before fetching GitHub notifications. -Example: - (add-hook \\='doom-modeline-before-github-fetch-notification-hook - #\\='auth-source-pass-enable)") - -(defvar doom-modeline-after-github-fetch-notification-hook nil - "Hooks after fetching GitHub notifications.") - -(defun doom-modeline--github-fetch-notifications () - "Fetch GitHub notifications." - (when (and doom-modeline-github - (require 'async nil t)) - (async-start - `(lambda () - ,(async-inject-variables - "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'") - (run-hooks 'doom-modeline-before-github-fetch-notification-hook) - (when (require 'ghub nil t) - (with-timeout (10) - (ignore-errors - (when-let* ((username (ghub--username ghub-default-host)) - (token (or (ghub--token ghub-default-host username 'forge t) - (ghub--token ghub-default-host username 'ghub t)))) - (ghub-get "/notifications" - '((notifications . t)) - :host ghub-default-host - :username username - :auth token - :unpaginate t - :noerror t)))))) - (lambda (result) - (message "") ; suppress message - (setq doom-modeline--github-notification-number (length result)) - (run-hooks 'doom-modeline-after-github-fetch-notification-hook))))) - -(defvar doom-modeline--github-timer nil) -(defun doom-modeline-github-timer () - "Start/Stop the timer for GitHub fetching." - (if (timerp doom-modeline--github-timer) - (cancel-timer doom-modeline--github-timer)) - (setq doom-modeline--github-timer - (and doom-modeline-github - (run-with-idle-timer 30 - doom-modeline-github-interval - #'doom-modeline--github-fetch-notifications)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-github - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-github val) - (doom-modeline-github-timer)))) - -(doom-modeline-github-timer) - -(doom-modeline-def-segment github - "The GitHub notifications." - (when (and doom-modeline-github - (doom-modeline--segment-visible 'github) - (numberp doom-modeline--github-notification-number)) - (let ((sep (doom-modeline-spc))) - (concat - sep - (propertize - (concat - (doom-modeline-icon 'octicon "nf-oct-mark_github" "🔔" "&" - :face 'doom-modeline-notification) - (and (> doom-modeline--github-notification-number 0) (doom-modeline-vspc)) - (propertize - (cond - ((<= doom-modeline--github-notification-number 0) "") - ((> doom-modeline--github-notification-number 99) "99+") - (t (number-to-string doom-modeline--github-notification-number))) - 'face '(:inherit - (doom-modeline-unread-number doom-modeline-notification)))) - 'help-echo "Github Notifications -mouse-1: Show notifications -mouse-3: Fetch notifications" - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line mouse-1] - (lambda () - "Open GitHub notifications page." - (interactive) - (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications) - (browse-url "https://github.com/notifications"))) - (define-key map [mode-line mouse-3] - (lambda () - "Fetching GitHub notifications." - (interactive) - (message "Fetching GitHub notifications...") - (doom-modeline--github-fetch-notifications))) - map)) - sep)))) - - -;; -;; Debug states -;; - -;; Highlight the doom-modeline while debugging. -(defvar-local doom-modeline--debug-cookie nil) -(defun doom-modeline--debug-visual (&rest _) - "Update the face of mode-line for debugging." - (mapc (lambda (buffer) - (with-current-buffer buffer - (setq doom-modeline--debug-cookie - (face-remap-add-relative 'doom-modeline 'doom-modeline-debug-visual)) - (force-mode-line-update))) - (buffer-list))) - -(defun doom-modeline--normal-visual (&rest _) - "Restore the face of mode-line." - (mapc (lambda (buffer) - (with-current-buffer buffer - (when doom-modeline--debug-cookie - (face-remap-remove-relative doom-modeline--debug-cookie) - (force-mode-line-update)))) - (buffer-list))) - -(add-hook 'dap-session-created-hook #'doom-modeline--debug-visual) -(add-hook 'dap-terminated-hook #'doom-modeline--normal-visual) - -(defun doom-modeline-debug-icon (face) - "Display debug icon with FACE and ARGS." - (doom-modeline-icon 'codicon "nf-cod-debug" "🐛" "!" :face face)) - -(defun doom-modeline--debug-dap () - "The current `dap-mode' state." - (when (and (bound-and-true-p dap-mode) - (bound-and-true-p lsp-mode)) - (when-let ((session (dap--cur-session))) - (when (dap--session-running session) - (propertize (doom-modeline-debug-icon 'doom-modeline-info) - 'help-echo (format "DAP (%s - %s) -mouse-1: Display debug hydra -mouse-2: Display recent configurations -mouse-3: Disconnect session" - (dap--debug-session-name session) - (dap--debug-session-state session)) - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line mouse-1] - #'dap-hydra) - (define-key map [mode-line mouse-2] - #'dap-debug-recent) - (define-key map [mode-line mouse-3] - #'dap-disconnect) - map)))))) - -(defvar-local doom-modeline--debug-dap nil) -(defun doom-modeline-update-debug-dap (&rest _) - "Update dap debug state." - (setq doom-modeline--debug-dap (doom-modeline--debug-dap))) - -(add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap) -(add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap) -(add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap) - -(defsubst doom-modeline--debug-edebug () - "The current `edebug' state." - (when (bound-and-true-p edebug-mode) - (propertize (doom-modeline-debug-icon 'doom-modeline-info) - 'help-echo (format "EDebug (%s) -mouse-1: Show help -mouse-2: Next -mouse-3: Stop debugging" - edebug-execution-mode) - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line mouse-1] - #'edebug-help) - (define-key map [mode-line mouse-2] - #'edebug-next-mode) - (define-key map [mode-line mouse-3] - #'edebug-stop) - map)))) - -(defsubst doom-modeline--debug-on-error () - "The current `debug-on-error' state." - (when debug-on-error - (propertize (doom-modeline-debug-icon 'doom-modeline-urgent) - 'help-echo "Debug on Error -mouse-1: Toggle Debug on Error" - 'mouse-face 'doom-modeline-highlight - 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error)))) - -(defsubst doom-modeline--debug-on-quit () - "The current `debug-on-quit' state." - (when debug-on-quit - (propertize (doom-modeline-debug-icon 'doom-modeline-warning) - 'help-echo "Debug on Quit -mouse-1: Toggle Debug on Quit" - 'mouse-face 'doom-modeline-highlight - 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit)))) - -(doom-modeline-def-segment debug - "The current debug state." - (when (doom-modeline--segment-visible 'debug) - (let* ((dap doom-modeline--debug-dap) - (edebug (doom-modeline--debug-edebug)) - (on-error (doom-modeline--debug-on-error)) - (on-quit (doom-modeline--debug-on-quit)) - (vsep (doom-modeline-vspc)) - (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc)))) - (concat sep - (and dap (concat dap (and (or edebug on-error on-quit) vsep))) - (and edebug (concat edebug (and (or on-error on-quit) vsep))) - (and on-error (concat on-error (and on-quit vsep))) - on-quit - sep)))) - - -;; -;; PDF pages -;; - -(defvar-local doom-modeline--pdf-pages nil) -(defun doom-modeline-update-pdf-pages () - "Update PDF pages." - (setq doom-modeline--pdf-pages - (format " P%d/%d " - (or (eval `(pdf-view-current-page)) 0) - (pdf-cache-number-of-pages)))) -(add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages) - -(doom-modeline-def-segment pdf-pages - "Display PDF pages." - doom-modeline--pdf-pages) - - -;; -;; `mu4e' notifications -;; - -(doom-modeline-def-segment mu4e - "Show notifications of any unread emails in `mu4e'." - (when (and doom-modeline-mu4e - (doom-modeline--segment-visible 'mu4e)) - (let ((sep (doom-modeline-spc)) - (vsep (doom-modeline-vspc)) - (icon (doom-modeline-icon 'mdicon "nf-md-email" "📧" "#" - :face 'doom-modeline-notification))) - (cond ((and (bound-and-true-p mu4e-alert-mode-line) - (numberp mu4e-alert-mode-line) - ;; don't display if the unread mails count is zero - (> mu4e-alert-mode-line 0)) - (concat - sep - (propertize - (concat - icon - vsep - (propertize - (if (> mu4e-alert-mode-line doom-modeline-number-limit) - (format "%d+" doom-modeline-number-limit) - (number-to-string mu4e-alert-mode-line)) - 'face '(:inherit - (doom-modeline-unread-number doom-modeline-notification)))) - 'mouse-face 'doom-modeline-highlight - 'keymap '(mode-line keymap - (mouse-1 . mu4e-alert-view-unread-mails) - (mouse-2 . mu4e-alert-view-unread-mails) - (mouse-3 . mu4e-alert-view-unread-mails)) - 'help-echo (concat (if (= mu4e-alert-mode-line 1) - "You have an unread email" - (format "You have %s unread emails" mu4e-alert-mode-line)) - "\nClick here to view " - (if (= mu4e-alert-mode-line 1) "it" "them"))) - sep)) - ((bound-and-true-p mu4e-modeline-mode) - (concat sep icon vsep - (propertize (mu4e--modeline-string) - 'face 'doom-modeline-notification) - sep)))))) - -(defun doom-modeline-override-mu4e-alert (&rest _) - "Delete `mu4e-alert-mode-line' from global modeline string." - (when (and (featurep 'mu4e-alert) - (bound-and-true-p mu4e-alert-mode-line)) - (if (and doom-modeline-mu4e - (bound-and-true-p doom-modeline-mode)) - ;; Delete original modeline - (progn - (setq global-mode-string - (delete '(:eval mu4e-alert-mode-line) global-mode-string)) - (setq mu4e-alert-modeline-formatter #'identity)) - ;; Recover default settings - (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter)))) -(advice-add #'mu4e-alert-enable-mode-line-display - :after #'doom-modeline-override-mu4e-alert) -(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert) - -(defun doom-modeline-override-mu4e-modeline (&rest _) - "Delete `mu4e-alert-mode-line' from global modeline string." - (when (bound-and-true-p mu4e-modeline-mode) - (if (and doom-modeline-mu4e - (bound-and-true-p doom-modeline-mode)) - ;; Delete original modeline - (setq global-mode-string - (delete mu4e--modeline-item global-mode-string)) - ;; Recover default settings - (add-to-list 'global-mode-string mu4e--modeline-item)))) -(add-hook 'mu4e-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) -(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) - -(doom-modeline-add-variable-watcher - 'doom-modeline-mu4e - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-mu4e val) - (doom-modeline-override-mu4e-alert) - (doom-modeline-override-mu4e-modeline)))) - - -;; -;; `gnus' notifications -;; - -(defvar doom-modeline--gnus-unread-mail 0) -(defvar doom-modeline--gnus-started nil - "Used to determine if gnus has started.") -(defun doom-modeline-update-gnus-status (&rest _) - "Get the total number of unread news of gnus group." - (setq doom-modeline--gnus-unread-mail - (when (and doom-modeline-gnus - doom-modeline--gnus-started) - (let ((total-unread-news-number 0)) - (mapc (lambda (g) - (let* ((group (car g)) - (unread (eval `(gnus-group-unread ,group)))) - (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group)) - (numberp unread) - (> unread 0)) - (setq total-unread-news-number (+ total-unread-news-number unread))))) - gnus-newsrc-alist) - total-unread-news-number)))) - -;; Update the modeline after changes have been made -(add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status) -(add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status) -(add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status) -(add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status) - -;; Only start to listen to gnus when gnus is actually running -(defun doom-modeline-start-gnus-listener () - "Start GNUS listener." - (when (and doom-modeline-gnus - (not doom-modeline--gnus-started)) - (setq doom-modeline--gnus-started t) - ;; Scan gnus in the background if the timer is higher than 0 - (doom-modeline-update-gnus-status) - (if (> doom-modeline-gnus-timer 0) - (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle)))) -(add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener) - -;; Stop the listener if gnus isn't running -(defun doom-modeline-stop-gnus-listener () - "Stop GNUS listener." - (setq doom-modeline--gnus-started nil)) -(add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener) - -(doom-modeline-def-segment gnus - "Show notifications of any unread emails in `gnus'." - (when (and (doom-modeline--segment-visible 'gnus) - doom-modeline-gnus - doom-modeline--gnus-started - ;; Don't display if the unread mails count is zero - (numberp doom-modeline--gnus-unread-mail) - (> doom-modeline--gnus-unread-mail 0)) - (let ((sep (doom-modeline-spc)) - (vsep (doom-modeline-vspc))) - (concat - sep - (propertize - (concat - (doom-modeline-icon 'mdicon "nf-md-email" "📧" "#" - :face 'doom-modeline-notification) - vsep - (propertize - (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit) - (format "%d+" doom-modeline-number-limit) - (number-to-string doom-modeline--gnus-unread-mail)) - 'face '(:inherit - (doom-modeline-unread-number doom-modeline-notification)))) - 'mouse-face 'doom-modeline-highlight - 'help-echo (if (= doom-modeline--gnus-unread-mail 1) - "You have an unread email" - (format "You have %s unread emails" doom-modeline--gnus-unread-mail))) - sep)))) - - -;; -;; IRC notifications -;; - -(defun doom-modeline-shorten-irc (name) - "Wrapper for `tracking-shorten' and `erc-track-shorten-function' with NAME. - -One key difference is that when `tracking-shorten' and -`erc-track-shorten-function' returns nil we will instead return the original -value of name. This is necessary in cases where the user has stylized the name -to be an icon and we don't want to remove that so we just return the original." - (or (and (fboundp 'tracking-shorten) - (car (tracking-shorten (list name)))) - (and (boundp 'erc-track-shorten-function) - (functionp erc-track-shorten-function) - (car (funcall erc-track-shorten-function (list name)))) - (and (fboundp 'rcirc-short-buffer-name) - (rcirc-short-buffer-name name)) - name)) - -(defun doom-modeline--tracking-buffers (buffers) - "Logic to convert some irc BUFFERS to their font-awesome icon." - (mapconcat - (lambda (b) - (propertize - (funcall doom-modeline-irc-stylize b) - 'face '(:inherit (doom-modeline-unread-number doom-modeline-notification)) - 'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b) - 'mouse-face 'doom-modeline-highlight - 'local-map (make-mode-line-mouse-map - 'mouse-1 - (lambda () - (interactive) - (when (buffer-live-p (get-buffer b)) - (switch-to-buffer b)))))) - buffers - (doom-modeline-vspc))) - -(defun doom-modeline--circe-p () - "Check if `circe' is in use." - (boundp 'tracking-mode-line-buffers)) - -(defun doom-modeline--erc-p () - "Check if `erc' is in use." - (boundp 'erc-modified-channels-alist)) - -(defun doom-modeline--rcirc-p () - "Check if `rcirc' is in use." - (bound-and-true-p rcirc-track-minor-mode)) - -(defun doom-modeline--get-buffers () - "Gets the buffers that have activity." - (cond - ((doom-modeline--circe-p) - tracking-buffers) - ((doom-modeline--erc-p) - (mapcar (lambda (l) - (buffer-name (car l))) - erc-modified-channels-alist)) - ((doom-modeline--rcirc-p) - (mapcar (lambda (b) - (buffer-name b)) - rcirc-activity)))) - -;; Create a modeline segment that contains all the irc tracked buffers -(doom-modeline-def-segment irc-buffers - "The list of shortened, unread irc buffers." - (when (and doom-modeline-irc - (doom-modeline--segment-visible 'irc-buffers)) - (let* ((buffers (doom-modeline--get-buffers)) - (number (length buffers)) - (sep (doom-modeline-spc))) - (when (> number 0) - (concat - sep - (doom-modeline--tracking-buffers buffers) - sep))))) - -(doom-modeline-def-segment irc - "A notification icon for any unread irc buffer." - (when (and doom-modeline-irc - (doom-modeline--segment-visible 'irc)) - (let* ((buffers (doom-modeline--get-buffers)) - (number (length buffers)) - (sep (doom-modeline-spc)) - (vsep (doom-modeline-vspc))) - (when (> number 0) - (concat - sep - - (propertize (concat - (doom-modeline-icon 'mdicon "nf-md-message_processing" "🗊" "#" - :face 'doom-modeline-notification) - vsep - ;; Display the number of unread buffers - (propertize (number-to-string number) - 'face '(:inherit - (doom-modeline-unread-number - doom-modeline-notification)))) - 'help-echo (format "IRC Notifications: %s\n%s" - (mapconcat - (lambda (b) (funcall doom-modeline-irc-stylize b)) - buffers - ", ") - (cond - ((doom-modeline--circe-p) - "mouse-1: Switch to previous unread buffer -mouse-3: Switch to next unread buffer") - ((doom-modeline--erc-p) - "mouse-1: Switch to buffer -mouse-3: Switch to next unread buffer") - ((doom-modeline--rcirc-p) - "mouse-1: Switch to server buffer -mouse-3: Switch to next unread buffer"))) - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (cond - ((doom-modeline--circe-p) - (define-key map [mode-line mouse-1] - #'tracking-previous-buffer) - (define-key map [mode-line mouse-3] - #'tracking-next-buffer)) - ((doom-modeline--erc-p) - (define-key map [mode-line mouse-1] - #'erc-switch-to-buffer) - (define-key map [mode-line mouse-3] - #'erc-track-switch-buffer)) - ((doom-modeline--rcirc-p) - (define-key map [mode-line mouse-1] - #'rcirc-switch-to-server-buffer) - (define-key map [mode-line mouse-3] - #'rcirc-next-active-buffer))) - map)) - - ;; Display the unread irc buffers as well - (when doom-modeline-irc-buffers - (concat sep (doom-modeline--tracking-buffers buffers))) - - sep))))) - -(defun doom-modeline-override-rcirc () - "Override default `rcirc' mode-line." - (if (and doom-modeline-irc - (bound-and-true-p doom-modeline-mode)) - (setq global-mode-string - (delq 'rcirc-activity-string global-mode-string)) - (when (and rcirc-track-minor-mode - (not (memq 'rcirc-activity-string global-mode-string))) - (setq global-mode-string - (append global-mode-string '(rcirc-activity-string)))))) -(add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc) -(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc) - -(doom-modeline-add-variable-watcher - 'doom-modeline-irc - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-irc val) - (doom-modeline-override-rcirc)))) - - -;; -;; Battery status -;; - -(defun doom-modeline-battery-icon (icon unicode text face) - "Displays the battery ICON with FACE. - -UNICODE and TEXT are fallbacks. -Uses `nerd-icons-mdicon' to fetch the icon." - (doom-modeline-icon 'mdicon icon unicode text :face face)) - -(defvar doom-modeline--battery-status nil) -(defun doom-modeline-update-battery-status () - "Update battery status." - (setq doom-modeline--battery-status - (when (and doom-modeline-battery - (bound-and-true-p display-battery-mode)) - (let* ((data (and battery-status-function - (functionp battery-status-function) - (funcall battery-status-function))) - (status (cdr (assoc ?L data))) - (charging? (or (string-equal "AC" status) - (string-equal "on-line" status))) - (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR")))) - (valid-percentage? (and (numberp percentage) - (>= percentage 0) - (<= percentage battery-mode-line-limit))) - (face (if valid-percentage? - (cond (charging? 'doom-modeline-battery-charging) - ((< percentage battery-load-critical) 'doom-modeline-battery-critical) - ((< percentage 25) 'doom-modeline-battery-warning) - ((< percentage 95) 'doom-modeline-battery-normal) - (t 'doom-modeline-battery-full)) - 'doom-modeline-battery-error)) - (icon (if valid-percentage? - (cond - ((>= percentage 100) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_100" - "nf-md-battery") - "🔋" "-" face)) - ((>= percentage 90) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_90" - "nf-md-battery_90") - "🔋" "-" face)) - ((>= percentage 80) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_80" - "nf-md-battery_80") - "🔋" "-" face)) - ((>= percentage 70) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_70" - "nf-md-battery_70") - "🔋" "-" face)) - ((>= percentage 60) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_60" - "nf-md-battery_60") - "🔋" "-" face)) - ((>= percentage 50) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_50" - "nf-md-battery_50") - "🔋" "-" face)) - ((>= percentage 40) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_40" - "nf-md-battery_40") - "🔋" "-" face)) - ((>= percentage 30) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_30" - "nf-md-battery_30") - "🔋" "-" face)) - ((>= percentage 20) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_20" - "nf-md-battery_20") - "🔋" "-" face)) - ((>= percentage 10) - (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_10" - "nf-md-battery_10") - "🪫" "-" face)) - (t (doom-modeline-battery-icon (if charging? - "nf-md-battery_charging_outline" - "nf-md-battery_outline") - "🪫" "!" face))) - (doom-modeline-battery-icon "nf-md-battery_alert" "⚠" "N/A" face))) - (text (if valid-percentage? (format "%d%s" percentage "%%") "")) - (help-echo (if (and battery-echo-area-format data valid-percentage?) - (battery-format battery-echo-area-format data) - "Battery status not available"))) - (cons (propertize icon 'help-echo help-echo) - (propertize text 'face face 'help-echo help-echo)))))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-icon - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-icon val) - (doom-modeline-update-battery-status)))) - -(doom-modeline-add-variable-watcher - 'doom-modeline-unicode-fallback - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-unicode-fallback val) - (doom-modeline-update-battery-status)))) - -(doom-modeline-def-segment battery - "Display battery status." - (when (and doom-modeline-battery - (bound-and-true-p display-battery-mode) - (doom-modeline--segment-visible 'battery)) - (let ((sep (doom-modeline-spc)) - (vsep (doom-modeline-vspc))) - (concat sep - (car doom-modeline--battery-status) - vsep - (cdr doom-modeline--battery-status) - sep)))) - -(defun doom-modeline-override-battery () - "Override default battery mode-line." - (if (and doom-modeline-battery - (bound-and-true-p doom-modeline-mode)) - (progn - (advice-add #'battery-update :override #'doom-modeline-update-battery-status) - (setq global-mode-string - (delq 'battery-mode-line-string global-mode-string)) - (and (bound-and-true-p display-battery-mode) (battery-update))) - (progn - (advice-remove #'battery-update #'doom-modeline-update-battery-status) - (when (and display-battery-mode battery-status-function battery-mode-line-format - (not (memq 'battery-mode-line-string global-mode-string))) - (setq global-mode-string - (append global-mode-string '(battery-mode-line-string))))))) -(add-hook 'display-battery-mode-hook #'doom-modeline-override-battery) -(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery) - -(doom-modeline-add-variable-watcher - 'doom-modeline-battery - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-battery val) - (doom-modeline-override-battery)))) - - -;; -;; Package information -;; - -(doom-modeline-def-segment package - "Show package information via `paradox'." - (concat - (doom-modeline-display-text - (format-mode-line 'mode-line-front-space)) - - (when (and doom-modeline-icon doom-modeline-major-mode-icon) - (concat - (doom-modeline-spc) - (doom-modeline-icon 'faicon "nf-fa-archive" nil nil - :face (doom-modeline-face - (if doom-modeline-major-mode-color-icon - 'nerd-icons-silver - 'mode-line))))) - (doom-modeline-display-text - (format-mode-line 'mode-line-buffer-identification)))) - - -;; -;; Helm -;; - -(defvar doom-modeline--helm-buffer-ids - '(("*helm*" . "HELM") - ("*helm M-x*" . "HELM M-x") - ("*swiper*" . "SWIPER") - ("*Projectile Perspectives*" . "HELM Projectile Perspectives") - ("*Projectile Layouts*" . "HELM Projectile Layouts") - ("*helm-ag*" . (lambda () - (format "HELM Ag: Using %s" - (car (split-string helm-ag-base-command)))))) - "Alist of custom helm buffer names to use. -The cdr can also be a function that returns a name to use.") - -(doom-modeline-def-segment helm-buffer-id - "Helm session identifier." - (when (bound-and-true-p helm-alive-p) - (let ((sep (doom-modeline-spc))) - (concat - sep - (when doom-modeline-icon - (concat - (doom-modeline-icon 'sucicon "nf-custom-emacs" nil nil - :face (doom-modeline-face - (and doom-modeline-major-mode-color-icon - 'nerd-icons-blue))) - sep)) - (propertize - (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids))) - (case-fold-search t) - (name (replace-regexp-in-string "-" " " (buffer-name)))) - (cond ((stringp custom) custom) - ((functionp custom) (funcall custom)) - (t - (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name) - (concat "HELM " (capitalize (match-string 2 name)))))) - 'face (doom-modeline-face 'doom-modeline-buffer-file)) - sep)))) - -(doom-modeline-def-segment helm-number - "Number of helm candidates." - (when (bound-and-true-p helm-alive-p) - (concat - (propertize (format " %d/%d" - (helm-candidate-number-at-point) - (helm-get-candidate-number t)) - 'face (doom-modeline-face 'doom-modeline-buffer-path)) - (propertize (format " (%d total) " (helm-get-candidate-number)) - 'face (doom-modeline-face 'doom-modeline-info))))) - -(doom-modeline-def-segment helm-help - "Helm keybindings help." - (when (bound-and-true-p helm-alive-p) - (mapcar - (lambda (s) - (if (string-prefix-p "\\<" s) - (propertize (substitute-command-keys s) - 'face (doom-modeline-face - 'doom-modeline-buffer-file)) - s)) - '("\\<helm-map>\\[helm-help]" "(help) " - "\\<helm-map>\\[helm-select-action]" "(actions) " - "\\<helm-map>\\[helm-maybe-exit-minibuffer]/F1/F2..." "(action) ")))) - -(doom-modeline-def-segment helm-prefix-argument - "Helm prefix argument." - (when (and (bound-and-true-p helm-alive-p) - helm--mode-line-display-prefarg) - (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg)))) - (unless (= arg 1) - (propertize (format "C-u %s" arg) - 'face (doom-modeline-face 'doom-modeline-info)))))) - -(defvar doom-modeline--helm-current-source nil - "The currently active helm source.") -(doom-modeline-def-segment helm-follow - "Helm follow indicator." - (and (bound-and-true-p helm-alive-p) - doom-modeline--helm-current-source - (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source))) - "HF")) - -;; -;; Git timemachine -;; - -(doom-modeline-def-segment git-timemachine - (concat - (doom-modeline-spc) - (doom-modeline--buffer-mode-icon) - (doom-modeline--buffer-state-icon) - (propertize - "*%b*" - 'face (doom-modeline-face 'doom-modeline-buffer-timemachine)))) - -;; -;; Markdown/Org preview -;; - -(doom-modeline-def-segment grip - (when (bound-and-true-p grip-mode) - (let ((sep (doom-modeline-spc))) - (concat - sep - (let ((face (doom-modeline-face - (if grip--process - (pcase (process-status grip--process) - ('run 'doom-modeline-info) - ('exit 'doom-modeline-warning) - (_ 'doom-modeline-urgent)) - 'doom-modeline-urgent)))) - (propertize - (doom-modeline-icon 'codicon "nf-cod-open_preview" "🗐" "@" :face face) - 'help-echo (format "Preview on %s -mouse-1: Preview in browser -mouse-2: Stop preview -mouse-3: Restart preview" - (grip--preview-url)) - 'mouse-face 'doom-modeline-highlight - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line mouse-1] - #'grip-browse-preview) - (define-key map [mode-line mouse-2] - #'grip-stop-preview) - (define-key map [mode-line mouse-3] - #'grip-restart-preview) - map))) - sep)))) - -;; -;; Follow mode -;; - -(doom-modeline-def-segment follow - (when (bound-and-true-p follow-mode) - (let* ((windows (follow-all-followers)) - (nwindows (length windows)) - (nfollowing (- (length (memq (selected-window) windows)) 1))) - (concat - (doom-modeline-spc) - (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows) - 'face 'doom-modeline-buffer-minor-mode))))) - -;; -;; Display time -;; - -(defconst doom-modeline--clock-hour-hand-ratio 0.45 - "Length of the hour hand as a proportion of the radius.") - -(defconst doom-modeline--clock-minute-hand-ratio 0.7 - "Length of the minute hand as a proportion of the radius.") - -(defun doom-modeline--create-clock-svg (hour minute radius color) - "Construct an SVG clock showing the time HOUR:MINUTE. -The clock will be of the specified RADIUS and COLOR." - (let ((thickness-factor (image-compute-scaling-factor 'auto)) - (hour-x (* radius (sin (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) - doom-modeline--clock-hour-hand-ratio)) - (hour-y (* radius (cos (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) - doom-modeline--clock-hour-hand-ratio)) - (minute-x (* radius (sin (* (- 30 minute) (/ float-pi 30))) - doom-modeline--clock-minute-hand-ratio)) - (minute-y (* radius (cos (* (- 30 minute) (/ float-pi 30))) - doom-modeline--clock-minute-hand-ratio)) - (svg (svg-create (* 2 radius) (* 2 radius) :stroke color))) - (svg-circle svg radius radius (- radius thickness-factor) - :fill "none" :stroke-width (* 2 thickness-factor)) - (svg-circle svg radius radius thickness-factor - :fill color :stroke "none") - (svg-line svg radius radius (+ radius hour-x) (+ radius hour-y) - :stroke-width (* 2 thickness-factor)) - (svg-line svg radius radius (+ radius minute-x) (+ radius minute-y) - :stroke-width (* 1.5 thickness-factor)) - svg)) - -(defvar doom-modeline--clock-cache nil - "The last result of `doom-modeline--generate-clock'.") - -(defun doom-modeline--generate-clock () - "Return a string containing the current time as an analogue clock svg. -When the svg library is not available, return nil." - (cdr - (or (and (equal (truncate (float-time) - (* doom-modeline-time-clock-minute-resolution 60)) - (car doom-modeline--clock-cache)) - doom-modeline--clock-cache) - (and (require 'svg nil t) - (setq doom-modeline--clock-cache - (cons (truncate (float-time) - (* doom-modeline-time-clock-minute-resolution 60)) - (propertize - " " - 'display - (svg-image - (doom-modeline--create-clock-svg - (string-to-number (format-time-string "%-I")) ; hour - (* (truncate (string-to-number (format-time-string "%-M")) - doom-modeline-time-clock-minute-resolution) - doom-modeline-time-clock-minute-resolution) ; minute - (if (integerp doom-modeline-time-clock-size) ; radius - doom-modeline-time-clock-size - (* doom-modeline-height 0.5 doom-modeline-time-clock-size)) - "currentColor") - :scale 1 :ascent 'center) - 'face 'doom-modeline-time - 'help-echo (lambda (_window _object _pos) - (format-time-string "%c"))))))))) - -(defun doom-modeline-time-icon () - "Displays the time icon." - (or (and doom-modeline-time-live-icon - doom-modeline-time-analogue-clock - (display-graphic-p) - (doom-modeline--generate-clock)) - (doom-modeline-icon - 'mdicon - (if doom-modeline-time-live-icon - (pcase (% (caddr (decode-time)) 12) - (0 "nf-md-clock_time_twelve_outline") - (1 "nf-md-clock_time_one_outline") - (2 "nf-md-clock_time_two_outline") - (3 "nf-md-clock_time_three_outline") - (4 "nf-md-clock_time_four_outline") - (5 "nf-md-clock_time_five_outline") - (6 "nf-md-clock_time_six_outline") - (7 "nf-md-clock_time_seven_outline") - (8 "nf-md-clock_time_eight_outline") - (9 "nf-md-clock_time_nine_outline") - (10 "nf-md-clock_time_ten_outline") - (11 "nf-md-clock_time_eleven_outline")) - "nf-md-clock_outline") - "⏰" - "" - :face '(:inherit doom-modeline-time :weight normal)))) - -(doom-modeline-def-segment time - (when (and doom-modeline-time - (bound-and-true-p display-time-mode) - (doom-modeline--segment-visible 'time)) - (concat - (doom-modeline-spc) - (when doom-modeline-time-icon - (concat - (doom-modeline-time-icon) - (and (or doom-modeline-icon doom-modeline-unicode-fallback) - (doom-modeline-vspc)))) - (propertize display-time-string - 'face (doom-modeline-face 'doom-modeline-time))))) - -(defun doom-modeline-override-time () - "Override default `display-time' mode-line." - (or global-mode-string (setq global-mode-string '(""))) - (if (and doom-modeline-time - (bound-and-true-p doom-modeline-mode)) - (setq global-mode-string (delq 'display-time-string global-mode-string)) - (setq global-mode-string (append global-mode-string '(display-time-string))))) -(add-hook 'display-time-mode-hook #'doom-modeline-override-time) -(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-time) - -(doom-modeline-add-variable-watcher - 'doom-modeline-time - (lambda (_sym val op _where) - (when (eq op 'set) - (setq doom-modeline-time val) - (doom-modeline-override-time)))) - -;; -;; Compilation -;; - -(doom-modeline-def-segment compilation - (and (bound-and-true-p compilation-in-progress) - (propertize "[Compiling] " - 'face (doom-modeline-face 'doom-modeline-compilation) - 'help-echo "Compiling; mouse-2: Goto Buffer" - 'mouse-face 'doom-modeline-highlight - 'local-map - (make-mode-line-mouse-map - 'mouse-2 - #'compilation-goto-in-progress-buffer)))) - -;; -;; Eldoc -;; - -(doom-modeline-def-segment eldoc - (and (bound-and-true-p eldoc-mode) - '(eldoc-mode-line-string - (" " eldoc-mode-line-string " ")))) - -(defun doom-modeline-eldoc-minibuffer-message (format-string &rest args) - "Display message specified by FORMAT-STRING and ARGS on the mode-line as needed. -This function displays the message produced by formatting ARGS -with FORMAT-STRING on the mode line when the current buffer is a minibuffer. -Otherwise, it displays the message like `message' would." - (if (minibufferp) - (progn - (add-hook 'minibuffer-exit-hook - (lambda () (setq eldoc-mode-line-string nil - ;; https://debbugs.gnu.org/16920 - eldoc-last-message nil)) - nil t) - (with-current-buffer - (window-buffer - (or (window-in-direction 'above (minibuffer-window)) - (minibuffer-selected-window) - (get-largest-window))) - (setq eldoc-mode-line-string - (when (stringp format-string) - (apply #'format-message format-string args))) - (force-mode-line-update))) - (apply #'message format-string args))) - -;; -;; Kubernetes -;; - -(doom-modeline-def-segment k8s - (when (and (bound-and-true-p kele-mode) (doom-modeline--segment-visible 'k8s)) - (let* ((ctx (kele-current-context-name :wait nil)) - (ns (kele-current-namespace :wait nil)) - (icon (doom-modeline-icon 'mdicon "nf-md-kubernetes" "K8s:" "K8s:")) - (sep (doom-modeline-spc)) - (help-msg (let ((msgs (list (format "Current context: %s" ctx)))) - (when ns - (setq msgs (append msgs (list (format "Current namespace: %s" ns))))) - (string-join msgs "\n")))) - (propertize (concat - icon sep ctx - (when (and doom-modeline-k8s-show-namespace ns) (format "(%s)" ns)) - sep) - 'local-map (let ((map (make-sparse-keymap))) - (define-key map [mode-line down-mouse-1] kele-menu-map) - map) - 'mouse-face 'doom-modeline-highlight - 'help-echo help-msg)))) - -(provide 'doom-modeline-segments) - -;;; doom-modeline-segments.el ends here diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-segments.elc b/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-segments.elc Binary files differ. diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-autoloads.el b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-autoloads.el diff --git a/emacs/elpa/doom-modeline-20240816.749/doom-modeline-core.el b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-core.el @@ -0,0 +1,1718 @@ +;;; doom-modeline-core.el --- The core libraries for doom-modeline -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2024 Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; + +;;; Commentary: +;; +;; The core libraries for doom-modeline. +;; + +;;; Code: + +(require 'compat) +(eval-when-compile + (require 'cl-lib) + (require 'subr-x)) +(require 'nerd-icons) +(require 'shrink-path) + + +;; +;; Compatibility +;; + +(unless (boundp 'mode-line-right-align-edge) + (defcustom mode-line-right-align-edge 'window + "Where mode-line should align to. +Internally, that function uses `:align-to' in a display property, +so aligns to the left edge of the given area. See info node +`(elisp)Pixel Specification'. + +Must be set to a symbol. Acceptable values are: +- `window': align to extreme right of window, regardless of margins + or fringes +- `right-fringe': align to right-fringe +- `right-margin': align to right-margin" + :type '(choice (const right-margin) + (const right-fringe) + (const window)) + :group 'mode-line)) + + +;; +;; Optimization +;; + +;; Don’t compact font caches during GC. +(when (eq system-type 'windows-nt) + (setq inhibit-compacting-font-caches t)) + + +;; +;; Customization +;; + +(defgroup doom-modeline nil + "A minimal and modern mode-line." + :group 'mode-line + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defcustom doom-modeline-support-imenu nil + "If non-nil, cause imenu to see `doom-modeline' declarations. +This is done by adjusting `lisp-imenu-generic-expression' to +include support for finding `doom-modeline-def-*' forms. + +Must be set before loading `doom-modeline'." + :type 'boolean + :set (lambda (_sym val) + (if val + (add-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu) + (remove-hook 'emacs-lisp-mode-hook #'doom-modeline-add-imenu))) + :group 'doom-modeline) + +(defcustom doom-modeline-height (+ (frame-char-height) 4) + "How tall the mode-line should be. It's only respected in GUI. +If the actual char height is larger, it respects the actual char height." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-bar-width 4 + "How wide the mode-line bar should be. It's only respected in GUI." + :type 'integer + :set (lambda (sym val) + (set sym (if (> val 0) val 1))) + :group 'doom-modeline) + +(defcustom doom-modeline-hud nil + "Whether to use hud instead of default bar. It's only respected in GUI." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-hud-min-height 2 + "Minimum height in pixels of the \"thumb\" of the hud. +Only respected in GUI." + :type 'integer + :set (lambda (sym val) + (set sym (if (> val 1) val 1))) + :group 'doom-modeline) + +(defcustom doom-modeline-window-width-limit 85 + "The limit of the window width. + +If `window-width' is smaller than the limit, some information won't be +displayed. It can be an integer or a float number. nil means no limit." + :type '(choice integer + float + (const :tag "Disable" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-project-detection 'auto + "How to detect the project root. + +nil means to use `default-directory'. + +The project management packages have some issues on detecting project root. +e.g. `projectile' doesn't handle symlink folders well, while `project' is +unable to handle sub-projects. +Specify another one if you encounter the issue." + :type '(choice (const :tag "Auto-detect" auto) + (const :tag "Find File in Project" ffip) + (const :tag "Projectile" projectile) + (const :tag "Built-in Project" project) + (const :tag "Disable" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-file-name-style 'auto + "Determines the style used by `doom-modeline-buffer-file-name'. + +Given ~/Projects/FOSS/emacs/lisp/comint.el + auto => emacs/l/comint.el (in a project) or comint.el + truncate-upto-project => ~/P/F/emacs/lisp/comint.el + truncate-from-project => ~/Projects/FOSS/emacs/l/comint.el + truncate-with-project => emacs/l/comint.el + truncate-except-project => ~/P/F/emacs/l/comint.el + truncate-upto-root => ~/P/F/e/lisp/comint.el + truncate-all => ~/P/F/e/l/comint.el + truncate-nil => ~/Projects/FOSS/emacs/lisp/comint.el + relative-from-project => emacs/lisp/comint.el + relative-to-project => lisp/comint.el + file-name => comint.el + file-name-with-project => FOSS|comint.el + buffer-name => comint.el<2> (uniquify buffer name)" + :type '(choice (const auto) + (const truncate-upto-project) + (const truncate-from-project) + (const truncate-with-project) + (const truncate-except-project) + (const truncate-upto-root) + (const truncate-all) + (const truncate-nil) + (const relative-from-project) + (const relative-to-project) + (const file-name) + (const file-name-with-project) + (const buffer-name)) + :group'doom-modeline) + +(defcustom doom-modeline-buffer-file-true-name nil + "Use `file-truename' on buffer file name. + +Project detection(projectile.el) may uses `file-truename' on directory path. +Turn on this to provide right relative path for buffer file name." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-icon t + "Whether display the icons in the mode-line. + +While using the server mode in GUI, should set the value explicitly." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-major-mode-icon t + "Whether display the icon for `major-mode'. + +It respects option `doom-modeline-icon'." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-major-mode-color-icon t + "Whether display the colorful icon for `major-mode'. + +It respects option `nerd-icons-color-icons'." + :type 'boolean + :group'doom-modeline) + +(defcustom doom-modeline-buffer-state-icon t + "Whether display the icon for the buffer state. + +It respects option `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-modification-icon t + "Whether display the modification icon for the buffer. + +It respects option `doom-modeline-icon' and `doom-modeline-buffer-state-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-lsp-icon t + "Whether display the icon of lsp client. + +It respects option `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-time-icon t + "Whether display the icon of time. + +It respects option `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-time-live-icon t + "Whether display the live icons of time. + +It respects option `doom-modeline-icon' and option `doom-modeline-time-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-time-analogue-clock t + "Whether to draw an analogue clock SVG as the live time icon. +It respects the option `doom-modeline-icon', option `doom-modeline-time-icon', +and option `doom-modeline-time-live-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-time-clock-minute-resolution 1 + "The clock will be updated every this many minutes, truncated. +See `doom-modeline-time-analogue-clock'." + :type 'natnum + :group 'doom-modeline) + +(defcustom doom-modeline-time-clock-size 0.7 + "Size of the analogue clock drawn, either in pixels or as a proportional height. +An integer value is used as the diameter of clock in pixels. +A floating point value sets the diameter of the clock realtive to +`doom-modeline-height'. + +Only relevant when `doom-modeline-time-analogue-clock' is non-nil, which see." + :type 'number + :group 'doom-modeline) + +(defcustom doom-modeline-unicode-fallback nil + "Whether to use unicode as a fallback (instead of ASCII) when not using icons." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-name t + "Whether display the buffer name." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-highlight-modified-buffer-name t + "Whether highlight the modified buffer name." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-column-zero-based t + "When non-nil, mode line displays column numbers zero-based. +See `column-number-indicator-zero-based'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-percent-position '(-3 "%p") + "Specification of \"percentage offset\" of window through buffer. +See `mode-line-percent-position'." + :type '(radio + (const :tag "nil: No offset is displayed" nil) + (const :tag "\"%o\": Proportion of \"travel\" of the window through the buffer" + (-3 "%o")) + (const :tag "\"%p\": Percentage offset of top of window" + (-3 "%p")) + (const :tag "\"%P\": Percentage offset of bottom of window" + (-3 "%P")) + (const :tag "\"%q\": Offsets of both top and bottom of window" + (6 "%q"))) + :group 'doom-modeline) + +(defcustom doom-modeline-position-line-format '("L%l") + "Format used to display line numbers in the mode line. +See `mode-line-position-line-format'." + :type '(list string) + :group 'doom-modeline) + +(defcustom doom-modeline-position-column-format '("C%c") + "Format used to display column numbers in the mode line. +See `mode-line-position-column-format'." + :type '(list string) + :group 'doom-modeline) + +(defcustom doom-modeline-position-column-line-format '("%l:%c") + "Format used to display combined line/column numbers in the mode line. +See `mode-line-position-column-line-format'." + :type '(list string) + :group 'doom-modeline) + +(defcustom doom-modeline-minor-modes nil + "Whether display the minor modes in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-enable-word-count nil + "If non-nil, a word count will be added to the selection-info modeline segment." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-continuous-word-count-modes + '(markdown-mode gfm-mode org-mode) + "Major modes in which to display word count continuously. + +It respects `doom-modeline-enable-word-count'." + :type '(repeat (symbol :tag "Major-Mode") ) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-encoding t + "Whether display the buffer encoding." + :type '(choice (const :tag "Always" t) + (const :tag "When non-default" nondefault) + (const :tag "Never" nil)) + :group 'doom-modeline) + +(defcustom doom-modeline-default-coding-system 'utf-8 + "Default coding system for `doom-modeline-buffer-encoding' `nondefault'." + :type 'coding-system + :group 'doom-modeline) + +(defcustom doom-modeline-default-eol-type 0 + "Default EOL type for `doom-modeline-buffer-encoding' `nondefault'." + :type '(choice (const :tag "Unix-style LF" 0) + (const :tag "DOS-style CRLF" 1) + (const :tag "Mac-style CR" 2)) + :group 'doom-modeline) + +(defcustom doom-modeline-indent-info nil + "Whether display the indentation information." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-total-line-number nil + "Whether display the total line number." + :type 'boolean + :group 'doom-modeline) + +;; It is based upon `editorconfig-indentation-alist' but is used to read indentation levels instead +;; of setting them. (https://github.com/editorconfig/editorconfig-emacs) +(defcustom doom-modeline-indent-alist + '((apache-mode apache-indent-level) + (awk-mode c-basic-offset) + (bpftrace-mode c-basic-offset) + (c++-mode c-basic-offset) + (c-mode c-basic-offset) + (cmake-mode cmake-tab-width) + (coffee-mode coffee-tab-width) + (cperl-mode cperl-indent-level) + (crystal-mode crystal-indent-level) + (csharp-mode c-basic-offset) + (css-mode css-indent-offset) + (d-mode c-basic-offset) + (emacs-lisp-mode lisp-indent-offset) + (enh-ruby-mode enh-ruby-indent-level) + (erlang-mode erlang-indent-level) + (ess-mode ess-indent-offset) + (f90-mode f90-associate-indent + f90-continuation-indent + f90-critical-indent + f90-do-indent + f90-if-indent + f90-program-indent + f90-type-indent) + (feature-mode feature-indent-offset + feature-indent-level) + (fsharp-mode fsharp-continuation-offset + fsharp-indent-level + fsharp-indent-offset) + (groovy-mode groovy-indent-offset) + (haskell-mode haskell-indent-spaces + haskell-indent-offset + haskell-indentation-layout-offset + haskell-indentation-left-offset + haskell-indentation-starter-offset + haskell-indentation-where-post-offset + haskell-indentation-where-pre-offset + shm-indent-spaces) + (haxor-mode haxor-tab-width) + (idl-mode c-basic-offset) + (jade-mode jade-tab-width) + (java-mode c-basic-offset) + (js-mode js-indent-level) + (js-jsx-mode js-indent-level + sgml-basic-offset) + (js2-mode js2-basic-offset) + (js2-jsx-mode js2-basic-offset + sgml-basic-offset) + (js3-mode js3-indent-level) + (json-mode js-indent-level) + (julia-mode julia-indent-offset) + (kotlin-mode kotlin-tab-width) + (latex-mode tex-indent-basic) + (lisp-mode lisp-indent-offset) + (livescript-mode livescript-tab-width) + (lua-mode lua-indent-level) + (matlab-mode matlab-indent-level) + (mips-mode mips-tab-width) + (mustache-mode mustache-basic-offset) + (nasm-mode nasm-basic-offset) + (nginx-mode nginx-indent-level) + (nxml-mode nxml-child-indent) + (objc-mode c-basic-offset) + (octave-mode octave-block-offset) + (perl-mode perl-indent-level) + (php-mode c-basic-offset) + (pike-mode c-basic-offset) + (ps-mode ps-mode-tab) + (pug-mode pug-tab-width) + (puppet-mode puppet-indent-level) + (python-mode python-indent-offset) + (ruby-mode ruby-indent-level) + (rust-mode rust-indent-offset) + (rustic-mode rustic-indent-offset) + (scala-mode scala-indent:step) + (scss-mode css-indent-offset) + (sgml-mode sgml-basic-offset) + (sh-mode sh-basic-offset + sh-indentation) + (slim-mode slim-indent-offset) + (sml-mode sml-indent-level) + (tcl-mode tcl-indent-level + tcl-continued-indent-level) + (terra-mode terra-indent-level) + (typescript-mode typescript-indent-level) + (verilog-mode verilog-indent-level + verilog-indent-level-behavioral + verilog-indent-level-declaration + verilog-indent-level-module + verilog-cexp-indent + verilog-case-indent) + (web-mode web-mode-attr-indent-offset + web-mode-attr-value-indent-offset + web-mode-code-indent-offset + web-mode-css-indent-offset + web-mode-markup-indent-offset + web-mode-sql-indent-offset + web-mode-block-padding + web-mode-script-padding + web-mode-style-padding) + (yaml-mode yaml-indent-offset)) + "Indentation retrieving variables matched to major modes. + +Which is used when `doom-modeline-indent-info' is non-nil. +When multiple variables are specified for a mode, they will be tried resolved +in the given order." + :type '(alist :key-type symbol :value-type sexp) + :group 'doom-modeline) + +(defcustom doom-modeline-vcs-icon t + "Whether display the icon of vcs segment. + +It respects option `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-vcs-max-length 15 + "The maximum displayed length of the branch name of version control." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-vcs-display-function #'doom-modeline-vcs-name + "The function to display the branch name." + :type 'function + :group 'doom-modeline) + +(defcustom doom-modeline-check-icon t + "Whether display the icon of check segment. + +It respects option `doom-modeline-icon'." + :type 'boolean + :group 'doom-modeline) + +(define-obsolete-variable-alias + 'doom-modeline-checker-simple-format + 'doom-modeline-check-simple-format + "4.2.0") + +(defcustom doom-modeline-check-simple-format nil + "If non-nil, only display one number for check information if applicable." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-number-limit 99 + "The maximum number displayed for notifications." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-workspace-name t + "Whether display the workspace name. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-persp-name t + "Whether display the perspective name. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-display-default-persp-name nil + "If non nil the default perspective name is displayed in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-persp-icon t + "If non nil the perspective name is displayed alongside a folder icon." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-repl t + "Whether display the `repl' state. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-lsp t + "Whether display the `lsp' state. + +Non-nil to display in the mode-line." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-github nil + "Whether display the GitHub notifications. + +It requires `ghub' and `async' packages. Additionally, your GitHub personal +access token must have `notifications' permissions. + +If you use `pass' to manage your secrets, you also need to add this hook: + (add-hook \\='doom-modeline-before-github-fetch-notification-hook + #\\='auth-source-pass-enable)" + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-github-interval 1800 ; (* 30 60) + "The interval of checking GitHub." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-env-version t + "Whether display the environment version." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-modal t + "Whether display the modal state. + +Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-modal-icon t + "Whether display the modal state icon. + +Including `evil', `overwrite', `god', `ryo' and `xah-fly-keys', etc." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-modal-modern-icon t + "Whether display the modern icons for modals." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-always-show-macro-register nil + "When non-nil, always show the register name when recording an evil macro." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-mu4e nil + "Whether display the mu4e notifications. + +It requires `mu4e-alert' package." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-gnus nil + "Whether to display notifications from gnus. + +It requires `gnus' to be setup" + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-timer 2 + "The wait time in minutes before gnus fetches mail. + +If nil, don't set up a hook." + :type 'integer + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-idle nil + "Whether to wait an idle time to scan for news. + +When t, sets `doom-modeline-gnus-timer' as an idle timer. If a +number, Emacs must have been idle this given time, checked after +reach the defined timer, to fetch news. The time step can be +configured in `gnus-demon-timestep'." + :type '(choice + (boolean :tag "Set `doom-modeline-gnus-timer' as an idle timer") + (number :tag "Set a custom idle timer")) + :group 'doom-modeline) + +(defcustom doom-modeline-gnus-excluded-groups nil + "A list of groups to be excluded from the unread count. +Groups' names list in `gnus-newsrc-alist'`" + :type '(repeat string) + :group 'doom-modeline) + +(defcustom doom-modeline-irc t + "Whether display the irc notifications. + +It requires either `circe' , `erc' or `rcirc' package." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-irc-buffers nil + "Whether display the unread irc buffers." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-irc-stylize #'doom-modeline-shorten-irc + "Which function to call to stylize IRC buffer names. + +Buffer names are stylized using the selected `function'. +By default buffer names are shortened, you may want to disable or call +your own function. +The function must accept `buffer-name' and return `shortened-name'." + :type '(radio (function-item :tag "Shorten" + :format "%t: %v\n %h" + doom-modeline-shorten-irc) + (function-item + :tag "Leave unchanged" + :format "%t: %v\n" + identity) + (function + :tag "Other function")) + :group 'doom-modeline) + +(defcustom doom-modeline-battery t + "Whether display the battery status. + +It respects `display-battery-mode'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-time t + "Whether display the time. + +It respects `display-time-mode'." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-display-misc-in-all-mode-lines t + "Whether display the misc segment on all mode lines. + +If nil, display only if the mode line is active." + :type 'boolean + :group 'doom-modeline) + +(defcustom doom-modeline-always-visible-segments nil + "A list of segments that should be visible even in inactive windows." + :type '(repeat symbol) + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-file-name-function #'identity + "The function to handle variable `buffer-file-name'." + :type 'function + :group 'doom-modeline) + +(defcustom doom-modeline-buffer-file-truename-function #'identity + "The function to handle `buffer-file-truename'." + :type 'function + :group 'doom-modeline) + +(defcustom doom-modeline-k8s-show-namespace t + "Whether to show the current Kubernetes context's default namespace." + :type 'boolean + :group 'doom-modeline) + + +;; +;; Faces +;; + +(defgroup doom-modeline-faces nil + "The faces of `doom-modeline'." + :group 'doom-modeline + :group 'faces + :link '(url-link :tag "Homepage" "https://github.com/seagle0128/doom-modeline")) + +(defface doom-modeline + '((t ())) + "Default face." + :group 'doom-modeline-faces) + +(defface doom-modeline-emphasis + '((t (:inherit (doom-modeline mode-line-emphasis)))) + "Face used for emphasis." + :group 'doom-modeline-faces) + +(defface doom-modeline-highlight + '((t (:inherit (doom-modeline mode-line-highlight)))) + "Face used for highlighting." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-path + '((t (:inherit (doom-modeline-emphasis bold)))) + "Face used for the dirname part of the buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-file + '((t (:inherit (doom-modeline mode-line-buffer-id bold)))) + "Face used for the filename part of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-modified + '((t (:inherit (doom-modeline warning bold) :background unspecified))) + "Face used for the \\='unsaved\\=' symbol in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-major-mode + '((t (:inherit (doom-modeline-emphasis bold)))) + "Face used for the major-mode segment in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-minor-mode + '((t (:inherit (doom-modeline font-lock-doc-face) :weight normal :slant normal))) + "Face used for the minor-modes segment in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-parent-dir + '((t (:inherit (doom-modeline font-lock-comment-face bold)))) + "Face used for the project parent directory of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-dir + '((t (:inherit (doom-modeline font-lock-string-face bold)))) + "Face used for the project directory of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-project-root-dir + '((t (:inherit (doom-modeline-emphasis bold)))) + "Face used for the project part of the mode-line buffer path." + :group 'doom-modeline-faces) + +(defface doom-modeline-panel + '((t (:inherit doom-modeline-highlight))) + "Face for \\='X out of Y\\=' segments. +This applies to `anzu', `evil-substitute', `iedit' etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-host + '((t (:inherit (doom-modeline italic)))) + "Face for remote hosts in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-input-method + '((t (:inherit (doom-modeline-emphasis)))) + "Face for input method in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-input-method-alt + '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) + "Alternative face for input method in the mode-line." + :group 'doom-modeline-faces) + +(defface doom-modeline-debug + '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) + "Face for debug-level messages in the mode-line. Used by vcs, check, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-info + '((t (:inherit (doom-modeline success)))) + "Face for info-level messages in the mode-line. Used by vcs, check, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-warning + '((t (:inherit (doom-modeline warning)))) + "Face for warnings in the mode-line. Used by vcs, check, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-urgent + '((t (:inherit (doom-modeline error)))) + "Face for errors in the mode-line. Used by vcs, check, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-notification + '((t (:inherit doom-modeline-warning))) + "Face for notifications in the mode-line. Used by GitHub, mu4e, etc. +Also see the face `doom-modeline-unread-number'." + :group 'doom-modeline-faces) + +(defface doom-modeline-unread-number + '((t (:inherit doom-modeline :slant italic))) + "Face for unread number in the mode-line. Used by GitHub, mu4e, etc." + :group 'doom-modeline-faces) + +(defface doom-modeline-bar + '((t (:inherit doom-modeline-highlight))) + "The face used for the left-most bar in the mode-line of an active window." + :group 'doom-modeline-faces) + +(defface doom-modeline-bar-inactive + `((t (:inherit doom-modeline))) + "The face used for the left-most bar in the mode-line of an inactive window." + :group 'doom-modeline-faces) + +(defface doom-modeline-debug-visual + '((((background light)) :foreground "#D4843E" :inherit doom-modeline) + (((background dark)) :foreground "#915B2D" :inherit doom-modeline)) + "Face to use for the mode-line while debugging." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-emacs-state + '((t (:inherit (doom-modeline font-lock-builtin-face)))) + "Face for the Emacs state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-insert-state + '((t (:inherit (doom-modeline font-lock-keyword-face)))) + "Face for the insert state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-motion-state + '((t (:inherit (doom-modeline font-lock-doc-face) :slant normal))) + "Face for the motion state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-normal-state + '((t (:inherit doom-modeline-info))) + "Face for the normal state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-operator-state + '((t (:inherit (doom-modeline mode-line)))) + "Face for the operator state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-visual-state + '((t (:inherit doom-modeline-warning))) + "Face for the visual state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-replace-state + '((t (:inherit doom-modeline-urgent))) + "Face for the replace state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-evil-user-state + '((t (:inherit doom-modeline-warning))) + "Face for the replace state tag in evil indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-overwrite + '((t (:inherit doom-modeline-urgent))) + "Face for overwrite indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-god + '((t (:inherit doom-modeline-info))) + "Face for god-mode indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-ryo + '((t (:inherit doom-modeline-info))) + "Face for RYO indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-fly-insert-state + '((t (:inherit (doom-modeline font-lock-keyword-face)))) + "Face for the insert state in xah-fly-keys indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-fly-normal-state + '((t (:inherit doom-modeline-info))) + "Face for the normal state in xah-fly-keys indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-boon-command-state + '((t (:inherit doom-modeline-info))) + "Face for the command state tag in boon indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-boon-insert-state + '((t (:inherit (doom-modeline font-lock-keyword-face)))) + "Face for the insert state tag in boon indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-boon-special-state + '((t (:inherit (doom-modeline font-lock-builtin-face)))) + "Face for the special state tag in boon indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-boon-off-state + '((t (:inherit (doom-modeline mode-line)))) + "Face for the off state tag in boon indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-meow-normal-state + '((t (:inherit doom-modeline-evil-normal-state))) + "Face for the normal state in meow-edit indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-meow-insert-state + '((t (:inherit doom-modeline-evil-insert-state))) + "Face for the insert state in meow-edit indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-meow-beacon-state + '((t (:inherit doom-modeline-evil-visual-state))) + "Face for the beacon state in meow-edit indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-meow-motion-state + '((t (:inherit doom-modeline-evil-motion-state))) + "Face for the motion state in meow-edit indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-meow-keypad-state + '((t (:inherit doom-modeline-evil-operator-state))) + "Face for the keypad state in meow-edit indicator." + :group 'doom-modeline-faces) + +(defface doom-modeline-persp-name + '((t (:inherit (doom-modeline font-lock-comment-face italic)))) + "Face for the persp name." + :group 'doom-modeline-faces) + +(defface doom-modeline-persp-buffer-not-in-persp + '((t (:inherit (doom-modeline font-lock-doc-face italic)))) + "Face for the buffers which are not in the persp." + :group 'doom-modeline-faces) + +(defface doom-modeline-repl-success + '((t (:inherit doom-modeline-info))) + "Face for REPL success state." + :group 'doom-modeline-faces) + +(defface doom-modeline-repl-warning + '((t (:inherit doom-modeline-warning))) + "Face for REPL warning state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-success + '((t (:inherit doom-modeline-info))) + "Face for LSP success state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-warning + '((t (:inherit doom-modeline-warning))) + "Face for LSP warning state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-error + '((t (:inherit doom-modeline-urgent))) + "Face for LSP error state." + :group 'doom-modeline-faces) + +(defface doom-modeline-lsp-running + '((t (:inherit (doom-modeline compilation-mode-line-run) :weight normal :slant normal))) + "Face for LSP running state." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-charging + '((t (:inherit doom-modeline-info))) + "Face for battery charging status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-full + '((t (:inherit doom-modeline-info))) + "Face for battery full status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-normal + '((t (:inherit (doom-modeline mode-line)))) + "Face for battery normal status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-warning + '((t (:inherit doom-modeline-warning))) + "Face for battery warning status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-critical + '((t (:inherit doom-modeline-urgent))) + "Face for battery critical status." + :group 'doom-modeline-faces) + +(defface doom-modeline-battery-error + '((t (:inherit doom-modeline-urgent))) + "Face for battery error status." + :group 'doom-modeline-faces) + +(defface doom-modeline-buffer-timemachine + '((t (:inherit doom-modeline-buffer-file :slant italic))) + "Face for timemachine status." + :group 'doom-modeline-faces) + +(defface doom-modeline-time + '((t (:inherit doom-modeline))) + "Face for display time." + :group 'doom-modeline-faces) + +(defface doom-modeline-compilation + '((t (:inherit doom-modeline-warning :slant italic :height 0.9))) + "Face for compilation progress." + :group 'doom-modeline-faces) + +;; +;; Externals +;; + +(defvar mode-line-right-align-edge) + +(declare-function doom-modeline-shorten-irc "doom-modeline-segments") +(declare-function face-remap-remove-relative "face-remap") +(declare-function ffip-project-root "ext:find-file-in-project") +(declare-function project-root "project") +(declare-function projectile-project-root "ext:projectile") + + +;; +;; Utilities +;; + +(defun doom-modeline-add-font-lock () + "Fontify `doom-modeline-def-*' statements." + (font-lock-add-keywords + 'emacs-lisp-mode + '(("(\\(doom-modeline-def-.+\\)\\_> +\\(.*?\\)\\_>" + (1 font-lock-keyword-face) + (2 font-lock-constant-face))))) +(doom-modeline-add-font-lock) + +(defun doom-modeline-add-imenu () + "Add to `imenu' index." + (add-to-list + 'imenu-generic-expression + '("Modelines" + "^\\s-*(\\(doom-modeline-def-modeline\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\s'\\|\\\\.\\)+\\)" + 2)) + (add-to-list + 'imenu-generic-expression + '("Segments" + "^\\s-*(\\(doom-modeline-def-segment\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" + 2)) + (add-to-list + 'imenu-generic-expression + '("Envs" + "^\\s-*(\\(doom-modeline-def-env\\)\\s-+\\(\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)" + 2))) + + +;; +;; Core helpers +;; + +;; FIXME #183: Force to calculate mode-line height +;; @see https://github.com/seagle0128/doom-modeline/issues/183 +;; @see https://github.com/seagle0128/doom-modeline/issues/483 +(unless (>= emacs-major-version 29) + (eval-and-compile + (defun doom-modeline-redisplay (&rest _) + "Call `redisplay' to trigger mode-line height calculations. + +Certain functions, including e.g. `fit-window-to-buffer', base +their size calculations on values which are incorrect if the +mode-line has a height different from that of the `default' face +and certain other calculations have not yet taken place for the +window in question. + +These calculations can be triggered by calling `redisplay' +explicitly at the appropriate time and this functions purpose +is to make it easier to do so. + +This function is like `redisplay' with non-nil FORCE argument, +but it will only trigger a redisplay when there is a non nil +`mode-line-format' and the height of the mode-line is different +from that of the `default' face. This function is intended to be +used as an advice to window creation functions." + (when (and (bound-and-true-p doom-modeline-mode) + mode-line-format + (/= (frame-char-height) (window-mode-line-height))) + (redisplay t)))) + (advice-add #'fit-window-to-buffer :before #'doom-modeline-redisplay)) + +;; For `flycheck-color-mode-line' +(with-eval-after-load 'flycheck-color-mode-line + (defvar flycheck-color-mode-line-face-to-color) + (setq flycheck-color-mode-line-face-to-color 'doom-modeline)) + +(defun doom-modeline-icon-displayable-p () + "Return non-nil if icons are displayable." + (and doom-modeline-icon (featurep 'nerd-icons))) + +(defun doom-modeline-mwheel-available-p () + "Whether mouse wheel is available." + (and (featurep 'mwheel) (bound-and-true-p mouse-wheel-mode))) + +;; Keep `doom-modeline-current-window' up-to-date +(defun doom-modeline--selected-window () + "Get the selected window." + (frame-selected-window)) + +(defvar doom-modeline-current-window (doom-modeline--selected-window) + "Current window.") + +(defun doom-modeline--active () + "Whether is an active window." + (unless (and (bound-and-true-p mini-frame-frame) + (and (frame-live-p mini-frame-frame) + (frame-visible-p mini-frame-frame))) + (and doom-modeline-current-window + (eq (doom-modeline--selected-window) doom-modeline-current-window)))) + +(defvar-local doom-modeline--limited-width-p nil) + +(defun doom-modeline--segment-visible (name) + "Whether the segment NAME should be displayed." + (and + (or (doom-modeline--active) + (member name doom-modeline-always-visible-segments)) + (not doom-modeline--limited-width-p))) + +(defun doom-modeline-set-selected-window (&rest _) + "Set `doom-modeline-current-window' appropriately." + (let ((win (doom-modeline--selected-window))) + (setq doom-modeline-current-window + (if (minibuffer-window-active-p win) + (minibuffer-selected-window) + win)))) + +(defun doom-modeline-unset-selected-window () + "Unset `doom-modeline-current-window' appropriately." + (setq doom-modeline-current-window nil)) + +(add-hook 'pre-redisplay-functions #'doom-modeline-set-selected-window) + +;; Ensure modeline is inactive when Emacs is unfocused +(defvar doom-modeline--remap-faces '(mode-line + mode-line-active + mode-line-emphasis + mode-line-highlight + mode-line-buffer-id + doom-modeline + solaire-mode-line-face + solaire-mode-line-active-face + paradox-mode-line-face + flycheck-color-mode-line-error-face + flycheck-color-mode-line-warning-face + flycheck-color-mode-line-info-face + flycheck-color-mode-line-success-face)) + +(defvar doom-modeline--remap-face-cookie-alist nil) +(defun doom-modeline-focus () + "Focus mode-line." + (mapc #'face-remap-remove-relative doom-modeline--remap-face-cookie-alist)) + +(defun doom-modeline-unfocus () + "Unfocus mode-line." + (dolist (face doom-modeline--remap-faces) + (add-to-list 'doom-modeline--remap-face-cookie-alist + (face-remap-add-relative face 'mode-line-inactive)))) + +(with-no-warnings + (if (boundp 'after-focus-change-function) + (progn + (defun doom-modeline-focus-change (&rest _) + (if (frame-focus-state (frame-parent)) + (progn + (doom-modeline-focus) + ;; HACK: pulse after focusing in the frame to refresh the buffer name. + ;; @see https://github.com/seagle0128/doom-modeline/issues/591 + (when (fboundp 'pulse-momentary-highlight-region) + (pulse-momentary-highlight-region 0 0))) + (doom-modeline-unfocus))) + (advice-add #'handle-switch-frame :after #'doom-modeline-focus-change) + (add-function :after after-focus-change-function #'doom-modeline-focus-change)) + (progn + (add-hook 'focus-in-hook #'doom-modeline-focus) + (add-hook 'focus-out-hook #'doom-modeline-unfocus)))) + + +;; +;; Core +;; + +(defvar doom-modeline-fn-alist ()) +(defvar doom-modeline-var-alist ()) + +(defmacro doom-modeline-def-segment (name &rest body) + "Define a modeline segment NAME with BODY and byte compiles it." + (declare (indent defun) (doc-string 2)) + (let ((sym (intern (format "doom-modeline-segment--%s" name))) + (docstring (if (stringp (car body)) + (pop body) + (format "%s modeline segment" name)))) + (cond ((and (symbolp (car body)) + (not (cdr body))) + `(add-to-list 'doom-modeline-var-alist (cons ',name ',(car body)))) + (t + `(progn + (defun ,sym () ,docstring ,@body) + (add-to-list 'doom-modeline-fn-alist (cons ',name ',sym)) + ,(unless (bound-and-true-p byte-compile-current-file) + `(let (byte-compile-warnings) + (unless (and (fboundp 'subr-native-elisp-p) + (subr-native-elisp-p (symbol-function #',sym))) + (byte-compile #',sym))))))))) + +(defun doom-modeline--prepare-segments (segments) + "Prepare mode-line `SEGMENTS'." + (let (forms it) + (dolist (seg segments) + (cond ((stringp seg) + (push seg forms)) + ((symbolp seg) + (cond ((setq it (alist-get seg doom-modeline-fn-alist)) + (push (list :eval (list it)) forms)) + ((setq it (alist-get seg doom-modeline-var-alist)) + (push it forms)) + ((error "%s is not a defined segment" seg)))) + ((error "%s is not a valid segment" seg)))) + (nreverse forms))) + +(defun doom-modeline-def-modeline (name lhs &optional rhs) + "Define a modeline format and byte-compiles it. +NAME is a symbol to identify it (used by `doom-modeline' for retrieval). +LHS and RHS are lists of symbols of modeline segments defined with +`doom-modeline-def-segment'. + +Example: + (doom-modeline-def-modeline \\='minimal + \\='(bar matches \" \" buffer-info) + \\='(media-info major-mode)) + (doom-modeline-set-modeline \\='minimal t)" + (let ((sym (intern (format "doom-modeline-format--%s" name))) + (lhs-forms (doom-modeline--prepare-segments lhs)) + (rhs-forms (doom-modeline--prepare-segments rhs))) + (defalias sym + (lambda () + (list lhs-forms + (let* ((rhs-str (format-mode-line (cons "" rhs-forms))) + (rhs-width (progn + (add-face-text-property + 0 (length rhs-str) 'mode-line t rhs-str) + (doom-modeline-string-pixel-width rhs-str)))) + (propertize + " " + 'face (doom-modeline-face) + 'display + ;; Backport from `mode-line-right-align-edge' in 30 + (if (and (display-graphic-p) + (not (eq mode-line-right-align-edge 'window))) + `(space :align-to (- ,mode-line-right-align-edge + (,rhs-width))) + `(space :align-to (,(- (window-pixel-width) + (window-scroll-bar-width) + (window-right-divider-width) + (* (or (cdr (window-margins)) 1) + (frame-char-width)) + (pcase mode-line-right-align-edge + ('right-margin + (or (cdr (window-margins)) 0)) + ('right-fringe + (or (cadr (window-fringes)) 0)) + (_ 0)) + rhs-width)))))) + rhs-forms)) + (concat "Modeline:\n" + (format " %s\n %s" + (prin1-to-string lhs) + (prin1-to-string rhs)))))) +(put 'doom-modeline-def-modeline 'lisp-indent-function 'defun) + +(defun doom-modeline (key) + "Return a mode-line configuration associated with KEY (a symbol). +Throws an error if it doesn't exist." + (let ((fn (intern-soft (format "doom-modeline-format--%s" key)))) + (when (functionp fn) + `(:eval (,fn))))) + +(defun doom-modeline-set-modeline (key &optional default) + "Set the modeline format. Does nothing if the modeline KEY doesn't exist. +If DEFAULT is non-nil, set the default mode-line for all buffers." + (when-let ((modeline (doom-modeline key))) + (setf (if default + (default-value 'mode-line-format) + mode-line-format) + (list "%e" modeline)))) + +;; +;; Helpers +;; + +(defconst doom-modeline-ellipsis + (if (char-displayable-p ?…) "…" "...") + "Ellipsis.") + +(defsubst doom-modeline-spc () + "Whitespace." + (propertize " " 'face (doom-modeline-face))) + +(defsubst doom-modeline-wspc () + "Wide Whitespace." + (propertize " " 'face (doom-modeline-face))) + +(defsubst doom-modeline-vspc () + "Thin whitespace." + (propertize " " + 'face (doom-modeline-face) + 'display '((space :relative-width 0.5)))) + +(defun doom-modeline-face (&optional face inactive-face) + "Display FACE in active window, and INACTIVE-FACE in inactive window. +IF FACE is nil, `mode-line' face will be used. +If INACTIVE-FACE is nil, `mode-line-inactive' face will be used." + (if (doom-modeline--active) + (or (and (facep face) `(:inherit (doom-modeline ,face))) + (and (facep 'mode-line-active) '(:inherit (doom-modeline mode-line-active))) + '(:inherit (doom-modeline mode-line))) + (or (and (facep face) `(:inherit (doom-modeline mode-line-inactive ,face))) + (and (facep inactive-face) `(:inherit (doom-modeline ,inactive-face))) + '(:inherit (doom-modeline mode-line-inactive))))) + +(defun doom-modeline-string-pixel-width (str) + "Return the width of STR in pixels." + (if (fboundp 'string-pixel-width) + (string-pixel-width str) + (* (string-width str) (window-font-width nil 'mode-line) + (if (display-graphic-p) 1.05 1.0)))) + +(defun doom-modeline--font-height () + "Calculate the actual char height of the mode-line." + (let ((height (face-attribute 'mode-line :height)) + (char-height (window-font-height nil 'mode-line))) + (round + (* 1.0 (cond ((integerp height) (/ height 10)) + ((floatp height) (* height char-height)) + (t char-height)))))) + +(defun doom-modeline--original-value (sym) + "Return the original value for SYM, if any. + +If SYM has an original value, return it in a list. Return nil +otherwise." + (let* ((orig-val-expr (get sym 'standard-value))) + (when (consp orig-val-expr) + (ignore-errors + (list + (eval (car orig-val-expr))))))) + +(defun doom-modeline-add-variable-watcher (symbol watch-function) + "Cause WATCH-FUNCTION to be called when SYMBOL is set if possible. + +See docs of `add-variable-watcher'." + (when (fboundp 'add-variable-watcher) + (add-variable-watcher symbol watch-function))) + +(defun doom-modeline-propertize-icon (icon &optional face) + "Propertize the ICON with the specified FACE. + +The face should be the first attribute, or the font family may be overridden. +So convert the face \":family XXX :height XXX :inherit XXX\" to +\":inherit XXX :family XXX :height XXX\". +See https://github.com/seagle0128/doom-modeline/issues/301." + (when icon + (if (doom-modeline-icon-displayable-p) + (when-let ((props (get-text-property 0 'face icon))) + (when (listp props) + (cl-destructuring-bind (&key family height inherit &allow-other-keys) props + (propertize icon 'face `(:inherit (doom-modeline ,(or face inherit props)) + :family ,(or family "") + :height ,(or height 1.0)))))) + (propertize icon 'face `(:inherit (doom-modeline ,face)))))) + +(defun doom-modeline-icon (icon-set icon-name unicode text &rest args) + "Display icon of ICON-NAME with ARGS in mode-line. + +ICON-SET includes `ipsicon', `octicon', `pomicon', `powerline', `faicon', +`wicon', `sucicon', `devicon', `codicon', `flicon' and `mdicon', etc. +UNICODE is the unicode char fallback. TEXT is the ASCII char fallback. +ARGS is same as `nerd-icons-octicon' and others." + (let ((face `(:inherit (doom-modeline + ,(or (plist-get args :face) 'mode-line))))) + (cond + ;; Icon + ((and (doom-modeline-icon-displayable-p) + icon-name + (not (string-empty-p icon-name))) + (if-let* ((func (nerd-icons--function-name icon-set)) + (icon (and (fboundp func) + (apply func icon-name args)))) + (doom-modeline-propertize-icon icon face) + "")) + ;; Unicode fallback + ((and doom-modeline-unicode-fallback + unicode + (not (string-empty-p unicode)) + (char-displayable-p (string-to-char unicode))) + (propertize unicode 'face face)) + ;; ASCII text + (text + (propertize text 'face face)) + ;; Fallback + (t "")))) + +(defun doom-modeline-icon-for-buffer () + "Get the formatted icon for the current buffer." + (nerd-icons-icon-for-buffer)) + +(defun doom-modeline-display-icon (icon) + "Display ICON in mode-line." + (if (doom-modeline--active) + icon + (doom-modeline-propertize-icon icon 'mode-line-inactive))) + +(defun doom-modeline-display-text (text) + "Display TEXT in mode-line." + (if (doom-modeline--active) + text + (propertize text 'face `(:inherit (mode-line-inactive + ,(get-text-property 0 'face text)))))) + +(defun doom-modeline-vcs-name () + "Display the vcs name." + (and vc-mode (cadr (split-string (string-trim vc-mode) "^[A-Z]+[-:]+")))) + +(defun doom-modeline--create-bar-image (face width height) + "Create the bar image. + +Use FACE for the bar, WIDTH and HEIGHT are the image size in pixels." + (when (and (image-type-available-p 'pbm) + (numberp width) (> width 0) + (numberp height) (> height 0)) + (propertize + " " 'display + (let ((color (or (face-background face nil t) "None"))) + (ignore-errors + (create-image + (concat (format "P1\n%i %i\n" width height) + (make-string (* width height) ?1) + "\n") + 'pbm t :scale 1 :foreground color :ascent 'center)))))) + +(defun doom-modeline--create-hud-image + (face1 face2 width height top-margin bottom-margin) + "Create the hud image. + +Use FACE1 for the bar, FACE2 for the background. +WIDTH and HEIGHT are the image size in pixels. +TOP-MARGIN and BOTTOM-MARGIN are the size of the margin above and below the bar, +respectively." + (when (and (display-graphic-p) + (image-type-available-p 'pbm) + (numberp width) (> width 0) + (numberp height) (> height 0)) + (let ((min-height (min height doom-modeline-hud-min-height))) + (unless (> (- height top-margin bottom-margin) min-height) + (let ((margin (- height min-height))) + (setq top-margin (/ (* margin top-margin) (+ top-margin bottom-margin)) + bottom-margin (- margin top-margin))))) + (propertize + " " 'display + (let ((color1 (or (face-background face1 nil t) "None")) + (color2 (or (face-background face2 nil t) "None"))) + (create-image + (concat + (format "P1\n%i %i\n" width height) + (make-string (* top-margin width) ?0) + (make-string (* (- height top-margin bottom-margin) width) ?1) + (make-string (* bottom-margin width) ?0) + "\n") + 'pbm t :foreground color1 :background color2 :ascent 'center))))) + +;; Check whether `window-total-width' is smaller than the limit +(defun doom-modeline-window-size-change-function (&rest _) + "Function for `window-size-change-functions'." + (setq doom-modeline--limited-width-p + (cond + ((integerp doom-modeline-window-width-limit) + (<= (window-total-width) doom-modeline-window-width-limit)) + ((floatp doom-modeline-window-width-limit) + (<= (/ (window-total-width) (frame-width) 1.0) + doom-modeline-window-width-limit))))) + +(add-hook 'after-revert-hook #'doom-modeline-window-size-change-function) +(add-hook 'buffer-list-update-hook #'doom-modeline-window-size-change-function) +(add-hook 'window-size-change-functions #'doom-modeline-window-size-change-function) + +(defvar-local doom-modeline--project-root nil) +(defun doom-modeline--project-root () + "Get the path to the project root. +Return nil if no project was found." + (or doom-modeline--project-root + (setq doom-modeline--project-root + (cond + ((and (memq doom-modeline-project-detection '(auto ffip)) + (fboundp 'ffip-project-root)) + (let ((inhibit-message t)) + (ffip-project-root))) + ((and (memq doom-modeline-project-detection '(auto projectile)) + (bound-and-true-p projectile-mode)) + (projectile-project-root)) + ((and (memq doom-modeline-project-detection '(auto project)) + (fboundp 'project-current)) + (when-let ((project (project-current))) + (expand-file-name + (if (fboundp 'project-root) + (project-root project) + (car (with-no-warnings + (project-roots project))))))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-project-detection + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-project-detection val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (setq doom-modeline--project-root nil) + (and buffer-file-name (revert-buffer t t))))))) + +(defun doom-modeline-project-p () + "Check if the file is in a project." + (doom-modeline--project-root)) + +(defun doom-modeline-project-root () + "Get the path to the root of your project. +Return `default-directory' if no project was found." + (abbreviate-file-name + (or (doom-modeline--project-root) default-directory))) + +(defun doom-modeline--format-buffer-file-name () + "Get and format the buffer file name." + (let ((buffer-file-name (file-local-name + (or (buffer-file-name (buffer-base-buffer)) "")))) + (or (and doom-modeline-buffer-file-name-function + (funcall doom-modeline-buffer-file-name-function buffer-file-name)) + buffer-file-name))) + +(defun doom-modeline--format-buffer-file-truename (b-f-n) + "Get and format buffer file truename via B-F-N." + (let ((buffer-file-truename (file-local-name + (or (file-truename b-f-n) "")))) + (or (and doom-modeline-buffer-file-truename-function + (funcall doom-modeline-buffer-file-truename-function buffer-file-truename)) + buffer-file-truename))) + +(defun doom-modeline-buffer-file-name () + "Propertize file name based on `doom-modeline-buffer-file-name-style'." + (let* ((buffer-file-name (doom-modeline--format-buffer-file-name)) + (buffer-file-truename (doom-modeline--format-buffer-file-truename buffer-file-name)) + (file-name + (pcase doom-modeline-buffer-file-name-style + ('auto + (if (doom-modeline-project-p) + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide) + (propertize "%b" 'face 'doom-modeline-buffer-file))) + ('truncate-upto-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink)) + ('truncate-from-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil 'shrink)) + ('truncate-with-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink 'hide)) + ('truncate-except-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename 'shrink 'shrink)) + ('truncate-upto-root + (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename)) + ('truncate-all + (doom-modeline--buffer-file-name-truncate buffer-file-name buffer-file-truename t)) + ('truncate-nil + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename)) + ('relative-to-project + (doom-modeline--buffer-file-name-relative buffer-file-name buffer-file-truename)) + ('relative-from-project + (doom-modeline--buffer-file-name buffer-file-name buffer-file-truename nil nil 'hide)) + ('file-name + (propertize (file-name-nondirectory buffer-file-name) + 'face 'doom-modeline-buffer-file)) + ('file-name-with-project + (format "%s|%s" + (propertize (file-name-nondirectory + (directory-file-name (file-local-name (doom-modeline-project-root)))) + 'face 'doom-modeline-project-dir) + (propertize (file-name-nondirectory buffer-file-name) + 'face 'doom-modeline-buffer-file))) + ((or 'buffer-name _) + (propertize "%b" 'face 'doom-modeline-buffer-file))))) + (propertize (if (string-empty-p file-name) + (propertize "%b" 'face 'doom-modeline-buffer-file) + file-name) + 'mouse-face 'mode-line-highlight + 'help-echo (concat buffer-file-truename + (unless (string= (file-name-nondirectory buffer-file-truename) + (buffer-name)) + (concat "\n" (buffer-name))) + "\nmouse-1: Previous buffer\nmouse-3: Next buffer") + 'local-map mode-line-buffer-identification-keymap))) + +(defun doom-modeline--buffer-file-name-truncate (file-path true-file-path &optional truncate-tail) + "Propertize file name that truncates every dir along path. + +If TRUNCATE-TAIL is t also truncate the parent directory of the file." + (let ((dirs (shrink-path-prompt (file-name-directory true-file-path)))) + (if (null dirs) + (propertize "%b" 'face 'doom-modeline-buffer-file) + (let ((dirname (car dirs)) + (basename (cdr dirs))) + (concat (propertize (concat dirname + (if truncate-tail (substring basename 0 1) basename) + "/") + 'face 'doom-modeline-project-root-dir) + (propertize (file-name-nondirectory file-path) + 'face 'doom-modeline-buffer-file)))))) + +(defun doom-modeline--buffer-file-name-relative (_file-path true-file-path &optional include-project) + "Propertize file name showing directories relative to project's root only. + +If INCLUDE-PROJECT is non-nil, the project path will be included." + (let ((root (file-local-name (doom-modeline-project-root)))) + (if (null root) + (propertize "%b" 'face 'doom-modeline-buffer-file) + (let ((relative-dirs (file-relative-name (file-name-directory true-file-path) + (if include-project (concat root "../") root)))) + (and (equal "./" relative-dirs) (setq relative-dirs "")) + (concat (propertize relative-dirs 'face 'doom-modeline-buffer-path) + (propertize (file-name-nondirectory true-file-path) + 'face 'doom-modeline-buffer-file)))))) + +(defun doom-modeline--buffer-file-name (file-path + true-file-path + &optional + truncate-project-root-parent + truncate-project-relative-path + hide-project-root-parent) + "Propertize buffer name given by FILE-PATH or TRUE-FILE-PATH. + +If TRUNCATE-PROJECT-ROOT-PARENT is non-nil will be saved by truncating project +root parent down fish-shell style. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => ~/P/F/emacs/lisp/comint.el + +If TRUNCATE-PROJECT-RELATIVE-PATH is non-nil will be saved by truncating project +relative path down fish-shell style. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => ~/Projects/FOSS/emacs/l/comint.el + +If HIDE-PROJECT-ROOT-PARENT is non-nil will hide project root parent. + +Example: + ~/Projects/FOSS/emacs/lisp/comint.el => emacs/lisp/comint.el" + (let ((project-root (file-local-name (doom-modeline-project-root)))) + (concat + ;; Project root parent + (unless hide-project-root-parent + (when-let (root-path-parent + (file-name-directory (directory-file-name project-root))) + (propertize + (if (and truncate-project-root-parent + (not (string-empty-p root-path-parent)) + (not (string= root-path-parent "/"))) + (shrink-path--dirs-internal root-path-parent t) + (abbreviate-file-name root-path-parent)) + 'face 'doom-modeline-project-parent-dir))) + ;; Project directory + (propertize + (concat (file-name-nondirectory (directory-file-name project-root)) "/") + 'face 'doom-modeline-project-dir) + ;; relative path + (propertize + (when-let (relative-path (file-relative-name + (or (file-name-directory + (if doom-modeline-buffer-file-true-name + true-file-path file-path)) + "./") + project-root)) + (if (string= relative-path "./") + "" + (if truncate-project-relative-path + (substring (shrink-path--dirs-internal relative-path t) 1) + relative-path))) + 'face 'doom-modeline-buffer-path) + ;; File name + (propertize (file-name-nondirectory file-path) + 'face 'doom-modeline-buffer-file)))) + +(provide 'doom-modeline-core) + +;;; doom-modeline-core.el ends here diff --git a/emacs/elpa/doom-modeline-20240816.749/doom-modeline-core.elc b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-core.elc Binary files differ. diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-env.el b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-env.el diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline-env.elc b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-env.elc Binary files differ. diff --git a/emacs/elpa/doom-modeline-20240816.749/doom-modeline-pkg.el b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-pkg.el @@ -0,0 +1,17 @@ +(define-package "doom-modeline" "20240816.749" "A minimal and modern mode-line" + '((emacs "25.1") + (compat "29.1.4.5") + (nerd-icons "0.1.0") + (shrink-path "0.3.1")) + :commit "37fc5cfe4cc8487e82942cf8478c4e42eb0a95bd" :authors + '(("Vincent Zhang" . "seagle0128@gmail.com")) + :maintainers + '(("Vincent Zhang" . "seagle0128@gmail.com")) + :maintainer + '("Vincent Zhang" . "seagle0128@gmail.com") + :keywords + '("faces" "mode-line") + :url "https://github.com/seagle0128/doom-modeline") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/doom-modeline-20240816.749/doom-modeline-segments.el b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-segments.el @@ -0,0 +1,3261 @@ +;;; doom-modeline-segments.el --- The segments for doom-modeline -*- lexical-binding: t; -*- + +;; Copyright (C) 2018-2024 Vincent Zhang + +;; This file is not part of GNU Emacs. + +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; + +;;; Commentary: +;; +;; The segments for doom-modeline. +;; Use `doom-modeline-def-segment' to create a new segment. +;; + +;;; Code: + +(require 'doom-modeline-core) +(require 'doom-modeline-env) +(eval-when-compile + (require 'cl-lib) + (require 'seq) + (require 'subr-x)) + + +;; +;; Externals +;; + +(defvar Info-current-file) +(defvar Info-current-node) +(defvar Info-mode-line-node-keymap) +(defvar anzu--cached-count) +(defvar anzu--current-position) +(defvar anzu--overflow-p) +(defvar anzu--state) +(defvar anzu--total-matched) +(defvar anzu-cons-mode-line-p) +(defvar aw-keys) +(defvar battery-echo-area-format) +(defvar battery-load-critical) +(defvar battery-mode-line-format) +(defvar battery-mode-line-limit) +(defvar battery-status-function) +(defvar boon-command-state) +(defvar boon-insert-state) +(defvar boon-off-state) +(defvar boon-special-state) +(defvar display-time-string) +(defvar edebug-execution-mode) +(defvar eglot--managed-mode) +(defvar erc-modified-channels-alist) +(defvar evil-ex-active-highlights-alist) +(defvar evil-ex-argument) +(defvar evil-ex-range) +(defvar evil-mc-frozen) +(defvar evil-state) +(defvar evil-visual-beginning) +(defvar evil-visual-end) +(defvar evil-visual-selection) +(defvar flycheck--automatically-enabled-checkers) +(defvar flycheck-current-errors) +(defvar flycheck-mode-menu-map) +(defvar flymake--mode-line-format) +(defvar flymake--state) +(defvar flymake-menu) +(defvar gnus-newsrc-alist) +(defvar gnus-newsrc-hashtb) +(defvar grip--process) +(defvar helm--mode-line-display-prefarg) +(defvar iedit-occurrences-overlays) +(defvar kele-menu-map) +(defvar meow--indicator) +(defvar minions-mode-line-lighter) +(defvar minions-mode-line-minor-modes-map) +(defvar mlscroll-minimum-current-width) +(defvar mlscroll-right-align) +(defvar mu4e--modeline-item) +(defvar mu4e-alert-mode-line) +(defvar mu4e-alert-modeline-formatter) +(defvar mu4e-modeline-mode) +(defvar nyan-minimum-window-width) +(defvar objed--obj-state) +(defvar objed--object) +(defvar objed-modeline-setup-func) +(defvar persp-nil-name) +(defvar phi-replace--mode-line-format) +(defvar phi-search--overlays) +(defvar phi-search--selection) +(defvar phi-search-mode-line-format) +(defvar poke-line-minimum-window-width) +(defvar rcirc-activity) +(defvar sml-modeline-len) +(defvar symbol-overlay-keywords-alist) +(defvar symbol-overlay-temp-symbol) +(defvar text-scale-mode-amount) +(defvar tracking-buffers) +(defvar winum-auto-setup-mode-line) +(defvar xah-fly-insert-state-p) + +(declare-function anzu--reset-status "ext:anzu") +(declare-function anzu--where-is-here "ext:anzu") +(declare-function async-inject-variables "ext:async") +(declare-function async-start "ext:async") +(declare-function avy-traverse "ext:avy") +(declare-function avy-tree "ext:avy") +(declare-function aw-update "ext:ace-window") +(declare-function aw-window-list "ext:ace-window") +(declare-function battery-format "battery") +(declare-function battery-update "battery") +(declare-function boon-modeline-string "ext:boon") +(declare-function boon-state-string "ext:boon") +(declare-function cider--connection-info "ext:cider") +(declare-function cider-connected-p "ext:cider") +(declare-function cider-current-repl "ext:cider") +(declare-function cider-jack-in "ext:cider") +(declare-function cider-quit "ext:cider") +(declare-function citre-mode "ext:citre-basic-tools") +(declare-function compilation-goto-in-progress-buffer "compile") +(declare-function dap--cur-session "ext:dap-mode") +(declare-function dap--debug-session-name "ext:dap-mode") +(declare-function dap--debug-session-state "ext:dap-mode") +(declare-function dap--session-running "ext:dap-mode") +(declare-function dap-debug-recent "ext:dap-mode") +(declare-function dap-disconnect "ext:dap-mode") +(declare-function dap-hydra "ext:dap-hydra") +(declare-function edebug-help "edebug") +(declare-function edebug-next-mode "edebug") +(declare-function edebug-stop "edebug") +(declare-function eglot "ext:eglot") +(declare-function eglot--major-modes "ext:eglot" t t) +(declare-function eglot--project-nickname "ext:eglot" t t) +(declare-function eglot-clear-status "ext:eglot") +(declare-function eglot-current-server "ext:eglot") +(declare-function eglot-events-buffer "ext:eglot") +(declare-function eglot-forget-pending-continuations "ext:eglot") +(declare-function eglot-managed-p "ext:glot") +(declare-function eglot-reconnect "ext:eglot") +(declare-function eglot-shutdown "ext:eglot") +(declare-function eglot-stderr-buffer "ext:eglot") +(declare-function erc-switch-to-buffer "erc") +(declare-function erc-track-switch-buffer "erc-track") +(declare-function evil-delimited-arguments "ext:evil-common") +(declare-function evil-emacs-state-p "ext:evil-states" t t) +(declare-function evil-force-normal-state "ext:evil-commands" t t) +(declare-function evil-insert-state-p "ext:evil-states" t t) +(declare-function evil-motion-state-p "ext:evil-states" t t) +(declare-function evil-normal-state-p "ext:evil-states" t t) +(declare-function evil-operator-state-p "ext:evil-states" t t) +(declare-function evil-replace-state-p "ext:evil-states" t t) +(declare-function evil-state-property "ext:evil-common") +(declare-function evil-visual-state-p "ext:evil-states" t t) +(declare-function eyebrowse--get "ext:eyebrowse") +(declare-function face-remap-remove-relative "face-remap") +(declare-function fancy-narrow-active-p "ext:fancy-narrow") +(declare-function flycheck-buffer "ext:flycheck") +(declare-function flycheck-count-errors "ext:flycheck") +(declare-function flycheck-error-level-compilation-level "ext:flycheck") +(declare-function flycheck-list-errors "ext:flycheck") +(declare-function flycheck-next-error "ext:flycheck") +(declare-function flycheck-previous-error "ext:flycheck") +(declare-function flymake--diag-type "ext:flymake" t t) +(declare-function flymake--handle-report "ext:flymake") +(declare-function flymake--lookup-type-property "ext:flymake") +(declare-function flymake--state-diags "ext:flymake" t t) +(declare-function flymake-disabled-backends "ext:flymake") +(declare-function flymake-goto-next-error "ext:flymake") +(declare-function flymake-goto-prev-error "ext:flymake") +(declare-function flymake-reporting-backends "ext:flymake") +(declare-function flymake-running-backends "ext:flymake") +(declare-function flymake-show-buffer-diagnostics "ext:flymake") +(declare-function flymake-show-buffer-diagnostics "ext:flymake") +(declare-function flymake-start "ext:flymake") +(declare-function follow-all-followers "follow") +(declare-function gnus-demon-add-handler "gnus-demon") +(declare-function grip--preview-url "ext:grip-mode") +(declare-function grip-browse-preview "ext:grip-mode") +(declare-function grip-restart-preview "ext:grip-mode") +(declare-function grip-stop-preview "ext:grip-mode") +(declare-function helm-candidate-number-at-point "ext:helm-core") +(declare-function helm-get-candidate-number "ext:helm-core") +(declare-function iedit-find-current-occurrence-overlay "ext:iedit-lib") +(declare-function iedit-prev-occurrence "ext:iedit-lib") +(declare-function image-get-display-property "image-mode") +(declare-function jsonrpc--request-continuations "ext:jsonrpc" t t) +(declare-function jsonrpc-last-error "ext:jsonrpc" t t) +(declare-function kele-current-context-name "ext:kele") +(declare-function kele-current-namespace "ext:kele") +(declare-function lsp--workspace-print "ext:lsp-mode") +(declare-function lsp-describe-session "ext:lsp-mode") +(declare-function lsp-workspace-folders-open "ext:lsp-mode") +(declare-function lsp-workspace-restart "ext:lsp-mode") +(declare-function lsp-workspace-shutdown "ext:lsp-mode") +(declare-function lsp-workspaces "ext:lsp-mode") +(declare-function lv-message "ext:lv") +(declare-function mc/num-cursors "ext:multiple-cursors-core") +(declare-function meow--current-state "ext:meow") +(declare-function meow-beacon-mode-p "ext:meow") +(declare-function meow-insert-mode-p "ext:meow") +(declare-function meow-keypad-mode-p "ext:meow") +(declare-function meow-motion-mode-p "ext:meow") +(declare-function meow-normal-mode-p "ext:meow") +(declare-function minions--prominent-modes "ext:minions") +(declare-function mlscroll-mode-line "ext:mlscroll") +(declare-function mu4e--modeline-string "ext:mu4e-modeline") +(declare-function mu4e-alert-default-mode-line-formatter "ext:mu4e-alert") +(declare-function mu4e-alert-enable-mode-line-display "ext:mu4e-alert") +(declare-function nyan-create "ext:nyan-mode") +(declare-function org-edit-src-save "ext:org-src") +(declare-function parrot-create "ext:parrot") +(declare-function pdf-cache-number-of-pages "ext:pdf-cache" t t) +(declare-function persp-add-buffer "ext:persp-mode") +(declare-function persp-contain-buffer-p "ext:persp-mode") +(declare-function persp-switch "ext:persp-mode") +(declare-function phi-search--initialize "ext:phi-search") +(declare-function poke-line-create "ext:poke-line") +(declare-function popup-create "ext:popup") +(declare-function popup-delete "ext:popup") +(declare-function rcirc-next-active-buffer "rcirc") +(declare-function rcirc-short-buffer-name "rcirc") +(declare-function rcirc-switch-to-server-buffer "rcirc") +(declare-function rcirc-window-configuration-change "rcirc") +(declare-function rime--should-enable-p "ext:rime") +(declare-function rime--should-inline-ascii-p "ext:rime") +(declare-function sml-modeline-create "ext:sml-modeline") +(declare-function svg-circle "svg") +(declare-function svg-create "svg") +(declare-function svg-image "svg") +(declare-function svg-line "svg") +(declare-function symbol-overlay-assoc "ext:symbol-overlay") +(declare-function symbol-overlay-get-list "ext:symbol-overlay") +(declare-function symbol-overlay-get-symbol "ext:symbol-overlay") +(declare-function symbol-overlay-rename "ext:symbol-overlay") +(declare-function tab-bar--current-tab "tab-bar") +(declare-function tab-bar--current-tab-index "tab-bar") +(declare-function tracking-next-buffer "ext:tracking") +(declare-function tracking-previous-buffer "ext:tracking") +(declare-function tracking-shorten "ext:tracking") +(declare-function undo-tree-redo-1 "ext:undo-tree") +(declare-function undo-tree-undo-1 "ext:undo-tree") +(declare-function warning-numeric-level "warnings") +(declare-function window-numbering-clear-mode-line "ext:window-numbering") +(declare-function window-numbering-get-number-string "ext:window-numbering") +(declare-function window-numbering-install-mode-line "ext:window-numbering") +(declare-function winum--clear-mode-line "ext:winum") +(declare-function winum--install-mode-line "ext:winum") +(declare-function winum-get-number-string "ext:winum") + + + +;; +;; Buffer information +;; + +(defvar-local doom-modeline--buffer-file-icon nil) +(defun doom-modeline-update-buffer-file-icon (&rest _) + "Update file icon in mode-line." + (setq doom-modeline--buffer-file-icon + (when (and doom-modeline-major-mode-icon + (doom-modeline-icon-displayable-p)) + (let ((icon (doom-modeline-icon-for-buffer))) + (propertize (if (or (null icon) (symbolp icon)) + (doom-modeline-icon 'faicon "nf-fa-file_o" nil nil + :face 'nerd-icons-dsilver) + (doom-modeline-propertize-icon icon)) + 'help-echo (format "Major-mode: %s" (format-mode-line mode-name))))))) +(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-icon) +(add-hook 'after-change-major-mode-hook #'doom-modeline-update-buffer-file-icon) +(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-icon) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-buffer-file-icon)))))) + +(defun doom-modeline-buffer-file-state-icon (icon unicode text face) + "Displays an ICON of buffer state with FACE. +UNICODE and TEXT are the alternatives if it is not applicable. +Uses `nerd-icons-mdicon' to fetch the icon." + (doom-modeline-icon 'mdicon icon unicode text :face face)) + +(defvar-local doom-modeline--buffer-file-state-icon nil) +(defun doom-modeline-update-buffer-file-state-icon (&rest _) + "Update the buffer or file state in mode-line." + (setq doom-modeline--buffer-file-state-icon + (when doom-modeline-buffer-state-icon + (ignore-errors + (concat + (cond (buffer-read-only + (doom-modeline-buffer-file-state-icon + "nf-md-lock" "🔒" "%1*" + 'doom-modeline-warning)) + ((and buffer-file-name (buffer-modified-p) + doom-modeline-buffer-modification-icon) + (doom-modeline-buffer-file-state-icon + "nf-md-content_save_edit" "💾" "%1*" + 'doom-modeline-warning)) + ((and buffer-file-name + ;; Avoid freezing while connection is lost + (not (file-remote-p buffer-file-name)) + (not (file-exists-p buffer-file-name))) + (doom-modeline-buffer-file-state-icon + "nf-md-cancel" "🚫" "!" + 'doom-modeline-urgent)) + (t "")) + (when (or (buffer-narrowed-p) + (and (bound-and-true-p fancy-narrow-mode) + (fancy-narrow-active-p)) + (bound-and-true-p dired-narrow-mode)) + (doom-modeline-buffer-file-state-icon + "nf-md-unfold_less_horizontal" "↕" "><" + 'doom-modeline-warning))))))) + +(defvar-local doom-modeline--buffer-file-name nil) +(defun doom-modeline-update-buffer-file-name (&rest _) + "Update buffer file name in mode-line." + (setq doom-modeline--buffer-file-name + (ignore-errors + (save-match-data + (if buffer-file-name + (doom-modeline-buffer-file-name) + (propertize "%b" + 'face 'doom-modeline-buffer-file + 'mouse-face 'doom-modeline-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap)))))) +(add-hook 'find-file-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'after-save-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'clone-indirect-buffer-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'evil-insert-state-exit-hook #'doom-modeline-update-buffer-file-name) +(add-hook 'Info-selection-hook #'doom-modeline-update-buffer-file-name) +(advice-add #'rename-buffer :after #'doom-modeline-update-buffer-file-name) +(advice-add #'set-visited-file-name :after #'doom-modeline-update-buffer-file-name) +(advice-add #'pop-to-buffer :after #'doom-modeline-update-buffer-file-name) +(advice-add #'popup-create :after #'doom-modeline-update-buffer-file-name) +(advice-add #'popup-delete :after #'doom-modeline-update-buffer-file-name) +;; (advice-add #'primitive-undo :after #'doom-modeline-update-buffer-file-name) +;; (advice-add #'set-buffer-modified-p :after #'doom-modeline-update-buffer-file-name) + +(with-no-warnings + (if (boundp 'after-focus-change-function) + (progn + (advice-add #'handle-switch-frame :after #'doom-modeline-update-buffer-file-name) + (add-function :after after-focus-change-function #'doom-modeline-update-buffer-file-name)) + (progn + (add-hook 'focus-in-hook #'doom-modeline-update-buffer-file-name) + (add-hook 'focus-out-hook #'doom-modeline-update-buffer-file-name)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-buffer-file-name-style + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-buffer-file-name-style val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when buffer-file-name + (doom-modeline-update-buffer-file-name))))))) + +(defsubst doom-modeline--buffer-mode-icon () + "The icon of the current major mode." + (when (and doom-modeline-icon doom-modeline-major-mode-icon) + (when-let ((icon (or doom-modeline--buffer-file-icon + (doom-modeline-update-buffer-file-icon)))) + (unless (string-empty-p icon) + (concat + (if doom-modeline-major-mode-color-icon + (doom-modeline-display-icon icon) + (doom-modeline-propertize-icon + icon + (doom-modeline-face))) + (doom-modeline-vspc)))))) + +(defsubst doom-modeline--buffer-state-icon () + "The icon of the current buffer state." + (when doom-modeline-buffer-state-icon + (when-let ((icon (doom-modeline-update-buffer-file-state-icon))) + (unless (string-empty-p icon) + (concat + (doom-modeline-display-icon icon) + (doom-modeline-vspc)))))) + +(defsubst doom-modeline--buffer-simple-name () + "The buffer simple name." + (propertize "%b" + 'face (doom-modeline-face + (if (and doom-modeline-highlight-modified-buffer-name + (buffer-modified-p)) + 'doom-modeline-buffer-modified + 'doom-modeline-buffer-file)) + 'mouse-face 'doom-modeline-highlight + 'help-echo "Buffer name +mouse-1: Previous buffer\nmouse-3: Next buffer" + 'local-map mode-line-buffer-identification-keymap)) + +(defsubst doom-modeline--buffer-name () + "The current buffer name." + (when doom-modeline-buffer-name + (if (and (not (eq doom-modeline-buffer-file-name-style 'file-name)) + doom-modeline--limited-width-p) + ;; Only display the buffer name if the window is small, and doesn't + ;; need to respect file-name style. + (doom-modeline--buffer-simple-name) + (when-let ((name (or doom-modeline--buffer-file-name + (doom-modeline-update-buffer-file-name)))) + ;; Check if the buffer is modified + (if (and doom-modeline-highlight-modified-buffer-name + (buffer-modified-p)) + (propertize name 'face (doom-modeline-face 'doom-modeline-buffer-modified)) + (doom-modeline-display-text name)))))) + +(doom-modeline-def-segment buffer-info + "Combined information about the current buffer. + +Including the current working directory, the file name, and its state (modified, +read-only or non-existent)." + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (doom-modeline--buffer-name))) + +(doom-modeline-def-segment buffer-info-simple + "Display only the current buffer's name, but with fontification." + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (doom-modeline--buffer-simple-name))) + +(doom-modeline-def-segment calc + "Display calculator icons and info." + (concat + (doom-modeline-spc) + (when-let ((icon (doom-modeline-icon 'faicon "nf-fa-calculator" "🖩" ""))) + (concat + (doom-modeline-display-icon icon) + (doom-modeline-vspc))) + (doom-modeline--buffer-simple-name))) + +(doom-modeline-def-segment buffer-default-directory + "Displays `default-directory' with the icon and state. + +This is for special buffers like the scratch buffer where knowing the current +project directory is important." + (let ((face (doom-modeline-face + (if (and buffer-file-name (buffer-modified-p)) + 'doom-modeline-buffer-modified + 'doom-modeline-buffer-path)))) + (concat + (doom-modeline-spc) + (and doom-modeline-major-mode-icon + (concat + (doom-modeline-icon + 'octicon "nf-oct-file_directory_fill" "🖿" "" :face face) + (doom-modeline-vspc))) + (doom-modeline--buffer-state-icon) + (propertize (abbreviate-file-name default-directory) 'face face)))) + +(doom-modeline-def-segment buffer-default-directory-simple + "Displays `default-directory'. + +This is for special buffers like the scratch buffer where knowing the current +project directory is important." + (let ((face (doom-modeline-face 'doom-modeline-buffer-path))) + (concat + (doom-modeline-spc) + (and doom-modeline-major-mode-icon + (concat + (doom-modeline-icon + 'octicon "nf-oct-file_directory_fill" "🖿" "" :face face) + (doom-modeline-vspc))) + (propertize (abbreviate-file-name default-directory) 'face face)))) + + +;; +;; Encoding +;; + +(doom-modeline-def-segment buffer-encoding + "Displays the eol and the encoding style of the buffer." + (when doom-modeline-buffer-encoding + (let ((sep (doom-modeline-spc)) + (face (doom-modeline-face)) + (mouse-face 'doom-modeline-highlight)) + (concat + sep + + ;; eol type + (let ((eol (coding-system-eol-type buffer-file-coding-system))) + (when (or (eq doom-modeline-buffer-encoding t) + (and (eq doom-modeline-buffer-encoding 'nondefault) + (not (equal eol doom-modeline-default-eol-type)))) + (propertize + (pcase eol + (0 "LF ") + (1 "CRLF ") + (2 "CR ") + (_ "")) + 'face face + 'mouse-face mouse-face + 'help-echo (format "End-of-line style: %s\nmouse-1: Cycle" + (pcase eol + (0 "Unix-style LF") + (1 "DOS-style CRLF") + (2 "Mac-style CR") + (_ "Undecided"))) + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] 'mode-line-change-eol) + map)))) + + ;; coding system + (let* ((sys (coding-system-plist buffer-file-coding-system)) + (cat (plist-get sys :category)) + (sym (if (memq cat + '(coding-category-undecided coding-category-utf-8)) + 'utf-8 + (plist-get sys :name)))) + (when (or (eq doom-modeline-buffer-encoding t) + (and (eq doom-modeline-buffer-encoding 'nondefault) + (not (eq cat 'coding-category-undecided)) + (not (eq sym doom-modeline-default-coding-system)))) + (propertize + (upcase (symbol-name sym)) + 'face face + 'mouse-face mouse-face + 'help-echo 'mode-line-mule-info-help-echo + 'local-map mode-line-coding-system-map))) + + sep)))) + + +;; +;; Indentation +;; + +(doom-modeline-def-segment indent-info + "Displays the indentation information." + (when doom-modeline-indent-info + (let ((do-propertize + (lambda (mode size) + (propertize + (format " %s %d " mode size) + 'face (doom-modeline-face))))) + (if indent-tabs-mode + (funcall do-propertize "TAB" tab-width) + (let ((lookup-var + (seq-find (lambda (var) + (and var (boundp var) (symbol-value var))) + (cdr (assoc major-mode doom-modeline-indent-alist)) nil))) + (funcall do-propertize "SPC" + (if lookup-var + (symbol-value lookup-var) + tab-width))))))) + +;; +;; Remote host +;; + +(doom-modeline-def-segment remote-host + "Hostname for remote buffers." + (when default-directory + (when-let ((host (file-remote-p default-directory 'host))) + (propertize + (concat "@" host) + 'face (doom-modeline-face 'doom-modeline-host))))) + + +;; +;; Major mode +;; + +(doom-modeline-def-segment major-mode + "The major mode, including environment and text-scale info." + (let ((sep (doom-modeline-spc)) + (face (doom-modeline-face 'doom-modeline-buffer-major-mode))) + (concat + sep + (propertize (concat + (format-mode-line + (or (and (boundp 'delighted-modes) + (cadr (assq major-mode delighted-modes))) + mode-name)) + (when (and doom-modeline-env-version doom-modeline-env--version) + (format " %s" doom-modeline-env--version))) + 'help-echo "Major mode\n\ +mouse-1: Display major mode menu\n\ +mouse-2: Show help for major mode\n\ +mouse-3: Toggle minor modes" + 'face face + 'mouse-face 'doom-modeline-highlight + 'local-map mode-line-major-mode-keymap) + (and (boundp 'text-scale-mode-amount) + (/= text-scale-mode-amount 0) + (propertize + (format + (if (> text-scale-mode-amount 0) " (%+d)" " (%-d)") + text-scale-mode-amount) + 'face face)) + sep))) + + +;; +;; Process +;; + +(doom-modeline-def-segment process + "The process info." + (doom-modeline-display-text + (format-mode-line mode-line-process))) + + +;; +;; Minor modes +;; + +(doom-modeline-def-segment minor-modes + (when doom-modeline-minor-modes + (let ((sep (doom-modeline-spc)) + (face (doom-modeline-face 'doom-modeline-buffer-minor-mode)) + (mouse-face 'doom-modeline-highlight) + (help-echo "Minor mode + mouse-1: Display minor mode menu + mouse-2: Show help for minor mode + mouse-3: Toggle minor modes")) + (if (bound-and-true-p minions-mode) + `((:propertize ("" ,(minions--prominent-modes)) + face ,face + mouse-face ,mouse-face + help-echo ,help-echo + local-map ,mode-line-minor-mode-keymap) + ,sep + (:propertize ("" ,(doom-modeline-icon 'octicon "nf-oct-gear" "⚙" + minions-mode-line-lighter + :face face)) + mouse-face ,mouse-face + help-echo "Minions +mouse-1: Display minor modes menu" + local-map ,minions-mode-line-minor-modes-map) + ,sep) + `((:propertize ("" minor-mode-alist) + face ,face + mouse-face ,mouse-face + help-echo ,help-echo + local-map ,mode-line-minor-mode-keymap) + ,sep))))) + + +;; +;; VCS +;; + +(defun doom-modeline-vcs-icon (icon &optional unicode text face) + "Displays the vcs ICON with FACE and VOFFSET. + +UNICODE and TEXT are fallbacks. +Uses `nerd-icons-octicon' to fetch the icon." + (doom-modeline-icon 'devicon (and doom-modeline-vcs-icon icon) + unicode text :face face)) + +(defvar-local doom-modeline--vcs nil) +(defun doom-modeline-update-vcs (&rest _) + "Update vcs state in mode-line." + (setq doom-modeline--vcs + (when (and vc-mode buffer-file-name) + (let* ((backend (vc-backend buffer-file-name)) + (state (vc-state buffer-file-name backend)) + (icon (cond ((memq state '(edited added)) + (doom-modeline-vcs-icon "nf-dev-git_compare" "🔃" "*" 'doom-modeline-info)) + ((eq state 'needs-merge) + (doom-modeline-vcs-icon "nf-dev-git_merge" "🔀" "?" 'doom-modeline-info)) + ((eq state 'needs-update) + (doom-modeline-vcs-icon "nf-dev-git_pull_request" "⬇" "!" 'doom-modeline-warning)) + ((memq state '(removed conflict unregistered)) + (doom-modeline-icon 'octicon "nf-oct-alert" "⚠" "!" :face 'doom-modeline-urgent)) + (t (doom-modeline-vcs-icon "nf-dev-git_branch" "" "@" 'doom-modeline-info)))) + (str (or (and vc-display-status + (functionp #'doom-modeline-vcs-name) + (funcall #'doom-modeline-vcs-name)) + "")) + (face (cond ((eq state 'needs-update) + '(doom-modeline-warning bold)) + ((memq state '(removed conflict unregistered)) + '(doom-modeline-urgent bold)) + (t '(doom-modeline-info bold)))) + (text (propertize (if (length> str doom-modeline-vcs-max-length) + (concat + (substring str 0 (- doom-modeline-vcs-max-length 3)) + doom-modeline-ellipsis) + str) + 'face face))) + `((icon . ,icon) (text . ,text)))))) +(add-hook 'find-file-hook #'doom-modeline-update-vcs) +(add-hook 'after-save-hook #'doom-modeline-update-vcs) +(advice-add #'vc-refresh-state :after #'doom-modeline-update-vcs) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-vcs-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-vcs-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs)))))) + +(doom-modeline-add-variable-watcher + 'vc-display-status + (lambda (_sym val op _where) + (when (eq op 'set) + (setq vc-display-status val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-vcs)))))) + +(doom-modeline-def-segment vcs + "Displays the current branch, colored based on its state." + (when doom-modeline--vcs + (let-alist doom-modeline--vcs + (let ((sep (doom-modeline-spc)) + (vsep (doom-modeline-vspc))) + (concat sep + (propertize (concat + (doom-modeline-display-icon .icon) + vsep + (doom-modeline-display-text .text)) + 'help-echo (get-text-property 1 'help-echo vc-mode) + 'mouse-face 'doom-modeline-highlight + 'local-map (get-text-property 1 'local-map vc-mode)) + sep))))) + + +;; +;; Check +;; + +(defun doom-modeline-check-icon (icon unicode text face) + "Displays the check ICON with FACE. + +UNICODE and TEXT are fallbacks. +Uses `nerd-icons-mdicon' to fetch the icon." + (doom-modeline-icon 'mdicon (and doom-modeline-check-icon icon) + unicode text :face face)) + +(defun doom-modeline-check-text (text &optional face) + "Displays the check TEXT with FACE." + (propertize text 'face (or face 'mode-line))) + +;; Flycheck + +(defun doom-modeline--flycheck-count-errors () + "Count the number of ERRORS, grouped by level. + +Return an alist, where each ITEM is a cons cell whose `car' is an +error level, and whose `cdr' is the number of errors of that +level." + (let ((info 0) (warning 0) (error 0)) + (mapc + (lambda (item) + (let ((count (cdr item))) + (pcase (flycheck-error-level-compilation-level (car item)) + (0 (cl-incf info count)) + (1 (cl-incf warning count)) + (2 (cl-incf error count))))) + (flycheck-count-errors flycheck-current-errors)) + `((info . ,info) (warning . ,warning) (error . ,error)))) + +(defvar-local doom-modeline--flycheck nil) +(defun doom-modeline-update-flycheck (&optional status) + "Update flycheck via STATUS." + (setq doom-modeline--flycheck + (let-alist (doom-modeline--flycheck-count-errors) + (let* ((vsep (doom-modeline-vspc)) + (seg (if doom-modeline-check-simple-format + (let ((count (+ .error .warning .info))) + (pcase status + ('finished (if (> count 0) + (let ((face (if (> .error 0) 'doom-modeline-urgent 'doom-modeline-warning))) + (concat + (doom-modeline-check-icon "nf-md-alert_circle_outline" "⚠" "!" face) + vsep + (doom-modeline-check-text (number-to-string count) face))) + (doom-modeline-check-icon "nf-md-check_circle_outline" "✔" "*" 'doom-modeline-info))) + ('running (concat + (doom-modeline-check-icon "nf-md-timer_sand" "⏳" "*" 'doom-modeline-debug) + (when (> count 0) + (concat + vsep + (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug))))) + ('no-checker (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "-" 'doom-modeline-debug)) + ('errored (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-urgent)) + ('interrupted (doom-modeline-check-icon "nf-md-pause_circle_outline" "⦷" "." 'doom-modeline-debug)) + ('suspicious (doom-modeline-check-icon "nf-md-file_question_outline" "❓" "?" 'doom-modeline-debug)) + (_ ""))) + (concat (doom-modeline-check-icon "nf-md-close_circle_outline" "⮾" "!" 'doom-modeline-urgent) + vsep + (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent) + vsep + (doom-modeline-check-icon "nf-md-alert_outline" "⚠" "!" 'doom-modeline-warning) + vsep + (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning) + vsep + (doom-modeline-check-icon "nf-md-information_outline" "🛈" "!" 'doom-modeline-info) + vsep + (doom-modeline-check-text (number-to-string .info) 'doom-modeline-info))))) + (propertize seg + 'help-echo (concat "Flycheck\n" + (pcase status + ('finished (format "error: %d, warning: %d, info: %d" .error .warning .info)) + ('running "Checking...") + ('no-checker "No Checker") + ('errored "Error") + ('interrupted "Interrupted") + ('suspicious "Suspicious")) + "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode") + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + flycheck-mode-menu-map) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'flycheck-mode))) + map)))))) +(add-hook 'flycheck-status-changed-functions #'doom-modeline-update-flycheck) +(add-hook 'flycheck-mode-hook #'doom-modeline-update-flycheck) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (doom-modeline-update-flycheck))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-check-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-check-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (doom-modeline-update-flycheck))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (doom-modeline-update-flycheck))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-check-simple-format + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-check-simple-format val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flycheck-mode) + (doom-modeline-update-flycheck))))))) + +;; Flymake + +;; Compatibility +;; @see https://github.com/emacs-mirror/emacs/commit/6e100869012da9244679696634cab6b9cac96303. +(with-eval-after-load 'flymake + (unless (boundp 'flymake--state) + (defvaralias 'flymake--state 'flymake--backend-state)) + (unless (fboundp 'flymake--state-diags) + (defalias 'flymake--state-diags 'flymake--backend-state-diags))) + +(defun doom-modeline--flymake-count-errors () + "Count the number of ERRORS, grouped by level." + (let ((warning-level (warning-numeric-level :warning)) + (note-level (warning-numeric-level :debug)) + (note 0) (warning 0) (error 0)) + (maphash (lambda (_b state) + (cl-loop + with diags = (flymake--state-diags state) + for diag in diags do + (let ((severity (flymake--lookup-type-property (flymake--diag-type diag) 'severity + (warning-numeric-level :error)))) + (cond ((> severity warning-level) (cl-incf error)) + ((> severity note-level) (cl-incf warning)) + (t (cl-incf note)))))) + flymake--state) + `((note . ,note) (warning . ,warning) (error . ,error)))) + +(defvar-local doom-modeline--flymake nil) +(defun doom-modeline-update-flymake (&rest _) + "Update flymake." + (setq doom-modeline--flymake + (let* ((known (hash-table-keys flymake--state)) + (running (flymake-running-backends)) + (disabled (flymake-disabled-backends)) + (reported (flymake-reporting-backends)) + (all-disabled (and disabled (null running))) + (some-waiting (cl-set-difference running reported))) + (let-alist (doom-modeline--flymake-count-errors) + (let* ((vsep (doom-modeline-vspc)) + (seg (if doom-modeline-check-simple-format + (let ((count (+ .error .warning .note))) + (cond + (some-waiting (concat + (doom-modeline-check-icon "nf-md-timer_sand" "⏳" "*" 'doom-modeline-debug) + (when (> count 0) + (concat + vsep + (doom-modeline-check-text (number-to-string count) 'doom-modeline-debug))))) + ((null known) (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-urgent)) + (all-disabled (doom-modeline-check-icon "nf-md-alert_box_outline" "⚠" "!" 'doom-modeline-warning)) + (t (if (> count 0) + (let ((face (cond ((> .error 0) 'doom-modeline-urgent) + ((> .warning 0) 'doom-modeline-warning) + (t 'doom-modeline-info)))) + (concat + (doom-modeline-check-icon "nf-md-alert_circle_outline" "⚠" "!" face) + vsep + (doom-modeline-check-text (number-to-string count) face))) + (doom-modeline-check-icon "nf-md-check_circle_outline" "✔" "*" 'doom-modeline-info))))) + (concat + (doom-modeline-check-icon "nf-md-close_circle_outline" "⮾" "!" 'doom-modeline-urgent) + vsep + (doom-modeline-check-text (number-to-string .error) 'doom-modeline-urgent) + vsep + (doom-modeline-check-icon "nf-md-alert_outline" "⚠" "!" 'doom-modeline-warning) + vsep + (doom-modeline-check-text (number-to-string .warning) 'doom-modeline-warning) + vsep + (doom-modeline-check-icon "nf-md-information_outline" "🛈" "!" 'doom-modeline-info) + vsep + (doom-modeline-check-text (number-to-string .note) 'doom-modeline-info))))) + (propertize + seg + 'help-echo (concat + "Flymake\n" + (cond (some-waiting "Checking...") + ((null known) "No Checker") + (all-disabled "All Checkers Disabled") + (t (format "%d/%d backends running\nerror: %d, warning: %d, note: %d" + (length running) (length known) .error .warning .note))) + "\nmouse-1: Display minor mode menu\nmouse-2: Show help for minor mode") + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] + flymake-menu) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'flymake-mode))) + map))))))) +(advice-add #'flymake--handle-report :after #'doom-modeline-update-flymake) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (doom-modeline-update-flymake))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-check-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-check-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (doom-modeline-update-flymake))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (doom-modeline-update-flymake))))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-check-simple-format + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-check-simple-format val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (bound-and-true-p flymake-mode) + (doom-modeline-update-flymake))))))) + +(doom-modeline-def-segment check + "Displays color-coded error status in the current buffer with pretty icons." + (when-let ((sep (doom-modeline-spc)) + (vsep (doom-modeline-vspc)) + (seg (cond + ((and (bound-and-true-p flymake-mode) + (bound-and-true-p flymake--state)) ; only support 26+ + doom-modeline--flymake) + ((and (bound-and-true-p flycheck-mode) + (bound-and-true-p flycheck--automatically-enabled-checkers)) + doom-modeline--flycheck)))) + (concat + sep + (let ((str)) + (dolist (s (split-string seg " ")) + (setq str + (concat str + (if (string-match-p "^[0-9]+$" s) + (concat vsep + (doom-modeline-display-text s) + vsep) + (doom-modeline-display-icon s))))) + (propertize str + 'help-echo (get-text-property 0 'help-echo seg) + 'mouse-face 'doom-modeline-highlight + 'local-map (get-text-property 0 'local-map seg))) + sep))) + + +;; +;; Word Count +;; + +(doom-modeline-def-segment word-count + "The buffer word count. +Displayed when in a major mode in `doom-modeline-continuous-word-count-modes'. +Respects `doom-modeline-enable-word-count'." + (when (and doom-modeline-enable-word-count + (member major-mode doom-modeline-continuous-word-count-modes)) + (propertize (format " %dW" (count-words (point-min) (point-max))) + 'face (doom-modeline-face)))) + + +;; +;; Selection +;; + +(defsubst doom-modeline-column (pos) + "Get the column of the position `POS'." + (save-excursion (goto-char pos) + (current-column))) + +(doom-modeline-def-segment selection-info + "Information about the current selection. + +Such as how many characters and lines are selected, or the NxM dimensions of a +block selection." + (when (and (or mark-active (and (bound-and-true-p evil-local-mode) + (eq evil-state 'visual))) + (doom-modeline--active)) + (cl-destructuring-bind (beg . end) + (if (and (bound-and-true-p evil-local-mode) (eq evil-state 'visual)) + (cons evil-visual-beginning evil-visual-end) + (cons (region-beginning) (region-end))) + (propertize + (let ((lines (count-lines beg (min end (point-max))))) + (concat + " " + (cond ((or (bound-and-true-p rectangle-mark-mode) + (and (bound-and-true-p evil-visual-selection) + (eq 'block evil-visual-selection))) + (let ((cols (abs (- (doom-modeline-column end) + (doom-modeline-column beg))))) + (format "%dx%dB" lines cols))) + ((and (bound-and-true-p evil-visual-selection) + (eq evil-visual-selection 'line)) + (format "%dL" lines)) + ((> lines 1) + (format "%dC %dL" (- end beg) lines)) + (t + (format "%dC" (- end beg)))) + (when doom-modeline-enable-word-count + (format " %dW" (count-words beg end))) + " ")) + 'face 'doom-modeline-emphasis)))) + + +;; +;; Matches (macro, anzu, evil-substitute, iedit, symbol-overlay and multi-cursors) +;; + +(defsubst doom-modeline--macro-recording () + "Display current Emacs or evil macro being recorded." + (when (and (doom-modeline--active) + (or defining-kbd-macro executing-kbd-macro)) + (let ((sep (propertize " " 'face 'doom-modeline-panel)) + (vsep (propertize " " 'face + '(:inherit (doom-modeline-panel variable-pitch)))) + (macro-name (if (bound-and-true-p evil-this-macro) + (format " @%s " + (char-to-string evil-this-macro)) + "Macro"))) + (concat + sep + (if doom-modeline-always-show-macro-register + (propertize macro-name 'face 'doom-modeline-panel) + (concat + (doom-modeline-icon 'mdicon "nf-md-record" "●" + macro-name + :face '(:inherit (doom-modeline-urgent doom-modeline-panel)) + :v-adjust 0.15) + vsep + (doom-modeline-icon 'mdicon "nf-md-menu_right" "▶" ">" + :face 'doom-modeline-panel + :v-adjust 0.15))) + sep)))) + +;; `anzu' and `evil-anzu' expose current/total state that can be displayed in the +;; mode-line. +(defun doom-modeline-fix-anzu-count (positions here) + "Calulate anzu count via POSITIONS and HERE." + (cl-loop with i = 0 + for (start . end) in positions + do (cl-incf i) + when (and (>= here start) (<= here end)) + return i + finally return 0)) + +(advice-add #'anzu--where-is-here :override #'doom-modeline-fix-anzu-count) + +(setq anzu-cons-mode-line-p nil) ; manage modeline segment ourselves +;; Ensure anzu state is cleared when searches & iedit are done +(with-eval-after-load 'anzu + (add-hook 'isearch-mode-end-hook #'anzu--reset-status t) + (add-hook 'iedit-mode-end-hook #'anzu--reset-status) + (advice-add #'evil-force-normal-state :after #'anzu--reset-status) + ;; Fix matches segment mirroring across all buffers + (mapc #'make-variable-buffer-local + '(anzu--total-matched + anzu--current-position anzu--state anzu--cached-count + anzu--cached-positions anzu--last-command + anzu--last-isearch-string anzu--overflow-p))) + +(defsubst doom-modeline--anzu () + "Show the match index and total number thereof. +Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with +`evil-search'." + (when (and (bound-and-true-p anzu--state) + (not (bound-and-true-p iedit-mode))) + (propertize + (let ((here anzu--current-position) + (total anzu--total-matched)) + (cond ((eq anzu--state 'replace-query) + (format " %d replace " anzu--cached-count)) + ((eq anzu--state 'replace) + (format " %d/%d " here total)) + (anzu--overflow-p + (format " %s+ " total)) + (t + (format " %s/%d " here total)))) + 'face (doom-modeline-face 'doom-modeline-panel)))) + +(defsubst doom-modeline--evil-substitute () + "Show number of matches for `evil-ex' in real time. +The number of matches contains substitutions and highlightings." + (when (and (bound-and-true-p evil-local-mode) + (or (assq 'evil-ex-substitute evil-ex-active-highlights-alist) + (assq 'evil-ex-global-match evil-ex-active-highlights-alist) + (assq 'evil-ex-buffer-match evil-ex-active-highlights-alist))) + (propertize + (let ((range (if evil-ex-range + (cons (car evil-ex-range) (cadr evil-ex-range)) + (cons (line-beginning-position) (line-end-position)))) + (pattern (car-safe (evil-delimited-arguments evil-ex-argument 2)))) + (if pattern + (format " %s matches " (how-many pattern (car range) (cdr range))) + " - ")) + 'face (doom-modeline-face 'doom-modeline-panel)))) + +(defun doom-modeline-themes--overlay-sort (a b) + "Sort overlay A and B." + (< (overlay-start a) (overlay-start b))) + +(defsubst doom-modeline--iedit () + "Show the number of iedit regions matches + what match you're on." + (when (and (bound-and-true-p iedit-mode) + (bound-and-true-p iedit-occurrences-overlays)) + (propertize + (let ((this-oc (or (let ((inhibit-message t)) + (iedit-find-current-occurrence-overlay)) + (save-excursion (iedit-prev-occurrence) + (iedit-find-current-occurrence-overlay)))) + (length (length iedit-occurrences-overlays))) + (format " %s/%d " + (if this-oc + (- length + (length (memq this-oc (sort (append iedit-occurrences-overlays nil) + #'doom-modeline-themes--overlay-sort))) + -1) + "-") + length)) + 'face (doom-modeline-face 'doom-modeline-panel)))) + +(defsubst doom-modeline--symbol-overlay () + "Show the number of matches for symbol overlay." + (when (and (doom-modeline--active) + (bound-and-true-p symbol-overlay-keywords-alist) + (not (bound-and-true-p symbol-overlay-temp-symbol)) + (not (bound-and-true-p iedit-mode))) + (let* ((keyword (symbol-overlay-assoc (symbol-overlay-get-symbol t))) + (symbol (car keyword)) + (before (symbol-overlay-get-list -1 symbol)) + (after (symbol-overlay-get-list 1 symbol)) + (count (length before))) + (if (symbol-overlay-assoc symbol) + (propertize + (format (concat " %d/%d " (and (cadr keyword) "in scope ")) + (+ count 1) + (+ count (length after))) + 'face (doom-modeline-face 'doom-modeline-panel)))))) + +(defsubst doom-modeline--multiple-cursors () + "Show the number of multiple cursors." + (cl-destructuring-bind (count . face) + (cond ((bound-and-true-p multiple-cursors-mode) + (cons (mc/num-cursors) + (doom-modeline-face 'doom-modeline-panel))) + ((bound-and-true-p evil-mc-cursor-list) + (cons (length evil-mc-cursor-list) + (doom-modeline-face (if evil-mc-frozen + 'doom-modeline-bar + 'doom-modeline-panel)))) + ((cons nil nil))) + (when count + (concat (propertize " " 'face face) + (if (doom-modeline-icon-displayable-p) + (doom-modeline-icon 'faicon "nf-fa-i_cursor" "" "" :face face) + (propertize "I" + 'face `(:inherit ,face :height 1.4 :weight normal) + 'display '(raise -0.1))) + (propertize " " + 'face `(:inherit (variable-pitch ,face))) + (propertize (format "%d " count) + 'face face))))) + +(defsubst doom-modeline--phi-search () + "Show the number of matches for `phi-search' and `phi-replace'." + (when (and (doom-modeline--active) + (bound-and-true-p phi-search--overlays)) + (let ((total (length phi-search--overlays)) + (selection phi-search--selection)) + (when selection + (propertize + (format " %d/%d " (1+ selection) total) + 'face (doom-modeline-face 'doom-modeline-panel)))))) + +(defun doom-modeline--override-phi-search (orig-fun &rest args) + "Override the mode-line of `phi-search' and `phi-replace'. +Apply ORIG-FUN with ARGS." + (if (bound-and-true-p doom-modeline-mode) + (apply orig-fun mode-line-format (cdr args)) + (apply orig-fun args))) +(advice-add #'phi-search--initialize :around #'doom-modeline--override-phi-search) + +(defsubst doom-modeline--buffer-size () + "Show buffer size." + (when size-indication-mode + (let ((sep (doom-modeline-spc))) + (concat sep + (propertize "%I" + 'face (doom-modeline-face) + 'help-echo "Buffer size +mouse-1: Display Line and Column Mode Menu" + 'mouse-face 'doom-modeline-highlight + 'local-map mode-line-column-line-number-mode-map) + sep)))) + +(doom-modeline-def-segment matches + "Displays matches. + +Including: +1. the currently recording macro, 2. A current/total for the +current search term (with `anzu'), 3. The number of substitutions being +conducted with `evil-ex-substitute', and/or 4. The number of active `iedit' +regions, 5. The current/total for the highlight term (with `symbol-overlay'), +6. The number of active `multiple-cursors'." + (let ((meta (concat (doom-modeline--macro-recording) + (doom-modeline--anzu) + (doom-modeline--phi-search) + (doom-modeline--evil-substitute) + (doom-modeline--iedit) + (doom-modeline--symbol-overlay) + (doom-modeline--multiple-cursors)))) + (or (and (not (string-empty-p meta)) meta) + (doom-modeline--buffer-size)))) + +(doom-modeline-def-segment buffer-size + "Display buffer size." + (doom-modeline--buffer-size)) + +;; +;; Media +;; + +(doom-modeline-def-segment media-info + "Metadata regarding the current file, such as dimensions for images." + ;; TODO: Include other information + (cond ((eq major-mode 'image-mode) + (cl-destructuring-bind (width . height) + (when (fboundp 'image-size) + (image-size (image-get-display-property) :pixels)) + (format " %dx%d " width height))))) + + +;; +;; Bars +;; + +(defvar doom-modeline--bar-active nil) +(defvar doom-modeline--bar-inactive nil) + +(defsubst doom-modeline--bar () + "The default bar regulates the height of the mode-line in GUI." + (unless (and doom-modeline--bar-active doom-modeline--bar-inactive) + (let ((width doom-modeline-bar-width) + (height (max doom-modeline-height (doom-modeline--font-height)))) + (setq doom-modeline--bar-active + (doom-modeline--create-bar-image 'doom-modeline-bar width height) + doom-modeline--bar-inactive + (doom-modeline--create-bar-image + 'doom-modeline-bar-inactive width height)))) + (if (doom-modeline--active) + doom-modeline--bar-active + doom-modeline--bar-inactive)) + +(defun doom-modeline-refresh-bars () + "Refresh mode-line bars on next redraw." + (setq doom-modeline--bar-active nil + doom-modeline--bar-inactive nil)) + +(cl-defstruct doom-modeline--hud-cache active inactive top-margin bottom-margin) + +(defsubst doom-modeline--hud () + "Powerline's hud segment reimplemented in the style of Doom's bar segment." + (let* ((ws (window-start)) + (we (window-end)) + (bs (buffer-size)) + (height (max doom-modeline-height (doom-modeline--font-height))) + (top-margin (if (zerop bs) + 0 + (/ (* height (1- ws)) bs))) + (bottom-margin (if (zerop bs) + 0 + (max 0 (/ (* height (- bs we 1)) bs)))) + (cache (or (window-parameter nil 'doom-modeline--hud-cache) + (set-window-parameter + nil + 'doom-modeline--hud-cache + (make-doom-modeline--hud-cache))))) + (unless (and (doom-modeline--hud-cache-active cache) + (doom-modeline--hud-cache-inactive cache) + (= top-margin (doom-modeline--hud-cache-top-margin cache)) + (= bottom-margin + (doom-modeline--hud-cache-bottom-margin cache))) + (setf (doom-modeline--hud-cache-active cache) + (doom-modeline--create-hud-image + 'doom-modeline-bar 'default doom-modeline-bar-width + height top-margin bottom-margin) + (doom-modeline--hud-cache-inactive cache) + (doom-modeline--create-hud-image + 'doom-modeline-bar-inactive 'default doom-modeline-bar-width + height top-margin bottom-margin) + (doom-modeline--hud-cache-top-margin cache) top-margin + (doom-modeline--hud-cache-bottom-margin cache) bottom-margin)) + (if (doom-modeline--active) + (doom-modeline--hud-cache-active cache) + (doom-modeline--hud-cache-inactive cache)))) + +(defun doom-modeline-invalidate-huds () + "Invalidate all cached hud images." + (dolist (frame (frame-list)) + (dolist (window (window-list frame)) + (set-window-parameter window 'doom-modeline--hud-cache nil)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-height + (lambda (_sym val op _where) + (when (and (eq op 'set) (integerp val)) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-bar-width + (lambda (_sym val op _where) + (when (and (eq op 'set) (integerp val)) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym _val op _where) + (when (eq op 'set) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym _val op _where) + (when (eq op 'set) + (doom-modeline-refresh-bars) + (doom-modeline-invalidate-huds)))) + +(add-hook 'window-configuration-change-hook #'doom-modeline-refresh-bars) +(add-hook 'window-configuration-change-hook #'doom-modeline-invalidate-huds) + +(doom-modeline-def-segment bar + "The bar regulates the height of the `doom-modeline' in GUI." + (when (display-graphic-p) + (concat + (if doom-modeline-hud + (doom-modeline--hud) + (doom-modeline--bar)) + (doom-modeline-spc)))) + +(doom-modeline-def-segment hud + "Powerline's hud segment reimplemented in the style of bar segment." + (when (display-graphic-p) + (concat + (doom-modeline--hud) + (doom-modeline-spc)))) + + +;; +;; Window number +;; + +;; HACK: `ace-window-display-mode' should respect the ignore buffers. +(defun doom-modeline-aw-update () + "Update ace-window-path window parameter for all windows. +Ensure all windows are labeled so the user can select a specific +one. The ignored buffers are excluded unless `aw-ignore-on' is nil." + (let ((ignore-window-parameters t)) + (avy-traverse + (avy-tree (aw-window-list) aw-keys) + (lambda (path leaf) + (set-window-parameter + leaf 'ace-window-path + (propertize + (apply #'string (reverse path)) + 'face 'aw-mode-line-face)))))) +(advice-add #'aw-update :override #'doom-modeline-aw-update) + +;; Remove original window number of `ace-window-display-mode'. +(add-hook 'ace-window-display-mode-hook + (lambda () + (setq-default mode-line-format + (assq-delete-all 'ace-window-display-mode + (default-value 'mode-line-format))))) + +(advice-add #'window-numbering-install-mode-line :override #'ignore) +(advice-add #'window-numbering-clear-mode-line :override #'ignore) +(advice-add #'winum--install-mode-line :override #'ignore) +(advice-add #'winum--clear-mode-line :override #'ignore) + +(doom-modeline-def-segment window-number + "The current window number." + (let ((num (cond + ((bound-and-true-p ace-window-display-mode) + (aw-update) + (window-parameter (selected-window) 'ace-window-path)) + ((bound-and-true-p winum-mode) + (setq winum-auto-setup-mode-line nil) + (winum-get-number-string)) + ((bound-and-true-p window-numbering-mode) + (window-numbering-get-number-string)) + (t "")))) + (when (and (length> num 0) + (length> (cl-mapcan + (lambda (frame) + ;; Exclude minibuffer, tooltip and child frames + (unless (or (and (fboundp 'frame-parent) (frame-parent frame)) + (string= (frame-parameter frame 'name) + (alist-get 'name (bound-and-true-p tooltip-frame-parameters)))) + (window-list frame 'never))) + (visible-frame-list)) + 1)) + (propertize (format " %s " num) + 'face (doom-modeline-face 'doom-modeline-buffer-major-mode))))) + + +;; +;; Workspace +;; + +(doom-modeline-def-segment workspace-name + "The current workspace name or number. +Requires `eyebrowse-mode' to be enabled or `tab-bar-mode' tabs to be created." + (when doom-modeline-workspace-name + (when-let + ((name (cond + ((and (bound-and-true-p eyebrowse-mode) + (length> (eyebrowse--get 'window-configs) 1)) + (setq mode-line-misc-info + (assq-delete-all 'eyebrowse-mode mode-line-misc-info)) + (when-let* + ((num (eyebrowse--get 'current-slot)) + (tag (nth 2 (assoc num (eyebrowse--get 'window-configs))))) + (if (length> tag 0) tag (int-to-string num)))) + ((and (fboundp 'tab-bar-mode) + (length> (frame-parameter nil 'tabs) 1)) + (let* ((current-tab (tab-bar--current-tab)) + (tab-index (tab-bar--current-tab-index)) + (explicit-name (alist-get 'explicit-name current-tab)) + (tab-name (alist-get 'name current-tab))) + (if explicit-name tab-name (+ 1 tab-index))))))) + (propertize (format " %s " name) + 'face (doom-modeline-face 'doom-modeline-buffer-major-mode))))) + + +;; +;; Perspective +;; + +(defvar-local doom-modeline--persp-name nil) +(defun doom-modeline-update-persp-name (&rest _) + "Update perspective name in mode-line." + (setq doom-modeline--persp-name + ;; Support `persp-mode', while not support `perspective' + (when (and doom-modeline-persp-name + (bound-and-true-p persp-mode) + (fboundp 'safe-persp-name) + (fboundp 'get-current-persp)) + (let* ((persp (get-current-persp)) + (name (safe-persp-name persp)) + (face (if (and persp + (not (persp-contain-buffer-p (current-buffer) persp))) + 'doom-modeline-persp-buffer-not-in-persp + 'doom-modeline-persp-name)) + (icon (doom-modeline-icon 'octicon "nf-oct-repo" "🖿" "#" + :face `(:inherit ,face :slant normal)))) + (when (or doom-modeline-display-default-persp-name + (not (string-equal persp-nil-name name))) + (concat " " + (propertize (concat (and doom-modeline-persp-icon + (concat icon + (propertize + " " + 'display '((space :relative-width 0.5))))) + (propertize name 'face face)) + 'help-echo "mouse-1: Switch perspective +mouse-2: Show help for minor mode" + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'persp-switch) + (define-key map [mode-line mouse-2] + (lambda () + (interactive) + (describe-function 'persp-mode))) + map)) + " ")))))) + +(add-hook 'buffer-list-update-hook #'doom-modeline-update-persp-name) +(add-hook 'find-file-hook #'doom-modeline-update-persp-name) +(add-hook 'persp-activated-functions #'doom-modeline-update-persp-name) +(add-hook 'persp-renamed-functions #'doom-modeline-update-persp-name) +(advice-add #'lv-message :after #'doom-modeline-update-persp-name) + +(doom-modeline-def-segment persp-name + "The current perspective name." + (when (doom-modeline--segment-visible 'persp-name) + doom-modeline--persp-name)) + + +;; +;; Misc info +;; + +(doom-modeline-def-segment misc-info + "Mode line construct for miscellaneous information. +By default, this shows the information specified by `global-mode-string'." + (when (and (doom-modeline--segment-visible 'misc-info) + (or doom-modeline-display-misc-in-all-mode-lines + (doom-modeline--active))) + (doom-modeline-display-text + (format-mode-line mode-line-misc-info)))) + + +;; +;; Position +;; + +(doom-modeline-def-segment buffer-position + "The buffer position information." + (let ((visible (doom-modeline--segment-visible 'buffer-position)) + (sep (doom-modeline-spc)) + (wsep (doom-modeline-wspc)) + (face (doom-modeline-face)) + (help-echo "Buffer percentage\n\ +mouse-1: Display Line and Column Mode Menu") + (mouse-face 'doom-modeline-highlight) + (local-map mode-line-column-line-number-mode-map)) + `(,wsep + + ;; Line and column + (:propertize + ((line-number-mode + (column-number-mode + (doom-modeline-column-zero-based + doom-modeline-position-column-line-format + ,(string-replace + "%c" "%C" (car doom-modeline-position-column-line-format))) + doom-modeline-position-line-format) + (column-number-mode + (doom-modeline-column-zero-based + doom-modeline-position-column-format + ,(string-replace + "%c" "%C" (car doom-modeline-position-column-format))))) + (doom-modeline-total-line-number + ,(format "/%d" (line-number-at-pos (point-max))))) + face ,face + help-echo ,help-echo + mouse-face ,mouse-face + local-map ,local-map) + + ((or line-number-mode column-number-mode) + ,sep) + + ;; Position + (,visible + ,(cond + ((and (bound-and-true-p nyan-mode) + (>= (window-width) nyan-minimum-window-width)) + (concat sep (nyan-create) sep)) + ((and (bound-and-true-p poke-line-mode) + (>= (window-width) poke-line-minimum-window-width)) + (concat sep (poke-line-create) sep)) + ((and (bound-and-true-p mlscroll-mode) + (>= (window-width) mlscroll-minimum-current-width)) + (concat + sep + (let ((mlscroll-right-align nil)) + (format-mode-line (mlscroll-mode-line))) + sep)) + ((and (bound-and-true-p sml-modeline-mode) + (>= (window-width) sml-modeline-len)) + (concat sep (sml-modeline-create) sep)) + (t ""))) + + ;; Percent position + (doom-modeline-percent-position + ((:propertize ("" doom-modeline-percent-position) + face ,face + help-echo ,help-echo + mouse-face ,mouse-face + local-map ,local-map) + ,sep))))) + +;; +;; Party parrot +;; +(doom-modeline-def-segment parrot + "The party parrot animated icon. Requires `parrot-mode' to be enabled." + (when (and (doom-modeline--segment-visible 'parrot) + (bound-and-true-p parrot-mode)) + (concat (doom-modeline-wspc) + (parrot-create) + (doom-modeline-spc)))) + +;; +;; Modals (evil, overwrite, god, ryo and xah-fly-keys, etc.) +;; + +(defun doom-modeline--modal-icon (text face help-echo &optional icon unicode) + "Display the model icon with FACE and HELP-ECHO. +TEXT is alternative if icon is not available." + (propertize (doom-modeline-icon + 'mdicon + (and doom-modeline-modal-icon + (or (and doom-modeline-modal-modern-icon icon) + "nf-md-record")) + (or (and doom-modeline-modal-modern-icon unicode) "●") + text + :face (doom-modeline-face face)) + 'help-echo help-echo)) + +(defsubst doom-modeline--evil () + "The current evil state. Requires `evil-mode' to be enabled." + (when (bound-and-true-p evil-local-mode) + (doom-modeline--modal-icon + (let ((tag (evil-state-property evil-state :tag t))) + (if (stringp tag) tag (funcall tag))) + (cond + ((evil-normal-state-p) 'doom-modeline-evil-normal-state) + ((evil-emacs-state-p) 'doom-modeline-evil-emacs-state) + ((evil-insert-state-p) 'doom-modeline-evil-insert-state) + ((evil-motion-state-p) 'doom-modeline-evil-motion-state) + ((evil-visual-state-p) 'doom-modeline-evil-visual-state) + ((evil-operator-state-p) 'doom-modeline-evil-operator-state) + ((evil-replace-state-p) 'doom-modeline-evil-replace-state) + (t 'doom-modeline-evil-user-state)) + (evil-state-property evil-state :name t) + (cond + ((evil-normal-state-p) "nf-md-alpha_n_circle") + ((evil-emacs-state-p) "nf-md-alpha_e_circle") + ((evil-insert-state-p) "nf-md-alpha_i_circle") + ((evil-motion-state-p) "nf-md-alpha_m_circle") + ((evil-visual-state-p) "nf-md-alpha_v_circle") + ((evil-operator-state-p) "nf-md-alpha_o_circle") + ((evil-replace-state-p) "nf-md-alpha_r_circle") + (t "nf-md-alpha_u_circle")) + (cond + ((evil-normal-state-p) "🅝") + ((evil-emacs-state-p) "🅔") + ((evil-insert-state-p) "🅘") + ((evil-motion-state-p) "🅜") + ((evil-visual-state-p) "🅥") + ((evil-operator-state-p) "🅞") + ((evil-replace-state-p) "🅡") + (t "🅤"))))) + +(defsubst doom-modeline--overwrite () + "The current overwrite state which is enabled by command `overwrite-mode'." + (when (and (bound-and-true-p overwrite-mode) + (not (bound-and-true-p evil-local-mode))) + (doom-modeline--modal-icon + "<W>" 'doom-modeline-overwrite "Overwrite mode" + "nf-md-marker" "🅦"))) + +(defsubst doom-modeline--god () + "The current god state which is enabled by the command `god-mode'." + (when (bound-and-true-p god-local-mode) + (doom-modeline--modal-icon + "<G>" 'doom-modeline-god "God mode" + "nf-md-account_circle" "🅖"))) + +(defsubst doom-modeline--ryo () + "The current ryo-modal state which is enabled by the command `ryo-modal-mode'." + (when (bound-and-true-p ryo-modal-mode) + (doom-modeline--modal-icon + "<R>" 'doom-modeline-ryo "Ryo modal" + "nf-md-star_circle" "✪"))) + +(defsubst doom-modeline--xah-fly-keys () + "The current `xah-fly-keys' state." + (when (bound-and-true-p xah-fly-keys) + (if xah-fly-insert-state-p + (doom-modeline--modal-icon + "<I>" 'doom-modeline-fly-insert-state "Xah-fly insert mode" + "nf-md-airplane_edit" "🛧") + (doom-modeline--modal-icon + "<C>" 'doom-modeline-fly-normal-state "Xah-fly command mode" + "nf-md-airplane_cog" "🛧")))) + +(defsubst doom-modeline--boon () + "The current Boon state. Requires `boon-mode' to be enabled." + (when (bound-and-true-p boon-local-mode) + (doom-modeline--modal-icon + (boon-state-string) + (cond + (boon-command-state 'doom-modeline-boon-command-state) + (boon-insert-state 'doom-modeline-boon-insert-state) + (boon-special-state 'doom-modeline-boon-special-state) + (boon-off-state 'doom-modeline-boon-off-state) + (t 'doom-modeline-boon-off-state)) + (boon-modeline-string) + "nf-md-coffee" "🍵"))) + +(defsubst doom-modeline--meow () + "The current Meow state. Requires `meow-mode' to be enabled." + (when (bound-and-true-p meow-mode) + (doom-modeline--modal-icon + (substring-no-properties meow--indicator) + (cond + ((meow-normal-mode-p) 'doom-modeline-meow-normal-state) + ((meow-insert-mode-p) 'doom-modeline-meow-insert-state) + ((meow-beacon-mode-p) 'doom-modeline-meow-beacon-state) + ((meow-motion-mode-p) 'doom-modeline-meow-motion-state) + ((meow-keypad-mode-p) 'doom-modeline-meow-keypad-state) + (t 'doom-modeline-meow-normal-state)) + (symbol-name (meow--current-state)) + (cond + ((meow-normal-mode-p) "nf-md-alpha_n_circle") + ((meow-insert-mode-p) "nf-md-alpha_i_circle") + ((meow-beacon-mode-p) "nf-md-alpha_b_circle") + ((meow-motion-mode-p) "nf-md-alpha_m_circle") + ((meow-keypad-mode-p) "nf-md-alpha_k_circle") + (t "nf-md-alpha_n_circle")) + (cond + ((meow-normal-mode-p) "🅝") + ((meow-insert-mode-p) "🅘") + ((meow-beacon-mode-p) "🅑") + ((meow-motion-mode-p) "🅜") + ((meow-keypad-mode-p) "🅚") + (t "🅝"))))) + +(doom-modeline-def-segment modals + "Displays modal editing states. + +Including `evil', `overwrite', `god', `ryo' and `xha-fly-kyes', etc." + (when doom-modeline-modal + (let* ((evil (doom-modeline--evil)) + (ow (doom-modeline--overwrite)) + (god (doom-modeline--god)) + (ryo (doom-modeline--ryo)) + (xf (doom-modeline--xah-fly-keys)) + (boon (doom-modeline--boon)) + (vsep (doom-modeline-vspc)) + (meow (doom-modeline--meow)) + (sep (and (or evil ow god ryo xf boon) (doom-modeline-spc)))) + (concat sep + (and evil (concat evil (and (or ow god ryo xf boon meow) vsep))) + (and ow (concat ow (and (or god ryo xf boon meow) vsep))) + (and god (concat god (and (or ryo xf boon meow) vsep))) + (and ryo (concat ryo (and (or xf boon meow) vsep))) + (and xf (concat xf (and (or boon meow) vsep))) + (and boon (concat boon (and meow vsep))) + meow + sep)))) + +;; +;; Objed state +;; + +(defvar doom-modeline--objed-active nil) + +(defun doom-modeline-update-objed (_ &optional reset) + "Update `objed' status, inactive when RESET is true." + (setq doom-modeline--objed-active (not reset))) + +(setq objed-modeline-setup-func #'doom-modeline-update-objed) + +(doom-modeline-def-segment objed-state () + "The current objed state." + (when (and doom-modeline--objed-active + (doom-modeline--active)) + (propertize (format " %s(%s) " + (symbol-name objed--object) + (char-to-string (aref (symbol-name objed--obj-state) 0))) + 'face 'doom-modeline-evil-emacs-state + 'help-echo (format "Objed object: %s (%s)" + (symbol-name objed--object) + (symbol-name objed--obj-state))))) + + +;; +;; Input method +;; + +(doom-modeline-def-segment input-method + "The current input method." + (when-let ((im (cond + (current-input-method + current-input-method-title) + ((and (bound-and-true-p evil-local-mode) + (bound-and-true-p evil-input-method)) + (nth 3 (assoc default-input-method input-method-alist))) + (t nil))) + (sep (doom-modeline-spc))) + (concat + sep + (propertize im + 'face (doom-modeline-face + (if (and (bound-and-true-p rime-mode) + (equal current-input-method "rime")) + (if (and (rime--should-enable-p) + (not (rime--should-inline-ascii-p))) + 'doom-modeline-input-method + 'doom-modeline-input-method-alt) + 'doom-modeline-input-method)) + 'help-echo (concat + "Current input method: " + current-input-method + "\n\ +mouse-2: Disable input method\n\ +mouse-3: Describe current input method") + 'mouse-face 'doom-modeline-highlight + 'local-map mode-line-input-method-map) + sep))) + + +;; +;; Info +;; + +(doom-modeline-def-segment info-nodes + "The topic and nodes in the Info buffer." + (concat + " (" + ;; topic + (propertize (if (stringp Info-current-file) + (replace-regexp-in-string + "%" "%%" + (file-name-sans-extension + (file-name-nondirectory Info-current-file))) + (format "*%S*" Info-current-file)) + 'face (doom-modeline-face 'doom-modeline-info)) + ") " + ;; node + (when Info-current-node + (propertize (replace-regexp-in-string + "%" "%%" Info-current-node) + 'face (doom-modeline-face 'doom-modeline-buffer-path) + 'help-echo + "mouse-1: scroll forward, mouse-3: scroll back" + 'mouse-face 'doom-modeline-highlight + 'local-map Info-mode-line-node-keymap)))) + + +;; +;; REPL +;; + +(defun doom-modeline-repl-icon (text face) + "Display REPL icon (or TEXT in terminal) with FACE." + (doom-modeline-icon 'faicon "nf-fa-terminal" "$" text :face face)) + +(defvar doom-modeline--cider nil) + +(defun doom-modeline-update-cider () + "Update cider repl state." + (setq doom-modeline--cider + (let* ((connected (cider-connected-p)) + (face (if connected 'doom-modeline-repl-success 'doom-modeline-repl-warning)) + (repl-buffer (cider-current-repl nil nil)) + (cider-info (when repl-buffer + (cider--connection-info repl-buffer t))) + (icon (doom-modeline-repl-icon "REPL" face))) + (propertize icon + 'help-echo + (if connected + (format "CIDER Connected %s\nmouse-2: CIDER quit" cider-info) + "CIDER Disconnected\nmouse-1: CIDER jack-in") + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (if connected + (define-key map [mode-line mouse-2] + #'cider-quit) + (define-key map [mode-line mouse-1] + #'cider-jack-in)) + map))))) + +(add-hook 'cider-connected-hook #'doom-modeline-update-cider) +(add-hook 'cider-disconnected-hook #'doom-modeline-update-cider) +(add-hook 'cider-mode-hook #'doom-modeline-update-cider) + +(doom-modeline-def-segment repl + "The REPL state." + (when doom-modeline-repl + (when-let ((icon (when (bound-and-true-p cider-mode) + doom-modeline--cider)) + (sep (doom-modeline-spc))) + (concat + sep + (doom-modeline-display-icon icon) + sep)))) + + +;; +;; LSP +;; + +(defun doom-modeline-lsp-icon (text face) + "Display LSP icon (or TEXT in terminal) with FACE." + (if doom-modeline-lsp-icon + (doom-modeline-icon 'octicon "nf-oct-rocket" "🚀" text :face face) + (propertize text 'face face))) + +(defvar-local doom-modeline--lsp nil) +(defun doom-modeline-update-lsp (&rest _) + "Update `lsp-mode' state." + (setq doom-modeline--lsp + (let* ((workspaces (lsp-workspaces)) + (face (if workspaces 'doom-modeline-lsp-success 'doom-modeline-lsp-warning)) + (icon (doom-modeline-lsp-icon "LSP" face))) + (propertize icon + 'help-echo + (if workspaces + (concat "LSP Connected " + (string-join + (mapcar (lambda (w) + (format "[%s]\n" (lsp--workspace-print w))) + workspaces)) + "C-mouse-1: Switch to another workspace folder +mouse-1: Describe current session +mouse-2: Quit server +mouse-3: Reconnect to server") + "LSP Disconnected +mouse-1: Reload to start server") + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (if workspaces + (progn + (define-key map [mode-line C-mouse-1] + #'lsp-workspace-folders-open) + (define-key map [mode-line mouse-1] + #'lsp-describe-session) + (define-key map [mode-line mouse-2] + #'lsp-workspace-shutdown) + (define-key map [mode-line mouse-3] + #'lsp-workspace-restart)) + (progn + (define-key map [mode-line mouse-1] + (lambda () + (interactive) + (ignore-errors (revert-buffer t t)))))) + map))))) +(add-hook 'lsp-before-initialize-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-initialize-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-uninitialized-functions #'doom-modeline-update-lsp) +(add-hook 'lsp-before-open-hook #'doom-modeline-update-lsp) +(add-hook 'lsp-after-open-hook #'doom-modeline-update-lsp) + +(defun doom-modeline--eglot-pending-count (server) + "Get count of pending eglot requests to SERVER." + (if (fboundp 'jsonrpc-continuation-count) + (jsonrpc-continuation-count server) + (hash-table-count (jsonrpc--request-continuations server)))) + +(defvar-local doom-modeline--eglot nil) +(defun doom-modeline-update-eglot () + "Update `eglot' state." + (setq doom-modeline--eglot + (pcase-let* ((server (and (eglot-managed-p) (eglot-current-server))) + (nick (and server (eglot--project-nickname server))) + (pending (and server (doom-modeline--eglot-pending-count server))) + (last-error (and server (jsonrpc-last-error server))) + (face (cond (last-error 'doom-modeline-lsp-error) + ((and pending (cl-plusp pending)) 'doom-modeline-lsp-warning) + (nick 'doom-modeline-lsp-success) + (t 'doom-modeline-lsp-warning))) + (icon (doom-modeline-lsp-icon "EGLOT" face))) + (propertize icon + 'help-echo (cond + (last-error + (format "EGLOT\nAn error occured: %s +mouse-3: Clear this status" (plist-get last-error :message))) + ((and pending (cl-plusp pending)) + (format "EGLOT\n%d outstanding requests" pending)) + (nick (format "EGLOT Connected (%s/%s) +C-mouse-1: Go to server errors +mouse-1: Go to server events +mouse-2: Quit server +mouse-3: Reconnect to server" nick (eglot--major-modes server))) + (t "EGLOT Disconnected +mouse-1: Start server")) + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (cond (last-error + (define-key map [mode-line mouse-3] + #'eglot-clear-status)) + ((and pending (cl-plusp pending)) + (define-key map [mode-line mouse-3] + #'eglot-forget-pending-continuations)) + (nick + (define-key map [mode-line C-mouse-1] + #'eglot-stderr-buffer) + (define-key map [mode-line mouse-1] + #'eglot-events-buffer) + (define-key map [mode-line mouse-2] + #'eglot-shutdown) + (define-key map [mode-line mouse-3] + #'eglot-reconnect)) + (t (define-key map [mode-line mouse-1] + #'eglot))) + map))))) +(add-hook 'eglot-managed-mode-hook #'doom-modeline-update-eglot) + +(defvar-local doom-modeline--tags nil) +(defun doom-modeline-update-tags () + "Update tags state." + (setq doom-modeline--tags + (propertize + (doom-modeline-lsp-icon "TAGS" 'doom-modeline-lsp-success) + 'help-echo "TAGS: Citre mode +mouse-1: Toggle citre mode" + 'mouse-face 'doom-modeline-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'citre-mode)))) +(add-hook 'citre-mode-hook #'doom-modeline-update-tags) + +(defun doom-modeline-update-lsp-icon () + "Update lsp icon." + (cond ((bound-and-true-p lsp-mode) + (doom-modeline-update-lsp)) + ((bound-and-true-p eglot--managed-mode) + (doom-modeline-update-eglot)) + ((bound-and-true-p citre-mode) + (doom-modeline-update-tags)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-lsp-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-lsp-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (doom-modeline-update-lsp-icon)))))) + +(doom-modeline-def-segment lsp + "The LSP server state." + (when doom-modeline-lsp + (when-let ((icon (cond ((bound-and-true-p lsp-mode) + doom-modeline--lsp) + ((bound-and-true-p eglot--managed-mode) + doom-modeline--eglot) + ((bound-and-true-p citre-mode) + doom-modeline--tags))) + (sep (doom-modeline-spc))) + (concat + sep + (doom-modeline-display-icon icon) + sep)))) + +(defun doom-modeline-override-eglot () + "Override `eglot' mode-line." + (if (and doom-modeline-lsp + (bound-and-true-p doom-modeline-mode)) + (setq mode-line-misc-info + (delq (assq 'eglot--managed-mode mode-line-misc-info) mode-line-misc-info)) + (add-to-list 'mode-line-misc-info + `(eglot--managed-mode (" [" eglot--mode-line-format "] "))))) +(add-hook 'eglot-managed-mode-hook #'doom-modeline-override-eglot) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-eglot) + +(doom-modeline-add-variable-watcher + 'doom-modeline-battery + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-lsp val) + (doom-modeline-override-eglot)))) + + +;; +;; GitHub +;; + +(defvar doom-modeline--github-notification-number 0) +(defvar doom-modeline-before-github-fetch-notification-hook nil + "Hooks before fetching GitHub notifications. +Example: + (add-hook \\='doom-modeline-before-github-fetch-notification-hook + #\\='auth-source-pass-enable)") + +(defvar doom-modeline-after-github-fetch-notification-hook nil + "Hooks after fetching GitHub notifications.") + +(defun doom-modeline--github-fetch-notifications () + "Fetch GitHub notifications." + (when (and doom-modeline-github + (require 'async nil t)) + (async-start + `(lambda () + ,(async-inject-variables + "\\`\\(load-path\\|auth-sources\\|doom-modeline-before-github-fetch-notification-hook\\)\\'") + (run-hooks 'doom-modeline-before-github-fetch-notification-hook) + (when (require 'ghub nil t) + (with-timeout (10) + (ignore-errors + (when-let* ((username (ghub--username ghub-default-host)) + (token (or (ghub--token ghub-default-host username 'forge t) + (ghub--token ghub-default-host username 'ghub t)))) + (ghub-get "/notifications" + '((notifications . t)) + :host ghub-default-host + :username username + :auth token + :unpaginate t + :noerror t)))))) + (lambda (result) + (message "") ; suppress message + (setq doom-modeline--github-notification-number (length result)) + (run-hooks 'doom-modeline-after-github-fetch-notification-hook))))) + +(defvar doom-modeline--github-timer nil) +(defun doom-modeline-github-timer () + "Start/Stop the timer for GitHub fetching." + (if (timerp doom-modeline--github-timer) + (cancel-timer doom-modeline--github-timer)) + (setq doom-modeline--github-timer + (and doom-modeline-github + (run-with-idle-timer 30 + doom-modeline-github-interval + #'doom-modeline--github-fetch-notifications)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-github + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-github val) + (doom-modeline-github-timer)))) + +(doom-modeline-github-timer) + +(doom-modeline-def-segment github + "The GitHub notifications." + (when (and doom-modeline-github + (doom-modeline--segment-visible 'github) + (numberp doom-modeline--github-notification-number)) + (let ((sep (doom-modeline-spc))) + (concat + sep + (propertize + (concat + (doom-modeline-icon 'octicon "nf-oct-mark_github" "🔔" "&" + :face 'doom-modeline-notification) + (and (> doom-modeline--github-notification-number 0) (doom-modeline-vspc)) + (propertize + (cond + ((<= doom-modeline--github-notification-number 0) "") + ((> doom-modeline--github-notification-number 99) "99+") + (t (number-to-string doom-modeline--github-notification-number))) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'help-echo "Github Notifications +mouse-1: Show notifications +mouse-3: Fetch notifications" + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + (lambda () + "Open GitHub notifications page." + (interactive) + (run-with-idle-timer 300 nil #'doom-modeline--github-fetch-notifications) + (browse-url "https://github.com/notifications"))) + (define-key map [mode-line mouse-3] + (lambda () + "Fetching GitHub notifications." + (interactive) + (message "Fetching GitHub notifications...") + (doom-modeline--github-fetch-notifications))) + map)) + sep)))) + + +;; +;; Debug states +;; + +;; Highlight the doom-modeline while debugging. +(defvar-local doom-modeline--debug-cookie nil) +(defun doom-modeline--debug-visual (&rest _) + "Update the face of mode-line for debugging." + (mapc (lambda (buffer) + (with-current-buffer buffer + (setq doom-modeline--debug-cookie + (face-remap-add-relative 'doom-modeline 'doom-modeline-debug-visual)) + (force-mode-line-update))) + (buffer-list))) + +(defun doom-modeline--normal-visual (&rest _) + "Restore the face of mode-line." + (mapc (lambda (buffer) + (with-current-buffer buffer + (when doom-modeline--debug-cookie + (face-remap-remove-relative doom-modeline--debug-cookie) + (force-mode-line-update)))) + (buffer-list))) + +(add-hook 'dap-session-created-hook #'doom-modeline--debug-visual) +(add-hook 'dap-terminated-hook #'doom-modeline--normal-visual) + +(defun doom-modeline-debug-icon (face) + "Display debug icon with FACE and ARGS." + (doom-modeline-icon 'codicon "nf-cod-debug" "🐛" "!" :face face)) + +(defun doom-modeline--debug-dap () + "The current `dap-mode' state." + (when (and (bound-and-true-p dap-mode) + (bound-and-true-p lsp-mode)) + (when-let ((session (dap--cur-session))) + (when (dap--session-running session) + (propertize (doom-modeline-debug-icon 'doom-modeline-info) + 'help-echo (format "DAP (%s - %s) +mouse-1: Display debug hydra +mouse-2: Display recent configurations +mouse-3: Disconnect session" + (dap--debug-session-name session) + (dap--debug-session-state session)) + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'dap-hydra) + (define-key map [mode-line mouse-2] + #'dap-debug-recent) + (define-key map [mode-line mouse-3] + #'dap-disconnect) + map)))))) + +(defvar-local doom-modeline--debug-dap nil) +(defun doom-modeline-update-debug-dap (&rest _) + "Update dap debug state." + (setq doom-modeline--debug-dap (doom-modeline--debug-dap))) + +(add-hook 'dap-session-created-hook #'doom-modeline-update-debug-dap) +(add-hook 'dap-session-changed-hook #'doom-modeline-update-debug-dap) +(add-hook 'dap-terminated-hook #'doom-modeline-update-debug-dap) + +(defsubst doom-modeline--debug-edebug () + "The current `edebug' state." + (when (bound-and-true-p edebug-mode) + (propertize (doom-modeline-debug-icon 'doom-modeline-info) + 'help-echo (format "EDebug (%s) +mouse-1: Show help +mouse-2: Next +mouse-3: Stop debugging" + edebug-execution-mode) + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'edebug-help) + (define-key map [mode-line mouse-2] + #'edebug-next-mode) + (define-key map [mode-line mouse-3] + #'edebug-stop) + map)))) + +(defsubst doom-modeline--debug-on-error () + "The current `debug-on-error' state." + (when debug-on-error + (propertize (doom-modeline-debug-icon 'doom-modeline-urgent) + 'help-echo "Debug on Error +mouse-1: Toggle Debug on Error" + 'mouse-face 'doom-modeline-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-error)))) + +(defsubst doom-modeline--debug-on-quit () + "The current `debug-on-quit' state." + (when debug-on-quit + (propertize (doom-modeline-debug-icon 'doom-modeline-warning) + 'help-echo "Debug on Quit +mouse-1: Toggle Debug on Quit" + 'mouse-face 'doom-modeline-highlight + 'local-map (make-mode-line-mouse-map 'mouse-1 #'toggle-debug-on-quit)))) + +(doom-modeline-def-segment debug + "The current debug state." + (when (doom-modeline--segment-visible 'debug) + (let* ((dap doom-modeline--debug-dap) + (edebug (doom-modeline--debug-edebug)) + (on-error (doom-modeline--debug-on-error)) + (on-quit (doom-modeline--debug-on-quit)) + (vsep (doom-modeline-vspc)) + (sep (and (or dap edebug on-error on-quit) (doom-modeline-spc)))) + (concat sep + (and dap (concat dap (and (or edebug on-error on-quit) vsep))) + (and edebug (concat edebug (and (or on-error on-quit) vsep))) + (and on-error (concat on-error (and on-quit vsep))) + on-quit + sep)))) + + +;; +;; PDF pages +;; + +(defvar-local doom-modeline--pdf-pages nil) +(defun doom-modeline-update-pdf-pages () + "Update PDF pages." + (setq doom-modeline--pdf-pages + (format " P%d/%d " + (or (eval `(pdf-view-current-page)) 0) + (pdf-cache-number-of-pages)))) +(add-hook 'pdf-view-change-page-hook #'doom-modeline-update-pdf-pages) + +(doom-modeline-def-segment pdf-pages + "Display PDF pages." + doom-modeline--pdf-pages) + + +;; +;; `mu4e' notifications +;; + +(doom-modeline-def-segment mu4e + "Show notifications of any unread emails in `mu4e'." + (when (and doom-modeline-mu4e + (doom-modeline--segment-visible 'mu4e)) + (let ((sep (doom-modeline-spc)) + (vsep (doom-modeline-vspc)) + (icon (doom-modeline-icon 'mdicon "nf-md-email" "📧" "#" + :face 'doom-modeline-notification))) + (cond ((and (bound-and-true-p mu4e-alert-mode-line) + (numberp mu4e-alert-mode-line) + ;; don't display if the unread mails count is zero + (> mu4e-alert-mode-line 0)) + (concat + sep + (propertize + (concat + icon + vsep + (propertize + (if (> mu4e-alert-mode-line doom-modeline-number-limit) + (format "%d+" doom-modeline-number-limit) + (number-to-string mu4e-alert-mode-line)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'mouse-face 'doom-modeline-highlight + 'keymap '(mode-line keymap + (mouse-1 . mu4e-alert-view-unread-mails) + (mouse-2 . mu4e-alert-view-unread-mails) + (mouse-3 . mu4e-alert-view-unread-mails)) + 'help-echo (concat (if (= mu4e-alert-mode-line 1) + "You have an unread email" + (format "You have %s unread emails" mu4e-alert-mode-line)) + "\nClick here to view " + (if (= mu4e-alert-mode-line 1) "it" "them"))) + sep)) + ((bound-and-true-p mu4e-modeline-mode) + (concat sep icon vsep + (propertize (mu4e--modeline-string) + 'face 'doom-modeline-notification) + sep)))))) + +(defun doom-modeline-override-mu4e-alert (&rest _) + "Delete `mu4e-alert-mode-line' from global modeline string." + (when (and (featurep 'mu4e-alert) + (bound-and-true-p mu4e-alert-mode-line)) + (if (and doom-modeline-mu4e + (bound-and-true-p doom-modeline-mode)) + ;; Delete original modeline + (progn + (setq global-mode-string + (delete '(:eval mu4e-alert-mode-line) global-mode-string)) + (setq mu4e-alert-modeline-formatter #'identity)) + ;; Recover default settings + (setq mu4e-alert-modeline-formatter #'mu4e-alert-default-mode-line-formatter)))) +(advice-add #'mu4e-alert-enable-mode-line-display + :after #'doom-modeline-override-mu4e-alert) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-alert) + +(defun doom-modeline-override-mu4e-modeline (&rest _) + "Delete `mu4e-alert-mode-line' from global modeline string." + (when (bound-and-true-p mu4e-modeline-mode) + (if (and doom-modeline-mu4e + (bound-and-true-p doom-modeline-mode)) + ;; Delete original modeline + (setq global-mode-string + (delete mu4e--modeline-item global-mode-string)) + ;; Recover default settings + (add-to-list 'global-mode-string mu4e--modeline-item)))) +(add-hook 'mu4e-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-mu4e-modeline) + +(doom-modeline-add-variable-watcher + 'doom-modeline-mu4e + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-mu4e val) + (doom-modeline-override-mu4e-alert) + (doom-modeline-override-mu4e-modeline)))) + + +;; +;; `gnus' notifications +;; + +(defvar doom-modeline--gnus-unread-mail 0) +(defvar doom-modeline--gnus-started nil + "Used to determine if gnus has started.") +(defun doom-modeline-update-gnus-status (&rest _) + "Get the total number of unread news of gnus group." + (setq doom-modeline--gnus-unread-mail + (when (and doom-modeline-gnus + doom-modeline--gnus-started) + (let ((total-unread-news-number 0)) + (mapc (lambda (g) + (let* ((group (car g)) + (unread (eval `(gnus-group-unread ,group)))) + (when (and (not (seq-contains-p doom-modeline-gnus-excluded-groups group)) + (numberp unread) + (> unread 0)) + (setq total-unread-news-number (+ total-unread-news-number unread))))) + gnus-newsrc-alist) + total-unread-news-number)))) + +;; Update the modeline after changes have been made +(add-hook 'gnus-group-update-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-summary-update-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-group-update-group-hook #'doom-modeline-update-gnus-status) +(add-hook 'gnus-after-getting-new-news-hook #'doom-modeline-update-gnus-status) + +;; Only start to listen to gnus when gnus is actually running +(defun doom-modeline-start-gnus-listener () + "Start GNUS listener." + (when (and doom-modeline-gnus + (not doom-modeline--gnus-started)) + (setq doom-modeline--gnus-started t) + ;; Scan gnus in the background if the timer is higher than 0 + (doom-modeline-update-gnus-status) + (if (> doom-modeline-gnus-timer 0) + (gnus-demon-add-handler 'gnus-demon-scan-news doom-modeline-gnus-timer doom-modeline-gnus-idle)))) +(add-hook 'gnus-started-hook #'doom-modeline-start-gnus-listener) + +;; Stop the listener if gnus isn't running +(defun doom-modeline-stop-gnus-listener () + "Stop GNUS listener." + (setq doom-modeline--gnus-started nil)) +(add-hook 'gnus-exit-gnus-hook #'doom-modeline-stop-gnus-listener) + +(doom-modeline-def-segment gnus + "Show notifications of any unread emails in `gnus'." + (when (and (doom-modeline--segment-visible 'gnus) + doom-modeline-gnus + doom-modeline--gnus-started + ;; Don't display if the unread mails count is zero + (numberp doom-modeline--gnus-unread-mail) + (> doom-modeline--gnus-unread-mail 0)) + (let ((sep (doom-modeline-spc)) + (vsep (doom-modeline-vspc))) + (concat + sep + (propertize + (concat + (doom-modeline-icon 'mdicon "nf-md-email" "📧" "#" + :face 'doom-modeline-notification) + vsep + (propertize + (if (> doom-modeline--gnus-unread-mail doom-modeline-number-limit) + (format "%d+" doom-modeline-number-limit) + (number-to-string doom-modeline--gnus-unread-mail)) + 'face '(:inherit + (doom-modeline-unread-number doom-modeline-notification)))) + 'mouse-face 'doom-modeline-highlight + 'help-echo (if (= doom-modeline--gnus-unread-mail 1) + "You have an unread email" + (format "You have %s unread emails" doom-modeline--gnus-unread-mail))) + sep)))) + + +;; +;; IRC notifications +;; + +(defun doom-modeline-shorten-irc (name) + "Shorten IRC buffer `name' according to IRC mode. + +Calls the mode specific function to return the shortened +version of `NAME' if applicable: +- Circe: `tracking-shorten' +- ERC: `erc-track-shorten-function' +- rcirc: `rcirc-shorten-buffer-name' + +The specific function will decide how to stylize the buffer name, +read the individual functions documentation for more." + (or (and (fboundp 'tracking-shorten) + (car (tracking-shorten (list name)))) + (and (boundp 'erc-track-shorten-function) + (functionp erc-track-shorten-function) + (car (funcall erc-track-shorten-function (list name)))) + (and (fboundp 'rcirc-short-buffer-name) + (rcirc-short-buffer-name name)) + name)) + +(defun doom-modeline--tracking-buffers (buffers) + "Logic to convert some irc BUFFERS to their font-awesome icon." + (mapconcat + (lambda (b) + (propertize + (funcall doom-modeline-irc-stylize b) + 'face '(:inherit (doom-modeline-unread-number doom-modeline-notification)) + 'help-echo (format "IRC Notification: %s\nmouse-1: Switch to buffer" b) + 'mouse-face 'doom-modeline-highlight + 'local-map (make-mode-line-mouse-map + 'mouse-1 + (lambda () + (interactive) + (when (buffer-live-p (get-buffer b)) + (switch-to-buffer b)))))) + buffers + (doom-modeline-vspc))) + +(defun doom-modeline--circe-p () + "Check if `circe' is in use." + (boundp 'tracking-mode-line-buffers)) + +(defun doom-modeline--erc-p () + "Check if `erc' is in use." + (boundp 'erc-modified-channels-alist)) + +(defun doom-modeline--rcirc-p () + "Check if `rcirc' is in use." + (bound-and-true-p rcirc-track-minor-mode)) + +(defun doom-modeline--get-buffers () + "Gets the buffers that have activity." + (cond + ((doom-modeline--circe-p) + tracking-buffers) + ((doom-modeline--erc-p) + (mapcar (lambda (l) + (buffer-name (car l))) + erc-modified-channels-alist)) + ((doom-modeline--rcirc-p) + (mapcar (lambda (b) + (buffer-name b)) + rcirc-activity)))) + +;; Create a modeline segment that contains all the irc tracked buffers +(doom-modeline-def-segment irc-buffers + "The list of shortened, unread irc buffers." + (when (and doom-modeline-irc + (doom-modeline--segment-visible 'irc-buffers)) + (let* ((buffers (doom-modeline--get-buffers)) + (number (length buffers)) + (sep (doom-modeline-spc))) + (when (> number 0) + (concat + sep + (doom-modeline--tracking-buffers buffers) + sep))))) + +(doom-modeline-def-segment irc + "A notification icon for any unread irc buffer." + (when (and doom-modeline-irc + (doom-modeline--segment-visible 'irc)) + (let* ((buffers (doom-modeline--get-buffers)) + (number (length buffers)) + (sep (doom-modeline-spc)) + (vsep (doom-modeline-vspc))) + (when (> number 0) + (concat + sep + + (propertize (concat + (doom-modeline-icon 'mdicon "nf-md-message_processing" "🗊" "#" + :face 'doom-modeline-notification) + vsep + ;; Display the number of unread buffers + (propertize (number-to-string number) + 'face '(:inherit + (doom-modeline-unread-number + doom-modeline-notification)))) + 'help-echo (format "IRC Notifications: %s\n%s" + (mapconcat + (lambda (b) (funcall doom-modeline-irc-stylize b)) + buffers + ", ") + (cond + ((doom-modeline--circe-p) + "mouse-1: Switch to previous unread buffer +mouse-3: Switch to next unread buffer") + ((doom-modeline--erc-p) + "mouse-1: Switch to buffer +mouse-3: Switch to next unread buffer") + ((doom-modeline--rcirc-p) + "mouse-1: Switch to server buffer +mouse-3: Switch to next unread buffer"))) + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (cond + ((doom-modeline--circe-p) + (define-key map [mode-line mouse-1] + #'tracking-previous-buffer) + (define-key map [mode-line mouse-3] + #'tracking-next-buffer)) + ((doom-modeline--erc-p) + (define-key map [mode-line mouse-1] + #'erc-switch-to-buffer) + (define-key map [mode-line mouse-3] + #'erc-track-switch-buffer)) + ((doom-modeline--rcirc-p) + (define-key map [mode-line mouse-1] + #'rcirc-switch-to-server-buffer) + (define-key map [mode-line mouse-3] + #'rcirc-next-active-buffer))) + map)) + + ;; Display the unread irc buffers as well + (when doom-modeline-irc-buffers + (concat sep (doom-modeline--tracking-buffers buffers))) + + sep))))) + +(defun doom-modeline-override-rcirc () + "Override default `rcirc' mode-line." + (if (and doom-modeline-irc + (bound-and-true-p doom-modeline-mode)) + (setq global-mode-string + (delq 'rcirc-activity-string global-mode-string)) + (when (and rcirc-track-minor-mode + (not (memq 'rcirc-activity-string global-mode-string))) + (setq global-mode-string + (append global-mode-string '(rcirc-activity-string)))))) +(add-hook 'rcirc-track-minor-mode-hook #'doom-modeline-override-rcirc) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-rcirc) + +(doom-modeline-add-variable-watcher + 'doom-modeline-irc + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-irc val) + (doom-modeline-override-rcirc)))) + + +;; +;; Battery status +;; + +(defun doom-modeline-battery-icon (icon unicode text face) + "Displays the battery ICON with FACE. + +UNICODE and TEXT are fallbacks. +Uses `nerd-icons-mdicon' to fetch the icon." + (doom-modeline-icon 'mdicon icon unicode text :face face)) + +(defvar doom-modeline--battery-status nil) +(defun doom-modeline-update-battery-status () + "Update battery status." + (setq doom-modeline--battery-status + (when (and doom-modeline-battery + (bound-and-true-p display-battery-mode)) + (let* ((data (and battery-status-function + (functionp battery-status-function) + (funcall battery-status-function))) + (status (cdr (assoc ?L data))) + (charging? (or (string-equal "AC" status) + (string-equal "on-line" status))) + (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR")))) + (valid-percentage? (and (numberp percentage) + (>= percentage 0) + (<= percentage battery-mode-line-limit))) + (face (if valid-percentage? + (cond (charging? 'doom-modeline-battery-charging) + ((< percentage battery-load-critical) 'doom-modeline-battery-critical) + ((< percentage 25) 'doom-modeline-battery-warning) + ((< percentage 95) 'doom-modeline-battery-normal) + (t 'doom-modeline-battery-full)) + 'doom-modeline-battery-error)) + (icon (if valid-percentage? + (cond + ((>= percentage 100) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_100" + "nf-md-battery") + "🔋" "-" face)) + ((>= percentage 90) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_90" + "nf-md-battery_90") + "🔋" "-" face)) + ((>= percentage 80) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_80" + "nf-md-battery_80") + "🔋" "-" face)) + ((>= percentage 70) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_70" + "nf-md-battery_70") + "🔋" "-" face)) + ((>= percentage 60) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_60" + "nf-md-battery_60") + "🔋" "-" face)) + ((>= percentage 50) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_50" + "nf-md-battery_50") + "🔋" "-" face)) + ((>= percentage 40) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_40" + "nf-md-battery_40") + "🔋" "-" face)) + ((>= percentage 30) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_30" + "nf-md-battery_30") + "🔋" "-" face)) + ((>= percentage 20) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_20" + "nf-md-battery_20") + "🔋" "-" face)) + ((>= percentage 10) + (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_10" + "nf-md-battery_10") + "🪫" "-" face)) + (t (doom-modeline-battery-icon (if charging? + "nf-md-battery_charging_outline" + "nf-md-battery_outline") + "🪫" "!" face))) + (doom-modeline-battery-icon "nf-md-battery_alert" "⚠" "N/A" face))) + (text (if valid-percentage? (format "%d%s" percentage "%%") "")) + (help-echo (if (and battery-echo-area-format data valid-percentage?) + (battery-format battery-echo-area-format data) + "Battery status not available"))) + (cons (propertize icon 'help-echo help-echo) + (propertize text 'face face 'help-echo help-echo)))))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-icon + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-icon val) + (doom-modeline-update-battery-status)))) + +(doom-modeline-add-variable-watcher + 'doom-modeline-unicode-fallback + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-unicode-fallback val) + (doom-modeline-update-battery-status)))) + +(doom-modeline-def-segment battery + "Display battery status." + (when (and doom-modeline-battery + (bound-and-true-p display-battery-mode) + (doom-modeline--segment-visible 'battery)) + (let ((sep (doom-modeline-spc)) + (vsep (doom-modeline-vspc))) + (concat sep + (car doom-modeline--battery-status) + vsep + (cdr doom-modeline--battery-status) + sep)))) + +(defun doom-modeline-override-battery () + "Override default battery mode-line." + (if (and doom-modeline-battery + (bound-and-true-p doom-modeline-mode)) + (progn + (advice-add #'battery-update :override #'doom-modeline-update-battery-status) + (setq global-mode-string + (delq 'battery-mode-line-string global-mode-string)) + (and (bound-and-true-p display-battery-mode) (battery-update))) + (progn + (advice-remove #'battery-update #'doom-modeline-update-battery-status) + (when (and display-battery-mode battery-status-function battery-mode-line-format + (not (memq 'battery-mode-line-string global-mode-string))) + (setq global-mode-string + (append global-mode-string '(battery-mode-line-string))))))) +(add-hook 'display-battery-mode-hook #'doom-modeline-override-battery) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-battery) + +(doom-modeline-add-variable-watcher + 'doom-modeline-battery + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-battery val) + (doom-modeline-override-battery)))) + + +;; +;; Package information +;; + +(doom-modeline-def-segment package + "Show package information via `paradox'." + (concat + (doom-modeline-display-text + (format-mode-line 'mode-line-front-space)) + + (when (and doom-modeline-icon doom-modeline-major-mode-icon) + (concat + (doom-modeline-spc) + (doom-modeline-icon 'faicon "nf-fa-archive" nil nil + :face (doom-modeline-face + (if doom-modeline-major-mode-color-icon + 'nerd-icons-silver + 'mode-line))))) + (doom-modeline-display-text + (format-mode-line 'mode-line-buffer-identification)))) + + +;; +;; Helm +;; + +(defvar doom-modeline--helm-buffer-ids + '(("*helm*" . "HELM") + ("*helm M-x*" . "HELM M-x") + ("*swiper*" . "SWIPER") + ("*Projectile Perspectives*" . "HELM Projectile Perspectives") + ("*Projectile Layouts*" . "HELM Projectile Layouts") + ("*helm-ag*" . (lambda () + (format "HELM Ag: Using %s" + (car (split-string helm-ag-base-command)))))) + "Alist of custom helm buffer names to use. +The cdr can also be a function that returns a name to use.") + +(doom-modeline-def-segment helm-buffer-id + "Helm session identifier." + (when (bound-and-true-p helm-alive-p) + (let ((sep (doom-modeline-spc))) + (concat + sep + (when doom-modeline-icon + (concat + (doom-modeline-icon 'sucicon "nf-custom-emacs" nil nil + :face (doom-modeline-face + (and doom-modeline-major-mode-color-icon + 'nerd-icons-blue))) + sep)) + (propertize + (let ((custom (cdr (assoc (buffer-name) doom-modeline--helm-buffer-ids))) + (case-fold-search t) + (name (replace-regexp-in-string "-" " " (buffer-name)))) + (cond ((stringp custom) custom) + ((functionp custom) (funcall custom)) + (t + (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name) + (concat "HELM " (capitalize (match-string 2 name)))))) + 'face (doom-modeline-face 'doom-modeline-buffer-file)) + sep)))) + +(doom-modeline-def-segment helm-number + "Number of helm candidates." + (when (bound-and-true-p helm-alive-p) + (concat + (propertize (format " %d/%d" + (helm-candidate-number-at-point) + (helm-get-candidate-number t)) + 'face (doom-modeline-face 'doom-modeline-buffer-path)) + (propertize (format " (%d total) " (helm-get-candidate-number)) + 'face (doom-modeline-face 'doom-modeline-info))))) + +(doom-modeline-def-segment helm-help + "Helm keybindings help." + (when (bound-and-true-p helm-alive-p) + (mapcar + (lambda (s) + (if (string-prefix-p "\\<" s) + (propertize (substitute-command-keys s) + 'face (doom-modeline-face + 'doom-modeline-buffer-file)) + s)) + '("\\<helm-map>\\[helm-help]" "(help) " + "\\<helm-map>\\[helm-select-action]" "(actions) " + "\\<helm-map>\\[helm-maybe-exit-minibuffer]/F1/F2..." "(action) ")))) + +(doom-modeline-def-segment helm-prefix-argument + "Helm prefix argument." + (when (and (bound-and-true-p helm-alive-p) + helm--mode-line-display-prefarg) + (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg)))) + (unless (= arg 1) + (propertize (format "C-u %s" arg) + 'face (doom-modeline-face 'doom-modeline-info)))))) + +(defvar doom-modeline--helm-current-source nil + "The currently active helm source.") +(doom-modeline-def-segment helm-follow + "Helm follow indicator." + (and (bound-and-true-p helm-alive-p) + doom-modeline--helm-current-source + (eq 1 (cdr (assq 'follow doom-modeline--helm-current-source))) + "HF")) + +;; +;; Git timemachine +;; + +(doom-modeline-def-segment git-timemachine + (concat + (doom-modeline-spc) + (doom-modeline--buffer-mode-icon) + (doom-modeline--buffer-state-icon) + (propertize + "*%b*" + 'face (doom-modeline-face 'doom-modeline-buffer-timemachine)))) + +;; +;; Markdown/Org preview +;; + +(doom-modeline-def-segment grip + (when (bound-and-true-p grip-mode) + (let ((sep (doom-modeline-spc))) + (concat + sep + (let ((face (doom-modeline-face + (if grip--process + (pcase (process-status grip--process) + ('run 'doom-modeline-info) + ('exit 'doom-modeline-warning) + (_ 'doom-modeline-urgent)) + 'doom-modeline-urgent)))) + (propertize + (doom-modeline-icon 'codicon "nf-cod-open_preview" "🗐" "@" :face face) + 'help-echo (format "Preview on %s +mouse-1: Preview in browser +mouse-2: Stop preview +mouse-3: Restart preview" + (grip--preview-url)) + 'mouse-face 'doom-modeline-highlight + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line mouse-1] + #'grip-browse-preview) + (define-key map [mode-line mouse-2] + #'grip-stop-preview) + (define-key map [mode-line mouse-3] + #'grip-restart-preview) + map))) + sep)))) + +;; +;; Follow mode +;; + +(doom-modeline-def-segment follow + (when (bound-and-true-p follow-mode) + (let* ((windows (follow-all-followers)) + (nwindows (length windows)) + (nfollowing (- (length (memq (selected-window) windows)) 1))) + (concat + (doom-modeline-spc) + (propertize (format "Follow %d/%d" (- nwindows nfollowing) nwindows) + 'face 'doom-modeline-buffer-minor-mode))))) + +;; +;; Display time +;; + +(defconst doom-modeline--clock-hour-hand-ratio 0.45 + "Length of the hour hand as a proportion of the radius.") + +(defconst doom-modeline--clock-minute-hand-ratio 0.7 + "Length of the minute hand as a proportion of the radius.") + +(defun doom-modeline--create-clock-svg (hour minute radius color) + "Construct an SVG clock showing the time HOUR:MINUTE. +The clock will be of the specified RADIUS and COLOR." + (let ((thickness-factor (image-compute-scaling-factor 'auto)) + (hour-x (* radius (sin (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) + doom-modeline--clock-hour-hand-ratio)) + (hour-y (* radius (cos (* (- 6 hour (/ minute 60.0)) (/ float-pi 6))) + doom-modeline--clock-hour-hand-ratio)) + (minute-x (* radius (sin (* (- 30 minute) (/ float-pi 30))) + doom-modeline--clock-minute-hand-ratio)) + (minute-y (* radius (cos (* (- 30 minute) (/ float-pi 30))) + doom-modeline--clock-minute-hand-ratio)) + (svg (svg-create (* 2 radius) (* 2 radius) :stroke color))) + (svg-circle svg radius radius (- radius thickness-factor) + :fill "none" :stroke-width (* 2 thickness-factor)) + (svg-circle svg radius radius thickness-factor + :fill color :stroke "none") + (svg-line svg radius radius (+ radius hour-x) (+ radius hour-y) + :stroke-width (* 2 thickness-factor)) + (svg-line svg radius radius (+ radius minute-x) (+ radius minute-y) + :stroke-width (* 1.5 thickness-factor)) + svg)) + +(defvar doom-modeline--clock-cache nil + "The last result of `doom-modeline--generate-clock'.") + +(defun doom-modeline--generate-clock () + "Return a string containing the current time as an analogue clock svg. +When the svg library is not available, return nil." + (cdr + (or (and (equal (truncate (float-time) + (* doom-modeline-time-clock-minute-resolution 60)) + (car doom-modeline--clock-cache)) + doom-modeline--clock-cache) + (and (require 'svg nil t) + (setq doom-modeline--clock-cache + (cons (truncate (float-time) + (* doom-modeline-time-clock-minute-resolution 60)) + (propertize + " " + 'display + (svg-image + (doom-modeline--create-clock-svg + (string-to-number (format-time-string "%-I")) ; hour + (* (truncate (string-to-number (format-time-string "%-M")) + doom-modeline-time-clock-minute-resolution) + doom-modeline-time-clock-minute-resolution) ; minute + (if (integerp doom-modeline-time-clock-size) ; radius + doom-modeline-time-clock-size + (* doom-modeline-height 0.5 doom-modeline-time-clock-size)) + "currentColor") + :scale 1 :ascent 'center) + 'face 'doom-modeline-time + 'help-echo (lambda (_window _object _pos) + (format-time-string "%c"))))))))) + +(defun doom-modeline-time-icon () + "Displays the time icon." + (or (and doom-modeline-time-live-icon + doom-modeline-time-analogue-clock + (display-graphic-p) + (doom-modeline--generate-clock)) + (doom-modeline-icon + 'mdicon + (if doom-modeline-time-live-icon + (pcase (% (caddr (decode-time)) 12) + (0 "nf-md-clock_time_twelve_outline") + (1 "nf-md-clock_time_one_outline") + (2 "nf-md-clock_time_two_outline") + (3 "nf-md-clock_time_three_outline") + (4 "nf-md-clock_time_four_outline") + (5 "nf-md-clock_time_five_outline") + (6 "nf-md-clock_time_six_outline") + (7 "nf-md-clock_time_seven_outline") + (8 "nf-md-clock_time_eight_outline") + (9 "nf-md-clock_time_nine_outline") + (10 "nf-md-clock_time_ten_outline") + (11 "nf-md-clock_time_eleven_outline")) + "nf-md-clock_outline") + "⏰" + "" + :face '(:inherit doom-modeline-time :weight normal)))) + +(doom-modeline-def-segment time + (when (and doom-modeline-time + (bound-and-true-p display-time-mode) + (doom-modeline--segment-visible 'time)) + (concat + (doom-modeline-spc) + (when doom-modeline-time-icon + (concat + (doom-modeline-time-icon) + (and (or doom-modeline-icon doom-modeline-unicode-fallback) + (doom-modeline-vspc)))) + (propertize display-time-string + 'face (doom-modeline-face 'doom-modeline-time))))) + +(defun doom-modeline-override-time () + "Override default `display-time' mode-line." + (or global-mode-string (setq global-mode-string '(""))) + (if (and doom-modeline-time + (bound-and-true-p doom-modeline-mode)) + (setq global-mode-string (delq 'display-time-string global-mode-string)) + (setq global-mode-string (append global-mode-string '(display-time-string))))) +(add-hook 'display-time-mode-hook #'doom-modeline-override-time) +(add-hook 'doom-modeline-mode-hook #'doom-modeline-override-time) + +(doom-modeline-add-variable-watcher + 'doom-modeline-time + (lambda (_sym val op _where) + (when (eq op 'set) + (setq doom-modeline-time val) + (doom-modeline-override-time)))) + +;; +;; Compilation +;; + +(doom-modeline-def-segment compilation + (and (bound-and-true-p compilation-in-progress) + (propertize "[Compiling] " + 'face (doom-modeline-face 'doom-modeline-compilation) + 'help-echo "Compiling; mouse-2: Goto Buffer" + 'mouse-face 'doom-modeline-highlight + 'local-map + (make-mode-line-mouse-map + 'mouse-2 + #'compilation-goto-in-progress-buffer)))) + +;; +;; Eldoc +;; + +(doom-modeline-def-segment eldoc + (and (bound-and-true-p eldoc-mode) + '(eldoc-mode-line-string + (" " eldoc-mode-line-string " ")))) + +(defun doom-modeline-eldoc-minibuffer-message (format-string &rest args) + "Display message specified by FORMAT-STRING and ARGS on the mode-line as needed. +This function displays the message produced by formatting ARGS +with FORMAT-STRING on the mode line when the current buffer is a minibuffer. +Otherwise, it displays the message like `message' would." + (if (minibufferp) + (progn + (add-hook 'minibuffer-exit-hook + (lambda () (setq eldoc-mode-line-string nil + ;; https://debbugs.gnu.org/16920 + eldoc-last-message nil)) + nil t) + (with-current-buffer + (window-buffer + (or (window-in-direction 'above (minibuffer-window)) + (minibuffer-selected-window) + (get-largest-window))) + (setq eldoc-mode-line-string + (when (stringp format-string) + (apply #'format-message format-string args))) + (force-mode-line-update))) + (apply #'message format-string args))) + +;; +;; Kubernetes +;; + +(doom-modeline-def-segment k8s + (when (and (bound-and-true-p kele-mode) (doom-modeline--segment-visible 'k8s)) + (let* ((ctx (kele-current-context-name :wait nil)) + (ns (kele-current-namespace :wait nil)) + (icon (doom-modeline-icon 'mdicon "nf-md-kubernetes" "K8s:" "K8s:")) + (sep (doom-modeline-spc)) + (help-msg (let ((msgs (list (format "Current context: %s" ctx)))) + (when ns + (setq msgs (append msgs (list (format "Current namespace: %s" ns))))) + (string-join msgs "\n")))) + (propertize (concat + icon sep ctx + (when (and doom-modeline-k8s-show-namespace ns) (format "(%s)" ns)) + sep) + 'local-map (let ((map (make-sparse-keymap))) + (define-key map [mode-line down-mouse-1] kele-menu-map) + map) + 'mouse-face 'doom-modeline-highlight + 'help-echo help-msg)))) + +(provide 'doom-modeline-segments) + +;;; doom-modeline-segments.el ends here diff --git a/emacs/elpa/doom-modeline-20240816.749/doom-modeline-segments.elc b/emacs/elpa/doom-modeline-20240816.749/doom-modeline-segments.elc Binary files differ. diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline.el b/emacs/elpa/doom-modeline-20240816.749/doom-modeline.el diff --git a/emacs/elpa/doom-modeline-20240811.1437/doom-modeline.elc b/emacs/elpa/doom-modeline-20240816.749/doom-modeline.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-magik.el b/emacs/elpa/lsp-mode-20240801.2341/lsp-magik.el @@ -1,177 +0,0 @@ -;;; lsp-magik.el --- Language server client for Magik -*- lexical-binding: t; -*- - -;; Copyright (C) 2022 Keronic - -;; Author: <robin.putters@keronic.com> -;; Keywords: lsp, magik - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; LSP client for the Magik programming language -;; https://github.com/StevenLooman/magik-tools - -;;; Code: - -(require `lsp-mode) - -(defgroup lsp-magik nil - "LSP support for Magik." - :link '(url-link "https://github.com/StevenLooman/magik-tools") - :group 'lsp-mode - :tag "Lsp Magik" - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-version "0.10.0" - "Version of LSP server." - :type `string - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-download-url-lsp (format "https://github.com/StevenLooman/magik-tools/releases/download/%s/magik-language-server-%s.jar" lsp-magik-version lsp-magik-version) - "URL of LSP server to download." - :type `string - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(lsp-dependency - 'magik-ls - `(:download :url lsp-magik-download-url-lsp - :store-path ,(f-join lsp-server-install-dir "magik-ls" (format "magik-language-server-%s.jar" lsp-magik-version)))) - -(defcustom lsp-magik-ls-path - (f-join lsp-server-install-dir (format "magik-ls/magik-language-server-%s.jar" lsp-magik-version)) - "Path of the language server." - :type 'string - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-java-home nil - "Path to Java Runtime, Java 17 minimum." - :type `string - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-product-dirs [] - "Paths to (compiled, containing a libs/ directory) products." - :type `lsp-string-vector - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-lint-override-config-file nil - "Override path to magiklintrc.properties." - :type 'string - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-type-database-paths [] - "Paths to type databases." - :type `lsp-string-vector - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-show-typing-inlay-hints nil - "Show typing inlay hints." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-show-argument-inlay-hints nil - "Show (certain) argument name inlay hints." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-enable-checks nil - "Enable typing checks." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-index-global-usages t - "Enable indexing of usages of globals by methods." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-index-method-usages nil - "Enable indexing of usages of methods by methods." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-index-slot-usages t - "Enable indexing of usages of slots by methods." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-index-condition-usages t - "Enable indexing of usages of conditions by methods." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-typing-cache-indexed-definitions-method-usages t - "Store and load the indexed definitions in the workspace folders." - :type `boolean - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-magik-java-path (lambda () - (cond ((eq system-type 'windows-nt) - (or (lsp-resolve-value (executable-find (expand-file-name "bin/java" (getenv "JAVA_HOME")))) - (lsp-resolve-value (executable-find "java")))) - (t "java"))) - "Path to Java Runtime, Java 11 minimum." - :type 'string - :group `lsp-magik - :package-version '(lsp-mode . "9.0.0")) - -(lsp-register-client - (make-lsp-client - :download-server-fn (lambda (_client callback error-callback _update?) - (lsp-package-ensure 'magik-ls callback error-callback)) - :new-connection (lsp-stdio-connection - (lambda () - (list - (substitute-in-file-name (lsp-resolve-value lsp-magik-java-path)) - "-jar" - (substitute-in-file-name lsp-magik-ls-path) - "--debug"))) - :activation-fn (lsp-activate-on "magik") - :initialized-fn (lambda (workspace) - (with-lsp-workspace workspace - (lsp--set-configuration (lsp-configuration-section "magik")))) - :server-id 'magik)) - -(lsp-register-custom-settings - `(("magik.javaHome" lsp-magik-java-home) - ("magik.productDirs" lsp-magik-product-dirs) - ("magik.lint.overrideConfigFile" lsp-magik-lint-override-config-file) - ("magik.typing.typeDatabasePaths" lsp-magik-typing-type-database-paths) - ("magik.typing.showTypingInlayHints" lsp-magik-typing-show-typing-inlay-hints) - ("magik.typing.showArgumentInlayHints" lsp-magik-typing-show-argument-inlay-hints) - ("magik.typing.enableChecks" lsp-magik-typing-enable-checks) - ("magik.typing.indexGlobalUsages" lsp-magik-typing-index-global-usages) - ("magik.typing.indexMethodUsages" lsp-magik-typing-index-method-usages) - ("magik.typing.indexSlotUsages" lsp-magik-typing-index-slot-usages) - ("magik.typing.indexConditionUsages" lsp-magik-typing-index-condition-usages) - ("magik.typing.cacheIndexedDefinitions" lsp-magik-typing-cache-indexed-definitions))) - -(lsp-consistency-check lsp-magik) - -(provide 'lsp-magik) -;;; lsp-magik.el ends here diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-magik.elc b/emacs/elpa/lsp-mode-20240801.2341/lsp-magik.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mode-pkg.el b/emacs/elpa/lsp-mode-20240801.2341/lsp-mode-pkg.el @@ -1,15 +0,0 @@ -(define-package "lsp-mode" "20240801.2341" "LSP mode" - '((emacs "27.1") - (dash "2.18.0") - (f "0.20.0") - (ht "2.3") - (spinner "1.7.3") - (markdown-mode "2.3") - (lv "0") - (eldoc "1.11")) - :commit "c8d8bd0f5c40123821bf7c90afa5b6abb05074cb" :keywords - '("languages") - :url "https://github.com/emacs-lsp/lsp-mode") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rust.el b/emacs/elpa/lsp-mode-20240801.2341/lsp-rust.el @@ -1,1781 +0,0 @@ -;;; lsp-rust.el --- Rust Client settings -*- lexical-binding: t; -*- - -;; Copyright (C) 2019 Ivan Yonchovski - -;; Author: Ivan Yonchovski <yyoncho@gmail.com> -;; Keywords: - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; lsp-rust client - -;;; Code: - -(require 'lsp-mode) -(require 'ht) -(require 'dash) -(require 'lsp-semantic-tokens) -(require 's) - -(defgroup lsp-rust nil - "LSP support for Rust, using Rust Language Server or rust-analyzer." - :group 'lsp-mode - :link '(url-link "https://github.com/rust-lang/rls") - :package-version '(lsp-mode . "6.1")) - -(defgroup lsp-rust-rls nil - "LSP support for Rust, using Rust Language Server." - :group 'lsp-mode - :link '(url-link "https://github.com/rust-lang/rls") - :package-version '(lsp-mode . "8.0.0")) - -(defgroup lsp-rust-analyzer nil - "LSP support for Rust, using rust-analyzer." - :group 'lsp-mode - :link '(url-link "https://github.com/rust-lang/rust-analyzer") - :package-version '(lsp-mode . "8.0.0")) - -(defgroup lsp-rust-analyzer-semantic-tokens nil - "LSP semantic tokens support for rust-analyzer." - :group 'lsp-rust-analyzer - :link '(url-link "https://github.com/rust-lang/rust-analyzer") - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-server 'rust-analyzer - "Choose LSP server." - :type '(choice (const :tag "rls" rls) - (const :tag "rust-analyzer" rust-analyzer)) - :group 'lsp-rust - :package-version '(lsp-mode . "6.2")) - -;; RLS - -(defcustom lsp-rust-rls-server-command '("rls") - "Command to start RLS." - :type '(repeat string) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-library-directories - '("~/.cargo/registry/src" "~/.rustup/toolchains") - "List of directories which will be considered to be libraries." - :risky t - :type '(repeat string) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-sysroot nil - "If non-nil, use the given path as the sysroot for all rustc invocations -instead of trying to detect the sysroot automatically." - :type '(choice - (const :tag "None" nil) - (string :tag "Sysroot")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-target nil - "If non-nil, use the given target triple for all rustc invocations." - :type '(choice - (const :tag "None" nil) - (string :tag "Target")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-rustflags nil - "Flags added to RUSTFLAGS." - :type '(choice - (const :tag "None" nil) - (string :tag "Flags")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-clear-env-rust-log t - "Clear the RUST_LOG environment variable before running rustc or cargo." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-build-lib nil - "If non-nil, checks the project as if you passed the `--lib' argument to -cargo. - -Mutually exclusive with, and preferred over, `lsp-rust-build-bin'. (Unstable)" - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-build-bin nil - "If non-nil, checks the project as if you passed `-- bin <build_bin>' -argument to cargo. - -Mutually exclusive with `lsp-rust-build-lib'. (Unstable)" - :type '(choice - (const :tag "None" nil) - (string :tag "Binary")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-cfg-test nil - "If non-nil, checks the project as if you were running `cargo test' rather -than cargo build. - -I.e., compiles (but does not run) test code." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-unstable-features nil - "Enable unstable features." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-wait-to-build nil - "Time in milliseconds between receiving a change notification -and starting build. If not specified, automatically inferred by -the latest build duration." - :type '(choice - (const :tag "Auto" nil) - (number :tag "Time")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-show-warnings t - "Show warnings." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-crate-blocklist [ - "cocoa" - "gleam" - "glium" - "idna" - "libc" - "openssl" - "rustc_serialize" - "serde" - "serde_json" - "typenum" - "unicode_normalization" - "unicode_segmentation" - "winapi" - ] - "A list of Cargo crates to blocklist." - :type 'lsp-string-vector - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-build-on-save nil - "Only index the project when a file is saved and not on change." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-features [] - "List of features to activate. -Set this to `\"all\"` to pass `--all-features` to cargo." - :type 'lsp-string-vector - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-all-features nil - "Enable all Cargo features." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-no-default-features nil - "Do not enable default Cargo features." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-racer-completion t - "Enables code completion using racer." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-clippy-preference "opt-in" - "Controls eagerness of clippy diagnostics when available. -Valid values are (case-insensitive): - - \"off\": Disable clippy lints. - - \"opt-in\": Clippy lints are shown when crates specify `#![warn(clippy)]'. - - \"on\": Clippy lints enabled for all crates in workspace. - -You need to install clippy via rustup if you haven't already." - :type '(choice - (const "on") - (const "opt-in") - (const "off")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-jobs nil - "Number of Cargo jobs to be run in parallel." - :type '(choice - (const :tag "Auto" nil) - (number :tag "Jobs")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-all-targets t - "Checks the project as if you were running cargo check --all-targets. -I.e., check all targets and integration tests too." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-target-dir nil - "When specified, it places the generated analysis files at the -specified target directory. By default it is placed target/rls -directory." - :type '(choice - (const :tag "Default" nil) - (string :tag "Directory")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-rustfmt-path nil - "When specified, RLS will use the Rustfmt pointed at the path -instead of the bundled one" - :type '(choice - (const :tag "Bundled" nil) - (string :tag "Path")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-build-command nil - "EXPERIMENTAL (requires `rust.unstable_features') -If set, executes a given program responsible for rebuilding save-analysis to be -loaded by the RLS. The program given should output a list of resulting .json -files on stdout. - -Implies `rust.build_on_save': true." - :type '(choice - (const :tag "None" nil) - (string :tag "Command")) - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-full-docs nil - "Instructs cargo to enable full documentation extraction during -save-analysis while building the crate." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(defcustom lsp-rust-show-hover-context t - "Show additional context in hover tooltips when available. This -is often the type local variable declaration." - :type 'boolean - :group 'lsp-rust-rls - :package-version '(lsp-mode . "6.1")) - -(lsp-register-custom-settings - '(("rust.show_hover_context" lsp-rust-show-hover-context t) - ("rust.full_docs" lsp-rust-full-docs t) - ("rust.build_command" lsp-rust-build-command) - ("rust.rustfmt_path" lsp-rust-rustfmt-path) - ("rust.target_dir" lsp-rust-target-dir) - ("rust.all_targets" lsp-rust-all-targets t) - ("rust.jobs" lsp-rust-jobs) - ("rust.clippy_preference" lsp-rust-clippy-preference) - ("rust.racer_completion" lsp-rust-racer-completion t) - ("rust.no_default_features" lsp-rust-no-default-features t) - ("rust.all_features" lsp-rust-all-features t) - ("rust.features" lsp-rust-features) - ("rust.build_on_save" lsp-rust-build-on-save t) - ("rust.crate_blocklist" lsp-rust-crate-blocklist) - ("rust.show_warnings" lsp-rust-show-warnings t) - ("rust.wait_to_build" lsp-rust-wait-to-build) - ("rust.unstable_features" lsp-rust-unstable-features t) - ("rust.cfg_test" lsp-rust-cfg-test t) - ("rust.build_bin" lsp-rust-build-bin) - ("rust.build_lib" lsp-rust-build-lib t) - ("rust.clear_env_rust_log" lsp-rust-clear-env-rust-log t) - ("rust.rustflags" lsp-rust-rustflags) - ("rust.target" lsp-rust-target) - ("rust.sysroot" lsp-rust-sysroot))) - -(defun lsp-clients--rust-window-progress (workspace params) - "Progress report handling. -PARAMS progress report notification data." - (-let [(&v1:ProgressParams :done? :message? :title) params] - (if (or done? (s-blank-str? message?)) - (lsp-workspace-status nil workspace) - (lsp-workspace-status (format "%s - %s" title (or message? "")) workspace)))) - -(lsp-defun lsp-rust--rls-run ((&Command :arguments? params)) - (-let* (((&rls:Cmd :env :binary :args :cwd) (lsp-seq-first params)) - (default-directory (or cwd (lsp-workspace-root) default-directory) )) - (compile - (format "%s %s %s" - (s-join " " (ht-amap (format "%s=%s" key value) env)) - binary - (s-join " " args))))) - -(lsp-register-client - (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-rust-rls-server-command)) - :activation-fn (lsp-activate-on "rust") - :priority (if (eq lsp-rust-server 'rls) 1 -1) - :initialization-options '((omitInitBuild . t) - (cmdRun . t)) - :notification-handlers (ht ("window/progress" 'lsp-clients--rust-window-progress)) - :action-handlers (ht ("rls.run" 'lsp-rust--rls-run)) - :library-folders-fn (lambda (_workspace) lsp-rust-library-directories) - :initialized-fn (lambda (workspace) - (with-lsp-workspace workspace - (lsp--set-configuration - (lsp-configuration-section "rust")))) - :server-id 'rls)) - - -;; rust-analyzer -(defcustom lsp-rust-analyzer-server-command '("rust-analyzer") - "Command to start rust-analyzer." - :type '(repeat string) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-rust-analyzer-library-directories - '("~/.cargo/registry/src" "~/.rustup/toolchains") - "List of directories which will be considered to be libraries." - :risky t - :type '(repeat string) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-server-format-inlay-hints t - "Whether to ask rust-analyzer to format inlay hints itself. If -active, the various inlay format settings are not used." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-hide-closure-initialization nil - "Whether to hide inlay type hints for `let` statements that initialize -to a closure. Only applies to closures with blocks, same as -`#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-highlight-breakpoints t - "Enables highlighting of related references while the cursor is on -`break`, `loop`, `while`, or `for` keywords." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-highlight-closure-captures t - "Enables highlighting of all captures of a closure while the -cursor is on the `|` or move keyword of a closure." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-highlight-exit-points t - "Enables highlighting of all exit points while the cursor is on -any `return`, `?`, `fn`, or return type arrow (`->`)." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-highlight-references t - "Enables highlighting of related references while the cursor is on -any identifier." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-highlight-yield-points t - "Enables highlighting of all break points for a loop or block -context while the cursor is on any `async` or `await` keywords." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-closure-return-type-hints "never" - "Whether to show inlay type hints for return types of closures." - :type '(choice - (const "never") - (const "always") - (const "with_block")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-discriminants-hints "never" - "Whether to show enum variant discriminant hints." - :type '(choice - (const "never") - (const "always") - (const "fieldless")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-expression-adjustment-hints "never" - "Whether to show inlay hints for type adjustments.." - :type '(choice - (const "never") - (const "always") - (const "reborrow")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-expression-adjustment-hints-mode "prefix" - "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc)." - :type '(choice - (const "prefix") - (const "postfix") - (const "prefer_prefix") - (const "prefer_postfix")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-expression-adjustment-hide-unsafe nil - "Whether to hide inlay hints for type adjustments outside of -`unsafe` blocks." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-implicit-drops nil - "Whether to show implicit drop hints." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - - -(defcustom lsp-rust-analyzer-closure-capture-hints nil - "Whether to show inlay hints for closure captures." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-closure-style "impl_fn" - "Closure notation in type and chaining inlay hints." - :type 'string - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-hide-named-constructor nil - "Whether to hide inlay type hints for constructors." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-max-inlay-hint-length nil - "Max inlay hint length." - :type 'integer - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-display-chaining-hints nil - "Whether to show inlay type hints for method chains. These -hints will be formatted with the type hint formatting options, if -the mode is not configured to ask the server to format them." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-display-lifetime-elision-hints-enable "never" - "Whether to show elided lifetime inlay hints." - :type '(choice - (const "never") - (const "always") - (const "skip_trivial")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names nil - "When showing elided lifetime inlay hints, whether to use -parameter names or numeric placeholder names for the lifetimes." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-display-closure-return-type-hints nil - "Whether to show closure return type inlay hints for closures -with block bodies." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-display-parameter-hints nil - "Whether to show function parameter name inlay hints at the call site." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-display-reborrow-hints "never" - "Whether to show inlay type hints for compiler inserted reborrows." - :type '(choice - (const "always") - (const "never") - (const "mutable")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-binding-mode-hints nil - "Whether to show inlay type hints for binding modes." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-closing-brace-hints t - "Whether to show inlay hints after a closing `}` to indicate what item it -belongs to." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-closing-brace-hints-min-lines 25 - "Minimum number of lines required before the `}` until the hint is shown -\(set to 0 or 1 to always show them)." - :type 'integer - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lru-capacity nil - "Number of syntax trees rust-analyzer keeps in memory." - :type 'integer - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-cargo-target nil - "Compilation target (target triple)." - :type '(choice - (string :tag "Target") - (const :tag "None" nil)) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-cargo-watch-enable t - "Enable Cargo watch." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-cargo-watch-command "check" - "Cargo watch command." - :type 'string - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-cargo-watch-args [] - "Extra arguments for `cargo check`." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-cargo-override-command [] - "Advanced option, fully override the command rust-analyzer uses for checking. -The command should include `--message=format=json` or similar option." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-check-all-targets t - "Enables --all-targets for `cargo check`." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.2")) - -(defcustom lsp-rust-analyzer-checkonsave-features [] - "List of features to activate. -Set this to `\"all\"` to pass `--all-features` to cargo." - :type 'lsp-string-vector - :group 'lsp-rust-rust-analyzer - :package-version '(lsp-mode . "8.0.2")) - -(defcustom lsp-rust-analyzer-cargo-unset-test [] - "force rust-analyzer to unset `#[cfg(test)]` for the specified crates." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-use-client-watching t - "Use client watching" - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-exclude-globs [] - "Exclude globs" - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-exclude-dirs [] - "These directories will be ignored by rust-analyzer." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-macro-expansion-method 'lsp-rust-analyzer-macro-expansion-default - "Use a different function if you want formatted macro expansion results and -syntax highlighting." - :type 'function - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.2.2")) - -(defcustom lsp-rust-analyzer-diagnostics-enable t - "Whether to show native rust-analyzer diagnostics." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-diagnostics-enable-experimental nil - "Whether to show native rust-analyzer diagnostics that are still experimental -\(might have more false positives than usual)." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-diagnostics-disabled [] - "List of native rust-analyzer diagnostics to disable." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-diagnostics-warnings-as-hint [] - "List of warnings that should be displayed with hint severity." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-diagnostics-warnings-as-info [] - "List of warnings that should be displayed with info severity." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(define-obsolete-variable-alias - 'lsp-rust-analyzer-cargo-load-out-dirs-from-check - 'lsp-rust-analyzer-cargo-run-build-scripts - "8.0.0") - -(defcustom lsp-rust-analyzer-cargo-run-build-scripts t - "Whether to run build scripts (`build.rs`) for more precise code analysis." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-rustfmt-extra-args [] - "Additional arguments to rustfmt." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-rustfmt-override-command [] - "Advanced option, fully override the command rust-analyzer uses -for formatting." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-rustfmt-rangeformatting-enable nil - "Enables the use of rustfmt's unstable range formatting command for the -`textDocument/rangeFormatting` request. The rustfmt option is unstable and only -available on a nightly build." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-completion-add-call-parenthesis t - "Whether to add parenthesis when completing functions." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-completion-add-call-argument-snippets t - "Whether to add argument snippets when completing functions." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-completion-postfix-enable t - "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-call-info-full t - "Whether to show function name and docs in parameter hints." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-proc-macro-enable t - "Enable Proc macro support. -Implies `lsp-rust-analyzer-cargo-run-build-scripts'" - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "6.3.2")) - -(defcustom lsp-rust-analyzer-import-prefix "plain" - "The path structure for newly inserted paths to use. -Valid values are: - - \"plain\": Insert import paths relative to the current module, using up to -one `super' prefix if the parent module contains the requested item. - - \"by_self\": Prefix all import paths with `self' if they don't begin with -`self', `super', `crate' or a crate name. - - \"by_crate\": Force import paths to be absolute by always starting -them with `crate' or the crate name they refer to." - :type '(choice - (const "plain") - (const "by_self") - (const "by_crate")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-import-granularity "crate" - "How imports should be grouped into use statements." - :type '(choice - (const "crate" :doc "Merge imports from the same crate into a single use statement. This kind of nesting is only supported in Rust versions later than 1.24.") - (const "module" :doc "Merge imports from the same module into a single use statement.") - (const "item" :doc "Don’t merge imports at all, creating one import per item.") - (const "preserve" :doc "Do not change the granularity of any imports. For auto-import this has the same effect as `\"item\"'")) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-cargo-auto-reload t - "Automatically refresh project info via `cargo metadata' on `Cargo.toml' changes." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts t - "Use `RUSTC_WRAPPER=rust-analyzer' when running build scripts to avoid -compiling unnecessary things." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-completion-auto-import-enable t - "Toggles the additional completions that automatically add imports when -completed. `lsp-completion-enable-additional-text-edit' must be non-nil - for this feature to be fully enabled." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-completion-auto-self-enable t - "Toggles the additional completions that automatically show method calls -and field accesses with self prefixed to them when inside a method." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-import-enforce-granularity nil - "Whether to enforce the import granularity setting for all files. - If set to nil rust-analyzer will try to keep import styles consistent per file." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-imports-merge-glob t - "Whether to allow import insertion to merge new imports into single path -glob imports like `use std::fmt::*;`." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-import-group t - "Group inserted imports by the following order: -https://rust-analyzer.github.io/manual.html#auto-import. - Groups are separated by newlines." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-highlighting-strings t - "Use semantic tokens for strings." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-rustc-source nil - "Path to the Cargo.toml of the rust compiler workspace." - :type '(choice - (file :tag "Path") - (const :tag "None" nil)) - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-linked-projects [] - "Disable project auto-discovery in favor of explicitly specified set of -projects. Elements must be paths pointing to `Cargo.toml`, `rust-project.json`, -or JSON objects in `rust-project.json` format." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-experimental-proc-attr-macros t - "Whether to enable experimental support for expanding proc macro attributes." - :type 'boolean - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-cargo-extra-args [] - "Extra arguments that are passed to every cargo invocation." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-cargo-extra-env [] - "Extra environment variables that will be set when running cargo, rustc or -other commands within the workspace. Useful for setting RUSTFLAGS." - :type 'lsp-string-vector - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "9.0.0")) - -(defconst lsp-rust-notification-handlers - '(("rust-analyzer/publishDecorations" . (lambda (_w _p))))) - -(defconst lsp-rust-action-handlers - '()) - -(define-derived-mode lsp-rust-analyzer-syntax-tree-mode special-mode "Rust-Analyzer-Syntax-Tree" - "Mode for the rust-analyzer syntax tree buffer.") - -(defun lsp-rust-analyzer-syntax-tree () - "Display syntax tree for current buffer." - (interactive) - (-let* ((root (lsp-workspace-root default-directory)) - (params (lsp-make-rust-analyzer-syntax-tree-params - :text-document (lsp--text-document-identifier) - :range? (if (use-region-p) - (lsp--region-to-range (region-beginning) (region-end)) - (lsp--region-to-range (point-min) (point-max))))) - (results (lsp-send-request (lsp-make-request - "rust-analyzer/syntaxTree" - params)))) - (let ((buf (get-buffer-create (format "*rust-analyzer syntax tree %s*" root))) - (inhibit-read-only t)) - (with-current-buffer buf - (lsp-rust-analyzer-syntax-tree-mode) - (erase-buffer) - (insert results) - (goto-char (point-min))) - (pop-to-buffer buf)))) - -(define-derived-mode lsp-rust-analyzer-status-mode special-mode "Rust-Analyzer-Status" - "Mode for the rust-analyzer status buffer.") - -(defun lsp-rust-analyzer-status () - "Displays status information for rust-analyzer." - (interactive) - (-let* ((root (lsp-workspace-root default-directory)) - (params (lsp-make-rust-analyzer-analyzer-status-params - :text-document (lsp--text-document-identifier))) - (results (lsp-send-request (lsp-make-request - "rust-analyzer/analyzerStatus" - params)))) - (let ((buf (get-buffer-create (format "*rust-analyzer status %s*" root))) - (inhibit-read-only t)) - (with-current-buffer buf - (lsp-rust-analyzer-status-mode) - (erase-buffer) - (insert results) - (pop-to-buffer buf))))) - -(defun lsp-rust-analyzer-view-item-tree () - "Show item tree of rust file." - (interactive) - (-let* ((params (lsp-make-rust-analyzer-view-item-tree - :text-document (lsp--text-document-identifier))) - (results (lsp-send-request (lsp-make-request - "rust-analyzer/viewItemTree" - params)))) - (let ((buf (get-buffer-create "*rust-analyzer item tree*")) - (inhibit-read-only t)) - (with-current-buffer buf - (special-mode) - (erase-buffer) - (insert (lsp--render-string results "rust")) - (pop-to-buffer buf))))) - -(defun lsp-rust-analyzer-view-hir () - "View Hir of function at point." - (interactive) - (-let* ((params (lsp-make-rust-analyzer-expand-macro-params - :text-document (lsp--text-document-identifier) - :position (lsp--cur-position))) - (results (lsp-send-request (lsp-make-request - "rust-analyzer/viewHir" - params)))) - (let ((buf (get-buffer-create "*rust-analyzer hir*")) - (inhibit-read-only t)) - (with-current-buffer buf - (special-mode) - (erase-buffer) - (insert results) - (pop-to-buffer buf))))) - -(defun lsp-rust-analyzer-join-lines () - "Join selected lines into one, smartly fixing up whitespace and trailing commas." - (interactive) - (let* ((params (lsp-make-rust-analyzer-join-lines-params - :text-document (lsp--text-document-identifier) - :ranges (vector (if (use-region-p) - (lsp--region-to-range (region-beginning) (region-end)) - (lsp--region-to-range (point) (point)))))) - (result (lsp-send-request (lsp-make-request "experimental/joinLines" params)))) - (lsp--apply-text-edits result 'code-action))) - -(defun lsp-rust-analyzer-reload-workspace () - "Reload workspace, picking up changes from Cargo.toml" - (interactive) - (lsp--cur-workspace-check) - (lsp-send-request (lsp-make-request "rust-analyzer/reloadWorkspace"))) - -(defcustom lsp-rust-analyzer-download-url - (let* ((x86 (string-prefix-p "x86_64" system-configuration)) - (arch (if x86 "x86_64" "aarch64"))) - (format "https://github.com/rust-lang/rust-analyzer/releases/latest/download/%s" - (pcase system-type - ('gnu/linux (format "rust-analyzer-%s-unknown-linux-gnu.gz" arch)) - ('darwin (format "rust-analyzer-%s-apple-darwin.gz" arch)) - ('windows-nt (format "rust-analyzer-%s-pc-windows-msvc.zip" arch))))) - "Automatic download url for Rust Analyzer" - :type 'string - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(defcustom lsp-rust-analyzer-store-path (f-join lsp-server-install-dir "rust" - (pcase system-type - ('windows-nt "rust-analyzer.exe") - (_ "rust-analyzer"))) - "The path to the file in which `rust-analyzer' will be stored." - :type 'file - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -(lsp-dependency - 'rust-analyzer - `(:download :url lsp-rust-analyzer-download-url - :decompress ,(pcase system-type ('windows-nt :zip) (_ :gzip)) - :store-path lsp-rust-analyzer-store-path - :set-executable? t) - `(:system ,(file-name-nondirectory lsp-rust-analyzer-store-path))) - -(lsp-defun lsp-rust--analyzer-run-single ((&Command :arguments?)) - (lsp-rust-analyzer-run (lsp-seq-first arguments?))) - -(lsp-defun lsp-rust--analyzer-show-references - ((&Command :title :arguments? [_uri _filepos references])) - (lsp-show-xrefs (lsp--locations-to-xref-items references) nil - (s-contains-p "reference" title))) - -(declare-function dap-debug "ext:dap-mode" (template) t) - -(lsp-defun lsp-rust--analyzer-debug-lens ((&Command :arguments? [args])) - (lsp-rust-analyzer-debug args)) - -;; Semantic tokens - -;; Modifier faces -(defface lsp-rust-analyzer-documentation-modifier-face - '((t nil)) - "The face modification to use for documentation items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-declaration-modifier-face - '((t nil)) - "The face modification to use for declaration items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-definition-modifier-face - '((t nil)) - "The face modification to use for definition items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-static-modifier-face - '((t nil)) - "The face modification to use for static items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-abstract-modifier-face - '((t nil)) - "The face modification to use for abstract items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-deprecated-modifier-face - '((t nil)) - "The face modification to use for deprecated items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-readonly-modifier-face - '((t nil)) - "The face modification to use for readonly items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-default-library-modifier-face - '((t nil)) - "The face modification to use for default-library items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-async-modifier-face - '((t nil)) - "The face modification to use for async items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-attribute-modifier-face - '((t nil)) - "The face modification to use for attribute items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-callable-modifier-face - '((t nil)) - "The face modification to use for callable items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-constant-modifier-face - '((t nil)) - "The face modification to use for constant items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-consuming-modifier-face - '((t nil)) - "The face modification to use for consuming items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-control-flow-modifier-face - '((t nil)) - "The face modification to use for control-flow items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-crate-root-modifier-face - '((t nil)) - "The face modification to use for crate-root items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-injected-modifier-face - '((t nil)) - "The face modification to use for injected items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-intra-doc-link-modifier-face - '((t nil)) - "The face modification to use for intra-doc-link items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-library-modifier-face - '((t nil)) - "The face modification to use for library items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-mutable-modifier-face - '((t :underline t)) - "The face modification to use for mutable items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-public-modifier-face - '((t nil)) - "The face modification to use for public items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-reference-modifier-face - '((t :bold t)) - "The face modification to use for reference items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-trait-modifier-face - '((t nil)) - "The face modification to use for trait items." - :group 'lsp-rust-analyzer-semantic-tokens) - -(defface lsp-rust-analyzer-unsafe-modifier-face - '((t nil)) - "The face modification to use for unsafe items." - :group 'lsp-rust-analyzer-semantic-tokens) - - -;; --------------------------------------------------------------------- -;; Semantic token modifier face customization - -(defcustom lsp-rust-analyzer-documentation-modifier 'lsp-rust-analyzer-documentation-modifier-face - "Face for semantic token modifier for `documentation' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-declaration-modifier 'lsp-rust-analyzer-declaration-modifier-face - "Face for semantic token modifier for `declaration' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-definition-modifier 'lsp-rust-analyzer-definition-modifier-face - "Face for semantic token modifier for `definition' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-static-modifier 'lsp-rust-analyzer-static-modifier-face - "Face for semantic token modifier for `static' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-abstract-modifier 'lsp-rust-analyzer-abstract-modifier-face - "Face for semantic token modifier for `abstract' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-deprecated-modifier 'lsp-rust-analyzer-deprecated-modifier-face - "Face for semantic token modifier for `deprecated' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-readonly-modifier 'lsp-rust-analyzer-readonly-modifier-face - "Face for semantic token modifier for `readonly' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-default-library-modifier 'lsp-rust-analyzer-default-library-modifier-face - "Face for semantic token modifier for `default' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-async-modifier 'lsp-rust-analyzer-async-modifier-face - "Face for semantic token modifier for `async' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-attribute-modifier 'lsp-rust-analyzer-attribute-modifier-face - "Face for semantic token modifier for `attribute' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-callable-modifier 'lsp-rust-analyzer-callable-modifier-face - "Face for semantic token modifier for `callable' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-constant-modifier 'lsp-rust-analyzer-constant-modifier-face - "Face for semantic token modifier for `constant' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-consuming-modifier 'lsp-rust-analyzer-consuming-modifier-face - "Face for semantic token modifier for `consuming' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-control-flow-modifier 'lsp-rust-analyzer-control-flow-modifier-face - "Face for semantic token modifier for `control_flow' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-crate-root-modifier 'lsp-rust-analyzer-crate-root-modifier-face - "Face for semantic token modifier for `crate_root' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-injected-modifier 'lsp-rust-analyzer-injected-modifier-face - "Face for semantic token modifier for `injected' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-intra-doc-link-modifier 'lsp-rust-analyzer-intra-doc-link-modifier-face - "Face for semantic token modifier for `intra_doc_link' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-library-modifier 'lsp-rust-analyzer-library-modifier-face - "Face for semantic token modifier for `library' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-mutable-modifier 'lsp-rust-analyzer-mutable-modifier-face - "Face for semantic token modifier for `mutable' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-public-modifier 'lsp-rust-analyzer-public-modifier-face - "Face for semantic token modifier for `public' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-reference-modifier 'lsp-rust-analyzer-reference-modifier-face - "Face for semantic token modifier for `reference' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-trait-modifier 'lsp-rust-analyzer-trait-modifier-face - "Face for semantic token modifier for `trait' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-unsafe-modifier 'lsp-rust-analyzer-unsafe-modifier-face - "Face for semantic token modifier for `unsafe' attribute." - :type 'face - :group 'lsp-rust-analyzer-semantic-tokens - :package-version '(lsp-mode . "9.0.0")) - -;; --------------------------------------------------------------------- - -(defun lsp-rust-analyzer--semantic-modifiers () - "Mapping between rust-analyzer keywords and fonts to apply. -The keywords are sent in the initialize response, in the semantic -tokens legend." - `(("documentation" . ,lsp-rust-analyzer-documentation-modifier) - ("declaration" . ,lsp-rust-analyzer-declaration-modifier) - ("definition" . ,lsp-rust-analyzer-definition-modifier) - ("static" . ,lsp-rust-analyzer-static-modifier) - ("abstract" . ,lsp-rust-analyzer-abstract-modifier) - ("deprecated" . ,lsp-rust-analyzer-deprecated-modifier) - ("readonly" . ,lsp-rust-analyzer-readonly-modifier) - ("default_library" . ,lsp-rust-analyzer-default-library-modifier) - ("async" . ,lsp-rust-analyzer-async-modifier) - ("attribute" . ,lsp-rust-analyzer-attribute-modifier) - ("callable" . ,lsp-rust-analyzer-callable-modifier) - ("constant" . ,lsp-rust-analyzer-constant-modifier) - ("consuming" . ,lsp-rust-analyzer-consuming-modifier) - ("control_flow" . ,lsp-rust-analyzer-control-flow-modifier) - ("crate_root" . ,lsp-rust-analyzer-crate-root-modifier) - ("injected" . ,lsp-rust-analyzer-injected-modifier) - ("intra_doc_link" . ,lsp-rust-analyzer-intra-doc-link-modifier) - ("library" . ,lsp-rust-analyzer-library-modifier) - ("mutable" . ,lsp-rust-analyzer-mutable-modifier) - ("public" . ,lsp-rust-analyzer-public-modifier) - ("reference" . ,lsp-rust-analyzer-reference-modifier) - ("trait" . ,lsp-rust-analyzer-trait-modifier) - ("unsafe" . ,lsp-rust-analyzer-unsafe-modifier))) - -(defun lsp-rust-switch-server (&optional lsp-server) - "Switch priorities of lsp servers, unless LSP-SERVER is already active." - (interactive) - (let ((current-server (if (> (lsp--client-priority (gethash 'rls lsp-clients)) 0) - 'rls - 'rust-analyzer))) - (unless (eq lsp-server current-server) - (dolist (server '(rls rust-analyzer)) - (when (natnump (setf (lsp--client-priority (gethash server lsp-clients)) - (* (lsp--client-priority (gethash server lsp-clients)) -1))) - (message (format "Switched to server %s." server))))))) - -;; -;;; Inlay hints - -(defcustom lsp-rust-analyzer-debug-lens-extra-dap-args - '(:MIMode "gdb" :miDebuggerPath "gdb" :stopAtEntry t :externalConsole :json-false) - "Extra arguments to pass to DAP template when debugging a test from code lens. - -As a rule of the thumb, do not add extra keys to this plist unless you exactly -what you are doing, it might break the \"Debug test\" lens otherwise. - -See dap-mode documentation and cpptools documentation for the extra variables -meaning." - :type 'plist - :group 'lsp-rust-analyzer - :package-version '(lsp-mode . "8.0.0")) - -;; -;;; Lenses - -(defgroup lsp-rust-analyzer-lens nil - "LSP lens support for Rust when using rust-analyzer. - -Lenses are (depending on your configuration) clickable links to -the right of function definitions and the like. These display -some useful information in their own right and/or perform a -shortcut action when clicked such as displaying uses of that -function or running an individual test. -" - :prefix "lsp-rust-analyzer-lens-" - :group 'lsp-rust-analyzer - :link '(url-link "https://emacs-lsp.github.io/lsp-mode/") - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-debug-enable t - "Enable or disable the Debug lens." - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-enable t - "Master-enable of lenses in Rust files." - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -;; This customisation "works" in that it works as described, but the default is fine and changing it -;; from the default will either stop lenses working or do nothing. -;; -;; If this is ever uncommented to re-enable the option, don't forget to also uncomment it in defun -;; lsp-rust-analyzer--make-init-options too or it'll not do anything. - -;; (defcustom lsp-rust-analyzer-lens-force-custom-commands t -;; "Internal config: use custom client-side commands even when the -;; client doesn't set the corresponding capability." -;; :type 'boolean -;; :group 'lsp-rust-analyzer-lens -;; :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-implementations-enable t - "Enable or disable the Implementations lens. - -The Implementations lens shows `NN implementations' to the right -of the first line of an enum, struct, or union declaration. This -is the count of impl blocks, including derived traits. Clicking -on it gives a list of the impls of that type. -" - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -;; The valid range of values for this is documented in the rust-lang/rust-analyzer repository at the -;; path "editors/code/package.json"; the TL:DR is that it's "above_name" or "above_whole_item". -;; However, setting it to "above_whole_item" causes lenses to disappear in Emacs. I suspect this -;; feature has only ever been tested in some other IDE and it's broken in Emacs. So I've disabled it -;; for now. -;; -;; If this is ever uncommented to re-enable the option, don't forget to also uncomment it in defun -;; lsp-rust-analyzer--make-init-options too or it'll not do anything. - -;; (defcustom lsp-rust-analyzer-lens-location "above_name" -;; "Where to render annotations." -;; :type '(choice -;; (const :tag "Above name" "above_name") -;; (const :tag "Above whole item" "above_whole_item") -;; :group 'lsp-rust-analyzer-lens -;; :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-references-adt-enable nil - "Enable or disable the References lens on enums, structs, and traits. - -The References lens shows `NN references` to the right of the -first line of each enum, struct, or union declaration. This is -the count of uses of that type. Clicking on it gives a list of -where that type is used." - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-references-enum-variant-enable nil - "Enable or disable the References lens on enum variants. - -The References lens shows `NN references` to the right of the -first (or only) line of each enum variant. This is the count of -uses of that enum variant. Clicking on it gives a list of where -that enum variant is used." - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-references-method-enable nil - "Enable or disable the References lens on functions. - -The References lens shows `NN references` to the right of the -first line of each function declaration. This is the count of -uses of that function. Clicking on it gives a list of where that -function is used." - - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-references-trait-enable nil - "Enable or disable the References lens on traits. - -The References lens shows `NN references` to the right of the -first line of each trait declaration. This is a count of uses of -that trait. Clicking on it gives a list of where that trait is -used. - -There is some overlap with the Implementations lens which slows -all of the trait's impl blocks, but this also shows other uses -such as imports and dyn traits." - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -(defcustom lsp-rust-analyzer-lens-run-enable t - "Enable or disable the Run lens." - :type 'boolean - :group 'lsp-rust-analyzer-lens - :package-version '(lsp-mode . "9.0.0")) - -(defun lsp-rust-analyzer-initialized? () - (when-let ((workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name)))) - (eq 'initialized (lsp--workspace-status workspace)))) - -(defun lsp-rust-analyzer-expand-macro () - "Expands the macro call at point recursively." - (interactive) - (-if-let* ((params (lsp-make-rust-analyzer-expand-macro-params - :text-document (lsp--text-document-identifier) - :position (lsp--cur-position))) - (response (lsp-request - "rust-analyzer/expandMacro" - params)) - ((&rust-analyzer:ExpandedMacro :expansion) response)) - (funcall lsp-rust-analyzer-macro-expansion-method expansion) - (lsp--error "No macro found at point, or it could not be expanded."))) - -(defun lsp-rust-analyzer-macro-expansion-default (result) - "Default method for displaying macro expansion." - (let* ((root (lsp-workspace-root default-directory)) - (buf (get-buffer-create (get-buffer-create (format "*rust-analyzer macro expansion %s*" root))))) - (with-current-buffer buf - (let ((inhibit-read-only t)) - (erase-buffer) - (insert (lsp--render-string result "rust")) - (special-mode))) - (pop-to-buffer buf))) - -;; -;;; Runnables - -(defvar lsp-rust-analyzer--last-runnable nil - "Record the last runnable.") - -(defun lsp-rust-analyzer--runnables () - "Return list of runnables." - (lsp-send-request (lsp-make-request - "experimental/runnables" - (lsp-make-rust-analyzer-runnables-params - :text-document (lsp--text-document-identifier) - :position? (lsp--cur-position))))) - -(defun lsp-rust-analyzer--select-runnable () - "Select runnable." - (lsp--completing-read - "Select runnable:" - (if lsp-rust-analyzer--last-runnable - (cons lsp-rust-analyzer--last-runnable - (-remove (-lambda ((&rust-analyzer:Runnable :label)) - (equal label (lsp-get lsp-rust-analyzer--last-runnable :label))) - (lsp-rust-analyzer--runnables))) - (lsp-rust-analyzer--runnables)) - (-lambda ((&rust-analyzer:Runnable :label)) label))) - -(defun lsp-rust-analyzer--common-runner (runnable) - "Execute a given RUNNABLE. - -Extract the arguments, prepare the minor mode (cargo-process-mode if possible) -and run a compilation" - (-let* (((&rust-analyzer:Runnable :kind :label :args) runnable) - ((&rust-analyzer:RunnableArgs :cargo-args :executable-args :workspace-root? :expect-test?) args) - (default-directory (or workspace-root? default-directory))) - (if (not (string-equal kind "cargo")) - (lsp--error "'%s' runnable is not supported" kind) - (compilation-start - (string-join (append (when expect-test? '("env" "UPDATE_EXPECT=1")) - (list "cargo") cargo-args - (when executable-args '("--")) executable-args '()) " ") - - ;; cargo-process-mode is nice, but try to work without it... - (if (functionp 'cargo-process-mode) 'cargo-process-mode nil) - (lambda (_) (concat "*" label "*")))))) - -(defun lsp-rust-analyzer-run (runnable) - "Select and run a RUNNABLE action." - (interactive (list (lsp-rust-analyzer--select-runnable))) - (when (lsp-rust-analyzer--common-runner runnable) - (setq lsp-rust-analyzer--last-runnable runnable))) - -(defun lsp-rust-analyzer-debug (runnable) - "Select and debug a RUNNABLE action." - (interactive (list (lsp-rust-analyzer--select-runnable))) - (unless (or (featurep 'dap-cpptools) (featurep 'dap-gdb)) - (user-error "You must require `dap-cpptools' or 'dap-gdb'")) - (-let (((&rust-analyzer:Runnable - :args (&rust-analyzer:RunnableArgs :cargo-args :workspace-root? :executable-args) - :label) runnable)) - (pcase (aref cargo-args 0) - ("run" (aset cargo-args 0 "build")) - ("test" (when (-contains? (append cargo-args ()) "--no-run") - (cl-callf append cargo-args (list "--no-run"))))) - (->> (append (list (executable-find "cargo")) - cargo-args - (list "--message-format=json")) - (s-join " ") - (shell-command-to-string) - (s-lines) - (-keep (lambda (s) - (condition-case nil - (-let* ((json-object-type 'plist) - ((msg &as &plist :reason :executable) (json-read-from-string s))) - (when (and executable (string= "compiler-artifact" reason)) - executable)) - (error)))) - (funcall - (lambda (artifact-spec) - (pcase artifact-spec - (`() (user-error "No compilation artifacts or obtaining the runnable artifacts failed")) - (`(,spec) spec) - (_ (user-error "Multiple compilation artifacts are not supported"))))) - (list :type (if (featurep 'dap-gdb) "gdb" "cppdbg") - :request "launch" - :name label - :args executable-args - :cwd workspace-root? - :sourceLanguages ["rust"] - :program) - (append lsp-rust-analyzer-debug-lens-extra-dap-args) - (dap-debug)))) - -(defun lsp-rust-analyzer-rerun (&optional runnable) - (interactive (list (or lsp-rust-analyzer--last-runnable - (lsp-rust-analyzer--select-runnable)))) - (lsp-rust-analyzer-run (or runnable lsp-rust-analyzer--last-runnable))) - -;; goto parent module -(cl-defun lsp-rust-find-parent-module (&key display-action) - "Find parent module of current module." - (interactive) - (lsp-find-locations "experimental/parentModule" nil :display-action display-action)) - -(defun lsp-rust-analyzer-open-cargo-toml (&optional new-window) - "Open the closest Cargo.toml from the current file. - -Rust-Analyzer LSP protocol documented here and added in November 2020 -https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-cargotoml - -If NEW-WINDOW (interactively the prefix argument) is non-nil, -open in a new window." - (interactive "P") - (-if-let (workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name))) - (-if-let* ((response (with-lsp-workspace workspace - (lsp-send-request (lsp-make-request - "experimental/openCargoToml" - (lsp-make-rust-analyzer-open-cargo-toml-params - :text-document (lsp--text-document-identifier)))))) - ((&Location :uri :range) response)) - (funcall (if new-window #'find-file-other-window #'find-file) - (lsp--uri-to-path uri)) - (lsp--warn "Couldn't find a Cargo.toml file or your version of rust-analyzer doesn't support this extension")) - (lsp--error "OpenCargoToml is an extension available only with rust-analyzer"))) - -(defun lsp-rust-analyzer-open-external-docs () - "Open a URL for documentation related to the current TextDocumentPosition. - -Rust-Analyzer LSP protocol documented here -https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-external-documentation" - (interactive) - (-if-let* ((params (lsp-make-rust-analyzer-open-external-docs-params - :text-document (lsp--text-document-identifier) - :position (lsp--cur-position))) - (url (lsp-request "experimental/externalDocs" params))) - (browse-url url) - (lsp--warn "Couldn't find documentation URL or your version of rust-analyzer doesn't support this extension"))) - -(defun lsp-rust-analyzer--related-tests () - "Get runnable test items related to the current TextDocumentPosition. -Calls a rust-analyzer LSP extension endpoint that returns a wrapper over -Runnable[]." - (lsp-send-request (lsp-make-request - "rust-analyzer/relatedTests" - (lsp--text-document-position-params)))) - -(defun lsp-rust-analyzer--select-related-test () - "Call the endpoint and ask for user selection. - -Cannot reuse `lsp-rust-analyzer--select-runnable' because the runnables endpoint -responds with Runnable[], while relatedTests responds with TestInfo[], -which is a wrapper over runnable. Also, this method doesn't set -the `lsp-rust-analyzer--last-runnable' variable." - (-if-let* ((resp (lsp-rust-analyzer--related-tests)) - (runnables (seq-map - #'lsp:rust-analyzer-related-tests-runnable - resp))) - (lsp--completing-read - "Select test: " - runnables - #'lsp:rust-analyzer-runnable-label))) - -(defun lsp-rust-analyzer-related-tests (runnable) - "Execute a RUNNABLE test related to the current document position. - -Rust-Analyzer LSP protocol extension -https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#related-tests" - (interactive (list (lsp-rust-analyzer--select-related-test))) - (if runnable - (lsp-rust-analyzer--common-runner runnable) - (lsp--info "There are no tests related to the symbol at point"))) - -(defun lsp-rust-analyzer-move-item (direction) - "Move item under cursor or selection in some DIRECTION" - (let* ((params (lsp-make-rust-analyzer-move-item-params - :text-document (lsp--text-document-identifier) - :range (if (use-region-p) - (lsp--region-to-range (region-beginning) (region-end)) - (lsp--region-to-range (point) (point))) - :direction direction)) - (edits (lsp-request "experimental/moveItem" params))) - (lsp--apply-text-edits edits 'code-action))) - -(defun lsp-rust-analyzer-move-item-up () - "Move item under cursor or selection up" - (interactive) - (lsp-rust-analyzer-move-item "Up")) - -(defun lsp-rust-analyzer-move-item-down () - "Move item under cursor or selection down" - (interactive) - (lsp-rust-analyzer-move-item "Down")) - -(defun lsp-rust-analyzer--make-init-options () - "Init options for rust-analyzer" - `(:diagnostics - ( :enable ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable) - :enableExperimental ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable-experimental) - :disabled ,lsp-rust-analyzer-diagnostics-disabled - :warningsAsHint ,lsp-rust-analyzer-diagnostics-warnings-as-hint - :warningsAsInfo ,lsp-rust-analyzer-diagnostics-warnings-as-info) - :imports ( :granularity ( :enforce ,(lsp-json-bool lsp-rust-analyzer-import-enforce-granularity) - :group ,lsp-rust-analyzer-import-granularity) - :group ,(lsp-json-bool lsp-rust-analyzer-import-group) - :merge (:glob ,(lsp-json-bool lsp-rust-analyzer-imports-merge-glob)) - :prefix ,lsp-rust-analyzer-import-prefix) - :lruCapacity ,lsp-rust-analyzer-lru-capacity - :checkOnSave ( :enable ,(lsp-json-bool lsp-rust-analyzer-cargo-watch-enable) - :command ,lsp-rust-analyzer-cargo-watch-command - :extraArgs ,lsp-rust-analyzer-cargo-watch-args - :allTargets ,(lsp-json-bool lsp-rust-analyzer-check-all-targets) - :features ,lsp-rust-analyzer-checkonsave-features - :overrideCommand ,lsp-rust-analyzer-cargo-override-command) - :highlightRelated ( :breakPoints (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-breakpoints)) - :closureCaptures (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-closure-captures)) - :exitPoints (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-exit-points)) - :references (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-references)) - :yieldPoints (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-yield-points))) - :files ( :exclude ,lsp-rust-analyzer-exclude-globs - :watcher ,(if lsp-rust-analyzer-use-client-watching "client" "notify") - :excludeDirs ,lsp-rust-analyzer-exclude-dirs) - :cargo ( :allFeatures ,(lsp-json-bool lsp-rust-all-features) - :noDefaultFeatures ,(lsp-json-bool lsp-rust-no-default-features) - :features ,lsp-rust-features - :extraArgs ,lsp-rust-analyzer-cargo-extra-args - :extraEnv ,lsp-rust-analyzer-cargo-extra-env - :target ,lsp-rust-analyzer-cargo-target - :runBuildScripts ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts) - ;; Obsolete, but used by old Rust-Analyzer versions - :loadOutDirsFromCheck ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts) - :autoreload ,(lsp-json-bool lsp-rust-analyzer-cargo-auto-reload) - :useRustcWrapperForBuildScripts ,(lsp-json-bool lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts) - :unsetTest ,lsp-rust-analyzer-cargo-unset-test) - :rustfmt ( :extraArgs ,lsp-rust-analyzer-rustfmt-extra-args - :overrideCommand ,lsp-rust-analyzer-rustfmt-override-command - :rangeFormatting (:enable ,(lsp-json-bool lsp-rust-analyzer-rustfmt-rangeformatting-enable))) - :lens ( :debug (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-debug-enable)) - :enable ,(lsp-json-bool lsp-rust-analyzer-lens-enable) - ;; :forceCustomCommands ,(lsp-json-bool lsp-rust-analyzer-lens-force-custom-commands) - :implementations (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-implementations-enable)) - ;; :location ,lsp-rust-analyzer-lens-location - :references ( :adt (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-adt-enable)) - :enumVariant (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-enum-variant-enable)) - :method (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-method-enable)) - :trait (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-trait-enable))) - :run (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-run-enable))) - - :inlayHints ( :bindingModeHints (:enable ,(lsp-json-bool lsp-rust-analyzer-binding-mode-hints)) - :chainingHints (:enable ,(lsp-json-bool lsp-rust-analyzer-display-chaining-hints)) - :closingBraceHints ( :enable ,(lsp-json-bool lsp-rust-analyzer-closing-brace-hints) - :minLines ,lsp-rust-analyzer-closing-brace-hints-min-lines) - :closureCaptureHints (:enable ,(lsp-json-bool lsp-rust-analyzer-closure-capture-hints)) - :closureReturnTypeHints (:enable ,lsp-rust-analyzer-closure-return-type-hints) - :closureStyle ,lsp-rust-analyzer-closure-style - :discriminantHints (:enable ,lsp-rust-analyzer-discriminants-hints) - - :expressionAdjustmentHints ( :enable ,lsp-rust-analyzer-expression-adjustment-hints - :hideOutsideUnsafe ,(lsp-json-bool lsp-rust-analyzer-expression-adjustment-hide-unsafe) - :mode ,lsp-rust-analyzer-expression-adjustment-hints-mode) - :implicitDrops (:enable ,(lsp-json-bool lsp-rust-analyzer-implicit-drops)) - :lifetimeElisionHints ( :enable ,lsp-rust-analyzer-display-lifetime-elision-hints-enable - :useParameterNames ,(lsp-json-bool lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names)) - :maxLength ,lsp-rust-analyzer-max-inlay-hint-length - :parameterHints (:enable ,(lsp-json-bool lsp-rust-analyzer-display-parameter-hints)) - :reborrowHints (:enable ,lsp-rust-analyzer-display-reborrow-hints) - :renderColons ,(lsp-json-bool lsp-rust-analyzer-server-format-inlay-hints) - :typeHints ( :enable ,(lsp-json-bool lsp-inlay-hint-enable) - :hideClosureInitialization ,(lsp-json-bool lsp-rust-analyzer-hide-closure-initialization) - :hideNamedConstructor ,(lsp-json-bool lsp-rust-analyzer-hide-named-constructor))) - :completion ( :addCallParenthesis ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-parenthesis) - :addCallArgumentSnippets ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-argument-snippets) - :postfix (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-postfix-enable)) - :autoimport (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-import-enable)) - :autoself (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-self-enable))) - :callInfo (:full ,(lsp-json-bool lsp-rust-analyzer-call-info-full)) - :procMacro (:enable ,(lsp-json-bool lsp-rust-analyzer-proc-macro-enable)) - :rustcSource ,lsp-rust-analyzer-rustc-source - :linkedProjects ,lsp-rust-analyzer-linked-projects - :highlighting (:strings ,(lsp-json-bool lsp-rust-analyzer-highlighting-strings)) - :experimental (:procAttrMacros ,(lsp-json-bool lsp-rust-analyzer-experimental-proc-attr-macros)))) - -(lsp-register-client - (make-lsp-client - :new-connection (lsp-stdio-connection - (lambda () - `(,(or (executable-find - (cl-first lsp-rust-analyzer-server-command)) - (lsp-package-path 'rust-analyzer) - "rust-analyzer") - ,@(cl-rest lsp-rust-analyzer-server-command)))) - :activation-fn (lsp-activate-on "rust") - :priority (if (eq lsp-rust-server 'rust-analyzer) 1 -1) - :initialization-options 'lsp-rust-analyzer--make-init-options - :notification-handlers (ht<-alist lsp-rust-notification-handlers) - :action-handlers (ht ("rust-analyzer.runSingle" #'lsp-rust--analyzer-run-single) - ("rust-analyzer.debugSingle" #'lsp-rust--analyzer-debug-lens) - ("rust-analyzer.showReferences" #'lsp-rust--analyzer-show-references) - ("rust-analyzer.triggerParameterHints" #'lsp--action-trigger-parameter-hints)) - :library-folders-fn (lambda (_workspace) lsp-rust-analyzer-library-directories) - :semantic-tokens-faces-overrides `( :discard-default-modifiers t - :modifiers ,(lsp-rust-analyzer--semantic-modifiers)) - :server-id 'rust-analyzer - :custom-capabilities `((experimental . ((snippetTextEdit . ,(and lsp-enable-snippet (fboundp 'yas-minor-mode)))))) - :download-server-fn (lambda (_client callback error-callback _update?) - (lsp-package-ensure 'rust-analyzer callback error-callback)))) - -(cl-defmethod lsp-clients-extract-signature-on-hover (contents (_server-id (eql rust-analyzer))) - "Extract first non-comment line from rust-analyzer's hover CONTENTS. -The first line of the hover contents is usally about memory layout or notable -traits starting with //, with the actual signature follows." - (let* ((lines (s-lines (s-trim (lsp--render-element contents)))) - (non-comment-lines (--filter (not (s-prefix? "//" it)) lines))) - (if non-comment-lines - (car non-comment-lines) - (car lines)))) - -(lsp-consistency-check lsp-rust) - -(provide 'lsp-rust) -;;; lsp-rust.el ends here diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rust.elc b/emacs/elpa/lsp-mode-20240801.2341/lsp-rust.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-terraform.elc b/emacs/elpa/lsp-mode-20240801.2341/lsp-terraform.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-yaml.el b/emacs/elpa/lsp-mode-20240801.2341/lsp-yaml.el @@ -1,242 +0,0 @@ -;;; lsp-yaml.el --- LSP YAML server integration -*- lexical-binding: t; -*- - -;; Copyright (C) 2019 Aya Igarashi - -;; Author: Aya Igarashi <ladiclexxx@gmail.com> -;; Keywords: - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; - -;;; Code: - -(require 'lsp-mode) -(require 'dash) - -(defgroup lsp-yaml nil - "LSP support for YAML, using yaml-language-server." - :group 'lsp-mode - :link '(url-link "https://github.com/redhat-developer/yaml-language-server") - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-format-enable t - "Enable/disable default YAML formatter." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-single-quote nil - "Use single quote instead of double quotes." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-bracket-spacing t - "Print spaces between brackets in objects." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-prose-wrap "preserve" - "Options for prose-wrap. - Always: wrap prose if it exceeds the print width. - Never: never wrap the prose. - Preserve: wrap prose as-is." - :type '(choice - (const "always") - (const "never") - (const "preserve")) - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-print-width 80 - "Specify the line length that the printer will wrap on." - :type 'number - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-validate t - "Enable/disable validation feature." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-hover t - "Enable/disable hover feature." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-completion t - "Enable/disable completion feature." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-schemas '() - "Associate schemas to YAML files in a glob pattern." - :type '(alist :key-type (symbol :tag "schema") :value-type (lsp-string-vector :tag "files (glob)")) - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-schema-store-enable t - "Enable/disable JSON Schema store. When set to true, available YAML - schemas will be automatically pulled from the store." - :type 'boolean - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-custom-tags nil - "Custom tags for the parser to use." - :type '(lsp-repeatable-vector string) - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(defcustom lsp-yaml-schema-store-uri "https://www.schemastore.org/api/json/catalog.json" - "URL of schema store catalog to use." - :type 'string - :group 'lsp-yaml) - -(defcustom lsp-yaml-schema-store-local-db (expand-file-name - (locate-user-emacs-file - (f-join ".cache" "lsp" "lsp-yaml-schemas.json"))) - "Cached database of schema store." - :type 'file - :group 'lsp-yaml) - -(defcustom lsp-yaml-max-items-computed 5000 - "The maximum number of outline symbols and folding regions computed. -Limited for performance reasons." - :type 'number - :group 'lsp-yaml - :package-version '(lsp-mode . "8.0.0")) - - -(defvar lsp-yaml--schema-store-schemas-alist nil - "A list of schemas fetched from schema stores.") - -(lsp-register-custom-settings - '(("yaml.format.enable" lsp-yaml-format-enable t) - ("yaml.format.singleQuote" lsp-yaml-single-quote t) - ("yaml.format.bracketSpacing" lsp-yaml-bracket-spacing) - ("yaml.format.proseWrap" lsp-yaml-prose-wrap) - ("yaml.format.printWidth" lsp-yaml-print-width) - ("yaml.validate" lsp-yaml-validate t) - ("yaml.hover" lsp-yaml-hover t) - ("yaml.completion" lsp-yaml-completion t) - ("yaml.schemas" lsp-yaml-schemas) - ("yaml.schemaStore.enable" lsp-yaml-schema-store-enable t) - ("yaml.schemaStore.url" lsp-yaml-schema-store-uri) - ("yaml.customTags" lsp-yaml-custom-tags) - ("yaml.maxItemsComputed" lsp-yaml-max-items-computed))) - -(defcustom lsp-yaml-server-command '("yaml-language-server" "--stdio") - "Command to start yaml-languageserver." - :type '(repeat string) - :group 'lsp-yaml - :package-version '(lsp-mode . "6.2")) - -(lsp-dependency 'yaml-language-server - '(:system "yaml-language-server") - '(:npm :package "yaml-language-server" - :path "yaml-language-server")) - -(lsp-register-client - (make-lsp-client :new-connection (lsp-stdio-connection - (lambda () - `(,(or (executable-find (cl-first lsp-yaml-server-command)) - (lsp-package-path 'yaml-language-server)) - ,@(cl-rest lsp-yaml-server-command)))) - :activation-fn (lsp-activate-on "yaml") - :priority 0 - :server-id 'yamlls - :initialized-fn (lambda (workspace) - (with-lsp-workspace workspace - (lsp--set-configuration - (lsp-configuration-section "yaml")))) - :download-server-fn (lambda (_client callback error-callback _update?) - (lsp-package-ensure 'yaml-language-server - callback error-callback)))) - -(defconst lsp-yaml--built-in-kubernetes-schema - '((name . "Kubernetes") - (description . "Built-in kubernetes manifest schema definition") - (url . "kubernetes") - (fileMatch . ["*-k8s.yaml" "*-k8s.yml"]))) - -(defun lsp-yaml-download-schema-store-db (&optional force-downloading) - "Download remote schema store at `lsp-yaml-schema-store-uri' into local cache. -Set FORCE-DOWNLOADING to non-nil to force re-download the database." - (interactive "P") - (when (or force-downloading (not (file-exists-p lsp-yaml-schema-store-local-db))) - (unless (file-directory-p (file-name-directory lsp-yaml-schema-store-local-db)) - (mkdir (file-name-directory lsp-yaml-schema-store-local-db) t)) - (url-copy-file lsp-yaml-schema-store-uri lsp-yaml-schema-store-local-db force-downloading))) - -(defun lsp-yaml--get-supported-schemas () - "Get out the list of supported schemas." - (when (and lsp-yaml-schema-store-enable - (not lsp-yaml--schema-store-schemas-alist)) - (lsp-yaml-download-schema-store-db) - (setq lsp-yaml--schema-store-schemas-alist - (alist-get 'schemas (json-read-file lsp-yaml-schema-store-local-db)))) - (seq-concatenate 'list (list lsp-yaml--built-in-kubernetes-schema) lsp-yaml--schema-store-schemas-alist)) - -(defun lsp-yaml-set-buffer-schema (uri-string) - "Set yaml schema for the current buffer to URI-STRING." - (interactive "MURI: ") - (let* ((uri (intern uri-string)) - (workspace-path (file-relative-name - (lsp--uri-to-path (lsp--buffer-uri)) - (lsp-workspace-root (lsp--buffer-uri)))) - (glob (concat "/" workspace-path)) - (current-config (assoc uri lsp-yaml-schemas)) - (current-patterns (and current-config (cdr current-config)))) - (if current-config - (or (member glob (append current-patterns nil)) - (setq lsp-yaml-schemas - (cl-acons uri - (vconcat (vector glob) current-patterns) - (assq-delete-all uri - (mapcar (lambda (x) (lsp-yaml--remove-glob x glob)) - lsp-yaml-schemas))))) - (setq lsp-yaml-schemas - (cl-acons uri (vector glob) (mapcar (lambda (x) (lsp-yaml--remove-glob x glob)) - lsp-yaml-schemas)))) - (lsp--set-configuration (lsp-configuration-section "yaml")))) - -(defun lsp-yaml-select-buffer-schema () - "Select schema for the current buffer based on the list of supported schemas." - (interactive) - (let* ((schema (lsp--completing-read "Select buffer schema: " - (lsp-yaml--get-supported-schemas) - (lambda (schema) - (format "%s: %s" (alist-get 'name schema)(alist-get 'description schema))) - nil t)) - (uri (alist-get 'url schema))) - (lsp-yaml-set-buffer-schema uri))) - -(defun lsp-yaml--remove-glob (mapping glob) - (let ((patterns (cdr mapping))) - (cons (car mapping) - (vconcat (-filter (lambda (p) (not (equal p glob))) - (append patterns nil)) nil)))) - -(lsp-consistency-check lsp-yaml) - -(provide 'lsp-yaml) -;;; lsp-yaml.el ends here diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-yaml.elc b/emacs/elpa/lsp-mode-20240801.2341/lsp-yaml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-actionscript.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-actionscript.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-actionscript.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-actionscript.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ada.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ada.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ada.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ada.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-angular.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-angular.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-angular.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-angular.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ansible.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ansible.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ansible.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ansible.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-asm.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-asm.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-asm.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-asm.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-astro.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-astro.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-astro.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-astro.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-autotools.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-autotools.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-autotools.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-autotools.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-awk.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-awk.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-awk.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-awk.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-bash.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-bash.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-bash.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-bash.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-beancount.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-beancount.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-beancount.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-beancount.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-bufls.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-bufls.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-bufls.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-bufls.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-camel.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-camel.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-camel.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-camel.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-clangd.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-clangd.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-clangd.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-clangd.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-clojure.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-clojure.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-clojure.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-clojure.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cmake.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-cmake.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cmake.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-cmake.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cobol.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-cobol.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cobol.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-cobol.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-completion.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-completion.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-completion.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-completion.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-credo.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-credo.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-credo.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-credo.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-crystal.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-crystal.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-crystal.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-crystal.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-csharp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-csharp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-csharp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-csharp.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-css.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-css.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-css.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-css.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cucumber.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-cucumber.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cucumber.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-cucumber.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cypher.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-cypher.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-cypher.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-cypher.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-d.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-d.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-d.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-d.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dhall.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-dhall.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dhall.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-dhall.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-diagnostics.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-diagnostics.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-diagnostics.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-diagnostics.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dired.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-dired.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dired.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-dired.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dockerfile.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-dockerfile.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dockerfile.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-dockerfile.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dot.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-dot.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-dot.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-dot.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-earthly.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-earthly.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-earthly.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-earthly.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-elixir.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-elixir.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-elixir.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-elixir.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-elm.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-elm.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-elm.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-elm.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-emmet.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-emmet.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-emmet.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-emmet.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-erlang.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-erlang.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-erlang.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-erlang.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-eslint.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-eslint.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-eslint.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-eslint.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-fortran.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-fortran.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-fortran.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-fortran.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-fsharp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-fsharp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-fsharp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-fsharp.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-gdscript.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-gdscript.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-gdscript.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-gdscript.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-gleam.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-gleam.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-gleam.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-gleam.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-glsl.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-glsl.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-glsl.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-glsl.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-go.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-go.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-go.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-go.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-golangci-lint.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-golangci-lint.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-golangci-lint.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-golangci-lint.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-graphql.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-graphql.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-graphql.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-graphql.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-groovy.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-groovy.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-groovy.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-groovy.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-hack.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-hack.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-hack.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-hack.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-haxe.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-haxe.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-haxe.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-haxe.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-headerline.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-headerline.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-headerline.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-headerline.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-html.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-html.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-html.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-html.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-hy.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-hy.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-hy.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-hy.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-icons.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-icons.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-icons.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-icons.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ido.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ido.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ido.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ido.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-idris.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-idris.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-idris.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-idris.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-iedit.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-iedit.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-iedit.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-iedit.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-javascript.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-javascript.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-javascript.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-javascript.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-jq.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-jq.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-jq.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-jq.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-json.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-json.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-json.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-json.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-jsonnet.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-jsonnet.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-jsonnet.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-jsonnet.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-kotlin.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-kotlin.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-kotlin.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-kotlin.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-lens.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-lens.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-lens.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-lens.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-lisp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-lisp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-lisp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-lisp.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-lua.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-lua.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-lua.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-lua.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-magik.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-magik.el @@ -0,0 +1,175 @@ +;;; lsp-magik.el --- Language server client for Magik -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Keronic + +;; Author: <robin.putters@keronic.com> +;; Keywords: lsp, magik + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for the Magik programming language +;; https://github.com/StevenLooman/magik-tools + +;;; Code: + +(require `lsp-mode) + +(defgroup lsp-magik nil + "LSP support for Magik." + :link '(url-link "https://github.com/StevenLooman/magik-tools") + :group 'lsp-mode + :tag "Lsp Magik" + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-magik-version "0.10.1" + "Version of LSP server." + :type `string + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-magik-download-url-lsp (format "https://github.com/StevenLooman/magik-tools/releases/download/%s/magik-language-server-%s.jar" lsp-magik-version lsp-magik-version) + "URL of LSP server to download." + :type `string + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0")) + +(lsp-dependency + 'magik-ls + `(:download :url lsp-magik-download-url-lsp + :store-path ,(f-join lsp-server-install-dir "magik-ls" (format "magik-language-server-%s.jar" lsp-magik-version)))) + +(defcustom lsp-magik-ls-path + (f-join lsp-server-install-dir (format "magik-ls/magik-language-server-%s.jar" lsp-magik-version)) + "Path of the language server." + :type 'string + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0")) + +(lsp-defcustom lsp-magik-java-home nil + "Path to Java Runtime, Java 17 minimum." + :type `string + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0") + :lsp-path "magik.javaHome") + +(lsp-defcustom lsp-magik-product-dirs [] + "Paths to (compiled, containing a libs/ directory) products." + :type `lsp-string-vector + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.productDirs") + +(lsp-defcustom lsp-magik-lint-override-config-file nil + "Override path to magiklintrc.properties." + :type 'string + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0") + :lsp-path "magik.lint.overrideConfigFile") + +(lsp-defcustom lsp-magik-typing-type-database-paths [] + "Paths to type databases." + :type `lsp-string-vector + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0") + :lsp-path "magik.typing.typeDatabasePaths") + +(lsp-defcustom lsp-magik-typing-show-typing-inlay-hints nil + "Show typing inlay hints." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.showTypingInlayHints") + +(lsp-defcustom lsp-magik-typing-show-argument-inlay-hints nil + "Show (certain) argument name inlay hints." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.showArgumentInlayHints") + +(lsp-defcustom lsp-magik-typing-enable-checks nil + "Enable typing checks." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.0") + :lsp-path "magik.typing.enableChecks") + +(lsp-defcustom lsp-magik-typing-index-global-usages t + "Enable indexing of usages of globals by methods." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.indexGlobalUsages") + +(lsp-defcustom lsp-magik-typing-index-method-usages nil + "Enable indexing of usages of methods by methods." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.indexMethodUsages") + +(lsp-defcustom lsp-magik-typing-index-slot-usages t + "Enable indexing of usages of slots by methods." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.indexSlotUsages") + +(lsp-defcustom lsp-magik-typing-index-condition-usages t + "Enable indexing of usages of conditions by methods." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.indexConditionUsages") + +(lsp-defcustom lsp-magik-typing-cache-indexed-definitions-method-usages t + "Store and load the indexed definitions in the workspace folders." + :type `boolean + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1") + :lsp-path "magik.typing.cacheIndexedDefinitions") + +(defcustom lsp-magik-java-path (lambda () + (cond ((eq system-type 'windows-nt) + (or (lsp-resolve-value (executable-find (expand-file-name "bin/java" (getenv "JAVA_HOME")))) + (lsp-resolve-value (executable-find "java")))) + (t "java"))) + "Path to Java Runtime, Java 11 minimum." + :type 'string + :group `lsp-magik + :package-version '(lsp-mode . "9.0.1")) + +(lsp-register-client + (make-lsp-client + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'magik-ls callback error-callback)) + :new-connection (lsp-stdio-connection + (lambda () + (list + (substitute-in-file-name (lsp-resolve-value lsp-magik-java-path)) + "-jar" + (substitute-in-file-name lsp-magik-ls-path) + "--debug"))) + :activation-fn (lsp-activate-on "magik") + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "magik")))) + :server-id 'magik)) + +(lsp-consistency-check lsp-magik) + +(provide 'lsp-magik) +;;; lsp-magik.el ends here diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-magik.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-magik.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-markdown.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-markdown.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-markdown.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-markdown.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-marksman.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-marksman.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-marksman.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-marksman.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mdx.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-mdx.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mdx.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-mdx.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-meson.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-meson.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-meson.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-meson.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mint.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-mint.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mint.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-mint.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mode-autoloads.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-mode-autoloads.el diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-mode-pkg.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-mode-pkg.el @@ -0,0 +1,15 @@ +(define-package "lsp-mode" "20240817.1400" "LSP mode" + '((emacs "27.1") + (dash "2.18.0") + (f "0.20.0") + (ht "2.3") + (spinner "1.7.3") + (markdown-mode "2.3") + (lv "0") + (eldoc "1.11")) + :commit "12befaabe4a1bf8a548bc820faa192be8ee89533" :keywords + '("languages") + :url "https://github.com/emacs-lsp/lsp-mode") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mode.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-mode.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mode.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-mode.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-modeline.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-modeline.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-modeline.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-modeline.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mojo.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-mojo.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-mojo.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-mojo.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-move.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-move.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-move.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-move.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nginx.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-nginx.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nginx.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-nginx.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nim.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-nim.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nim.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-nim.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nix.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-nix.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nix.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-nix.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nushell.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-nushell.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-nushell.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-nushell.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ocaml.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ocaml.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ocaml.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ocaml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-openscad.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-openscad.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-openscad.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-openscad.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-perl.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-perl.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-perl.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-perl.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-perlnavigator.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-perlnavigator.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-perlnavigator.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-perlnavigator.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-php.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-php.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-php.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-php.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pls.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-pls.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pls.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-pls.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-prolog.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-prolog.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-prolog.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-prolog.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-protocol.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-protocol.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-protocol.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-protocol.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-purescript.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-purescript.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-purescript.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-purescript.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pwsh.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-pwsh.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pwsh.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-pwsh.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pyls.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-pyls.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pyls.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-pyls.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pylsp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-pylsp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-pylsp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-pylsp.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-qml.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-qml.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-qml.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-qml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-r.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-r.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-r.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-r.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-racket.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-racket.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-racket.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-racket.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-remark.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-remark.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-remark.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-remark.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rf.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-rf.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rf.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-rf.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-roslyn.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-roslyn.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-roslyn.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-roslyn.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rpm-spec.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-rpm-spec.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rpm-spec.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-rpm-spec.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rubocop.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-rubocop.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-rubocop.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-rubocop.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ruby-lsp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-lsp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ruby-lsp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-lsp.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ruby-syntax-tree.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-syntax-tree.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ruby-syntax-tree.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ruby-syntax-tree.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ruff-lsp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ruff-lsp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ruff-lsp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ruff-lsp.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-rust.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-rust.el @@ -0,0 +1,1791 @@ +;;; lsp-rust.el --- Rust Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-rust client + +;;; Code: + +(require 'lsp-mode) +(require 'ht) +(require 'dash) +(require 'lsp-semantic-tokens) +(require 's) + +(defgroup lsp-rust nil + "LSP support for Rust, using Rust Language Server or rust-analyzer." + :group 'lsp-mode + :link '(url-link "https://github.com/rust-lang/rls") + :package-version '(lsp-mode . "6.1")) + +(defgroup lsp-rust-rls nil + "LSP support for Rust, using Rust Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/rust-lang/rls") + :package-version '(lsp-mode . "8.0.0")) + +(defgroup lsp-rust-analyzer nil + "LSP support for Rust, using rust-analyzer." + :group 'lsp-mode + :link '(url-link "https://github.com/rust-lang/rust-analyzer") + :package-version '(lsp-mode . "8.0.0")) + +(defgroup lsp-rust-analyzer-semantic-tokens nil + "LSP semantic tokens support for rust-analyzer." + :group 'lsp-rust-analyzer + :link '(url-link "https://github.com/rust-lang/rust-analyzer") + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-server 'rust-analyzer + "Choose LSP server." + :type '(choice (const :tag "rls" rls) + (const :tag "rust-analyzer" rust-analyzer)) + :group 'lsp-rust + :package-version '(lsp-mode . "6.2")) + +;; RLS + +(defcustom lsp-rust-rls-server-command '("rls") + "Command to start RLS." + :type '(repeat string) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-library-directories + '("~/.cargo/registry/src" "~/.rustup/toolchains") + "List of directories which will be considered to be libraries." + :risky t + :type '(repeat string) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-sysroot nil + "If non-nil, use the given path as the sysroot for all rustc invocations +instead of trying to detect the sysroot automatically." + :type '(choice + (const :tag "None" nil) + (string :tag "Sysroot")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-target nil + "If non-nil, use the given target triple for all rustc invocations." + :type '(choice + (const :tag "None" nil) + (string :tag "Target")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-rustflags nil + "Flags added to RUSTFLAGS." + :type '(choice + (const :tag "None" nil) + (string :tag "Flags")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-clear-env-rust-log t + "Clear the RUST_LOG environment variable before running rustc or cargo." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-lib nil + "If non-nil, checks the project as if you passed the `--lib' argument to +cargo. + +Mutually exclusive with, and preferred over, `lsp-rust-build-bin'. (Unstable)" + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-bin nil + "If non-nil, checks the project as if you passed `-- bin <build_bin>' +argument to cargo. + +Mutually exclusive with `lsp-rust-build-lib'. (Unstable)" + :type '(choice + (const :tag "None" nil) + (string :tag "Binary")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-cfg-test nil + "If non-nil, checks the project as if you were running `cargo test' rather +than cargo build. + +I.e., compiles (but does not run) test code." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-unstable-features nil + "Enable unstable features." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-wait-to-build nil + "Time in milliseconds between receiving a change notification +and starting build. If not specified, automatically inferred by +the latest build duration." + :type '(choice + (const :tag "Auto" nil) + (number :tag "Time")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-show-warnings t + "Show warnings." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-crate-blocklist [ + "cocoa" + "gleam" + "glium" + "idna" + "libc" + "openssl" + "rustc_serialize" + "serde" + "serde_json" + "typenum" + "unicode_normalization" + "unicode_segmentation" + "winapi" + ] + "A list of Cargo crates to blocklist." + :type 'lsp-string-vector + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-on-save nil + "Only index the project when a file is saved and not on change." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-features [] + "List of features to activate. +Set this to `\"all\"` to pass `--all-features` to cargo." + :type 'lsp-string-vector + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-all-features nil + "Enable all Cargo features." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-no-default-features nil + "Do not enable default Cargo features." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-racer-completion t + "Enables code completion using racer." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-clippy-preference "opt-in" + "Controls eagerness of clippy diagnostics when available. +Valid values are (case-insensitive): + - \"off\": Disable clippy lints. + - \"opt-in\": Clippy lints are shown when crates specify `#![warn(clippy)]'. + - \"on\": Clippy lints enabled for all crates in workspace. + +You need to install clippy via rustup if you haven't already." + :type '(choice + (const "on") + (const "opt-in") + (const "off")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-jobs nil + "Number of Cargo jobs to be run in parallel." + :type '(choice + (const :tag "Auto" nil) + (number :tag "Jobs")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-all-targets t + "Checks the project as if you were running cargo check --all-targets. +I.e., check all targets and integration tests too." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-target-dir nil + "When specified, it places the generated analysis files at the +specified target directory. By default it is placed target/rls +directory." + :type '(choice + (const :tag "Default" nil) + (string :tag "Directory")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-rustfmt-path nil + "When specified, RLS will use the Rustfmt pointed at the path +instead of the bundled one" + :type '(choice + (const :tag "Bundled" nil) + (string :tag "Path")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-command nil + "EXPERIMENTAL (requires `rust.unstable_features') +If set, executes a given program responsible for rebuilding save-analysis to be +loaded by the RLS. The program given should output a list of resulting .json +files on stdout. + +Implies `rust.build_on_save': true." + :type '(choice + (const :tag "None" nil) + (string :tag "Command")) + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-full-docs nil + "Instructs cargo to enable full documentation extraction during +save-analysis while building the crate." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-show-hover-context t + "Show additional context in hover tooltips when available. This +is often the type local variable declaration." + :type 'boolean + :group 'lsp-rust-rls + :package-version '(lsp-mode . "6.1")) + +(lsp-register-custom-settings + '(("rust.show_hover_context" lsp-rust-show-hover-context t) + ("rust.full_docs" lsp-rust-full-docs t) + ("rust.build_command" lsp-rust-build-command) + ("rust.rustfmt_path" lsp-rust-rustfmt-path) + ("rust.target_dir" lsp-rust-target-dir) + ("rust.all_targets" lsp-rust-all-targets t) + ("rust.jobs" lsp-rust-jobs) + ("rust.clippy_preference" lsp-rust-clippy-preference) + ("rust.racer_completion" lsp-rust-racer-completion t) + ("rust.no_default_features" lsp-rust-no-default-features t) + ("rust.all_features" lsp-rust-all-features t) + ("rust.features" lsp-rust-features) + ("rust.build_on_save" lsp-rust-build-on-save t) + ("rust.crate_blocklist" lsp-rust-crate-blocklist) + ("rust.show_warnings" lsp-rust-show-warnings t) + ("rust.wait_to_build" lsp-rust-wait-to-build) + ("rust.unstable_features" lsp-rust-unstable-features t) + ("rust.cfg_test" lsp-rust-cfg-test t) + ("rust.build_bin" lsp-rust-build-bin) + ("rust.build_lib" lsp-rust-build-lib t) + ("rust.clear_env_rust_log" lsp-rust-clear-env-rust-log t) + ("rust.rustflags" lsp-rust-rustflags) + ("rust.target" lsp-rust-target) + ("rust.sysroot" lsp-rust-sysroot))) + +(defun lsp-clients--rust-window-progress (workspace params) + "Progress report handling. +PARAMS progress report notification data." + (-let [(&v1:ProgressParams :done? :message? :title) params] + (if (or done? (s-blank-str? message?)) + (lsp-workspace-status nil workspace) + (lsp-workspace-status (format "%s - %s" title (or message? "")) workspace)))) + +(lsp-defun lsp-rust--rls-run ((&Command :arguments? params)) + (-let* (((&rls:Cmd :env :binary :args :cwd) (lsp-seq-first params)) + (default-directory (or cwd (lsp-workspace-root) default-directory) )) + (compile + (format "%s %s %s" + (s-join " " (ht-amap (format "%s=%s" key value) env)) + binary + (s-join " " args))))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-rust-rls-server-command)) + :activation-fn (lsp-activate-on "rust") + :priority (if (eq lsp-rust-server 'rls) 1 -1) + :initialization-options '((omitInitBuild . t) + (cmdRun . t)) + :notification-handlers (ht ("window/progress" 'lsp-clients--rust-window-progress)) + :action-handlers (ht ("rls.run" 'lsp-rust--rls-run)) + :library-folders-fn (lambda (_workspace) lsp-rust-library-directories) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "rust")))) + :server-id 'rls)) + + +;; rust-analyzer +(defcustom lsp-rust-analyzer-server-command '("rust-analyzer") + "Command to start rust-analyzer." + :type '(repeat string) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-rust-analyzer-library-directories + '("~/.cargo/registry/src" "~/.rustup/toolchains") + "List of directories which will be considered to be libraries." + :risky t + :type '(repeat string) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-server-format-inlay-hints t + "Whether to ask rust-analyzer to format inlay hints itself. If +active, the various inlay format settings are not used." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-hide-closure-initialization nil + "Whether to hide inlay type hints for `let` statements that initialize +to a closure. Only applies to closures with blocks, same as +`#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-highlight-breakpoints t + "Enables highlighting of related references while the cursor is on +`break`, `loop`, `while`, or `for` keywords." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-highlight-closure-captures t + "Enables highlighting of all captures of a closure while the +cursor is on the `|` or move keyword of a closure." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-highlight-exit-points t + "Enables highlighting of all exit points while the cursor is on +any `return`, `?`, `fn`, or return type arrow (`->`)." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-highlight-references t + "Enables highlighting of related references while the cursor is on +any identifier." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-highlight-yield-points t + "Enables highlighting of all break points for a loop or block +context while the cursor is on any `async` or `await` keywords." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-closure-return-type-hints "never" + "Whether to show inlay type hints for return types of closures." + :type '(choice + (const "never") + (const "always") + (const "with_block")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-discriminants-hints "never" + "Whether to show enum variant discriminant hints." + :type '(choice + (const "never") + (const "always") + (const "fieldless")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-expression-adjustment-hints "never" + "Whether to show inlay hints for type adjustments.." + :type '(choice + (const "never") + (const "always") + (const "reborrow")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-expression-adjustment-hints-mode "prefix" + "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc)." + :type '(choice + (const "prefix") + (const "postfix") + (const "prefer_prefix") + (const "prefer_postfix")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-expression-adjustment-hide-unsafe nil + "Whether to hide inlay hints for type adjustments outside of +`unsafe` blocks." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-implicit-drops nil + "Whether to show implicit drop hints." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + + +(defcustom lsp-rust-analyzer-closure-capture-hints nil + "Whether to show inlay hints for closure captures." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-closure-style "impl_fn" + "Closure notation in type and chaining inlay hints." + :type 'string + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-hide-named-constructor nil + "Whether to hide inlay type hints for constructors." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-max-inlay-hint-length nil + "Max inlay hint length." + :type 'integer + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-display-chaining-hints nil + "Whether to show inlay type hints for method chains. These +hints will be formatted with the type hint formatting options, if +the mode is not configured to ask the server to format them." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-display-lifetime-elision-hints-enable "never" + "Whether to show elided lifetime inlay hints." + :type '(choice + (const "never") + (const "always") + (const "skip_trivial")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names nil + "When showing elided lifetime inlay hints, whether to use +parameter names or numeric placeholder names for the lifetimes." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-display-closure-return-type-hints nil + "Whether to show closure return type inlay hints for closures +with block bodies." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-display-parameter-hints nil + "Whether to show function parameter name inlay hints at the call site." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-display-reborrow-hints "never" + "Whether to show inlay type hints for compiler inserted reborrows." + :type '(choice + (const "always") + (const "never") + (const "mutable")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-binding-mode-hints nil + "Whether to show inlay type hints for binding modes." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-closing-brace-hints t + "Whether to show inlay hints after a closing `}` to indicate what item it +belongs to." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-closing-brace-hints-min-lines 25 + "Minimum number of lines required before the `}` until the hint is shown +\(set to 0 or 1 to always show them)." + :type 'integer + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lru-capacity nil + "Number of syntax trees rust-analyzer keeps in memory." + :type 'integer + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-target nil + "Compilation target (target triple)." + :type '(choice + (string :tag "Target") + (const :tag "None" nil)) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-cargo-watch-enable t + "Enable Cargo watch." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-watch-command "check" + "Cargo watch command." + :type 'string + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-watch-args [] + "Extra arguments for `cargo check`." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-override-command [] + "Advanced option, fully override the command rust-analyzer uses for checking. +The command should include `--message=format=json` or similar option." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-check-all-targets t + "Enables --all-targets for `cargo check`." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.2")) + +(defcustom lsp-rust-analyzer-checkonsave-features [] + "List of features to activate. +Set this to `\"all\"` to pass `--all-features` to cargo." + :type 'lsp-string-vector + :group 'lsp-rust-rust-analyzer + :package-version '(lsp-mode . "8.0.2")) + +(defcustom lsp-rust-analyzer-cargo-unset-test [] + "force rust-analyzer to unset `#[cfg(test)]` for the specified crates." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-use-client-watching t + "Use client watching" + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-exclude-globs [] + "Exclude globs" + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-exclude-dirs [] + "These directories will be ignored by rust-analyzer." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-macro-expansion-method 'lsp-rust-analyzer-macro-expansion-default + "Use a different function if you want formatted macro expansion results and +syntax highlighting." + :type 'function + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-diagnostics-enable t + "Whether to show native rust-analyzer diagnostics." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-diagnostics-enable-experimental nil + "Whether to show native rust-analyzer diagnostics that are still experimental +\(might have more false positives than usual)." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-diagnostics-disabled [] + "List of native rust-analyzer diagnostics to disable." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-diagnostics-warnings-as-hint [] + "List of warnings that should be displayed with hint severity." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-diagnostics-warnings-as-info [] + "List of warnings that should be displayed with info severity." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(define-obsolete-variable-alias + 'lsp-rust-analyzer-cargo-load-out-dirs-from-check + 'lsp-rust-analyzer-cargo-run-build-scripts + "8.0.0") + +(defcustom lsp-rust-analyzer-cargo-run-build-scripts t + "Whether to run build scripts (`build.rs`) for more precise code analysis." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-rustfmt-extra-args [] + "Additional arguments to rustfmt." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-rustfmt-override-command [] + "Advanced option, fully override the command rust-analyzer uses +for formatting." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-rustfmt-rangeformatting-enable nil + "Enables the use of rustfmt's unstable range formatting command for the +`textDocument/rangeFormatting` request. The rustfmt option is unstable and only +available on a nightly build." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-completion-add-call-parenthesis t + "Whether to add parenthesis when completing functions." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-completion-add-call-argument-snippets t + "Whether to add argument snippets when completing functions." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-completion-postfix-enable t + "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-call-info-full t + "Whether to show function name and docs in parameter hints." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-proc-macro-enable t + "Enable Proc macro support. +Implies `lsp-rust-analyzer-cargo-run-build-scripts'" + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-import-prefix "plain" + "The path structure for newly inserted paths to use. +Valid values are: + - \"plain\": Insert import paths relative to the current module, using up to +one `super' prefix if the parent module contains the requested item. + - \"by_self\": Prefix all import paths with `self' if they don't begin with +`self', `super', `crate' or a crate name. + - \"by_crate\": Force import paths to be absolute by always starting +them with `crate' or the crate name they refer to." + :type '(choice + (const "plain") + (const "by_self") + (const "by_crate")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-import-granularity "crate" + "How imports should be grouped into use statements." + :type '(choice + (const "crate" :doc "Merge imports from the same crate into a single use statement. This kind of nesting is only supported in Rust versions later than 1.24.") + (const "module" :doc "Merge imports from the same module into a single use statement.") + (const "item" :doc "Don’t merge imports at all, creating one import per item.") + (const "preserve" :doc "Do not change the granularity of any imports. For auto-import this has the same effect as `\"item\"'")) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-cargo-auto-reload t + "Automatically refresh project info via `cargo metadata' on `Cargo.toml' changes." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts t + "Use `RUSTC_WRAPPER=rust-analyzer' when running build scripts to avoid +compiling unnecessary things." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-completion-auto-import-enable t + "Toggles the additional completions that automatically add imports when +completed. `lsp-completion-enable-additional-text-edit' must be non-nil + for this feature to be fully enabled." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-completion-auto-self-enable t + "Toggles the additional completions that automatically show method calls +and field accesses with self prefixed to them when inside a method." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-import-enforce-granularity nil + "Whether to enforce the import granularity setting for all files. + If set to nil rust-analyzer will try to keep import styles consistent per file." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-imports-merge-glob t + "Whether to allow import insertion to merge new imports into single path +glob imports like `use std::fmt::*;`." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-import-group t + "Group inserted imports by the following order: +https://rust-analyzer.github.io/manual.html#auto-import. + Groups are separated by newlines." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-highlighting-strings t + "Use semantic tokens for strings." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-rustc-source nil + "Path to the Cargo.toml of the rust compiler workspace." + :type '(choice + (file :tag "Path") + (const :tag "None" nil)) + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-linked-projects [] + "Disable project auto-discovery in favor of explicitly specified set of +projects. Elements must be paths pointing to `Cargo.toml`, `rust-project.json`, +or JSON objects in `rust-project.json` format." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-experimental-proc-attr-macros t + "Whether to enable experimental support for expanding proc macro attributes." + :type 'boolean + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-cargo-extra-args [] + "Extra arguments that are passed to every cargo invocation." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-cargo-extra-env [] + "Extra environment variables that will be set when running cargo, rustc or +other commands within the workspace. Useful for setting RUSTFLAGS." + :type 'lsp-string-vector + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "9.0.0")) + +(defconst lsp-rust-notification-handlers + '(("rust-analyzer/publishDecorations" . (lambda (_w _p))))) + +(defconst lsp-rust-action-handlers + '()) + +(define-derived-mode lsp-rust-analyzer-syntax-tree-mode special-mode "Rust-Analyzer-Syntax-Tree" + "Mode for the rust-analyzer syntax tree buffer.") + +(defun lsp-rust-analyzer-syntax-tree () + "Display syntax tree for current buffer." + (interactive) + (-let* ((root (lsp-workspace-root default-directory)) + (params (lsp-make-rust-analyzer-syntax-tree-params + :text-document (lsp--text-document-identifier) + :range? (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point-min) (point-max))))) + (results (lsp-send-request (lsp-make-request + "rust-analyzer/syntaxTree" + params)))) + (let ((buf (get-buffer-create (format "*rust-analyzer syntax tree %s*" root))) + (inhibit-read-only t)) + (with-current-buffer buf + (lsp-rust-analyzer-syntax-tree-mode) + (erase-buffer) + (insert results) + (goto-char (point-min))) + (pop-to-buffer buf)))) + +(define-derived-mode lsp-rust-analyzer-status-mode special-mode "Rust-Analyzer-Status" + "Mode for the rust-analyzer status buffer.") + +(defun lsp-rust-analyzer-status () + "Displays status information for rust-analyzer." + (interactive) + (-let* ((root (lsp-workspace-root default-directory)) + (params (lsp-make-rust-analyzer-analyzer-status-params + :text-document (lsp--text-document-identifier))) + (results (lsp-send-request (lsp-make-request + "rust-analyzer/analyzerStatus" + params)))) + (let ((buf (get-buffer-create (format "*rust-analyzer status %s*" root))) + (inhibit-read-only t)) + (with-current-buffer buf + (lsp-rust-analyzer-status-mode) + (erase-buffer) + (insert results) + (pop-to-buffer buf))))) + +(defun lsp-rust-analyzer-view-item-tree () + "Show item tree of rust file." + (interactive) + (-let* ((params (lsp-make-rust-analyzer-view-item-tree + :text-document (lsp--text-document-identifier))) + (results (lsp-send-request (lsp-make-request + "rust-analyzer/viewItemTree" + params)))) + (let ((buf (get-buffer-create "*rust-analyzer item tree*")) + (inhibit-read-only t)) + (with-current-buffer buf + (special-mode) + (erase-buffer) + (insert (lsp--render-string results "rust")) + (pop-to-buffer buf))))) + +(defun lsp-rust-analyzer-view-hir () + "View Hir of function at point." + (interactive) + (-let* ((params (lsp-make-rust-analyzer-expand-macro-params + :text-document (lsp--text-document-identifier) + :position (lsp--cur-position))) + (results (lsp-send-request (lsp-make-request + "rust-analyzer/viewHir" + params)))) + (let ((buf (get-buffer-create "*rust-analyzer hir*")) + (inhibit-read-only t)) + (with-current-buffer buf + (special-mode) + (erase-buffer) + (insert results) + (pop-to-buffer buf))))) + +(defun lsp-rust-analyzer-join-lines () + "Join selected lines into one, smartly fixing up whitespace and trailing commas." + (interactive) + (let* ((params (lsp-make-rust-analyzer-join-lines-params + :text-document (lsp--text-document-identifier) + :ranges (vector (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point) (point)))))) + (result (lsp-send-request (lsp-make-request "experimental/joinLines" params)))) + (lsp--apply-text-edits result 'code-action))) + +(defun lsp-rust-analyzer-reload-workspace () + "Reload workspace, picking up changes from Cargo.toml" + (interactive) + (lsp--cur-workspace-check) + (lsp-send-request (lsp-make-request "rust-analyzer/reloadWorkspace"))) + +(defcustom lsp-rust-analyzer-download-url + (let* ((x86 (string-prefix-p "x86_64" system-configuration)) + (arch (if x86 "x86_64" "aarch64"))) + (format "https://github.com/rust-lang/rust-analyzer/releases/latest/download/%s" + (pcase system-type + ('gnu/linux (format "rust-analyzer-%s-unknown-linux-gnu.gz" arch)) + ('darwin (format "rust-analyzer-%s-apple-darwin.gz" arch)) + ('windows-nt (format "rust-analyzer-%s-pc-windows-msvc.zip" arch))))) + "Automatic download url for Rust Analyzer" + :type 'string + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(defcustom lsp-rust-analyzer-store-path (f-join lsp-server-install-dir "rust" + (pcase system-type + ('windows-nt "rust-analyzer.exe") + (_ "rust-analyzer"))) + "The path to the file in which `rust-analyzer' will be stored." + :type 'file + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +(lsp-dependency + 'rust-analyzer + `(:download :url lsp-rust-analyzer-download-url + :decompress ,(pcase system-type ('windows-nt :zip) (_ :gzip)) + :store-path lsp-rust-analyzer-store-path + :set-executable? t) + `(:system ,(file-name-nondirectory lsp-rust-analyzer-store-path))) + +(lsp-defun lsp-rust--analyzer-run-single ((&Command :arguments?)) + (lsp-rust-analyzer-run (lsp-seq-first arguments?))) + +(lsp-defun lsp-rust--analyzer-show-references + ((&Command :title :arguments? [_uri _filepos references])) + (lsp-show-xrefs (lsp--locations-to-xref-items references) nil + (s-contains-p "reference" title))) + +(declare-function dap-debug "ext:dap-mode" (template) t) + +(lsp-defun lsp-rust--analyzer-debug-lens ((&Command :arguments? [args])) + (lsp-rust-analyzer-debug args)) + +;; Semantic tokens + +;; Modifier faces +(defface lsp-rust-analyzer-documentation-modifier-face + '((t nil)) + "The face modification to use for documentation items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-declaration-modifier-face + '((t nil)) + "The face modification to use for declaration items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-definition-modifier-face + '((t nil)) + "The face modification to use for definition items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-static-modifier-face + '((t nil)) + "The face modification to use for static items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-abstract-modifier-face + '((t nil)) + "The face modification to use for abstract items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-deprecated-modifier-face + '((t nil)) + "The face modification to use for deprecated items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-readonly-modifier-face + '((t nil)) + "The face modification to use for readonly items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-default-library-modifier-face + '((t nil)) + "The face modification to use for default-library items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-async-modifier-face + '((t nil)) + "The face modification to use for async items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-attribute-modifier-face + '((t nil)) + "The face modification to use for attribute items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-callable-modifier-face + '((t nil)) + "The face modification to use for callable items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-constant-modifier-face + '((t nil)) + "The face modification to use for constant items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-consuming-modifier-face + '((t nil)) + "The face modification to use for consuming items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-control-flow-modifier-face + '((t nil)) + "The face modification to use for control-flow items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-crate-root-modifier-face + '((t nil)) + "The face modification to use for crate-root items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-injected-modifier-face + '((t nil)) + "The face modification to use for injected items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-intra-doc-link-modifier-face + '((t nil)) + "The face modification to use for intra-doc-link items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-library-modifier-face + '((t nil)) + "The face modification to use for library items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-mutable-modifier-face + '((t :underline t)) + "The face modification to use for mutable items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-public-modifier-face + '((t nil)) + "The face modification to use for public items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-reference-modifier-face + '((t :bold t)) + "The face modification to use for reference items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-trait-modifier-face + '((t nil)) + "The face modification to use for trait items." + :group 'lsp-rust-analyzer-semantic-tokens) + +(defface lsp-rust-analyzer-unsafe-modifier-face + '((t nil)) + "The face modification to use for unsafe items." + :group 'lsp-rust-analyzer-semantic-tokens) + + +;; --------------------------------------------------------------------- +;; Semantic token modifier face customization + +(defcustom lsp-rust-analyzer-documentation-modifier 'lsp-rust-analyzer-documentation-modifier-face + "Face for semantic token modifier for `documentation' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-declaration-modifier 'lsp-rust-analyzer-declaration-modifier-face + "Face for semantic token modifier for `declaration' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-definition-modifier 'lsp-rust-analyzer-definition-modifier-face + "Face for semantic token modifier for `definition' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-static-modifier 'lsp-rust-analyzer-static-modifier-face + "Face for semantic token modifier for `static' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-abstract-modifier 'lsp-rust-analyzer-abstract-modifier-face + "Face for semantic token modifier for `abstract' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-deprecated-modifier 'lsp-rust-analyzer-deprecated-modifier-face + "Face for semantic token modifier for `deprecated' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-readonly-modifier 'lsp-rust-analyzer-readonly-modifier-face + "Face for semantic token modifier for `readonly' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-default-library-modifier 'lsp-rust-analyzer-default-library-modifier-face + "Face for semantic token modifier for `default' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-async-modifier 'lsp-rust-analyzer-async-modifier-face + "Face for semantic token modifier for `async' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-attribute-modifier 'lsp-rust-analyzer-attribute-modifier-face + "Face for semantic token modifier for `attribute' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-callable-modifier 'lsp-rust-analyzer-callable-modifier-face + "Face for semantic token modifier for `callable' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-constant-modifier 'lsp-rust-analyzer-constant-modifier-face + "Face for semantic token modifier for `constant' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-consuming-modifier 'lsp-rust-analyzer-consuming-modifier-face + "Face for semantic token modifier for `consuming' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-control-flow-modifier 'lsp-rust-analyzer-control-flow-modifier-face + "Face for semantic token modifier for `control_flow' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-crate-root-modifier 'lsp-rust-analyzer-crate-root-modifier-face + "Face for semantic token modifier for `crate_root' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-injected-modifier 'lsp-rust-analyzer-injected-modifier-face + "Face for semantic token modifier for `injected' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-intra-doc-link-modifier 'lsp-rust-analyzer-intra-doc-link-modifier-face + "Face for semantic token modifier for `intra_doc_link' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-library-modifier 'lsp-rust-analyzer-library-modifier-face + "Face for semantic token modifier for `library' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-mutable-modifier 'lsp-rust-analyzer-mutable-modifier-face + "Face for semantic token modifier for `mutable' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-public-modifier 'lsp-rust-analyzer-public-modifier-face + "Face for semantic token modifier for `public' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-reference-modifier 'lsp-rust-analyzer-reference-modifier-face + "Face for semantic token modifier for `reference' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-trait-modifier 'lsp-rust-analyzer-trait-modifier-face + "Face for semantic token modifier for `trait' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-unsafe-modifier 'lsp-rust-analyzer-unsafe-modifier-face + "Face for semantic token modifier for `unsafe' attribute." + :type 'face + :group 'lsp-rust-analyzer-semantic-tokens + :package-version '(lsp-mode . "9.0.0")) + +;; --------------------------------------------------------------------- + +(defun lsp-rust-analyzer--semantic-modifiers () + "Mapping between rust-analyzer keywords and fonts to apply. +The keywords are sent in the initialize response, in the semantic +tokens legend." + `(("documentation" . ,lsp-rust-analyzer-documentation-modifier) + ("declaration" . ,lsp-rust-analyzer-declaration-modifier) + ("definition" . ,lsp-rust-analyzer-definition-modifier) + ("static" . ,lsp-rust-analyzer-static-modifier) + ("abstract" . ,lsp-rust-analyzer-abstract-modifier) + ("deprecated" . ,lsp-rust-analyzer-deprecated-modifier) + ("readonly" . ,lsp-rust-analyzer-readonly-modifier) + ("default_library" . ,lsp-rust-analyzer-default-library-modifier) + ("async" . ,lsp-rust-analyzer-async-modifier) + ("attribute" . ,lsp-rust-analyzer-attribute-modifier) + ("callable" . ,lsp-rust-analyzer-callable-modifier) + ("constant" . ,lsp-rust-analyzer-constant-modifier) + ("consuming" . ,lsp-rust-analyzer-consuming-modifier) + ("control_flow" . ,lsp-rust-analyzer-control-flow-modifier) + ("crate_root" . ,lsp-rust-analyzer-crate-root-modifier) + ("injected" . ,lsp-rust-analyzer-injected-modifier) + ("intra_doc_link" . ,lsp-rust-analyzer-intra-doc-link-modifier) + ("library" . ,lsp-rust-analyzer-library-modifier) + ("mutable" . ,lsp-rust-analyzer-mutable-modifier) + ("public" . ,lsp-rust-analyzer-public-modifier) + ("reference" . ,lsp-rust-analyzer-reference-modifier) + ("trait" . ,lsp-rust-analyzer-trait-modifier) + ("unsafe" . ,lsp-rust-analyzer-unsafe-modifier))) + +(defun lsp-rust-switch-server (&optional lsp-server) + "Switch priorities of lsp servers, unless LSP-SERVER is already active." + (interactive) + (let ((current-server (if (> (lsp--client-priority (gethash 'rls lsp-clients)) 0) + 'rls + 'rust-analyzer))) + (unless (eq lsp-server current-server) + (dolist (server '(rls rust-analyzer)) + (when (natnump (setf (lsp--client-priority (gethash server lsp-clients)) + (* (lsp--client-priority (gethash server lsp-clients)) -1))) + (message (format "Switched to server %s." server))))))) + +;; +;;; Inlay hints + +(defcustom lsp-rust-analyzer-debug-lens-extra-dap-args + '(:MIMode "gdb" :miDebuggerPath "gdb" :stopAtEntry t :externalConsole :json-false) + "Extra arguments to pass to DAP template when debugging a test from code lens. + +As a rule of the thumb, do not add extra keys to this plist unless you exactly +what you are doing, it might break the \"Debug test\" lens otherwise. + +See dap-mode documentation and cpptools documentation for the extra variables +meaning." + :type 'plist + :group 'lsp-rust-analyzer + :package-version '(lsp-mode . "8.0.0")) + +;; +;;; Lenses + +(defgroup lsp-rust-analyzer-lens nil + "LSP lens support for Rust when using rust-analyzer. + +Lenses are (depending on your configuration) clickable links to +the right of function definitions and the like. These display +some useful information in their own right and/or perform a +shortcut action when clicked such as displaying uses of that +function or running an individual test. +" + :prefix "lsp-rust-analyzer-lens-" + :group 'lsp-rust-analyzer + :link '(url-link "https://emacs-lsp.github.io/lsp-mode/") + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-debug-enable t + "Enable or disable the Debug lens." + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-enable t + "Master-enable of lenses in Rust files." + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +;; This customisation "works" in that it works as described, but the default is fine and changing it +;; from the default will either stop lenses working or do nothing. +;; +;; If this is ever uncommented to re-enable the option, don't forget to also uncomment it in defun +;; lsp-rust-analyzer--make-init-options too or it'll not do anything. + +;; (defcustom lsp-rust-analyzer-lens-force-custom-commands t +;; "Internal config: use custom client-side commands even when the +;; client doesn't set the corresponding capability." +;; :type 'boolean +;; :group 'lsp-rust-analyzer-lens +;; :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-implementations-enable t + "Enable or disable the Implementations lens. + +The Implementations lens shows `NN implementations' to the right +of the first line of an enum, struct, or union declaration. This +is the count of impl blocks, including derived traits. Clicking +on it gives a list of the impls of that type. +" + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +;; The valid range of values for this is documented in the rust-lang/rust-analyzer repository at the +;; path "editors/code/package.json"; the TL:DR is that it's "above_name" or "above_whole_item". +;; However, setting it to "above_whole_item" causes lenses to disappear in Emacs. I suspect this +;; feature has only ever been tested in some other IDE and it's broken in Emacs. So I've disabled it +;; for now. +;; +;; If this is ever uncommented to re-enable the option, don't forget to also uncomment it in defun +;; lsp-rust-analyzer--make-init-options too or it'll not do anything. + +;; (defcustom lsp-rust-analyzer-lens-location "above_name" +;; "Where to render annotations." +;; :type '(choice +;; (const :tag "Above name" "above_name") +;; (const :tag "Above whole item" "above_whole_item") +;; :group 'lsp-rust-analyzer-lens +;; :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-references-adt-enable nil + "Enable or disable the References lens on enums, structs, and traits. + +The References lens shows `NN references` to the right of the +first line of each enum, struct, or union declaration. This is +the count of uses of that type. Clicking on it gives a list of +where that type is used." + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-references-enum-variant-enable nil + "Enable or disable the References lens on enum variants. + +The References lens shows `NN references` to the right of the +first (or only) line of each enum variant. This is the count of +uses of that enum variant. Clicking on it gives a list of where +that enum variant is used." + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-references-method-enable nil + "Enable or disable the References lens on functions. + +The References lens shows `NN references` to the right of the +first line of each function declaration. This is the count of +uses of that function. Clicking on it gives a list of where that +function is used." + + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-references-trait-enable nil + "Enable or disable the References lens on traits. + +The References lens shows `NN references` to the right of the +first line of each trait declaration. This is a count of uses of +that trait. Clicking on it gives a list of where that trait is +used. + +There is some overlap with the Implementations lens which slows +all of the trait's impl blocks, but this also shows other uses +such as imports and dyn traits." + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +(defcustom lsp-rust-analyzer-lens-run-enable t + "Enable or disable the Run lens." + :type 'boolean + :group 'lsp-rust-analyzer-lens + :package-version '(lsp-mode . "9.0.0")) + +(defun lsp-rust-analyzer-initialized? () + (when-let ((workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name)))) + (eq 'initialized (lsp--workspace-status workspace)))) + +(defun lsp-rust-analyzer-expand-macro () + "Expands the macro call at point recursively." + (interactive) + (-if-let* ((params (lsp-make-rust-analyzer-expand-macro-params + :text-document (lsp--text-document-identifier) + :position (lsp--cur-position))) + (response (lsp-request + "rust-analyzer/expandMacro" + params)) + ((&rust-analyzer:ExpandedMacro :expansion) response)) + (funcall lsp-rust-analyzer-macro-expansion-method expansion) + (lsp--error "No macro found at point, or it could not be expanded."))) + +(defun lsp-rust-analyzer-macro-expansion-default (result) + "Default method for displaying macro expansion." + (let* ((root (lsp-workspace-root default-directory)) + (buf (get-buffer-create (get-buffer-create (format "*rust-analyzer macro expansion %s*" root))))) + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer) + (insert (lsp--render-string result "rust")) + (special-mode))) + (pop-to-buffer buf))) + +;; +;;; Runnables + +(defvar lsp-rust-analyzer--last-runnable nil + "Record the last runnable.") + +(defun lsp-rust-analyzer--runnables () + "Return list of runnables." + (lsp-send-request (lsp-make-request + "experimental/runnables" + (lsp-make-rust-analyzer-runnables-params + :text-document (lsp--text-document-identifier) + :position? (lsp--cur-position))))) + +(defun lsp-rust-analyzer--select-runnable () + "Select runnable." + (lsp--completing-read + "Select runnable:" + (if lsp-rust-analyzer--last-runnable + (cons lsp-rust-analyzer--last-runnable + (-remove (-lambda ((&rust-analyzer:Runnable :label)) + (equal label (lsp-get lsp-rust-analyzer--last-runnable :label))) + (lsp-rust-analyzer--runnables))) + (lsp-rust-analyzer--runnables)) + (-lambda ((&rust-analyzer:Runnable :label)) label))) + +(defun lsp-rust-analyzer--common-runner (runnable) + "Execute a given RUNNABLE. + +Extract the arguments, prepare the minor mode (cargo-process-mode if possible) +and run a compilation" + (-let* (((&rust-analyzer:Runnable :kind :label :args) runnable) + ((&rust-analyzer:RunnableArgs :cargo-args :executable-args :workspace-root? :expect-test?) args) + (default-directory (or workspace-root? default-directory))) + (if (not (string-equal kind "cargo")) + (lsp--error "'%s' runnable is not supported" kind) + (compilation-start + (string-join (append (when expect-test? '("env" "UPDATE_EXPECT=1")) + (list "cargo") cargo-args + (when executable-args '("--")) executable-args '()) " ") + + ;; cargo-process-mode is nice, but try to work without it... + (if (functionp 'cargo-process-mode) 'cargo-process-mode nil) + (lambda (_) (concat "*" label "*")))))) + +(defun lsp-rust-analyzer-run (runnable) + "Select and run a RUNNABLE action." + (interactive (list (lsp-rust-analyzer--select-runnable))) + (when (lsp-rust-analyzer--common-runner runnable) + (setq lsp-rust-analyzer--last-runnable runnable))) + +(defun lsp-rust-analyzer-debug (runnable) + "Select and debug a RUNNABLE action." + (interactive (list (lsp-rust-analyzer--select-runnable))) + (unless (or (featurep 'dap-cpptools) (featurep 'dap-gdb)) + (user-error "You must require `dap-cpptools' or 'dap-gdb'")) + (-let (((&rust-analyzer:Runnable + :args (&rust-analyzer:RunnableArgs :cargo-args :workspace-root? :executable-args) + :label) runnable)) + (pcase (aref cargo-args 0) + ("run" (aset cargo-args 0 "build")) + ("test" (when (-contains? (append cargo-args ()) "--no-run") + (cl-callf append cargo-args (list "--no-run"))))) + (->> (append (list (executable-find "cargo")) + cargo-args + (list "--message-format=json")) + (s-join " ") + (shell-command-to-string) + (s-lines) + (-keep (lambda (s) + (condition-case nil + (-let* ((json-object-type 'plist) + ((msg &as &plist :reason :executable) (json-read-from-string s))) + (when (and executable (string= "compiler-artifact" reason)) + executable)) + (error)))) + (funcall + (lambda (artifact-spec) + (pcase artifact-spec + (`() (user-error "No compilation artifacts or obtaining the runnable artifacts failed")) + (`(,spec) spec) + (_ (user-error "Multiple compilation artifacts are not supported"))))) + (list :type (if (featurep 'dap-gdb) "gdb" "cppdbg") + :request "launch" + :name label + :args executable-args + :cwd workspace-root? + :sourceLanguages ["rust"] + :program) + (append lsp-rust-analyzer-debug-lens-extra-dap-args) + (dap-debug)))) + +(defun lsp-rust-analyzer-rerun (&optional runnable) + (interactive (list (or lsp-rust-analyzer--last-runnable + (lsp-rust-analyzer--select-runnable)))) + (lsp-rust-analyzer-run (or runnable lsp-rust-analyzer--last-runnable))) + +;; goto parent module +(cl-defun lsp-rust-find-parent-module (&key display-action) + "Find parent module of current module." + (interactive) + (lsp-find-locations "experimental/parentModule" nil :display-action display-action)) + +(defun lsp-rust-analyzer-open-cargo-toml (&optional new-window) + "Open the closest Cargo.toml from the current file. + +Rust-Analyzer LSP protocol documented here and added in November 2020 +https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-cargotoml + +If NEW-WINDOW (interactively the prefix argument) is non-nil, +open in a new window." + (interactive "P") + (-if-let (workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name))) + (-if-let* ((response (with-lsp-workspace workspace + (lsp-send-request (lsp-make-request + "experimental/openCargoToml" + (lsp-make-rust-analyzer-open-cargo-toml-params + :text-document (lsp--text-document-identifier)))))) + ((&Location :uri :range) response)) + (funcall (if new-window #'find-file-other-window #'find-file) + (lsp--uri-to-path uri)) + (lsp--warn "Couldn't find a Cargo.toml file or your version of rust-analyzer doesn't support this extension")) + (lsp--error "OpenCargoToml is an extension available only with rust-analyzer"))) + +(defun lsp-rust-analyzer-open-external-docs () + "Open a URL for documentation related to the current TextDocumentPosition. + +Rust-Analyzer LSP protocol documented here +https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-external-documentation" + (interactive) + (-if-let* ((params (lsp-make-rust-analyzer-open-external-docs-params + :text-document (lsp--text-document-identifier) + :position (lsp--cur-position))) + (url (lsp-request "experimental/externalDocs" params))) + (browse-url url) + (lsp--warn "Couldn't find documentation URL or your version of rust-analyzer doesn't support this extension"))) + +(defun lsp-rust-analyzer--related-tests () + "Get runnable test items related to the current TextDocumentPosition. +Calls a rust-analyzer LSP extension endpoint that returns a wrapper over +Runnable[]." + (lsp-send-request (lsp-make-request + "rust-analyzer/relatedTests" + (lsp--text-document-position-params)))) + +(defun lsp-rust-analyzer--select-related-test () + "Call the endpoint and ask for user selection. + +Cannot reuse `lsp-rust-analyzer--select-runnable' because the runnables endpoint +responds with Runnable[], while relatedTests responds with TestInfo[], +which is a wrapper over runnable. Also, this method doesn't set +the `lsp-rust-analyzer--last-runnable' variable." + (-if-let* ((resp (lsp-rust-analyzer--related-tests)) + (runnables (seq-map + #'lsp:rust-analyzer-related-tests-runnable + resp))) + (lsp--completing-read + "Select test: " + runnables + #'lsp:rust-analyzer-runnable-label))) + +(defun lsp-rust-analyzer-related-tests (runnable) + "Execute a RUNNABLE test related to the current document position. + +Rust-Analyzer LSP protocol extension +https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#related-tests" + (interactive (list (lsp-rust-analyzer--select-related-test))) + (if runnable + (lsp-rust-analyzer--common-runner runnable) + (lsp--info "There are no tests related to the symbol at point"))) + +(defun lsp-rust-analyzer-move-item (direction) + "Move item under cursor or selection in some DIRECTION" + (let* ((params (lsp-make-rust-analyzer-move-item-params + :text-document (lsp--text-document-identifier) + :range (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point) (point))) + :direction direction)) + (edits (lsp-request "experimental/moveItem" params))) + (lsp--apply-text-edits edits 'code-action))) + +(defun lsp-rust-analyzer-move-item-up () + "Move item under cursor or selection up" + (interactive) + (lsp-rust-analyzer-move-item "Up")) + +(defun lsp-rust-analyzer-move-item-down () + "Move item under cursor or selection down" + (interactive) + (lsp-rust-analyzer-move-item "Down")) + +(defun lsp-rust-analyzer--make-init-options () + "Init options for rust-analyzer" + `(:diagnostics + ( :enable ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable) + :enableExperimental ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable-experimental) + :disabled ,lsp-rust-analyzer-diagnostics-disabled + :warningsAsHint ,lsp-rust-analyzer-diagnostics-warnings-as-hint + :warningsAsInfo ,lsp-rust-analyzer-diagnostics-warnings-as-info) + :imports ( :granularity ( :enforce ,(lsp-json-bool lsp-rust-analyzer-import-enforce-granularity) + :group ,lsp-rust-analyzer-import-granularity) + :group ,(lsp-json-bool lsp-rust-analyzer-import-group) + :merge (:glob ,(lsp-json-bool lsp-rust-analyzer-imports-merge-glob)) + :prefix ,lsp-rust-analyzer-import-prefix) + :lruCapacity ,lsp-rust-analyzer-lru-capacity + :checkOnSave ( :enable ,(lsp-json-bool lsp-rust-analyzer-cargo-watch-enable) + :command ,lsp-rust-analyzer-cargo-watch-command + :extraArgs ,lsp-rust-analyzer-cargo-watch-args + :allTargets ,(lsp-json-bool lsp-rust-analyzer-check-all-targets) + :features ,lsp-rust-analyzer-checkonsave-features + :overrideCommand ,lsp-rust-analyzer-cargo-override-command) + :highlightRelated ( :breakPoints (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-breakpoints)) + :closureCaptures (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-closure-captures)) + :exitPoints (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-exit-points)) + :references (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-references)) + :yieldPoints (:enable ,(lsp-json-bool lsp-rust-analyzer-highlight-yield-points))) + :files ( :exclude ,lsp-rust-analyzer-exclude-globs + :watcher ,(if lsp-rust-analyzer-use-client-watching "client" "notify") + :excludeDirs ,lsp-rust-analyzer-exclude-dirs) + :cargo ( :allFeatures ,(lsp-json-bool lsp-rust-all-features) + :noDefaultFeatures ,(lsp-json-bool lsp-rust-no-default-features) + :features ,lsp-rust-features + :extraArgs ,lsp-rust-analyzer-cargo-extra-args + :extraEnv ,lsp-rust-analyzer-cargo-extra-env + :target ,lsp-rust-analyzer-cargo-target + :runBuildScripts ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts) + ;; Obsolete, but used by old Rust-Analyzer versions + :loadOutDirsFromCheck ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts) + :autoreload ,(lsp-json-bool lsp-rust-analyzer-cargo-auto-reload) + :useRustcWrapperForBuildScripts ,(lsp-json-bool lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts) + :unsetTest ,lsp-rust-analyzer-cargo-unset-test) + :rustfmt ( :extraArgs ,lsp-rust-analyzer-rustfmt-extra-args + :overrideCommand ,lsp-rust-analyzer-rustfmt-override-command + :rangeFormatting (:enable ,(lsp-json-bool lsp-rust-analyzer-rustfmt-rangeformatting-enable))) + :lens ( :debug (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-debug-enable)) + :enable ,(lsp-json-bool lsp-rust-analyzer-lens-enable) + ;; :forceCustomCommands ,(lsp-json-bool lsp-rust-analyzer-lens-force-custom-commands) + :implementations (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-implementations-enable)) + ;; :location ,lsp-rust-analyzer-lens-location + :references ( :adt (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-adt-enable)) + :enumVariant (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-enum-variant-enable)) + :method (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-method-enable)) + :trait (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-references-trait-enable))) + :run (:enable ,(lsp-json-bool lsp-rust-analyzer-lens-run-enable))) + + :inlayHints ( :bindingModeHints (:enable ,(lsp-json-bool lsp-rust-analyzer-binding-mode-hints)) + :chainingHints (:enable ,(lsp-json-bool lsp-rust-analyzer-display-chaining-hints)) + :closingBraceHints ( :enable ,(lsp-json-bool lsp-rust-analyzer-closing-brace-hints) + :minLines ,lsp-rust-analyzer-closing-brace-hints-min-lines) + :closureCaptureHints (:enable ,(lsp-json-bool lsp-rust-analyzer-closure-capture-hints)) + :closureReturnTypeHints (:enable ,lsp-rust-analyzer-closure-return-type-hints) + :closureStyle ,lsp-rust-analyzer-closure-style + :discriminantHints (:enable ,lsp-rust-analyzer-discriminants-hints) + + :expressionAdjustmentHints ( :enable ,lsp-rust-analyzer-expression-adjustment-hints + :hideOutsideUnsafe ,(lsp-json-bool lsp-rust-analyzer-expression-adjustment-hide-unsafe) + :mode ,lsp-rust-analyzer-expression-adjustment-hints-mode) + :implicitDrops (:enable ,(lsp-json-bool lsp-rust-analyzer-implicit-drops)) + :lifetimeElisionHints ( :enable ,lsp-rust-analyzer-display-lifetime-elision-hints-enable + :useParameterNames ,(lsp-json-bool lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names)) + :maxLength ,lsp-rust-analyzer-max-inlay-hint-length + :parameterHints (:enable ,(lsp-json-bool lsp-rust-analyzer-display-parameter-hints)) + :reborrowHints (:enable ,lsp-rust-analyzer-display-reborrow-hints) + :renderColons ,(lsp-json-bool lsp-rust-analyzer-server-format-inlay-hints) + :typeHints ( :enable ,(lsp-json-bool lsp-inlay-hint-enable) + :hideClosureInitialization ,(lsp-json-bool lsp-rust-analyzer-hide-closure-initialization) + :hideNamedConstructor ,(lsp-json-bool lsp-rust-analyzer-hide-named-constructor))) + :completion ( :addCallParenthesis ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-parenthesis) + :addCallArgumentSnippets ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-argument-snippets) + :postfix (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-postfix-enable)) + :autoimport (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-import-enable)) + :autoself (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-self-enable))) + :callInfo (:full ,(lsp-json-bool lsp-rust-analyzer-call-info-full)) + :procMacro (:enable ,(lsp-json-bool lsp-rust-analyzer-proc-macro-enable)) + :rustcSource ,lsp-rust-analyzer-rustc-source + :linkedProjects ,lsp-rust-analyzer-linked-projects + :highlighting (:strings ,(lsp-json-bool lsp-rust-analyzer-highlighting-strings)) + :experimental (:procAttrMacros ,(lsp-json-bool lsp-rust-analyzer-experimental-proc-attr-macros)))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find + (cl-first lsp-rust-analyzer-server-command)) + (lsp-package-path 'rust-analyzer) + "rust-analyzer") + ,@(cl-rest lsp-rust-analyzer-server-command)))) + :activation-fn (lsp-activate-on "rust") + :priority (if (eq lsp-rust-server 'rust-analyzer) 1 -1) + :initialization-options 'lsp-rust-analyzer--make-init-options + :notification-handlers (ht<-alist lsp-rust-notification-handlers) + :action-handlers (ht ("rust-analyzer.runSingle" #'lsp-rust--analyzer-run-single) + ("rust-analyzer.debugSingle" #'lsp-rust--analyzer-debug-lens) + ("rust-analyzer.showReferences" #'lsp-rust--analyzer-show-references) + ("rust-analyzer.triggerParameterHints" #'lsp--action-trigger-parameter-hints)) + :library-folders-fn (lambda (_workspace) lsp-rust-analyzer-library-directories) + :semantic-tokens-faces-overrides `( :discard-default-modifiers t + :modifiers ,(lsp-rust-analyzer--semantic-modifiers)) + :server-id 'rust-analyzer + :custom-capabilities `((experimental . + ((snippetTextEdit . ,(and lsp-enable-snippet (fboundp 'yas-minor-mode))) + (commands . ((commands . + [ + "rust-analyzer.runSingle" + "rust-analyzer.debugSingle" + "rust-analyzer.showReferences" + ;; "rust-analyzer.gotoLocation" + "rust-analyzer.triggerParameterHints" + ;; "rust-analyzer.rename" + ])))))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'rust-analyzer callback error-callback)))) + +(cl-defmethod lsp-clients-extract-signature-on-hover (contents (_server-id (eql rust-analyzer))) + "Extract first non-comment line from rust-analyzer's hover CONTENTS. +The first line of the hover contents is usally about memory layout or notable +traits starting with //, with the actual signature follows." + (let* ((lines (s-lines (s-trim (lsp--render-element contents)))) + (non-comment-lines (--filter (not (s-prefix? "//" it)) lines))) + (if non-comment-lines + (car non-comment-lines) + (car lines)))) + +(lsp-consistency-check lsp-rust) + +(provide 'lsp-rust) +;;; lsp-rust.el ends here diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-rust.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-rust.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-semantic-tokens.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-semantic-tokens.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-semantic-tokens.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-semantic-tokens.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-semgrep.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-semgrep.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-semgrep.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-semgrep.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sml.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-sml.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sml.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-sml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-solargraph.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-solargraph.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-solargraph.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-solargraph.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-solidity.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-solidity.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-solidity.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-solidity.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sorbet.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-sorbet.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sorbet.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-sorbet.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sql.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-sql.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sql.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-sql.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sqls.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-sqls.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-sqls.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-sqls.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-steep.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-steep.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-steep.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-steep.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-svelte.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-svelte.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-svelte.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-svelte.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-terraform.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-terraform.el diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-terraform.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-terraform.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-tex.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-tex.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-tex.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-tex.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-tilt.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-tilt.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-tilt.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-tilt.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-toml.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-toml.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-toml.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-toml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-trunk.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-trunk.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-trunk.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-trunk.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ttcn3.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-ttcn3.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-ttcn3.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-ttcn3.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-typeprof.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-typeprof.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-typeprof.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-typeprof.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-v.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-v.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-v.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-v.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vala.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-vala.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vala.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-vala.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-verilog.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-verilog.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-verilog.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-verilog.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vetur.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-vetur.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vetur.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-vetur.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vhdl.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-vhdl.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vhdl.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-vhdl.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vimscript.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-vimscript.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-vimscript.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-vimscript.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-volar.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-volar.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-volar.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-volar.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-wgsl.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-wgsl.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-wgsl.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-wgsl.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-xml.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-xml.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-xml.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-xml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-yaml.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-yaml.el @@ -0,0 +1,247 @@ +;;; lsp-yaml.el --- LSP YAML server integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Aya Igarashi + +;; Author: Aya Igarashi <ladiclexxx@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-mode) +(require 'dash) + +(defgroup lsp-yaml nil + "LSP support for YAML, using yaml-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/redhat-developer/yaml-language-server") + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-format-enable t + "Enable/disable default YAML formatter." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-single-quote nil + "Use single quote instead of double quotes." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-bracket-spacing t + "Print spaces between brackets in objects." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-prose-wrap "preserve" + "Options for prose-wrap. + Always: wrap prose if it exceeds the print width. + Never: never wrap the prose. + Preserve: wrap prose as-is." + :type '(choice + (const "always") + (const "never") + (const "preserve")) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-print-width 80 + "Specify the line length that the printer will wrap on." + :type 'number + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-validate t + "Enable/disable validation feature." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-hover t + "Enable/disable hover feature." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-completion t + "Enable/disable completion feature." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-schemas '() + "Associate schemas to YAML files in a glob pattern." + :type '(alist :key-type (symbol :tag "schema") :value-type (lsp-string-vector :tag "files (glob)")) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-schema-store-enable t + "Enable/disable JSON Schema store. When set to true, available YAML + schemas will be automatically pulled from the store." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-custom-tags nil + "Custom tags for the parser to use." + :type '(lsp-repeatable-vector string) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-schema-store-uri "https://www.schemastore.org/api/json/catalog.json" + "URL of schema store catalog to use." + :type 'string + :group 'lsp-yaml) + +(defcustom lsp-yaml-schema-store-local-db (expand-file-name + (locate-user-emacs-file + (f-join ".cache" "lsp" "lsp-yaml-schemas.json"))) + "Cached database of schema store." + :type 'file + :group 'lsp-yaml) + +(defcustom lsp-yaml-max-items-computed 5000 + "The maximum number of outline symbols and folding regions computed. +Limited for performance reasons." + :type 'number + :group 'lsp-yaml + :package-version '(lsp-mode . "8.0.0")) + + +(defvar lsp-yaml--schema-store-schemas-alist nil + "A list of schemas fetched from schema stores.") + +(lsp-register-custom-settings + '(("yaml.format.enable" lsp-yaml-format-enable t) + ("yaml.format.singleQuote" lsp-yaml-single-quote t) + ("yaml.format.bracketSpacing" lsp-yaml-bracket-spacing) + ("yaml.format.proseWrap" lsp-yaml-prose-wrap) + ("yaml.format.printWidth" lsp-yaml-print-width) + ("yaml.validate" lsp-yaml-validate t) + ("yaml.hover" lsp-yaml-hover t) + ("yaml.completion" lsp-yaml-completion t) + ("yaml.schemas" lsp-yaml-schemas) + ("yaml.schemaStore.enable" lsp-yaml-schema-store-enable t) + ("yaml.schemaStore.url" lsp-yaml-schema-store-uri) + ("yaml.customTags" lsp-yaml-custom-tags) + ("yaml.maxItemsComputed" lsp-yaml-max-items-computed))) + +(defcustom lsp-yaml-server-command '("yaml-language-server" "--stdio") + "Command to start yaml-languageserver." + :type '(repeat string) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(lsp-dependency 'yaml-language-server + '(:system "yaml-language-server") + '(:npm :package "yaml-language-server" + :path "yaml-language-server")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find (cl-first lsp-yaml-server-command)) + (lsp-package-path 'yaml-language-server)) + ,@(cl-rest lsp-yaml-server-command)))) + :activation-fn (lsp-activate-on "yaml") + :priority 0 + :server-id 'yamlls + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "yaml")))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'yaml-language-server + callback error-callback)))) + +(defcustom lsp-yaml-schema-extensions '(((name . "Kubernetes v1.30.3") + (description . "Kubernetes v1.30.3 manifest schema definition") + (url . "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.30.3-standalone-strict/all.json") + (fileMatch . ["*-k8s.yaml" "*-k8s.yml"]))) + "User defined schemas that extend default schema store. +Used in `lsp-yaml--get-supported-schemas' to supplement schemas provided by +`lsp-yaml-schema-store-uri'." + :type 'list + :group 'lsp-yaml + :package-version '(lsp-mode . "9.0.1")) + +(defun lsp-yaml-download-schema-store-db (&optional force-downloading) + "Download remote schema store at `lsp-yaml-schema-store-uri' into local cache. +Set FORCE-DOWNLOADING to non-nil to force re-download the database." + (interactive "P") + (when (or force-downloading (not (file-exists-p lsp-yaml-schema-store-local-db))) + (unless (file-directory-p (file-name-directory lsp-yaml-schema-store-local-db)) + (mkdir (file-name-directory lsp-yaml-schema-store-local-db) t)) + (url-copy-file lsp-yaml-schema-store-uri lsp-yaml-schema-store-local-db force-downloading))) + +(defun lsp-yaml--get-supported-schemas () + "Get out the list of supported schemas." + (when (and lsp-yaml-schema-store-enable + (not lsp-yaml--schema-store-schemas-alist)) + (lsp-yaml-download-schema-store-db) + (setq lsp-yaml--schema-store-schemas-alist + (alist-get 'schemas (json-read-file lsp-yaml-schema-store-local-db)))) + (seq-concatenate 'list lsp-yaml-schema-extensions lsp-yaml--schema-store-schemas-alist)) + +(defun lsp-yaml-set-buffer-schema (uri-string) + "Set yaml schema for the current buffer to URI-STRING." + (interactive "MURI: ") + (let* ((uri (intern uri-string)) + (workspace-path (file-relative-name + (lsp--uri-to-path (lsp--buffer-uri)) + (lsp-workspace-root (lsp--buffer-uri)))) + (glob (concat "/" workspace-path)) + (current-config (assoc uri lsp-yaml-schemas)) + (current-patterns (and current-config (cdr current-config)))) + (if current-config + (or (member glob (append current-patterns nil)) + (setq lsp-yaml-schemas + (cl-acons uri + (vconcat (vector glob) current-patterns) + (assq-delete-all uri + (mapcar (lambda (x) (lsp-yaml--remove-glob x glob)) + lsp-yaml-schemas))))) + (setq lsp-yaml-schemas + (cl-acons uri (vector glob) (mapcar (lambda (x) (lsp-yaml--remove-glob x glob)) + lsp-yaml-schemas)))) + (lsp--set-configuration (lsp-configuration-section "yaml")))) + +(defun lsp-yaml-select-buffer-schema () + "Select schema for the current buffer based on the list of supported schemas." + (interactive) + (let* ((schema (lsp--completing-read "Select buffer schema: " + (lsp-yaml--get-supported-schemas) + (lambda (schema) + (format "%s: %s" (alist-get 'name schema)(alist-get 'description schema))) + nil t)) + (uri (alist-get 'url schema))) + (lsp-yaml-set-buffer-schema uri))) + +(defun lsp-yaml--remove-glob (mapping glob) + (let ((patterns (cdr mapping))) + (cons (car mapping) + (vconcat (-filter (lambda (p) (not (equal p glob))) + (append patterns nil)) nil)))) + +(lsp-consistency-check lsp-yaml) + +(provide 'lsp-yaml) +;;; lsp-yaml.el ends here diff --git a/emacs/elpa/lsp-mode-20240817.1400/lsp-yaml.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-yaml.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-yang.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-yang.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-yang.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-yang.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-zig.el b/emacs/elpa/lsp-mode-20240817.1400/lsp-zig.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp-zig.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp-zig.elc Binary files differ. diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp.el b/emacs/elpa/lsp-mode-20240817.1400/lsp.el diff --git a/emacs/elpa/lsp-mode-20240801.2341/lsp.elc b/emacs/elpa/lsp-mode-20240817.1400/lsp.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-diff.elc b/emacs/elpa/magit-20240811.1419/magit-diff.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-log.elc b/emacs/elpa/magit-20240811.1419/magit-log.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-pkg.el b/emacs/elpa/magit-20240811.1419/magit-pkg.el @@ -1,20 +0,0 @@ -(define-package "magit" "20240811.1419" "A Git porcelain inside Emacs." - '((emacs "26.1") - (compat "30.0.0.0") - (dash "20240510") - (git-commit "20240808") - (magit-section "20240808") - (seq "2.24") - (transient "20240805") - (with-editor "20240806")) - :commit "a2739d7db1fdf19b95f36f6ddd15b0c1f523bd26" :authors - '(("Marius Vollmer" . "marius.vollmer@gmail.com") - ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) - :maintainer - '("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") - :keywords - '("git" "tools" "vc") - :url "https://github.com/magit/magit") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/magit-20240811.1419/magit.info b/emacs/elpa/magit-20240811.1419/magit.info @@ -1,11592 +0,0 @@ -This is magit.info, produced by makeinfo version 6.8 from magit.texi. - - Copyright (C) 2015-2024 Jonas Bernoulli - <emacs.magit@jonas.bernoulli.dev> - - You can redistribute this document 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 document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit: (magit). Using Git from Emacs with Magit. -END-INFO-DIR-ENTRY - - -File: magit.info, Node: Top, Next: Introduction, Up: (dir) - -Magit User Manual -***************** - -Magit is an interface to the version control system Git, implemented as -an Emacs package. Magit aspires to be a complete Git porcelain. While -we cannot (yet) claim that Magit wraps and improves upon each and every -Git command, it is complete enough to allow even experienced Git users -to perform almost all of their daily version control tasks directly from -within Emacs. While many fine Git clients exist, only Magit and Git -itself deserve to be called porcelains. - -This manual is for Magit version 3.3.0.50-git. - - Copyright (C) 2015-2024 Jonas Bernoulli - <emacs.magit@jonas.bernoulli.dev> - - You can redistribute this document 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 document 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. - -* Menu: - -* Introduction:: -* Installation:: -* Getting Started:: -* Interface Concepts:: -* Inspecting:: -* Manipulating:: -* Transferring:: -* Miscellaneous:: -* Customizing:: -* Plumbing:: -* FAQ:: -* Debugging Tools:: -* Keystroke Index:: -* Function and Command Index:: -* Variable Index:: - -— The Detailed Node Listing — - -Installation - -* Installing from Melpa:: -* Installing from the Git Repository:: -* Post-Installation Tasks:: - -Interface Concepts - -* Modes and Buffers:: -* Sections:: -* Transient Commands:: -* Transient Arguments and Buffer Variables:: -* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. -* Mouse Support:: -* Running Git:: - -Modes and Buffers - -* Switching Buffers:: -* Naming Buffers:: -* Quitting Windows:: -* Automatic Refreshing of Magit Buffers:: -* Automatic Saving of File-Visiting Buffers:: -* Automatic Reverting of File-Visiting Buffers:: - - -Sections - -* Section Movement:: -* Section Visibility:: -* Section Hooks:: -* Section Types and Values:: -* Section Options:: - - -Completion, Confirmation and the Selection - -* Action Confirmation:: -* Completion and Confirmation:: -* The Selection:: -* The hunk-internal region:: -* Support for Completion Frameworks:: -* Additional Completion Options:: - - -Running Git - -* Viewing Git Output:: -* Git Process Status:: -* Running Git Manually:: -* Git Executable:: -* Global Git Arguments:: - - -Inspecting - -* Status Buffer:: -* Repository List:: -* Logging:: -* Diffing:: -* Ediffing:: -* References Buffer:: -* Bisecting:: -* Visiting Files and Blobs:: -* Blaming:: - -Status Buffer - -* Status Sections:: -* Status Header Sections:: -* Status Module Sections:: -* Status Options:: - - -Logging - -* Refreshing Logs:: -* Log Buffer:: -* Log Margin:: -* Select from Log:: -* Reflog:: -* Cherries:: - - -Diffing - -* Refreshing Diffs:: -* Commands Available in Diffs:: -* Diff Options:: -* Revision Buffer:: - - -References Buffer - -* References Sections:: - - -Visiting Files and Blobs - -* General-Purpose Visit Commands:: -* Visiting Files and Blobs from a Diff:: - - -Manipulating - -* Creating Repository:: -* Cloning Repository:: -* Staging and Unstaging:: -* Applying:: -* Committing:: -* Branching:: -* Merging:: -* Resolving Conflicts:: -* Rebasing:: -* Cherry Picking:: -* Resetting:: -* Stashing:: - -Staging and Unstaging - -* Staging from File-Visiting Buffers:: - - -Committing - -* Initiating a Commit:: -* Editing Commit Messages:: - - -Branching - -* The Two Remotes:: -* Branch Commands:: -* Branch Git Variables:: -* Auxiliary Branch Commands:: - - -Rebasing - -* Editing Rebase Sequences:: -* Information About In-Progress Rebase:: - - -Cherry Picking - -* Reverting:: - - -Transferring - -* Remotes:: -* Fetching:: -* Pulling:: -* Pushing:: -* Plain Patches:: -* Maildir Patches:: - -Remotes - -* Remote Commands:: -* Remote Git Variables:: - - -Miscellaneous - -* Tagging:: -* Notes:: -* Submodules:: -* Subtree:: -* Worktree:: -* Sparse checkouts:: -* Bundle:: -* Common Commands:: -* Wip Modes:: -* Commands for Buffers Visiting Files:: -* Minor Mode for Buffers Visiting Blobs:: - -Submodules - -* Listing Submodules:: -* Submodule Transient:: - - -Wip Modes - -* Wip Graph:: -* Legacy Wip Modes:: - - -Customizing - -* Per-Repository Configuration:: -* Essential Settings:: - -Essential Settings - -* Safety:: -* Performance:: -* Global Bindings:: - - -Plumbing - -* Calling Git:: -* Section Plumbing:: -* Refreshing Buffers:: -* Conventions:: - -Calling Git - -* Getting a Value from Git:: -* Calling Git for Effect:: - - -Section Plumbing - -* Creating Sections:: -* Section Selection:: -* Matching Sections:: - - -Conventions - -* Theming Faces:: - - -FAQ - -* FAQ - How to ...?:: -* FAQ - Issues and Errors:: - -FAQ - How to ...? - -* How to pronounce Magit?:: -* How to show git's output?:: -* How to install the gitman info manual?:: -* How to show diffs for gpg-encrypted files?:: -* How does branching and pushing work?:: -* Should I disable VC?:: - - -FAQ - Issues and Errors - -* Magit is slow:: -* I changed several thousand files at once and now Magit is unusable:: -* I am having problems committing:: -* I am using MS Windows and cannot push with Magit:: -* I am using macOS and SOMETHING works in shell, but not in Magit: I am using macOS and SOMETHING works in shell but not in Magit. -* Expanding a file to show the diff causes it to disappear:: -* Point is wrong in the COMMIT_EDITMSG buffer:: -* The mode-line information isn't always up-to-date:: -* A branch and tag sharing the same name breaks SOMETHING:: -* My Git hooks work on the command-line but not inside Magit:: -* git-commit-mode isn't used when committing from the command-line:: -* Point ends up inside invisible text when jumping to a file-visiting buffer:: -* I am no longer able to save popup defaults:: - - - - -File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top - -1 Introduction -************** - -Magit is an interface to the version control system Git, implemented as -an Emacs package. Magit aspires to be a complete Git porcelain. While -we cannot (yet) claim that Magit wraps and improves upon each and every -Git command, it is complete enough to allow even experienced Git users -to perform almost all of their daily version control tasks directly from -within Emacs. While many fine Git clients exist, only Magit and Git -itself deserve to be called porcelains. - - Staging and otherwise applying changes is one of the most important -features in a Git porcelain and here Magit outshines anything else, -including Git itself. Git’s own staging interface (‘git add --patch’) -is so cumbersome that many users only use it in exceptional cases. In -Magit staging a hunk or even just part of a hunk is as trivial as -staging all changes made to a file. - - The most visible part of Magit’s interface is the status buffer, -which displays information about the current repository. Its content is -created by running several Git commands and making their output -actionable. Among other things, it displays information about the -current branch, lists unpulled and unpushed changes and contains -sections displaying the staged and unstaged changes. That might sound -noisy, but, since sections are collapsible, it’s not. - - To stage or unstage a change one places the cursor on the change and -then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the -region is active (i.e., when there is a selection) several files or -hunks, or even just part of a hunk. The change or changes that these -commands - and many others - would act on are highlighted. - - Magit also implements several other "apply variants" in addition to -staging and unstaging. One can discard or reverse a change, or apply it -to the working tree. Git’s own porcelain only supports this for staging -and unstaging and you would have to do something like ‘git diff ... | -??? | git apply ...’ to discard, revert, or apply a single hunk on the -command line. In fact that’s exactly what Magit does internally (which -is what lead to the term "apply variants"). - - Magit isn’t just for Git experts, but it does assume some prior -experience with Git as well as Emacs. That being said, many users have -reported that using Magit was what finally taught them what Git is -capable of and how to use it to its fullest. Other users wished they -had switched to Emacs sooner so that they would have gotten their hands -on Magit earlier. - - While one has to know the basic features of Emacs to be able to make -full use of Magit, acquiring just enough Emacs skills doesn’t take long -and is worth it, even for users who prefer other editors. Vim users are -advised to give Evil (https://github.com/emacs-evil/evil), the -"Extensible VI Layer for Emacs", and Spacemacs -(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused -on Evil" a try. - - Magit provides a consistent and efficient Git porcelain. After a -short learning period, you will be able to perform most of your daily -version control tasks faster than you would on the command line. You -will likely also start using features that seemed too daunting in the -past. - - Magit fully embraces Git. It exposes many advanced features using a -simple but flexible interface instead of only wrapping the trivial ones -like many GUI clients do. Of course Magit supports logging, cloning, -pushing, and other commands that usually don’t fail in spectacular ways; -but it also supports tasks that often cannot be completed in a single -step. Magit fully supports tasks such as merging, rebasing, -cherry-picking, reverting, and blaming by not only providing a command -to initiate these tasks but also by displaying context sensitive -information along the way and providing commands that are useful for -resolving conflicts and resuming the sequence after doing so. - - Magit wraps and in many cases improves upon at least the following -Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’, -‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’, -‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’, -‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’, -‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’, -‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain -commands are implemented on top of Git plumbing commands. - - -File: magit.info, Node: Installation, Next: Getting Started, Prev: Introduction, Up: Top - -2 Installation -************** - -Magit can be installed using Emacs’ package manager or manually from its -development repository. - -* Menu: - -* Installing from Melpa:: -* Installing from the Git Repository:: -* Post-Installation Tasks:: - - -File: magit.info, Node: Installing from Melpa, Next: Installing from the Git Repository, Up: Installation - -2.1 Installing from Melpa -========================= - -Magit is available from Melpa and Melpa-Stable. If you haven’t used -Emacs’ package manager before, then it is high time you familiarize -yourself with it by reading the documentation in the Emacs manual, see -*note (emacs)Packages::. Then add one of the archives to -‘package-archives’: - - • To use Melpa: - - (require 'package) - (add-to-list 'package-archives - '("melpa" . "https://melpa.org/packages/") t) - - • To use Melpa-Stable: - - (require 'package) - (add-to-list 'package-archives - '("melpa-stable" . "https://stable.melpa.org/packages/") t) - - Once you have added your preferred archive, you need to update the -local package list using: - - M-x package-refresh-contents RET - - Once you have done that, you can install Magit and its dependencies -using: - - M-x package-install RET magit RET - - Now see *note Post-Installation Tasks::. - - -File: magit.info, Node: Installing from the Git Repository, Next: Post-Installation Tasks, Prev: Installing from Melpa, Up: Installation - -2.2 Installing from the Git Repository -====================================== - -Magit depends on the ‘compat’, ‘dash’, ‘transient’ and ‘with-editor’ -libraries which are available from Melpa and Melpa-Stable. Install them -using ‘M-x package-install RET <package> RET’. Of course you may also -install them manually from their repository. - - Then clone the Magit repository: - - $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit - $ cd ~/.emacs.d/site-lisp/magit - - Then compile the libraries and generate the info manuals: - - $ make - - If you haven’t installed ‘compat’, ‘dash’, ‘transient’ and -‘with-editor’ from Melpa or at ‘/path/to/magit/../<package>’, then you -have to tell ‘make’ where to find them. To do so create the file -‘/path/to/magit/config.mk’ with the following content before running -‘make’: - - LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp - LOAD_PATH += -L ~/.emacs.d/site-lisp/dash - LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp - LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor/lisp - LOAD_PATH += -L ~/.emacs.d/site-lisp/compat - - Finally add this to your init file: - - (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp") - (require 'magit) - - (with-eval-after-load 'info - (info-initialize) - (add-to-list 'Info-directory-list - "~/.emacs.d/site-lisp/magit/Documentation/")) - - Of course if you installed the dependencies manually as well, then -you have to tell Emacs about them too, by prefixing the above with: - - (add-to-list 'load-path "~/.emacs.d/site-lisp/dash") - (add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp") - (add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor") - - Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’, -not the top-level of the repository, and that elements of ‘load-path’ -should not end with a slash, while those of ‘Info-directory-list’ -should. - - Instead of requiring the feature ‘magit’, you could load just the -autoload definitions, by loading the file ‘magit-autoloads.el’. - - (load "/path/to/magit/lisp/magit-autoloads") - - Instead of running Magit directly from the repository by adding that -to the ‘load-path’, you might want to instead install it in some other -directory using ‘sudo make install’ and setting ‘load-path’ accordingly. - - To update Magit use: - - $ git pull - $ make - - At times it might be necessary to run ‘make clean all’ instead. - - To view all available targets use ‘make help’. - - Now see *note Post-Installation Tasks::. - - -File: magit.info, Node: Post-Installation Tasks, Prev: Installing from the Git Repository, Up: Installation - -2.3 Post-Installation Tasks -=========================== - -After installing Magit you should verify that you are indeed using the -Magit, Git, and Emacs releases you think you are using. It’s best to -restart Emacs before doing so, to make sure you are not using an -outdated value for ‘load-path’. - - M-x magit-version RET - - should display something like - - Magit 2.8.0, Git 2.10.2, Emacs 25.1.1, gnu/linux - - Then you might also want to read about options that many users likely -want to customize. See *note Essential Settings::. - - To be able to follow cross references to Git manpages found in this -manual, you might also have to manually install the ‘gitman’ info -manual, or advice ‘Info-follow-nearest-node’ to instead open the actual -manpage. See *note How to install the gitman info manual?::. - - If you are completely new to Magit then see *note Getting Started::. - - If you run into problems, then please see the *note FAQ::. Also see -the *note Debugging Tools::. - - And last but not least please consider making a donation, to ensure -that I can keep working on Magit. See <https://magit.vc/donations>. -for various donation options. - - -File: magit.info, Node: Getting Started, Next: Interface Concepts, Prev: Installation, Up: Top - -3 Getting Started -***************** - -This short tutorial describes the most essential features that many -Magitians use on a daily basis. It only scratches the surface but -should be enough to get you started. - - IMPORTANT: It is safest if you clone some repository just for this -tutorial. Alternatively you can use an existing local repository, but -if you do that, then you should commit all uncommitted changes before -proceeding. - - Type ‘C-x g’ to display information about the current Git repository -in a dedicated buffer, called the status buffer. - - Most Magit commands are commonly invoked from the status buffer. It -can be considered the primary interface for interacting with Git using -Magit. Many other Magit buffers may exist at a given time, but they are -often created from this buffer. - - Depending on what state your repository is in, this buffer may -contain sections titled "Staged changes", "Unstaged changes", "Unmerged -into origin/master", "Unpushed to origin/master", and many others. - - Since we are starting from a safe state, which you can easily return -to (by doing a ‘git reset --hard PRE-MAGIT-STATE’), there currently are -no staged or unstaged changes. Edit some files and save the changes. -Then go back to the status buffer, while at the same time refreshing it, -by typing ‘C-x g’. (When the status buffer, or any Magit buffer for -that matter, is the current buffer, then you can also use just ‘g’ to -refresh it). - - Move between sections using ‘p’ and ‘n’. Note that the bodies of -some sections are hidden. Type ‘TAB’ to expand or collapse the section -at point. You can also use ‘C-tab’ to cycle the visibility of the -current section and its children. Move to a file section inside the -section named "Unstaged changes" and type ‘s’ to stage the changes you -have made to that file. That file now appears under "Staged changes". - - Magit can stage and unstage individual hunks, not just complete -files. Move to the file you have just staged, expand it using ‘TAB’, -move to one of the hunks using ‘n’, and unstage just that by typing ‘u’. -Note how the staging (‘s’) and unstaging (‘u’) commands operate on the -change at point. Many other commands behave the same way. - - You can also un-/stage just part of a hunk. Inside the body of a -hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and -move down until some added and/or removed lines fall inside the region -but not all of them. Again type ‘s’ to stage. - - It is also possible to un-/stage multiple files at once. Move to a -file section, type ‘C-SPC’, move to the next file using ‘n’, and then -‘s’ to stage both files. Note that both the mark and point have to be -on the headings of sibling sections for this to work. If the region -looks like it does in other buffers, then it doesn’t select Magit -sections that can be acted on as a unit. - - And then of course you want to commit your changes. Type ‘c’. This -shows the available commit commands and arguments in a buffer at the -bottom of the frame. Each command and argument is prefixed with the key -that invokes/sets it. Do not worry about this for now. We want to -create a "normal" commit, which is done by typing ‘c’ again. - - Now two new buffers appear. One is for writing the commit message, -the other shows a diff with the changes that you are about to commit. -Write a message and then type ‘C-c C-c’ to actually create the commit. - - You probably don’t want to push the commit you just created because -you just committed some random changes, but if that is not the case you -could push it by typing ‘P’ to show all the available push commands and -arguments and then ‘p’ to push to a branch with the same name as the -local branch onto the remote configured as the push-remote. (If the -push-remote is not configured yet, then you would first be prompted for -the remote to push to.) - - So far we have mentioned the commit and push menu commands. These -are probably among the menus you will be using the most, but many others -exist. To show a menu that lists all other menus (as well as the -various apply commands and some other essential commands), type ‘h’. -Try a few. (Such menus are also called "transient prefix commands" or -just "transients".) - - The key bindings in that menu correspond to the bindings in Magit -buffers, including but not limited to the status buffer. So you could -type ‘h d’ to bring up the diff menu, but once you remember that "d" -stands for "diff", you would usually do so by just typing ‘d’. - - This "prefix of prefixes" is useful even once you have memorized all -the bindings, as it can provide easy access to Magit commands from -non-Magit buffers. So, by default, it is globally bound to ‘C-x M-g’. - - A similar menu featuring (for the most part) commands that act on -just the file being visited in the current buffer, is globally bound to -‘C-c M-g’. That binding can also be used in buffers, which do not visit -a file, but then only a subset of the commands is available. - - The global key bindings mentioned in the previous two paragraphs are -quite inconvenient. We recommend using ‘C-c g’ and ‘C-c f’ instead, but -cannot use those key sequences by default because they are strictly -reserved for bindings added by the user. See *note Global Bindings::, -if you want to explicitly opt-in to the recommended key bindings. - - Magit also provides context menus and other mouse commands, see *note -Mouse Support::. - - It is not necessary that you do so now, but if you stick with Magit, -then it is highly recommended that you read the next section too. - - -File: magit.info, Node: Interface Concepts, Next: Inspecting, Prev: Getting Started, Up: Top - -4 Interface Concepts -******************** - -* Menu: - -* Modes and Buffers:: -* Sections:: -* Transient Commands:: -* Transient Arguments and Buffer Variables:: -* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. -* Mouse Support:: -* Running Git:: - - -File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface Concepts - -4.1 Modes and Buffers -===================== - -Magit provides several major-modes. For each of these modes there -usually exists only one buffer per repository. Separate modes and thus -buffers exist for commits, diffs, logs, and some other things. - - Besides these special purpose buffers, there also exists an overview -buffer, called the *status buffer*. It’s usually from this buffer that -the user invokes Git commands, or creates or visits other buffers. - - In this manual we often speak about "Magit buffers". By that we mean -buffers whose major-modes derive from ‘magit-mode’. - -‘M-x magit-toggle-buffer-lock’ - This command locks the current buffer to its value or if the buffer - is already locked, then it unlocks it. - - Locking a buffer to its value prevents it from being reused to - display another value. The name of a locked buffer contains its - value, which allows telling it apart from other locked buffers and - the unlocked buffer. - - Not all Magit buffers can be locked to their values; for example, - it wouldn’t make sense to lock a status buffer. - - There can only be a single unlocked buffer using a certain - major-mode per repository. So when a buffer is being unlocked and - another unlocked buffer already exists for that mode and - repository, then the former buffer is instead deleted and the - latter is displayed in its place. - -* Menu: - -* Switching Buffers:: -* Naming Buffers:: -* Quitting Windows:: -* Automatic Refreshing of Magit Buffers:: -* Automatic Saving of File-Visiting Buffers:: -* Automatic Reverting of File-Visiting Buffers:: - - -File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers - -4.1.1 Switching Buffers ------------------------ - - -- Function: magit-display-buffer buffer &optional display-function - This function is a wrapper around ‘display-buffer’ and is used to - display any Magit buffer. It displays BUFFER in some window and, - unlike ‘display-buffer’, also selects that window, provided - ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks - mentioned below. - - If optional DISPLAY-FUNCTION is non-nil, then that is used to - display the buffer. Usually that is ‘nil’ and the function - specified by ‘magit-display-buffer-function’ is used. - - -- Variable: magit-display-buffer-noselect - When this is non-nil, then ‘magit-display-buffer’ only displays the - buffer but forgoes also selecting the window. This variable should - not be set globally, it is only intended to be let-bound, by code - that automatically updates "the other window". This is used for - example when the revision buffer is updated when you move inside - the log buffer. - - -- User Option: magit-display-buffer-function - The function specified here is called by ‘magit-display-buffer’ - with one argument, a buffer, to actually display that buffer. This - function should call ‘display-buffer’ with that buffer as first and - a list of display actions as second argument. - - Magit provides several functions, listed below, that are suitable - values for this option. If you want to use different rules, then a - good way of doing that is to start with a copy of one of these - functions and then adjust it to your needs. - - Instead of using a wrapper around ‘display-buffer’, that function - itself can be used here, in which case the display actions have to - be specified by adding them to ‘display-buffer-alist’ instead. - - To learn about display actions, see *note (elisp)Choosing Window::. - - -- Function: magit-display-buffer-traditional buffer - This function is the current default value of the option - ‘magit-display-buffer-function’. Before that option and this - function were added, the behavior was hard-coded in many places all - over the code base but now all the rules are contained in this one - function (except for the "noselect" special case mentioned above). - - -- Function: magit-display-buffer-same-window-except-diff-v1 - This function displays most buffers in the currently selected - window. If a buffer’s mode derives from ‘magit-diff-mode’ or - ‘magit-process-mode’, it is displayed in another window. - - -- Function: magit-display-buffer-fullframe-status-v1 - This function fills the entire frame when displaying a status - buffer. Otherwise, it behaves like - ‘magit-display-buffer-traditional’. - - -- Function: magit-display-buffer-fullframe-status-topleft-v1 - This function fills the entire frame when displaying a status - buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’ - except that it displays buffers that derive from ‘magit-diff-mode’ - or ‘magit-process-mode’ to the top or left of the current buffer - rather than to the bottom or right. As a result, Magit buffers - tend to pop up on the same side as they would if - ‘magit-display-buffer-traditional’ were in use. - - -- Function: magit-display-buffer-fullcolumn-most-v1 - This function displays most buffers so that they fill the entire - height of the frame. However, the buffer is displayed in another - window if (1) the buffer’s mode derives from ‘magit-process-mode’, - or (2) the buffer’s mode derives from ‘magit-diff-mode’, provided - that the mode of the current buffer derives from ‘magit-log-mode’ - or ‘magit-cherry-mode’. - - -- User Option: magit-pre-display-buffer-hook - This hook is run by ‘magit-display-buffer’ before displaying the - buffer. - - -- Function: magit-save-window-configuration - This function saves the current window configuration. Later when - the buffer is buried, it may be restored by - ‘magit-restore-window-configuration’. - - -- User Option: magit-post-display-buffer-hook - This hook is run by ‘magit-display-buffer’ after displaying the - buffer. - - -- Function: magit-maybe-set-dedicated - This function remembers if a new window had to be created to - display the buffer, or whether an existing window was reused. This - information is later used by ‘magit-mode-quit-window’, to determine - whether the window should be deleted when its last Magit buffer is - buried. - - -File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers - -4.1.2 Naming Buffers --------------------- - - -- User Option: magit-generate-buffer-name-function - The function used to generate the names of Magit buffers. - - Such a function should take the options - ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’ - into account. If it doesn’t, then should be clearly stated in the - doc-string. And if it supports %-sequences beyond those mentioned - in the doc-string of the option ‘magit-buffer-name-format’, then - its own doc-string should describe the additions. - - -- Function: magit-generate-buffer-name-default-function mode - This function returns a buffer name suitable for a buffer whose - major-mode is MODE and which shows information about the repository - in which ‘default-directory’ is located. - - This function uses ‘magit-buffer-name-format’ and supporting all of - the %-sequences mentioned the documentation of that option. It - also respects the option ‘magit-uniquify-buffer-names’. - - -- User Option: magit-buffer-name-format - The format string used to name Magit buffers. - - At least the following %-sequences are supported: - - • ‘%m’ - - The name of the major-mode, but with the ‘-mode’ suffix - removed. - - • ‘%M’ - - Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’. - - • ‘%v’ - - The value the buffer is locked to, in parentheses, or an empty - string if the buffer is not locked to a value. - - • ‘%V’ - - Like ‘%v’, but the string is prefixed with a space, unless it - is an empty string. - - • ‘%t’ - - The top-level directory of the working tree of the repository, - or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation - of that. - - • ‘%x’ - - If ‘magit-uniquify-buffer-names’ is nil "*", otherwise the - empty string. Due to limitations of the ‘uniquify’ package, - buffer names must end with the path. - - The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and - ‘%t’. If ‘magit-uniquify-buffer-names’ is non-nil, then the value - must end with ‘%t’ or ‘%t%x’. See issue #2841. - - -- User Option: magit-uniquify-buffer-names - This option controls whether the names of Magit buffers are - uniquified. If the names are not being uniquified, then they - contain the full path of the top-level of the working tree of the - corresponding repository. If they are being uniquified, then they - end with the basename of the top-level, or if that would conflict - with the name used for other buffers, then the names of all these - buffers are adjusted until they no longer conflict. - - This is done using the ‘uniquify’ package; customize its options to - control how buffer names are uniquified. - - -File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers - -4.1.3 Quitting Windows ----------------------- - -‘q’ (‘magit-mode-bury-buffer’) - This command buries or kills the current Magit buffer. The - function specified by option ‘magit-bury-buffer-function’ is used - to bury the buffer when called without a prefix argument or to kill - it when called with a single prefix argument. - - When called with two or more prefix arguments then it always kills - all Magit buffers, associated with the current project, including - the current buffer. - - -- User Option: magit-bury-buffer-function - The function used to actually bury or kill the current buffer. - - ‘magit-mode-bury-buffer’ calls this function with one argument. If - the argument is non-nil, then the function has to kill the current - buffer. Otherwise it has to bury it alive. The default value - currently is ‘magit-mode-quit-window’. - - -- Function: magit-restore-window-configuration kill-buffer - Bury or kill the current buffer using ‘quit-window’, which is - called with KILL-BUFFER as first and the selected window as second - argument. - - Then restore the window configuration that existed right before the - current buffer was displayed in the selected frame. Unfortunately - that also means that point gets adjusted in all the buffers, which - are being displayed in the selected frame. - - -- Function: magit-mode-quit-window kill-buffer - Bury or kill the current buffer using ‘quit-window’, which is - called with KILL-BUFFER as first and the selected window as second - argument. - - Then, if the window was originally created to display a Magit - buffer and the buried buffer was the last remaining Magit buffer - that was ever displayed in the window, then that is deleted. - - -File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers - -4.1.4 Automatic Refreshing of Magit Buffers -------------------------------------------- - -After running a command which may change the state of the current -repository, the current Magit buffer and the corresponding status buffer -are refreshed. The status buffer can be automatically refreshed -whenever a buffer is saved to a file inside the respective repository by -adding a hook, like so: - - (with-eval-after-load 'magit-mode - (add-hook 'after-save-hook 'magit-after-save-refresh-status t)) - - Automatically refreshing Magit buffers ensures that the displayed -information is up-to-date most of the time but can lead to a noticeable -delay in big repositories. Other Magit buffers are not refreshed to -keep the delay to a minimum and also because doing so can sometimes be -undesirable. - - Buffers can also be refreshed explicitly, which is useful in buffers -that weren’t current during the last refresh and after changes were made -to the repository outside of Magit. - -‘g’ (‘magit-refresh’) - This command refreshes the current buffer if its major mode derives - from ‘magit-mode’ as well as the corresponding status buffer. - - If the option ‘magit-revert-buffers’ calls for it, then it also - reverts all unmodified buffers that visit files being tracked in - the current repository. - -‘G’ (‘magit-refresh-all’) - This command refreshes all Magit buffers belonging to the current - repository and also reverts all unmodified buffers that visit files - being tracked in the current repository. - - The file-visiting buffers are always reverted, even if - ‘magit-revert-buffers’ is nil. - - -- User Option: magit-refresh-buffer-hook - This hook is run in each Magit buffer that was refreshed during the - current refresh - normally the current buffer and the status - buffer. - - -- User Option: magit-refresh-status-buffer - When this option is non-nil, then the status buffer is - automatically refreshed after running git for side-effects, in - addition to the current Magit buffer, which is always refreshed - automatically. - - Only set this to nil after exhausting all other options to improve - performance. - - -- Function: magit-after-save-refresh-status - This function is intended to be added to ‘after-save-hook’. After - doing that the corresponding status buffer is refreshed whenever a - buffer is saved to a file inside a repository. - - Note that refreshing a Magit buffer is done by re-creating its - contents from scratch, which can be slow in large repositories. If - you are not satisfied with Magit’s performance, then you should - obviously not add this function to that hook. - - -File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers - -4.1.5 Automatic Saving of File-Visiting Buffers ------------------------------------------------ - -File-visiting buffers are by default saved at certain points in time. -This doesn’t guarantee that Magit buffers are always up-to-date, but, -provided one only edits files by editing them in Emacs and uses only -Magit to interact with Git, one can be fairly confident. When in doubt -or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh -explicitly. - - -- User Option: magit-save-repository-buffers - This option controls whether file-visiting buffers are saved before - certain events. - - If this is non-nil then all modified file-visiting buffers - belonging to the current repository may be saved before running - commands, before creating new Magit buffers, and before explicitly - refreshing such buffers. If this is ‘dontask’ then this is done - without user intervention. If it is ‘t’ then the user has to - confirm each save. - - -File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers - -4.1.6 Automatic Reverting of File-Visiting Buffers --------------------------------------------------- - -By default Magit automatically reverts buffers that are visiting files -that are being tracked in a Git repository, after they have changed on -disk. When using Magit one often changes files on disk by running Git, -i.e., "outside Emacs", making this a rather important feature. - - For example, if you discard a change in the status buffer, then that -is done by running ‘git apply --reverse ...’, and Emacs considers the -file to have "changed on disk". If Magit did not automatically revert -the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in -the visiting buffer before you could continue making changes. - - -- User Option: magit-auto-revert-mode - When this mode is enabled, then buffers that visit tracked files - are automatically reverted after the visited files change on disk. - - -- User Option: global-auto-revert-mode - When this mode is enabled, then any file-visiting buffer is - automatically reverted after the visited file changes on disk. - - If you like buffers that visit tracked files to be automatically - reverted, then you might also like any buffer to be reverted, not - just those visiting tracked files. If that is the case, then - enable this mode _instead of_ ‘magit-auto-revert-mode’. - - -- User Option: magit-auto-revert-immediately - This option controls whether Magit reverts buffers immediately. - - If this is non-nil and either ‘global-auto-revert-mode’ or - ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts - buffers by explicitly calling ‘auto-revert-buffers’ after running - Git for side-effects. - - If ‘auto-revert-use-notify’ is non-nil (and file notifications are - actually supported), then ‘magit-auto-revert-immediately’ does not - have to be non-nil, because the reverts happen immediately anyway. - - If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are - both ‘nil’, then reverts happen after ‘auto-revert-interval’ - seconds of user inactivity. That is not desirable. - - -- User Option: auto-revert-use-notify - This option controls whether file notification functions should be - used. Note that this variable unfortunately defaults to ‘t’ even - on systems on which file notifications cannot be used. - - -- User Option: magit-auto-revert-tracked-only - This option controls whether ‘magit-auto-revert-mode’ only reverts - tracked files or all files that are located inside Git - repositories, including untracked files and files located inside - Git’s control directory. - - -- User Option: auto-revert-mode - The global mode ‘magit-auto-revert-mode’ works by turning on this - local mode in the appropriate buffers (but - ‘global-auto-revert-mode’ is implemented differently). You can - also turn it on or off manually, which might be necessary if Magit - does not notice that a previously untracked file now is being - tracked or vice-versa. - - -- User Option: auto-revert-stop-on-user-input - This option controls whether the arrival of user input suspends the - automatic reverts for ‘auto-revert-interval’ seconds. - - -- User Option: auto-revert-interval - This option controls how many seconds Emacs waits for before - resuming suspended reverts. - - -- User Option: auto-revert-buffer-list-filter - This option specifies an additional filter used by - ‘auto-revert-buffers’ to determine whether a buffer should be - reverted or not. - - This option is provided by Magit, which also advises - ‘auto-revert-buffers’ to respect it. Magit users who do not turn - on the local mode ‘auto-revert-mode’ themselves, are best served by - setting the value to ‘magit-auto-revert-repository-buffer-p’. - - However the default is nil, so as not to disturb users who do use - the local mode directly. If you experience delays when running - Magit commands, then you should consider using one of the - predicates provided by Magit - especially if you also use Tramp. - - Users who do turn on ‘auto-revert-mode’ in buffers in which Magit - doesn’t do that for them, should likely not use any filter. Users - who turn on ‘global-auto-revert-mode’, do not have to worry about - this option, because it is disregarded if the global mode is - enabled. - - -- User Option: auto-revert-verbose - This option controls whether Emacs reports when a buffer has been - reverted. - - The options with the ‘auto-revert-’ prefix are located in the Custom -group named ‘auto-revert’. The other, Magit-specific, options are -located in the ‘magit’ group. - -* Menu: - -* Risk of Reverting Automatically:: - - -File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers - -Risk of Reverting Automatically -............................... - -For the vast majority of users, automatically reverting file-visiting -buffers after they have changed on disk is harmless. - - If a buffer is modified (i.e., it contains changes that haven’t been -saved yet), then Emacs will refuse to automatically revert it. If you -save a previously modified buffer, then that results in what is seen by -Git as an uncommitted change. Git will then refuse to carry out any -commands that would cause these changes to be lost. In other words, if -there is anything that could be lost, then either Git or Emacs will -refuse to discard the changes. - - However, if you use file-visiting buffers as a sort of ad hoc -"staging area", then the automatic reverts could potentially cause data -loss. So far I have heard from only one user who uses such a workflow. - - An example: You visit some file in a buffer, edit it, and save the -changes. Then, outside of Emacs (or at least not using Magit or by -saving the buffer) you change the file on disk again. At this point the -buffer is the only place where the intermediate version still exists. -You have saved the changes to disk, but that has since been overwritten. -Meanwhile Emacs considers the buffer to be unmodified (because you have -not made any changes to it since you last saved it to the visited file) -and therefore would not object to it being automatically reverted. At -this point an Auto-Revert mode would kick in. It would check whether -the buffer is modified and since that is not the case it would revert -it. The intermediate version would be lost. (Actually you could still -get it back using the ‘undo’ command.) - - If your workflow depends on Emacs preserving the intermediate version -in the buffer, then you have to disable all Auto-Revert modes. But -please consider that such a workflow would be dangerous even without -using an Auto-Revert mode, and should therefore be avoided. If Emacs -crashes or if you quit Emacs by mistake, then you would also lose the -buffer content. There would be no autosave file still containing the -intermediate version (because that was deleted when you saved the -buffer) and you would not be asked whether you want to save the buffer -(because it isn’t modified). - - -File: magit.info, Node: Sections, Next: Transient Commands, Prev: Modes and Buffers, Up: Interface Concepts - -4.2 Sections -============ - -Magit buffers are organized into nested sections, which can be collapsed -and expanded, similar to how sections are handled in Org mode. Each -section also has a type, and some sections also have a value. For each -section type there can also be a local keymap, shared by all sections of -that type. - - Taking advantage of the section value and type, many commands operate -on the current section, or when the region is active and selects -sections of the same type, all of the selected sections. Commands that -only make sense for a particular section type (as opposed to just -behaving differently depending on the type) are usually bound in section -type keymaps. - -* Menu: - -* Section Movement:: -* Section Visibility:: -* Section Hooks:: -* Section Types and Values:: -* Section Options:: - - -File: magit.info, Node: Section Movement, Next: Section Visibility, Up: Sections - -4.2.1 Section Movement ----------------------- - -To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’ -etc), whose global bindings are not shadowed. To move to another -section use the following commands. - -‘p’ (‘magit-section-backward’) - When not at the beginning of a section, then move to the beginning - of the current section. At the beginning of a section, instead - move to the beginning of the previous visible section. - -‘n’ (‘magit-section-forward’) - Move to the beginning of the next visible section. - -‘M-p’ (‘magit-section-backward-siblings’) - Move to the beginning of the previous sibling section. If there is - no previous sibling section, then move to the parent section - instead. - -‘M-n’ (‘magit-section-forward-siblings’) - Move to the beginning of the next sibling section. If there is no - next sibling section, then move to the parent section instead. - -‘^’ (‘magit-section-up’) - Move to the beginning of the parent of the current section. - - The above commands all call the hook ‘magit-section-movement-hook’. -Any of the functions listed below can be used as members of this hook. - - You might want to remove some of the functions that Magit adds using -‘add-hook’. In doing so you have to make sure you do not attempt to -remove function that haven’t even been added yet, for example: - - (with-eval-after-load 'magit-diff - (remove-hook 'magit-section-movement-hook - 'magit-hunk-set-window-start)) - - -- Variable: magit-section-movement-hook - This hook is run by all of the above movement commands, after - arriving at the destination. - - -- Function: magit-hunk-set-window-start - This hook function ensures that the beginning of the current - section is visible, provided it is a ‘hunk’ section. Otherwise, it - does nothing. - - Loading ‘magit-diff’ adds this function to the hook. - - -- Function: magit-section-set-window-start - This hook function ensures that the beginning of the current - section is visible, regardless of the section’s type. If you add - this to ‘magit-section-movement-hook’, then you must remove the - hunk-only variant in turn. - - -- Function: magit-log-maybe-show-more-commits - This hook function only has an effect in log buffers, and ‘point’ - is on the "show more" section. If that is the case, then it - doubles the number of commits that are being shown. - - Loading ‘magit-log’ adds this function to the hook. - - -- Function: magit-log-maybe-update-revision-buffer - When moving inside a log buffer, then this function updates the - revision buffer, provided it is already being displayed in another - window of the same frame. - - Loading ‘magit-log’ adds this function to the hook. - - -- Function: magit-log-maybe-update-blob-buffer - When moving inside a log buffer and another window of the same - frame displays a blob buffer, then this function instead displays - the blob buffer for the commit at point in that window. - - -- Function: magit-status-maybe-update-revision-buffer - When moving inside a status buffer, then this function updates the - revision buffer, provided it is already being displayed in another - window of the same frame. - - -- Function: magit-status-maybe-update-stash-buffer - When moving inside a status buffer, then this function updates the - stash buffer, provided it is already being displayed in another - window of the same frame. - - -- Function: magit-status-maybe-update-blob-buffer - When moving inside a status buffer and another window of the same - frame displays a blob buffer, then this function instead displays - the blob buffer for the commit at point in that window. - - -- Function: magit-stashes-maybe-update-stash-buffer - When moving inside a buffer listing stashes, then this function - updates the stash buffer, provided it is already being displayed in - another window of the same frame. - - -- User Option: magit-update-other-window-delay - Delay before automatically updating the other window. - - When moving around in certain buffers, then certain other buffers, - which are being displayed in another window, may optionally be - updated to display information about the section at point. - - When holding down a key to move by more than just one section, then - that would update that buffer for each section on the way. To - prevent that, updating the revision buffer is delayed, and this - option controls for how long. For optimal experience you might - have to adjust this delay and/or the keyboard repeat rate and delay - of your graphical environment or operating system. - - -File: magit.info, Node: Section Visibility, Next: Section Hooks, Prev: Section Movement, Up: Sections - -4.2.2 Section Visibility ------------------------- - -Magit provides many commands for changing the visibility of sections, -but all you need to get started are the next two. - -‘<TAB>’ (‘magit-section-toggle’) - Toggle the visibility of the body of the current section. - -‘C-c <TAB>’ (‘magit-section-cycle’) -‘C-<tab>’ (‘magit-section-cycle’) - Cycle the visibility of current section and its children. - - If this command is invoked using ‘C-<tab>’ and that is globally - bound to ‘tab-next’, then this command pivots to behave like that - command, and you must instead use ‘C-c TAB’ to cycle section - visibility. - - If you would like to keep using ‘C-<tab>’ to cycle section - visibility but also want to use ‘tab-bar-mode’, then you have to - prevent that mode from using this key and instead bind another key - to ‘tab-next’. Because ‘tab-bar-mode’ does not use a mode map but - instead manipulates the global map, this involves advising - ‘tab-bar--define-keys’. - -‘M-<tab>’ (‘magit-section-cycle-diffs’) - Cycle the visibility of diff-related sections in the current - buffer. - -‘S-<tab>’ (‘magit-section-cycle-global’) - Cycle the visibility of all sections in the current buffer. - -‘1’ (‘magit-section-show-level-1’) -‘2’ (‘magit-section-show-level-2’) -‘3’ (‘magit-section-show-level-3’) -‘4’ (‘magit-section-show-level-4’) - Show sections surrounding the current section up to level N. - -‘M-1’ (‘magit-section-show-level-1-all’) -‘M-2’ (‘magit-section-show-level-2-all’) -‘M-3’ (‘magit-section-show-level-3-all’) -‘M-4’ (‘magit-section-show-level-4-all’) - Show all sections up to level N. - - Some functions, which are used to implement the above commands, are -also exposed as commands themselves. By default no keys are bound to -these commands, as they are generally perceived to be much less useful. -But your mileage may vary. - - -- Command: magit-section-show - Show the body of the current section. - - -- Command: magit-section-hide - Hide the body of the current section. - - -- Command: magit-section-show-headings - Recursively show headings of children of the current section. Only - show the headings. Previously shown text-only bodies are hidden. - - -- Command: magit-section-show-children - Recursively show the bodies of children of the current section. - With a prefix argument show children down to the level of the - current section, and hide deeper children. - - -- Command: magit-section-hide-children - Recursively hide the bodies of children of the current section. - - -- Command: magit-section-toggle-children - Toggle visibility of bodies of children of the current section. - - When a buffer is first created then some sections are shown expanded -while others are not. This is hard coded. When a buffer is refreshed -then the previous visibility is preserved. The initial visibility of -certain sections can also be overwritten using the hook -‘magit-section-set-visibility-hook’. - - -- User Option: magit-section-initial-visibility-alist - This options can be used to override the initial visibility of - sections. In the future it will also be used to define the - defaults, but currently a section’s default is still hardcoded. - - The value is an alist. Each element maps a section type or lineage - to the initial visibility state for such sections. The state has - to be one of ‘show’ or ‘hide’, or a function that returns one of - these symbols. A function is called with the section as the only - argument. - - Use the command ‘magit-describe-section-briefly’ to determine a - section’s lineage or type. The vector in the output is the section - lineage and the type is the first element of that vector. - Wildcards can be used, see ‘magit-section-match’. - - -- User Option: magit-section-cache-visibility - This option controls for which sections the previous visibility - state should be restored if a section disappears and later appears - again. The value is a boolean or a list of section types. If t, - then the visibility of all sections is cached. Otherwise this is - only done for sections whose type matches one of the listed types. - - This requires that the function ‘magit-section-cached-visibility’ - is a member of ‘magit-section-set-visibility-hook’. - - -- Variable: magit-section-set-visibility-hook - This hook is run when first creating a buffer and also when - refreshing an existing buffer, and is used to determine the - visibility of the section currently being inserted. - - Each function is called with one argument, the section being - inserted. It should return ‘hide’ or ‘show’, or to leave the - visibility undefined ‘nil’. If no function decides on the - visibility and the buffer is being refreshed, then the visibility - is preserved; or if the buffer is being created, then the hard - coded default is used. - - Usually this should only be used to set the initial visibility but - not during refreshes. If ‘magit-insert-section--oldroot’ is - non-nil, then the buffer is being refreshed and these functions - should immediately return ‘nil’. - - -- User Option: magit-section-visibility-indicator - This option controls whether and how to indicate that a section can - be expanded/collapsed. - - If nil, then no visibility indicators are shown. Otherwise the - value has to have one of these two forms: - - • ‘(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)’ - - Both values have to be variables whose values are fringe - bitmaps. In this case every section that can be expanded or - collapsed gets an indicator in the left fringe. - - To provide extra padding around the indicator, set - ‘left-fringe-width’ in ‘magit-mode-hook’, e.g.: - - (add-hook 'magit-mode-hook (lambda () - (setq left-fringe-width 20))) - - • ‘(STRING . BOOLEAN)’ - - In this case STRING (usually an ellipsis) is shown at the end - of the heading of every collapsed section. Expanded sections - get no indicator. The cdr controls whether the appearance of - these ellipsis take section highlighting into account. Doing - so might potentially have an impact on performance, while not - doing so is kinda ugly. - - -File: magit.info, Node: Section Hooks, Next: Section Types and Values, Prev: Section Visibility, Up: Sections - -4.2.3 Section Hooks -------------------- - -Which sections are inserted into certain buffers is controlled with -hooks. This includes the status and the refs buffers. For other -buffers, e.g., log and diff buffers, this is not possible. The command -‘magit-describe-section’ can be used to see which hook (if any) was -responsible for inserting the section at point. - - For buffers whose sections can be customized by the user, a hook -variable called ‘magit-TYPE-sections-hook’ exists. This hook should be -changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the -Custom interface. - - The various available section hook variables are described later in -this manual along with the appropriate "section inserter functions". - - -- Function: magit-add-section-hook hook function &optional at append - local - Add the function FUNCTION to the value of section hook HOOK. - - Add FUNCTION at the beginning of the hook list unless optional - APPEND is non-nil, in which case FUNCTION is added at the end. If - FUNCTION already is a member then move it to the new location. - - If optional AT is non-nil and a member of the hook list, then add - FUNCTION next to that instead. Add before or after AT, or replace - AT with FUNCTION depending on APPEND. If APPEND is the symbol - ‘replace’, then replace AT with FUNCTION. For any other non-nil - value place FUNCTION right after AT. If nil, then place FUNCTION - right before AT. If FUNCTION already is a member of the list but - AT is not, then leave FUNCTION where ever it already is. - - If optional LOCAL is non-nil, then modify the hook’s buffer-local - value rather than its global value. This makes the hook local by - copying the default value. That copy is then modified. - - HOOK should be a symbol. If HOOK is void, it is first set to nil. - HOOK’s value must not be a single hook function. FUNCTION should - be a function that takes no arguments and inserts one or multiple - sections at point, moving point forward. FUNCTION may choose not - to insert its section(s), when doing so would not make sense. It - should not be abused for other side-effects. - - To remove a function from a section hook, use ‘remove-hook’. - - -File: magit.info, Node: Section Types and Values, Next: Section Options, Prev: Section Hooks, Up: Sections - -4.2.4 Section Types and Values ------------------------------- - -Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’. -Instances of certain section types also have a value. The value of a -section of type ‘file’, for example, is a file name. - - Users usually do not have to worry about a section’s type and value, -but knowing them can be handy at times. - -‘H’ (‘magit-describe-section’) - This command shows information about the section at point in a - separate buffer. - - -- Command: magit-describe-section-briefly - This command shows information about the section at point in the - echo area, as ‘#<magit-section VALUE [TYPE PARENT-TYPE...] - BEGINNING-END>’. - - Many commands behave differently depending on the type of the section -at point and/or somehow consume the value of that section. But that is -only one of the reasons why the same key may do something different, -depending on what section is current. - - Additionally for each section type a keymap *might* be defined, named -‘magit-TYPE-section-map’. That keymap is used as text property keymap -of all text belonging to any section of the respective type. If such a -map does not exist for a certain type, then you can define it yourself, -and it will automatically be used. - - -File: magit.info, Node: Section Options, Prev: Section Types and Values, Up: Sections - -4.2.5 Section Options ---------------------- - -This section describes options that have an effect on more than just a -certain type of sections. As you can see there are not many of those. - - -- User Option: magit-section-show-child-count - Whether to append the number of children to section headings. This - only affects sections that could benefit from this information. - - -File: magit.info, Node: Transient Commands, Next: Transient Arguments and Buffer Variables, Prev: Sections, Up: Interface Concepts - -4.3 Transient Commands -====================== - -Many Magit commands are implemented as *transient* commands. First the -user invokes a *prefix* command, which causes its *infix* arguments and -*suffix* commands to be displayed in the echo area. The user then -optionally sets some infix arguments and finally invokes one of the -suffix commands. - - This is implemented in the library ‘transient’. Earlier Magit -releases used the package ‘magit-popup’ and even earlier versions -library ‘magit-key-mode’. - - Transient is documented in *note (transient)Top::. - -‘C-x M-g’ (‘magit-dispatch’) -‘C-c g’ (‘magit-dispatch’) - This transient prefix command binds most of Magit’s other prefix - commands as suffix commands and displays them in a temporary buffer - until one of them is invoked. Invoking such a sub-prefix causes - the suffixes of that command to be bound and displayed instead of - those of ‘magit-dispatch’. - - This command is also, or especially, useful outside Magit buffers, - so Magit by default binds it to ‘C-c M-g’ in the global keymap. - ‘C-c g’ would be a better binding, but we cannot use that by - default, because that key sequence is reserved for the user. See - *note Global Bindings:: to learn more default and recommended key - bindings. - - -File: magit.info, Node: Transient Arguments and Buffer Variables, Next: Completion Confirmation and the Selection, Prev: Transient Commands, Up: Interface Concepts - -4.4 Transient Arguments and Buffer Variables -============================================ - -The infix arguments of many of Magit’s transient prefix commands cease -to have an effect once the ‘git’ command that is called with those -arguments has returned. Commands that create a commit are a good -example for this. If the user changes the arguments, then that only -affects the next invocation of a suffix command. If the same transient -prefix command is later invoked again, then the arguments are initially -reset to the default value. This default value can be set for the -current Emacs session or saved permanently, see *note (transient)Saving -Values::. It is also possible to cycle through previously used sets of -arguments using ‘C-M-p’ and ‘C-M-n’, see *note (transient)Using -History::. - - However the infix arguments of many other transient commands continue -to have an effect even after the ‘git’ command that was called with -those arguments has returned. The most important commands like this are -those that display a diff or log in a dedicated buffer. Their arguments -obviously continue to have an effect for as long as the respective diff -or log is being displayed. Furthermore the used arguments are stored in -buffer-local variables for future reference. - - For commands in the second group it isn’t always desirable to reset -their arguments to the global value when the transient prefix command is -invoked again. - - As mentioned above, it is possible to cycle through previously used -sets of arguments while a transient popup is visible. That means that -we could always reset the infix arguments to the default because the set -of arguments that is active in the existing buffer is only a few ‘C-M-p’ -away. Magit can be configured to behave like that, but because I expect -that most users would not find that very convenient, it is not the -default. - - Also note that it is possible to change the diff and log arguments -used in the current buffer (including the status buffer, which contains -both diff and log sections) using the respective "refresh" transient -prefix commands on ‘D’ and ‘L’. (‘d’ and ‘l’ on the other hand are -intended to change *what* diff or log is being displayed. It is -possible to also change *how* the diff or log is being displayed at the -same time, but if you only want to do the latter, then you should use -the refresh variants.) Because these secondary diff and log transient -prefixes are about *changing* the arguments used in the current buffer, -they *always* start out with the set of arguments that are currently in -effect in that buffer. - - Some commands are usually invoked directly even though they can also -be invoked as the suffix of a transient prefix command. Most -prominently ‘magit-show-commit’ is usually invoked by typing ‘RET’ while -point is on a commit in a log, but it can also be invoked from the -‘magit-diff’ transient prefix. - - When such a command is invoked directly, then it is important to -reuse the arguments as specified by the respective buffer-local values, -instead of using the default arguments. Imagine you press ‘RET’ in a -log to display the commit at point in a different buffer and then use -‘D’ to change how the diff is displayed in that buffer. And then you -press ‘RET’ on another commit to show that instead and the diff -arguments are reset to the default. Not cool; so Magit does not do that -by default. - - -- User Option: magit-prefix-use-buffer-arguments - This option controls whether the infix arguments initially shown in - certain transient prefix commands are based on the arguments that - are currently in effect in the buffer that their suffixes update. - - The ‘magit-diff’ and ‘magit-log’ transient prefix commands are - affected by this option. - - -- User Option: magit-direct-use-buffer-arguments - This option controls whether certain commands, when invoked - directly (i.e., not as the suffix of a transient prefix command), - use the arguments that are currently active in the buffer that they - are about to update. The alternative is to use the default value - for these arguments, which might change the arguments that are used - in the buffer. - -Valid values for both of the above options are: - - • ‘always’: Always use the set of arguments that is currently active - in the respective buffer, provided that buffer exists of course. - • ‘selected’ or ‘t’: Use the set of arguments from the respective - buffer, but only if it is displayed in a window of the current - frame. This is the default for both variables. - • ‘current’: Use the set of arguments from the respective buffer, but - only if it is the current buffer. - • ‘never’: Never use the set of arguments from the respective buffer. - -I am afraid it gets more complicated still: - - • The global diff and log arguments are set for each supported mode - individually. The diff arguments for example have different values - in ‘magit-diff-mode’, ‘magit-revision-mode’, - ‘magit-merge-preview-mode’ and ‘magit-status-mode’ buffers. - Setting or saving the value for one mode does not change the value - for other modes. The history however is shared. - - • When ‘magit-show-commit’ is invoked directly from a log buffer, - then the file filter is picked up from that buffer, not from the - revision buffer or the mode’s global diff arguments. - - • Even though they are suffixes of the diff prefix - ‘magit-show-commit’ and ‘magit-stash-show’ do not use the diff - buffer used by the diff commands, instead they use the dedicated - revision and stash buffers. - - At the time you invoke the diff prefix it is unknown to Magit which - of the suffix commands you are going to invoke. While not certain, - more often than not users invoke one of the commands that use the - diff buffer, so the initial infix arguments are those used in that - buffer. However if you invoke one of these commands directly, then - Magit knows that it should use the arguments from the revision - resp. stash buffer. - - • The log prefix also features reflog commands, but these commands do - not use the log arguments. - - • If ‘magit-show-refs’ is invoked from a ‘magit-refs-mode’ buffer, - then it acts as a refresh prefix and therefore unconditionally uses - the buffer’s arguments as initial arguments. If it is invoked - elsewhere with a prefix argument, then it acts as regular prefix - and therefore respects ‘magit-prefix-use-buffer-arguments’. If it - is invoked elsewhere without a prefix argument, then it acts as a - direct command and therefore respects - ‘magit-direct-use-buffer-arguments’. - - -File: magit.info, Node: Completion Confirmation and the Selection, Next: Mouse Support, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts - -4.5 Completion, Confirmation and the Selection -============================================== - -* Menu: - -* Action Confirmation:: -* Completion and Confirmation:: -* The Selection:: -* The hunk-internal region:: -* Support for Completion Frameworks:: -* Additional Completion Options:: - - -File: magit.info, Node: Action Confirmation, Next: Completion and Confirmation, Up: Completion Confirmation and the Selection - -4.5.1 Action Confirmation -------------------------- - -By default many actions that could potentially lead to data loss have to -be confirmed. This includes many very common actions, so this can -quickly become annoying. Many of these actions can be undone and if you -have thought about how to undo certain mistakes, then it should be safe -to disable confirmation for the respective actions. - - The option ‘magit-no-confirm’ can be used to tell Magit to perform -certain actions without the user having to confirm them. Note that -while this option can only be used to disable confirmation for a -specific set of actions, the next section explains another way of -telling Magit to ask fewer questions. - - -- User Option: magit-no-confirm - The value of this option is a list of symbols, representing actions - that do not have to be confirmed by the user before being carried - out. - - By default many potentially dangerous commands ask the user for - confirmation. Each of the below symbols stands for an action - which, when invoked unintentionally or without being fully aware of - the consequences, could lead to tears. In many cases there are - several commands that perform variations of a certain action, so we - don’t use the command names but more generic symbols. - - • Applying changes: - - • ‘discard’ Discarding one or more changes (i.e., hunks or - the complete diff for a file) loses that change, - obviously. - - • ‘reverse’ Reverting one or more changes can usually be - undone by reverting the reversion. - - • ‘stage-all-changes’, ‘unstage-all-changes’ When there are - both staged and unstaged changes, then un-/staging - everything would destroy that distinction. Of course - that also applies when un-/staging a single change, but - then less is lost and one does that so often that having - to confirm every time would be unacceptable. - - • Files: - - • ‘delete’ When a file that isn’t yet tracked by Git is - deleted, then it is completely lost, not just the last - changes. Very dangerous. - - • ‘trash’ Instead of deleting a file it can also be move to - the system trash. Obviously much less dangerous than - deleting it. - - Also see option ‘magit-delete-by-moving-to-trash’. - - • ‘resurrect’ A deleted file can easily be resurrected by - "deleting" the deletion, which is done using the same - command that was used to delete the same file in the - first place. - - • ‘untrack’ Untracking a file can be undone by tracking it - again. - - • ‘rename’ Renaming a file can easily be undone. - - • Sequences: - - • ‘reset-bisect’ Aborting (known to Git as "resetting") a - bisect operation loses all information collected so far. - - • ‘abort-cherry-pick’ Aborting a cherry-pick throws away - all conflict resolutions which have already been carried - out by the user. - - • ‘abort-revert’ Aborting a revert throws away all conflict - resolutions which have already been carried out by the - user. - - • ‘abort-rebase’ Aborting a rebase throws away all already - modified commits, but it’s possible to restore those from - the reflog. - - • ‘abort-merge’ Aborting a merge throws away all conflict - resolutions which have already been carried out by the - user. - - • ‘merge-dirty’ Merging with a dirty worktree can make it - hard to go back to the state before the merge was - initiated. - - • References: - - • ‘delete-unmerged-branch’ Once a branch has been deleted, - it can only be restored using low-level recovery tools - provided by Git. And even then the reflog is gone. The - user always has to confirm the deletion of a branch by - accepting the default choice (or selecting another - branch), but when a branch has not been merged yet, also - make sure the user is aware of that. - - • ‘delete-pr-remote’ When deleting a branch that was - created from a pull-request and if no other branches - still exist on that remote, then ‘magit-branch-delete’ - offers to delete the remote as well. This should be safe - because it only happens if no other refs exist in the - remotes namespace, and you can recreate the remote if - necessary. - - • ‘drop-stashes’ Dropping a stash is dangerous because Git - stores stashes in the reflog. Once a stash is removed, - there is no going back without using low-level recovery - tools provided by Git. When a single stash is dropped, - then the user always has to confirm by accepting the - default (or selecting another). This action only - concerns the deletion of multiple stashes at once. - - • Publishing: - - • ‘set-and-push’ When pushing to the upstream or the - push-remote and that isn’t actually configured yet, then - the user can first set the target. If s/he confirms the - default too quickly, then s/he might end up pushing to - the wrong branch and if the remote repository is - configured to disallow fixing such mistakes, then that - can be quite embarrassing and annoying. - - • Edit published history: - - Without adding these symbols here, you will be warned before - editing commits that have already been pushed to one of the - branches listed in ‘magit-published-branches’. - - • ‘amend-published’ Affects most commands that amend to - "HEAD". - - • ‘rebase-published’ Affects commands that perform - interactive rebases. This includes commands from the - commit transient that modify a commit other than "HEAD", - namely the various fixup and squash variants. - - • ‘edit-published’ Affects the commands - ‘magit-edit-line-commit’ and - ‘magit-diff-edit-hunk-commit’. These two commands make - it quite easy to accidentally edit a published commit, so - you should think twice before configuring them not to ask - for confirmation. - - To disable confirmation completely, add all three symbols here - or set ‘magit-published-branches’ to ‘nil’. - - • Various: - - • ‘stash-apply-3way’ When a stash cannot be applied using - ‘git stash apply’, then Magit uses ‘git apply’ instead, - possibly using the ‘--3way’ argument, which isn’t always - perfectly safe. See also ‘magit-stash-apply’. - - • ‘kill-process’ There seldom is a reason to kill a - process. - - • Global settings: - - Instead of adding all of the above symbols to the value of - this option, you can also set it to the atom ‘t’, which has - the same effect as adding all of the above symbols. Doing - that most certainly is a bad idea, especially because other - symbols might be added in the future. So even if you don’t - want to be asked for confirmation for any of these actions, - you are still better of adding all of the respective symbols - individually. - - When ‘magit-wip-before-change-mode’ is enabled, then the - following actions can be undone fairly easily: ‘discard’, - ‘reverse’, ‘stage-all-changes’, and ‘unstage-all-changes’. If - and only if this mode is enabled, then ‘safe-with-wip’ has the - same effect as adding all of these symbols individually. - - -File: magit.info, Node: Completion and Confirmation, Next: The Selection, Prev: Action Confirmation, Up: Completion Confirmation and the Selection - -4.5.2 Completion and Confirmation ---------------------------------- - -Many Magit commands ask the user to select from a list of possible -things to act on, while offering the most likely choice as the default. -For many of these commands the default is the thing at point, provided -that it actually is a valid thing to act on. For many commands that act -on a branch, the current branch serves as the default if there is no -branch at point. - - These commands combine asking for confirmation and asking for a -target to act on into a single action. The user can confirm the default -target using ‘RET’ or abort using ‘C-g’. This is similar to a -‘y-or-n-p’ prompt, but the keys to confirm or abort differ. - - At the same time the user is also given the opportunity to select -another target, which is useful because for some commands and/or in some -situations you might want to select the action before selecting the -target by moving to it. - - However you might find that for some commands you always want to use -the default target, if any, or even that you want the command to act on -the default without requiring any confirmation at all. The option -‘magit-dwim-selection’ can be used to configure certain commands to that -effect. - - Note that when the region is active then many commands act on the -things that are selected using a mechanism based on the region, in many -cases after asking for confirmation. This region-based mechanism is -called the "selection" and is described in detail in the next section. -When a selection exists that is valid for the invoked command, then that -command never offers to act on something else, and whether it asks for -confirmation is not controlled by this option. - - Also note that Magit asks for confirmation of certain actions that -are not coupled with completion (or the selection). Such dialogs are -also not affected by this option and are described in the previous -section. - - -- User Option: magit-dwim-selection - This option can be used to tell certain commands to use the thing at -point instead of asking the user to select a candidate to act on, with -or without confirmation. - - The value has the form ‘((COMMAND nil|PROMPT DEFAULT)...)’. - - • COMMAND is the command that should not prompt for a choice. To - have an effect, the command has to use the function - ‘magit-completing-read’ or a utility function which in turn uses - that function. - - • If the command uses ‘magit-completing-read’ multiple times, then - PROMPT can be used to only affect one of these uses. PROMPT, if - non-nil, is a regular expression that is used to match against the - PROMPT argument passed to ‘magit-completing-read’. - - • DEFAULT specifies how to use the default. If it is ‘t’, then the - DEFAULT argument passed to ‘magit-completing-read’ is used without - confirmation. If it is ‘ask’, then the user is given a chance to - abort. DEFAULT can also be ‘nil’, in which case the entry has no - effect. - - -File: magit.info, Node: The Selection, Next: The hunk-internal region, Prev: Completion and Confirmation, Up: Completion Confirmation and the Selection - -4.5.3 The Selection -------------------- - -If the region is active, then many Magit commands act on the things that -are selected using a mechanism based on the region instead of one single -thing. When the region is not active, then these commands act on the -thing at point or read a single thing to act on. This is described in -the previous section — this section only covers how multiple things are -selected, how that is visualized, and how certain commands behave when -that is the case. - - Magit’s mechanism for selecting multiple things, or rather sections -that represent these things, is based on the Emacs region, but the area -that Magit considers to be selected is typically larger than the region -and additional restrictions apply. - - Magit makes a distinction between a region that qualifies as forming -a valid Magit selection and a region that does not. If the region does -not qualify, then it is displayed as it is in other Emacs buffers. If -the region does qualify as a Magit selection, then the selection is -always visualized, while the region itself is only visualized if it -begins and ends on the same line. - - For a region to qualify as a Magit selection, it must begin in the -heading of one section and end in the heading of a sibling section. -Note that if the end of the region is at the very beginning of section -heading (i.e., at the very beginning of a line) then that section is -considered to be *inside* the selection. - - This is not consistent with how the region is normally treated in -Emacs — if the region ends at the beginning of a line, then that line is -outside the region. Due to how Magit visualizes the selection, it -should be obvious that this difference exists. - - Not every command acts on every valid selection. Some commands do -not even consider the location of point, others may act on the section -at point but not support acting on the selection, and even commands that -do support the selection of course only do so if it selects things that -they can act on. - - This is the main reason why the selection must include the section at -point. Even if a selection exists, the invoked command may disregard -it, in which case it may act on the current section only. It is much -safer to only act on the current section but not the other selected -sections than it is to act on the current section *instead* of the -selected sections. The latter would be much more surprising and if the -current section always is part of the selection, then that cannot -happen. - - -- Variable: magit-keep-region-overlay - This variable controls whether the region is visualized as usual - even when a valid Magit selection or a hunk-internal region exists. - See the doc-string for more information. - - -File: magit.info, Node: The hunk-internal region, Next: Support for Completion Frameworks, Prev: The Selection, Up: Completion Confirmation and the Selection - -4.5.4 The hunk-internal region ------------------------------- - -Somewhat related to the Magit selection described in the previous -section is the hunk-internal region. - - Like the selection, the hunk-internal region is based on the Emacs -region but causes that region to not be visualized as it would in other -Emacs buffers, and includes the line on which the region ends even if it -ends at the very beginning of that line. - - Unlike the selection, which is based on a region that must begin in -the heading of one section and ends in the section of a sibling section, -the hunk-internal region must begin inside the *body* of a hunk section -and end in the body of the *same* section. - - The hunk-internal region is honored by "apply" commands, which can, -among other targets, act on a hunk. If the hunk-internal region is -active, then such commands act only on the marked part of the hunk -instead of on the complete hunk. - - -File: magit.info, Node: Support for Completion Frameworks, Next: Additional Completion Options, Prev: The hunk-internal region, Up: Completion Confirmation and the Selection - -4.5.5 Support for Completion Frameworks ---------------------------------------- - -The built-in option ‘completing-read-function’ specifies the low-level -function used by ‘completing-read’ to ask a user to select from a list -of choices. Its default value is ‘completing-read-default’. -Alternative completion frameworks typically activate themselves by -substituting their own implementation. - - Mostly for historic reasons Magit provides a similar option named -‘magit-completing-read-function’, which only controls the low-level -function used by ‘magit-completing-read’. This option also makes it -possible to use a different completing mechanism for Magit than for the -rest of Emacs, but doing that is not recommend. - - You most likely don’t have to customize the magit-specific option to -use an alternative completion framework. For example, if you enable -‘ivy-mode’, then Magit will respect that, and if you enable ‘helm-mode’, -then you are done too. - - However if you want to use Ido, then ‘ido-mode’ won’t do the trick. -You will also have to install the ‘ido-completing-read+’ package and use -‘magit-ido-completing-read’ as ‘magit-completing-read-function’. - - -- User Option: magit-completing-read-function - The value of this variable is the low-level function used to - perform completion by code that uses ‘magit-completing-read’ (as - opposed to the built-in ‘completing-read’). - - The default value, ‘magit-builtin-completing-read’, is suitable for - the standard completion mechanism, ‘ivy-mode’, and ‘helm-mode’ at - least. - - The built-in ‘completing-read’ and ‘completing-read-default’ are - *not* suitable to be used here. ‘magit-builtin-completing-read’ - performs some additional work, and any function used in its place - has to do the same. - - -- Function: magit-builtin-completing-read prompt choices &optional - predicate require-match initial-input hist def - This function performs completion using the built-in - ‘completing-read’ and does some additional magit-specific work. - - -- Function: magit-ido-completing-read prompt choices &optional - predicate require-match initial-input hist def - This function performs completion using ‘ido-completing-read+’ from - the package by the same name (which you have to explicitly install) - and does some additional magit-specific work. - - We have to use ‘ido-completing-read+’ instead of the - ‘ido-completing-read’ that comes with Ido itself, because the - latter, while intended as a drop-in replacement, cannot serve that - purpose because it violates too many of the implicit conventions. - - -- Function: magit-completing-read prompt choices &optional predicate - require-match initial-input hist def fallback - This is the function that Magit commands use when they need the - user to select a single thing to act on. The arguments have the - same meaning as for ‘completing-read’, except for FALLBACK, which - is unique to this function and is described below. - - Instead of asking the user to choose from a list of possible - candidates, this function may just return the default specified by - DEF, with or without requiring user confirmation. Whether that is - the case depends on PROMPT, ‘this-command’ and - ‘magit-dwim-selection’. See the documentation of the latter for - more information. - - If it does read a value in the minibuffer, then this function acts - similar to ‘completing-read’, except for the following: - - • COLLECTION must be a list of choices. A function is not - supported. - - • If REQUIRE-MATCH is ‘nil’ and the user exits without a choice, - then ‘nil’ is returned instead of an empty string. - - • If REQUIRE-MATCH is non-nil and the users exits without a - choice, an user-error is raised. - - • FALLBACK specifies a secondary default that is only used if - the primary default DEF is ‘nil’. The secondary default is - not subject to ‘magit-dwim-selection’ — if DEF is ‘nil’ but - FALLBACK is not, then this function always asks the user to - choose a candidate, just as if both defaults were ‘nil’. - - • ‘format-prompt’ is called on PROMPT and DEF (or FALLBACK if - DEF is ‘nil’). This appends ": " to the prompt and may also - add the default to the prompt, using the format specified by - ‘minibuffer-default-prompt-format’ and depending on - ‘magit-completing-read-default-prompt-predicate’. - - -File: magit.info, Node: Additional Completion Options, Prev: Support for Completion Frameworks, Up: Completion Confirmation and the Selection - -4.5.6 Additional Completion Options ------------------------------------ - - -- User Option: magit-list-refs-sortby - For many commands that read a ref or refs from the user, the value - of this option can be used to control the order of the refs. Valid - values include any key accepted by the ‘--sort’ flag of ‘git - for-each-ref’. By default, refs are sorted alphabetically by their - full name (e.g., "refs/heads/master"). - - -File: magit.info, Node: Mouse Support, Next: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts - -4.6 Mouse Support -================= - -Double clicking on a section heading toggles the visibility of its body, -if any. Likewise clicking in the left fringe toggles the visibility of -the appropriate section. - - A context menu is provided but has to be enabled explicitly. In -Emacs 28 and greater, enable the global mode ‘context-menu-mode’. If -you use an older Emacs release, set -‘magit-section-show-context-menu-for-emacs<28’. - - -File: magit.info, Node: Running Git, Prev: Mouse Support, Up: Interface Concepts - -4.7 Running Git -=============== - -* Menu: - -* Viewing Git Output:: -* Git Process Status:: -* Running Git Manually:: -* Git Executable:: -* Global Git Arguments:: - - -File: magit.info, Node: Viewing Git Output, Next: Git Process Status, Up: Running Git - -4.7.1 Viewing Git Output ------------------------- - -Magit runs Git either for side-effects (e.g., when pushing) or to get -some value (e.g., the name of the current branch). - - When Git is run for side-effects, the process output is logged in a -per-repository log buffer, which can be consulted using the -‘magit-process’ command when things don’t go as expected. - - The output/errors for up to ‘magit-process-log-max’ Git commands are -retained. - -‘$’ (‘magit-process’) - This commands displays the process buffer for the current - repository. - - Inside that buffer, the usual key bindings for navigating and showing -sections are available. There is one additional command. - -‘k’ (‘magit-process-kill’) - This command kills the process represented by the section at point. - - -- Variable: magit-git-debug - This option controls whether additional reporting of git errors is - enabled. - - Magit basically calls git for one of these two reasons: for - side-effects or to do something with its standard output. - - When git is run for side-effects then its output, including error - messages, go into the process buffer which is shown when using ‘$’. - - When git’s output is consumed in some way, then it would be too - expensive to also insert it into this buffer, but when this option - is non-nil and git returns with a non-zero exit status, then at - least its standard error is inserted into this buffer. - - This is only intended for debugging purposes. Do not enable this - permanently, that would negatively affect performance. - - This is only intended for debugging purposes. Do not enable this - permanently, that would negatively affect performance. Also note - that just because git exits with a non-zero exit status and prints - an error message that usually doesn’t mean that it is an error as - far as Magit is concerned, which is another reason we usually hide - these error messages. Whether some error message is relevant in - the context of some unexpected behavior has to be judged on a case - by case basis. - - The command ‘magit-toggle-git-debug’ changes the value of this - variable. - - -- Variable: magit-process-extreme-logging - This option controls whether ‘magit-process-file’ logs to the - ‘*Messages*’ buffer. - - Only intended for temporary use when you try to figure out how - Magit uses Git behind the scene. Output that normally goes to the - magit-process buffer continues to go there. Not all output goes to - either of these two buffers. - - -File: magit.info, Node: Git Process Status, Next: Running Git Manually, Prev: Viewing Git Output, Up: Running Git - -4.7.2 Git Process Status ------------------------- - -When a Git process is running for side-effects, Magit displays an -indicator in the mode line, using the ‘magit-mode-line-process’ face. - - If the Git process exits successfully, the process indicator is -removed from the mode line immediately. - - In the case of a Git error, the process indicator is not removed, but -is instead highlighted with the ‘magit-mode-line-process-error’ face, -and the error details from the process buffer are provided as a tooltip -for mouse users. This error indicator persists in the mode line until -the next magit buffer refresh. - - If you do not wish process errors to be indicated in the mode line, -customize the ‘magit-process-display-mode-line-error’ user option. - - Process errors are additionally indicated at the top of the status -buffer. - - -File: magit.info, Node: Running Git Manually, Next: Git Executable, Prev: Git Process Status, Up: Running Git - -4.7.3 Running Git Manually --------------------------- - -While Magit provides many Emacs commands to interact with Git, it does -not cover everything. In those cases your existing Git knowledge will -come in handy. Magit provides some commands for running arbitrary Git -commands by typing them into the minibuffer, instead of having to switch -to a shell. - -‘!’ (‘magit-run’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘! !’ (‘magit-git-command-topdir’) - This command reads a command from the user and executes it in the - top-level directory of the current working tree. - - The string "git " is used as initial input when prompting the user - for the command. It can be removed to run another command. - -‘:’ (‘magit-git-command’) -‘! p’ - This command reads a command from the user and executes it in - ‘default-directory’. With a prefix argument the command is - executed in the top-level directory of the current working tree - instead. - - The string "git " is used as initial input when prompting the user - for the command. It can be removed to run another command. - -‘! s’ (‘magit-shell-command-topdir’) - This command reads a command from the user and executes it in the - top-level directory of the current working tree. - -‘! S’ (‘magit-shell-command’) - This command reads a command from the user and executes it in - ‘default-directory’. With a prefix argument the command is - executed in the top-level directory of the current working tree - instead. - - -- User Option: magit-shell-command-verbose-prompt - Whether the prompt, used by the above commands when reading a shell - command, shows the directory in which it will be run. - - These suffix commands start external gui tools. - -‘! k’ (‘magit-run-gitk’) - This command runs ‘gitk’ in the current repository. - -‘! a’ (‘magit-run-gitk-all’) - This command runs ‘gitk --all’ in the current repository. - -‘! b’ (‘magit-run-gitk-branches’) - This command runs ‘gitk --branches’ in the current repository. - -‘! g’ (‘magit-run-git-gui’) - This command runs ‘git gui’ in the current repository. - -‘! m’ (‘magit-git-mergetool’) - This command runs ‘git mergetool --gui’ in the current repository. - - With a prefix argument this acts as a transient prefix command, - allowing the user to select the mergetool and change some settings. - - -File: magit.info, Node: Git Executable, Next: Global Git Arguments, Prev: Running Git Manually, Up: Running Git - -4.7.4 Git Executable --------------------- - -When Magit calls Git, then it may do so using the absolute path to the -‘git’ executable, or using just its name. - - When running ‘git’ locally and the ‘system-type’ is ‘windows-nt’ (any -Windows version) or ‘darwin’ (macOS) then ‘magit-git-executable’ is set -to an absolute path when Magit is loaded. - - On Windows it is necessary to use an absolute path because Git comes -with several wrapper scripts for the actual ‘git’ binary, which are also -placed on ‘$PATH’, and using one of these wrappers instead of the binary -would degrade performance horribly. For some macOS users using just the -name of the executable also performs horribly, so we avoid doing that on -that platform as well. On other platforms, using just the name seems to -work just fine. - - Using an absolute path when running ‘git’ on a remote machine over -Tramp, would be problematic to use an absolute path that is suitable on -the local machine, so a separate option is used to control the name or -path that is used on remote machines. - - -- User Option: magit-git-executable - The ‘git’ executable used by Magit on the local host. This should - be either the absolute path to the executable, or the string "git" - to let Emacs find the executable itself, using the standard - mechanism for doing such things. - - -- User Option: magit-remote-git-executable - The ‘git’ executable used by Magit on remote machines over Tramp. - Normally this should be just the string "git". Consider - customizing ‘tramp-remote-path’ instead of this option. - - If Emacs is unable to find the correct executable, then you can work -around that by explicitly setting the value of one of these two options. -Doing that should be considered a kludge; it is better to make sure that -the order in ‘exec-path’ or ‘tramp-remote-path’ is correct. - - Note that ‘exec-path’ is set based on the value of the ‘PATH’ -environment variable that is in effect when Emacs is started. If you -set ‘PATH’ in your shell’s init files, then that only has an effect on -Emacs if you start it from that shell (because the environment of a -process is only passed to its child processes, not to arbitrary other -processes). If that is not how you start Emacs, then the -‘exec-path-from-shell’ package can help; though honestly I consider that -a kludge too. - - The command ‘magit-debug-git-executable’ can be useful to find out -where Emacs is searching for ‘git’. - -‘M-x magit-debug-git-executable’ - This command displays a buffer with information about - ‘magit-git-executable’ and ‘magit-remote-git-executable’. - -‘M-x magit-version’ - This command shows the currently used versions of Magit, Git, and - Emacs in the echo area. Non-interactively this just returns the - Magit version. - - -File: magit.info, Node: Global Git Arguments, Prev: Git Executable, Up: Running Git - -4.7.5 Global Git Arguments --------------------------- - - -- User Option: magit-git-global-arguments - The arguments set here are used every time the git executable is - run as a subprocess. They are placed right after the executable - itself and before the git command - as in ‘git HERE... COMMAND - REST’. For valid arguments see *note (gitman)git::. - - Be careful what you add here, especially if you are using Tramp to - connect to servers with ancient Git versions. Never remove - anything that is part of the default value, unless you really know - what you are doing. And think very hard before adding something; - it will be used every time Magit runs Git for any purpose. - - -File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface Concepts, Up: Top - -5 Inspecting -************ - -The functionality provided by Magit can be roughly divided into three -groups: inspecting existing data, manipulating existing data or adding -new data, and transferring data. Of course that is a rather crude -distinction that often falls short, but it’s more useful than no -distinction at all. This section is concerned with inspecting data, the -next two with manipulating and transferring it. Then follows a section -about miscellaneous functionality, which cannot easily be fit into this -distinction. - - Of course other distinctions make sense too, e.g., Git’s distinction -between porcelain and plumbing commands, which for the most part is -equivalent to Emacs’ distinction between interactive commands and -non-interactive functions. All of the sections mentioned before are -mainly concerned with the porcelain – Magit’s plumbing layer is -described later. - -* Menu: - -* Status Buffer:: -* Repository List:: -* Logging:: -* Diffing:: -* Ediffing:: -* References Buffer:: -* Bisecting:: -* Visiting Files and Blobs:: -* Blaming:: - - -File: magit.info, Node: Status Buffer, Next: Repository List, Up: Inspecting - -5.1 Status Buffer -================= - -While other Magit buffers contain, e.g., one particular diff or one -particular log, the status buffer contains the diffs for staged and -unstaged changes, logs for unpushed and unpulled commits, lists of -stashes and untracked files, and information related to the current -branch. - - During certain incomplete operations – for example when a merge -resulted in a conflict – additional information is displayed that helps -proceeding with or aborting the operation. - - The command ‘magit-status’ displays the status buffer belonging to -the current repository in another window. This command is used so often -that it should be bound globally. We recommend using ‘C-x g’: - - (global-set-key (kbd "C-x g") 'magit-status) - -‘C-x g’ (‘magit-status’) - When invoked from within an existing Git repository, then this - command shows the status of that repository in a buffer. - - If the current directory isn’t located within a Git repository, - then this command prompts for an existing repository or an - arbitrary directory, depending on the option - ‘magit-repository-directories’, and the status for the selected - repository is shown instead. - - • If that option specifies any existing repositories, then the - user is asked to select one of them. - - • Otherwise the user is asked to select an arbitrary directory - using regular file-name completion. If the selected directory - is the top-level directory of an existing working tree, then - the status buffer for that is shown. - - • Otherwise the user is offered to initialize the selected - directory as a new repository. After creating the repository - its status buffer is shown. - - These fallback behaviors can also be forced using one or more - prefix arguments: - - • With two prefix arguments (or more precisely a numeric prefix - value of 16 or greater) an arbitrary directory is read, which - is then acted on as described above. The same could be - accomplished using the command ‘magit-init’. - - • With a single prefix argument an existing repository is read - from the user, or if no repository can be found based on the - value of ‘magit-repository-directories’, then the behavior is - the same as with two prefix arguments. - - -- User Option: magit-repository-directories - List of directories that are Git repositories or contain Git - repositories. - - Each element has the form ‘(DIRECTORY . DEPTH)’. DIRECTORY has to - be a directory or a directory file-name, a string. DEPTH, an - integer, specifies the maximum depth to look for Git repositories. - If it is 0, then only add DIRECTORY itself. - - This option controls which repositories are being listed by - ‘magit-list-repositories’. It also affects ‘magit-status’ (which - see) in potentially surprising ways (see above). - - -- Command: magit-status-quick - This command is an alternative to ‘magit-status’ that usually - avoids refreshing the status buffer. - - If the status buffer of the current Git repository exists but isn’t - being displayed in the selected frame, then it is displayed without - being refreshed. - - If the status buffer is being displayed in the selected frame, then - this command refreshes it. - - Prefix arguments have the same meaning as for ‘magit-status’, and - additionally cause the buffer to be refresh. - - To use this command add this to your init file: - - (global-set-key (kbd "C-x g") 'magit-status-quick). - - If you do that and then for once want to redisplay the buffer and - also immediately refresh it, then type ‘C-x g’ followed by ‘g’. - - A possible alternative command is - ‘magit-display-repository-buffer’. It supports displaying any - existing Magit buffer that belongs to the current repository; not - just the status buffer. - - -- Command: ido-enter-magit-status - From an Ido prompt used to open a file, instead drop into - ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which, - despite its name, usually causes a Dired buffer to be created. - - To make this command available, use something like: - - (add-hook 'ido-setup-hook - (lambda () - (define-key ido-completion-map - (kbd \"C-x g\") 'ido-enter-magit-status))) - - Starting with Emacs 25.1 the Ido keymaps are defined just once - instead of every time Ido is invoked, so now you can modify it like - pretty much every other keymap: - - (define-key ido-common-completion-map - (kbd \"C-x g\") 'ido-enter-magit-status) - -* Menu: - -* Status Sections:: -* Status Header Sections:: -* Status Module Sections:: -* Status Options:: - - -File: magit.info, Node: Status Sections, Next: Status Header Sections, Up: Status Buffer - -5.1.1 Status Sections ---------------------- - -The contents of status buffers is controlled using the hook -‘magit-status-sections-hook’. See *note Section Hooks:: to learn about -such hooks and how to customize them. - - -- User Option: magit-status-sections-hook - Hook run to insert sections into a status buffer. - - The first function on that hook by default is -‘magit-insert-status-headers’; it is described in the next section. By -default the following functions are also members of that hook: - - -- Function: magit-insert-merge-log - Insert section for the on-going merge. Display the heads that are - being merged. If no merge is in progress, do nothing. - - -- Function: magit-insert-rebase-sequence - Insert section for the on-going rebase sequence. If no such - sequence is in progress, do nothing. - - -- Function: magit-insert-am-sequence - Insert section for the on-going patch applying sequence. If no - such sequence is in progress, do nothing. - - -- Function: magit-insert-sequencer-sequence - Insert section for the on-going cherry-pick or revert sequence. If - no such sequence is in progress, do nothing. - - -- Function: magit-insert-bisect-output - While bisecting, insert section with output from ‘git bisect’. - - -- Function: magit-insert-bisect-rest - While bisecting, insert section visualizing the bisect state. - - -- Function: magit-insert-bisect-log - While bisecting, insert section logging bisect progress. - - -- Function: magit-insert-untracked-files - Maybe insert a list or tree of untracked files. - - Do so depending on the value of ‘status.showUntrackedFiles’. Note - that even if the value is ‘all’, Magit still initially only shows - directories. But the directory sections can then be expanded using - ‘TAB’. - - -- Function: magit-insert-unstaged-changes - Insert section showing unstaged changes. - - -- Function: magit-insert-staged-changes - Insert section showing staged changes. - - -- Function: magit-insert-stashes &optional ref heading - Insert the ‘stashes’ section showing reflog for "refs/stash". If - optional REF is non-nil show reflog for that instead. If optional - HEADING is non-nil use that as section heading instead of - "Stashes:". - - -- Function: magit-insert-unpulled-from-upstream - Insert section showing commits that haven’t been pulled from the - upstream branch yet. - - -- Function: magit-insert-unpulled-from-pushremote - Insert section showing commits that haven’t been pulled from the - push-remote branch yet. - - -- Function: magit-insert-unpushed-to-upstream - Insert section showing commits that haven’t been pushed to the - upstream yet. - - -- Function: magit-insert-unpushed-to-pushremote - Insert section showing commits that haven’t been pushed to the - push-remote yet. - - The following functions can also be added to the above hook: - - -- Function: magit-insert-tracked-files - Insert a tree of tracked files. - - -- Function: magit-insert-ignored-files - Insert a tree of ignored files. Its possible to limit the logs in - the current buffer to a certain directory using ‘D = f <DIRECTORY> - RET g’. If you do that, then that that also affects this command. - - The log filter can be used to limit to multiple files. In that - case this function only respects the first of the files and only if - it is a directory. - - -- Function: magit-insert-skip-worktree-files - Insert a tree of skip-worktree files. If the first element of - ‘magit-buffer-diff-files’ is a directory, then limit the list to - files below that. The value of that variable can be set using ‘D - -- DIRECTORY RET g’. - - -- Function: magit-insert-assumed-unchanged-files - Insert a tree of files that are assumed to be unchanged. If the - first element of ‘magit-buffer-diff-files’ is a directory, then - limit the list to files below that. The value of that variable can - be set using ‘D -- DIRECTORY RET g’. - - -- Function: magit-insert-unpulled-or-recent-commits - Insert section showing unpulled or recent commits. If an upstream - is configured for the current branch and it is ahead of the current - branch, then show the missing commits. Otherwise, show the last - ‘magit-log-section-commit-count’ commits. - - -- Function: magit-insert-recent-commits - Insert section showing the last ‘magit-log-section-commit-count’ - commits. - - -- User Option: magit-log-section-commit-count - How many recent commits ‘magit-insert-recent-commits’ and - ‘magit-insert-unpulled-or-recent-commits’ (provided there are no - unpulled commits) show. - - -- Function: magit-insert-unpulled-cherries - Insert section showing unpulled commits. Like - ‘magit-insert-unpulled-commits’ but prefix each commit that has not - been applied yet (i.e., a commit with a patch-id not shared with - any local commit) with "+", and all others with "-". - - -- Function: magit-insert-unpushed-cherries - Insert section showing unpushed commits. Like - ‘magit-insert-unpushed-commits’ but prefix each commit which has - not been applied to upstream yet (i.e., a commit with a patch-id - not shared with any upstream commit) with "+" and all others with - "-". - - See *note References Buffer:: for some more section inserters, which -could be used here. - - -File: magit.info, Node: Status Header Sections, Next: Status Module Sections, Prev: Status Sections, Up: Status Buffer - -5.1.2 Status Header Sections ----------------------------- - -The contents of status buffers is controlled using the hook -‘magit-status-sections-hook’ (see *note Status Sections::). - - By default ‘magit-insert-status-headers’ is the first member of that -hook variable. - - -- Function: magit-insert-status-headers - Insert headers sections appropriate for ‘magit-status-mode’ - buffers. The sections are inserted by running the functions on the - hook ‘magit-status-headers-hook’. - - -- User Option: magit-status-headers-hook - Hook run to insert headers sections into the status buffer. - - This hook is run by ‘magit-insert-status-headers’, which in turn - has to be a member of ‘magit-status-sections-hook’ to be used at - all. - - By default the following functions are members of the above hook: - - -- Function: magit-insert-error-header - Insert a header line showing the message about the Git error that - just occurred. - - This function is only aware of the last error that occur when Git - was run for side-effects. If, for example, an error occurs while - generating a diff, then that error won’t be inserted. Refreshing - the status buffer causes this section to disappear again. - - -- Function: magit-insert-diff-filter-header - Insert a header line showing the effective diff filters. - - -- Function: magit-insert-head-branch-header - Insert a header line about the current branch or detached ‘HEAD’. - - -- Function: magit-insert-upstream-branch-header - Insert a header line about the branch that is usually pulled into - the current branch. - - -- Function: magit-insert-push-branch-header - Insert a header line about the branch that the current branch is - usually pushed to. - - -- Function: magit-insert-tags-header - Insert a header line about the current and/or next tag, along with - the number of commits between the tag and ‘HEAD’. - - The following functions can also be added to the above hook: - - -- Function: magit-insert-repo-header - Insert a header line showing the path to the repository top-level. - - -- Function: magit-insert-remote-header - Insert a header line about the remote of the current branch. - - If no remote is configured for the current branch, then fall back - showing the "origin" remote, or if that does not exist the first - remote in alphabetic order. - - -- Function: magit-insert-user-header - Insert a header line about the current user. - - -File: magit.info, Node: Status Module Sections, Next: Status Options, Prev: Status Header Sections, Up: Status Buffer - -5.1.3 Status Module Sections ----------------------------- - -The contents of status buffers is controlled using the hook -‘magit-status-sections-hook’ (see *note Status Sections::). - - By default ‘magit-insert-modules’ is _not_ a member of that hook -variable. - - -- Function: magit-insert-modules - Insert submodule sections. - - Hook ‘magit-module-sections-hook’ controls which module sections - are inserted, and option ‘magit-module-sections-nested’ controls - whether they are wrapped in an additional section. - - -- User Option: magit-module-sections-hook - Hook run by ‘magit-insert-modules’. - - -- User Option: magit-module-sections-nested - This option controls whether ‘magit-insert-modules’ wraps inserted - sections in an additional section. - - If this is non-nil, then only a single top-level section is - inserted. If it is nil, then all sections listed in - ‘magit-module-sections-hook’ become top-level sections. - - -- Function: magit-insert-modules-overview - Insert sections for all submodules. For each section insert the - path, the branch, and the output of ‘git describe --tags’, or, - failing that, the abbreviated HEAD commit hash. - - Press ‘RET’ on such a submodule section to show its own status - buffer. Press ‘RET’ on the "Modules" section to display a list of - submodules in a separate buffer. This shows additional information - not displayed in the super-repository’s status buffer. - - -- Function: magit-insert-modules-unpulled-from-upstream - Insert sections for modules that haven’t been pulled from the - upstream yet. These sections can be expanded to show the - respective commits. - - -- Function: magit-insert-modules-unpulled-from-pushremote - Insert sections for modules that haven’t been pulled from the - push-remote yet. These sections can be expanded to show the - respective commits. - - -- Function: magit-insert-modules-unpushed-to-upstream - Insert sections for modules that haven’t been pushed to the - upstream yet. These sections can be expanded to show the - respective commits. - - -- Function: magit-insert-modules-unpushed-to-pushremote - Insert sections for modules that haven’t been pushed to the - push-remote yet. These sections can be expanded to show the - respective commits. - - -File: magit.info, Node: Status Options, Prev: Status Module Sections, Up: Status Buffer - -5.1.4 Status Options --------------------- - - -- User Option: magit-status-margin - This option specifies whether the margin is initially shown in - Magit-Status mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - Also see the proceeding section for more options concerning status -buffers. - - -File: magit.info, Node: Repository List, Next: Logging, Prev: Status Buffer, Up: Inspecting - -5.2 Repository List -=================== - - -- Command: magit-list-repositories - This command displays a list of repositories in a separate buffer. - - The option ‘magit-repository-directories’ controls which - repositories are displayed. - - -- User Option: magit-repolist-columns - This option controls what columns are displayed by the command - ‘magit-list-repositories’ and how they are displayed. - - Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. - - HEADER is the string displayed in the header. WIDTH is the width - of the column. FORMAT is a function that is called with one - argument, the repository identification (usually its basename), and - with ‘default-directory’ bound to the toplevel of its working tree. - It has to return a string to be inserted or nil. PROPS is an alist - that supports the keys ‘:right-align’, ‘:pad-right’ and ‘:sort’. - - The ‘:sort’ function has a weird interface described in the - docstring of ‘tabulated-list--get-sort’. Alternatively ‘<’ and - ‘magit-repolist-version<’ can be used as those functions are - automatically replaced with functions that satisfy the interface. - Set ‘:sort’ to ‘nil’ to inhibit sorting; if unspecified, then the - column is sortable using the default sorter. - - You may wish to display a range of numeric columns using just one - character per column and without any padding between columns, in - which case you should use an appropriate HEADER, set WIDTH to 1, - and set ‘:pad-right’ to 9. ‘+’ is substituted for numbers higher - than 9. - -The following functions can be added to the above option: - - -- Function: magit-repolist-column-ident - This function inserts the identification of the repository. - Usually this is just its basename. - - -- Function: magit-repolist-column-path - This function inserts the absolute path of the repository. - - -- Function: magit-repolist-column-version - This function inserts a description of the repository’s ‘HEAD’ - revision. - - -- Function: magit-repolist-column-branch - This function inserts the name of the current branch. - - -- Function: magit-repolist-column-upstream - This function inserts the name of the upstream branch of the - current branch. - - -- Function: magit-repolist-column-branches - This function inserts the number of branches. - - -- Function: magit-repolist-column-stashes - This function inserts the number of stashes. - - -- Function: magit-repolist-column-flag - This function inserts a flag as specified by - ‘magit-repolist-column-flag-alist’. - - By default this indicates whether there are uncommitted changes. - - • ‘N’ if there is at least one untracked file. - • ‘U’ if there is at least one unstaged file. - • ‘S’ if there is at least one staged file. - - Only the first one of these that applies is shown. - - -- Function: magit-repolist-column-flags - This functions insert all flags as specified by - ‘magit-repolist-column-flag-alist’. - - This is an alternative to function ‘magit-repolist-column-flag’, - which only lists the first one found. - - -- Function: magit-repolist-column-unpulled-from-upstream - This function inserts the number of upstream commits not in the - current branch. - - -- Function: magit-repolist-column-unpulled-from-pushremote - This function inserts the number of commits in the push branch but - not the current branch. - - -- Function: magit-repolist-column-unpushed-to-upstream - This function inserts the number of commits in the current branch - but not its upstream. - - -- Function: magit-repolist-column-unpushed-to-pushremote - This function inserts the number of commits in the current branch - but not its push branch. - -The following commands are available in repolist buffers: - -‘<RET>’ (‘magit-repolist-status’) - This command shows the status for the repository at point. - -‘m’ (‘magit-repolist-mark’) - This command marks the repository at point. - -‘u’ (‘magit-repolist-unmark’) - This command unmarks the repository at point. - -‘f’ (‘magit-repolist-fetch’) - This command fetches all marked repositories. If no repositories - are marked, then it offers to fetch all displayed repositories. - -‘5’ (‘magit-repolist-find-file-other-frame’) - This command reads a relative file-name (without completion) and - opens the respective file in each marked repository in a new frame. - If no repositories are marked, then it offers to do this for all - displayed repositories. - - -File: magit.info, Node: Logging, Next: Diffing, Prev: Repository List, Up: Inspecting - -5.3 Logging -=========== - -The status buffer contains logs for the unpushed and unpulled commits, -but that obviously isn’t enough. The transient prefix command -‘magit-log’, on ‘l’, features several suffix commands, which show a -specific log in a separate log buffer. - - Like other transient prefix commands, ‘magit-log’ also features -several infix arguments that can be changed before invoking one of the -suffix commands. However, in the case of the log transient, these -arguments may be taken from those currently in use in the current -repository’s log buffer, depending on the value of -‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and -Buffer Variables::). - - For information about the various arguments, see *note -(gitman)git-log::. The switch ‘++order=VALUE’ is converted to one of -‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being -passed to ‘git log’. - - The log transient also features several reflog commands. See *note -Reflog::. - -‘l’ (‘magit-log’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘l l’ (‘magit-log-current’) - Show log for the current branch. When ‘HEAD’ is detached or with a - prefix argument, show log for one or more revs read from the - minibuffer. - -‘l h’ (‘magit-log-head’) - Show log for ‘HEAD’. - -‘l u’ (‘magit-log-related’) - Show log for the current branch, its upstream and its push target. - When the upstream is a local branch, then also show its own - upstream. When ‘HEAD’ is detached, then show log for that, the - previously checked out branch and its upstream and push-target. - -‘l o’ (‘magit-log-other’) - Show log for one or more revs read from the minibuffer. The user - can input any revision or revisions separated by a space, or even - ranges, but only branches, tags, and a representation of the commit - at point are available as completion candidates. - -‘l L’ (‘magit-log-branches’) - Show log for all local branches and ‘HEAD’. - -‘l b’ (‘magit-log-all-branches’) - Show log for all local and remote branches and ‘HEAD’. - -‘l a’ (‘magit-log-all’) - Show log for all references and ‘HEAD’. - - Two additional commands that show the log for the file or blob that -is being visited in the current buffer exists, see *note Commands for -Buffers Visiting Files::. The command ‘magit-cherry’ also shows a log, -see *note Cherries::. - -* Menu: - -* Refreshing Logs:: -* Log Buffer:: -* Log Margin:: -* Select from Log:: -* Reflog:: -* Cherries:: - - -File: magit.info, Node: Refreshing Logs, Next: Log Buffer, Up: Logging - -5.3.1 Refreshing Logs ---------------------- - -The transient prefix command ‘magit-log-refresh’, on ‘L’, can be used to -change the log arguments used in the current buffer, without changing -which log is shown. This works in dedicated log buffers, but also in -the status buffer. - -‘L’ (‘magit-log-refresh’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘L g’ (‘magit-log-refresh’) - This suffix command sets the local log arguments for the current - buffer. - -‘L s’ (‘magit-log-set-default-arguments’) - This suffix command sets the default log arguments for buffers of - the same type as that of the current buffer. Other existing - buffers of the same type are not affected because their local - values have already been initialized. - -‘L w’ (‘magit-log-save-default-arguments’) - This suffix command sets the default log arguments for buffers of - the same type as that of the current buffer, and saves the value - for future sessions. Other existing buffers of the same type are - not affected because their local values have already been - initialized. - -‘L L’ (‘magit-toggle-margin’) - Show or hide the margin. - - -File: magit.info, Node: Log Buffer, Next: Log Margin, Prev: Refreshing Logs, Up: Logging - -5.3.2 Log Buffer ----------------- - -‘L’ (‘magit-log-refresh’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - See *note Refreshing Logs::. - -‘q’ (‘magit-log-bury-buffer’) - Bury the current buffer or the revision buffer in the same frame. - Like ‘magit-mode-bury-buffer’ (which see) but with a negative - prefix argument instead bury the revision buffer, provided it is - displayed in the current frame. - -‘C-c C-b’ (‘magit-go-backward’) - Move backward in current buffer’s history. - -‘C-c C-f’ (‘magit-go-forward’) - Move forward in current buffer’s history. - -‘C-c C-n’ (‘magit-log-move-to-parent’) - Move to a parent of the current commit. By default, this is the - first parent, but a numeric prefix can be used to specify another - parent. - -‘j’ (‘magit-log-move-to-revision’) - Read a revision and move to it in current log buffer. - - If the chosen reference or revision isn’t being displayed in the - current log buffer, then inform the user about that and do nothing - else. - - If invoked outside any log buffer, then display the log buffer of - the current repository first; creating it if necessary. - -‘<SPC>’ (‘magit-diff-show-or-scroll-up’) - Update the commit or diff buffer for the thing at point. - - Either show the commit or stash at point in the appropriate buffer, - or if that buffer is already being displayed in the current frame - and contains information about that commit or stash, then instead - scroll the buffer up. If there is no commit or stash at point, - then prompt for a commit. - -‘<DEL>’ (‘magit-diff-show-or-scroll-down’) - Update the commit or diff buffer for the thing at point. - - Either show the commit or stash at point in the appropriate buffer, - or if that buffer is already being displayed in the current frame - and contains information about that commit or stash, then instead - scroll the buffer down. If there is no commit or stash at point, - then prompt for a commit. - -‘=’ (‘magit-log-toggle-commit-limit’) - Toggle the number of commits the current log buffer is limited to. - If the number of commits is currently limited, then remove that - limit. Otherwise set it to 256. - -‘+’ (‘magit-log-double-commit-limit’) - Double the number of commits the current log buffer is limited to. - -‘-’ (‘magit-log-half-commit-limit’) - Half the number of commits the current log buffer is limited to. - - -- User Option: magit-log-auto-more - Insert more log entries automatically when moving past the last - entry. Only considered when moving past the last entry with - ‘magit-goto-*-section’ commands. - - -- User Option: magit-log-show-refname-after-summary - Whether to show the refnames after the commit summaries. This is - useful if you use really long branch names. - - -- User Option: magit-log-show-color-graph-limit - When showing more commits than specified by this option, then the - ‘--color’ argument, if specified, is silently dropped. This is - necessary because the ‘ansi-color’ library, which is used to turn - control sequences into faces, is just too slow. - - -- User Option: magit-log-show-signatures-limit - When showing more commits than specified by this option, then the - ‘--show-signature’ argument, if specified, is silently dropped. - This is necessary because checking the signature of a large number - of commits is just too slow. - - Magit displays references in logs a bit differently from how Git does -it. - - Local branches are blue and remote branches are green. Of course -that depends on the used theme, as do the colors used for other types of -references. The current branch has a box around it, as do remote -branches that are their respective remote’s ‘HEAD’ branch. - - If a local branch and its push-target point at the same commit, then -their names are combined to preserve space and to make that relationship -visible. For example: - - origin/feature - [green][blue-] - - instead of - - feature origin/feature - [blue-] [green-------] - - Also note that while the transient features the ‘--show-signature’ -argument, that won’t actually be used when enabled, because Magit -defaults to use just one line per commit. Instead the commit colorized -to indicate the validity of the signed commit object, using the faces -named ‘magit-signature-*’ (which see). - - For a description of ‘magit-log-margin’ see *note Log Margin::. - - -File: magit.info, Node: Log Margin, Next: Select from Log, Prev: Log Buffer, Up: Logging - -5.3.3 Log Margin ----------------- - -In buffers which show one or more logs, it is possible to show -additional information about each commit in the margin. The options -used to configure the margin are named ‘magit-INFIX-margin’, where INFIX -is the same as in the respective major-mode ‘magit-INFIX-mode’. In -regular log buffers that would be ‘magit-log-margin’. - - -- User Option: magit-log-margin - This option specifies whether the margin is initially shown in - Magit-Log mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - You can change the STYLE and AUTHOR-WIDTH of all ‘magit-INFIX-margin’ -options to the same values by customizing ‘magit-log-margin’ *before* -‘magit’ is loaded. If you do that, then the respective values for the -other options will default to what you have set for that variable. -Likewise if you set INIT in ‘magit-log-margin’ to ‘nil’, then that is -used in the default of all other options. But setting it to ‘t’, i.e. -re-enforcing the default for that option, does not carry to other -options. - - -- User Option: magit-log-margin-show-committer-date - This option specifies whether to show the committer date in the - margin. This option only controls whether the committer date is - displayed instead of the author date. Whether some date is - displayed in the margin and whether the margin is displayed at all - is controlled by other options. - -‘L’ (‘magit-margin-settings’) - This transient prefix command binds the following suffix commands, - each of which changes the appearance of the margin in some way. - - In some buffers that support the margin, ‘L’ is instead bound to -‘magit-log-refresh’, but that transient features the same commands, and -then some other unrelated commands. - -‘L L’ (‘magit-toggle-margin’) - This command shows or hides the margin. - -‘L l’ (‘magit-cycle-margin-style’) - This command cycles the style used for the margin. - -‘L d’ (‘magit-toggle-margin-details’) - This command shows or hides details in the margin. - - -File: magit.info, Node: Select from Log, Next: Reflog, Prev: Log Margin, Up: Logging - -5.3.4 Select from Log ---------------------- - -When the user has to select a recent commit that is reachable from -‘HEAD’, using regular completion would be inconvenient (because most -humans cannot remember hashes or "HEAD~5", at least not without double -checking). Instead a log buffer is used to select the commit, which has -the advantage that commits are presented in order and with the commit -message. - - Such selection logs are used when selecting the beginning of a rebase -and when selecting the commit to be squashed into. - - In addition to the key bindings available in all log buffers, the -following additional key bindings are available in selection log -buffers: - -‘C-c C-c’ (‘magit-log-select-pick’) - Select the commit at point and act on it. Call - ‘magit-log-select-pick-function’ with the selected commit as - argument. - -‘C-c C-k’ (‘magit-log-select-quit’) - Abort selecting a commit, don’t act on any commit. - - -- User Option: magit-log-select-margin - This option specifies whether the margin is initially shown in - Magit-Log-Select mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Reflog, Next: Cherries, Prev: Select from Log, Up: Logging - -5.3.5 Reflog ------------- - -Also see *note (gitman)git-reflog::. - - These reflog commands are available from the log transient. See -*note Logging::. - -‘l r’ (‘magit-reflog-current’) - Display the reflog of the current branch. - -‘l O’ (‘magit-reflog-other’) - Display the reflog of a branch or another ref. - -‘l H’ (‘magit-reflog-head’) - Display the ‘HEAD’ reflog. - - -- User Option: magit-reflog-margin - This option specifies whether the margin is initially shown in - Magit-Reflog mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Cherries, Prev: Reflog, Up: Logging - -5.3.6 Cherries --------------- - -Cherries are commits that haven’t been applied upstream (yet), and are -usually visualized using a log. Each commit is prefixed with ‘-’ if it -has an equivalent in the upstream and ‘+’ if it does not, i.e., if it is -a cherry. - - The command ‘magit-cherry’ shows cherries for a single branch, but -the references buffer (see *note References Buffer::) can show cherries -for multiple "upstreams" at once. - - Also see *note (gitman)git-reflog::. - -‘Y’ (‘magit-cherry’) - Show commits that are in a certain branch but that have not been - merged in the upstream branch. - - -- User Option: magit-cherry-margin - This option specifies whether the margin is initially shown in - Magit-Cherry mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting - -5.4 Diffing -=========== - -The status buffer contains diffs for the staged and unstaged commits, -but that obviously isn’t enough. The transient prefix command -‘magit-diff’, on ‘d’, features several suffix commands, which show a -specific diff in a separate diff buffer. - - Like other transient prefix commands, ‘magit-diff’ also features -several infix arguments that can be changed before invoking one of the -suffix commands. However, in the case of the diff transient, these -arguments may be taken from those currently in use in the current -repository’s diff buffer, depending on the value of -‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and -Buffer Variables::). - - Also see *note (gitman)git-diff::. - -‘d’ (‘magit-diff’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘d d’ (‘magit-diff-dwim’) - Show changes for the thing at point. - -‘d r’ (‘magit-diff-range’) - Show differences between two commits. - - RANGE should be a range (A..B or A...B) but can also be a single - commit. If one side of the range is omitted, then it defaults to - ‘HEAD’. If just a commit is given, then changes in the working - tree relative to that commit are shown. - - If the region is active, use the revisions on the first and last - line of the region. With a prefix argument, instead of diffing the - revisions, choose a revision to view changes along, starting at the - common ancestor of both revisions (i.e., use a "..." range). - -‘d w’ (‘magit-diff-working-tree’) - Show changes between the current working tree and the ‘HEAD’ - commit. With a prefix argument show changes between the working - tree and a commit read from the minibuffer. - -‘d s’ (‘magit-diff-staged’) - Show changes between the index and the ‘HEAD’ commit. With a - prefix argument show changes between the index and a commit read - from the minibuffer. - -‘d u’ (‘magit-diff-unstaged’) - Show changes between the working tree and the index. - -‘d p’ (‘magit-diff-paths’) - Show changes between any two files on disk. - - All of the above suffix commands update the repository’s diff buffer. -The diff transient also features two commands which show differences in -another buffer: - -‘d c’ (‘magit-show-commit’) - Show the commit at point. If there is no commit at point or with a - prefix argument, prompt for a commit. - -‘d t’ (‘magit-stash-show’) - Show all diffs of a stash in a buffer. - - Two additional commands that show the diff for the file or blob that -is being visited in the current buffer exists, see *note Commands for -Buffers Visiting Files::. - -* Menu: - -* Refreshing Diffs:: -* Commands Available in Diffs:: -* Diff Options:: -* Revision Buffer:: - - -File: magit.info, Node: Refreshing Diffs, Next: Commands Available in Diffs, Up: Diffing - -5.4.1 Refreshing Diffs ----------------------- - -The transient prefix command ‘magit-diff-refresh’, on ‘D’, can be used -to change the diff arguments used in the current buffer, without -changing which diff is shown. This works in dedicated diff buffers, but -also in the status buffer. - - (There is one exception; diff arguments cannot be changed in buffers -created by ‘magit-merge-preview’ because the underlying Git command does -not support these arguments.) - -‘D’ (‘magit-diff-refresh’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘D g’ (‘magit-diff-refresh’) - This suffix command sets the local diff arguments for the current - buffer. - -‘D s’ (‘magit-diff-set-default-arguments’) - This suffix command sets the default diff arguments for buffers of - the same type as that of the current buffer. Other existing - buffers of the same type are not affected because their local - values have already been initialized. - -‘D w’ (‘magit-diff-save-default-arguments’) - This suffix command sets the default diff arguments for buffers of - the same type as that of the current buffer, and saves the value - for future sessions. Other existing buffers of the same type are - not affected because their local values have already been - initialized. - -‘D t’ (‘magit-diff-toggle-refine-hunk’) - This command toggles hunk refinement on or off. - -‘D r’ (‘magit-diff-switch-range-type’) - This command converts the diff range type from "revA..revB" to - "revB...revA", or vice versa. - -‘D f’ (‘magit-diff-flip-revs’) - This command swaps revisions in the diff range from "revA..revB" to - "revB..revA", or vice versa. - -‘D F’ (‘magit-diff-toggle-file-filter’) - This command toggles the file restriction of the diffs in the - current buffer, allowing you to quickly switch between viewing all - the changes in the commit and the restricted subset. As a special - case, when this command is called from a log buffer, it toggles the - file restriction in the repository’s revision buffer, which is - useful when you display a revision from a log buffer that is - restricted to a file or files. - - In addition to the above transient, which allows changing any of the -supported arguments, there also exist some commands that change only a -particular argument. - -‘-’ (‘magit-diff-less-context’) - This command decreases the context for diff hunks by COUNT lines. - -‘+’ (‘magit-diff-more-context’) - This command increases the context for diff hunks by COUNT lines. - -‘0’ (‘magit-diff-default-context’) - This command resets the context for diff hunks to the default - height. - - The following commands quickly change what diff is being displayed -without having to using one of the diff transient. - -‘C-c C-d’ (‘magit-diff-while-committing’) - While committing, this command shows the changes that are about to - be committed. While amending, invoking the command again toggles - between showing just the new changes or all the changes that will - be committed. - - This binding is available in the diff buffer as well as the commit - message buffer. - -‘C-c C-b’ (‘magit-go-backward’) - This command moves backward in current buffer’s history. - -‘C-c C-f’ (‘magit-go-forward’) - This command moves forward in current buffer’s history. - - -File: magit.info, Node: Commands Available in Diffs, Next: Diff Options, Prev: Refreshing Diffs, Up: Diffing - -5.4.2 Commands Available in Diffs ---------------------------------- - -Some commands are only available if point is inside a diff. - - ‘magit-diff-visit-file’ and related commands visit the appropriate -version of the file that the diff at point is about. Likewise -‘magit-diff-visit-worktree-file’ and related commands visit the worktree -version of the file that the diff at point is about. See *note Visiting -Files and Blobs from a Diff:: for more information and the key bindings. - -‘C-c C-t’ (‘magit-diff-trace-definition’) - This command shows a log for the definition at point. - - -- User Option: magit-log-trace-definition-function - The function specified by this option is used by - ‘magit-log-trace-definition’ to determine the function at point. - For major-modes that have special needs, you could set the local - value using the mode’s hook. - -‘C-c C-e’ (‘magit-diff-edit-hunk-commit’) - From a hunk, this command edits the respective commit and visits - the file. - - First it visits the file being modified by the hunk at the correct - location using ‘magit-diff-visit-file’. This actually visits a - blob. When point is on a diff header, not within an individual - hunk, then this visits the blob the first hunk is about. - - Then it invokes ‘magit-edit-line-commit’, which uses an interactive - rebase to make the commit editable, or if that is not possible - because the commit is not reachable from ‘HEAD’ by checking out - that commit directly. This also causes the actual worktree file to - be visited. - - Neither the blob nor the file buffer are killed when finishing the - rebase. If that is undesirable, then it might be better to use - ‘magit-rebase-edit-commit’ instead of this command. - -‘j’ (‘magit-jump-to-diffstat-or-diff’) - This command jumps to the diffstat or diff. When point is on a - file inside the diffstat section, then jump to the respective diff - section. Otherwise, jump to the diffstat section or a child - thereof. - - The next two commands are not specific to Magit-Diff mode (or and -Magit buffer for that matter), but it might be worth pointing out that -they are available here too. - -‘<SPC>’ (‘scroll-up’) - This command scrolls text upward. - -‘<DEL>’ (‘scroll-down’) - This command scrolls text downward. - - -File: magit.info, Node: Diff Options, Next: Revision Buffer, Prev: Commands Available in Diffs, Up: Diffing - -5.4.3 Diff Options ------------------- - - -- User Option: magit-diff-refine-hunk - Whether to show word-granularity differences within diff hunks. - - • ‘nil’ Never show fine differences. - • ‘t’ Show fine differences for the current diff hunk only. - • ‘all’ Show fine differences for all displayed diff hunks. - - -- User Option: magit-diff-refine-ignore-whitespace - Whether to ignore whitespace changes in word-granularity - differences. - - -- User Option: magit-diff-adjust-tab-width - Whether to adjust the width of tabs in diffs. - - Determining the correct width can be expensive if it requires - opening large and/or many files, so the widths are cached in the - variable ‘magit-diff--tab-width-cache’. Set that to nil to - invalidate the cache. - - • ‘nil’ Never adjust tab width. Use ‘tab-width’s value from the - Magit buffer itself instead. - - • ‘t’ If the corresponding file-visiting buffer exits, then use - ‘tab-width’’s value from that buffer. Doing this is cheap, so - this value is used even if a corresponding cache entry exists. - - • ‘always’ If there is no such buffer, then temporarily visit - the file to determine the value. - - • NUMBER Like ‘always’, but don’t visit files larger than NUMBER - bytes. - - -- User Option: magit-diff-paint-whitespace - Specify where to highlight whitespace errors. - - See ‘magit-diff-highlight-trailing’, - ‘magit-diff-highlight-indentation’. The symbol ‘t’ means in all - diffs, ‘status’ means only in the status buffer, and nil means - nowhere. - - • ‘nil’ Never highlight whitespace errors. - • ‘t’ Highlight whitespace errors everywhere. - • ‘uncommitted’ Only highlight whitespace errors in diffs - showing uncommitted changes. For backward compatibility - ‘status’ is treated as a synonym. - - -- User Option: magit-diff-paint-whitespace-lines - Specify in what kind of lines to highlight whitespace errors. - - • ‘t’ Highlight only in added lines. - • ‘both’ Highlight in added and removed lines. - • ‘all’ Highlight in added, removed and context lines. - - -- User Option: magit-diff-highlight-trailing - Whether to highlight whitespace at the end of a line in diffs. - Used only when ‘magit-diff-paint-whitespace’ is non-nil. - - -- User Option: magit-diff-highlight-indentation - This option controls whether to highlight the indentation in case - it used the "wrong" indentation style. Indentation is only - highlighted if ‘magit-diff-paint-whitespace’ is also non-nil. - - The value is an alist of the form ‘((REGEXP . INDENT)...)’. The - path to the current repository is matched against each element in - reverse order. Therefore if a REGEXP matches, then earlier - elements are not tried. - - If the used INDENT is ‘tabs’, highlight indentation with tabs. If - INDENT is an integer, highlight indentation with at least that many - spaces. Otherwise, highlight neither. - - -- User Option: magit-diff-hide-trailing-cr-characters - Whether to hide ^M characters at the end of a line in diffs. - - -- User Option: magit-diff-highlight-hunk-region-functions - This option specifies the functions used to highlight the - hunk-internal region. - - ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside - of the hunk internal selection with a face that causes the added - and removed lines to have the same background color as context - lines. This function should not be removed from the value of this - option. - - ‘magit-diff-highlight-hunk-region-using-overlays’ and - ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the - region by placing delimiting horizontal lines before and after it. - Both of these functions have glitches which cannot be fixed due to - limitations of Emacs’ display engine. For more information see - <https://github.com/magit/magit/issues/2758> ff. - - Instead of, or in addition to, using delimiting horizontal lines, - to emphasize the boundaries, you may wish to emphasize the text - itself, using ‘magit-diff-highlight-hunk-region-using-face’. - - In terminal frames it’s not possible to draw lines as the overlay - and underline variants normally do, so there they fall back to - calling the face function instead. - - -- User Option: magit-diff-unmarked-lines-keep-foreground - This option controls whether added and removed lines outside the - hunk-internal region only lose their distinct background color or - also the foreground color. Whether the outside of the region is - dimmed at all depends on - ‘magit-diff-highlight-hunk-region-functions’. - - -- User Option: magit-diff-extra-stat-arguments - This option specifies additional arguments to be used alongside - ‘--stat’. - - The value is a list of zero or more arguments or a function that - takes no argument and returns such a list. These arguments are - allowed here: ‘--stat-width’, ‘--stat-name-width’, - ‘--stat-graph-width’ and ‘--compact-summary’. Also see *note - (gitman)git-diff::. - - -File: magit.info, Node: Revision Buffer, Prev: Diff Options, Up: Diffing - -5.4.4 Revision Buffer ---------------------- - - -- User Option: magit-revision-insert-related-refs - Whether to show related branches in revision buffers. - - • ‘nil’ Don’t show any related branches. - • ‘t’ Show related local branches. - • ‘all’ Show related local and remote branches. - • ‘mixed’ Show all containing branches and local merged - branches. - - -- User Option: magit-revision-show-gravatars - Whether to show gravatar images in revision buffers. - - If ‘nil’, then don’t insert any gravatar images. If ‘t’, then - insert both images. If ‘author’ or ‘committer’, then insert only - the respective image. - - If you have customized the option ‘magit-revision-headers-format’ - and want to insert the images then you might also have to specify - where to do so. In that case the value has to be a cons-cell of - two regular expressions. The car specifies where to insert the - author’s image. The top half of the image is inserted right after - the matched text, the bottom half on the next line in the same - column. The cdr specifies where to insert the committer’s image, - accordingly. Either the car or the cdr may be nil." - - -- User Option: magit-revision-use-hash-sections - Whether to turn hashes inside the commit message into sections. - - If non-nil, then hashes inside the commit message are turned into - ‘commit’ sections. There is a trade off to be made between - performance and reliability: - - • ‘slow’ calls git for every word to be absolutely sure. - • ‘quick’ skips words less than seven characters long. - • ‘quicker’ additionally skips words that don’t contain a - number. - • ‘quickest’ uses all words that are at least seven characters - long and which contain at least one number as well as at least - one letter. - - If nil, then no hashes are turned into sections, but you can still - visit the commit at point using "RET". - - The diffs shown in the revision buffer may be automatically -restricted to a subset of the changed files. If the revision buffer is -displayed from a log buffer, the revision buffer will share the same -file restriction as that log buffer (also see the command -‘magit-diff-toggle-file-filter’). - - -- User Option: magit-revision-filter-files-on-follow - Whether showing a commit from a log buffer honors the log’s file - filter when the log arguments include ‘--follow’. - - When this option is nil, displaying a commit from a log ignores the - log’s file filter if the log arguments include ‘--follow’. Doing - so avoids showing an empty diff in revision buffers for commits - before a rename event. In such cases, the ‘--patch’ argument of - the log transient can be used to show the file-restricted diffs - inline. - - Set this option to non-nil to keep the log’s file restriction even - if ‘--follow’ is present in the log arguments. - - If the revision buffer is not displayed from a log buffer, the file -restriction is determined as usual (see *note Transient Arguments and -Buffer Variables::). - - -File: magit.info, Node: Ediffing, Next: References Buffer, Prev: Diffing, Up: Inspecting - -5.5 Ediffing -============ - -This section describes how to enter Ediff from Magit buffers. For -information on how to use Ediff itself, see *note (ediff)Top::. - -‘e’ (‘magit-ediff-dwim’) - Compare, stage, or resolve using Ediff. - - This command tries to guess what file, and what commit or range the - user wants to compare, stage, or resolve using Ediff. It might - only be able to guess either the file, or range/commit, in which - case the user is asked about the other. It might not always guess - right, in which case the appropriate ‘magit-ediff-*’ command has to - be used explicitly. If it cannot read the user’s mind at all, then - it asks the user for a command to run. - -‘E’ (‘magit-ediff’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘E r’ (‘magit-ediff-compare’) - Compare two revisions of a file using Ediff. - - If the region is active, use the revisions on the first and last - line of the region. With a prefix argument, instead of diffing the - revisions, choose a revision to view changes along, starting at the - common ancestor of both revisions (i.e., use a "..." range). - -‘E m’ (‘magit-ediff-resolve-rest’) - This command allows you to resolve outstanding conflicts in the - file at point using Ediff. If there is no file at point or if it - doesn’t have any unmerged changes, then this command prompts for a - file. - - Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you - can view the file’s merge-base revision using ‘/’ in the Ediff - control buffer. - - The A, B and Ancestor buffers are constructed from the conflict - markers in the worktree file. Because you and/or Git may have - already resolved some conflicts, that means that these buffers may - not contain the actual versions from the respective blobs. - -‘E M’ (‘magit-ediff-resolve-all’) - This command allows you to resolve all conflicts in the file at - point using Ediff. If there is no file at point or if it doesn’t - have any unmerged changes, then this command prompts for a file. - - Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you - can view the file’s merge-base revision using ‘/’ in the Ediff - control buffer. - - First the file in the worktree is moved aside, appending the suffix - ‘.ORIG’, so that you could later go back to that version. Then it - is reconstructed from the two sides of the conflict and the - merge-base, if available. - - It would be nice if the worktree file were just used as-is, but - Ediff does not support that. This means that all conflicts, that - Git has already resolved, are restored. On the other hand Ediff - also tries to resolve conflicts, and in many cases Ediff and Git - should produce similar results. - - However if you have already resolved some conflicts manually, then - those changes are discarded (though you can recover them from the - backup file). In such cases ‘magit-ediff-resolve-rest’ might be - more suitable. - - The advantage that this command has over ‘magit-ediff-resolve-rest’ - is that the A, B and Ancestor buffers correspond to blobs from the - respective commits, allowing you to inspect a side in context and - to use Magit commands in these buffers to do so. Blame and log - commands are particularly useful here. - -‘E t’ (‘magit-git-mergetool’) - This command does not actually use Ediff. While it serves the same - purpose as ‘magit-ediff-resolve-rest’, it uses ‘git mergetool - --gui’ to resolve conflicts. - - With a prefix argument this acts as a transient prefix command, - allowing the user to select the mergetool and change some settings. - -‘E s’ (‘magit-ediff-stage’) - Stage and unstage changes to a file using Ediff, defaulting to the - file at point. - -‘E u’ (‘magit-ediff-show-unstaged’) - Show unstaged changes to a file using Ediff. - -‘E i’ (‘magit-ediff-show-staged’) - Show staged changes to a file using Ediff. - -‘E w’ (‘magit-ediff-show-working-tree’) - Show changes in a file between ‘HEAD’ and working tree using Ediff. - -‘E c’ (‘magit-ediff-show-commit’) - Show changes to a file introduced by a commit using Ediff. - -‘E z’ (‘magit-ediff-show-stash’) - Show changes to a file introduced by a stash using Ediff. - - -- User Option: magit-ediff-dwim-resolve-function - This option controls which function ‘magit-ediff-dwim’ uses to - resolve conflicts. One of ‘magit-ediff-resolve-rest’, - ‘magit-ediff-resolve-all’ or ‘magit-git-mergetool’; which are all - discussed above. - - -- User Option: magit-ediff-dwim-show-on-hunks - This option controls what command ‘magit-ediff-dwim’ calls when - point is on uncommitted hunks. When nil, always run - ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and - ‘magit-ediff-show-unstaged’ to show staged and unstaged changes, - respectively. - - -- User Option: magit-ediff-show-stash-with-index - This option controls whether ‘magit-ediff-show-stash’ includes a - buffer containing the file’s state in the index at the time the - stash was created. This makes it possible to tell which changes in - the stash were staged. - - -- User Option: magit-ediff-quit-hook - This hook is run after quitting an Ediff session that was created - using a Magit command. The hook functions are run inside the Ediff - control buffer, and should not change the current buffer. - - This is similar to ‘ediff-quit-hook’ but takes the needs of Magit - into account. The regular ‘ediff-quit-hook’ is ignored by Ediff - sessions that were created using a Magit command. - - -File: magit.info, Node: References Buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting - -5.6 References Buffer -===================== - -‘y’ (‘magit-show-refs’) - This command lists branches and tags in a dedicated buffer. - - However if this command is invoked again from this buffer or if it - is invoked with a prefix argument, then it acts as a transient - prefix command, which binds the following suffix commands and some - infix arguments. - - All of the following suffix commands list exactly the same branches -and tags. The only difference the optional feature that can be enabled -by changing the value of ‘magit-refs-show-commit-count’ (see below). -These commands specify a different branch or commit against which all -the other references are compared. - -‘y y’ (‘magit-show-refs-head’) - This command lists branches and tags in a dedicated buffer. Each - reference is being compared with ‘HEAD’. - -‘y c’ (‘magit-show-refs-current’) - This command lists branches and tags in a dedicated buffer. Each - reference is being compared with the current branch or ‘HEAD’ if it - is detached. - -‘y o’ (‘magit-show-refs-other’) - This command lists branches and tags in a dedicated buffer. Each - reference is being compared with a branch read from the user. - -‘y r’ (‘magit-refs-set-show-commit-count’) - This command changes for which refs the commit count is shown. - - -- User Option: magit-refs-show-commit-count - Whether to show commit counts in Magit-Refs mode buffers. - - • ‘all’ Show counts for branches and tags. - • ‘branch’ Show counts for branches only. - • ‘nil’ Never show counts. - - The default is ‘nil’ because anything else can be very expensive. - - -- User Option: magit-refs-pad-commit-counts - Whether to pad all commit counts on all sides in Magit-Refs mode - buffers. - - If this is nil, then some commit counts are displayed right next to - one of the branches that appear next to the count, without any - space in between. This might look bad if the branch name faces - look too similar to ‘magit-dimmed’. - - If this is non-nil, then spaces are placed on both sides of all - commit counts. - - -- User Option: magit-refs-show-remote-prefix - Whether to show the remote prefix in lists of remote branches. - - Showing the prefix is redundant because the name of the remote is - already shown in the heading preceding the list of its branches. - - -- User Option: magit-refs-primary-column-width - Width of the primary column in ‘magit-refs-mode’ buffers. The - primary column is the column that contains the name of the branch - that the current row is about. - - If this is an integer, then the column is that many columns wide. - Otherwise it has to be a cons-cell of two integers. The first - specifies the minimal width, the second the maximal width. In that - case the actual width is determined using the length of the names - of the shown local branches. (Remote branches and tags are not - taken into account when calculating to optimal width.) - - -- User Option: magit-refs-focus-column-width - Width of the focus column in ‘magit-refs-mode’ buffers. - - The focus column is the first column, which marks one branch - (usually the current branch) as the focused branch using ‘*’ or - ‘@’. For each other reference, this column optionally shows how - many commits it is ahead of the focused branch and ‘<’, or if it - isn’t ahead then the commits it is behind and ‘>’, or if it isn’t - behind either, then a ‘=’. - - This column may also display only ‘*’ or ‘@’ for the focused - branch, in which case this option is ignored. Use ‘L v’ to change - the verbosity of this column. - - -- User Option: magit-refs-margin - This option specifies whether the margin is initially shown in - Magit-Refs mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -- User Option: magit-refs-margin-for-tags - This option specifies whether to show information about tags in the - margin. This is disabled by default because it is slow if there - are many tags. - - The following variables control how individual refs are displayed. -If you change one of these variables (especially the "%c" part), then -you should also change the others to keep things aligned. The following -%-sequences are supported: - - • ‘%a’ Number of commits this ref has over the one we compare to. - • ‘%b’ Number of commits the ref we compare to has over this one. - • ‘%c’ Number of commits this ref has over the one we compare to. - For the ref which all other refs are compared this is instead "@", - if it is the current branch, or "#" otherwise. - • ‘%C’ For the ref which all other refs are compared this is "@", if - it is the current branch, or "#" otherwise. For all other refs " - ". - • ‘%h’ Hash of this ref’s tip. - • ‘%m’ Commit summary of the tip of this ref. - • ‘%n’ Name of this ref. - • ‘%u’ Upstream of this local branch. - • ‘%U’ Upstream of this local branch and additional local vs. - upstream information. - - -- User Option: magit-refs-filter-alist - The purpose of this option is to forgo displaying certain refs - based on their name. If you want to not display any refs of a - certain type, then you should remove the appropriate function from - ‘magit-refs-sections-hook’ instead. - - This alist controls which tags and branches are omitted from being - displayed in ‘magit-refs-mode’ buffers. If it is ‘nil’, then all - refs are displayed (subject to ‘magit-refs-sections-hook’). - - All keys are tried in order until one matches. Then its value is - used and subsequent elements are ignored. If the value is non-nil, - then the reference is displayed, otherwise it is not. If no - element matches, then the reference is displayed. - - A key can either be a regular expression that the refname has to - match, or a function that takes the refname as only argument and - returns a boolean. A remote branch such as "origin/master" is - displayed as just "master", however for this comparison the former - is used. - -‘<RET>’ (‘magit-visit-ref’) - This command visits the reference or revision at point in another - buffer. If there is no revision at point or with a prefix argument - then it prompts for a revision. - - This command behaves just like ‘magit-show-commit’ as described - above, except if point is on a reference in a ‘magit-refs-mode’ - buffer, in which case the behavior may be different, but only if - you have customized the option ‘magit-visit-ref-behavior’. - - -- User Option: magit-visit-ref-behavior - This option controls how ‘magit-visit-ref’ behaves in - ‘magit-refs-mode’ buffers. - - By default ‘magit-visit-ref’ behaves like ‘magit-show-commit’, in - all buffers, including ‘magit-refs-mode’ buffers. When the type of - the section at point is ‘commit’ then "RET" is bound to - ‘magit-show-commit’, and when the type is either ‘branch’ or ‘tag’ - then it is bound to ‘magit-visit-ref’. - - "RET" is one of Magit’s most essential keys and at least by default - it should behave consistently across all of Magit, especially - because users quickly learn that it does something very harmless; - it shows more information about the thing at point in another - buffer. - - However "RET" used to behave differently in ‘magit-refs-mode’ - buffers, doing surprising things, some of which cannot really be - described as "visit this thing". If you’ve grown accustomed this - behavior, you can restore it by adding one or more of the below - symbols to the value of this option. But keep in mind that by - doing so you don’t only introduce inconsistencies, you also lose - some functionality and might have to resort to ‘M-x - magit-show-commit’ to get it back. - - ‘magit-visit-ref’ looks for these symbols in the order in which - they are described here. If the presence of a symbol applies to - the current situation, then the symbols that follow do not affect - the outcome. - - • ‘focus-on-ref’ - - With a prefix argument update the buffer to show commit counts - and lists of cherry commits relative to the reference at point - instead of relative to the current buffer or ‘HEAD’. - - Instead of adding this symbol, consider pressing "C-u y o - RET". - - • ‘create-branch’ - - If point is on a remote branch, then create a new local branch - with the same name, use the remote branch as its upstream, and - then check out the local branch. - - Instead of adding this symbol, consider pressing "b c RET - RET", like you would do in other buffers. - - • ‘checkout-any’ - - Check out the reference at point. If that reference is a tag - or a remote branch, then this results in a detached ‘HEAD’. - - Instead of adding this symbol, consider pressing "b b RET", - like you would do in other buffers. - - • ‘checkout-branch’ - - Check out the local branch at point. - - Instead of adding this symbol, consider pressing "b b RET", - like you would do in other buffers. - -* Menu: - -* References Sections:: - - -File: magit.info, Node: References Sections, Up: References Buffer - -5.6.1 References Sections -------------------------- - -The contents of references buffers is controlled using the hook -‘magit-refs-sections-hook’. See *note Section Hooks:: to learn about -such hooks and how to customize them. All of the below functions are -members of the default value. Note that it makes much less sense to -customize this hook than it does for the respective hook used for the -status buffer. - - -- User Option: magit-refs-sections-hook - Hook run to insert sections into a references buffer. - - -- Function: magit-insert-local-branches - Insert sections showing all local branches. - - -- Function: magit-insert-remote-branches - Insert sections showing all remote-tracking branches. - - -- Function: magit-insert-tags - Insert sections showing all tags. - - -File: magit.info, Node: Bisecting, Next: Visiting Files and Blobs, Prev: References Buffer, Up: Inspecting - -5.7 Bisecting -============= - -Also see *note (gitman)git-bisect::. - -‘B’ (‘magit-bisect’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - - When bisecting is not in progress, then the transient features the -following suffix commands. - -‘B B’ (‘magit-bisect-start’) - Start a bisect session. - - Bisecting a bug means to find the commit that introduced it. This - command starts such a bisect session by asking for a known good - commit and a known bad commit. If you’re bisecting a change that - isn’t a regression, you can select alternate terms that are - conceptually more fitting than "bad" and "good", but the infix - arguments to do so are disabled by default. - -‘B s’ (‘magit-bisect-run’) - Bisect automatically by running commands after each step. - - When bisecting in progress, then the transient instead features the -following suffix commands. - -‘B b’ (‘magit-bisect-bad’) - Mark the current commit as bad. Use this after you have asserted - that the commit does contain the bug in question. - -‘B g’ (‘magit-bisect-good’) - Mark the current commit as good. Use this after you have asserted - that the commit does not contain the bug in question. - -‘B m’ (‘magit-bisect-mark’) - Mark the current commit with one of the bisect terms. This command - provides an alternative to ‘magit-bisect-bad’ and - ‘magit-bisect-good’ and is useful when using terms other than "bad" - and "good". This suffix is disabled by default. - -‘B k’ (‘magit-bisect-skip’) - Skip the current commit. Use this if for some reason the current - commit is not a good one to test. This command lets Git choose a - different one. - -‘B r’ (‘magit-bisect-reset’) - After bisecting, cleanup bisection state and return to original - ‘HEAD’. - - By default the status buffer shows information about the ongoing -bisect session. - - -- User Option: magit-bisect-show-graph - This option controls whether a graph is displayed for the log of - commits that still have to be bisected. - - -File: magit.info, Node: Visiting Files and Blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting - -5.8 Visiting Files and Blobs -============================ - -Magit provides several commands that visit a file or blob (the version -of a file that is stored in a certain commit). Actually it provides -several *groups* of such commands and the several *variants* within each -group. - - Also see *note Commands for Buffers Visiting Files::. - -* Menu: - -* General-Purpose Visit Commands:: -* Visiting Files and Blobs from a Diff:: - - -File: magit.info, Node: General-Purpose Visit Commands, Next: Visiting Files and Blobs from a Diff, Up: Visiting Files and Blobs - -5.8.1 General-Purpose Visit Commands ------------------------------------- - -These commands can be used anywhere to open any blob. Currently no keys -are bound to these commands by default, but that is likely to change. - - -- Command: magit-find-file - This command reads a filename and revision from the user and visits - the respective blob in a buffer. The buffer is displayed in the - selected window. - - -- Command: magit-find-file-other-window - This command reads a filename and revision from the user and visits - the respective blob in a buffer. The buffer is displayed in - another window. - - -- Command: magit-find-file-other-frame - This command reads a filename and revision from the user and visits - the respective blob in a buffer. The buffer is displayed in - another frame. - - -File: magit.info, Node: Visiting Files and Blobs from a Diff, Prev: General-Purpose Visit Commands, Up: Visiting Files and Blobs - -5.8.2 Visiting Files and Blobs from a Diff ------------------------------------------- - -These commands can only be used when point is inside a diff. - -‘<RET>’ (‘magit-diff-visit-file’) - This command visits the appropriate version of the file that the - diff at point is about. - - This commands visits the worktree version of the appropriate file. - The location of point inside the diff determines which file is - being visited. The visited version depends on what changes the - diff is about. - - 1. If the diff shows uncommitted changes (i.e., staged or - unstaged changes), then visit the file in the working tree - (i.e., the same "real" file that ‘find-file’ would visit. In - all other cases visit a "blob" (i.e., the version of a file as - stored in some commit). - - 2. If point is on a removed line, then visit the blob for the - first parent of the commit that removed that line, i.e., the - last commit where that line still exists. - - 3. If point is on an added or context line, then visit the blob - that adds that line, or if the diff shows from more than a - single commit, then visit the blob from the last of these - commits. - - In the file-visiting buffer this command goes to the line that - corresponds to the line that point is on in the diff. - - The buffer is displayed in the selected window. With a prefix - argument the buffer is displayed in another window instead. - - -- User Option: magit-diff-visit-previous-blob - This option controls whether ‘magit-diff-visit-file’ may visit the - previous blob. When this is ‘t’ (the default) and point is on a - removed line in a diff for a committed change, then - ‘magit-diff-visit-file’ visits the blob from the last revision - which still had that line. - - Currently this is only supported for committed changes, for staged - and unstaged changes ‘magit-diff-visit-file’ always visits the file - in the working tree. - -‘C-<return>’ (‘magit-diff-visit-file-worktree’) - This command visits the worktree version of the appropriate file. - The location of point inside the diff determines which file is - being visited. Unlike ‘magit-diff-visit-file’ it always visits the - "real" file in the working tree, i.e the "current version" of the - file. - - In the file-visiting buffer this command goes to the line that - corresponds to the line that point is on in the diff. Lines that - were added or removed in the working tree, the index and other - commits in between are automatically accounted for. - - The buffer is displayed in the selected window. With a prefix - argument the buffer is displayed in another window instead. - - Variants of the above two commands exist that instead visit the file -in another window or in another frame. If you prefer such behavior, -then you may want to change the above key bindings, but note that the -above commands also use another window when invoked with a prefix -argument. - - -- Command: magit-diff-visit-file-other-window - -- Command: magit-diff-visit-file-other-frame - -- Command: magit-diff-visit-worktree-file-other-window - -- Command: magit-diff-visit-worktree-file-other-frame - - -File: magit.info, Node: Blaming, Prev: Visiting Files and Blobs, Up: Inspecting - -5.9 Blaming -=========== - -Also see *note (gitman)git-blame::. - - To start blaming, invoke the ‘magit-file-dispatch’ transient prefix -command. When using the default key bindings, that can be done by -pressing ‘C-c M-g’. When using the recommended bindings, this command -is instead bound to ‘C-c f’. Also see *note Global Bindings::. - - The blaming suffix commands can be invoked directly from the file -dispatch transient. However if you want to set an infix argument, then -you have to enter the blaming sub-prefix first. - -‘C-c f B’ (‘magit-blame’) -‘C-c f b’ (‘magit-blame-addition’) -‘C-c f B b’ -‘C-c f r’ (‘magit-blame-removal’) -‘C-c f B r’ -‘C-c f f’ (‘magit-blame-reverse’) -‘C-c f B f’ -‘C-c f e’ (‘magit-blame-echo’) -‘C-c f B e’ -‘C-c f q’ (‘magit-blame-quit’) -‘C-c f B q’ - Each of these commands is documented individually right below, - alongside their default key bindings. The bindings shown above are - the recommended bindings, which you can enable by following the - instructions in *note Global Bindings::. - -‘C-c M-g B’ (‘magit-blame’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - Note that not all of the following suffixes are available at all -times. For example if ‘magit-blame-mode’ is not enabled, then the -command whose purpose is to turn off that mode would not be of any use -and therefore isn’t available. - -‘C-c M-g b’ (‘magit-blame-addition’) -‘C-c M-g B b’ - This command augments each line or chunk of lines in the current - file-visiting or blob-visiting buffer with information about what - commits last touched these lines. - - If the buffer visits a revision of that file, then history up to - that revision is considered. Otherwise, the file’s full history is - considered, including uncommitted changes. - - If Magit-Blame mode is already turned on in the current buffer then - blaming is done recursively, by visiting REVISION:FILE (using - ‘magit-find-file’), where REVISION is a parent of the revision that - added the current line or chunk of lines. - -‘C-c M-g r’ (‘magit-blame-removal’) -‘C-c M-g B r’ - This command augments each line or chunk of lines in the current - blob-visiting buffer with information about the revision that - removes it. It cannot be used in file-visiting buffers. - - Like ‘magit-blame-addition’, this command can be used recursively. - -‘C-c M-g f’ (‘magit-blame-reverse’) -‘C-c M-g B f’ - This command augments each line or chunk of lines in the current - file-visiting or blob-visiting buffer with information about the - last revision in which a line still existed. - - Like ‘magit-blame-addition’, this command can be used recursively. - -‘C-c M-g e’ (‘magit-blame-echo’) -‘C-c M-g B e’ - This command is like ‘magit-blame-addition’ except that it doesn’t - turn on ‘read-only-mode’ and that it initially uses the - visualization style specified by option ‘magit-blame-echo-style’. - - The following key bindings are available when Magit-Blame mode is -enabled and Read-Only mode is not enabled. These commands are also -available in other buffers; here only the behavior is described that is -relevant in file-visiting buffers that are being blamed. - -‘C-c M-g q’ (‘magit-blame-quit’) -‘C-c M-g B q’ - This command turns off Magit-Blame mode. If the buffer was created - during a recursive blame, then it also kills the buffer. - -‘<RET>’ (‘magit-show-commit’) - This command shows the commit that last touched the line at point. - -‘<SPC>’ (‘magit-diff-show-or-scroll-up’) - This command updates the commit buffer. - - This either shows the commit that last touched the line at point in - the appropriate buffer, or if that buffer is already being - displayed in the current frame and if that buffer contains - information about that commit, then the buffer is scrolled up - instead. - -‘<DEL>’ (‘magit-diff-show-or-scroll-down’) - This command updates the commit buffer. - - This either shows the commit that last touched the line at point in - the appropriate buffer, or if that buffer is already being - displayed in the current frame and if that buffer contains - information about that commit, then the buffer is scrolled down - instead. - - The following key bindings are available when both Magit-Blame mode -and Read-Only mode are enabled. - -‘b’ (‘magit-blame’) - See above. - -‘n’ (‘magit-blame-next-chunk’) - This command moves to the next chunk. - -‘N’ (‘magit-blame-next-chunk-same-commit’) - This command moves to the next chunk from the same commit. - -‘p’ (‘magit-blame-previous-chunk’) - This command moves to the previous chunk. - -‘P’ (‘magit-blame-previous-chunk-same-commit’) - This command moves to the previous chunk from the same commit. - -‘q’ (‘magit-blame-quit’) - This command turns off Magit-Blame mode. If the buffer was created - during a recursive blame, then it also kills the buffer. - -‘M-w’ (‘magit-blame-copy-hash’) - This command saves the hash of the current chunk’s commit to the - kill ring. - - When the region is active, the command saves the region’s content - instead of the hash, like ‘kill-ring-save’ would. - -‘c’ (‘magit-blame-cycle-style’) - This command changes how blame information is visualized in the - current buffer by cycling through the styles specified using the - option ‘magit-blame-styles’. - - Blaming is also controlled using the following options. - - -- User Option: magit-blame-styles - This option defines a list of styles used to visualize blame - information. For now see its doc-string to learn more. - - -- User Option: magit-blame-echo-style - This option specifies the blame visualization style used by the - command ‘magit-blame-echo’. This must be a symbol that is used as - the identifier for one of the styles defined in - ‘magit-blame-styles’. - - -- User Option: magit-blame-time-format - This option specifies the format string used to display times when - showing blame information. - - -- User Option: magit-blame-read-only - This option controls whether blaming a buffer also makes - temporarily read-only. - - -- User Option: magit-blame-disable-modes - This option lists incompatible minor-modes that should be disabled - temporarily when a buffer contains blame information. They are - enabled again when the buffer no longer shows blame information. - - -- User Option: magit-blame-goto-chunk-hook - This hook is run when moving between chunks. - - -File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top - -6 Manipulating -************** - -* Menu: - -* Creating Repository:: -* Cloning Repository:: -* Staging and Unstaging:: -* Applying:: -* Committing:: -* Branching:: -* Merging:: -* Resolving Conflicts:: -* Rebasing:: -* Cherry Picking:: -* Resetting:: -* Stashing:: - - -File: magit.info, Node: Creating Repository, Next: Cloning Repository, Up: Manipulating - -6.1 Creating Repository -======================= - -‘I’ (‘magit-init’) - This command initializes a repository and then shows the status - buffer for the new repository. - - If the directory is below an existing repository, then the user has - to confirm that a new one should be created inside. If the - directory is the root of the existing repository, then the user has - to confirm that it should be reinitialized. - - -File: magit.info, Node: Cloning Repository, Next: Staging and Unstaging, Prev: Creating Repository, Up: Manipulating - -6.2 Cloning Repository -====================== - -To clone a remote or local repository use ‘C’, which is bound to the -command ‘magit-clone’. This command either act as a transient prefix -command, which binds several infix arguments and suffix commands, or it -can invoke ‘git clone’ directly, depending on whether a prefix argument -is used and on the value of ‘magit-clone-always-transient’. - - -- User Option: magit-clone-always-transient - This option controls whether the command ‘magit-clone’ always acts - as a transient prefix command, regardless of whether a prefix - argument is used or not. If ‘t’, then that command always acts as - a transient prefix. If ‘nil’, then a prefix argument has to be - used for it to act as a transient. - -‘C’ (‘magit-clone’) - This command either acts as a transient prefix command as described - above or does the same thing as ‘transient-clone-regular’ as - described below. - - If it acts as a transient prefix, then it binds the following - suffix commands and several infix arguments. - -‘C C’ (‘magit-clone-regular’) - This command creates a regular clone of an existing repository. - The repository and the target directory are read from the user. - -‘C s’ (‘magit-clone-shallow’) - This command creates a shallow clone of an existing repository. - The repository and the target directory are read from the user. By - default the depth of the cloned history is a single commit, but - with a prefix argument the depth is read from the user. - -‘C >’ (‘magit-clone-sparse’) - This command creates a clone of an existing repository and - initializes a sparse checkout, avoiding a checkout of the full - working tree. To add more directories, use the - ‘magit-sparse-checkout’ transient (see *note Sparse checkouts::). - -‘C b’ (‘magit-clone-bare’) - This command creates a bare clone of an existing repository. The - repository and the target directory are read from the user. - -‘C m’ (‘magit-clone-mirror’) - This command creates a mirror of an existing repository. The - repository and the target directory are read from the user. - - The following suffixes are disabled by default. See *note -(transient)Enabling and Disabling Suffixes:: for how to enable them. - -‘C d’ (‘magit-clone-shallow-since’) - This command creates a shallow clone of an existing repository. - Only commits that were committed after a date are cloned, which is - read from the user. The repository and the target directory are - also read from the user. - -‘C e’ (‘magit-clone-shallow-exclude’) - This command creates a shallow clone of an existing repository. - This reads a branch or tag from the user. Commits that are - reachable from that are not cloned. The repository and the target - directory are also read from the user. - - -- User Option: magit-clone-set-remote-head - This option controls whether cloning causes the reference - ‘refs/remotes/<remote>/HEAD’ to be created in the clone. The - default is to delete the reference after running ‘git clone’, which - insists on creating it. This is because the reference has not been - found to be particularly useful as it is not automatically updated - when the ‘HEAD’ of the remote changes. Setting this option to ‘t’ - preserves Git’s default behavior of creating the reference. - - -- User Option: magit-clone-set-remote.pushDefault - This option controls whether the value of the Git variable - ‘remote.pushDefault’ is set after cloning. - - • If ‘t’, then it is always set without asking. - • If ‘ask’, then the users are asked every time they clone a - repository. - • If ‘nil’, then it is never set. - - -- User Option: magit-clone-default-directory - This option control the default directory name used when reading - the destination for a cloning operation. - - • If ‘nil’ (the default), then the value of ‘default-directory’ - is used. - • If a directory, then that is used. - • If a function, then that is called with the remote url as the - only argument and the returned value is used. - - -- User Option: magit-clone-name-alist - This option maps regular expressions, which match repository names, - to repository urls, making it possible for users to enter short - names instead of urls when cloning repositories. - - Each element has the form ‘(REGEXP HOSTNAME USER)’. When the user - enters a name when a cloning command asks for a name or url, then - that is looked up in this list. The first element whose REGEXP - matches is used. - - The format specified by option ‘magit-clone-url-format’ is used to - turn the name into an url, using HOSTNAME and the repository name. - If the provided name contains a slash, then that is used. - Otherwise if the name omits the owner of the repository, then the - default user specified in the matched entry is used. - - If USER contains a dot, then it is treated as a Git variable and - the value of that is used as the username. Otherwise it is used as - the username itself. - - -- User Option: magit-clone-url-format - The format specified by this option is used when turning repository - names into urls. ‘%h’ is the hostname and ‘%n’ is the repository - name, including the name of the owner. The value can be a string - (representing a single static format) or an alist with elements - ‘(HOSTNAME . FORMAT)’ mapping hostnames to formats. When an alist - is used, the ‘t’ key represents the default format. - - Example of a single format string: - - (setq magit-clone-url-format - "git@%h:%n.git") - - Example of by-hostname format strings: - - (setq magit-clone-url-format - '(("git.example.com" . "git@%h:~%n") - (nil . "git@%h:%n.git"))) - - -- User Option: magit-post-clone-hook - Hook run after the Git process has successfully finished cloning - the repository. When the hook is called, ‘default-directory’ is - let-bound to the directory where the repository has been cloned. - - -File: magit.info, Node: Staging and Unstaging, Next: Applying, Prev: Cloning Repository, Up: Manipulating - -6.3 Staging and Unstaging -========================= - -Like Git, Magit can of course stage and unstage complete files. Unlike -Git, it also allows users to gracefully un-/stage individual hunks and -even just part of a hunk. To stage individual hunks and parts of hunks -using Git directly, one has to use the very modal and rather clumsy -interface of a ‘git add --interactive’ session. - - With Magit, on the other hand, one can un-/stage individual hunks by -just moving point into the respective section inside a diff displayed in -the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To -operate on just parts of a hunk, mark the changes that should be -un-/staged using the region and then press the same key that would be -used to un-/stage. To stage multiple files or hunks at once use a -region that starts inside the heading of such a section and ends inside -the heading of a sibling section of the same type. - - Besides staging and unstaging, Magit also provides several other -"apply variants" that can also operate on a file, multiple files at -once, a hunk, multiple hunks at once, and on parts of a hunk. These -apply variants are described in the next section. - - You can also use Ediff to stage and unstage. See *note Ediffing::. - -‘s’ (‘magit-stage’) - Add the change at point to the staging area. - - With a prefix argument and an untracked file (or files) at point, - stage the file but not its content. This makes it possible to - stage only a subset of the new file’s changes. - -‘S’ (‘magit-stage-modified’) - Stage all changes to files modified in the worktree. Stage all new - content of tracked files and remove tracked files that no longer - exist in the working tree from the index also. With a prefix - argument also stage previously untracked (but not ignored) files. - -‘u’ (‘magit-unstage’) - Remove the change at point from the staging area. - - Only staged changes can be unstaged. But by default this command - performs an action that is somewhat similar to unstaging, when it - is called on a committed change: it reverses the change in the - index but not in the working tree. - -‘U’ (‘magit-unstage-all’) - Remove all changes from the staging area. - - -- User Option: magit-unstage-committed - This option controls whether ‘magit-unstage’ "unstages" committed - changes by reversing them in the index but not the working tree. - The alternative is to raise an error. - -‘M-x magit-reverse-in-index’ - This command reverses the committed change at point in the index - but not the working tree. By default no key is bound directly to - this command, but it is indirectly called when ‘u’ - (‘magit-unstage’) is pressed on a committed change. - - This allows extracting a change from ‘HEAD’, while leaving it in - the working tree, so that it can later be committed using a - separate commit. A typical workflow would be: - - 1. Optionally make sure that there are no uncommitted changes. - 2. Visit the ‘HEAD’ commit and navigate to the change that should - not have been included in that commit. - 3. Type ‘u’ (‘magit-unstage’) to reverse it in the index. This - assumes that ‘magit-unstage-committed’ is non-nil. - 4. Type ‘c e’ to extend ‘HEAD’ with the staged changes, including - those that were already staged before. - 5. Optionally stage the remaining changes using ‘s’ or ‘S’ and - then type ‘c c’ to create a new commit. - -‘M-x magit-reset-index’ - Reset the index to some commit. The commit is read from the user - and defaults to the commit at point. If there is no commit at - point, then it defaults to ‘HEAD’. - -* Menu: - -* Staging from File-Visiting Buffers:: - - -File: magit.info, Node: Staging from File-Visiting Buffers, Up: Staging and Unstaging - -6.3.1 Staging from File-Visiting Buffers ----------------------------------------- - -Fine-grained un-/staging has to be done from the status or a diff -buffer, but it’s also possible to un-/stage all changes made to the file -visited in the current buffer right from inside that buffer. - -‘M-x magit-stage-file’ - When invoked inside a file-visiting buffer, then stage all changes - to that file. In a Magit buffer, stage the file at point if any. - Otherwise prompt for a file to be staged. With a prefix argument - always prompt the user for a file, even in a file-visiting buffer - or when there is a file section at point. - -‘M-x magit-unstage-file’ - When invoked inside a file-visiting buffer, then unstage all - changes to that file. In a Magit buffer, unstage the file at point - if any. Otherwise prompt for a file to be unstaged. With a prefix - argument always prompt the user for a file, even in a file-visiting - buffer or when there is a file section at point. - - -File: magit.info, Node: Applying, Next: Committing, Prev: Staging and Unstaging, Up: Manipulating - -6.4 Applying -============ - -Magit provides several "apply variants": stage, unstage, discard, -reverse, and "regular apply". At least when operating on a hunk they -are all implemented using ‘git apply’, which is why they are called -"apply variants". - - • Stage. Apply a change from the working tree to the index. The - change also remains in the working tree. - - • Unstage. Remove a change from the index. The change remains in - the working tree. - - • Discard. On a staged change, remove it from the working tree and - the index. On an unstaged change, remove it from the working tree - only. - - • Reverse. Reverse a change in the working tree. Both committed and - staged changes can be reversed. Unstaged changes cannot be - reversed. Discard them instead. - - • Apply. Apply a change to the working tree. Both committed and - staged changes can be applied. Unstaged changes cannot be applied - - as they already have been applied. - - The previous section described the staging and unstaging commands. -What follows are the commands which implement the remaining apply -variants. - -‘a’ (‘magit-apply’) - Apply the change at point to the working tree. - - With a prefix argument fallback to a 3-way merge. Doing so causes - the change to be applied to the index as well. - -‘k’ (‘magit-discard’) - Remove the change at point from the working tree. - - On a hunk or file with unresolved conflicts prompt which side to - keep (while discarding the other). If point is within the text of - a side, then keep that side without prompting. - -‘v’ (‘magit-reverse’) - Reverse the change at point in the working tree. - - With a prefix argument fallback to a 3-way merge. Doing so causes - the change to be applied to the index as well. - - With a prefix argument all apply variants attempt a 3-way merge when -appropriate (i.e., when ‘git apply’ is used internally). - - -File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating - -6.5 Committing -============== - -When the user initiates a commit, Magit calls ‘git commit’ without any -arguments, so Git has to get it from the user. It creates the file -‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit -arranges for that editor to be the Emacsclient. Once the user finishes -the editing session, the Emacsclient exits and Git creates the commit -using the file’s content as message. - -* Menu: - -* Initiating a Commit:: -* Editing Commit Messages:: - - -File: magit.info, Node: Initiating a Commit, Next: Editing Commit Messages, Up: Committing - -6.5.1 Initiating a Commit -------------------------- - -Also see *note (gitman)git-commit::. - -‘c’ (‘magit-commit’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘c c’ (‘magit-commit-create’) - Create a new commit on ‘HEAD’. With a prefix argument amend to the - commit at ‘HEAD’ instead. - -‘c a’ (‘magit-commit-amend’) - Amend the last commit. - -‘c e’ (‘magit-commit-extend’) - Amend the last commit, without editing the message. With a prefix - argument keep the committer date, otherwise change it. The option - ‘magit-commit-extend-override-date’ can be used to inverse the - meaning of the prefix argument. - - Non-interactively respect the optional OVERRIDE-DATE argument and - ignore the option. - -‘c w’ (‘magit-commit-reword’) - Reword the last commit, ignoring staged changes. With a prefix - argument keep the committer date, otherwise change it. The option - ‘magit-commit-reword-override-date’ can be used to inverse the - meaning of the prefix argument. - - Non-interactively respect the optional OVERRIDE-DATE argument and - ignore the option. - -‘c f’ (‘magit-commit-fixup’) - Create a fixup commit. - - With a prefix argument the target commit has to be confirmed. - Otherwise the commit at point may be used without confirmation - depending on the value of option ‘magit-commit-squash-confirm’. - -‘c F’ (‘magit-commit-instant-fixup’) - Create a fixup commit and instantly rebase. - -‘c s’ (‘magit-commit-squash’) - Create a squash commit, without editing the squash message. - - With a prefix argument the target commit has to be confirmed. - Otherwise the commit at point may be used without confirmation - depending on the value of option ‘magit-commit-squash-confirm’. - -‘c S’ (‘magit-commit-instant-squash’) - Create a squash commit and instantly rebase. - -‘c A’ (‘magit-commit-augment’) - Create a squash commit, editing the squash message. - - With a prefix argument the target commit has to be confirmed. - Otherwise the commit at point may be used without confirmation - depending on the value of option ‘magit-commit-squash-confirm’. - - -- User Option: magit-commit-ask-to-stage - Whether to ask to stage all unstaged changes when committing and - nothing is staged. - - -- User Option: magit-commit-show-diff - Whether the relevant diff is automatically shown when committing. - - -- User Option: magit-commit-extend-override-date - Whether using ‘magit-commit-extend’ changes the committer date. - - -- User Option: magit-commit-reword-override-date - Whether using ‘magit-commit-reword’ changes the committer date. - - -- User Option: magit-commit-squash-confirm - Whether the commit targeted by squash and fixup has to be - confirmed. When non-nil then the commit at point (if any) is used - as default choice. Otherwise it has to be confirmed. This option - only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The - "instant" variants always require confirmation because making an - error while using those is harder to recover from. - - -- User Option: magit-post-commit-hook - Hook run after creating a commit without the user editing a - message. - - This hook is run by ‘magit-refresh’ if ‘this-command’ is a member - of ‘magit-post-commit-hook-commands’. This only includes commands - named ‘magit-commit-*’ that do *not* require that the user edits - the commit message in a buffer. - - Also see ‘git-commit-post-finish-hook’. - - -- User Option: magit-commit-diff-inhibit-same-window - Whether to inhibit use of same window when showing diff while - committing. - - When writing a commit, then a diff of the changes to be committed - is automatically shown. The idea is that the diff is shown in a - different window of the same frame and for most users that just - works. In other words most users can completely ignore this option - because its value doesn’t make a difference for them. - - However for users who configured Emacs to never create a new window - even when the package explicitly tries to do so, then displaying - two new buffers necessarily means that the first is immediately - replaced by the second. In our case the message buffer is - immediately replaced by the diff buffer, which is of course highly - undesirable. - - A workaround is to suppress this user configuration in this - particular case. Users have to explicitly opt-in by toggling this - option. We cannot enable the workaround unconditionally because - that again causes issues for other users: if the frame is too tiny - or the relevant settings too aggressive, then the diff buffer would - end up being displayed in a new frame. - - Also see <https://github.com/magit/magit/issues/4132>. - - -File: magit.info, Node: Editing Commit Messages, Prev: Initiating a Commit, Up: Committing - -6.5.2 Editing Commit Messages ------------------------------ - -After initiating a commit as described in the previous section, two new -buffers appear. One shows the changes that are about to be committed, -while the other is used to write the message. - - Commit messages are edited in an edit session - in the background -‘git’ is waiting for the editor, in our case ‘emacsclient’, to save the -commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then -return. If the editor returns with a non-zero exit status then ‘git’ -does not create the commit. So the most important commands are those -for finishing and aborting the commit. - -‘C-c C-c’ (‘with-editor-finish’) - Finish the current editing session by returning with exit code 0. - Git then creates the commit using the message it finds in the file. - -‘C-c C-k’ (‘with-editor-cancel’) - Cancel the current editing session by returning with exit code 1. - Git then cancels the commit, but leaves the file untouched. - - In addition to being used by ‘git commit’, messages may also be -stored in a ring that persists until Emacs is closed. By default the -message is stored at the beginning and the end of an edit session -(regardless of whether the session is finished successfully or was -canceled). It is sometimes useful to bring back messages from that -ring. - -‘C-c M-s’ (‘git-commit-save-message’) - Save the current buffer content to the commit message ring. - -‘M-p’ (‘git-commit-prev-message’) - Cycle backward through the commit message ring, after saving the - current message to the ring. With a numeric prefix ARG, go back - ARG comments. - -‘M-n’ (‘git-commit-next-message’) - Cycle forward through the commit message ring, after saving the - current message to the ring. With a numeric prefix ARG, go back - ARG comments. - - By default the diff for the changes that are about to be committed -are automatically shown when invoking the commit. To prevent that, -remove ‘magit-commit-diff’ from ‘server-switch-hook’. - - When amending to an existing commit it may be useful to show either -the changes that are about to be added to that commit or to show those -changes alongside those that have already been committed. - -‘C-c C-d’ (‘magit-diff-while-committing’) - While committing, show the changes that are about to be committed. - While amending, invoking the command again toggles between showing - just the new changes or all the changes that will be committed. - -* Menu: - -* Using the Revision Stack:: -* Commit Pseudo Headers:: -* Commit Mode and Hooks:: -* Commit Message Conventions:: - - -File: magit.info, Node: Using the Revision Stack, Next: Commit Pseudo Headers, Up: Editing Commit Messages - -Using the Revision Stack -........................ - -‘C-c C-w’ (‘magit-pop-revision-stack’) - This command inserts a representation of a revision into the - current buffer. It can be used inside buffers used to write commit - messages but also in other buffers such as buffers used to edit - emails or ChangeLog files. - - By default this command pops the revision which was last added to - the ‘magit-revision-stack’ and inserts it into the current buffer - according to ‘magit-pop-revision-stack-format’. Revisions can be - put on the stack using ‘magit-copy-section-value’ and - ‘magit-copy-buffer-revision’. - - If the stack is empty or with a prefix argument it instead reads a - revision in the minibuffer. By using the minibuffer history this - allows selecting an item which was popped earlier or to insert an - arbitrary reference or revision without first pushing it onto the - stack. - - When reading the revision from the minibuffer, then it might not be - possible to guess the correct repository. When this command is - called inside a repository (e.g., while composing a commit - message), then that repository is used. Otherwise (e.g., while - composing an email) then the repository recorded for the top - element of the stack is used (even though we insert another - revision). If not called inside a repository and with an empty - stack, or with two prefix arguments, then read the repository in - the minibuffer too. - - -- User Option: magit-pop-revision-stack-format - This option controls how the command ‘magit-pop-revision-stack’ - inserts a revision into the current buffer. - - The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this - option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all - of which may be nil or a string (though either one of EOB-FORMAT or - POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil, - then the two formats should be too). - - First INDEX-REGEXP is used to find the previously inserted entry, - by searching backward from point. The first submatch must match - the index number. That number is incremented by one, and becomes - the index number of the entry to be inserted. If you don’t want to - number the inserted revisions, then use nil for INDEX-REGEXP. - - If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT - should contain \"%N\", which is replaced with the number that was - determined in the previous step. - - Both formats, if non-nil and after removing %N, are then expanded - using ‘git show --format=FORMAT ...’ inside TOPLEVEL. - - The expansion of POINT-FORMAT is inserted at point, and the - expansion of EOB-FORMAT is inserted at the end of the buffer (if - the buffer ends with a comment, then it is inserted right before - that). - - -File: magit.info, Node: Commit Pseudo Headers, Next: Commit Mode and Hooks, Prev: Using the Revision Stack, Up: Editing Commit Messages - -Commit Pseudo Headers -..................... - -Some projects use pseudo headers in commit messages. Magit colorizes -such headers and provides some commands to insert such headers. - - -- User Option: git-commit-known-pseudo-headers - A list of Git pseudo headers to be highlighted. - -‘C-c C-i’ (‘git-commit-insert-pseudo-header’) - Insert a commit message pseudo header. - -‘C-c C-a’ (‘git-commit-ack’) - Insert a header acknowledging that you have looked at the commit. - -‘C-c C-r’ (‘git-commit-review’) - Insert a header acknowledging that you have reviewed the commit. - -‘C-c C-s’ (‘git-commit-signoff’) - Insert a header to sign off the commit. - -‘C-c C-t’ (‘git-commit-test’) - Insert a header acknowledging that you have tested the commit. - -‘C-c C-o’ (‘git-commit-cc’) - Insert a header mentioning someone who might be interested. - -‘C-c C-p’ (‘git-commit-reported’) - Insert a header mentioning the person who reported the issue being - fixed by the commit. - -‘C-c M-i’ (‘git-commit-suggested’) - Insert a header mentioning the person who suggested the change. - - -File: magit.info, Node: Commit Mode and Hooks, Next: Commit Message Conventions, Prev: Commit Pseudo Headers, Up: Editing Commit Messages - -Commit Mode and Hooks -..................... - -‘git-commit-mode’ is a minor mode that is only used to establish certain -key bindings. This makes it possible to use an arbitrary major mode in -buffers used to edit commit messages. It is even possible to use -different major modes in different repositories, which is useful when -different projects impose different commit message conventions. - - -- User Option: git-commit-major-mode - The value of this option is the major mode used to edit Git commit - messages. - - Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook -to setup the buffer, except for the key bindings. All other setup -happens in the function ‘git-commit-setup’, which among other things -runs the hook ‘git-commit-setup-hook’. - - -- User Option: git-commit-setup-hook - Hook run at the end of ‘git-commit-setup’. - -The following functions are suitable for this hook: - - -- Function: git-commit-save-message - Save the current buffer content to the commit message ring. - - -- Function: git-commit-setup-changelog-support - After this function is called, ChangeLog entries are treated as - paragraphs. - - -- Function: git-commit-turn-on-auto-fill - Turn on ‘auto-fill-mode’. - - -- Function: git-commit-turn-on-flyspell - Turn on Flyspell mode. Also prevent comments from being checked - and finally check current non-comment text. - - -- Function: git-commit-propertize-diff - Propertize the diff shown inside the commit message buffer. Git - inserts such diffs into the commit message template when the - ‘--verbose’ argument is used. ‘magit-commit’ by default does not - offer that argument because the diff that is shown in a separate - buffer is more useful. But some users disagree, which is why this - function exists. - - -- Function: bug-reference-mode - Hyperlink bug references in the buffer. - - -- Function: with-editor-usage-message - Show usage information in the echo area. - - -- User Option: git-commit-post-finish-hook - Hook run after the user finished writing a commit message. - - This hook is only run after pressing ‘C-c C-c’ in a buffer used to - edit a commit message. If a commit is created without the user - typing a message into a buffer, then this hook is not run. - - This hook is not run until the new commit has been created. If - doing so takes Git longer than one second, then this hook isn’t run - at all. For certain commands such as ‘magit-rebase-continue’ this - hook is never run because doing so would lead to a race condition. - - This hook is only run if ‘magit’ is available. - - Also see ‘magit-post-commit-hook’. - - -File: magit.info, Node: Commit Message Conventions, Prev: Commit Mode and Hooks, Up: Editing Commit Messages - -Commit Message Conventions -.......................... - -Git-Commit highlights certain violations of commonly accepted commit -message conventions. Certain violations even cause Git-Commit to ask -you to confirm that you really want to do that. This nagging can of -course be turned off, but the result of doing that usually is that -instead of some code it’s now the human who is reviewing your commits -who has to waste some time telling you to fix your commits. - - -- User Option: git-commit-summary-max-length - The intended maximal length of the summary line of commit messages. - Characters beyond this column are colorized to indicate that this - preference has been violated. - - -- User Option: git-commit-finish-query-functions - List of functions called to query before performing commit. - - The commit message buffer is current while the functions are - called. If any of them returns nil, then the commit is not - performed and the buffer is not killed. The user should then fix - the issue and try again. - - The functions are called with one argument. If it is non-nil then - that indicates that the user used a prefix argument to force - finishing the session despite issues. Functions should usually - honor this wish and return non-nil. - - By default the only member is ‘git-commit-check-style-conventions’. - - -- Function: git-commit-check-style-conventions - This function checks for violations of certain basic style - conventions. For each violation it asks users if they want to - proceed anyway. - - -- User Option: git-commit-style-convention-checks - This option controls what conventions the function by the same name - tries to enforce. The value is a list of self-explanatory symbols - identifying certain conventions; ‘non-empty-second-line’ and - ‘overlong-summary-line’. - - -File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating - -6.6 Branching -============= - -* Menu: - -* The Two Remotes:: -* Branch Commands:: -* Branch Git Variables:: -* Auxiliary Branch Commands:: - - -File: magit.info, Node: The Two Remotes, Next: Branch Commands, Up: Branching - -6.6.1 The Two Remotes ---------------------- - -The upstream branch of some local branch is the branch into which the -commits on that local branch should eventually be merged, usually -something like ‘origin/master’. For the ‘master’ branch itself the -upstream branch and the branch it is being pushed to, are usually the -same remote branch. But for a feature branch the upstream branch and -the branch it is being pushed to should differ. - - The commits on feature branches too should _eventually_ end up in a -remote branch such as ‘origin/master’ or ‘origin/maint’. Such a branch -should therefore be used as the upstream. But feature branches -shouldn’t be pushed directly to such branches. Instead a feature branch -‘my-feature’ is usually pushed to ‘my-fork/my-feature’ or if you are a -contributor ‘origin/my-feature’. After the new feature has been -reviewed, the maintainer merges the feature into ‘master’. And finally -‘master’ (not ‘my-feature’ itself) is pushed to ‘origin/master’. - - But new features seldom are perfect on the first try, and so feature -branches usually have to be reviewed, improved, and re-pushed several -times. Pushing should therefore be easy to do, and for that reason many -Git users have concluded that it is best to use the remote branch to -which the local feature branch is being pushed as its upstream. - - But luckily Git has long ago gained support for a push-remote which -can be configured separately from the upstream branch, using the -variables ‘branch.<name>.pushRemote’ and ‘remote.pushDefault’. So we no -longer have to choose which of the two remotes should be used as "the -remote". - - Each of the fetching, pulling, and pushing transient commands -features three suffix commands that act on the current branch and some -other branch. Of these, ‘p’ is bound to a command which acts on the -push-remote, ‘u’ is bound to a command which acts on the upstream, and -‘e’ is bound to a command which acts on any other branch. The status -buffer shows unpushed and unpulled commits for both the push-remote and -the upstream. - - It’s fairly simple to configure these two remotes. The values of all -the variables that are related to fetching, pulling, and pushing (as -well as some other branch-related variables) can be inspected and -changed using the command ‘magit-branch-configure’, which is available -from many transient prefix commands that deal with branches. It is also -possible to set the push-remote or upstream while pushing (see *note -Pushing::). - - -File: magit.info, Node: Branch Commands, Next: Branch Git Variables, Prev: The Two Remotes, Up: Branching - -6.6.2 Branch Commands ---------------------- - -The transient prefix command ‘magit-branch’ is used to create and -checkout branches, and to make changes to existing branches. It is not -used to fetch, pull, merge, rebase, or push branches, i.e., this command -deals with branches themselves, not with the commits reachable from -them. Those features are available from separate transient command. - -‘b’ (‘magit-branch’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - - By default it also binds and displays the values of some - branch-related Git variables and allows changing their values. - - -- User Option: magit-branch-direct-configure - This option controls whether the transient command ‘magit-branch’ - can be used to directly change the values of Git variables. This - defaults to ‘t’ (to avoid changing key bindings). When set to - ‘nil’, then no variables are displayed by that transient command, - and its suffix command ‘magit-branch-configure’ has to be used - instead to view and change branch related variables. - -‘b C’ (‘magit-branch-configure’) -‘f C’ -‘F C’ -‘P C’ - This transient prefix command binds commands that set the value of - branch-related variables and displays them in a temporary buffer - until the transient is exited. - - With a prefix argument, this command always prompts for a branch. - - Without a prefix argument this depends on whether it was invoked as - a suffix of ‘magit-branch’ and on the - ‘magit-branch-direct-configure’ option. If ‘magit-branch’ already - displays the variables for the current branch, then it isn’t useful - to invoke another transient that displays them for the same branch. - In that case this command prompts for a branch. - - The variables are described in *note Branch Git Variables::. - -‘b b’ (‘magit-checkout’) - Checkout a revision read in the minibuffer and defaulting to the - branch or arbitrary revision at point. If the revision is a local - branch then that becomes the current branch. If it is something - else then ‘HEAD’ becomes detached. Checkout fails if the working - tree or the staging area contain changes. - -‘b n’ (‘magit-branch-create’) - Create a new branch. The user is asked for a branch or arbitrary - revision to use as the starting point of the new branch. When a - branch name is provided, then that becomes the upstream branch of - the new branch. The name of the new branch is also read in the - minibuffer. - - Also see option ‘magit-branch-prefer-remote-upstream’. - -‘b c’ (‘magit-branch-and-checkout’) - This command creates a new branch like ‘magit-branch-create’, but - then also checks it out. - - Also see option ‘magit-branch-prefer-remote-upstream’. - -‘b l’ (‘magit-branch-checkout’) - This command checks out an existing or new local branch. It reads - a branch name from the user offering all local branches and a - subset of remote branches as candidates. Remote branches for which - a local branch by the same name exists are omitted from the list of - candidates. The user can also enter a completely new branch name. - - • If the user selects an existing local branch, then that is - checked out. - - • If the user selects a remote branch, then it creates and - checks out a new local branch with the same name, and - configures the selected remote branch as the push target. - - • If the user enters a new branch name, then it creates and - checks that out, after also reading the starting-point from - the user. - - In the latter two cases the upstream is also set. Whether it is - set to the chosen starting point or something else depends on the - value of ‘magit-branch-adjust-remote-upstream-alist’. - -‘b s’ (‘magit-branch-spinoff’) - This command creates and checks out a new branch starting at and - tracking the current branch. That branch in turn is reset to the - last commit it shares with its upstream. If the current branch has - no upstream or no unpushed commits, then the new branch is created - anyway and the previously current branch is not touched. - - This is useful to create a feature branch after work has already - began on the old branch (likely but not necessarily "master"). - - If the current branch is a member of the value of option - ‘magit-branch-prefer-remote-upstream’ (which see), then the current - branch will be used as the starting point as usual, but the - upstream of the starting-point may be used as the upstream of the - new branch, instead of the starting-point itself. - - If optional FROM is non-nil, then the source branch is reset to - ‘FROM~’, instead of to the last commit it shares with its upstream. - Interactively, FROM is only ever non-nil, if the region selects - some commits, and among those commits, FROM is the commit that is - the fewest commits ahead of the source branch. - - The commit at the other end of the selection actually does not - matter, all commits between FROM and ‘HEAD’ are moved to the new - branch. If FROM is not reachable from ‘HEAD’ or is reachable from - the source branch’s upstream, then an error is raised. - -‘b S’ (‘magit-branch-spinout’) - This command behaves like ‘magit-branch-spinoff’, except that it - does not change the current branch. If there are any uncommitted - changes, then it behaves exactly like ‘magit-branch-spinoff’. - -‘b x’ (‘magit-branch-reset’) - This command resets a branch, defaulting to the branch at point, to - the tip of another branch or any other commit. - - When the branch being reset is the current branch, then a hard - reset is performed. If there are any uncommitted changes, then the - user has to confirm the reset because those changes would be lost. - - This is useful when you have started work on a feature branch but - realize it’s all crap and want to start over. - - When resetting to another branch and a prefix argument is used, - then the target branch is set as the upstream of the branch that is - being reset. - -‘b k’ (‘magit-branch-delete’) - Delete one or multiple branches. If the region marks multiple - branches, then offer to delete those. Otherwise, prompt for a - single branch to be deleted, defaulting to the branch at point. - - Require confirmation when deleting branches is dangerous in some - way. Option ‘magit-no-confirm’ can be customized to not require - confirmation in certain cases. See its docstring to learn why - confirmation is required by default in certain cases or if a prompt - is confusing. - -‘b m’ (‘magit-branch-rename’) - Rename a branch. The branch and the new name are read in the - minibuffer. With prefix argument the branch is renamed even if - that name conflicts with an existing branch. - - -- User Option: magit-branch-read-upstream-first - When creating a branch, whether to read the upstream branch before - the name of the branch that is to be created. The default is ‘t’, - and I recommend you leave it at that. - - -- User Option: magit-branch-prefer-remote-upstream - This option specifies whether remote upstreams are favored over - local upstreams when creating new branches. - - When a new branch is created, then the branch, commit, or stash at - point is suggested as the starting point of the new branch, or if - there is no such revision at point the current branch. In either - case the user may choose another starting point. - - If the chosen starting point is a branch, then it may also be set - as the upstream of the new branch, depending on the value of the - Git variable ‘branch.autoSetupMerge’. By default this is done for - remote branches, but not for local branches. - - You might prefer to always use some remote branch as upstream. If - the chosen starting point is (1) a local branch, (2) whose name - matches a member of the value of this option, (3) the upstream of - that local branch is a remote branch with the same name, and (4) - that remote branch can be fast-forwarded to the local branch, then - the chosen branch is used as starting point, but its own upstream - is used as the upstream of the new branch. - - Members of this option’s value are treated as branch names that - have to match exactly unless they contain a character that makes - them invalid as a branch name. Recommended characters to use to - trigger interpretation as a regexp are "*" and "^". Some other - characters which you might expect to be invalid, actually are not, - e.g., ".+$" are all perfectly valid. More precisely, if ‘git - check-ref-format --branch STRING’ exits with a non-zero status, - then treat STRING as a regexp. - - Assuming the chosen branch matches these conditions you would end - up with with e.g.: - - feature --upstream--> origin/master - - instead of - - feature --upstream--> master --upstream--> origin/master - - Which you prefer is a matter of personal preference. If you do - prefer the former, then you should add branches such as ‘master’, - ‘next’, and ‘maint’ to the value of this options. - - -- User Option: magit-branch-adjust-remote-upstream-alist - The value of this option is an alist of branches to be used as the - upstream when branching a remote branch. - - When creating a local branch from an ephemeral branch located on a - remote, e.g., a feature or hotfix branch, then that remote branch - should usually not be used as the upstream branch, since the - push-remote already allows accessing it and having both the - upstream and the push-remote reference the same related branch - would be wasteful. Instead a branch like "maint" or "master" - should be used as the upstream. - - This option allows specifying the branch that should be used as the - upstream when branching certain remote branches. The value is an - alist of the form ‘((UPSTREAM . RULE)...)’. The first matching - element is used, the following elements are ignored. - - UPSTREAM is the branch to be used as the upstream for branches - specified by RULE. It can be a local or a remote branch. - - RULE can either be a regular expression, matching branches whose - upstream should be the one specified by UPSTREAM. Or it can be a - list of the only branches that should *not* use UPSTREAM; all other - branches will. Matching is done after stripping the remote part of - the name of the branch that is being branched from. - - If you use a finite set of non-ephemeral branches across all your - repositories, then you might use something like: - - (("origin/master" . ("master" "next" "maint"))) - - Or if the names of all your ephemeral branches contain a slash, at - least in some repositories, then a good value could be: - - (("origin/master" . "/")) - - Of course you can also fine-tune: - - (("origin/maint" . "\\`hotfix/") - ("origin/master" . "\\`feature/")) - - UPSTREAM can be a local branch: - - (("master" . ("master" "next" "maint"))) - - Because the main branch is no longer almost always named "master" you -should also account for other common names: - - (("main" . ("main" "master" "next" "maint")) - ("master" . ("main" "master" "next" "maint"))) - - -- Command: magit-branch-orphan - This command creates and checks out a new orphan branch with - contents from a given revision. - - -- Command: magit-branch-or-checkout - This command is a hybrid between ‘magit-checkout’ and - ‘magit-branch-and-checkout’ and is intended as a replacement for - the former in ‘magit-branch’. - - It first asks the user for an existing branch or revision. If the - user input actually can be resolved as a branch or revision, then - it checks that out, just like ‘magit-checkout’ would. - - Otherwise it creates and checks out a new branch using the input as - its name. Before doing so it reads the starting-point for the new - branch. This is similar to what ‘magit-branch-and-checkout’ does. - - To use this command instead of ‘magit-checkout’ add this to your - init file: - - (transient-replace-suffix 'magit-branch 'magit-checkout - '("b" "dwim" magit-branch-or-checkout)) - - -File: magit.info, Node: Branch Git Variables, Next: Auxiliary Branch Commands, Prev: Branch Commands, Up: Branching - -6.6.3 Branch Git Variables --------------------------- - -These variables can be set from the transient prefix command -‘magit-branch-configure’. By default they can also be set from -‘magit-branch’. See *note Branch Commands::. - - -- Variable: branch.NAME.merge - Together with ‘branch.NAME.remote’ this variable defines the - upstream branch of the local branch named NAME. The value of this - variable is the full reference of the upstream _branch_. - - -- Variable: branch.NAME.remote - Together with ‘branch.NAME.merge’ this variable defines the - upstream branch of the local branch named NAME. The value of this - variable is the name of the upstream _remote_. - - -- Variable: branch.NAME.rebase - This variable controls whether pulling into the branch named NAME - is done by rebasing or by merging the fetched branch. - - • When ‘true’ then pulling is done by rebasing. - • When ‘false’ then pulling is done by merging. - • When undefined then the value of ‘pull.rebase’ is used. The - default of that variable is ‘false’. - - -- Variable: branch.NAME.pushRemote - This variable specifies the remote that the branch named NAME is - usually pushed to. The value has to be the name of an existing - remote. - - It is not possible to specify the name of _branch_ to push the - local branch to. The name of the remote branch is always the same - as the name of the local branch. - - If this variable is undefined but ‘remote.pushDefault’ is defined, - then the value of the latter is used. By default - ‘remote.pushDefault’ is undefined. - - -- Variable: branch.NAME.description - This variable can be used to describe the branch named NAME. That - description is used, e.g., when turning the branch into a series of - patches. - - The following variables specify defaults which are used if the above -branch-specific variables are not set. - - -- Variable: pull.rebase - This variable specifies whether pulling is done by rebasing or by - merging. It can be overwritten using ‘branch.NAME.rebase’. - - • When ‘true’ then pulling is done by rebasing. - • When ‘false’ (the default) then pulling is done by merging. - - Since it is never a good idea to merge the upstream branch into a - feature or hotfix branch and most branches are such branches, you - should consider setting this to ‘true’, and ‘branch.master.rebase’ - to ‘false’. - - -- Variable: remote.pushDefault - This variable specifies what remote the local branches are usually - pushed to. This can be overwritten per branch using - ‘branch.NAME.pushRemote’. - - The following variables are used during the creation of a branch and -control whether the various branch-specific variables are automatically -set at this time. - - -- Variable: branch.autoSetupMerge - This variable specifies under what circumstances creating a branch - NAME should result in the variables ‘branch.NAME.merge’ and - ‘branch.NAME.remote’ being set according to the starting point used - to create the branch. If the starting point isn’t a branch, then - these variables are never set. - - • When ‘always’ then the variables are set regardless of whether - the starting point is a local or a remote branch. - • When ‘true’ (the default) then the variables are set when the - starting point is a remote branch, but not when it is a local - branch. - • When ‘false’ then the variables are never set. - - -- Variable: branch.autoSetupRebase - This variable specifies whether creating a branch NAME should - result in the variable ‘branch.NAME.rebase’ being set to ‘true’. - - • When ‘always’ then the variable is set regardless of whether - the starting point is a local or a remote branch. - • When ‘local’ then the variable are set when the starting point - is a local branch, but not when it is a remote branch. - • When ‘remote’ then the variable are set when the starting - point is a remote branch, but not when it is a local branch. - • When ‘never’ (the default) then the variable is never set. - - Note that the respective commands always change the repository-local -values. If you want to change the global value, which is used when the -local value is undefined, then you have to do so on the command line, -e.g.: - - git config --global remote.autoSetupMerge always - - For more information about these variables you should also see *note -(gitman)git-config::. Also see *note (gitman)git-branch::. , *note -(gitman)git-checkout::. and *note Pushing::. - - -- User Option: magit-prefer-remote-upstream - This option controls whether commands that read a branch from the - user and then set it as the upstream branch, offer a local or a - remote branch as default completion candidate, when they have the - choice. - - This affects all commands that use ‘magit-read-upstream-branch’ or - ‘magit-read-starting-point’, which includes all commands that - change the upstream and many which create new branches. - - -File: magit.info, Node: Auxiliary Branch Commands, Prev: Branch Git Variables, Up: Branching - -6.6.4 Auxiliary Branch Commands -------------------------------- - -These commands are not available from the transient ‘magit-branch’ by -default. - - -- Command: magit-branch-shelve - This command shelves a branch. This is done by deleting the - branch, and creating a new reference "refs/shelved/BRANCH-NAME" - pointing at the same commit as the branch pointed at. If the - deleted branch had a reflog, then that is preserved as the reflog - of the new reference. - - This is useful if you want to move a branch out of sight, but are - not ready to completely discard it yet. - - -- Command: magit-branch-unshelve - This command unshelves a branch that was previously shelved using - ‘magit-branch-shelve’. This is done by deleting the reference - "refs/shelved/BRANCH-NAME" and creating a branch "BRANCH-NAME" - pointing at the same commit as the deleted reference pointed at. - If the deleted reference had a reflog, then that is restored as the - reflog of the branch. - - -File: magit.info, Node: Merging, Next: Resolving Conflicts, Prev: Branching, Up: Manipulating - -6.7 Merging -=========== - -Also see *note (gitman)git-merge::. For information on how to resolve -merge conflicts see the next section. - -‘m’ (‘magit-merge’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no merge is in progress, then the transient features the -following suffix commands. - -‘m m’ (‘magit-merge-plain’) - This command merges another branch or an arbitrary revision into - the current branch. The branch or revision to be merged is read in - the minibuffer and defaults to the branch at point. - - Unless there are conflicts or a prefix argument is used, then the - resulting merge commit uses a generic commit message, and the user - does not get a chance to inspect or change it before the commit is - created. With a prefix argument this does not actually create the - merge commit, which makes it possible to inspect how conflicts were - resolved and to adjust the commit message. - -‘m e’ (‘magit-merge-editmsg’) - This command merges another branch or an arbitrary revision into - the current branch and opens a commit message buffer, so that the - user can make adjustments. The commit is not actually created - until the user finishes with ‘C-c C-c’. - -‘m n’ (‘magit-merge-nocommit’) - This command merges another branch or an arbitrary revision into - the current branch, but does not actually create the merge commit. - The user can then further adjust the merge, even when automatic - conflict resolution succeeded and/or adjust the commit message. - -‘m a’ (‘magit-merge-absorb’) - This command merges another local branch into the current branch - and then removes the former. - - Before the source branch is merged, it is first force pushed to its - push-remote, provided the respective remote branch already exists. - This ensures that the respective pull-request (if any) won’t get - stuck on some obsolete version of the commits that are being - merged. Finally, if ‘magit-branch-pull-request’ was used to create - the merged branch, then the respective remote branch is also - removed. - -‘m i’ (‘magit-merge-into’) - This command merges the current branch into another local branch - and then removes the former. The latter becomes the new current - branch. - - Before the source branch is merged, it is first force pushed to its - push-remote, provided the respective remote branch already exists. - This ensures that the respective pull-request (if any) won’t get - stuck on some obsolete version of the commits that are being - merged. Finally, if ‘magit-branch-pull-request’ was used to create - the merged branch, then the respective remote branch is also - removed. - -‘m s’ (‘magit-merge-squash’) - This command squashes the changes introduced by another branch or - an arbitrary revision into the current branch. This only applies - the changes made by the squashed commits. No information is - preserved that would allow creating an actual merge commit. - Instead of this command you should probably use a command from the - apply transient. - -‘m p’ (‘magit-merge-preview’) - This command shows a preview of merging another branch or an - arbitrary revision into the current branch. - - Note that commands, that normally change how a diff is displayed, - do not work in buffers created by this command, because the - underlying Git command does not support diff arguments. - - When a merge is in progress, then the transient instead features the -following suffix commands. - -‘m m’ (‘magit-merge’) - After the user resolved conflicts, this command proceeds with the - merge. If some conflicts weren’t resolved, then this command - fails. - -‘m a’ (‘magit-merge-abort’) - This command aborts the current merge operation. - - -File: magit.info, Node: Resolving Conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating - -6.8 Resolving Conflicts -======================= - -When merging branches (or otherwise combining or changing history) -conflicts can occur. If you edited two completely different parts of -the same file in two branches and then merge one of these branches into -the other, then Git can resolve that on its own, but if you edit the -same area of a file, then a human is required to decide how the two -versions, or "sides of the conflict", are to be combined into one. - - Here we can only provide a brief introduction to the subject and -point you toward some tools that can help. If you are new to this, then -please also consult Git’s own documentation as well as other resources. - - If a file has conflicts and Git cannot resolve them by itself, then -it puts both versions into the affected file along with special markers -whose purpose is to denote the boundaries of the unresolved part of the -file and between the different versions. These boundary lines begin -with the strings consisting of seven times the same character, one of -‘<’, ‘|’, ‘=’ and ‘>’, and are followed by information about the source -of the respective versions, e.g.: - - <<<<<<< HEAD - Take the blue pill. - ======= - Take the red pill. - >>>>>>> feature - - In this case you have chosen to take the red pill on one branch and -on another you picked the blue pill. Now that you are merging these two -diverging branches, Git cannot possibly know which pill you want to -take. - - To resolve that conflict you have to create a version of the affected -area of the file by keeping only one of the sides, possibly by editing -it in order to bring in the changes from the other side, remove the -other versions as well as the markers, and then stage the result. A -possible resolution might be: - - Take both pills. - - Often it is useful to see not only the two sides of the conflict but -also the "original" version from before the same area of the file was -modified twice on different branches. Instruct Git to insert that -version as well by running this command once: - - git config --global merge.conflictStyle diff3 - - The above conflict might then have looked like this: - - <<<<<<< HEAD - Take the blue pill. - ||||||| merged common ancestors - Take either the blue or the red pill, but not both. - ======= - Take the red pill. - >>>>>>> feature - - If that were the case, then the above conflict resolution would not -have been correct, which demonstrates why seeing the original version -alongside the conflicting versions can be useful. - - You can perform the conflict resolution completely by hand, but Emacs -also provides some packages that help in the process: Smerge, Ediff -(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does -not provide its own tools for conflict resolution, but it does make -using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so -you probably don’t want to use the latter anyway.) - - In the Magit status buffer, files with unresolved conflicts are -listed in the "Unstaged changes" and/or "Staged changes" sections. They -are prefixed with the word "unmerged", which in this context essentially -is a synonym for "unresolved". - - Pressing ‘RET’ while point is on such a file section shows a buffer -visiting that file, turns on ‘smerge-mode’ in that buffer, and places -point inside the first area with conflicts. You should then resolve -that conflict using regular edit commands and/or Smerge commands. - - Unfortunately Smerge does not have a manual, but you can get a list -of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a -command name to read its documentation. - - Normally you would edit one version and then tell Smerge to keep only -that version. Use ‘C-c ^ m’ (‘smerge-keep-mine’) to keep the ‘HEAD’ -version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that -follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting -area in the same file. Once you are done resolving conflicts, return to -the Magit status buffer. The file should now be shown as "modified", no -longer as "unmerged", because Smerge automatically stages the file when -you save the buffer after resolving the last conflict. - - Magit now wraps the mentioned Smerge commands, allowing you to use -these key bindings without having to go to the file-visiting buffer. -Additionally ‘k’ (‘magit-discard’) on a hunk with unresolved conflicts -asks which side to keep or, if point is on a side, then it keeps it -without prompting. Similarly ‘k’ on a unresolved file ask which side to -keep. - - Alternatively you could use Ediff, which uses separate buffers for -the different versions of the file. To resolve conflicts in a file -using Ediff press ‘e’ while point is on such a file in the status -buffer. - - Ediff can be used for other purposes as well. For more information -on how to enter Ediff from Magit, see *note Ediffing::. Explaining how -to use Ediff is beyond the scope of this manual, instead see *note -(ediff)Top::. - - If you are unsure whether you should Smerge or Ediff, then use the -former. It is much easier to understand and use, and except for truly -complex conflicts, the latter is usually overkill. - - -File: magit.info, Node: Rebasing, Next: Cherry Picking, Prev: Resolving Conflicts, Up: Manipulating - -6.9 Rebasing -============ - -Also see *note (gitman)git-rebase::. For information on how to resolve -conflicts that occur during rebases see the preceding section. - -‘r’ (‘magit-rebase’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no rebase is in progress, then the transient features the -following suffix commands. - - Using one of these commands _starts_ a rebase sequence. Git might -then stop somewhere along the way, either because you told it to do so, -or because applying a commit failed due to a conflict. When that -happens, then the status buffer shows information about the rebase -sequence which is in progress in a section similar to a log section. -See *note Information About In-Progress Rebase::. - - For information about the upstream and the push-remote, see *note The -Two Remotes::. - -‘r p’ (‘magit-rebase-onto-pushremote’) - This command rebases the current branch onto its push-remote. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘r u’ (‘magit-rebase-onto-upstream’) - This command rebases the current branch onto its upstream branch. - - With a prefix argument or when the upstream is either not - configured or unusable, then let the user first configure the - upstream. - -‘r e’ (‘magit-rebase-branch’) - This command rebases the current branch onto a branch read in the - minibuffer. All commits that are reachable from head but not from - the selected branch TARGET are being rebased. - -‘r s’ (‘magit-rebase-subset’) - This command starts a non-interactive rebase sequence to transfer - commits from START to ‘HEAD’ onto NEWBASE. START has to be - selected from a list of recent commits. - - By default Magit uses the ‘--autostash’ argument, which causes -uncommitted changes to be stored in a stash before the rebase begins. -These changes are restored after the rebase completes and if possible -the stash is removed. If the stash does not apply cleanly, then the -stash is not removed. In case something goes wrong when resolving the -conflicts, this allows you to start over. - - Even though one of the actions is dedicated to interactive rebases, -the transient also features the infix argument ‘--interactive’. This -can be used to turn one of the other, non-interactive rebase variants -into an interactive rebase. - - For example if you want to clean up a feature branch and at the same -time rebase it onto ‘master’, then you could use ‘r-iu’. But we -recommend that you instead do that in two steps. First use ‘ri’ to -cleanup the feature branch, and then in a second step ‘ru’ to rebase it -onto ‘master’. That way if things turn out to be more complicated than -you thought and/or you make a mistake and have to start over, then you -only have to redo half the work. - - Explicitly enabling ‘--interactive’ won’t have an effect on the -following commands as they always use that argument anyway, even if it -is not enabled in the transient. - -‘r i’ (‘magit-rebase-interactive’) - This command starts an interactive rebase sequence. - -‘r f’ (‘magit-rebase-autosquash’) - This command combines squash and fixup commits with their intended - targets. - -‘r m’ (‘magit-rebase-edit-commit’) - This command starts an interactive rebase sequence that lets the - user edit a single older commit. - -‘r w’ (‘magit-rebase-reword-commit’) - This command starts an interactive rebase sequence that lets the - user reword a single older commit. - -‘r k’ (‘magit-rebase-remove-commit’) - This command removes a single older commit using rebase. - - When a rebase is in progress, then the transient instead features the -following suffix commands. - -‘r r’ (‘magit-rebase-continue’) - This command restart the current rebasing operation. - - In some cases this pops up a commit message buffer for you do edit. - With a prefix argument the old message is reused as-is. - -‘r s’ (‘magit-rebase-skip’) - This command skips the current commit and restarts the current - rebase operation. - -‘r e’ (‘magit-rebase-edit’) - This command lets the user edit the todo list of the current rebase - operation. - -‘r a’ (‘magit-rebase-abort’) - This command aborts the current rebase operation, restoring the - original branch. - -* Menu: - -* Editing Rebase Sequences:: -* Information About In-Progress Rebase:: - - -File: magit.info, Node: Editing Rebase Sequences, Next: Information About In-Progress Rebase, Up: Rebasing - -6.9.1 Editing Rebase Sequences ------------------------------- - -‘C-c C-c’ (‘with-editor-finish’) - Finish the current editing session by returning with exit code 0. - Git then uses the rebase instructions it finds in the file. - -‘C-c C-k’ (‘with-editor-cancel’) - Cancel the current editing session by returning with exit code 1. - Git then forgoes starting the rebase sequence. - -‘<RET>’ (‘git-rebase-show-commit’) - Show the commit on the current line in another buffer and select - that buffer. - -‘<SPC>’ (‘git-rebase-show-or-scroll-up’) - Show the commit on the current line in another buffer without - selecting that buffer. If the revision buffer is already visible - in another window of the current frame, then instead scroll that - window up. - -‘<DEL>’ (‘git-rebase-show-or-scroll-down’) - Show the commit on the current line in another buffer without - selecting that buffer. If the revision buffer is already visible - in another window of the current frame, then instead scroll that - window down. - -‘p’ (‘git-rebase-backward-line’) - Move to previous line. - -‘n’ (‘forward-line’) - Move to next line. - -‘M-p’ (‘git-rebase-move-line-up’) - Move the current commit (or command) up. - -‘M-n’ (‘git-rebase-move-line-down’) - Move the current commit (or command) down. - -‘r’ (‘git-rebase-reword’) - Edit message of commit on current line. - -‘e’ (‘git-rebase-edit’) - Stop at the commit on the current line. - -‘s’ (‘git-rebase-squash’) - Meld commit on current line into previous commit, and edit message. - -‘f’ (‘git-rebase-fixup’) - Meld commit on current line into previous commit, discarding the - current commit’s message. - -‘k’ (‘git-rebase-kill-line’) - Kill the current action line. - -‘c’ (‘git-rebase-pick’) - Use commit on current line. - -‘x’ (‘git-rebase-exec’) - Insert a shell command to be run after the proceeding commit. - - If there already is such a command on the current line, then edit - that instead. With a prefix argument insert a new command even - when there already is one on the current line. With empty input - remove the command on the current line, if any. - -‘b’ (‘git-rebase-break’) - Insert a break action before the current line, instructing Git to - return control to the user. - -‘y’ (‘git-rebase-insert’) - Read an arbitrary commit and insert it below current line. - -‘C-x u’ (‘git-rebase-undo’) - Undo some previous changes. Like ‘undo’ but works in read-only - buffers. - - -- User Option: git-rebase-auto-advance - Whether to move to next line after changing a line. - - -- User Option: git-rebase-show-instructions - Whether to show usage instructions inside the rebase buffer. - - -- User Option: git-rebase-confirm-cancel - Whether confirmation is required to cancel. - - When a rebase is performed with the ‘--rebase-merges’ option, the -sequence will include a few other types of actions and the following -commands become relevant. - -‘l’ (‘git-rebase-label’) - This commands inserts a label action or edits the one at point. - -‘t’ (‘git-rebase-reset’) - This command inserts a reset action or edits the one at point. The - prompt will offer the labels that are currently present in the - buffer. - -‘MM’ (‘git-rebase-merge’) - The command inserts a merge action or edits the one at point. The - prompt will offer the labels that are currently present in the - buffer. Specifying a message to reuse via ‘-c’ or ‘-C’ is not - supported; an editor will always be invoked for the merge. - -‘Mt’ (‘git-rebase-merge-toggle-editmsg’) - This command toggles between the ‘-C’ and ‘-c’ options of the merge - action at point. These options both specify a commit whose message - should be reused. The lower-case variant instructs Git to invoke - the editor when creating the merge, allowing the user to edit the - message. - - -File: magit.info, Node: Information About In-Progress Rebase, Prev: Editing Rebase Sequences, Up: Rebasing - -6.9.2 Information About In-Progress Rebase ------------------------------------------- - -While a rebase sequence is in progress, the status buffer features a -section that lists the commits that have already been applied as well as -the commits that still have to be applied. - - The commits are split in two halves. When rebase stops at a commit, -either because the user has to deal with a conflict or because s/he -explicitly requested that rebase stops at that commit, then point is -placed on the commit that separates the two groups, i.e., on ‘HEAD’. -The commits above it have not been applied yet, while the ‘HEAD’ and the -commits below it have already been applied. In between these two groups -of applied and yet-to-be applied commits, there sometimes is a commit -which has been dropped. - - Each commit is prefixed with a word and these words are additionally -shown in different colors to indicate the status of the commits. - - The following colors are used: - - • Commits that use the same foreground color as the ‘default’ face - have not been applied yet. - - • Yellow commits have some special relationship to the commit rebase - stopped at. This is used for the words "join", "goal", "same" and - "work" (see below). - - • Gray commits have already been applied. - - • The blue commit is the ‘HEAD’ commit. - - • The green commit is the commit the rebase sequence stopped at. If - this is the same commit as ‘HEAD’ (e.g., because you haven’t done - anything yet after rebase stopped at the commit, then this commit - is shown in blue, not green). There can only be a green *and* a - blue commit at the same time, if you create one or more new commits - after rebase stops at a commit. - - • Red commits have been dropped. They are shown for reference only, - e.g., to make it easier to diff. - - Of course these colors are subject to the color-theme in use. - - The following words are used: - - • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and - ‘fixup’ have not been applied yet. These words have the same - meaning here as they do in the buffer used to edit the rebase - sequence. See *note Editing Rebase Sequences::. When the - ‘--rebase-merges’ option was specified, ‘reset’, ‘label’, and - ‘merge’ lines may also be present. - - • Commits prefixed with ‘done’ and ‘onto’ have already been applied. - It is possible for such a commit to be the ‘HEAD’, in which case it - is blue. Otherwise it is grey. - - • The commit prefixed with ‘onto’ is the commit on top of which - all the other commits are being re-applied. This commit - itself did not have to be re-applied, it is the commit rebase - did rewind to before starting to re-apply other commits. - - • Commits prefixed with ‘done’ have already been re-applied. - This includes commits that have been re-applied but also new - commits that you have created during the rebase. - - • All other commits, those not prefixed with any of the above words, - are in some way related to the commit at which rebase stopped. - - To determine whether a commit is related to the stopped-at commit - their hashes, trees and patch-ids (1) are being compared. The - commit message is not used for this purpose. - - Generally speaking commits that are related to the stopped-at - commit can have any of the used colors, though not all color/word - combinations are possible. - - Words used for stopped-at commits are: - - • When a commit is prefixed with ‘void’, then that indicates - that Magit knows for sure that all the changes in that commit - have been applied using several new commits. This commit is - no longer reachable from ‘HEAD’, and it also isn’t one of the - commits that will be applied when resuming the session. - - • When a commit is prefixed with ‘join’, then that indicates - that the rebase sequence stopped at that commit due to a - conflict - you now have to join (merge) the changes with what - has already been applied. In a sense this is the commit - rebase stopped at, but while its effect is already in the - index and in the worktree (with conflict markers), the commit - itself has not actually been applied yet (it isn’t the - ‘HEAD’). So it is shown in yellow, like the other commits - that still have to be applied. - - • When a commit is prefixed with ‘stop’ or a _blue_ or _green_ - ‘same’, then that indicates that rebase stopped at this - commit, that it is still applied or has been applied again, - and that at least its patch-id is unchanged. - - • When a commit is prefixed with ‘stop’, then that - indicates that rebase stopped at that commit because you - requested that earlier, and its patch-id is unchanged. - It might even still be the exact same commit. - - • When a commit is prefixed with a _blue_ or _green_ - ‘same’, then that indicates that while its tree or hash - changed, its patch-id did not. If it is blue, then it is - the ‘HEAD’ commit (as always for blue). When it is - green, then it no longer is ‘HEAD’ because other commit - have been created since (but before continuing the - rebase). - - • When a commit is prefixed with ‘goal’, a _yellow_ ‘same,’ or - ‘work’, then that indicates that rebase applied that commit - but that you then reset ‘HEAD’ to an earlier commit (likely to - split it up into multiple commits), and that there are some - uncommitted changes remaining which likely (but not - necessarily) originate from that commit. - - • When a commit is prefixed with ‘goal’, then that - indicates that it is still possible to create a new - commit with the exact same tree (the "goal") without - manually editing any files, by committing the index, or - by staging all changes and then committing that. This is - the case when the original tree still exists in the index - or worktree in untainted form. - - • When a commit is prefixed with a yellow ‘same’, then that - indicates that it is no longer possible to create a - commit with the exact same tree, but that it is still - possible to create a commit with the same patch-id. This - would be the case if you created a new commit with other - changes, but the changes from the original commit still - exist in the index or working tree in untainted form. - - • When a commit is prefixed with ‘work’, then that - indicates that you reset ‘HEAD’ to an earlier commit, and - that there are some staged and/or unstaged changes - (likely, but not necessarily) originating from that - commit. However it is no longer possible to create a new - commit with the same tree or at least the same patch-id - because you have already made other changes. - - • When a commit is prefixed with ‘poof’ or ‘gone’, then that - indicates that rebase applied that commit but that you then - reset ‘HEAD’ to an earlier commit (likely to split it up into - multiple commits), and that there are no uncommitted changes. - - • When a commit is prefixed with ‘poof’, then that - indicates that it is no longer reachable from ‘HEAD’, but - that it has been replaced with one or more commits, which - together have the exact same effect. - - • When a commit is prefixed with ‘gone’, then that - indicates that it is no longer reachable from ‘HEAD’ and - that we also cannot determine whether its changes are - still in effect in one or more new commits. They might - be, but if so, then there must also be other changes - which makes it impossible to know for sure. - - Do not worry if you do not fully understand the above. That’s okay, -you will acquire a good enough understanding through practice. - - For other sequence operations such as cherry-picking, a similar -section is displayed, but they lack some of the features described -above, due to limitations in the git commands used to implement them. -Most importantly these sequences only support "picking" a commit but not -other actions such as "rewording", and they do not keep track of the -commits which have already been applied. - - ---------- Footnotes ---------- - - (1) The patch-id is a hash of the _changes_ introduced by a commit. -It differs from the hash of the commit itself, which is a hash of the -result of applying that change (i.e., the resulting trees and blobs) as -well as author and committer information, the commit message, and the -hashes of the parents of the commit. The patch-id hash on the other -hand is created only from the added and removed lines, even line numbers -and whitespace changes are ignored when calculating this hash. The -patch-ids of two commits can be used to answer the question "Do these -commits make the same change?". - - -File: magit.info, Node: Cherry Picking, Next: Resetting, Prev: Rebasing, Up: Manipulating - -6.10 Cherry Picking -=================== - -Also see *note (gitman)git-cherry-pick::. - -‘A’ (‘magit-cherry-pick’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no cherry-pick or revert is in progress, then the transient -features the following suffix commands. - -‘A A’ (‘magit-cherry-copy’) - This command copies COMMITS from another branch onto the current - branch. If the region selects multiple commits, then those are - copied, without prompting. Otherwise the user is prompted for a - commit or range, defaulting to the commit at point. - -‘A a’ (‘magit-cherry-apply’) - This command applies the changes in COMMITS from another branch - onto the current branch. If the region selects multiple commits, - then those are used, without prompting. Otherwise the user is - prompted for a commit or range, defaulting to the commit at point. - - This command also has a top-level binding, which can be invoked - without using the transient by typing ‘a’ at the top-level. - - The following commands not only apply some commits to some branch, -but also remove them from some other branch. The removal is performed -using either ‘git-update-ref’ or if necessary ‘git-rebase’. Both -applying commits as well as removing them using ‘git-rebase’ can lead to -conflicts. If that happens, then these commands abort and you not only -have to resolve the conflicts but also finish the process the same way -you would have to if these commands didn’t exist at all. - -‘A h’ (‘magit-cherry-harvest’) - This command moves the selected COMMITS that must be located on - another BRANCH onto the current branch instead, removing them from - the former. When this command succeeds, then the same branch is - current as before. - - Applying the commits on the current branch or removing them from - the other branch can lead to conflicts. When that happens, then - this command stops and you have to resolve the conflicts and then - finish the process manually. - -‘A d’ (‘magit-cherry-donate’) - This command moves the selected COMMITS from the current branch - onto another existing BRANCH, removing them from the former. When - this command succeeds, then the same branch is current as before. - ‘HEAD’ is allowed to be detached initially. - - Applying the commits on the other branch or removing them from the - current branch can lead to conflicts. When that happens, then this - command stops and you have to resolve the conflicts and then finish - the process manually. - -‘A n’ (‘magit-cherry-spinout’) - This command moves the selected COMMITS from the current branch - onto a new branch BRANCH, removing them from the former. When this - command succeeds, then the same branch is current as before. - - Applying the commits on the other branch or removing them from the - current branch can lead to conflicts. When that happens, then this - command stops and you have to resolve the conflicts and then finish - the process manually. - -‘A s’ (‘magit-cherry-spinoff’) - This command moves the selected COMMITS from the current branch - onto a new branch BRANCH, removing them from the former. When this - command succeeds, then the new branch is checked out. - - Applying the commits on the other branch or removing them from the - current branch can lead to conflicts. When that happens, then this - command stops and you have to resolve the conflicts and then finish - the process manually. - - When a cherry-pick or revert is in progress, then the transient -instead features the following suffix commands. - -‘A A’ (‘magit-sequence-continue’) - Resume the current cherry-pick or revert sequence. - -‘A s’ (‘magit-sequence-skip’) - Skip the stopped at commit during a cherry-pick or revert sequence. - -‘A a’ (‘magit-sequence-abort’) - Abort the current cherry-pick or revert sequence. This discards - all changes made since the sequence started. - -* Menu: - -* Reverting:: - - -File: magit.info, Node: Reverting, Up: Cherry Picking - -6.10.1 Reverting ----------------- - -‘V’ (‘magit-revert’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no cherry-pick or revert is in progress, then the transient -features the following suffix commands. - -‘V V’ (‘magit-revert-and-commit’) - Revert a commit by creating a new commit. Prompt for a commit, - defaulting to the commit at point. If the region selects multiple - commits, then revert all of them, without prompting. - -‘V v’ (‘magit-revert-no-commit’) - Revert a commit by applying it in reverse to the working tree. - Prompt for a commit, defaulting to the commit at point. If the - region selects multiple commits, then revert all of them, without - prompting. - - When a cherry-pick or revert is in progress, then the transient -instead features the following suffix commands. - -‘V V’ (‘magit-sequence-continue’) - Resume the current cherry-pick or revert sequence. - -‘V s’ (‘magit-sequence-skip’) - Skip the stopped at commit during a cherry-pick or revert sequence. - -‘V a’ (‘magit-sequence-abort’) - Abort the current cherry-pick or revert sequence. This discards - all changes made since the sequence started. - - -File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry Picking, Up: Manipulating - -6.11 Resetting -============== - -Also see *note (gitman)git-reset::. - -‘x’ (‘magit-reset-quickly’) - Reset the ‘HEAD’ and index to some commit read from the user and - defaulting to the commit at point, and possibly also reset the - working tree. With a prefix argument reset the working tree - otherwise don’t. - -‘X m’ (‘magit-reset-mixed’) - Reset the ‘HEAD’ and index to some commit read from the user and - defaulting to the commit at point. The working tree is kept as-is. - -‘X s’ (‘magit-reset-soft’) - Reset the ‘HEAD’ to some commit read from the user and defaulting - to the commit at point. The index and the working tree are kept - as-is. - -‘X h’ (‘magit-reset-hard’) - Reset the ‘HEAD’, index, and working tree to some commit read from - the user and defaulting to the commit at point. - -‘X k’ (‘magit-reset-keep’) - Reset the ‘HEAD’, index, and working tree to some commit read from - the user and defaulting to the commit at point. Uncommitted - changes are kept as-is. - -‘X i’ (‘magit-reset-index’) - Reset the index to some commit read from the user and defaulting to - the commit at point. Keep the ‘HEAD’ and working tree as-is, so if - the commit refers to the ‘HEAD’, then this effectively unstages all - changes. - -‘X w’ (‘magit-reset-worktree’) - Reset the working tree to some commit read from the user and - defaulting to the commit at point. Keep the ‘HEAD’ and index - as-is. - -‘X f’ (‘magit-file-checkout’) - Update file in the working tree and index to the contents from a - revision. Both the revision and file are read from the user. - - -File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating - -6.12 Stashing -============= - -Also see *note (gitman)git-stash::. - -‘z’ (‘magit-stash’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘z z’ (‘magit-stash-both’) - Create a stash of the index and working tree. Untracked files are - included according to infix arguments. One prefix argument is - equivalent to ‘--include-untracked’ while two prefix arguments are - equivalent to ‘--all’. - -‘z i’ (‘magit-stash-index’) - Create a stash of the index only. Unstaged and untracked changes - are not stashed. - -‘z w’ (‘magit-stash-worktree’) - Create a stash of unstaged changes in the working tree. Untracked - files are included according to infix arguments. One prefix - argument is equivalent to ‘--include-untracked’ while two prefix - arguments are equivalent to ‘--all’. - -‘z x’ (‘magit-stash-keep-index’) - Create a stash of the index and working tree, keeping index intact. - Untracked files are included according to infix arguments. One - prefix argument is equivalent to ‘--include-untracked’ while two - prefix arguments are equivalent to ‘--all’. - -‘z Z’ (‘magit-snapshot-both’) - Create a snapshot of the index and working tree. Untracked files - are included according to infix arguments. One prefix argument is - equivalent to ‘--include-untracked’ while two prefix arguments are - equivalent to ‘--all’. - -‘z I’ (‘magit-snapshot-index’) - Create a snapshot of the index only. Unstaged and untracked - changes are not stashed. - -‘z W’ (‘magit-snapshot-worktree’) - Create a snapshot of unstaged changes in the working tree. - Untracked files are included according to infix arguments. One - prefix argument is equivalent to ‘--include-untracked’ while two - prefix arguments are equivalent to ‘--all’-. - -‘z a’ (‘magit-stash-apply’) - Apply a stash to the working tree. - - First try ‘git stash apply --index’, which tries to preserve the - index stored in the stash, if any. This may fail because applying - the stash could result in conflicts and those have to be stored in - the index, making it impossible to also store the stash’s index - there as well. - - If the above failed, then try ‘git stash apply’. This fails (with - or without ‘--index’) if there are any uncommitted changes to files - that are also modified in the stash. - - If both of the above failed, then apply using ‘git apply’. If - there are no conflicting files, use ‘--3way’. If there are - conflicting files, then using ‘--3way’ requires that those files - are staged first, which may be undesirable, so prompt the user - whether to use ‘--3way’ or ‘--reject’. - - Customize ‘magit-no-confirm’ if you want to always use ‘--3way’, - without being prompted. - -‘z p’ (‘magit-stash-pop’) - Apply a stash to the working tree. On complete success (if the - stash can be applied without any conflicts, and while preserving - the stash’s index) then remove the stash from stash list. - - First try ‘git stash pop --index’, which tries to preserve the - index stored in the stash, if any. This may fail because applying - the stash could result in conflicts and those have to be stored in - the index, making it impossible to also store the stash’s index - there as well. - - If the above failed, then try ‘git stash apply’. This fails (with - or without ‘--index’) if there are any uncommitted changes to files - that are also modified in the stash. - - If both of the above failed, then apply using ‘git apply’. If - there are no conflicting files, use ‘--3way’. If there are - conflicting files, then using ‘--3way’ requires that those files - are staged first, which may be undesirable, so prompt the user - whether to use ‘--3way’ or ‘--reject’. - - Customize ‘magit-no-confirm’ if you want to always use ‘--3way’, - without being prompted. - -‘z k’ (‘magit-stash-drop’) - Remove a stash from the stash list. When the region is active, - offer to drop all contained stashes. - -‘z v’ (‘magit-stash-show’) - Show all diffs of a stash in a buffer. - -‘z b’ (‘magit-stash-branch’) - Create and checkout a new branch from an existing stash. The new - branch starts at the commit that was current when the stash was - created. - -‘z B’ (‘magit-stash-branch-here’) - Create and checkout a new branch from an existing stash. Use the - current branch or ‘HEAD’ as the starting-point of the new branch. - Then apply the stash, dropping it if it applies cleanly. - -‘z f’ (‘magit-stash-format-patch’) - Create a patch from STASH. - -‘k’ (‘magit-stash-clear’) - Remove all stashes saved in REF’s reflog by deleting REF. - -‘z l’ (‘magit-stash-list’) - List all stashes in a buffer. - - -- User Option: magit-stashes-margin - This option specifies whether the margin is initially shown in - stashes buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - • AUTHOR controls whether the name of the author is also shown - by default. - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top - -7 Transferring -************** - -* Menu: - -* Remotes:: -* Fetching:: -* Pulling:: -* Pushing:: -* Plain Patches:: -* Maildir Patches:: - - -File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring - -7.1 Remotes -=========== - -* Menu: - -* Remote Commands:: -* Remote Git Variables:: - - -File: magit.info, Node: Remote Commands, Next: Remote Git Variables, Up: Remotes - -7.1.1 Remote Commands ---------------------- - -The transient prefix command ‘magit-remote’ is used to add remotes and -to make changes to existing remotes. This command only deals with -remotes themselves, not with branches or the transfer of commits. Those -features are available from separate transient commands. - - Also see *note (gitman)git-remote::. - -‘M’ (‘magit-remote’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - - By default it also binds and displays the values of some - remote-related Git variables and allows changing their values. - - -- User Option: magit-remote-direct-configure - This option controls whether remote-related Git variables are - accessible directly from the transient ‘magit-remote’. - - If ‘t’ (the default) and a local branch is checked out, then - ‘magit-remote’ features the variables for the upstream remote of - that branch, or if ‘HEAD’ is detached, for ‘origin’, provided that - exists. - - If ‘nil’, then ‘magit-remote-configure’ has to be used to do so. - -‘M C’ (‘magit-remote-configure’) - This transient prefix command binds commands that set the value of - remote-related variables and displays them in a temporary buffer - until the transient is exited. - - With a prefix argument, this command always prompts for a remote. - - Without a prefix argument this depends on whether it was invoked as - a suffix of ‘magit-remote’ and on the - ‘magit-remote-direct-configure’ option. If ‘magit-remote’ already - displays the variables for the upstream, then it does not make - sense to invoke another transient that displays them for the same - remote. In that case this command prompts for a remote. - - The variables are described in *note Remote Git Variables::. - -‘M a’ (‘magit-remote-add’) - This command add a remote and fetches it. The remote name and url - are read in the minibuffer. - -‘M r’ (‘magit-remote-rename’) - This command renames a remote. Both the old and the new names are - read in the minibuffer. - -‘M u’ (‘magit-remote-set-url’) - This command changes the url of a remote. Both the remote and the - new url are read in the minibuffer. - -‘M k’ (‘magit-remote-remove’) - This command deletes a remote, read in the minibuffer. - -‘M p’ (‘magit-remote-prune’) - This command removes stale remote-tracking branches for a remote - read in the minibuffer. - -‘M P’ (‘magit-remote-prune-refspecs’) - This command removes stale refspecs for a remote read in the - minibuffer. - - A refspec is stale if there no longer exists at least one branch on - the remote that would be fetched due to that refspec. A stale - refspec is problematic because its existence causes Git to refuse - to fetch according to the remaining non-stale refspecs. - - If only stale refspecs remain, then this command offers to either - delete the remote or to replace the stale refspecs with the default - refspec ("+refs/heads/*:refs/remotes/REMOTE/*"). - - This command also removes the remote-tracking branches that were - created due to the now stale refspecs. Other stale branches are - not removed. - - -- User Option: magit-remote-add-set-remote.pushDefault - This option controls whether the user is asked whether they want to - set ‘remote.pushDefault’ after adding a remote. - - If ‘ask’, then users is always ask. If ‘ask-if-unset’, then the - user is only if the variable isn’t set already. If ‘nil’, then the - user isn’t asked and the variable isn’t set. If the value is a - string, then the variable is set without the user being asked, - provided that the name of the added remote is equal to that string - and the variable isn’t already set. - - -File: magit.info, Node: Remote Git Variables, Prev: Remote Commands, Up: Remotes - -7.1.2 Remote Git Variables --------------------------- - -These variables can be set from the transient prefix command -‘magit-remote-configure’. By default they can also be set from -‘magit-remote’. See *note Remote Commands::. - - -- Variable: remote.NAME.url - This variable specifies the url of the remote named NAME. It can - have multiple values. - - -- Variable: remote.NAME.fetch - The refspec used when fetching from the remote named NAME. It can - have multiple values. - - -- Variable: remote.NAME.pushurl - This variable specifies the url used for pushing to the remote - named NAME. If it is not specified, then ‘remote.NAME.url’ is used - instead. It can have multiple values. - - -- Variable: remote.NAME.push - The refspec used when pushing to the remote named NAME. It can - have multiple values. - - -- Variable: remote.NAME.tagOpts - This variable specifies what tags are fetched by default. If the - value is ‘--no-tags’ then no tags are fetched. If the value is - ‘--tags’, then all tags are fetched. If this variable has no - value, then only tags are fetched that are reachable from fetched - branches. - - -File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring - -7.2 Fetching -============ - -Also see *note (gitman)git-fetch::. For information about the upstream -and the push-remote, see *note The Two Remotes::. - -‘f’ (‘magit-fetch’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘f p’ (‘magit-fetch-from-pushremote’) - This command fetches from the current push-remote. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘f u’ (‘magit-fetch-from-upstream’) - This command fetch from the upstream of the current branch. - - If the upstream is configured for the current branch and names an - existing remote, then use that. Otherwise try to use another - remote: If only a single remote is configured, then use that. - Otherwise if a remote named "origin" exists, then use that. - - If no remote can be determined, then this command is not available - from the ‘magit-fetch’ transient prefix and invoking it directly - results in an error. - -‘f e’ (‘magit-fetch-other’) - This command fetch from a repository read from the minibuffer. - -‘f o’ (‘magit-fetch-branch’) - This command fetches a branch from a remote, both of which are read - from the minibuffer. - -‘f r’ (‘magit-fetch-refspec’) - This command fetches from a remote using an explicit refspec, both - of which are read from the minibuffer. - -‘f a’ (‘magit-fetch-all’) - This command fetches from all remotes. - -‘f m’ (‘magit-fetch-modules’) - This command fetches all submodules. With a prefix argument, it - acts as a transient prefix command, allowing the caller to set - options. - - -- User Option: magit-pull-or-fetch - By default fetch and pull commands are available from separate - transient prefix command. Setting this to ‘t’ adds some (but not - all) of the above suffix commands to the ‘magit-pull’ transient. - - If you do that, then you might also want to change the key binding - for these prefix commands, e.g.: - - (setq magit-pull-or-fetch t) - (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch - (define-key magit-mode-map "F" nil) ; was magit-pull - - -File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring - -7.3 Pulling -=========== - -Also see *note (gitman)git-pull::. For information about the upstream -and the push-remote, see *note The Two Remotes::. - -‘F’ (‘magit-pull’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘F p’ (‘magit-pull-from-pushremote’) - This command pulls from the push-remote of the current branch. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘F u’ (‘magit-pull-from-upstream’) - This command pulls from the upstream of the current branch. - - With a prefix argument or when the upstream is either not - configured or unusable, then let the user first configure the - upstream. - -‘F e’ (‘magit-pull-branch’) - This command pulls from a branch read in the minibuffer. - - -File: magit.info, Node: Pushing, Next: Plain Patches, Prev: Pulling, Up: Transferring - -7.4 Pushing -=========== - -Also see *note (gitman)git-push::. For information about the upstream -and the push-remote, see *note The Two Remotes::. - -‘P’ (‘magit-push’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘P p’ (‘magit-push-current-to-pushremote’) - This command pushes the current branch to its push-remote. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘P u’ (‘magit-push-current-to-upstream’) - This command pushes the current branch to its upstream branch. - - With a prefix argument or when the upstream is either not - configured or unusable, then let the user first configure the - upstream. - -‘P e’ (‘magit-push-current’) - This command pushes the current branch to a branch read in the - minibuffer. - -‘P o’ (‘magit-push-other’) - This command pushes an arbitrary branch or commit somewhere. Both - the source and the target are read in the minibuffer. - -‘P r’ (‘magit-push-refspecs’) - This command pushes one or multiple refspecs to a remote, both of - which are read in the minibuffer. - - To use multiple refspecs, separate them with commas. Completion is - only available for the part before the colon, or when no colon is - used. - -‘P m’ (‘magit-push-matching’) - This command pushes all matching branches to another repository. - - If only one remote exists, then push to that. Otherwise prompt for - a remote, offering the remote configured for the current branch as - default. - -‘P t’ (‘magit-push-tags’) - This command pushes all tags to another repository. - - If only one remote exists, then push to that. Otherwise prompt for - a remote, offering the remote configured for the current branch as - default. - -‘P T’ (‘magit-push-tag’) - This command pushes a tag to another repository. - - One of the infix arguments, ‘--force-with-lease’, deserves a word of -caution. It is passed without a value, which means "permit a force push -as long as the remote-tracking branches match their counterparts on the -remote end". If you’ve set up a tool to do automatic fetches (Magit -itself does not provide such functionality), using ‘--force-with-lease’ -can be dangerous because you don’t actually control or know the state of -the remote-tracking refs. In that case, you should consider setting -‘push.useForceIfIncludes’ to ‘true’ (available since Git 2.30). - - Two more push commands exist, which by default are not available from -the push transient. See their doc-strings for instructions on how to -add them to the transient. - - -- Command: magit-push-implicitly args - This command pushes somewhere without using an explicit refspec. - - This command simply runs ‘git push -v [ARGS]’. ARGS are the infix - arguments. No explicit refspec arguments are used. Instead the - behavior depends on at least these Git variables: ‘push.default’, - ‘remote.pushDefault’, ‘branch.<branch>.pushRemote’, - ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and - ‘remote.<remote>.push’. - - If you add this suffix to a transient prefix without explicitly - specifying the description, then an attempt is made to predict what - this command will do. For example: - - (transient-insert-suffix 'magit-push \"p\" - '(\"i\" magit-push-implicitly))" - - -- Command: magit-push-to-remote remote args - This command pushes to the remote REMOTE without using an explicit - refspec. The remote is read in the minibuffer. - - This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the - infix arguments. No refspec arguments are used. Instead the - behavior depends on at least these Git variables: ‘push.default’, - ‘remote.pushDefault’, ‘branch.<branch>.pushRemote’, - ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and - ‘remote.<remote>.push’. - - -File: magit.info, Node: Plain Patches, Next: Maildir Patches, Prev: Pushing, Up: Transferring - -7.5 Plain Patches -================= - -‘W’ (‘magit-patch’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘W c’ (‘magit-patch-create’) - This command creates patches for a set commits. If the region - marks several commits, then it creates patches for all of them. - Otherwise it functions as a transient prefix command, which - features several infix arguments and binds itself as a suffix - command. When this command is invoked as a suffix of itself, then - it creates a patch using the specified infix arguments. - -‘w a’ (‘magit-patch-apply’) - This command applies a patch. This is a transient prefix command, - which features several infix arguments and binds itself as a suffix - command. When this command is invoked as a suffix of itself, then - it applies a patch using the specified infix arguments. - -‘W s’ (‘magit-patch-save’) - This command creates a patch from the current diff. - - Inside ‘magit-diff-mode’ or ‘magit-revision-mode’ buffers, ‘C-x - C-w’ is also bound to this command. - - It is also possible to save a plain patch file by using ‘C-x C-w’ -inside a ‘magit-diff-mode’ or ‘magit-revision-mode’ buffer. - - -File: magit.info, Node: Maildir Patches, Prev: Plain Patches, Up: Transferring - -7.6 Maildir Patches -=================== - -Also see *note (gitman)git-am::. and *note (gitman)git-apply::. - -‘w’ (‘magit-am’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘w w’ (‘magit-am-apply-patches’) - This command applies one or more patches. If the region marks - files, then those are applied as patches. Otherwise this command - reads a file-name in the minibuffer, defaulting to the file at - point. - -‘w m’ (‘magit-am-apply-maildir’) - This command applies patches from a maildir. - -‘w a’ (‘magit-patch-apply’) - This command applies a plain patch. For a longer description see - *note Plain Patches::. This command is only available from the - ‘magit-am’ transient for historic reasons. - - When an "am" operation is in progress, then the transient instead -features the following suffix commands. - -‘w w’ (‘magit-am-continue’) - This command resumes the current patch applying sequence. - -‘w s’ (‘magit-am-skip’) - This command skips the stopped at patch during a patch applying - sequence. - -‘w a’ (‘magit-am-abort’) - This command aborts the current patch applying sequence. This - discards all changes made since the sequence started. - - -File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top - -8 Miscellaneous -*************** - -* Menu: - -* Tagging:: -* Notes:: -* Submodules:: -* Subtree:: -* Worktree:: -* Sparse checkouts:: -* Bundle:: -* Common Commands:: -* Wip Modes:: -* Commands for Buffers Visiting Files:: -* Minor Mode for Buffers Visiting Blobs:: - - -File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous - -8.1 Tagging -=========== - -Also see *note (gitman)git-tag::. - -‘t’ (‘magit-tag’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘t t’ (‘magit-tag-create’) - This command creates a new tag with the given NAME at REV. With a - prefix argument it creates an annotated tag. - -‘t r’ (‘magit-tag-release’) - This commands creates a release tag. It assumes that release tags - match ‘magit-release-tag-regexp’. - - First it prompts for the name of the new tag using the highest - existing tag as initial input and leaving it to the user to - increment the desired part of the version string. If you use - unconventional release tags or version numbers (e.g., - ‘v1.2.3-custom.1’), you can set the ‘magit-release-tag-regexp’ and - ‘magit-tag-version-regexp-alist’ variables. - - If ‘--annotate’ is enabled then it prompts for the message of the - new tag. The proposed tag message is based on the message of the - highest tag, provided that that contains the corresponding version - string and substituting the new version string for that. Otherwise - it proposes something like "Foo-Bar 1.2.3", given, for example, a - TAG "v1.2.3" and a repository located at something like - "/path/to/foo-bar". - -‘t k’ (‘magit-tag-delete’) - This command deletes one or more tags. If the region marks - multiple tags (and nothing else), then it offers to delete those. - Otherwise, it prompts for a single tag to be deleted, defaulting to - the tag at point. - -‘t p’ (‘magit-tag-prune’) - This command offers to delete tags missing locally from REMOTE, and - vice versa. - - -File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous - -8.2 Notes -========= - -Also see *note (gitman)git-notes::. - -‘T’ (‘magit-notes’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘T T’ (‘magit-notes-edit’) - Edit the note attached to a commit, defaulting to the commit at - point. - - By default use the value of Git variable ‘core.notesRef’ or - "refs/notes/commits" if that is undefined. - -‘T r’ (‘magit-notes-remove’) - Remove the note attached to a commit, defaulting to the commit at - point. - - By default use the value of Git variable ‘core.notesRef’ or - "refs/notes/commits" if that is undefined. - -‘T p’ (‘magit-notes-prune’) - Remove notes about unreachable commits. - - It is possible to merge one note ref into another. That may result -in conflicts which have to resolved in the temporary worktree -".git/NOTES_MERGE_WORKTREE". - -‘T m’ (‘magit-notes-merge’) - Merge the notes of a ref read from the user into the current notes - ref. The current notes ref is the value of Git variable - ‘core.notesRef’ or "refs/notes/commits" if that is undefined. - - When a notes merge is in progress then the transient features the -following suffix commands, instead of those listed above. - -‘T c’ (‘magit-notes-merge-commit’) - Commit the current notes ref merge, after manually resolving - conflicts. - -‘T a’ (‘magit-notes-merge-abort’) - Abort the current notes ref merge. - - The following variables control what notes reference ‘magit-notes-*’, -‘git notes’ and ‘git show’ act on and display. Both the local and -global values are displayed and can be modified. - - -- Variable: core.notesRef - This variable specifies the notes ref that is displayed by default - and which commands act on by default. - - -- Variable: notes.displayRef - This variable specifies additional notes ref to be displayed in - addition to the ref specified by ‘core.notesRef’. It can have - multiple values and may end with ‘*’ to display all refs in the - ‘refs/notes/’ namespace (or ‘**’ if some names contain slashes). - - -File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous - -8.3 Submodules -============== - -Also see *note (gitman)git-submodule::. - -* Menu: - -* Listing Submodules:: -* Submodule Transient:: - - -File: magit.info, Node: Listing Submodules, Next: Submodule Transient, Up: Submodules - -8.3.1 Listing Submodules ------------------------- - -The command ‘magit-list-submodules’ displays a list of the current -repository’s submodules in a separate buffer. It’s also possible to -display information about submodules directly in the status buffer of -the super-repository by adding ‘magit-insert-modules’ to the hook -‘magit-status-sections-hook’ as described in *note Status Module -Sections::. - - -- Command: magit-list-submodules - This command displays a list of the current repository’s populated - submodules in a separate buffer. - - It can be invoked by pressing ‘RET’ on the section titled - "Modules". - - -- User Option: magit-submodule-list-columns - This option controls what columns are displayed by the command - ‘magit-list-submodules’ and how they are displayed. - - Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. - - HEADER is the string displayed in the header. WIDTH is the width - of the column. FORMAT is a function that is called with one - argument, the repository identification (usually its basename), and - with ‘default-directory’ bound to the toplevel of its working tree. - It has to return a string to be inserted or nil. PROPS is an alist - that supports the keys ‘:right-align’, ‘:pad-right’ and ‘:sort’. - - The ‘:sort’ function has a weird interface described in the - docstring of ‘tabulated-list--get-sort’. Alternatively ‘<’ and - ‘magit-repolist-version<’ can be used as those functions are - automatically replaced with functions that satisfy the interface. - Set ‘:sort’ to ‘nil’ to inhibit sorting; if unspecified, then the - column is sortable using the default sorter. - - You may wish to display a range of numeric columns using just one - character per column and without any padding between columns, in - which case you should use an appropriate HEADER, set WIDTH to 1, - and set ‘:pad-right’ to 9. ‘+’ is substituted for numbers higher - than 9. - - -File: magit.info, Node: Submodule Transient, Prev: Listing Submodules, Up: Submodules - -8.3.2 Submodule Transient -------------------------- - -‘o’ (‘magit-submodule’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - Some of the below commands default to act on the modules that are -selected using the region. For brevity their description talk about -"the selected modules", but if no modules are selected, then they act on -the current module instead, or if point isn’t on a module, then the read -a single module to act on. With a prefix argument these commands ignore -the selection and the current module and instead act on all suitable -modules. - -‘o a’ (‘magit-submodule-add’) - This commands adds the repository at URL as a module. Optional - PATH is the path to the module relative to the root of the - super-project. If it is nil then the path is determined based on - URL. - -‘o r’ (‘magit-submodule-register’) - This command registers the selected modules by copying their urls - from ".gitmodules" to "$GIT_DIR/config". These values can then be - edited before running ‘magit-submodule-populate’. If you don’t - need to edit any urls, then use the latter directly. - -‘o p’ (‘magit-submodule-populate’) - This command creates the working directory or directories of the - selected modules, checking out the recorded commits. - -‘o u’ (‘magit-submodule-update’) - This command updates the selected modules checking out the recorded - commits. - -‘o s’ (‘magit-submodule-synchronize’) - This command synchronizes the urls of the selected modules, copying - the values from ".gitmodules" to the ".git/config" of the - super-project as well those of the modules. - -‘o d’ (‘magit-submodule-unpopulate’) - This command removes the working directory of the selected modules. - -‘o l’ (‘magit-list-submodules’) - This command displays a list of the current repository’s modules. - -‘o f’ (‘magit-fetch-modules’) - This command fetches all populated modules. With a prefix - argument, it acts as a transient prefix command, allowing the - caller to set options. - - Also fetch the super-repository, because ‘git fetch’ does not - support not doing that. - - -File: magit.info, Node: Subtree, Next: Worktree, Prev: Submodules, Up: Miscellaneous - -8.4 Subtree -=========== - -Also see *note (gitman)git-subtree::. - -‘O’ (‘magit-subtree’) - This transient prefix command binds the two sub-transients; one for - importing a subtree and one for exporting a subtree. - -‘O i’ (‘magit-subtree-import’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - The suffixes of this command import subtrees. - - If the ‘--prefix’ argument is set, then the suffix commands use - that prefix without prompting the user. If it is unset, then they - read the prefix in the minibuffer. - -‘O i a’ (‘magit-subtree-add’) - This command adds COMMIT from REPOSITORY as a new subtree at - PREFIX. - -‘O i c’ (‘magit-subtree-add-commit’) - This command add COMMIT as a new subtree at PREFIX. - -‘O i m’ (‘magit-subtree-merge’) - This command merges COMMIT into the PREFIX subtree. - -‘O i f’ (‘magit-subtree-pull’) - This command pulls COMMIT from REPOSITORY into the PREFIX subtree. - -‘O e’ (‘magit-subtree-export’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - The suffixes of this command export subtrees. - - If the ‘--prefix’ argument is set, then the suffix commands use - that prefix without prompting the user. If it is unset, then they - read the prefix in the minibuffer. - -‘O e p’ (‘magit-subtree-push’) - This command extract the history of the subtree PREFIX and pushes - it to REF on REPOSITORY. - -‘O e s’ (‘magit-subtree-split’) - This command extracts the history of the subtree PREFIX. - - -File: magit.info, Node: Worktree, Next: Sparse checkouts, Prev: Subtree, Up: Miscellaneous - -8.5 Worktree -============ - -Also see *note (gitman)git-worktree::. - -‘Z’ (‘magit-worktree’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘Z b’ (‘magit-worktree-checkout’) - Checkout BRANCH in a new worktree at PATH. - -‘Z c’ (‘magit-worktree-branch’) - Create a new BRANCH and check it out in a new worktree at PATH. - -‘Z m’ (‘magit-worktree-move’) - Move an existing worktree to a new PATH. - -‘Z k’ (‘magit-worktree-delete’) - Delete a worktree, defaulting to the worktree at point. The - primary worktree cannot be deleted. - -‘Z g’ (‘magit-worktree-status’) - Show the status for the worktree at point. - - If there is no worktree at point, then read one in the minibuffer. - If the worktree at point is the one whose status is already being - displayed in the current buffer, then show it in Dired instead. - - -File: magit.info, Node: Sparse checkouts, Next: Bundle, Prev: Worktree, Up: Miscellaneous - -8.6 Sparse checkouts -==================== - -Sparse checkouts provide a way to restrict the working tree to a subset -of directories. See *note (gitman)git-sparse-checkout::. - - *Warning*: Git introduced the ‘git sparse-checkout’ command in -version 2.25 and still advertises it as experimental and subject to -change. Magit’s interface should be considered the same. In -particular, if Git introduces a backward incompatible change, Magit’s -sparse checkout functionality may be updated in a way that requires a -more recent Git version. - -‘>’ (‘magit-sparse-checkout’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘> e’ (‘magit-sparse-checkout-enable’) - This command initializes a sparse checkout that includes only the - files in the top-level directory. - - Note that ‘magit-sparse-checkout-set’ and - ‘magit-sparse-checkout-add’ automatically initialize a sparse - checkout if necessary. However, you may want to call - ‘magit-sparse-checkout-enable’ explicitly to re-initialize a sparse - checkout after calling ‘magit-sparse-checkout-disable’, to pass - additional arguments to ‘git sparse-checkout init’, or to execute - the initialization asynchronously. - -‘> s’ (‘magit-sparse-checkout-set’) - This command takes a list of directories and configures the sparse - checkout to include only files in those subdirectories. Any - previously included directories are excluded unless they are in the - provided list of directories. - -‘> a’ (‘magit-sparse-checkout-add’) - This command is like ‘magit-sparse-checkout-set’, but instead adds - the specified list of directories to the set of directories that is - already included in the sparse checkout. - -‘> r’ (‘magit-sparse-checkout-reapply’) - This command applies the currently configured sparse checkout - patterns to the working tree. This is useful to call if excluded - files have been checked out after operations such as merging or - rebasing. - -‘> d’ (‘magit-sparse-checkout-disable’) - This command restores the full checkout. To return to the previous - sparse checkout, call ‘magit-sparse-checkout-enable’. - - A sparse checkout can also be initiated when cloning a repository by -using the ‘magit-clone-sparse’ command in the ‘magit-clone’ transient -(see *note Cloning Repository::). - - If you want the status buffer to indicate when a sparse checkout is -enabled, add the function ‘magit-sparse-checkout-insert-header’ to -‘magit-status-headers-hook’. - - -File: magit.info, Node: Bundle, Next: Common Commands, Prev: Sparse checkouts, Up: Miscellaneous - -8.7 Bundle -========== - -Also see *note (gitman)git-bundle::. - - -- Command: magit-bundle - This transient prefix command binds several suffix commands for - running ‘git bundle’ subcommands and displays them in a temporary - buffer until a suffix is invoked. - - -File: magit.info, Node: Common Commands, Next: Wip Modes, Prev: Bundle, Up: Miscellaneous - -8.8 Common Commands -=================== - - -- Command: magit-switch-to-repository-buffer - -- Command: magit-switch-to-repository-buffer-other-window - -- Command: magit-switch-to-repository-buffer-other-frame - -- Command: magit-display-repository-buffer - These commands read any existing Magit buffer that belongs to the - current repository from the user and then switch to the selected - buffer (without refreshing it). - - The last variant uses ‘magit-display-buffer’ to do so and thus - respects ‘magit-display-buffer-function’. - - These are some of the commands that can be used in all buffers whose -major-modes derive from ‘magit-mode’. There are other common commands -beside the ones below, but these didn’t fit well anywhere else. - -‘C-w’ (‘magit-copy-section-value’) - This command saves the value of the current section to the - ‘kill-ring’, and, provided that the current section is a commit, - branch, or tag section, it also pushes the (referenced) revision to - the ‘magit-revision-stack’. - - When the current section is a branch or a tag, and a prefix - argument is used, then it saves the revision at its tip to the - ‘kill-ring’ instead of the reference name. - - When the region is active, this command saves that to the - ‘kill-ring’, like ‘kill-ring-save’ would, instead of behaving as - described above. If a prefix argument is used and the region is - within a hunk, then it strips the diff marker column and keeps only - either the added or removed lines, depending on the sign of the - prefix argument. - -‘M-w’ (‘magit-copy-buffer-revision’) - This command saves the revision being displayed in the current - buffer to the ‘kill-ring’ and also pushes it to the - ‘magit-revision-stack’. It is mainly intended for use in - ‘magit-revision-mode’ buffers, the only buffers where it is always - unambiguous exactly which revision should be saved. - - Most other Magit buffers usually show more than one revision, in - some way or another, so this command has to select one of them, and - that choice might not always be the one you think would have been - the best pick. - - Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to -‘kill-ring-save’ and ‘kill-region’, and these commands would also be -useful in Magit buffers. Therefore when the region is active, then both -of these commands behave like ‘kill-ring-save’ instead of as described -above. - - -File: magit.info, Node: Wip Modes, Next: Commands for Buffers Visiting Files, Prev: Common Commands, Up: Miscellaneous - -8.9 Wip Modes -============= - -Git keeps *committed* changes around long enough for users to recover -changes they have accidentally deleted. It does so by not garbage -collecting any committed but no longer referenced objects for a certain -period of time, by default 30 days. - - But Git does *not* keep track of *uncommitted* changes in the working -tree and not even the index (the staging area). Because Magit makes it -so convenient to modify uncommitted changes, it also makes it easy to -shoot yourself in the foot in the process. - - For that reason Magit provides a global mode that saves *tracked* -files to work-in-progress references after or before certain actions. -(At present untracked files are never saved and for technical reasons -nothing is saved before the first commit has been created). - - Two separate work-in-progress references are used to track the state -of the index and of the working tree: ‘refs/wip/index/<branchref>’ and -‘refs/wip/wtree/<branchref>’, where ‘<branchref>’ is the full ref of the -current branch, e.g., ‘refs/heads/master’. When the ‘HEAD’ is detached -then ‘HEAD’ is used in place of ‘<branchref>’. - - Checking out another branch (or detaching ‘HEAD’) causes the use of -different wip refs for subsequent changes. - - -- User Option: magit-wip-mode - When this mode is enabled, then uncommitted changes are committed - to dedicated work-in-progress refs whenever appropriate (i.e., when - dataloss would be a possibility otherwise). - - Setting this variable directly does not take effect; either use the - Custom interface to do so or call the respective mode function. - - For historic reasons this mode is implemented on top of four other - ‘magit-wip-*’ modes, which can also be used individually, if you - want finer control over when the wip refs are updated; but that is - discouraged. See *note Legacy Wip Modes::. - - To view the log for a branch and its wip refs use the commands -‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’ -when using these commands. - - -- Command: magit-wip-log - This command shows the log for a branch and its wip refs. With a - negative prefix argument only the worktree wip ref is shown. - - The absolute numeric value of the prefix argument controls how many - "branches" of each wip ref are shown. This is only relevant if the - value of ‘magit-wip-merge-branch’ is ‘nil’. - - -- Command: magit-wip-log-current - This command shows the log for the current branch and its wip refs. - With a negative prefix argument only the worktree wip ref is shown. - - The absolute numeric value of the prefix argument controls how many - "branches" of each wip ref are shown. This is only relevant if the - value of ‘magit-wip-merge-branch’ is ‘nil’. - -‘X w’ (‘magit-reset-worktree’) - This command resets the working tree to some commit read from the - user and defaulting to the commit at point, while keeping the - ‘HEAD’ and index as-is. - - This can be used to restore files to the state committed to a wip - ref. Note that this will discard any unstaged changes that might - have existed before invoking this command (but of course only after - committing that to the working tree wip ref). - - Note that even if you enable ‘magit-wip-mode’ this won’t give you -perfect protection. The most likely scenario for losing changes despite -the use of ‘magit-wip-mode’ is making a change outside Emacs and then -destroying it also outside Emacs. In some such a scenario, Magit, being -an Emacs package, didn’t get the opportunity to keep you from shooting -yourself in the foot. - - When you are unsure whether Magit did commit a change to the wip -refs, then you can explicitly request that all changes to all tracked -files are being committed. - -‘M-x magit-wip-commit’ - This command commits all changes to all tracked files to the index - and working tree work-in-progress refs. Like the modes described - above, it does not commit untracked files, but it does check all - tracked files for changes. Use this command when you suspect that - the modes might have overlooked a change made outside Emacs/Magit. - - -- User Option: magit-wip-namespace - The namespace used for work-in-progress refs. It has to end with a - slash. The wip refs are named ‘<namespace>index/<branchref>’ and - ‘<namespace>wtree/<branchref>’. When snapshots are created while - the ‘HEAD’ is detached then ‘HEAD’ is used in place of - ‘<branchref>’. - - -- User Option: magit-wip-mode-lighter - Mode-line lighter for ‘magit-wip--mode’. - -* Menu: - -* Wip Graph:: -* Legacy Wip Modes:: - - -File: magit.info, Node: Wip Graph, Next: Legacy Wip Modes, Up: Wip Modes - -8.9.1 Wip Graph ---------------- - - -- User Option: magit-wip-merge-branch - This option controls whether the current branch is merged into the - wip refs after a new commit was created on the branch. - - If non-nil and the current branch has new commits, then it is - merged into the wip ref before creating a new wip commit. This - makes it easier to inspect wip history and the wip commits are - never garbage collected. - - If nil and the current branch has new commits, then the wip ref is - reset to the tip of the branch before creating a new wip commit. - With this setting wip commits are eventually garbage collected. - - When ‘magit-wip-merge-branch’ is ‘t’, then the history looks like -this: - - *--*--*--*--*--* refs/wip/index/refs/heads/master - / / / - A-----B-----C refs/heads/master - - When ‘magit-wip-merge-branch’ is ‘nil’, then creating a commit on the -real branch and then making a change causes the wip refs to be recreated -to fork from the new commit. But the old commits on the wip refs are -not lost. They are still available from the reflog. To make it easier -to see when the fork point of a wip ref was changed, an additional -commit with the message "restart autosaving" is created on it (‘xxO’ -commits below are such boundary commits). - - Starting with - - BI0---BI1 refs/wip/index/refs/heads/master - / - A---B refs/heads/master - \ - BW0---BW1 refs/wip/wtree/refs/heads/master - - and committing the staged changes and editing and saving a file would -result in - - BI0---BI1 refs/wip/index/refs/heads/master - / - A---B---C refs/heads/master - \ \ - \ CW0---CW1 refs/wip/wtree/refs/heads/master - \ - BW0---BW1 refs/wip/wtree/refs/heads/master@{2} - - The fork-point of the index wip ref is not changed until some change -is being staged. Likewise just checking out a branch or creating a -commit does not change the fork-point of the working tree wip ref. The -fork-points are not adjusted until there actually is a change that -should be committed to the respective wip ref. - - -File: magit.info, Node: Legacy Wip Modes, Prev: Wip Graph, Up: Wip Modes - -8.9.2 Legacy Wip Modes ----------------------- - -It is recommended that you use the mode ‘magit-wip-mode’ (which see) and -ignore the existence of the following modes, which are preserved for -historic reasons. - - Setting the following variables directly does not take effect; either -use the Custom interface to do so or call the respective mode functions. - - -- User Option: magit-wip-after-save-mode - When this mode is enabled, then saving a buffer that visits a file - tracked in a Git repository causes its current state to be - committed to the working tree wip ref for the current branch. - - -- User Option: magit-wip-after-apply-mode - When this mode is enabled, then applying (i.e., staging, unstaging, - discarding, reversing, and regularly applying) a change to a file - tracked in a Git repository causes its current state to be - committed to the index and/or working tree wip refs for the current - branch. - - If you only ever edit files using Emacs and only ever interact with -Git using Magit, then the above two modes should be enough to protect -each and every change from accidental loss. In practice nobody does -that. Two additional modes exists that do commit to the wip refs before -making changes that could cause the loss of earlier changes. - - -- User Option: magit-wip-before-change-mode - When this mode is enabled, then certain commands commit the - existing changes to the files they are about to make changes to. - - -- User Option: magit-wip-initial-backup-mode - When this mode is enabled, then the current version of a file is - committed to the worktree wip ref before the buffer visiting that - file is saved for the first time since the buffer was created. - - This backs up the same version of the file that ‘backup-buffer’ - would save. While ‘backup-buffer’ uses a backup file, this mode - uses the same worktree wip ref as used by the other Magit Wip - modes. Like ‘backup-buffer’, it only does this once; unless you - kill the buffer and visit the file again only one backup will be - created per Emacs session. - - This mode ignores the variables that affect ‘backup-buffer’ and can - be used along-side that function, which is recommended because it - only backs up files that are tracked in a Git repository. - - -- User Option: magit-wip-after-save-local-mode-lighter - Mode-line lighter for ‘magit-wip-after-save-local-mode’. - - -- User Option: magit-wip-after-apply-mode-lighter - Mode-line lighter for ‘magit-wip-after-apply-mode’. - - -- User Option: magit-wip-before-change-mode-lighter - Mode-line lighter for ‘magit-wip-before-change-mode’. - - -- User Option: magit-wip-initial-backup-mode-lighter - Mode-line lighter for ‘magit-wip-initial-backup-mode’. - - -File: magit.info, Node: Commands for Buffers Visiting Files, Next: Minor Mode for Buffers Visiting Blobs, Prev: Wip Modes, Up: Miscellaneous - -8.10 Commands for Buffers Visiting Files -======================================== - -By default Magit defines a few global key bindings. These bindings are -a compromise between providing no bindings at all and providing the -better bindings I would have liked to use instead. Magit cannot provide -the set of recommended bindings by default because those key sequences -are strictly reserved for bindings added by the user. Also see *note -Global Bindings:: and *note (elisp)Key Binding Conventions::. - - To use the recommended bindings, add this to your init file and -restart Emacs. - - (setq magit-define-global-key-bindings 'recommended) - - If you don’t want Magit to add any bindings to the global keymap at -all, add this to your init file and restart Emacs. - - (setq magit-define-global-key-bindings nil) - -‘C-c f’ (‘magit-file-dispatch’) -‘C-c f s’ (‘magit-stage-file’) -‘C-c f s’ (‘magit-stage-buffer-file’) -‘C-c f u’ (‘magit-unstage-file’) -‘C-c f u’ (‘magit-unstage-buffer-file’) -‘C-c f , x’ (‘magit-file-untrack’) -‘C-c f , r’ (‘magit-file-rename’) -‘C-c f , k’ (‘magit-file-delete’) -‘C-c f , c’ (‘magit-file-checkout’) -‘C-c f D’ (‘magit-diff’) -‘C-c f d’ (‘magit-diff-buffer-file’) -‘C-c f L’ (‘magit-log’) -‘C-c f l’ (‘magit-log-buffer-file’) -‘C-c f t’ (‘magit-log-trace-definition’) -‘C-c f M’ (‘magit-log-merged’) -‘C-c f B’ (‘magit-blame’) -‘C-c f b’ (‘magit-blame-additions’) -‘C-c f r’ (‘magit-blame-removal’) -‘C-c f f’ (‘magit-blame-reverse’) -‘C-c f m’ (‘magit-blame-echo’) -‘C-c f q’ (‘magit-blame-quit’) -‘C-c f p’ (‘magit-blob-previous’) -‘C-c f n’ (‘magit-blob-next’) -‘C-c f v’ (‘magit-find-file’) -‘C-c f V’ (‘magit-blob-visit-file’) -‘C-c f g’ (‘magit-status-here’) -‘C-c f G’ (‘magit-display-repository-buffer’) -‘C-c f c’ (‘magit-commit’) -‘C-c f e’ (‘magit-edit-line-commit’) - Each of these commands is documented individually right below, - alongside their default key bindings. The bindings shown above are - the recommended bindings, which you can enable by following the - instructions further up. - -‘C-c M-g’ (‘magit-file-dispatch’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘C-c M-g s’ (‘magit-stage-file’) -‘C-c M-g s’ (‘magit-stage-buffer-file’) - Stage all changes to the file being visited in the current buffer. - When not visiting a file, then the first command is used, which - prompts for a file. - -‘C-c M-g u’ (‘magit-unstage-file’) -‘C-c M-g u’ (‘magit-unstage-buffer-file’) - Unstage all changes to the file being visited in the current - buffer. When not visiting a file, then the first command is used, - which prompts for a file. - -‘C-c M-g , x’ (‘magit-file-untrack’) - This command untracks a file read from the user, defaulting to the - visited file. - -‘C-c M-g , r’ (‘magit-file-rename’) - This command renames a file read from the user, defaulting to the - visited file. - -‘C-c M-g , k’ (‘magit-file-delete’) - This command deletes a file read from the user, defaulting to the - visited file. - -‘C-c M-g , c’ (‘magit-file-checkout’) - This command updates a file in the working tree and index to the - contents from a revision. Both the revision and file are read from - the user. - -‘C-c M-g D’ (‘magit-diff’) - This transient prefix command binds several diff suffix commands - and infix arguments and displays them in a temporary buffer until a - suffix is invoked. See *note Diffing::. - - This is the same command that ‘d’ is bound to in Magit buffers. If - this command is invoked from a file-visiting buffer, then the - initial value of the option (‘--’) that limits the diff to certain - file(s) is set to the visited file. - -‘C-c M-g d’ (‘magit-diff-buffer-file’) - This command shows the diff for the file of blob that the current - buffer visits. - - -- User Option: magit-diff-buffer-file-locked - This option controls whether ‘magit-diff-buffer-file’ uses a - dedicated buffer. See *note Modes and Buffers::. - -‘C-c M-g L’ (‘magit-log’) - This transient prefix command binds several log suffix commands and - infix arguments and displays them in a temporary buffer until a - suffix is invoked. See *note Logging::. - - This is the same command that ‘l’ is bound to in Magit buffers. If - this command is invoked from a file-visiting buffer, then the - initial value of the option (‘--’) that limits the log to certain - file(s) is set to the visited file. - -‘C-c M-g l’ (‘magit-log-buffer-file’) - This command shows the log for the file of blob that the current - buffer visits. Renames are followed when a prefix argument is used - or when ‘--follow’ is an active log argument. When the region is - active, the log is restricted to the selected line range. - - -- User Option: magit-log-buffer-file-locked - This option controls whether ‘magit-log-buffer-file’ uses a - dedicated buffer. See *note Modes and Buffers::. - -‘C-c M-g t’ (‘magit-log-trace-definition’) - This command shows the log for the definition at point. - -‘C-c M-g M’ (‘magit-log-merged’) - This command reads a commit and a branch in shows a log concerning - the merge of the former into the latter. This shows multiple - commits even in case of a fast-forward merge. - -‘C-c M-g B’ (‘magit-blame’) - This transient prefix command binds all blaming suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - For more information about this and the following commands also see - *note Blaming::. - - In addition to the ‘magit-blame’ sub-transient, the dispatch - transient also binds several blaming suffix commands directly. See - *note Blaming:: for information about those commands and bindings. - -‘C-c M-g p’ (‘magit-blob-previous’) - This command visits the previous blob which modified the current - file. - -‘C-c M-g n’ (‘magit-blob-next’) - This command visits the next blob which modified the current file. - -‘C-c M-g v’ (‘magit-find-file’) - This command reads a revision and file and visits the respective - blob. - -‘C-c M-g V’ (‘magit-blob-visit-file’) - This command visits the file from the working tree, corresponding - to the current blob. When visiting a blob or the version from the - index, then it goes to the same location in the respective file in - the working tree. - -‘C-c M-g g’ (‘magit-status-here’) - This command displays the status of the current repository in a - buffer, like ‘magit-status’ does. Additionally it tries to go to - the position in that buffer, which corresponds to the position in - the current file-visiting buffer (if any). - -‘C-c M-g G’ (‘magit-display-repository-buffer’) - This command reads and displays a Magit buffer belonging to the - current repository, without refreshing it. - -‘C-c M-g c’ (‘magit-commit’) - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. See *note Initiating a - Commit::. - -‘C-c M-g e’ (‘magit-edit-line-commit’) - This command makes the commit editable that added the current line. - - With a prefix argument it makes the commit editable that removes - the line, if any. The commit is determined using ‘git blame’ and - made editable using ‘git rebase --interactive’ if it is reachable - from ‘HEAD’, or by checking out the commit (or a branch that points - at it) otherwise. - - -File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous - -8.11 Minor Mode for Buffers Visiting Blobs -========================================== - -The ‘magit-blob-mode’ enables certain Magit features in blob-visiting -buffers. Such buffers can be created using ‘magit-find-file’ and some -of the commands mentioned below, which also take care of turning on this -minor mode. Currently this mode only establishes a few key bindings, -but this might be extended. - -‘p’ (‘magit-blob-previous’) - Visit the previous blob which modified the current file. - -‘n’ (‘magit-blob-next’) - Visit the next blob which modified the current file. - -‘q’ (‘magit-kill-this-buffer’) - Kill the current buffer. - - -File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top - -9 Customizing -************* - -Both Git and Emacs are highly customizable. Magit is both a Git -porcelain as well as an Emacs package, so it makes sense to customize it -using both Git variables as well as Emacs options. However this -flexibility doesn’t come without problems, including but not limited to -the following. - - • Some Git variables automatically have an effect in Magit without - requiring any explicit support. Sometimes that is desirable - in - other cases, it breaks Magit. - - When a certain Git setting breaks Magit but you want to keep using - that setting on the command line, then that can be accomplished by - overriding the value for Magit only by appending something like - ‘("-c" "some.variable=compatible-value")’ to - ‘magit-git-global-arguments’. - - • Certain settings like ‘fetch.prune=true’ are respected by Magit - commands (because they simply call the respective Git command) but - their value is not reflected in the respective transient buffers. - In this case the ‘--prune’ argument in ‘magit-fetch’ might be - active or inactive, but that doesn’t keep the Git variable from - being honored by the suffix commands anyway. So pruning might - happen despite the ‘--prune’ arguments being displayed in a way - that seems to indicate that no pruning will happen. - - I intend to address these and similar issues in a future release. - -* Menu: - -* Per-Repository Configuration:: -* Essential Settings:: - - -File: magit.info, Node: Per-Repository Configuration, Next: Essential Settings, Up: Customizing - -9.1 Per-Repository Configuration -================================ - -Magit can be configured on a per-repository level using both Git -variables as well as Emacs options. - - To set a Git variable for one repository only, simply set it in -‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or -‘/etc/gitconfig’. See *note (gitman)git-config::. - - Similarly, Emacs options can be set for one repository only by -editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory -Variables::. For example to disable automatic refreshes of -file-visiting buffers in just one huge repository use this: - - • ‘/path/to/huge/repo/.dir-locals.el’ - - ((nil . ((magit-refresh-buffers . nil)))) - - It might only be costly to insert certain information into Magit -buffers for repositories that are exceptionally large, in which case you -can disable the respective section inserters just for that repository: - - • ‘/path/to/tag/invested/repo/.dir-locals.el’ - - ((magit-status-mode - . ((eval . (magit-disable-section-inserter 'magit-insert-tags-header))))) - - -- Function: magit-disable-section-inserter fn - This function disables the section inserter FN in the current - repository. It is only intended for use in ‘.dir-locals.el’ and - ‘.dir-locals-2.el’. - - If you want to apply the same settings to several, but not all, -repositories then keeping the repository-local config files in sync -would quickly become annoying. To avoid that you can create config -files for certain classes of repositories (e.g., "huge repositories") -and then include those files in the per-repository config files. For -example: - - • ‘/path/to/huge/repo/.git/config’ - - [include] - path = /path/to/huge-gitconfig - - • ‘/path/to/huge-gitconfig’ - - [status] - showUntrackedFiles = no - - • ‘$HOME/.emacs.d/init.el’ - - (dir-locals-set-class-variables 'huge-git-repository - '((nil . ((magit-refresh-buffers . nil))))) - - (dir-locals-set-directory-class - "/path/to/huge/repo/" 'huge-git-repository) - - -File: magit.info, Node: Essential Settings, Prev: Per-Repository Configuration, Up: Customizing - -9.2 Essential Settings -====================== - -The next three sections list and discuss several variables that many -users might want to customize, for safety and/or performance reasons. - -* Menu: - -* Safety:: -* Performance:: -* Global Bindings:: - - -File: magit.info, Node: Safety, Next: Performance, Up: Essential Settings - -9.2.1 Safety ------------- - -This section discusses various variables that you might want to change -(or *not* change) for safety reasons. - - Git keeps *committed* changes around long enough for users to recover -changes they have accidentally been deleted. It does not do the same -for *uncommitted* changes in the working tree and not even the index -(the staging area). Because Magit makes it so easy to modify -uncommitted changes, it also makes it easy to shoot yourself in the foot -in the process. For that reason Magit provides three global modes that -save *tracked* files to work-in-progress references after or before -certain actions. See *note Wip Modes::. - - These modes are not enabled by default because of performance -concerns. Instead a lot of potentially destructive commands require -confirmation every time they are used. In many cases this can be -disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion -and Confirmation::). If you enable the various wip modes then you -should add ‘safe-with-wip’ to this list. - - Similarly it isn’t necessary to require confirmation before moving a -file to the system trash - if you trashed a file by mistake then you can -recover it from there. Option ‘magit-delete-by-moving-to-trash’ -controls whether the system trash is used, which is the case by default. -Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might -want to change that. - - By default buffers visiting files are automatically reverted when the -visited file changes on disk. This isn’t as risky as it might seem, but -to make an informed decision you should see *note Risk of Reverting -Automatically::. - - -File: magit.info, Node: Performance, Next: Global Bindings, Prev: Safety, Up: Essential Settings - -9.2.2 Performance ------------------ - -After Magit has run ‘git’ for side-effects, it also refreshes the -current Magit buffer and the respective status buffer. This is -necessary because otherwise outdated information might be displayed -without the user noticing. Magit buffers are updated by recreating -their content from scratch, which makes updating simpler and less -error-prone, but also more costly. Keeping it simple and just -re-creating everything from scratch is an old design decision and -departing from that will require major refactoring. - - Meanwhile you can tell Magit to only automatically refresh the -current Magit buffer, but not the status buffer. If you do that, then -the status buffer is only refreshed automatically if it is the current -buffer. - - (setq magit-refresh-status-buffer nil) - - You should also check whether any third-party packages have added -anything to ‘magit-refresh-buffer-hook’, ‘magit-pre-refresh-hook’, and -‘magit-post-refresh-hook’. If so, then check whether those additions -impact performance significantly. - - Magit can be told to refresh buffers verbosely using ‘M-x -magit-toggle-verbose-refresh’. Enabling this helps figuring out which -sections are bottlenecks. Each line printed to the ‘*Messages*’ buffer -contains a section name, the number of seconds it took to show this -section, and from 0 to 2 exclamation marks: the more exclamation marks -the slower the section is. - - Magit also reverts buffers for visited files located inside the -current repository when the visited file changes on disk. That is -implemented on top of ‘auto-revert-mode’ from the built-in library -‘autorevert’. To figure out whether that impacts performance, check -whether performance is significantly worse, when many buffers exist -and/or when some buffers visit files using TRAMP. If so, then this -should help. - - (setq auto-revert-buffer-list-filter - 'magit-auto-revert-repository-buffer-p) - - For alternative approaches see *note Automatic Reverting of -File-Visiting Buffers::. - - If you have enabled any features that are disabled by default, then -you should check whether they impact performance significantly. It’s -likely that they were not enabled by default because it is known that -they reduce performance at least in large repositories. - - If performance is only slow inside certain unusually large -repositories, then you might want to disable certain features on a -per-repository or per-repository-class basis only. See *note -Per-Repository Configuration::. For example it takes a long time to -determine the next and current tag in repository with exceptional -numbers of tags. It would therefore be a good idea to disable -‘magit-insert-tags-headers’, as explained at the mentioned node. - -* Menu: - -* Microsoft Windows Performance:: -* MacOS Performance:: - -Log Performance -............... - -When showing logs, Magit limits the number of commits initially shown in -the hope that this avoids unnecessary work. When ‘--graph’ is used, -then this unfortunately does not have the desired effect for large -histories. Junio, Git’s maintainer, said on the Git mailing list -(<https://www.spinics.net/lists/git/msg232230.html>): "‘--graph’ wants -to compute the whole history and the max-count only affects the output -phase after ‘--graph’ does its computation". - - In other words, it’s not that Git is slow at outputting the -differences, or that Magit is slow at parsing the output - the problem -is that Git first goes outside and has a smoke. - - We actually work around this issue by limiting the number of commits -not only by using ‘-<N>’ but by also using a range. But unfortunately -that’s not always possible. - - When more than a few thousand commits are shown, then the use of -‘--graph’ can slow things down. - - Using ‘--color --graph’ is even slower. Magit uses code that is part -of Emacs to turn control characters into faces. That code is pretty -slow and this is quite noticeable when showing a log with many branches -and merges. For that reason ‘--color’ is not enabled by default -anymore. Consider leaving it at that. - -Diff Performance -................ - -If diffs are slow, then consider turning off some optional diff features -by setting all or some of the following variables to ‘nil’: -‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’, -‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and -‘magit-diff-refine-hunk’. - - When showing a commit instead of some arbitrary diff, then some -additional information is displayed. Calculating this information can -be quite expensive given certain circumstances. If looking at a commit -using ‘magit-revision-mode’ takes considerably more time than looking at -the same commit in ‘magit-diff-mode’, then consider setting -‘magit-revision-insert-related-refs’ to ‘nil’. - - When you are often confronted with diffs that contain deleted files, -then you might want to enable the ‘--irreversible-delete’ argument. If -you do that then diffs still show that a file was deleted but without -also showing the complete deleted content of the file. This argument is -not available by default, see *note (transient)Enabling and Disabling -Suffixes::. Once you have done that you should enable it and save that -setting, see *note (transient)Saving Values::. You should do this in -both the diff (‘d’) and the diff refresh (‘D’) transient popups. - -Refs Buffer Performance -....................... - -When refreshing the "references buffer" is slow, then that’s usually -because several hundred refs are being displayed. The best way to -address that is to display fewer refs, obviously. - - If you are not, or only mildly, interested in seeing the list of -tags, then start by not displaying them: - - (remove-hook 'magit-refs-sections-hook 'magit-insert-tags) - - Then you should also make sure that the listed remote branches -actually all exist. You can do so by pruning branches which no longer -exist using ‘f-pa’. - -Committing Performance -...................... - -When you initiate a commit, then Magit by default automatically shows a -diff of the changes you are about to commit. For large commits this can -take a long time, which is especially distracting when you are -committing large amounts of generated data which you don’t actually -intend to inspect before committing. This behavior can be turned off -using: - - (remove-hook 'server-switch-hook 'magit-commit-diff) - (remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff) - - Then you can type ‘C-c C-d’ to show the diff when you actually want -to see it, but only then. Alternatively you can leave the hook alone -and just type ‘C-g’ in those cases when it takes too long to generate -the diff. If you do that, then you will end up with a broken diff -buffer, but doing it this way has the advantage that you usually get to -see the diff, which is useful because it increases the odds that you -spot potential issues. - - -File: magit.info, Node: Microsoft Windows Performance, Next: MacOS Performance, Up: Performance - -Microsoft Windows Performance -............................. - -In order to update the status buffer, ‘git’ has to be run a few dozen -times. That is problematic on Microsoft Windows, because that operating -system is exceptionally slow at starting processes. Sadly this is an -issue that can only be fixed by Microsoft itself, and they don’t appear -to be particularly interested in doing so. - - Beside the subprocess issue, there are also other Windows-specific -performance issues. Some of these have workarounds. The maintainers of -"Git for Windows" try to improve performance on Windows. Always use the -latest release in order to benefit from the latest performance tweaks. -Magit too tries to work around some Windows-specific issues. - - According to some sources, setting the following Git variables can -also help. - - git config --global core.preloadindex true # default since v2.1 - git config --global core.fscache true # default since v2.8 - git config --global gc.auto 256 - - You should also check whether an anti-virus program is affecting -performance. - - -File: magit.info, Node: MacOS Performance, Prev: Microsoft Windows Performance, Up: Performance - -MacOS Performance -................. - -Before Emacs 26.1 child processes were created using ‘fork’ on macOS. -That needlessly copied GUI resources, which is expensive. The result -was that forking took about 30 times as long on Darwin than on Linux, -and because Magit starts many ‘git’ processes that made quite a -difference. - - So make sure that you are using at least Emacs 26.1, in which case -the faster ‘vfork’ will be used. (The creation of child processes still -takes about twice as long on Darwin compared to Linux.) See (1) for -more information. - - Additionally, ‘git’ installed from a package manager like ‘brew’ or -‘nix’ seems to be slower than the native executable. Profile the ‘git’ -executable you’re running against the one at ‘/usr/bin/git’, and if you -notice a notable difference try using the latter as -‘magit-git-executable’. - - ---------- Footnotes ---------- - - (1) -<https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html> - - -File: magit.info, Node: Global Bindings, Prev: Performance, Up: Essential Settings - -9.2.3 Global Bindings ---------------------- - - -- User Option: magit-define-global-key-bindings - This option controls which set of Magit key bindings, if any, may - be added to the global keymap, even before Magit is first used in - the current Emacs session. - - • If the value is ‘nil’, no bindings are added. - - • If ‘default’, maybe add: - - ‘C-x g’ ‘magit-status’ - ‘C-x M-g’ ‘magit-dispatch’ - ‘C-c M-g’ ‘magit-file-dispatch’ - - • If ‘recommended’, maybe add: - - ‘C-x g’ ‘magit-status’ - ‘C-c g’ ‘magit-dispatch’ - ‘C-c f’ ‘magit-file-dispatch’ - - These bindings are strongly recommended, but we cannot use - them by default, because the ‘C-c <LETTER>’ namespace is - strictly reserved for bindings added by the user (see *note - (elisp)Key Binding Conventions::). - - The bindings in the chosen set may be added when ‘after-init-hook’ - is run. Each binding is added if, and only if, at that time no - other key is bound to the same command, and no other command is - bound to the same key. In other words we try to avoid adding - bindings that are unnecessary, as well as bindings that conflict - with other bindings. - - Adding these bindings is delayed until ‘after-init-hook’ is run to - allow users to set the variable anywhere in their init file - (without having to make sure to do so before ‘magit’ is loaded or - autoloaded) and to increase the likelihood that all the potentially - conflicting user bindings have already been added. - - To set this variable use either ‘setq’ or the Custom interface. Do - not use the function ‘customize-set-variable’ because doing that - would cause Magit to be loaded immediately, when that form is - evaluated (this differs from ‘custom-set-variables’, which doesn’t - load the libraries that define the customized variables). - - Setting this variable has no effect if ‘after-init-hook’ has - already been run. - - -File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top - -10 Plumbing -*********** - -The following sections describe how to use several of Magit’s core -abstractions to extend Magit itself or implement a separate extension. - - A few of the low-level features used by Magit have been factored out -into separate libraries/packages, so that they can be used by other -packages, without having to depend on Magit. See *note -(with-editor)Top:: for information about ‘with-editor’. ‘transient’ -doesn’t have a manual yet. - - If you are trying to find an unused key that you can bind to a -command provided by your own Magit extension, then checkout -<https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry>. - -* Menu: - -* Calling Git:: -* Section Plumbing:: -* Refreshing Buffers:: -* Conventions:: - - -File: magit.info, Node: Calling Git, Next: Section Plumbing, Up: Plumbing - -10.1 Calling Git -================ - -Magit provides many specialized functions for calling Git. All of these -functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and -have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or -‘magit-git-’ (which is also used for other things). - - All of these functions accept an indefinite number of arguments, -which are strings that specify command line arguments for Git (or in -some cases an arbitrary executable). These arguments are flattened -before being passed on to the executable; so instead of strings they can -also be lists of strings and arguments that are ‘nil’ are silently -dropped. Some of these functions also require a single mandatory -argument before these command line arguments. - - Roughly speaking, these functions run Git either to get some value or -for side-effects. The functions that return a value are useful to -collect the information necessary to populate a Magit buffer, while the -others are used to implement Magit commands. - - The functions in the value-only group always run synchronously, and -they never trigger a refresh. The function in the side-effect group can -be further divided into subgroups depending on whether they run Git -synchronously or asynchronously, and depending on whether they trigger a -refresh when the executable has finished. - -* Menu: - -* Getting a Value from Git:: -* Calling Git for Effect:: - - -File: magit.info, Node: Getting a Value from Git, Next: Calling Git for Effect, Up: Calling Git - -10.1.1 Getting a Value from Git -------------------------------- - -These functions run Git in order to get a value, an exit status, or -output. Of course you could also use them to run Git commands that have -side-effects, but that should be avoided. - - -- Function: magit-git-exit-code &rest args - Executes git with ARGS and returns its exit code. - - -- Function: magit-git-success &rest args - Executes git with ARGS and returns ‘t’ if the exit code is ‘0’, - ‘nil’ otherwise. - - -- Function: magit-git-failure &rest args - Executes git with ARGS and returns ‘t’ if the exit code is ‘1’, - ‘nil’ otherwise. - - -- Function: magit-git-true &rest args - Executes git with ARGS and returns ‘t’ if the first line printed by - git is the string "true", ‘nil’ otherwise. - - -- Function: magit-git-false &rest args - Executes git with ARGS and returns ‘t’ if the first line printed by - git is the string "false", ‘nil’ otherwise. - - -- Function: magit-git-insert &rest args - Executes git with ARGS and inserts its output at point. - - -- Function: magit-git-string &rest args - Executes git with ARGS and returns the first line of its output. - If there is no output or if it begins with a newline character, - then this returns ‘nil’. - - -- Function: magit-git-lines &rest args - Executes git with ARGS and returns its output as a list of lines. - Empty lines anywhere in the output are omitted. - - -- Function: magit-git-items &rest args - Executes git with ARGS and returns its null-separated output as a - list. Empty items anywhere in the output are omitted. - - If the value of option ‘magit-git-debug’ is non-nil and git exits - with a non-zero exit status, then warn about that in the echo area - and add a section containing git’s standard error in the current - repository’s process buffer. - - -- Function: magit-process-git destination &rest args - Calls Git synchronously in a separate process, returning its exit - code. DESTINATION specifies how to handle the output, like for - ‘call-process’, except that file handlers are supported. Enables - Cygwin’s "noglob" option during the call and ensures unix eol - conversion. - - -- Function: magit-process-file process &optional infile buffer display - &rest args - Processes files synchronously in a separate process. Identical to - ‘process-file’ but temporarily enables Cygwin’s "noglob" option - during the call and ensures unix eol conversion. - - If an error occurs when using one of the above functions, then that -is usually due to a bug, i.e., using an argument which is not actually -supported. Such errors are usually not reported, but when they occur we -need to be able to debug them. - - -- User Option: magit-git-debug - Whether to report errors that occur when using ‘magit-git-insert’, - ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This - does not actually raise an error. Instead a message is shown in - the echo area, and git’s standard error is insert into a new - section in the current repository’s process buffer. - - -- Function: magit-git-str &rest args - This is a variant of ‘magit-git-string’ that ignores the option - ‘magit-git-debug’. It is mainly intended to be used while handling - errors in functions that do respect that option. Using such a - function while handing an error could cause yet another error and - therefore lead to an infinite recursion. You probably won’t ever - need to use this function. - - -File: magit.info, Node: Calling Git for Effect, Prev: Getting a Value from Git, Up: Calling Git - -10.1.2 Calling Git for Effect ------------------------------ - -These functions are used to run git to produce some effect. Most Magit -commands that actually run git do so by using such a function. - - Because we do not need to consume git’s output when using these -functions, their output is instead logged into a per-repository buffer, -which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’ -elsewhere. - - These functions can have an effect in two distinct ways. Firstly, -running git may change something, i.e., create or push a new commit. -Secondly, that change may require that Magit buffers are refreshed to -reflect the changed state of the repository. But refreshing isn’t -always desirable, so only some of these functions do perform such a -refresh after git has returned. - - Sometimes it is useful to run git asynchronously. For example, when -the user has just initiated a push, then there is no reason to make her -wait until that has completed. In other cases it makes sense to wait -for git to complete before letting the user do something else. For -example after staging a change it is useful to wait until after the -refresh because that also automatically moves to the next change. - - -- Function: magit-call-git &rest args - Calls git synchronously with ARGS. - - -- Function: magit-call-process program &rest args - Calls PROGRAM synchronously with ARGS. - - -- Function: magit-run-git &rest args - Calls git synchronously with ARGS and then refreshes. - - -- Function: magit-run-git-with-input &rest args - Calls git synchronously with ARGS and sends it the content of the - current buffer on standard input. - - If the current buffer’s ‘default-directory’ is on a remote - filesystem, this function actually runs git asynchronously. But - then it waits for the process to return, so the function itself is - synchronous. - - -- Function: magit-git &rest args - Calls git synchronously with ARGS for side-effects only. This - function does not refresh the buffer. - - -- Function: magit-git-wash washer &rest args - Execute Git with ARGS, inserting washed output at point. Actually - first insert the raw output at point. If there is no output call - ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to - the inserted text, move to its beginning, and then call function - WASHER with ARGS as its sole argument. - - And now for the asynchronous variants. - - -- Function: magit-run-git-async &rest args - Start Git, prepare for refresh, and return the process object. - ARGS is flattened and then used as arguments to Git. - - Display the command line arguments in the echo area. - - After Git returns some buffers are refreshed: the buffer that was - current when this function was called (if it is a Magit buffer and - still alive), as well as the respective Magit status buffer. - Unmodified buffers visiting files that are tracked in the current - repository are reverted if ‘magit-revert-buffers’ is non-nil. - - -- Function: magit-run-git-with-editor &rest args - Export GIT_EDITOR and start Git. Also prepare for refresh and - return the process object. ARGS is flattened and then used as - arguments to Git. - - Display the command line arguments in the echo area. - - After Git returns some buffers are refreshed: the buffer that was - current when this function was called (if it is a Magit buffer and - still alive), as well as the respective Magit status buffer. - - -- Function: magit-start-git input &rest args - Start Git, prepare for refresh, and return the process object. - - If INPUT is non-nil, it has to be a buffer or the name of an - existing buffer. The buffer content becomes the processes standard - input. - - Option ‘magit-git-executable’ specifies the Git executable and - option ‘magit-git-global-arguments’ specifies constant arguments. - The remaining arguments ARGS specify arguments to Git. They are - flattened before use. - - After Git returns, some buffers are refreshed: the buffer that was - current when this function was called (if it is a Magit buffer and - still alive), as well as the respective Magit status buffer. - Unmodified buffers visiting files that are tracked in the current - repository are reverted if ‘magit-revert-buffers’ is non-nil. - - -- Function: magit-start-process &rest args - Start PROGRAM, prepare for refresh, and return the process object. - - If optional argument INPUT is non-nil, it has to be a buffer or the - name of an existing buffer. The buffer content becomes the - processes standard input. - - The process is started using ‘start-file-process’ and then setup to - use the sentinel ‘magit-process-sentinel’ and the filter - ‘magit-process-filter’. Information required by these functions is - stored in the process object. When this function returns the - process has not started to run yet so it is possible to override - the sentinel and filter. - - After the process returns, ‘magit-process-sentinel’ refreshes the - buffer that was current when ‘magit-start-process’ was called (if - it is a Magit buffer and still alive), as well as the respective - Magit status buffer. Unmodified buffers visiting files that are - tracked in the current repository are reverted if - ‘magit-revert-buffers’ is non-nil. - - -- Variable: magit-this-process - The child process which is about to start. This can be used to - change the filter and sentinel. - - -- Variable: magit-process-raise-error - When this is non-nil, then ‘magit-process-sentinel’ raises an error - if git exits with a non-zero exit status. For debugging purposes. - - -File: magit.info, Node: Section Plumbing, Next: Refreshing Buffers, Prev: Calling Git, Up: Plumbing - -10.2 Section Plumbing -===================== - -* Menu: - -* Creating Sections:: -* Section Selection:: -* Matching Sections:: - - -File: magit.info, Node: Creating Sections, Next: Section Selection, Up: Section Plumbing - -10.2.1 Creating Sections ------------------------- - - -- Macro: magit-insert-section &rest args - Insert a section at point. - - TYPE is the section type, a symbol. Many commands that act on the - current section behave differently depending on that type. Also if - a variable ‘magit-TYPE-section-map’ exists, then use that as the - text-property ‘keymap’ of all text belonging to the section (but - this may be overwritten in subsections). TYPE can also have the - form ‘(eval FORM)’ in which case FORM is evaluated at runtime. - - Optional VALUE is the value of the section, usually a string that - is required when acting on the section. - - When optional HIDE is non-nil collapse the section body by default, - i.e., when first creating the section, but not when refreshing the - buffer. Otherwise, expand it by default. This can be overwritten - using ‘magit-section-set-visibility-hook’. When a section is - recreated during a refresh, then the visibility of predecessor is - inherited and HIDE is ignored (but the hook is still honored). - - BODY is any number of forms that actually insert the section’s - heading and body. Optional NAME, if specified, has to be a symbol, - which is then bound to the struct of the section being inserted. - - Before BODY is evaluated the ‘start’ of the section object is set - to the value of ‘point’ and after BODY was evaluated its ‘end’ is - set to the new value of ‘point’; BODY is responsible for moving - ‘point’ forward. - - If it turns out inside BODY that the section is empty, then - ‘magit-cancel-section’ can be used to abort and remove all traces - of the partially inserted section. This can happen when creating a - section by washing Git’s output and Git didn’t actually output - anything this time around. - - -- Function: magit-insert-heading &rest args - Insert the heading for the section currently being inserted. - - This function should only be used inside ‘magit-insert-section’. - - When called without any arguments, then just set the ‘content’ slot - of the object representing the section being inserted to a marker - at ‘point’. The section should only contain a single line when - this function is used like this. - - When called with arguments ARGS, which have to be strings, then - insert those strings at point. The section should not contain any - text before this happens and afterwards it should again only - contain a single line. If the ‘face’ property is set anywhere - inside any of these strings, then insert all of them unchanged. - Otherwise use the ‘magit-section-heading’ face for all inserted - text. - - The ‘content’ property of the section struct is the end of the - heading (which lasts from ‘start’ to ‘content’) and the beginning - of the body (which lasts from ‘content’ to ‘end’). If the value of - ‘content’ is nil, then the section has no heading and its body - cannot be collapsed. If a section does have a heading then its - height must be exactly one line, including a trailing newline - character. This isn’t enforced; you are responsible for getting it - right. The only exception is that this function does insert a - newline character if necessary. - - -- Function: magit-cancel-section - Cancel the section currently being inserted. This exits the - innermost call to ‘magit-insert-section’ and removes all traces of - what has already happened inside that call. - - -- Function: magit-define-section-jumper sym title &optional value - Define an interactive function to go to section SYM. TITLE is the - displayed title of the section. - - -File: magit.info, Node: Section Selection, Next: Matching Sections, Prev: Creating Sections, Up: Section Plumbing - -10.2.2 Section Selection ------------------------- - - -- Function: magit-current-section - Return the section at point. - - -- Function: magit-region-sections &optional condition multiple - Return a list of the selected sections. - - When the region is active and constitutes a valid section - selection, then return a list of all selected sections. This is - the case when the region begins in the heading of a section and - ends in the heading of the same section or in that of a sibling - section. If optional MULTIPLE is non-nil, then the region cannot - begin and end in the same section. - - When the selection is not valid, then return nil. In this case, - most commands that can act on the selected sections will instead - act on the section at point. - - When the region looks like it would in any other buffer then the - selection is invalid. When the selection is valid then the region - uses the ‘magit-section-highlight’ face. This does not apply to - diffs where things get a bit more complicated, but even here if the - region looks like it usually does, then that’s not a valid - selection as far as this function is concerned. - - If optional CONDITION is non-nil, then the selection not only has - to be valid; all selected sections additionally have to match - CONDITION, or nil is returned. See ‘magit-section-match’ for the - forms CONDITION can take. - - -- Function: magit-region-values &optional condition multiple - Return a list of the values of the selected sections. - - Return the values that themselves would be returned by - ‘magit-region-sections’ (which see). - - -File: magit.info, Node: Matching Sections, Prev: Section Selection, Up: Section Plumbing - -10.2.3 Matching Sections ------------------------- - -‘M-x magit-describe-section-briefly’ - Show information about the section at point. This command is - intended for debugging purposes. - - -- Function: magit-section-ident section - Return an unique identifier for SECTION. The return value has the - form ‘((TYPE . VALUE)...)’. - - -- Function: magit-get-section ident &optional root - Return the section identified by IDENT. IDENT has to be a list as - returned by ‘magit-section-ident’. - - -- Function: magit-section-match condition &optional section - Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the - section at point. If SECTION is not specified and there also is no - section at point, then return ‘nil’. - - CONDITION can take the following forms: - • ‘(CONDITION...)’ - - matches if any of the CONDITIONs matches. - - • ‘[CLASS...]’ - - matches if the section’s class is the same as the first CLASS - or a subclass of that; the section’s parent class matches the - second CLASS; and so on. - - • ‘[* CLASS...]’ - - matches sections that match ‘[CLASS...]’ and also recursively - all their child sections. - - • ‘CLASS’ - - matches if the section’s class is the same as CLASS or a - subclass of that; regardless of the classes of the parent - sections. - - Each CLASS should be a class symbol, identifying a class that - derives from ‘magit-section’. For backward compatibility CLASS can - also be a "type symbol". A section matches such a symbol if the - value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in - ‘magit--section-type-alist’, then a section also matches that type - if its class is a subclass of the class that corresponds to the - type as per that alist. - - Note that it is not necessary to specify the complete section - lineage as printed by ‘magit-describe-section-briefly’, unless of - course you want to be that precise. - - -- Function: magit-section-value-if condition &optional section - If the section at point matches CONDITION, then return its value. - - If optional SECTION is non-nil then test whether that matches - instead. If there is no section at point and SECTION is nil, then - return nil. If the section does not match, then return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - - -- Function: magit-section-case &rest clauses - Choose among clauses on the type of the section at point. - - Each clause looks like (CONDITION BODY...). The type of the - section is compared against each CONDITION; the BODY forms of the - first match are evaluated sequentially and the value of the last - form is returned. Inside BODY the symbol ‘it’ is bound to the - section at point. If no clause succeeds or if there is no section - at point return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - Additionally a CONDITION of t is allowed in the final clause and - matches if no other CONDITION match, even if there is no section at - point. - - -- Variable: magit-root-section - The root section in the current buffer. All other sections are - descendants of this section. The value of this variable is set by - ‘magit-insert-section’ and you should never modify it. - - For diff related sections a few additional tools exist. - - -- Function: magit-diff-type &optional section - Return the diff type of SECTION. - - The returned type is one of the symbols ‘staged’, ‘unstaged’, - ‘committed’, or ‘undefined’. This type serves a similar purpose as - the general type common to all sections (which is stored in the - ‘type’ slot of the corresponding ‘magit-section’ struct) but takes - additional information into account. When the SECTION isn’t - related to diffs and the buffer containing it also isn’t a - diff-only buffer, then return nil. - - Currently the type can also be one of ‘tracked’ and ‘untracked’, - but these values are not handled explicitly in every place they - should be. A possible fix could be to just return nil here. - - The section has to be a ‘diff’ or ‘hunk’ section, or a section - whose children are of type ‘diff’. If optional SECTION is nil, - return the diff type for the current section. In buffers whose - major mode is ‘magit-diff-mode’ SECTION is ignored and the type is - determined using other means. In ‘magit-revision-mode’ buffers the - type is always ‘committed’. - - -- Function: magit-diff-scope &optional section strict - Return the diff scope of SECTION or the selected section(s). - - A diff’s "scope" describes what part of a diff is selected, it is a - symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or - ‘list’. Do not confuse this with the diff "type", as returned by - ‘magit-diff-type’. - - If optional SECTION is non-nil, then return the scope of that, - ignoring the sections selected by the region. Otherwise return the - scope of the current section, or if the region is active and - selects a valid group of diff related sections, the type of these - sections, i.e., ‘hunks’ or ‘files’. If SECTION (or if the current - section that is nil) is a ‘hunk’ section and the region starts and - ends inside the body of a that section, then the type is ‘region’. - - If optional STRICT is non-nil then return nil if the diff type of - the section at point is ‘untracked’ or the section at point is not - actually a ‘diff’ but a ‘diffstat’ section. - - -File: magit.info, Node: Refreshing Buffers, Next: Conventions, Prev: Section Plumbing, Up: Plumbing - -10.3 Refreshing Buffers -======================= - -All commands that create a new Magit buffer or change what is being -displayed in an existing buffer do so by calling ‘magit-mode-setup’. -Among other things, that function sets the buffer local values of -‘default-directory’ (to the top-level of the repository), -‘magit-refresh-function’, and ‘magit-refresh-args’. - - Buffers are refreshed by calling the function that is the local value -of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’, -where ‘*’ may be something like ‘diff’) with the value of -‘magit-refresh-args’ as arguments. - - -- Macro: magit-mode-setup buffer switch-func mode refresh-func - &optional refresh-args - This function displays and selects BUFFER, turns on MODE, and - refreshes a first time. - - This function displays and optionally selects BUFFER by calling - ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as - arguments. Then it sets the local value of - ‘magit-refresh-function’ to REFRESH-FUNC and that of - ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the - buffer content by calling REFRESH-FUNC with REFRESH-ARGS as - arguments. - - All arguments are evaluated before switching to BUFFER. - - -- Function: magit-mode-display-buffer buffer mode &optional - switch-function - This function display BUFFER in some window and select it. BUFFER - may be a buffer or a string, the name of a buffer. The buffer is - returned. - - Unless BUFFER is already displayed in the selected frame, store the - previous window configuration as a buffer local value, so that it - can later be restored by ‘magit-mode-bury-buffer’. - - The buffer is displayed and selected using SWITCH-FUNCTION. If - that is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s - major mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ - is used. - - -- Variable: magit-refresh-function - The value of this buffer-local variable is the function used to - refresh the current buffer. It is called with ‘magit-refresh-args’ - as arguments. - - -- Variable: magit-refresh-args - The list of arguments used by ‘magit-refresh-function’ to refresh - the current buffer. ‘magit-refresh-function’ is called with these - arguments. - - The value is usually set using ‘magit-mode-setup’, but in some - cases it’s also useful to provide commands that can change the - value. For example, the ‘magit-diff-refresh’ transient can be used - to change any of the arguments used to display the diff, without - having to specify again which differences should be shown, but - ‘magit-diff-more-context’, ‘magit-diff-less-context’ and - ‘magit-diff-default-context’ change just the ‘-U<N>’ argument. In - both case this is done by changing the value of this variable and - then calling this ‘magit-refresh-function’. - - -File: magit.info, Node: Conventions, Prev: Refreshing Buffers, Up: Plumbing - -10.4 Conventions -================ - -Also see *note Completion and Confirmation::. - -* Menu: - -* Theming Faces:: - - -File: magit.info, Node: Theming Faces, Up: Conventions - -10.4.1 Theming Faces --------------------- - -The default theme uses blue for local branches, green for remote -branches, and goldenrod (brownish yellow) for tags. When creating a new -theme, you should probably follow that example. If your theme already -uses other colors, then stick to that. - - In older releases these reference faces used to have a background -color and a box around them. The basic default faces no longer do so, -to make Magit buffers much less noisy, and you should follow that -example at least with regards to boxes. (Boxes were used in the past to -work around a conflict between the highlighting overlay and text -property backgrounds. That’s no longer necessary because highlighting -no longer causes other background colors to disappear.) Alternatively -you can keep the background color and/or box, but then have to take -special care to adjust ‘magit-branch-current’ accordingly. By default -it looks mostly like ‘magit-branch-local’, but with a box (by default -the former is the only face that uses a box, exactly so that it sticks -out). If the former also uses a box, then you have to make sure that it -differs in some other way from the latter. - - The most difficult faces to theme are those related to diffs, -headings, highlighting, and the region. There are faces that fall into -all four groups - expect to spend some time getting this right. - - The ‘region’ face in the default theme, in both the light and dark -variants, as well as in many other themes, distributed with Emacs or by -third-parties, is very ugly. It is common to use a background color -that really sticks out, which is ugly but if that were the only problem -then it would be acceptable. Unfortunately many themes also set the -foreground color, which ensures that all text within the region is -readable. Without doing that there might be cases where some foreground -color is too close to the region background color to still be readable. -But it also means that text within the region loses all syntax -highlighting. - - I consider the work that went into getting the ‘region’ face right to -be a good indicator for the general quality of a theme. My -recommendation for the ‘region’ face is this: use a background color -slightly different from the background color of the ‘default’ face, and -do not set the foreground color at all. So for a light theme you might -use a light (possibly tinted) gray as the background color of ‘default’ -and a somewhat darker gray for the background of ‘region’. That should -usually be enough to not collide with the foreground color of any other -face. But if some other faces also set a light gray as background -color, then you should also make sure it doesn’t collide with those (in -some cases it might be acceptable though). - - Magit only uses the ‘region’ face when the region is "invalid" by its -own definition. In a Magit buffer the region is used to either select -multiple sibling sections, so that commands which support it act on all -of these sections instead of just the current section, or to select -lines within a single hunk section. In all other cases, the section is -considered invalid and Magit won’t act on it. But such invalid sections -happen, either because the user has not moved point enough yet to make -it valid or because she wants to use a non-magit command to act on the -region, e.g., ‘kill-region’. - - So using the regular ‘region’ face for invalid sections is a feature. -It tells the user that Magit won’t be able to act on it. It’s -acceptable if that face looks a bit odd and even (but less so) if it -collides with the background colors of section headings and other things -that have a background color. - - Magit highlights the current section. If a section has subsections, -then all of them are highlighted. This is done using faces that have -"highlight" in their names. For most sections, -‘magit-section-highlight’ is used for both the body and the heading. -Like the ‘region’ face, it should only set the background color to -something similar to that of ‘default’. The highlight background color -must be different from both the ‘region’ background color and the -‘default’ background color. - - For diff related sections Magit uses various faces to highlight -different parts of the selected section(s). Note that hunk headings, -unlike all other section headings, by default have a background color, -because it is useful to have very visible separators between hunks. -That face ‘magit-diff-hunk-heading’, should be different from both -‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as -well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’. -By default we do that by changing the foreground color. Changing the -background color would lead to complications, and there are already -enough we cannot get around. (Also note that it is generally a good -idea for section headings to always be bold, but only for sections that -have subsections). - - When there is a valid region selecting diff-related sibling sections, -i.e., multiple files or hunks, then the bodies of all these sections use -the respective highlight faces, but additionally the headings instead -use one of the faces ‘magit-diff-file-heading-selection’ or -‘magit-diff-hunk-heading-selection’. These faces have to be different -from the regular highlight variants to provide explicit visual -indication that the region is active. - - When theming diff related faces, start by setting the option -‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only -refine the current hunk or not use hunk refinement at all, but some of -the users of your theme want all hunks to be refined, so you have to -cater to that. - - (Also turn on ‘magit-diff-highlight-indentation’, -‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and -insert some whitespace errors into the code you use for testing.) - - For added lines you have to adjust three faces: ‘magit-diff-added’, -‘magit-diff-added-highlight’, and ‘diff-refined-added’. Make sure that -the latter works well with both of the former, as well as ‘smerge-other’ -and ‘diff-added’. Then do the same for the removed lines, context -lines, lines added by us, and lines added by them. Also make sure the -respective added, removed, and context faces use approximately the same -saturation for both the highlighted and unhighlighted variants. Also -make sure the file and diff headings work nicely with context lines -(e.g., make them look different). Line faces should set both the -foreground and the background color. For example, for added lines use -two different greens. - - It’s best if the foreground color of both the highlighted and the -unhighlighted variants are the same, so you will need to have to find a -color that works well on the highlight and unhighlighted background, the -refine background, and the highlight context background. When there is -an hunk internal region, then the added- and removed-lines background -color is used only within that region. Outside the region the -highlighted context background color is used. This makes it easier to -see what is being staged. With an hunk internal region the hunk heading -is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin -lines that are added around the lines that fall within the region. The -background color of that has to be distinct enough from the various -other involved background colors. - - Nobody said this would be easy. If your theme restricts itself to a -certain set of colors, then you should make an exception here. -Otherwise it would be impossible to make the diffs look good in each and -every variation. Actually you might want to just stick to the default -definitions for these faces. You have been warned. Also please note -that if you do not get this right, this will in some cases look to users -like bugs in Magit - so please do it right or not at all. - - -File: magit.info, Node: FAQ, Next: Debugging Tools, Prev: Plumbing, Up: Top - -Appendix A FAQ -************** - -The next two nodes lists frequently asked questions. For a list of -frequently *and recently* asked questions, i.e., questions that haven’t -made it into the manual yet, see -<https://github.com/magit/magit/wiki/FAQ>. - - Please also see *note Debugging Tools::. - -* Menu: - -* FAQ - How to ...?:: -* FAQ - Issues and Errors:: - - -File: magit.info, Node: FAQ - How to ...?, Next: FAQ - Issues and Errors, Up: FAQ - -A.1 FAQ - How to ...? -===================== - -* Menu: - -* How to pronounce Magit?:: -* How to show git's output?:: -* How to install the gitman info manual?:: -* How to show diffs for gpg-encrypted files?:: -* How does branching and pushing work?:: -* Should I disable VC?:: - - -File: magit.info, Node: How to pronounce Magit?, Next: How to show git's output?, Up: FAQ - How to ...? - -A.1.1 How to pronounce Magit? ------------------------------ - -Either ‘mu[m's] git’ or ‘magi{c => t}’ is fine. - - The slogan is "It’s Magit! The magical Git client", so it makes -sense to pronounce Magit like magic, while taking into account that C -and T do not sound the same. - - The German "Magie" is not pronounced the same as the English "magic", -so if you speak German then you can use the above rationale to justify -using the former pronunciation; ‘Mag{ie => it}’. - - You can also choose to use the former pronunciation just because you -like it better. - - Also see <https://magit.vc/assets/videos/magic.mp4>. Also see -<https://emacs.stackexchange.com/questions/13696>. - - -File: magit.info, Node: How to show git's output?, Next: How to install the gitman info manual?, Prev: How to pronounce Magit?, Up: FAQ - How to ...? - -A.1.2 How to show git’s output? -------------------------------- - -To show the output of recently run git commands, press ‘$’ (or, if that -isn’t available, ‘M-x magit-process-buffer’). This will show a buffer -containing a section per git invocation; as always press ‘TAB’ to expand -or collapse them. - - By default, git’s output is only inserted into the process buffer if -it is run for side-effects. When the output is consumed in some way, -also inserting it into the process buffer would be too expensive. For -debugging purposes, it’s possible to do so anyway by setting -‘magit-git-debug’ to ‘t’. - - -File: magit.info, Node: How to install the gitman info manual?, Next: How to show diffs for gpg-encrypted files?, Prev: How to show git's output?, Up: FAQ - How to ...? - -A.1.3 How to install the gitman info manual? --------------------------------------------- - -Git’s manpages can be exported as an info manual called ‘gitman’. -Magit’s own info manual links to nodes in that manual instead of the -actual manpages because Info doesn’t support linking to manpages. - - Unfortunately some distributions do not install the ‘gitman’ manual -by default and you will have to install a separate documentation package -to get it. - - Magit patches Info adding the ability to visit links to the ‘gitman’ -Info manual by instead viewing the respective manpage. If you prefer -that approach, then set the value of ‘magit-view-git-manual-method’ to -one of the supported packages ‘man’ or ‘woman’, e.g.: - - (setq magit-view-git-manual-method 'man) - - -File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: How does branching and pushing work?, Prev: How to install the gitman info manual?, Up: FAQ - How to ...? - -A.1.4 How to show diffs for gpg-encrypted files? ------------------------------------------------- - -Git supports showing diffs for encrypted files, but has to be told to do -so. Since Magit just uses Git to get the diffs, configuring Git also -affects the diffs displayed inside Magit. - - git config --global diff.gpg.textconv "gpg --no-tty --decrypt" - echo "*.gpg filter=gpg diff=gpg" > .gitattributes - - -File: magit.info, Node: How does branching and pushing work?, Next: Should I disable VC?, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ - How to ...? - -A.1.5 How does branching and pushing work? ------------------------------------------- - -Please see *note Branching:: and -<https://emacsair.me/2016/01/17/magit-2.4> - - -File: magit.info, Node: Should I disable VC?, Prev: How does branching and pushing work?, Up: FAQ - How to ...? - -A.1.6 Should I disable VC? --------------------------- - -If you don’t use VC (the built-in version control interface) then you -might be tempted to disable it, not least because we used to recommend -that you do that. - - We no longer recommend that you disable VC. Doing so would break -useful third-party packages (such as ‘diff-hl’), which depend on VC -being enabled. - - If you choose to disable VC anyway, then you can do so by changing -the value of ‘vc-handled-backends’. - - -File: magit.info, Node: FAQ - Issues and Errors, Prev: FAQ - How to ...?, Up: FAQ - -A.2 FAQ - Issues and Errors -=========================== - -* Menu: - -* Magit is slow:: -* I changed several thousand files at once and now Magit is unusable:: -* I am having problems committing:: -* I am using MS Windows and cannot push with Magit:: -* I am using macOS and SOMETHING works in shell, but not in Magit: I am using macOS and SOMETHING works in shell but not in Magit. -* Expanding a file to show the diff causes it to disappear:: -* Point is wrong in the COMMIT_EDITMSG buffer:: -* The mode-line information isn't always up-to-date:: -* A branch and tag sharing the same name breaks SOMETHING:: -* My Git hooks work on the command-line but not inside Magit:: -* git-commit-mode isn't used when committing from the command-line:: -* Point ends up inside invisible text when jumping to a file-visiting buffer:: -* I am no longer able to save popup defaults:: - - -File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors - -A.2.1 Magit is slow -------------------- - -See *note Performance:: and *note I changed several thousand files at -once and now Magit is unusable::. - - -File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ - Issues and Errors - -A.2.2 I changed several thousand files at once and now Magit is unusable ------------------------------------------------------------------------- - -Magit is currently not expected to work well under such conditions. It -sure would be nice if it did. Reaching satisfactory performance under -such conditions will require some heavy refactoring. This is no small -task but I hope to eventually find the time to make it happen. - - But for now we recommend you use the command line to complete this -one commit. Also see *note Performance::. - - -File: magit.info, Node: I am having problems committing, Next: I am using MS Windows and cannot push with Magit, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors - -A.2.3 I am having problems committing -------------------------------------- - -That likely means that Magit is having problems finding an appropriate -emacsclient executable. See *note (with-editor)Configuring -With-Editor:: and *note (with-editor)Debugging::. - - -File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using macOS and SOMETHING works in shell but not in Magit, Prev: I am having problems committing, Up: FAQ - Issues and Errors - -A.2.4 I am using MS Windows and cannot push with Magit ------------------------------------------------------- - -It’s almost certain that Magit is only incidental to this issue. It is -much more likely that this is a configuration issue, even if you can -push on the command line. - - Detailed setup instructions can be found at -<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>. - - -File: magit.info, Node: I am using macOS and SOMETHING works in shell but not in Magit, Next: Expanding a file to show the diff causes it to disappear, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ - Issues and Errors - -A.2.5 I am using macOS and SOMETHING works in shell, but not in Magit ---------------------------------------------------------------------- - -This usually occurs because Emacs doesn’t have the same environment -variables as your shell. Try installing and configuring -<https://github.com/purcell/exec-path-from-shell>. By default it -synchronizes ‘$PATH’, which helps Magit find the same ‘git’ as the one -you are using on the shell. - - If SOMETHING is "passphrase caching with gpg-agent for commit and/or -tag signing", then you’ll also need to synchronize ‘$GPG_AGENT_INFO’. - - -File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: I am using macOS and SOMETHING works in shell but not in Magit, Up: FAQ - Issues and Errors - -A.2.6 Expanding a file to show the diff causes it to disappear --------------------------------------------------------------- - -This is probably caused by a customization of a ‘diff.*’ Git variable. -You probably set that variable for a reason, and should therefore only -undo that setting in Magit by customizing ‘magit-git-global-arguments’. - - -File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ - Issues and Errors - -A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer ---------------------------------------------------- - -Neither Magit nor ‘git-commit.el’ fiddle with point in the buffer used -to write commit messages, so something else must be doing it. - - You have probably globally enabled a mode which restores point in -file-visiting buffers. It might be a bit surprising, but when you write -a commit message, then you are actually editing a file. - - So you have to figure out which package is doing it. ‘saveplace’, -‘pointback’, and ‘session’ are likely candidates. These snippets might -help: - - (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)") - - (with-eval-after-load 'pointback - (lambda () - (when (or git-commit-mode git-rebase-mode) - (pointback-mode -1)))) - - -File: magit.info, Node: The mode-line information isn't always up-to-date, Next: A branch and tag sharing the same name breaks SOMETHING, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ - Issues and Errors - -A.2.8 The mode-line information isn’t always up-to-date -------------------------------------------------------- - -Magit is not responsible for the version control information that is -being displayed in the mode-line and looks something like ‘Git-master’. -The built-in "Version Control" package, also known as "VC", updates that -information, and can be told to do so more often: - - (setq auto-revert-check-vc-info t) - - But doing so isn’t good for performance. For more (overly -optimistic) information see *note (emacs)VC Mode Line::. - - If you don’t really care about seeing this information in the -mode-line, but just don’t want to see _incorrect_ information, then -consider simply not displaying it in the mode-line: - - (setq-default mode-line-format - (delete '(vc-mode vc-mode) mode-line-format)) - - -File: magit.info, Node: A branch and tag sharing the same name breaks SOMETHING, Next: My Git hooks work on the command-line but not inside Magit, Prev: The mode-line information isn't always up-to-date, Up: FAQ - Issues and Errors - -A.2.9 A branch and tag sharing the same name breaks SOMETHING -------------------------------------------------------------- - -Or more generally, ambiguous refnames break SOMETHING. - - Magit assumes that refs are named non-ambiguously across the -"refs/heads/", "refs/tags/", and "refs/remotes/" namespaces (i.e., all -the names remain unique when those prefixes are stripped). We consider -ambiguous refnames unsupported and recommend that you use a -non-ambiguous naming scheme. However, if you do work with a repository -that has ambiguous refnames, please report any issues you encounter, so -that we can investigate whether there is a simple fix. - - -File: magit.info, Node: My Git hooks work on the command-line but not inside Magit, Next: git-commit-mode isn't used when committing from the command-line, Prev: A branch and tag sharing the same name breaks SOMETHING, Up: FAQ - Issues and Errors - -A.2.10 My Git hooks work on the command-line but not inside Magit ------------------------------------------------------------------ - -When Magit calls ‘git’ it adds a few global arguments including -‘--literal-pathspecs’ and the ‘git’ process started by Magit then passes -that setting on to other ‘git’ process it starts itself. It does so by -setting the environment variable ‘GIT_LITERAL_PATHSPECS’, not by calling -subprocesses with the ‘--literal-pathspecs’ argument. You can therefore -override this setting in hook scripts using ‘unset -GIT_LITERAL_PATHSPECS’. - - -File: magit.info, Node: git-commit-mode isn't used when committing from the command-line, Next: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: My Git hooks work on the command-line but not inside Magit, Up: FAQ - Issues and Errors - -A.2.11 ‘git-commit-mode’ isn’t used when committing from the command-line -------------------------------------------------------------------------- - -The reason for this is that ‘git-commit.el’ has not been loaded yet -and/or that the server has not been started yet. These things have -always already been taken care of when you commit from Magit because in -order to do so, Magit has to be loaded and doing that involves loading -‘git-commit’ and starting the server. - - If you want to commit from the command-line, then you have to take -care of these things yourself. Your ‘init.el’ file should contain: - - (require 'git-commit) - (server-mode) - - Instead of ‘(require ’git-commit)‘ you may also use: - - (load "/path/to/magit-autoloads.el") - - You might want to do that because loading ‘git-commit’ causes large -parts of Magit to be loaded. - - There are also some variations of ‘(server-mode)’ that you might want -to try. Personally I use: - - (use-package server - :config (or (server-running-p) (server-mode))) - - Now you can use: - - $ emacs& - $ EDITOR=emacsclient git commit - - However you cannot use: - - $ killall emacs - $ EDITOR="emacsclient --alternate-editor emacs" git commit - - This will actually end up using ‘emacs’, not ‘emacsclient’. If you -do this, then you can still edit the commit message but -‘git-commit-mode’ won’t be used and you have to exit ‘emacs’ to finish -the process. - - Tautology ahead. If you want to be able to use ‘emacsclient’ to -connect to a running ‘emacs’ instance, even though no ‘emacs’ instance -is running, then you cannot use ‘emacsclient’ directly. - - Instead you have to create a script that does something like this: - - Try to use ‘emacsclient’ (without using ‘--alternate-editor’). If -that succeeds, do nothing else. Otherwise start ‘emacs &’ (and -‘init.el’ must call ‘server-start’) and try to use ‘emacsclient’ again. - - -File: magit.info, Node: Point ends up inside invisible text when jumping to a file-visiting buffer, Next: I am no longer able to save popup defaults, Prev: git-commit-mode isn't used when committing from the command-line, Up: FAQ - Issues and Errors - -A.2.12 Point ends up inside invisible text when jumping to a file-visiting buffer ---------------------------------------------------------------------------------- - -This can happen when you type ‘RET’ on a hunk to visit the respective -file at the respective position. One solution to this problem is to use -‘global-reveal-mode’. It makes sure that text around point is always -visible. If that is too drastic for your taste, then you may instead -use ‘magit-diff-visit-file-hook’ to reveal the text, possibly using -‘reveal-post-command’ or for Org buffers ‘org-reveal’. - - -File: magit.info, Node: I am no longer able to save popup defaults, Prev: Point ends up inside invisible text when jumping to a file-visiting buffer, Up: FAQ - Issues and Errors - -A.2.13 I am no longer able to save popup defaults -------------------------------------------------- - -Magit used to use Magit-Popup to implement the transient popup menus. -Now it used Transient instead, which is Magit-Popup’s successor. - - In the older Magit-Popup menus, it was possible to save user settings -(e.g., setting the gpg signing key for commits) by using ‘C-c C-c’ in -the popup buffer. This would dismiss the popup, but save the settings -as the defaults for future popups. - - When switching to Transient menus, this functionality is now -available via ‘C-x C-s’ instead; the ‘C-x’ prefix has other options as -well when using Transient, which will be displayed when it is typed. -See <https://magit.vc/manual/transient/Saving-Values.html#Saving-Values> -for more details. - - -File: magit.info, Node: Debugging Tools, Next: Keystroke Index, Prev: FAQ, Up: Top - -B Debugging Tools -***************** - -Magit and its dependencies provide a few debugging tools, and we -appreciate it very much if you use those tools before reporting an -issue. Please include all relevant output when reporting an issue. - -‘M-x magit-version’ - This command shows the currently used versions of Magit, Git, and - Emacs in the echo area. Non-interactively this just returns the - Magit version. - -‘M-x magit-emacs-Q-command’ - This command shows a debugging shell command in the echo area and - adds it to the kill ring. Paste that command into a shell and run - it. - - This shell command starts ‘emacs’ with only ‘magit’ and its - dependencies loaded. Neither your configuration nor other - installed packages are loaded. This makes it easier to determine - whether some issue lays with Magit or something else. - - If you run Magit from its Git repository, then you should be able - to use ‘make emacs-Q’ instead of the output of this command. - -‘M-x magit-toggle-git-debug’ - This command toggles whether additional git errors are reported. - - Magit basically calls git for one of these two reasons: for - side-effects or to do something with its standard output. - - When git is run for side-effects then its output, including error - messages, go into the process buffer which is shown when using ‘$’. - - When git’s output is consumed in some way, then it would be too - expensive to also insert it into this buffer, but when this option - is non-nil and git returns with a non-zero exit status, then at - least its standard error is inserted into this buffer. - - This is only intended for debugging purposes. Do not enable this - permanently, that would negatively affect performance. Also note - that just because git exits with a non-zero exit status and prints - an error message that usually doesn’t mean that it is an error as - far as Magit is concerned, which is another reason we usually hide - these error messages. Whether some error message is relevant in - the context of some unexpected behavior has to be judged on a case - by case basis. - -‘M-x magit-toggle-verbose-refresh’ - This command toggles whether Magit refreshes buffers verbosely. - Enabling this helps figuring out which sections are bottlenecks. - The additional output can be found in the ‘*Messages*’ buffer. - -‘M-x magit-debug-git-executable’ - This command displays a buffer containing information about the - available and used ‘git’ executable(s), and can be useful when - investigating ‘exec-path’ issues. - - Also see *note Git Executable::. - -‘M-x with-editor-debug’ - This command displays a buffer containing information about the - available and used ‘emacsclient’ executable(s), and can be useful - when investigating why Magit (or rather ‘with-editor’) cannot find - an appropriate ‘emacsclient’ executable. - - Also see *note (with-editor)Debugging::. - -Please also see *note FAQ::. - - -File: magit.info, Node: Keystroke Index, Next: Function and Command Index, Prev: Debugging Tools, Up: Top - -Appendix C Keystroke Index -************************** - - -* Menu: - -* !: Running Git Manually. - (line 13) -* ! !: Running Git Manually. - (line 17) -* ! a: Running Git Manually. - (line 53) -* ! b: Running Git Manually. - (line 56) -* ! g: Running Git Manually. - (line 59) -* ! k: Running Git Manually. - (line 50) -* ! m: Running Git Manually. - (line 62) -* ! p: Running Git Manually. - (line 25) -* ! s: Running Git Manually. - (line 34) -* ! S: Running Git Manually. - (line 38) -* $: Viewing Git Output. (line 17) -* +: Log Buffer. (line 64) -* + <1>: Refreshing Diffs. (line 65) -* -: Log Buffer. (line 67) -* - <1>: Refreshing Diffs. (line 62) -* 0: Refreshing Diffs. (line 68) -* 1: Section Visibility. (line 39) -* 2: Section Visibility. (line 39) -* 3: Section Visibility. (line 39) -* 4: Section Visibility. (line 39) -* 5: Repository List. (line 115) -* :: Running Git Manually. - (line 25) -* =: Log Buffer. (line 59) -* >: Sparse checkouts. (line 17) -* > a: Sparse checkouts. (line 39) -* > d: Sparse checkouts. (line 50) -* > e: Sparse checkouts. (line 21) -* > r: Sparse checkouts. (line 44) -* > s: Sparse checkouts. (line 33) -* ^: Section Movement. (line 28) -* a: Applying. (line 34) -* A: Cherry Picking. (line 9) -* A A: Cherry Picking. (line 17) -* A a: Cherry Picking. (line 23) -* A A <1>: Cherry Picking. (line 85) -* A a <1>: Cherry Picking. (line 91) -* A d: Cherry Picking. (line 51) -* A h: Cherry Picking. (line 40) -* A n: Cherry Picking. (line 62) -* A s: Cherry Picking. (line 72) -* A s <1>: Cherry Picking. (line 88) -* B: Bisecting. (line 9) -* b: Blaming. (line 115) -* b <1>: Branch Commands. (line 13) -* b <2>: Editing Rebase Sequences. - (line 70) -* B B: Bisecting. (line 16) -* B b: Bisecting. (line 32) -* b b: Branch Commands. (line 47) -* b C: Branch Commands. (line 31) -* b c: Branch Commands. (line 63) -* B g: Bisecting. (line 36) -* B k: Bisecting. (line 46) -* b k: Branch Commands. (line 138) -* b l: Branch Commands. (line 69) -* B m: Bisecting. (line 40) -* b m: Branch Commands. (line 149) -* b n: Branch Commands. (line 54) -* B r: Bisecting. (line 51) -* B s: Bisecting. (line 26) -* b s: Branch Commands. (line 91) -* b S: Branch Commands. (line 118) -* b x: Branch Commands. (line 123) -* c: Blaming. (line 141) -* C: Cloning Repository. (line 20) -* c <1>: Initiating a Commit. (line 9) -* c <2>: Editing Rebase Sequences. - (line 59) -* C >: Cloning Repository. (line 38) -* c a: Initiating a Commit. (line 18) -* c A: Initiating a Commit. (line 59) -* C b: Cloning Repository. (line 44) -* C C: Cloning Repository. (line 28) -* c c: Initiating a Commit. (line 14) -* C d: Cloning Repository. (line 55) -* C e: Cloning Repository. (line 61) -* c e: Initiating a Commit. (line 21) -* c f: Initiating a Commit. (line 39) -* c F: Initiating a Commit. (line 46) -* C m: Cloning Repository. (line 48) -* C s: Cloning Repository. (line 32) -* c s: Initiating a Commit. (line 49) -* c S: Initiating a Commit. (line 56) -* c w: Initiating a Commit. (line 30) -* C-<return>: Visiting Files and Blobs from a Diff. - (line 50) -* C-<tab>: Section Visibility. (line 14) -* C-c C-a: Commit Pseudo Headers. - (line 16) -* C-c C-b: Log Buffer. (line 20) -* C-c C-b <1>: Refreshing Diffs. (line 84) -* C-c C-c: Select from Log. (line 21) -* C-c C-c <1>: Editing Commit Messages. - (line 18) -* C-c C-c <2>: Editing Rebase Sequences. - (line 7) -* C-c C-d: Refreshing Diffs. (line 75) -* C-c C-d <1>: Editing Commit Messages. - (line 54) -* C-c C-e: Commands Available in Diffs. - (line 24) -* C-c C-f: Log Buffer. (line 23) -* C-c C-f <1>: Refreshing Diffs. (line 87) -* C-c C-i: Commit Pseudo Headers. - (line 13) -* C-c C-k: Select from Log. (line 26) -* C-c C-k <1>: Editing Commit Messages. - (line 22) -* C-c C-k <2>: Editing Rebase Sequences. - (line 11) -* C-c C-n: Log Buffer. (line 26) -* C-c C-o: Commit Pseudo Headers. - (line 28) -* C-c C-p: Commit Pseudo Headers. - (line 31) -* C-c C-r: Commit Pseudo Headers. - (line 19) -* C-c C-s: Commit Pseudo Headers. - (line 22) -* C-c C-t: Commands Available in Diffs. - (line 15) -* C-c C-t <1>: Commit Pseudo Headers. - (line 25) -* C-c C-w: Using the Revision Stack. - (line 7) -* C-c f: Commands for Buffers Visiting Files. - (line 52) -* C-c f , c: Commands for Buffers Visiting Files. - (line 52) -* C-c f , k: Commands for Buffers Visiting Files. - (line 52) -* C-c f , r: Commands for Buffers Visiting Files. - (line 52) -* C-c f , x: Commands for Buffers Visiting Files. - (line 52) -* C-c f B: Blaming. (line 28) -* C-c f b: Blaming. (line 28) -* C-c f B <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f b <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f B b: Blaming. (line 28) -* C-c f B e: Blaming. (line 28) -* C-c f B f: Blaming. (line 28) -* C-c f B q: Blaming. (line 28) -* C-c f B r: Blaming. (line 28) -* C-c f c: Commands for Buffers Visiting Files. - (line 52) -* C-c f D: Commands for Buffers Visiting Files. - (line 52) -* C-c f d: Commands for Buffers Visiting Files. - (line 52) -* C-c f e: Blaming. (line 28) -* C-c f e <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f f: Blaming. (line 28) -* C-c f f <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f g: Commands for Buffers Visiting Files. - (line 52) -* C-c f G: Commands for Buffers Visiting Files. - (line 52) -* C-c f L: Commands for Buffers Visiting Files. - (line 52) -* C-c f l: Commands for Buffers Visiting Files. - (line 52) -* C-c f M: Commands for Buffers Visiting Files. - (line 52) -* C-c f m: Commands for Buffers Visiting Files. - (line 52) -* C-c f n: Commands for Buffers Visiting Files. - (line 52) -* C-c f p: Commands for Buffers Visiting Files. - (line 52) -* C-c f q: Blaming. (line 28) -* C-c f q <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f r: Blaming. (line 28) -* C-c f r <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f s: Commands for Buffers Visiting Files. - (line 52) -* C-c f s <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f t: Commands for Buffers Visiting Files. - (line 52) -* C-c f u: Commands for Buffers Visiting Files. - (line 52) -* C-c f u <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f v: Commands for Buffers Visiting Files. - (line 52) -* C-c f V: Commands for Buffers Visiting Files. - (line 52) -* C-c g: Transient Commands. (line 20) -* C-c M-g: Commands for Buffers Visiting Files. - (line 58) -* C-c M-g , c: Commands for Buffers Visiting Files. - (line 86) -* C-c M-g , k: Commands for Buffers Visiting Files. - (line 82) -* C-c M-g , r: Commands for Buffers Visiting Files. - (line 78) -* C-c M-g , x: Commands for Buffers Visiting Files. - (line 74) -* C-c M-g B: Blaming. (line 34) -* C-c M-g b: Blaming. (line 45) -* C-c M-g B <1>: Commands for Buffers Visiting Files. - (line 137) -* C-c M-g B b: Blaming. (line 45) -* C-c M-g B e: Blaming. (line 76) -* C-c M-g B f: Blaming. (line 68) -* C-c M-g B q: Blaming. (line 87) -* C-c M-g B r: Blaming. (line 60) -* C-c M-g c: Commands for Buffers Visiting Files. - (line 176) -* C-c M-g D: Commands for Buffers Visiting Files. - (line 91) -* C-c M-g d: Commands for Buffers Visiting Files. - (line 101) -* C-c M-g e: Blaming. (line 76) -* C-c M-g e <1>: Commands for Buffers Visiting Files. - (line 182) -* C-c M-g f: Blaming. (line 68) -* C-c M-g g: Commands for Buffers Visiting Files. - (line 166) -* C-c M-g G: Commands for Buffers Visiting Files. - (line 172) -* C-c M-g L: Commands for Buffers Visiting Files. - (line 109) -* C-c M-g l: Commands for Buffers Visiting Files. - (line 119) -* C-c M-g M: Commands for Buffers Visiting Files. - (line 132) -* C-c M-g n: Commands for Buffers Visiting Files. - (line 153) -* C-c M-g p: Commands for Buffers Visiting Files. - (line 149) -* C-c M-g q: Blaming. (line 87) -* C-c M-g r: Blaming. (line 60) -* C-c M-g s: Commands for Buffers Visiting Files. - (line 63) -* C-c M-g s <1>: Commands for Buffers Visiting Files. - (line 63) -* C-c M-g t: Commands for Buffers Visiting Files. - (line 129) -* C-c M-g u: Commands for Buffers Visiting Files. - (line 69) -* C-c M-g u <1>: Commands for Buffers Visiting Files. - (line 69) -* C-c M-g v: Commands for Buffers Visiting Files. - (line 156) -* C-c M-g V: Commands for Buffers Visiting Files. - (line 160) -* C-c M-i: Commit Pseudo Headers. - (line 35) -* C-c M-s: Editing Commit Messages. - (line 33) -* C-c TAB: Section Visibility. (line 14) -* C-w: Common Commands. (line 22) -* C-x g: Status Buffer. (line 23) -* C-x M-g: Transient Commands. (line 20) -* C-x u: Editing Rebase Sequences. - (line 77) -* d: Diffing. (line 22) -* D: Refreshing Diffs. (line 16) -* d c: Diffing. (line 63) -* d d: Diffing. (line 27) -* D f: Refreshing Diffs. (line 45) -* D F: Refreshing Diffs. (line 49) -* D g: Refreshing Diffs. (line 21) -* d p: Diffing. (line 56) -* d r: Diffing. (line 30) -* D r: Refreshing Diffs. (line 41) -* d s: Diffing. (line 48) -* D s: Refreshing Diffs. (line 25) -* d t: Diffing. (line 67) -* D t: Refreshing Diffs. (line 38) -* d u: Diffing. (line 53) -* d w: Diffing. (line 43) -* D w: Refreshing Diffs. (line 31) -* DEL: Log Buffer. (line 50) -* DEL <1>: Commands Available in Diffs. - (line 56) -* DEL <2>: Blaming. (line 103) -* DEL <3>: Editing Rebase Sequences. - (line 25) -* e: Ediffing. (line 10) -* E: Ediffing. (line 21) -* e <1>: Editing Rebase Sequences. - (line 46) -* E c: Ediffing. (line 100) -* E i: Ediffing. (line 94) -* E m: Ediffing. (line 33) -* E M: Ediffing. (line 48) -* E r: Ediffing. (line 25) -* E s: Ediffing. (line 87) -* E t: Ediffing. (line 79) -* E u: Ediffing. (line 91) -* E w: Ediffing. (line 97) -* E z: Ediffing. (line 103) -* f: Repository List. (line 111) -* f <1>: Editing Rebase Sequences. - (line 52) -* f <2>: Fetching. (line 10) -* F: Pulling. (line 10) -* f a: Fetching. (line 45) -* f C: Branch Commands. (line 31) -* F C: Branch Commands. (line 31) -* f e: Fetching. (line 34) -* F e: Pulling. (line 28) -* f m: Fetching. (line 48) -* f o: Fetching. (line 37) -* f p: Fetching. (line 15) -* F p: Pulling. (line 14) -* f r: Fetching. (line 41) -* f u: Fetching. (line 22) -* F u: Pulling. (line 21) -* g: Automatic Refreshing of Magit Buffers. - (line 26) -* G: Automatic Refreshing of Magit Buffers. - (line 34) -* H: Section Types and Values. - (line 14) -* I: Creating Repository. (line 7) -* j: Log Buffer. (line 31) -* j <1>: Commands Available in Diffs. - (line 43) -* k: Viewing Git Output. (line 24) -* k <1>: Applying. (line 40) -* k <2>: Editing Rebase Sequences. - (line 56) -* k <3>: Stashing. (line 118) -* l: Logging. (line 28) -* L: Refreshing Logs. (line 12) -* L <1>: Log Buffer. (line 7) -* L <2>: Log Margin. (line 52) -* l <1>: Editing Rebase Sequences. - (line 94) -* l a: Logging. (line 59) -* l b: Logging. (line 56) -* L d: Log Margin. (line 66) -* L g: Refreshing Logs. (line 17) -* l h: Logging. (line 38) -* l H: Reflog. (line 18) -* l l: Logging. (line 33) -* l L: Logging. (line 53) -* L L: Refreshing Logs. (line 34) -* L L <1>: Log Margin. (line 60) -* L l: Log Margin. (line 63) -* l o: Logging. (line 47) -* l O: Reflog. (line 15) -* l r: Reflog. (line 12) -* L s: Refreshing Logs. (line 21) -* l u: Logging. (line 41) -* L w: Refreshing Logs. (line 27) -* m: Repository List. (line 105) -* m <1>: Merging. (line 10) -* M: Remote Commands. (line 14) -* m a: Merging. (line 42) -* m a <1>: Merging. (line 91) -* M a: Remote Commands. (line 48) -* M C: Remote Commands. (line 32) -* m e: Merging. (line 30) -* m i: Merging. (line 54) -* M k: Remote Commands. (line 60) -* m m: Merging. (line 18) -* m m <1>: Merging. (line 86) -* m n: Merging. (line 36) -* m p: Merging. (line 75) -* M p: Remote Commands. (line 63) -* M P: Remote Commands. (line 67) -* M r: Remote Commands. (line 52) -* m s: Merging. (line 67) -* M u: Remote Commands. (line 56) -* M-1: Section Visibility. (line 45) -* M-2: Section Visibility. (line 45) -* M-3: Section Visibility. (line 45) -* M-4: Section Visibility. (line 45) -* M-<tab>: Section Visibility. (line 29) -* M-n: Section Movement. (line 24) -* M-n <1>: Editing Commit Messages. - (line 41) -* M-n <2>: Editing Rebase Sequences. - (line 40) -* M-p: Section Movement. (line 19) -* M-p <1>: Editing Commit Messages. - (line 36) -* M-p <2>: Editing Rebase Sequences. - (line 37) -* M-w: Blaming. (line 134) -* M-w <1>: Common Commands. (line 39) -* MM: Editing Rebase Sequences. - (line 102) -* Mt: Editing Rebase Sequences. - (line 108) -* n: Section Movement. (line 16) -* n <1>: Blaming. (line 118) -* N: Blaming. (line 121) -* n <2>: Editing Rebase Sequences. - (line 34) -* n <3>: Minor Mode for Buffers Visiting Blobs. - (line 16) -* o: Submodule Transient. (line 7) -* O: Subtree. (line 9) -* o a: Submodule Transient. (line 20) -* o d: Submodule Transient. (line 45) -* O e: Subtree. (line 37) -* O e p: Subtree. (line 48) -* O e s: Subtree. (line 52) -* o f: Submodule Transient. (line 51) -* O i: Subtree. (line 13) -* O i a: Subtree. (line 24) -* O i c: Subtree. (line 28) -* O i f: Subtree. (line 34) -* O i m: Subtree. (line 31) -* o l: Submodule Transient. (line 48) -* o p: Submodule Transient. (line 32) -* o r: Submodule Transient. (line 26) -* o s: Submodule Transient. (line 40) -* o u: Submodule Transient. (line 36) -* p: Section Movement. (line 11) -* p <1>: Blaming. (line 124) -* P: Blaming. (line 127) -* p <2>: Editing Rebase Sequences. - (line 31) -* P <1>: Pushing. (line 10) -* p <3>: Minor Mode for Buffers Visiting Blobs. - (line 13) -* P C: Branch Commands. (line 31) -* P e: Pushing. (line 29) -* P m: Pushing. (line 45) -* P o: Pushing. (line 33) -* P p: Pushing. (line 15) -* P r: Pushing. (line 37) -* P t: Pushing. (line 52) -* P T: Pushing. (line 59) -* P u: Pushing. (line 22) -* q: Quitting Windows. (line 7) -* q <1>: Log Buffer. (line 14) -* q <2>: Blaming. (line 130) -* q <3>: Minor Mode for Buffers Visiting Blobs. - (line 19) -* r: Rebasing. (line 10) -* r <1>: Editing Rebase Sequences. - (line 43) -* r a: Rebasing. (line 111) -* r e: Rebasing. (line 42) -* r e <1>: Rebasing. (line 107) -* r f: Rebasing. (line 79) -* r i: Rebasing. (line 76) -* r k: Rebasing. (line 91) -* r m: Rebasing. (line 83) -* r p: Rebasing. (line 28) -* r r: Rebasing. (line 97) -* r s: Rebasing. (line 47) -* r s <1>: Rebasing. (line 103) -* r u: Rebasing. (line 35) -* r w: Rebasing. (line 87) -* RET: Repository List. (line 102) -* RET <1>: References Buffer. (line 159) -* RET <2>: Visiting Files and Blobs from a Diff. - (line 9) -* RET <3>: Blaming. (line 91) -* RET <4>: Editing Rebase Sequences. - (line 15) -* s: Staging and Unstaging. - (line 29) -* S: Staging and Unstaging. - (line 36) -* s <1>: Editing Rebase Sequences. - (line 49) -* S-<tab>: Section Visibility. (line 33) -* SPC: Log Buffer. (line 41) -* SPC <1>: Commands Available in Diffs. - (line 53) -* SPC <2>: Blaming. (line 94) -* SPC <3>: Editing Rebase Sequences. - (line 19) -* t: Editing Rebase Sequences. - (line 97) -* t <1>: Tagging. (line 9) -* T: Notes. (line 9) -* T a: Notes. (line 47) -* T c: Notes. (line 43) -* t k: Tagging. (line 37) -* T m: Notes. (line 35) -* t p: Tagging. (line 43) -* T p: Notes. (line 28) -* t r: Tagging. (line 18) -* T r: Notes. (line 21) -* t t: Tagging. (line 14) -* T T: Notes. (line 14) -* TAB: Section Visibility. (line 10) -* u: Repository List. (line 108) -* u <1>: Staging and Unstaging. - (line 42) -* U: Staging and Unstaging. - (line 50) -* v: Applying. (line 47) -* V: Reverting. (line 7) -* V a: Reverting. (line 35) -* V s: Reverting. (line 32) -* V V: Reverting. (line 15) -* V v: Reverting. (line 20) -* V V <1>: Reverting. (line 29) -* W: Plain Patches. (line 7) -* w: Maildir Patches. (line 9) -* w a: Plain Patches. (line 20) -* w a <1>: Maildir Patches. (line 23) -* w a <2>: Maildir Patches. (line 38) -* W c: Plain Patches. (line 12) -* w m: Maildir Patches. (line 20) -* W s: Plain Patches. (line 26) -* w s: Maildir Patches. (line 34) -* w w: Maildir Patches. (line 14) -* w w <1>: Maildir Patches. (line 31) -* x: Editing Rebase Sequences. - (line 62) -* x <1>: Resetting. (line 9) -* X f: Resetting. (line 44) -* X h: Resetting. (line 24) -* X i: Resetting. (line 33) -* X k: Resetting. (line 28) -* X m: Resetting. (line 15) -* X s: Resetting. (line 19) -* X w: Resetting. (line 39) -* X w <1>: Wip Modes. (line 64) -* Y: Cherries. (line 18) -* y: References Buffer. (line 7) -* y <1>: Editing Rebase Sequences. - (line 74) -* y c: References Buffer. (line 25) -* y o: References Buffer. (line 30) -* y r: References Buffer. (line 34) -* y y: References Buffer. (line 21) -* z: Stashing. (line 9) -* Z: Worktree. (line 9) -* z a: Stashing. (line 52) -* z b: Stashing. (line 105) -* z B: Stashing. (line 110) -* Z b: Worktree. (line 13) -* Z c: Worktree. (line 16) -* z f: Stashing. (line 115) -* Z g: Worktree. (line 26) -* z i: Stashing. (line 20) -* z I: Stashing. (line 42) -* z k: Stashing. (line 98) -* Z k: Worktree. (line 22) -* z l: Stashing. (line 121) -* Z m: Worktree. (line 19) -* z p: Stashing. (line 74) -* z v: Stashing. (line 102) -* z w: Stashing. (line 24) -* z W: Stashing. (line 46) -* z x: Stashing. (line 30) -* z z: Stashing. (line 14) -* z Z: Stashing. (line 36) - - -File: magit.info, Node: Function and Command Index, Next: Variable Index, Prev: Keystroke Index, Up: Top - -Appendix D Function and Command Index -************************************* - - -* Menu: - -* bug-reference-mode: Commit Mode and Hooks. - (line 48) -* forward-line: Editing Rebase Sequences. - (line 34) -* git-commit-ack: Commit Pseudo Headers. - (line 16) -* git-commit-cc: Commit Pseudo Headers. - (line 28) -* git-commit-check-style-conventions: Commit Message Conventions. - (line 33) -* git-commit-insert-pseudo-header: Commit Pseudo Headers. - (line 13) -* git-commit-next-message: Editing Commit Messages. - (line 41) -* git-commit-prev-message: Editing Commit Messages. - (line 36) -* git-commit-propertize-diff: Commit Mode and Hooks. - (line 40) -* git-commit-reported: Commit Pseudo Headers. - (line 31) -* git-commit-review: Commit Pseudo Headers. - (line 19) -* git-commit-save-message: Editing Commit Messages. - (line 33) -* git-commit-save-message <1>: Commit Mode and Hooks. - (line 26) -* git-commit-setup-changelog-support: Commit Mode and Hooks. - (line 29) -* git-commit-signoff: Commit Pseudo Headers. - (line 22) -* git-commit-suggested: Commit Pseudo Headers. - (line 35) -* git-commit-test: Commit Pseudo Headers. - (line 25) -* git-commit-turn-on-auto-fill: Commit Mode and Hooks. - (line 33) -* git-commit-turn-on-flyspell: Commit Mode and Hooks. - (line 36) -* git-rebase-backward-line: Editing Rebase Sequences. - (line 31) -* git-rebase-break: Editing Rebase Sequences. - (line 70) -* git-rebase-edit: Editing Rebase Sequences. - (line 46) -* git-rebase-exec: Editing Rebase Sequences. - (line 62) -* git-rebase-fixup: Editing Rebase Sequences. - (line 52) -* git-rebase-insert: Editing Rebase Sequences. - (line 74) -* git-rebase-kill-line: Editing Rebase Sequences. - (line 56) -* git-rebase-label: Editing Rebase Sequences. - (line 94) -* git-rebase-merge: Editing Rebase Sequences. - (line 102) -* git-rebase-merge-toggle-editmsg: Editing Rebase Sequences. - (line 108) -* git-rebase-move-line-down: Editing Rebase Sequences. - (line 40) -* git-rebase-move-line-up: Editing Rebase Sequences. - (line 37) -* git-rebase-pick: Editing Rebase Sequences. - (line 59) -* git-rebase-reset: Editing Rebase Sequences. - (line 97) -* git-rebase-reword: Editing Rebase Sequences. - (line 43) -* git-rebase-show-commit: Editing Rebase Sequences. - (line 15) -* git-rebase-show-or-scroll-down: Editing Rebase Sequences. - (line 25) -* git-rebase-show-or-scroll-up: Editing Rebase Sequences. - (line 19) -* git-rebase-squash: Editing Rebase Sequences. - (line 49) -* git-rebase-undo: Editing Rebase Sequences. - (line 77) -* ido-enter-magit-status: Status Buffer. (line 96) -* magit-add-section-hook: Section Hooks. (line 20) -* magit-after-save-refresh-status: Automatic Refreshing of Magit Buffers. - (line 55) -* magit-am: Maildir Patches. (line 9) -* magit-am-abort: Maildir Patches. (line 38) -* magit-am-apply-maildir: Maildir Patches. (line 20) -* magit-am-apply-patches: Maildir Patches. (line 14) -* magit-am-continue: Maildir Patches. (line 31) -* magit-am-skip: Maildir Patches. (line 34) -* magit-apply: Applying. (line 34) -* magit-bisect: Bisecting. (line 9) -* magit-bisect-bad: Bisecting. (line 32) -* magit-bisect-good: Bisecting. (line 36) -* magit-bisect-mark: Bisecting. (line 40) -* magit-bisect-reset: Bisecting. (line 51) -* magit-bisect-run: Bisecting. (line 26) -* magit-bisect-skip: Bisecting. (line 46) -* magit-bisect-start: Bisecting. (line 16) -* magit-blame: Blaming. (line 28) -* magit-blame <1>: Blaming. (line 34) -* magit-blame <2>: Blaming. (line 115) -* magit-blame <3>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame <4>: Commands for Buffers Visiting Files. - (line 137) -* magit-blame-addition: Blaming. (line 28) -* magit-blame-addition <1>: Blaming. (line 45) -* magit-blame-additions: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-copy-hash: Blaming. (line 134) -* magit-blame-cycle-style: Blaming. (line 141) -* magit-blame-echo: Blaming. (line 28) -* magit-blame-echo <1>: Blaming. (line 76) -* magit-blame-echo <2>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-next-chunk: Blaming. (line 118) -* magit-blame-next-chunk-same-commit: Blaming. (line 121) -* magit-blame-previous-chunk: Blaming. (line 124) -* magit-blame-previous-chunk-same-commit: Blaming. (line 127) -* magit-blame-quit: Blaming. (line 28) -* magit-blame-quit <1>: Blaming. (line 87) -* magit-blame-quit <2>: Blaming. (line 130) -* magit-blame-quit <3>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-removal: Blaming. (line 28) -* magit-blame-removal <1>: Blaming. (line 60) -* magit-blame-removal <2>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-reverse: Blaming. (line 28) -* magit-blame-reverse <1>: Blaming. (line 68) -* magit-blame-reverse <2>: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-next: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-next <1>: Commands for Buffers Visiting Files. - (line 153) -* magit-blob-next <2>: Minor Mode for Buffers Visiting Blobs. - (line 16) -* magit-blob-previous: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-previous <1>: Commands for Buffers Visiting Files. - (line 149) -* magit-blob-previous <2>: Minor Mode for Buffers Visiting Blobs. - (line 13) -* magit-blob-visit-file: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-visit-file <1>: Commands for Buffers Visiting Files. - (line 160) -* magit-branch: Branch Commands. (line 13) -* magit-branch-and-checkout: Branch Commands. (line 63) -* magit-branch-checkout: Branch Commands. (line 69) -* magit-branch-configure: Branch Commands. (line 31) -* magit-branch-create: Branch Commands. (line 54) -* magit-branch-delete: Branch Commands. (line 138) -* magit-branch-or-checkout: Branch Commands. (line 257) -* magit-branch-orphan: Branch Commands. (line 253) -* magit-branch-rename: Branch Commands. (line 149) -* magit-branch-reset: Branch Commands. (line 123) -* magit-branch-shelve: Auxiliary Branch Commands. - (line 9) -* magit-branch-spinoff: Branch Commands. (line 91) -* magit-branch-spinout: Branch Commands. (line 118) -* magit-branch-unshelve: Auxiliary Branch Commands. - (line 19) -* magit-builtin-completing-read: Support for Completion Frameworks. - (line 41) -* magit-bundle: Bundle. (line 8) -* magit-call-git: Calling Git for Effect. - (line 28) -* magit-call-process: Calling Git for Effect. - (line 31) -* magit-cancel-section: Creating Sections. (line 69) -* magit-checkout: Branch Commands. (line 47) -* magit-cherry: Cherries. (line 18) -* magit-cherry-apply: Cherry Picking. (line 23) -* magit-cherry-copy: Cherry Picking. (line 17) -* magit-cherry-donate: Cherry Picking. (line 51) -* magit-cherry-harvest: Cherry Picking. (line 40) -* magit-cherry-pick: Cherry Picking. (line 9) -* magit-cherry-spinoff: Cherry Picking. (line 72) -* magit-cherry-spinout: Cherry Picking. (line 62) -* magit-clone: Cloning Repository. (line 20) -* magit-clone-bare: Cloning Repository. (line 44) -* magit-clone-mirror: Cloning Repository. (line 48) -* magit-clone-regular: Cloning Repository. (line 28) -* magit-clone-shallow: Cloning Repository. (line 32) -* magit-clone-shallow-exclude: Cloning Repository. (line 61) -* magit-clone-shallow-since: Cloning Repository. (line 55) -* magit-clone-sparse: Cloning Repository. (line 38) -* magit-commit: Initiating a Commit. (line 9) -* magit-commit <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-commit <2>: Commands for Buffers Visiting Files. - (line 176) -* magit-commit-amend: Initiating a Commit. (line 18) -* magit-commit-augment: Initiating a Commit. (line 59) -* magit-commit-create: Initiating a Commit. (line 14) -* magit-commit-extend: Initiating a Commit. (line 21) -* magit-commit-fixup: Initiating a Commit. (line 39) -* magit-commit-instant-fixup: Initiating a Commit. (line 46) -* magit-commit-instant-squash: Initiating a Commit. (line 56) -* magit-commit-reword: Initiating a Commit. (line 30) -* magit-commit-squash: Initiating a Commit. (line 49) -* magit-completing-read: Support for Completion Frameworks. - (line 57) -* magit-copy-buffer-revision: Common Commands. (line 39) -* magit-copy-section-value: Common Commands. (line 22) -* magit-current-section: Section Selection. (line 6) -* magit-cycle-margin-style: Log Margin. (line 63) -* magit-debug-git-executable: Git Executable. (line 55) -* magit-debug-git-executable <1>: Debugging Tools. (line 57) -* magit-define-section-jumper: Creating Sections. (line 74) -* magit-describe-section: Section Types and Values. - (line 14) -* magit-describe-section-briefly: Section Types and Values. - (line 17) -* magit-describe-section-briefly <1>: Matching Sections. (line 7) -* magit-diff: Diffing. (line 22) -* magit-diff <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-diff <2>: Commands for Buffers Visiting Files. - (line 91) -* magit-diff-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-diff-buffer-file <1>: Commands for Buffers Visiting Files. - (line 101) -* magit-diff-default-context: Refreshing Diffs. (line 68) -* magit-diff-dwim: Diffing. (line 27) -* magit-diff-edit-hunk-commit: Commands Available in Diffs. - (line 24) -* magit-diff-flip-revs: Refreshing Diffs. (line 45) -* magit-diff-less-context: Refreshing Diffs. (line 62) -* magit-diff-more-context: Refreshing Diffs. (line 65) -* magit-diff-paths: Diffing. (line 56) -* magit-diff-range: Diffing. (line 30) -* magit-diff-refresh: Refreshing Diffs. (line 16) -* magit-diff-refresh <1>: Refreshing Diffs. (line 21) -* magit-diff-save-default-arguments: Refreshing Diffs. (line 31) -* magit-diff-scope: Matching Sections. (line 110) -* magit-diff-set-default-arguments: Refreshing Diffs. (line 25) -* magit-diff-show-or-scroll-down: Log Buffer. (line 50) -* magit-diff-show-or-scroll-down <1>: Blaming. (line 103) -* magit-diff-show-or-scroll-up: Log Buffer. (line 41) -* magit-diff-show-or-scroll-up <1>: Blaming. (line 94) -* magit-diff-staged: Diffing. (line 48) -* magit-diff-switch-range-type: Refreshing Diffs. (line 41) -* magit-diff-toggle-file-filter: Refreshing Diffs. (line 49) -* magit-diff-toggle-refine-hunk: Refreshing Diffs. (line 38) -* magit-diff-trace-definition: Commands Available in Diffs. - (line 15) -* magit-diff-type: Matching Sections. (line 88) -* magit-diff-unstaged: Diffing. (line 53) -* magit-diff-visit-file: Visiting Files and Blobs from a Diff. - (line 9) -* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff. - (line 71) -* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff. - (line 70) -* magit-diff-visit-file-worktree: Visiting Files and Blobs from a Diff. - (line 50) -* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff. - (line 73) -* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff. - (line 72) -* magit-diff-while-committing: Refreshing Diffs. (line 75) -* magit-diff-while-committing <1>: Editing Commit Messages. - (line 54) -* magit-diff-working-tree: Diffing. (line 43) -* magit-disable-section-inserter: Per-Repository Configuration. - (line 31) -* magit-discard: Applying. (line 40) -* magit-dispatch: Transient Commands. (line 20) -* magit-display-buffer: Switching Buffers. (line 6) -* magit-display-buffer-fullcolumn-most-v1: Switching Buffers. (line 68) -* magit-display-buffer-fullframe-status-topleft-v1: Switching Buffers. - (line 59) -* magit-display-buffer-fullframe-status-v1: Switching Buffers. - (line 54) -* magit-display-buffer-same-window-except-diff-v1: Switching Buffers. - (line 49) -* magit-display-buffer-traditional: Switching Buffers. (line 42) -* magit-display-repository-buffer: Common Commands. (line 9) -* magit-display-repository-buffer <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-display-repository-buffer <2>: Commands for Buffers Visiting Files. - (line 172) -* magit-ediff: Ediffing. (line 21) -* magit-ediff-compare: Ediffing. (line 25) -* magit-ediff-dwim: Ediffing. (line 10) -* magit-ediff-resolve-all: Ediffing. (line 48) -* magit-ediff-resolve-rest: Ediffing. (line 33) -* magit-ediff-show-commit: Ediffing. (line 100) -* magit-ediff-show-staged: Ediffing. (line 94) -* magit-ediff-show-stash: Ediffing. (line 103) -* magit-ediff-show-unstaged: Ediffing. (line 91) -* magit-ediff-show-working-tree: Ediffing. (line 97) -* magit-ediff-stage: Ediffing. (line 87) -* magit-edit-line-commit: Commands for Buffers Visiting Files. - (line 52) -* magit-edit-line-commit <1>: Commands for Buffers Visiting Files. - (line 182) -* magit-emacs-Q-command: Debugging Tools. (line 16) -* magit-fetch: Fetching. (line 10) -* magit-fetch-all: Fetching. (line 45) -* magit-fetch-branch: Fetching. (line 37) -* magit-fetch-from-pushremote: Fetching. (line 15) -* magit-fetch-from-upstream: Fetching. (line 22) -* magit-fetch-modules: Fetching. (line 48) -* magit-fetch-modules <1>: Submodule Transient. (line 51) -* magit-fetch-other: Fetching. (line 34) -* magit-fetch-refspec: Fetching. (line 41) -* magit-file-checkout: Resetting. (line 44) -* magit-file-checkout <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-file-checkout <2>: Commands for Buffers Visiting Files. - (line 86) -* magit-file-delete: Commands for Buffers Visiting Files. - (line 52) -* magit-file-delete <1>: Commands for Buffers Visiting Files. - (line 82) -* magit-file-dispatch: Commands for Buffers Visiting Files. - (line 52) -* magit-file-dispatch <1>: Commands for Buffers Visiting Files. - (line 58) -* magit-file-rename: Commands for Buffers Visiting Files. - (line 52) -* magit-file-rename <1>: Commands for Buffers Visiting Files. - (line 78) -* magit-file-untrack: Commands for Buffers Visiting Files. - (line 52) -* magit-file-untrack <1>: Commands for Buffers Visiting Files. - (line 74) -* magit-find-file: General-Purpose Visit Commands. - (line 9) -* magit-find-file <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-find-file <2>: Commands for Buffers Visiting Files. - (line 156) -* magit-find-file-other-frame: General-Purpose Visit Commands. - (line 19) -* magit-find-file-other-window: General-Purpose Visit Commands. - (line 14) -* magit-generate-buffer-name-default-function: Naming Buffers. - (line 16) -* magit-get-section: Matching Sections. (line 14) -* magit-git: Calling Git for Effect. - (line 46) -* magit-git-command: Running Git Manually. - (line 25) -* magit-git-command-topdir: Running Git Manually. - (line 17) -* magit-git-exit-code: Getting a Value from Git. - (line 10) -* magit-git-failure: Getting a Value from Git. - (line 17) -* magit-git-false: Getting a Value from Git. - (line 25) -* magit-git-insert: Getting a Value from Git. - (line 29) -* magit-git-items: Getting a Value from Git. - (line 41) -* magit-git-lines: Getting a Value from Git. - (line 37) -* magit-git-mergetool: Running Git Manually. - (line 62) -* magit-git-mergetool <1>: Ediffing. (line 79) -* magit-git-str: Getting a Value from Git. - (line 75) -* magit-git-string: Getting a Value from Git. - (line 32) -* magit-git-success: Getting a Value from Git. - (line 13) -* magit-git-true: Getting a Value from Git. - (line 21) -* magit-git-wash: Calling Git for Effect. - (line 50) -* magit-go-backward: Log Buffer. (line 20) -* magit-go-backward <1>: Refreshing Diffs. (line 84) -* magit-go-forward: Log Buffer. (line 23) -* magit-go-forward <1>: Refreshing Diffs. (line 87) -* magit-hunk-set-window-start: Section Movement. (line 45) -* magit-ido-completing-read: Support for Completion Frameworks. - (line 46) -* magit-init: Creating Repository. (line 7) -* magit-insert-am-sequence: Status Sections. (line 25) -* magit-insert-assumed-unchanged-files: Status Sections. (line 98) -* magit-insert-bisect-log: Status Sections. (line 39) -* magit-insert-bisect-output: Status Sections. (line 33) -* magit-insert-bisect-rest: Status Sections. (line 36) -* magit-insert-diff-filter-header: Status Header Sections. - (line 35) -* magit-insert-error-header: Status Header Sections. - (line 26) -* magit-insert-head-branch-header: Status Header Sections. - (line 38) -* magit-insert-heading: Creating Sections. (line 41) -* magit-insert-ignored-files: Status Sections. (line 83) -* magit-insert-local-branches: References Sections. (line 16) -* magit-insert-merge-log: Status Sections. (line 17) -* magit-insert-modules: Status Module Sections. - (line 12) -* magit-insert-modules-overview: Status Module Sections. - (line 30) -* magit-insert-modules-unpulled-from-pushremote: Status Module Sections. - (line 45) -* magit-insert-modules-unpulled-from-upstream: Status Module Sections. - (line 40) -* magit-insert-modules-unpushed-to-pushremote: Status Module Sections. - (line 55) -* magit-insert-modules-unpushed-to-upstream: Status Module Sections. - (line 50) -* magit-insert-push-branch-header: Status Header Sections. - (line 45) -* magit-insert-rebase-sequence: Status Sections. (line 21) -* magit-insert-recent-commits: Status Sections. (line 110) -* magit-insert-remote-branches: References Sections. (line 19) -* magit-insert-remote-header: Status Header Sections. - (line 58) -* magit-insert-repo-header: Status Header Sections. - (line 55) -* magit-insert-section: Creating Sections. (line 6) -* magit-insert-sequencer-sequence: Status Sections. (line 29) -* magit-insert-skip-worktree-files: Status Sections. (line 92) -* magit-insert-staged-changes: Status Sections. (line 53) -* magit-insert-stashes: Status Sections. (line 56) -* magit-insert-status-headers: Status Header Sections. - (line 12) -* magit-insert-tags: References Sections. (line 22) -* magit-insert-tags-header: Status Header Sections. - (line 49) -* magit-insert-tracked-files: Status Sections. (line 80) -* magit-insert-unpulled-cherries: Status Sections. (line 119) -* magit-insert-unpulled-from-pushremote: Status Sections. (line 66) -* magit-insert-unpulled-from-upstream: Status Sections. (line 62) -* magit-insert-unpulled-or-recent-commits: Status Sections. (line 104) -* magit-insert-unpushed-cherries: Status Sections. (line 125) -* magit-insert-unpushed-to-pushremote: Status Sections. (line 74) -* magit-insert-unpushed-to-upstream: Status Sections. (line 70) -* magit-insert-unstaged-changes: Status Sections. (line 50) -* magit-insert-untracked-files: Status Sections. (line 42) -* magit-insert-upstream-branch-header: Status Header Sections. - (line 41) -* magit-insert-user-header: Status Header Sections. - (line 65) -* magit-jump-to-diffstat-or-diff: Commands Available in Diffs. - (line 43) -* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs. - (line 19) -* magit-list-repositories: Repository List. (line 6) -* magit-list-submodules: Listing Submodules. (line 13) -* magit-list-submodules <1>: Submodule Transient. (line 48) -* magit-log: Logging. (line 28) -* magit-log <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-log <2>: Commands for Buffers Visiting Files. - (line 109) -* magit-log-all: Logging. (line 59) -* magit-log-all-branches: Logging. (line 56) -* magit-log-branches: Logging. (line 53) -* magit-log-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-log-buffer-file <1>: Commands for Buffers Visiting Files. - (line 119) -* magit-log-bury-buffer: Log Buffer. (line 14) -* magit-log-current: Logging. (line 33) -* magit-log-double-commit-limit: Log Buffer. (line 64) -* magit-log-half-commit-limit: Log Buffer. (line 67) -* magit-log-head: Logging. (line 38) -* magit-log-maybe-show-more-commits: Section Movement. (line 58) -* magit-log-maybe-update-blob-buffer: Section Movement. (line 72) -* magit-log-maybe-update-revision-buffer: Section Movement. (line 65) -* magit-log-merged: Commands for Buffers Visiting Files. - (line 52) -* magit-log-merged <1>: Commands for Buffers Visiting Files. - (line 132) -* magit-log-move-to-parent: Log Buffer. (line 26) -* magit-log-move-to-revision: Log Buffer. (line 31) -* magit-log-other: Logging. (line 47) -* magit-log-refresh: Refreshing Logs. (line 12) -* magit-log-refresh <1>: Refreshing Logs. (line 17) -* magit-log-refresh <2>: Log Buffer. (line 7) -* magit-log-related: Logging. (line 41) -* magit-log-save-default-arguments: Refreshing Logs. (line 27) -* magit-log-select-pick: Select from Log. (line 21) -* magit-log-select-quit: Select from Log. (line 26) -* magit-log-set-default-arguments: Refreshing Logs. (line 21) -* magit-log-toggle-commit-limit: Log Buffer. (line 59) -* magit-log-trace-definition: Commands for Buffers Visiting Files. - (line 52) -* magit-log-trace-definition <1>: Commands for Buffers Visiting Files. - (line 129) -* magit-margin-settings: Log Margin. (line 52) -* magit-maybe-set-dedicated: Switching Buffers. (line 89) -* magit-merge: Merging. (line 10) -* magit-merge <1>: Merging. (line 86) -* magit-merge-abort: Merging. (line 91) -* magit-merge-absorb: Merging. (line 42) -* magit-merge-editmsg: Merging. (line 30) -* magit-merge-into: Merging. (line 54) -* magit-merge-nocommit: Merging. (line 36) -* magit-merge-plain: Merging. (line 18) -* magit-merge-preview: Merging. (line 75) -* magit-merge-squash: Merging. (line 67) -* magit-mode-bury-buffer: Quitting Windows. (line 7) -* magit-mode-display-buffer: Refreshing Buffers. (line 32) -* magit-mode-quit-window: Quitting Windows. (line 34) -* magit-mode-setup: Refreshing Buffers. (line 17) -* magit-notes: Notes. (line 9) -* magit-notes-edit: Notes. (line 14) -* magit-notes-merge: Notes. (line 35) -* magit-notes-merge-abort: Notes. (line 47) -* magit-notes-merge-commit: Notes. (line 43) -* magit-notes-prune: Notes. (line 28) -* magit-notes-remove: Notes. (line 21) -* magit-patch: Plain Patches. (line 7) -* magit-patch-apply: Plain Patches. (line 20) -* magit-patch-apply <1>: Maildir Patches. (line 23) -* magit-patch-create: Plain Patches. (line 12) -* magit-patch-save: Plain Patches. (line 26) -* magit-pop-revision-stack: Using the Revision Stack. - (line 7) -* magit-process: Viewing Git Output. (line 17) -* magit-process-file: Getting a Value from Git. - (line 57) -* magit-process-git: Getting a Value from Git. - (line 50) -* magit-process-kill: Viewing Git Output. (line 24) -* magit-pull: Pulling. (line 10) -* magit-pull-branch: Pulling. (line 28) -* magit-pull-from-pushremote: Pulling. (line 14) -* magit-pull-from-upstream: Pulling. (line 21) -* magit-push: Pushing. (line 10) -* magit-push-current: Pushing. (line 29) -* magit-push-current-to-pushremote: Pushing. (line 15) -* magit-push-current-to-upstream: Pushing. (line 22) -* magit-push-implicitly: Pushing. (line 74) -* magit-push-matching: Pushing. (line 45) -* magit-push-other: Pushing. (line 33) -* magit-push-refspecs: Pushing. (line 37) -* magit-push-tag: Pushing. (line 59) -* magit-push-tags: Pushing. (line 52) -* magit-push-to-remote: Pushing. (line 91) -* magit-rebase: Rebasing. (line 10) -* magit-rebase-abort: Rebasing. (line 111) -* magit-rebase-autosquash: Rebasing. (line 79) -* magit-rebase-branch: Rebasing. (line 42) -* magit-rebase-continue: Rebasing. (line 97) -* magit-rebase-edit: Rebasing. (line 107) -* magit-rebase-edit-commit: Rebasing. (line 83) -* magit-rebase-interactive: Rebasing. (line 76) -* magit-rebase-onto-pushremote: Rebasing. (line 28) -* magit-rebase-onto-upstream: Rebasing. (line 35) -* magit-rebase-remove-commit: Rebasing. (line 91) -* magit-rebase-reword-commit: Rebasing. (line 87) -* magit-rebase-skip: Rebasing. (line 103) -* magit-rebase-subset: Rebasing. (line 47) -* magit-reflog-current: Reflog. (line 12) -* magit-reflog-head: Reflog. (line 18) -* magit-reflog-other: Reflog. (line 15) -* magit-refresh: Automatic Refreshing of Magit Buffers. - (line 26) -* magit-refresh-all: Automatic Refreshing of Magit Buffers. - (line 34) -* magit-refs-set-show-commit-count: References Buffer. (line 34) -* magit-region-sections: Section Selection. (line 9) -* magit-region-values: Section Selection. (line 35) -* magit-remote: Remote Commands. (line 14) -* magit-remote-add: Remote Commands. (line 48) -* magit-remote-configure: Remote Commands. (line 32) -* magit-remote-prune: Remote Commands. (line 63) -* magit-remote-prune-refspecs: Remote Commands. (line 67) -* magit-remote-remove: Remote Commands. (line 60) -* magit-remote-rename: Remote Commands. (line 52) -* magit-remote-set-url: Remote Commands. (line 56) -* magit-repolist-column-branch: Repository List. (line 51) -* magit-repolist-column-branches: Repository List. (line 58) -* magit-repolist-column-flag: Repository List. (line 64) -* magit-repolist-column-flags: Repository List. (line 76) -* magit-repolist-column-ident: Repository List. (line 40) -* magit-repolist-column-path: Repository List. (line 44) -* magit-repolist-column-stashes: Repository List. (line 61) -* magit-repolist-column-unpulled-from-pushremote: Repository List. - (line 87) -* magit-repolist-column-unpulled-from-upstream: Repository List. - (line 83) -* magit-repolist-column-unpushed-to-pushremote: Repository List. - (line 95) -* magit-repolist-column-unpushed-to-upstream: Repository List. - (line 91) -* magit-repolist-column-upstream: Repository List. (line 54) -* magit-repolist-column-version: Repository List. (line 47) -* magit-repolist-fetch: Repository List. (line 111) -* magit-repolist-find-file-other-frame: Repository List. (line 115) -* magit-repolist-mark: Repository List. (line 105) -* magit-repolist-status: Repository List. (line 102) -* magit-repolist-unmark: Repository List. (line 108) -* magit-reset-hard: Resetting. (line 24) -* magit-reset-index: Staging and Unstaging. - (line 78) -* magit-reset-index <1>: Resetting. (line 33) -* magit-reset-keep: Resetting. (line 28) -* magit-reset-mixed: Resetting. (line 15) -* magit-reset-quickly: Resetting. (line 9) -* magit-reset-soft: Resetting. (line 19) -* magit-reset-worktree: Resetting. (line 39) -* magit-reset-worktree <1>: Wip Modes. (line 64) -* magit-restore-window-configuration: Quitting Windows. (line 24) -* magit-reverse: Applying. (line 47) -* magit-reverse-in-index: Staging and Unstaging. - (line 58) -* magit-revert: Reverting. (line 7) -* magit-revert-and-commit: Reverting. (line 15) -* magit-revert-no-commit: Reverting. (line 20) -* magit-run: Running Git Manually. - (line 13) -* magit-run-git: Calling Git for Effect. - (line 34) -* magit-run-git-async: Calling Git for Effect. - (line 59) -* magit-run-git-gui: Running Git Manually. - (line 59) -* magit-run-git-with-editor: Calling Git for Effect. - (line 71) -* magit-run-git-with-input: Calling Git for Effect. - (line 37) -* magit-run-gitk: Running Git Manually. - (line 50) -* magit-run-gitk-all: Running Git Manually. - (line 53) -* magit-run-gitk-branches: Running Git Manually. - (line 56) -* magit-save-window-configuration: Switching Buffers. (line 80) -* magit-section-backward: Section Movement. (line 11) -* magit-section-backward-siblings: Section Movement. (line 19) -* magit-section-case: Matching Sections. (line 66) -* magit-section-cycle: Section Visibility. (line 14) -* magit-section-cycle-diffs: Section Visibility. (line 29) -* magit-section-cycle-global: Section Visibility. (line 33) -* magit-section-forward: Section Movement. (line 16) -* magit-section-forward-siblings: Section Movement. (line 24) -* magit-section-hide: Section Visibility. (line 55) -* magit-section-hide-children: Section Visibility. (line 67) -* magit-section-ident: Matching Sections. (line 10) -* magit-section-match: Matching Sections. (line 18) -* magit-section-set-window-start: Section Movement. (line 52) -* magit-section-show: Section Visibility. (line 52) -* magit-section-show-children: Section Visibility. (line 62) -* magit-section-show-headings: Section Visibility. (line 58) -* magit-section-show-level-1: Section Visibility. (line 39) -* magit-section-show-level-1-all: Section Visibility. (line 45) -* magit-section-show-level-2: Section Visibility. (line 39) -* magit-section-show-level-2-all: Section Visibility. (line 45) -* magit-section-show-level-3: Section Visibility. (line 39) -* magit-section-show-level-3-all: Section Visibility. (line 45) -* magit-section-show-level-4: Section Visibility. (line 39) -* magit-section-show-level-4-all: Section Visibility. (line 45) -* magit-section-toggle: Section Visibility. (line 10) -* magit-section-toggle-children: Section Visibility. (line 70) -* magit-section-up: Section Movement. (line 28) -* magit-section-value-if: Matching Sections. (line 57) -* magit-sequence-abort: Cherry Picking. (line 91) -* magit-sequence-abort <1>: Reverting. (line 35) -* magit-sequence-continue: Cherry Picking. (line 85) -* magit-sequence-continue <1>: Reverting. (line 29) -* magit-sequence-skip: Cherry Picking. (line 88) -* magit-sequence-skip <1>: Reverting. (line 32) -* magit-shell-command: Running Git Manually. - (line 38) -* magit-shell-command-topdir: Running Git Manually. - (line 34) -* magit-show-commit: Diffing. (line 63) -* magit-show-commit <1>: Blaming. (line 91) -* magit-show-refs: References Buffer. (line 7) -* magit-show-refs-current: References Buffer. (line 25) -* magit-show-refs-head: References Buffer. (line 21) -* magit-show-refs-other: References Buffer. (line 30) -* magit-snapshot-both: Stashing. (line 36) -* magit-snapshot-index: Stashing. (line 42) -* magit-snapshot-worktree: Stashing. (line 46) -* magit-sparse-checkout: Sparse checkouts. (line 17) -* magit-sparse-checkout-add: Sparse checkouts. (line 39) -* magit-sparse-checkout-disable: Sparse checkouts. (line 50) -* magit-sparse-checkout-enable: Sparse checkouts. (line 21) -* magit-sparse-checkout-reapply: Sparse checkouts. (line 44) -* magit-sparse-checkout-set: Sparse checkouts. (line 33) -* magit-stage: Staging and Unstaging. - (line 29) -* magit-stage-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-stage-buffer-file <1>: Commands for Buffers Visiting Files. - (line 63) -* magit-stage-file: Staging from File-Visiting Buffers. - (line 11) -* magit-stage-file <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-stage-file <2>: Commands for Buffers Visiting Files. - (line 63) -* magit-stage-modified: Staging and Unstaging. - (line 36) -* magit-start-git: Calling Git for Effect. - (line 82) -* magit-start-process: Calling Git for Effect. - (line 100) -* magit-stash: Stashing. (line 9) -* magit-stash-apply: Stashing. (line 52) -* magit-stash-both: Stashing. (line 14) -* magit-stash-branch: Stashing. (line 105) -* magit-stash-branch-here: Stashing. (line 110) -* magit-stash-clear: Stashing. (line 118) -* magit-stash-drop: Stashing. (line 98) -* magit-stash-format-patch: Stashing. (line 115) -* magit-stash-index: Stashing. (line 20) -* magit-stash-keep-index: Stashing. (line 30) -* magit-stash-list: Stashing. (line 121) -* magit-stash-pop: Stashing. (line 74) -* magit-stash-show: Diffing. (line 67) -* magit-stash-show <1>: Stashing. (line 102) -* magit-stash-worktree: Stashing. (line 24) -* magit-stashes-maybe-update-stash-buffer: Section Movement. (line 92) -* magit-status: Status Buffer. (line 23) -* magit-status-here: Commands for Buffers Visiting Files. - (line 52) -* magit-status-here <1>: Commands for Buffers Visiting Files. - (line 166) -* magit-status-maybe-update-blob-buffer: Section Movement. (line 87) -* magit-status-maybe-update-revision-buffer: Section Movement. - (line 77) -* magit-status-maybe-update-stash-buffer: Section Movement. (line 82) -* magit-status-quick: Status Buffer. (line 70) -* magit-submodule: Submodule Transient. (line 7) -* magit-submodule-add: Submodule Transient. (line 20) -* magit-submodule-populate: Submodule Transient. (line 32) -* magit-submodule-register: Submodule Transient. (line 26) -* magit-submodule-synchronize: Submodule Transient. (line 40) -* magit-submodule-unpopulate: Submodule Transient. (line 45) -* magit-submodule-update: Submodule Transient. (line 36) -* magit-subtree: Subtree. (line 9) -* magit-subtree-add: Subtree. (line 24) -* magit-subtree-add-commit: Subtree. (line 28) -* magit-subtree-export: Subtree. (line 37) -* magit-subtree-import: Subtree. (line 13) -* magit-subtree-merge: Subtree. (line 31) -* magit-subtree-pull: Subtree. (line 34) -* magit-subtree-push: Subtree. (line 48) -* magit-subtree-split: Subtree. (line 52) -* magit-switch-to-repository-buffer: Common Commands. (line 6) -* magit-switch-to-repository-buffer-other-frame: Common Commands. - (line 8) -* magit-switch-to-repository-buffer-other-window: Common Commands. - (line 7) -* magit-tag: Tagging. (line 9) -* magit-tag-create: Tagging. (line 14) -* magit-tag-delete: Tagging. (line 37) -* magit-tag-prune: Tagging. (line 43) -* magit-tag-release: Tagging. (line 18) -* magit-toggle-buffer-lock: Modes and Buffers. (line 18) -* magit-toggle-git-debug: Debugging Tools. (line 29) -* magit-toggle-margin: Refreshing Logs. (line 34) -* magit-toggle-margin <1>: Log Margin. (line 60) -* magit-toggle-margin-details: Log Margin. (line 66) -* magit-toggle-verbose-refresh: Debugging Tools. (line 52) -* magit-unstage: Staging and Unstaging. - (line 42) -* magit-unstage-all: Staging and Unstaging. - (line 50) -* magit-unstage-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-unstage-buffer-file <1>: Commands for Buffers Visiting Files. - (line 69) -* magit-unstage-file: Staging from File-Visiting Buffers. - (line 18) -* magit-unstage-file <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-unstage-file <2>: Commands for Buffers Visiting Files. - (line 69) -* magit-version: Git Executable. (line 59) -* magit-version <1>: Debugging Tools. (line 11) -* magit-visit-ref: References Buffer. (line 159) -* magit-wip-commit: Wip Modes. (line 85) -* magit-wip-log: Wip Modes. (line 47) -* magit-wip-log-current: Wip Modes. (line 55) -* magit-worktree: Worktree. (line 9) -* magit-worktree-branch: Worktree. (line 16) -* magit-worktree-checkout: Worktree. (line 13) -* magit-worktree-delete: Worktree. (line 22) -* magit-worktree-move: Worktree. (line 19) -* magit-worktree-status: Worktree. (line 26) -* scroll-down: Commands Available in Diffs. - (line 56) -* scroll-up: Commands Available in Diffs. - (line 53) -* with-editor-cancel: Editing Commit Messages. - (line 22) -* with-editor-cancel <1>: Editing Rebase Sequences. - (line 11) -* with-editor-debug: Debugging Tools. (line 64) -* with-editor-finish: Editing Commit Messages. - (line 18) -* with-editor-finish <1>: Editing Rebase Sequences. - (line 7) -* with-editor-usage-message: Commit Mode and Hooks. - (line 51) - - -File: magit.info, Node: Variable Index, Prev: Function and Command Index, Up: Top - -Appendix E Variable Index -************************* - - -* Menu: - -* auto-revert-buffer-list-filter: Automatic Reverting of File-Visiting Buffers. - (line 73) -* auto-revert-interval: Automatic Reverting of File-Visiting Buffers. - (line 69) -* auto-revert-mode: Automatic Reverting of File-Visiting Buffers. - (line 57) -* auto-revert-stop-on-user-input: Automatic Reverting of File-Visiting Buffers. - (line 65) -* auto-revert-use-notify: Automatic Reverting of File-Visiting Buffers. - (line 46) -* auto-revert-verbose: Automatic Reverting of File-Visiting Buffers. - (line 94) -* branch.autoSetupMerge: Branch Git Variables. - (line 71) -* branch.autoSetupRebase: Branch Git Variables. - (line 85) -* branch.NAME.description: Branch Git Variables. - (line 42) -* branch.NAME.merge: Branch Git Variables. - (line 10) -* branch.NAME.pushRemote: Branch Git Variables. - (line 29) -* branch.NAME.rebase: Branch Git Variables. - (line 20) -* branch.NAME.remote: Branch Git Variables. - (line 15) -* core.notesRef: Notes. (line 53) -* git-commit-finish-query-functions: Commit Message Conventions. - (line 18) -* git-commit-known-pseudo-headers: Commit Pseudo Headers. - (line 9) -* git-commit-major-mode: Commit Mode and Hooks. - (line 12) -* git-commit-post-finish-hook: Commit Mode and Hooks. - (line 54) -* git-commit-setup-hook: Commit Mode and Hooks. - (line 21) -* git-commit-style-convention-checks: Commit Message Conventions. - (line 38) -* git-commit-summary-max-length: Commit Message Conventions. - (line 13) -* git-rebase-auto-advance: Editing Rebase Sequences. - (line 80) -* git-rebase-confirm-cancel: Editing Rebase Sequences. - (line 86) -* git-rebase-show-instructions: Editing Rebase Sequences. - (line 83) -* global-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. - (line 21) -* magit-auto-revert-immediately: Automatic Reverting of File-Visiting Buffers. - (line 30) -* magit-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. - (line 17) -* magit-auto-revert-tracked-only: Automatic Reverting of File-Visiting Buffers. - (line 51) -* magit-bisect-show-graph: Bisecting. (line 57) -* magit-blame-disable-modes: Blaming. (line 165) -* magit-blame-echo-style: Blaming. (line 151) -* magit-blame-goto-chunk-hook: Blaming. (line 170) -* magit-blame-read-only: Blaming. (line 161) -* magit-blame-styles: Blaming. (line 147) -* magit-blame-time-format: Blaming. (line 157) -* magit-branch-adjust-remote-upstream-alist: Branch Commands. (line 202) -* magit-branch-direct-configure: Branch Commands. (line 19) -* magit-branch-prefer-remote-upstream: Branch Commands. (line 158) -* magit-branch-read-upstream-first: Branch Commands. (line 153) -* magit-buffer-name-format: Naming Buffers. (line 25) -* magit-bury-buffer-function: Quitting Windows. (line 16) -* magit-cherry-margin: Cherries. (line 21) -* magit-clone-always-transient: Cloning Repository. (line 12) -* magit-clone-default-directory: Cloning Repository. (line 84) -* magit-clone-name-alist: Cloning Repository. (line 94) -* magit-clone-set-remote-head: Cloning Repository. (line 66) -* magit-clone-set-remote.pushDefault: Cloning Repository. (line 75) -* magit-clone-url-format: Cloning Repository. (line 114) -* magit-commit-ask-to-stage: Initiating a Commit. (line 65) -* magit-commit-diff-inhibit-same-window: Initiating a Commit. (line 97) -* magit-commit-extend-override-date: Initiating a Commit. (line 72) -* magit-commit-reword-override-date: Initiating a Commit. (line 75) -* magit-commit-show-diff: Initiating a Commit. (line 69) -* magit-commit-squash-confirm: Initiating a Commit. (line 78) -* magit-completing-read-function: Support for Completion Frameworks. - (line 27) -* magit-define-global-key-bindings: Global Bindings. (line 6) -* magit-diff-adjust-tab-width: Diff Options. (line 17) -* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files. - (line 104) -* magit-diff-extra-stat-arguments: Diff Options. (line 112) -* magit-diff-hide-trailing-cr-characters: Diff Options. (line 77) -* magit-diff-highlight-hunk-region-functions: Diff Options. (line 80) -* magit-diff-highlight-indentation: Diff Options. (line 63) -* magit-diff-highlight-trailing: Diff Options. (line 59) -* magit-diff-paint-whitespace: Diff Options. (line 38) -* magit-diff-paint-whitespace-lines: Diff Options. (line 52) -* magit-diff-refine-hunk: Diff Options. (line 6) -* magit-diff-refine-ignore-whitespace: Diff Options. (line 13) -* magit-diff-unmarked-lines-keep-foreground: Diff Options. (line 105) -* magit-diff-visit-previous-blob: Visiting Files and Blobs from a Diff. - (line 38) -* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables. - (line 73) -* magit-display-buffer-function: Switching Buffers. (line 25) -* magit-display-buffer-noselect: Switching Buffers. (line 17) -* magit-dwim-selection: Completion and Confirmation. - (line 42) -* magit-ediff-dwim-resolve-function: Ediffing. (line 105) -* magit-ediff-dwim-show-on-hunks: Ediffing. (line 111) -* magit-ediff-quit-hook: Ediffing. (line 124) -* magit-ediff-show-stash-with-index: Ediffing. (line 118) -* magit-generate-buffer-name-function: Naming Buffers. (line 6) -* magit-git-debug: Viewing Git Output. (line 26) -* magit-git-debug <1>: Getting a Value from Git. - (line 68) -* magit-git-executable: Git Executable. (line 26) -* magit-git-global-arguments: Global Git Arguments. - (line 6) -* magit-keep-region-overlay: The Selection. (line 52) -* magit-list-refs-sortby: Additional Completion Options. - (line 6) -* magit-log-auto-more: Log Buffer. (line 69) -* magit-log-buffer-file-locked: Commands for Buffers Visiting Files. - (line 124) -* magit-log-margin: Log Margin. (line 12) -* magit-log-margin-show-committer-date: Log Margin. (line 44) -* magit-log-section-commit-count: Status Sections. (line 114) -* magit-log-select-margin: Select from Log. (line 28) -* magit-log-show-color-graph-limit: Log Buffer. (line 78) -* magit-log-show-refname-after-summary: Log Buffer. (line 74) -* magit-log-show-signatures-limit: Log Buffer. (line 84) -* magit-log-trace-definition-function: Commands Available in Diffs. - (line 17) -* magit-module-sections-hook: Status Module Sections. - (line 19) -* magit-module-sections-nested: Status Module Sections. - (line 22) -* magit-no-confirm: Action Confirmation. (line 18) -* magit-pop-revision-stack-format: Using the Revision Stack. - (line 34) -* magit-post-clone-hook: Cloning Repository. (line 133) -* magit-post-commit-hook: Initiating a Commit. (line 86) -* magit-post-display-buffer-hook: Switching Buffers. (line 85) -* magit-pre-display-buffer-hook: Switching Buffers. (line 76) -* magit-prefer-remote-upstream: Branch Git Variables. - (line 108) -* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables. - (line 65) -* magit-process-extreme-logging: Viewing Git Output. (line 56) -* magit-process-raise-error: Calling Git for Effect. - (line 125) -* magit-pull-or-fetch: Fetching. (line 52) -* magit-reflog-margin: Reflog. (line 20) -* magit-refresh-args: Refreshing Buffers. (line 52) -* magit-refresh-buffer-hook: Automatic Refreshing of Magit Buffers. - (line 41) -* magit-refresh-function: Refreshing Buffers. (line 47) -* magit-refresh-status-buffer: Automatic Refreshing of Magit Buffers. - (line 46) -* magit-refs-filter-alist: References Buffer. (line 137) -* magit-refs-focus-column-width: References Buffer. (line 75) -* magit-refs-margin: References Buffer. (line 89) -* magit-refs-margin-for-tags: References Buffer. (line 112) -* magit-refs-pad-commit-counts: References Buffer. (line 45) -* magit-refs-primary-column-width: References Buffer. (line 63) -* magit-refs-sections-hook: References Sections. (line 13) -* magit-refs-show-commit-count: References Buffer. (line 36) -* magit-refs-show-remote-prefix: References Buffer. (line 57) -* magit-remote-add-set-remote.pushDefault: Remote Commands. (line 83) -* magit-remote-direct-configure: Remote Commands. (line 20) -* magit-remote-git-executable: Git Executable. (line 32) -* magit-repolist-columns: Repository List. (line 12) -* magit-repository-directories: Status Buffer. (line 57) -* magit-revision-filter-files-on-follow: Revision Buffer. (line 55) -* magit-revision-insert-related-refs: Revision Buffer. (line 6) -* magit-revision-show-gravatars: Revision Buffer. (line 15) -* magit-revision-use-hash-sections: Revision Buffer. (line 31) -* magit-root-section: Matching Sections. (line 81) -* magit-save-repository-buffers: Automatic Saving of File-Visiting Buffers. - (line 13) -* magit-section-cache-visibility: Section Visibility. (line 95) -* magit-section-initial-visibility-alist: Section Visibility. (line 79) -* magit-section-movement-hook: Section Movement. (line 41) -* magit-section-set-visibility-hook: Section Visibility. (line 105) -* magit-section-show-child-count: Section Options. (line 9) -* magit-section-visibility-indicator: Section Visibility. (line 122) -* magit-shell-command-verbose-prompt: Running Git Manually. - (line 43) -* magit-stashes-margin: Stashing. (line 123) -* magit-status-headers-hook: Status Header Sections. - (line 17) -* magit-status-margin: Status Options. (line 6) -* magit-status-sections-hook: Status Sections. (line 10) -* magit-submodule-list-columns: Listing Submodules. (line 20) -* magit-this-process: Calling Git for Effect. - (line 121) -* magit-uniquify-buffer-names: Naming Buffers. (line 65) -* magit-unstage-committed: Staging and Unstaging. - (line 52) -* magit-update-other-window-delay: Section Movement. (line 97) -* magit-visit-ref-behavior: References Buffer. (line 168) -* magit-wip-after-apply-mode: Legacy Wip Modes. (line 18) -* magit-wip-after-apply-mode-lighter: Legacy Wip Modes. (line 54) -* magit-wip-after-save-local-mode-lighter: Legacy Wip Modes. (line 51) -* magit-wip-after-save-mode: Legacy Wip Modes. (line 13) -* magit-wip-before-change-mode: Legacy Wip Modes. (line 31) -* magit-wip-before-change-mode-lighter: Legacy Wip Modes. (line 57) -* magit-wip-initial-backup-mode: Legacy Wip Modes. (line 35) -* magit-wip-initial-backup-mode-lighter: Legacy Wip Modes. (line 60) -* magit-wip-merge-branch: Wip Graph. (line 6) -* magit-wip-mode: Wip Modes. (line 30) -* magit-wip-mode-lighter: Wip Modes. (line 98) -* magit-wip-namespace: Wip Modes. (line 91) -* notes.displayRef: Notes. (line 57) -* pull.rebase: Branch Git Variables. - (line 50) -* remote.NAME.fetch: Remote Git Variables. - (line 14) -* remote.NAME.push: Remote Git Variables. - (line 23) -* remote.NAME.pushurl: Remote Git Variables. - (line 18) -* remote.NAME.tagOpts: Remote Git Variables. - (line 27) -* remote.NAME.url: Remote Git Variables. - (line 10) -* remote.pushDefault: Branch Git Variables. - (line 62) - - - -Tag Table: -Node: Top774 -Node: Introduction6566 -Node: Installation11282 -Node: Installing from Melpa11612 -Node: Installing from the Git Repository12687 -Node: Post-Installation Tasks15501 -Node: Getting Started16786 -Node: Interface Concepts22597 -Node: Modes and Buffers22976 -Node: Switching Buffers24687 -Node: Naming Buffers29426 -Node: Quitting Windows32501 -Node: Automatic Refreshing of Magit Buffers34436 -Node: Automatic Saving of File-Visiting Buffers37317 -Node: Automatic Reverting of File-Visiting Buffers38501 -Node: Risk of Reverting Automatically43486 -Node: Sections45868 -Node: Section Movement46794 -Node: Section Visibility51668 -Node: Section Hooks58355 -Node: Section Types and Values60761 -Node: Section Options62176 -Node: Transient Commands62647 -Node: Transient Arguments and Buffer Variables64123 -Node: Completion Confirmation and the Selection71140 -Node: Action Confirmation71586 -Node: Completion and Confirmation80091 -Node: The Selection83276 -Node: The hunk-internal region86174 -Node: Support for Completion Frameworks87263 -Node: Additional Completion Options92148 -Node: Mouse Support92746 -Node: Running Git93322 -Node: Viewing Git Output93567 -Node: Git Process Status96271 -Node: Running Git Manually97236 -Node: Git Executable99926 -Node: Global Git Arguments102934 -Node: Inspecting103739 -Node: Status Buffer104896 -Node: Status Sections109907 -Node: Status Header Sections115434 -Node: Status Module Sections118053 -Node: Status Options120550 -Node: Repository List121913 -Node: Logging126691 -Node: Refreshing Logs129530 -Node: Log Buffer130951 -Node: Log Margin135774 -Node: Select from Log138927 -Node: Reflog141137 -Node: Cherries142774 -Node: Diffing144612 -Node: Refreshing Diffs147646 -Node: Commands Available in Diffs151335 -Node: Diff Options153848 -Node: Revision Buffer159311 -Node: Ediffing162631 -Node: References Buffer168681 -Node: References Sections179275 -Node: Bisecting180132 -Node: Visiting Files and Blobs182443 -Node: General-Purpose Visit Commands182971 -Node: Visiting Files and Blobs from a Diff183924 -Node: Blaming187368 -Node: Manipulating194356 -Node: Creating Repository194698 -Node: Cloning Repository195235 -Node: Staging and Unstaging201676 -Node: Staging from File-Visiting Buffers205649 -Node: Applying206755 -Node: Committing208828 -Node: Initiating a Commit209411 -Node: Editing Commit Messages214601 -Node: Using the Revision Stack217374 -Node: Commit Pseudo Headers220419 -Node: Commit Mode and Hooks221714 -Node: Commit Message Conventions224572 -Node: Branching226559 -Node: The Two Remotes226785 -Node: Branch Commands229438 -Node: Branch Git Variables242288 -Node: Auxiliary Branch Commands247658 -Node: Merging248774 -Node: Resolving Conflicts252930 -Node: Rebasing258304 -Node: Editing Rebase Sequences263093 -Node: Information About In-Progress Rebase267309 -Ref: Information About In-Progress Rebase-Footnote-1276422 -Node: Cherry Picking277018 -Node: Reverting281352 -Node: Resetting282771 -Node: Stashing284597 -Node: Transferring290978 -Node: Remotes291200 -Node: Remote Commands291352 -Node: Remote Git Variables295391 -Node: Fetching296662 -Node: Pulling299145 -Node: Pushing300171 -Node: Plain Patches304462 -Node: Maildir Patches305933 -Node: Miscellaneous307412 -Node: Tagging307758 -Node: Notes309651 -Node: Submodules311986 -Node: Listing Submodules312204 -Node: Submodule Transient314352 -Node: Subtree316797 -Node: Worktree318728 -Node: Sparse checkouts319804 -Node: Bundle322580 -Node: Common Commands322955 -Node: Wip Modes325583 -Node: Wip Graph330474 -Node: Legacy Wip Modes332787 -Node: Commands for Buffers Visiting Files335674 -Node: Minor Mode for Buffers Visiting Blobs343901 -Node: Customizing344699 -Node: Per-Repository Configuration346295 -Node: Essential Settings348549 -Node: Safety348895 -Node: Performance350656 -Ref: Log Performance353619 -Ref: Diff Performance354924 -Ref: Refs Buffer Performance356265 -Ref: Committing Performance356840 -Node: Microsoft Windows Performance357822 -Node: MacOS Performance359013 -Ref: MacOS Performance-Footnote-1360036 -Node: Global Bindings360118 -Node: Plumbing362346 -Node: Calling Git363175 -Node: Getting a Value from Git364700 -Node: Calling Git for Effect368428 -Node: Section Plumbing374322 -Node: Creating Sections374550 -Node: Section Selection378446 -Node: Matching Sections380242 -Node: Refreshing Buffers386163 -Node: Conventions389307 -Node: Theming Faces389499 -Node: FAQ397604 -Node: FAQ - How to ...?398042 -Node: How to pronounce Magit?398399 -Node: How to show git's output?399202 -Node: How to install the gitman info manual?399988 -Node: How to show diffs for gpg-encrypted files?400958 -Node: How does branching and pushing work?401554 -Node: Should I disable VC?401887 -Node: FAQ - Issues and Errors402490 -Node: Magit is slow403435 -Node: I changed several thousand files at once and now Magit is unusable403728 -Node: I am having problems committing404454 -Node: I am using MS Windows and cannot push with Magit404935 -Node: I am using macOS and SOMETHING works in shell but not in Magit405553 -Node: Expanding a file to show the diff causes it to disappear406387 -Node: Point is wrong in the COMMIT_EDITMSG buffer406975 -Node: The mode-line information isn't always up-to-date408023 -Node: A branch and tag sharing the same name breaks SOMETHING409086 -Node: My Git hooks work on the command-line but not inside Magit409973 -Node: git-commit-mode isn't used when committing from the command-line410819 -Node: Point ends up inside invisible text when jumping to a file-visiting buffer413090 -Node: I am no longer able to save popup defaults413939 -Node: Debugging Tools414920 -Node: Keystroke Index418094 -Node: Function and Command Index459708 -Node: Variable Index517909 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/emacs/elpa/magit-20240811.1419/AUTHORS.md b/emacs/elpa/magit-20240818.1037/AUTHORS.md diff --git a/emacs/elpa/magit-20240811.1419/LICENSE b/emacs/elpa/magit-20240818.1037/LICENSE diff --git a/emacs/elpa/magit-20240811.1419/dir b/emacs/elpa/magit-20240818.1037/dir diff --git a/emacs/elpa/magit-20240811.1419/git-rebase.el b/emacs/elpa/magit-20240818.1037/git-rebase.el diff --git a/emacs/elpa/magit-20240811.1419/git-rebase.elc b/emacs/elpa/magit-20240818.1037/git-rebase.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-apply.el b/emacs/elpa/magit-20240818.1037/magit-apply.el diff --git a/emacs/elpa/magit-20240811.1419/magit-apply.elc b/emacs/elpa/magit-20240818.1037/magit-apply.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-autoloads.el b/emacs/elpa/magit-20240818.1037/magit-autoloads.el diff --git a/emacs/elpa/magit-20240811.1419/magit-autorevert.el b/emacs/elpa/magit-20240818.1037/magit-autorevert.el diff --git a/emacs/elpa/magit-20240811.1419/magit-autorevert.elc b/emacs/elpa/magit-20240818.1037/magit-autorevert.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-base.el b/emacs/elpa/magit-20240818.1037/magit-base.el diff --git a/emacs/elpa/magit-20240811.1419/magit-base.elc b/emacs/elpa/magit-20240818.1037/magit-base.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-bisect.el b/emacs/elpa/magit-20240818.1037/magit-bisect.el diff --git a/emacs/elpa/magit-20240811.1419/magit-bisect.elc b/emacs/elpa/magit-20240818.1037/magit-bisect.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-blame.el b/emacs/elpa/magit-20240818.1037/magit-blame.el diff --git a/emacs/elpa/magit-20240811.1419/magit-blame.elc b/emacs/elpa/magit-20240818.1037/magit-blame.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-bookmark.el b/emacs/elpa/magit-20240818.1037/magit-bookmark.el diff --git a/emacs/elpa/magit-20240811.1419/magit-bookmark.elc b/emacs/elpa/magit-20240818.1037/magit-bookmark.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-branch.el b/emacs/elpa/magit-20240818.1037/magit-branch.el diff --git a/emacs/elpa/magit-20240811.1419/magit-branch.elc b/emacs/elpa/magit-20240818.1037/magit-branch.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-bundle.el b/emacs/elpa/magit-20240818.1037/magit-bundle.el diff --git a/emacs/elpa/magit-20240811.1419/magit-bundle.elc b/emacs/elpa/magit-20240818.1037/magit-bundle.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-clone.el b/emacs/elpa/magit-20240818.1037/magit-clone.el diff --git a/emacs/elpa/magit-20240811.1419/magit-clone.elc b/emacs/elpa/magit-20240818.1037/magit-clone.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-commit.el b/emacs/elpa/magit-20240818.1037/magit-commit.el diff --git a/emacs/elpa/magit-20240811.1419/magit-commit.elc b/emacs/elpa/magit-20240818.1037/magit-commit.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-core.el b/emacs/elpa/magit-20240818.1037/magit-core.el diff --git a/emacs/elpa/magit-20240811.1419/magit-core.elc b/emacs/elpa/magit-20240818.1037/magit-core.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-diff.el b/emacs/elpa/magit-20240818.1037/magit-diff.el diff --git a/emacs/elpa/magit-20240818.1037/magit-diff.elc b/emacs/elpa/magit-20240818.1037/magit-diff.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-ediff.el b/emacs/elpa/magit-20240818.1037/magit-ediff.el diff --git a/emacs/elpa/magit-20240811.1419/magit-ediff.elc b/emacs/elpa/magit-20240818.1037/magit-ediff.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-extras.el b/emacs/elpa/magit-20240818.1037/magit-extras.el diff --git a/emacs/elpa/magit-20240811.1419/magit-extras.elc b/emacs/elpa/magit-20240818.1037/magit-extras.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-fetch.el b/emacs/elpa/magit-20240818.1037/magit-fetch.el diff --git a/emacs/elpa/magit-20240811.1419/magit-fetch.elc b/emacs/elpa/magit-20240818.1037/magit-fetch.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-files.el b/emacs/elpa/magit-20240818.1037/magit-files.el diff --git a/emacs/elpa/magit-20240811.1419/magit-files.elc b/emacs/elpa/magit-20240818.1037/magit-files.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-git.el b/emacs/elpa/magit-20240818.1037/magit-git.el diff --git a/emacs/elpa/magit-20240811.1419/magit-git.elc b/emacs/elpa/magit-20240818.1037/magit-git.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-gitignore.el b/emacs/elpa/magit-20240818.1037/magit-gitignore.el diff --git a/emacs/elpa/magit-20240811.1419/magit-gitignore.elc b/emacs/elpa/magit-20240818.1037/magit-gitignore.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-log.el b/emacs/elpa/magit-20240818.1037/magit-log.el diff --git a/emacs/elpa/magit-20240818.1037/magit-log.elc b/emacs/elpa/magit-20240818.1037/magit-log.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-margin.el b/emacs/elpa/magit-20240818.1037/magit-margin.el diff --git a/emacs/elpa/magit-20240811.1419/magit-margin.elc b/emacs/elpa/magit-20240818.1037/magit-margin.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-merge.el b/emacs/elpa/magit-20240818.1037/magit-merge.el diff --git a/emacs/elpa/magit-20240811.1419/magit-merge.elc b/emacs/elpa/magit-20240818.1037/magit-merge.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-mode.el b/emacs/elpa/magit-20240818.1037/magit-mode.el diff --git a/emacs/elpa/magit-20240811.1419/magit-mode.elc b/emacs/elpa/magit-20240818.1037/magit-mode.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-notes.el b/emacs/elpa/magit-20240818.1037/magit-notes.el diff --git a/emacs/elpa/magit-20240811.1419/magit-notes.elc b/emacs/elpa/magit-20240818.1037/magit-notes.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-patch.el b/emacs/elpa/magit-20240818.1037/magit-patch.el diff --git a/emacs/elpa/magit-20240811.1419/magit-patch.elc b/emacs/elpa/magit-20240818.1037/magit-patch.elc Binary files differ. diff --git a/emacs/elpa/magit-20240818.1037/magit-pkg.el b/emacs/elpa/magit-20240818.1037/magit-pkg.el @@ -0,0 +1,20 @@ +(define-package "magit" "20240818.1037" "A Git porcelain inside Emacs." + '((emacs "26.1") + (compat "30.0.0.0") + (dash "20240510") + (git-commit "20240808") + (magit-section "20240808") + (seq "2.24") + (transient "20240805") + (with-editor "20240806")) + :commit "61f6a778ab5b0ca97069778a5955ae527996cd0f" :authors + '(("Marius Vollmer" . "marius.vollmer@gmail.com") + ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) + :maintainer + '("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") + :keywords + '("git" "tools" "vc") + :url "https://github.com/magit/magit") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/magit-20240811.1419/magit-process.el b/emacs/elpa/magit-20240818.1037/magit-process.el diff --git a/emacs/elpa/magit-20240811.1419/magit-process.elc b/emacs/elpa/magit-20240818.1037/magit-process.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-pull.el b/emacs/elpa/magit-20240818.1037/magit-pull.el diff --git a/emacs/elpa/magit-20240811.1419/magit-pull.elc b/emacs/elpa/magit-20240818.1037/magit-pull.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-push.el b/emacs/elpa/magit-20240818.1037/magit-push.el diff --git a/emacs/elpa/magit-20240811.1419/magit-push.elc b/emacs/elpa/magit-20240818.1037/magit-push.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-reflog.el b/emacs/elpa/magit-20240818.1037/magit-reflog.el diff --git a/emacs/elpa/magit-20240811.1419/magit-reflog.elc b/emacs/elpa/magit-20240818.1037/magit-reflog.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-refs.el b/emacs/elpa/magit-20240818.1037/magit-refs.el diff --git a/emacs/elpa/magit-20240811.1419/magit-refs.elc b/emacs/elpa/magit-20240818.1037/magit-refs.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-remote.el b/emacs/elpa/magit-20240818.1037/magit-remote.el diff --git a/emacs/elpa/magit-20240811.1419/magit-remote.elc b/emacs/elpa/magit-20240818.1037/magit-remote.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-repos.el b/emacs/elpa/magit-20240818.1037/magit-repos.el diff --git a/emacs/elpa/magit-20240811.1419/magit-repos.elc b/emacs/elpa/magit-20240818.1037/magit-repos.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-reset.el b/emacs/elpa/magit-20240818.1037/magit-reset.el diff --git a/emacs/elpa/magit-20240811.1419/magit-reset.elc b/emacs/elpa/magit-20240818.1037/magit-reset.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-sequence.el b/emacs/elpa/magit-20240818.1037/magit-sequence.el diff --git a/emacs/elpa/magit-20240811.1419/magit-sequence.elc b/emacs/elpa/magit-20240818.1037/magit-sequence.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-sparse-checkout.el b/emacs/elpa/magit-20240818.1037/magit-sparse-checkout.el diff --git a/emacs/elpa/magit-20240811.1419/magit-sparse-checkout.elc b/emacs/elpa/magit-20240818.1037/magit-sparse-checkout.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-stash.el b/emacs/elpa/magit-20240818.1037/magit-stash.el diff --git a/emacs/elpa/magit-20240811.1419/magit-stash.elc b/emacs/elpa/magit-20240818.1037/magit-stash.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-status.el b/emacs/elpa/magit-20240818.1037/magit-status.el diff --git a/emacs/elpa/magit-20240811.1419/magit-status.elc b/emacs/elpa/magit-20240818.1037/magit-status.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-submodule.el b/emacs/elpa/magit-20240818.1037/magit-submodule.el diff --git a/emacs/elpa/magit-20240811.1419/magit-submodule.elc b/emacs/elpa/magit-20240818.1037/magit-submodule.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-subtree.el b/emacs/elpa/magit-20240818.1037/magit-subtree.el diff --git a/emacs/elpa/magit-20240811.1419/magit-subtree.elc b/emacs/elpa/magit-20240818.1037/magit-subtree.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-tag.el b/emacs/elpa/magit-20240818.1037/magit-tag.el diff --git a/emacs/elpa/magit-20240811.1419/magit-tag.elc b/emacs/elpa/magit-20240818.1037/magit-tag.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-transient.el b/emacs/elpa/magit-20240818.1037/magit-transient.el diff --git a/emacs/elpa/magit-20240811.1419/magit-transient.elc b/emacs/elpa/magit-20240818.1037/magit-transient.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-wip.el b/emacs/elpa/magit-20240818.1037/magit-wip.el diff --git a/emacs/elpa/magit-20240811.1419/magit-wip.elc b/emacs/elpa/magit-20240818.1037/magit-wip.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit-worktree.el b/emacs/elpa/magit-20240818.1037/magit-worktree.el diff --git a/emacs/elpa/magit-20240811.1419/magit-worktree.elc b/emacs/elpa/magit-20240818.1037/magit-worktree.elc Binary files differ. diff --git a/emacs/elpa/magit-20240811.1419/magit.el b/emacs/elpa/magit-20240818.1037/magit.el diff --git a/emacs/elpa/magit-20240811.1419/magit.elc b/emacs/elpa/magit-20240818.1037/magit.elc Binary files differ. diff --git a/emacs/elpa/magit-20240818.1037/magit.info b/emacs/elpa/magit-20240818.1037/magit.info @@ -0,0 +1,11595 @@ +This is magit.info, produced by makeinfo version 6.8 from magit.texi. + + Copyright (C) 2015-2024 Jonas Bernoulli + <emacs.magit@jonas.bernoulli.dev> + + You can redistribute this document 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 document 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. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Magit: (magit). Using Git from Emacs with Magit. +END-INFO-DIR-ENTRY + + +File: magit.info, Node: Top, Next: Introduction, Up: (dir) + +Magit User Manual +***************** + +Magit is an interface to the version control system Git, implemented as +an Emacs package. Magit aspires to be a complete Git porcelain. While +we cannot (yet) claim that Magit wraps and improves upon each and every +Git command, it is complete enough to allow even experienced Git users +to perform almost all of their daily version control tasks directly from +within Emacs. While many fine Git clients exist, only Magit and Git +itself deserve to be called porcelains. + +This manual is for Magit v4.0.0-13-g85bffbbf. + + Copyright (C) 2015-2024 Jonas Bernoulli + <emacs.magit@jonas.bernoulli.dev> + + You can redistribute this document 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 document 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. + +* Menu: + +* Introduction:: +* Installation:: +* Getting Started:: +* Interface Concepts:: +* Inspecting:: +* Manipulating:: +* Transferring:: +* Miscellaneous:: +* Customizing:: +* Plumbing:: +* FAQ:: +* Debugging Tools:: +* Keystroke Index:: +* Function and Command Index:: +* Variable Index:: + +— The Detailed Node Listing — + +Installation + +* Installing from Melpa:: +* Installing from the Git Repository:: +* Post-Installation Tasks:: + +Interface Concepts + +* Modes and Buffers:: +* Sections:: +* Transient Commands:: +* Transient Arguments and Buffer Variables:: +* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. +* Mouse Support:: +* Running Git:: + +Modes and Buffers + +* Switching Buffers:: +* Naming Buffers:: +* Quitting Windows:: +* Automatic Refreshing of Magit Buffers:: +* Automatic Saving of File-Visiting Buffers:: +* Automatic Reverting of File-Visiting Buffers:: + + +Sections + +* Section Movement:: +* Section Visibility:: +* Section Hooks:: +* Section Types and Values:: +* Section Options:: + + +Completion, Confirmation and the Selection + +* Action Confirmation:: +* Completion and Confirmation:: +* The Selection:: +* The hunk-internal region:: +* Support for Completion Frameworks:: +* Additional Completion Options:: + + +Running Git + +* Viewing Git Output:: +* Git Process Status:: +* Running Git Manually:: +* Git Executable:: +* Global Git Arguments:: + + +Inspecting + +* Status Buffer:: +* Repository List:: +* Logging:: +* Diffing:: +* Ediffing:: +* References Buffer:: +* Bisecting:: +* Visiting Files and Blobs:: +* Blaming:: + +Status Buffer + +* Status Sections:: +* Status Header Sections:: +* Status Module Sections:: +* Status Options:: + + +Logging + +* Refreshing Logs:: +* Log Buffer:: +* Log Margin:: +* Select from Log:: +* Reflog:: +* Cherries:: + + +Diffing + +* Refreshing Diffs:: +* Commands Available in Diffs:: +* Diff Options:: +* Revision Buffer:: + + +References Buffer + +* References Sections:: + + +Visiting Files and Blobs + +* General-Purpose Visit Commands:: +* Visiting Files and Blobs from a Diff:: + + +Manipulating + +* Creating Repository:: +* Cloning Repository:: +* Staging and Unstaging:: +* Applying:: +* Committing:: +* Branching:: +* Merging:: +* Resolving Conflicts:: +* Rebasing:: +* Cherry Picking:: +* Resetting:: +* Stashing:: + +Staging and Unstaging + +* Staging from File-Visiting Buffers:: + + +Committing + +* Initiating a Commit:: +* Editing Commit Messages:: + + +Branching + +* The Two Remotes:: +* Branch Commands:: +* Branch Git Variables:: +* Auxiliary Branch Commands:: + + +Rebasing + +* Editing Rebase Sequences:: +* Information About In-Progress Rebase:: + + +Cherry Picking + +* Reverting:: + + +Transferring + +* Remotes:: +* Fetching:: +* Pulling:: +* Pushing:: +* Plain Patches:: +* Maildir Patches:: + +Remotes + +* Remote Commands:: +* Remote Git Variables:: + + +Miscellaneous + +* Tagging:: +* Notes:: +* Submodules:: +* Subtree:: +* Worktree:: +* Sparse checkouts:: +* Bundle:: +* Common Commands:: +* Wip Modes:: +* Commands for Buffers Visiting Files:: +* Minor Mode for Buffers Visiting Blobs:: + +Submodules + +* Listing Submodules:: +* Submodule Transient:: + + +Wip Modes + +* Wip Graph:: +* Legacy Wip Modes:: + + +Customizing + +* Per-Repository Configuration:: +* Essential Settings:: + +Essential Settings + +* Safety:: +* Performance:: +* Global Bindings:: + + +Plumbing + +* Calling Git:: +* Section Plumbing:: +* Refreshing Buffers:: +* Conventions:: + +Calling Git + +* Getting a Value from Git:: +* Calling Git for Effect:: + + +Section Plumbing + +* Creating Sections:: +* Section Selection:: +* Matching Sections:: + + +Conventions + +* Theming Faces:: + + +FAQ + +* FAQ - How to ...?:: +* FAQ - Issues and Errors:: + +FAQ - How to ...? + +* How to pronounce Magit?:: +* How to show git's output?:: +* How to install the gitman info manual?:: +* How to show diffs for gpg-encrypted files?:: +* How does branching and pushing work?:: +* Should I disable VC?:: + + +FAQ - Issues and Errors + +* Magit is slow:: +* I changed several thousand files at once and now Magit is unusable:: +* I am having problems committing:: +* I am using MS Windows and cannot push with Magit:: +* I am using macOS and SOMETHING works in shell, but not in Magit: I am using macOS and SOMETHING works in shell but not in Magit. +* Expanding a file to show the diff causes it to disappear:: +* Point is wrong in the COMMIT_EDITMSG buffer:: +* The mode-line information isn't always up-to-date:: +* A branch and tag sharing the same name breaks SOMETHING:: +* My Git hooks work on the command-line but not inside Magit:: +* git-commit-mode isn't used when committing from the command-line:: +* Point ends up inside invisible text when jumping to a file-visiting buffer:: +* I am no longer able to save popup defaults:: + + + + +File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top + +1 Introduction +************** + +Magit is an interface to the version control system Git, implemented as +an Emacs package. Magit aspires to be a complete Git porcelain. While +we cannot (yet) claim that Magit wraps and improves upon each and every +Git command, it is complete enough to allow even experienced Git users +to perform almost all of their daily version control tasks directly from +within Emacs. While many fine Git clients exist, only Magit and Git +itself deserve to be called porcelains. + + Staging and otherwise applying changes is one of the most important +features in a Git porcelain and here Magit outshines anything else, +including Git itself. Git’s own staging interface (‘git add --patch’) +is so cumbersome that many users only use it in exceptional cases. In +Magit staging a hunk or even just part of a hunk is as trivial as +staging all changes made to a file. + + The most visible part of Magit’s interface is the status buffer, +which displays information about the current repository. Its content is +created by running several Git commands and making their output +actionable. Among other things, it displays information about the +current branch, lists unpulled and unpushed changes and contains +sections displaying the staged and unstaged changes. That might sound +noisy, but, since sections are collapsible, it’s not. + + To stage or unstage a change one places the cursor on the change and +then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the +region is active (i.e., when there is a selection) several files or +hunks, or even just part of a hunk. The change or changes that these +commands - and many others - would act on are highlighted. + + Magit also implements several other "apply variants" in addition to +staging and unstaging. One can discard or reverse a change, or apply it +to the working tree. Git’s own porcelain only supports this for staging +and unstaging and you would have to do something like ‘git diff ... | +??? | git apply ...’ to discard, revert, or apply a single hunk on the +command line. In fact that’s exactly what Magit does internally (which +is what lead to the term "apply variants"). + + Magit isn’t just for Git experts, but it does assume some prior +experience with Git as well as Emacs. That being said, many users have +reported that using Magit was what finally taught them what Git is +capable of and how to use it to its fullest. Other users wished they +had switched to Emacs sooner so that they would have gotten their hands +on Magit earlier. + + While one has to know the basic features of Emacs to be able to make +full use of Magit, acquiring just enough Emacs skills doesn’t take long +and is worth it, even for users who prefer other editors. Vim users are +advised to give Evil (https://github.com/emacs-evil/evil), the +"Extensible VI Layer for Emacs", and Spacemacs +(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused +on Evil" a try. + + Magit provides a consistent and efficient Git porcelain. After a +short learning period, you will be able to perform most of your daily +version control tasks faster than you would on the command line. You +will likely also start using features that seemed too daunting in the +past. + + Magit fully embraces Git. It exposes many advanced features using a +simple but flexible interface instead of only wrapping the trivial ones +like many GUI clients do. Of course Magit supports logging, cloning, +pushing, and other commands that usually don’t fail in spectacular ways; +but it also supports tasks that often cannot be completed in a single +step. Magit fully supports tasks such as merging, rebasing, +cherry-picking, reverting, and blaming by not only providing a command +to initiate these tasks but also by displaying context sensitive +information along the way and providing commands that are useful for +resolving conflicts and resuming the sequence after doing so. + + Magit wraps and in many cases improves upon at least the following +Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’, +‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’, +‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’, +‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’, +‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’, +‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain +commands are implemented on top of Git plumbing commands. + + +File: magit.info, Node: Installation, Next: Getting Started, Prev: Introduction, Up: Top + +2 Installation +************** + +Magit can be installed using Emacs’ package manager or manually from its +development repository. + +* Menu: + +* Installing from Melpa:: +* Installing from the Git Repository:: +* Post-Installation Tasks:: + + +File: magit.info, Node: Installing from Melpa, Next: Installing from the Git Repository, Up: Installation + +2.1 Installing from Melpa +========================= + +Magit is available from Melpa and Melpa-Stable. If you haven’t used +Emacs’ package manager before, then it is high time you familiarize +yourself with it by reading the documentation in the Emacs manual, see +*note (emacs)Packages::. Then add one of the archives to +‘package-archives’: + + • To use Melpa: + + (require 'package) + (add-to-list 'package-archives + '("melpa" . "https://melpa.org/packages/") t) + + • To use Melpa-Stable: + + (require 'package) + (add-to-list 'package-archives + '("melpa-stable" . "https://stable.melpa.org/packages/") t) + + Once you have added your preferred archive, you need to update the +local package list using: + + M-x package-refresh-contents RET + + Once you have done that, you can install Magit and its dependencies +using: + + M-x package-install RET magit RET + + Now see *note Post-Installation Tasks::. + + +File: magit.info, Node: Installing from the Git Repository, Next: Post-Installation Tasks, Prev: Installing from Melpa, Up: Installation + +2.2 Installing from the Git Repository +====================================== + +Magit depends on the ‘compat’, ‘dash’, ‘transient’ and ‘with-editor’ +libraries which are available from Melpa and Melpa-Stable. Install them +using ‘M-x package-install RET <package> RET’. Of course you may also +install them manually from their repository. + + Then clone the Magit repository: + + $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit + $ cd ~/.emacs.d/site-lisp/magit + + Then compile the libraries and generate the info manuals: + + $ make + + If you haven’t installed ‘compat’, ‘dash’, ‘transient’ and +‘with-editor’ from Melpa or at ‘/path/to/magit/../<package>’, then you +have to tell ‘make’ where to find them. To do so create the file +‘/path/to/magit/config.mk’ with the following content before running +‘make’: + + LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp + LOAD_PATH += -L ~/.emacs.d/site-lisp/dash + LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp + LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor/lisp + LOAD_PATH += -L ~/.emacs.d/site-lisp/compat + + Finally add this to your init file: + + (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp") + (require 'magit) + + (with-eval-after-load 'info + (info-initialize) + (add-to-list 'Info-directory-list + "~/.emacs.d/site-lisp/magit/Documentation/")) + + Of course if you installed the dependencies manually as well, then +you have to tell Emacs about them too, by prefixing the above with: + + (add-to-list 'load-path "~/.emacs.d/site-lisp/dash") + (add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp") + (add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor") + + Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’, +not the top-level of the repository, and that elements of ‘load-path’ +should not end with a slash, while those of ‘Info-directory-list’ +should. + + Instead of requiring the feature ‘magit’, you could load just the +autoload definitions, by loading the file ‘magit-autoloads.el’. + + (load "/path/to/magit/lisp/magit-autoloads") + + Instead of running Magit directly from the repository by adding that +to the ‘load-path’, you might want to instead install it in some other +directory using ‘sudo make install’ and setting ‘load-path’ accordingly. + + To update Magit use: + + $ git pull + $ make + + At times it might be necessary to run ‘make clean all’ instead. + + To view all available targets use ‘make help’. + + Now see *note Post-Installation Tasks::. + + +File: magit.info, Node: Post-Installation Tasks, Prev: Installing from the Git Repository, Up: Installation + +2.3 Post-Installation Tasks +=========================== + +After installing Magit you should verify that you are indeed using the +Magit, Git, and Emacs releases you think you are using. It’s best to +restart Emacs before doing so, to make sure you are not using an +outdated value for ‘load-path’. + + M-x magit-version RET + + should display something like + + Magit 2.8.0, Git 2.10.2, Emacs 25.1.1, gnu/linux + + Then you might also want to read about options that many users likely +want to customize. See *note Essential Settings::. + + To be able to follow cross references to Git manpages found in this +manual, you might also have to manually install the ‘gitman’ info +manual, or advice ‘Info-follow-nearest-node’ to instead open the actual +manpage. See *note How to install the gitman info manual?::. + + If you are completely new to Magit then see *note Getting Started::. + + If you run into problems, then please see the *note FAQ::. Also see +the *note Debugging Tools::. + + And last but not least please consider making a donation, to ensure +that I can keep working on Magit. See <https://magit.vc/donations>. +for various donation options. + + +File: magit.info, Node: Getting Started, Next: Interface Concepts, Prev: Installation, Up: Top + +3 Getting Started +***************** + +This short tutorial describes the most essential features that many +Magitians use on a daily basis. It only scratches the surface but +should be enough to get you started. + + IMPORTANT: It is safest if you clone some repository just for this +tutorial. Alternatively you can use an existing local repository, but +if you do that, then you should commit all uncommitted changes before +proceeding. + + Type ‘C-x g’ to display information about the current Git repository +in a dedicated buffer, called the status buffer. + + Most Magit commands are commonly invoked from the status buffer. It +can be considered the primary interface for interacting with Git using +Magit. Many other Magit buffers may exist at a given time, but they are +often created from this buffer. + + Depending on what state your repository is in, this buffer may +contain sections titled "Staged changes", "Unstaged changes", "Unmerged +into origin/master", "Unpushed to origin/master", and many others. + + Since we are starting from a safe state, which you can easily return +to (by doing a ‘git reset --hard PRE-MAGIT-STATE’), there currently are +no staged or unstaged changes. Edit some files and save the changes. +Then go back to the status buffer, while at the same time refreshing it, +by typing ‘C-x g’. (When the status buffer, or any Magit buffer for +that matter, is the current buffer, then you can also use just ‘g’ to +refresh it). + + Move between sections using ‘p’ and ‘n’. Note that the bodies of +some sections are hidden. Type ‘TAB’ to expand or collapse the section +at point. You can also use ‘C-tab’ to cycle the visibility of the +current section and its children. Move to a file section inside the +section named "Unstaged changes" and type ‘s’ to stage the changes you +have made to that file. That file now appears under "Staged changes". + + Magit can stage and unstage individual hunks, not just complete +files. Move to the file you have just staged, expand it using ‘TAB’, +move to one of the hunks using ‘n’, and unstage just that by typing ‘u’. +Note how the staging (‘s’) and unstaging (‘u’) commands operate on the +change at point. Many other commands behave the same way. + + You can also un-/stage just part of a hunk. Inside the body of a +hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and +move down until some added and/or removed lines fall inside the region +but not all of them. Again type ‘s’ to stage. + + It is also possible to un-/stage multiple files at once. Move to a +file section, type ‘C-SPC’, move to the next file using ‘n’, and then +‘s’ to stage both files. Note that both the mark and point have to be +on the headings of sibling sections for this to work. If the region +looks like it does in other buffers, then it doesn’t select Magit +sections that can be acted on as a unit. + + And then of course you want to commit your changes. Type ‘c’. This +shows the available commit commands and arguments in a buffer at the +bottom of the frame. Each command and argument is prefixed with the key +that invokes/sets it. Do not worry about this for now. We want to +create a "normal" commit, which is done by typing ‘c’ again. + + Now two new buffers appear. One is for writing the commit message, +the other shows a diff with the changes that you are about to commit. +Write a message and then type ‘C-c C-c’ to actually create the commit. + + You probably don’t want to push the commit you just created because +you just committed some random changes, but if that is not the case you +could push it by typing ‘P’ to show all the available push commands and +arguments and then ‘p’ to push to a branch with the same name as the +local branch onto the remote configured as the push-remote. (If the +push-remote is not configured yet, then you would first be prompted for +the remote to push to.) + + So far we have mentioned the commit and push menu commands. These +are probably among the menus you will be using the most, but many others +exist. To show a menu that lists all other menus (as well as the +various apply commands and some other essential commands), type ‘h’. +Try a few. (Such menus are also called "transient prefix commands" or +just "transients".) + + The key bindings in that menu correspond to the bindings in Magit +buffers, including but not limited to the status buffer. So you could +type ‘h d’ to bring up the diff menu, but once you remember that "d" +stands for "diff", you would usually do so by just typing ‘d’. + + This "prefix of prefixes" is useful even once you have memorized all +the bindings, as it can provide easy access to Magit commands from +non-Magit buffers. So, by default, it is globally bound to ‘C-x M-g’. + + A similar menu featuring (for the most part) commands that act on +just the file being visited in the current buffer, is globally bound to +‘C-c M-g’. That binding can also be used in buffers, which do not visit +a file, but then only a subset of the commands is available. + + The global key bindings mentioned in the previous two paragraphs are +quite inconvenient. We recommend using ‘C-c g’ and ‘C-c f’ instead, but +cannot use those key sequences by default because they are strictly +reserved for bindings added by the user. See *note Global Bindings::, +if you want to explicitly opt-in to the recommended key bindings. + + Magit also provides context menus and other mouse commands, see *note +Mouse Support::. + + It is not necessary that you do so now, but if you stick with Magit, +then it is highly recommended that you read the next section too. + + +File: magit.info, Node: Interface Concepts, Next: Inspecting, Prev: Getting Started, Up: Top + +4 Interface Concepts +******************** + +* Menu: + +* Modes and Buffers:: +* Sections:: +* Transient Commands:: +* Transient Arguments and Buffer Variables:: +* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. +* Mouse Support:: +* Running Git:: + + +File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface Concepts + +4.1 Modes and Buffers +===================== + +Magit provides several major-modes. For each of these modes there +usually exists only one buffer per repository. Separate modes and thus +buffers exist for commits, diffs, logs, and some other things. + + Besides these special purpose buffers, there also exists an overview +buffer, called the *status buffer*. It’s usually from this buffer that +the user invokes Git commands, or creates or visits other buffers. + + In this manual we often speak about "Magit buffers". By that we mean +buffers whose major-modes derive from ‘magit-mode’. + +‘M-x magit-toggle-buffer-lock’ + This command locks the current buffer to its value or if the buffer + is already locked, then it unlocks it. + + Locking a buffer to its value prevents it from being reused to + display another value. The name of a locked buffer contains its + value, which allows telling it apart from other locked buffers and + the unlocked buffer. + + Not all Magit buffers can be locked to their values; for example, + it wouldn’t make sense to lock a status buffer. + + There can only be a single unlocked buffer using a certain + major-mode per repository. So when a buffer is being unlocked and + another unlocked buffer already exists for that mode and + repository, then the former buffer is instead deleted and the + latter is displayed in its place. + +* Menu: + +* Switching Buffers:: +* Naming Buffers:: +* Quitting Windows:: +* Automatic Refreshing of Magit Buffers:: +* Automatic Saving of File-Visiting Buffers:: +* Automatic Reverting of File-Visiting Buffers:: + + +File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers + +4.1.1 Switching Buffers +----------------------- + + -- Function: magit-display-buffer buffer &optional display-function + This function is a wrapper around ‘display-buffer’ and is used to + display any Magit buffer. It displays BUFFER in some window and, + unlike ‘display-buffer’, also selects that window, provided + ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks + mentioned below. + + If optional DISPLAY-FUNCTION is non-nil, then that is used to + display the buffer. Usually that is ‘nil’ and the function + specified by ‘magit-display-buffer-function’ is used. + + -- Variable: magit-display-buffer-noselect + When this is non-nil, then ‘magit-display-buffer’ only displays the + buffer but forgoes also selecting the window. This variable should + not be set globally, it is only intended to be let-bound, by code + that automatically updates "the other window". This is used for + example when the revision buffer is updated when you move inside + the log buffer. + + -- User Option: magit-display-buffer-function + The function specified here is called by ‘magit-display-buffer’ + with one argument, a buffer, to actually display that buffer. This + function should call ‘display-buffer’ with that buffer as first and + a list of display actions as second argument. + + Magit provides several functions, listed below, that are suitable + values for this option. If you want to use different rules, then a + good way of doing that is to start with a copy of one of these + functions and then adjust it to your needs. + + Instead of using a wrapper around ‘display-buffer’, that function + itself can be used here, in which case the display actions have to + be specified by adding them to ‘display-buffer-alist’ instead. + + To learn about display actions, see *note (elisp)Choosing Window::. + + -- Function: magit-display-buffer-traditional buffer + This function is the current default value of the option + ‘magit-display-buffer-function’. Before that option and this + function were added, the behavior was hard-coded in many places all + over the code base but now all the rules are contained in this one + function (except for the "noselect" special case mentioned above). + + -- Function: magit-display-buffer-same-window-except-diff-v1 + This function displays most buffers in the currently selected + window. If a buffer’s mode derives from ‘magit-diff-mode’ or + ‘magit-process-mode’, it is displayed in another window. + + -- Function: magit-display-buffer-fullframe-status-v1 + This function fills the entire frame when displaying a status + buffer. Otherwise, it behaves like + ‘magit-display-buffer-traditional’. + + -- Function: magit-display-buffer-fullframe-status-topleft-v1 + This function fills the entire frame when displaying a status + buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’ + except that it displays buffers that derive from ‘magit-diff-mode’ + or ‘magit-process-mode’ to the top or left of the current buffer + rather than to the bottom or right. As a result, Magit buffers + tend to pop up on the same side as they would if + ‘magit-display-buffer-traditional’ were in use. + + -- Function: magit-display-buffer-fullcolumn-most-v1 + This function displays most buffers so that they fill the entire + height of the frame. However, the buffer is displayed in another + window if (1) the buffer’s mode derives from ‘magit-process-mode’, + or (2) the buffer’s mode derives from ‘magit-diff-mode’, provided + that the mode of the current buffer derives from ‘magit-log-mode’ + or ‘magit-cherry-mode’. + + -- User Option: magit-pre-display-buffer-hook + This hook is run by ‘magit-display-buffer’ before displaying the + buffer. + + -- Function: magit-save-window-configuration + This function saves the current window configuration. Later when + the buffer is buried, it may be restored by + ‘magit-restore-window-configuration’. + + -- User Option: magit-post-display-buffer-hook + This hook is run by ‘magit-display-buffer’ after displaying the + buffer. + + -- Function: magit-maybe-set-dedicated + This function remembers if a new window had to be created to + display the buffer, or whether an existing window was reused. This + information is later used by ‘magit-mode-quit-window’, to determine + whether the window should be deleted when its last Magit buffer is + buried. + + +File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers + +4.1.2 Naming Buffers +-------------------- + + -- User Option: magit-generate-buffer-name-function + The function used to generate the names of Magit buffers. + + Such a function should take the options + ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’ + into account. If it doesn’t, then should be clearly stated in the + doc-string. And if it supports %-sequences beyond those mentioned + in the doc-string of the option ‘magit-buffer-name-format’, then + its own doc-string should describe the additions. + + -- Function: magit-generate-buffer-name-default-function mode + This function returns a buffer name suitable for a buffer whose + major-mode is MODE and which shows information about the repository + in which ‘default-directory’ is located. + + This function uses ‘magit-buffer-name-format’ and supporting all of + the %-sequences mentioned the documentation of that option. It + also respects the option ‘magit-uniquify-buffer-names’. + + -- User Option: magit-buffer-name-format + The format string used to name Magit buffers. + + At least the following %-sequences are supported: + + • ‘%m’ + + The name of the major-mode, but with the ‘-mode’ suffix + removed. + + • ‘%M’ + + Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’. + + • ‘%v’ + + The value the buffer is locked to, in parentheses, or an empty + string if the buffer is not locked to a value. + + • ‘%V’ + + Like ‘%v’, but the string is prefixed with a space, unless it + is an empty string. + + • ‘%t’ + + The top-level directory of the working tree of the repository, + or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation + of that. + + • ‘%x’ + + If ‘magit-uniquify-buffer-names’ is nil "*", otherwise the + empty string. Due to limitations of the ‘uniquify’ package, + buffer names must end with the path. + + The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and + ‘%t’. If ‘magit-uniquify-buffer-names’ is non-nil, then the value + must end with ‘%t’ or ‘%t%x’. See issue #2841. + + -- User Option: magit-uniquify-buffer-names + This option controls whether the names of Magit buffers are + uniquified. If the names are not being uniquified, then they + contain the full path of the top-level of the working tree of the + corresponding repository. If they are being uniquified, then they + end with the basename of the top-level, or if that would conflict + with the name used for other buffers, then the names of all these + buffers are adjusted until they no longer conflict. + + This is done using the ‘uniquify’ package; customize its options to + control how buffer names are uniquified. + + +File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers + +4.1.3 Quitting Windows +---------------------- + +‘q’ (‘magit-mode-bury-buffer’) + This command buries or kills the current Magit buffer. The + function specified by option ‘magit-bury-buffer-function’ is used + to bury the buffer when called without a prefix argument or to kill + it when called with a single prefix argument. + + When called with two or more prefix arguments then it always kills + all Magit buffers, associated with the current project, including + the current buffer. + + -- User Option: magit-bury-buffer-function + The function used to actually bury or kill the current buffer. + + ‘magit-mode-bury-buffer’ calls this function with one argument. If + the argument is non-nil, then the function has to kill the current + buffer. Otherwise it has to bury it alive. The default value + currently is ‘magit-mode-quit-window’. + + -- Function: magit-restore-window-configuration kill-buffer + Bury or kill the current buffer using ‘quit-window’, which is + called with KILL-BUFFER as first and the selected window as second + argument. + + Then restore the window configuration that existed right before the + current buffer was displayed in the selected frame. Unfortunately + that also means that point gets adjusted in all the buffers, which + are being displayed in the selected frame. + + -- Function: magit-mode-quit-window kill-buffer + Bury or kill the current buffer using ‘quit-window’, which is + called with KILL-BUFFER as first and the selected window as second + argument. + + Then, if the window was originally created to display a Magit + buffer and the buried buffer was the last remaining Magit buffer + that was ever displayed in the window, then that is deleted. + + +File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers + +4.1.4 Automatic Refreshing of Magit Buffers +------------------------------------------- + +After running a command which may change the state of the current +repository, the current Magit buffer and the corresponding status buffer +are refreshed. The status buffer can be automatically refreshed +whenever a buffer is saved to a file inside the respective repository by +adding a hook, like so: + + (with-eval-after-load 'magit-mode + (add-hook 'after-save-hook 'magit-after-save-refresh-status t)) + + Automatically refreshing Magit buffers ensures that the displayed +information is up-to-date most of the time but can lead to a noticeable +delay in big repositories. Other Magit buffers are not refreshed to +keep the delay to a minimum and also because doing so can sometimes be +undesirable. + + Buffers can also be refreshed explicitly, which is useful in buffers +that weren’t current during the last refresh and after changes were made +to the repository outside of Magit. + +‘g’ (‘magit-refresh’) + This command refreshes the current buffer if its major mode derives + from ‘magit-mode’ as well as the corresponding status buffer. + + If the option ‘magit-revert-buffers’ calls for it, then it also + reverts all unmodified buffers that visit files being tracked in + the current repository. + +‘G’ (‘magit-refresh-all’) + This command refreshes all Magit buffers belonging to the current + repository and also reverts all unmodified buffers that visit files + being tracked in the current repository. + + The file-visiting buffers are always reverted, even if + ‘magit-revert-buffers’ is nil. + + -- User Option: magit-refresh-buffer-hook + This hook is run in each Magit buffer that was refreshed during the + current refresh - normally the current buffer and the status + buffer. + + -- User Option: magit-refresh-status-buffer + When this option is non-nil, then the status buffer is + automatically refreshed after running git for side-effects, in + addition to the current Magit buffer, which is always refreshed + automatically. + + Only set this to nil after exhausting all other options to improve + performance. + + -- Function: magit-after-save-refresh-status + This function is intended to be added to ‘after-save-hook’. After + doing that the corresponding status buffer is refreshed whenever a + buffer is saved to a file inside a repository. + + Note that refreshing a Magit buffer is done by re-creating its + contents from scratch, which can be slow in large repositories. If + you are not satisfied with Magit’s performance, then you should + obviously not add this function to that hook. + + +File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers + +4.1.5 Automatic Saving of File-Visiting Buffers +----------------------------------------------- + +File-visiting buffers are by default saved at certain points in time. +This doesn’t guarantee that Magit buffers are always up-to-date, but, +provided one only edits files by editing them in Emacs and uses only +Magit to interact with Git, one can be fairly confident. When in doubt +or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh +explicitly. + + -- User Option: magit-save-repository-buffers + This option controls whether file-visiting buffers are saved before + certain events. + + If this is non-nil then all modified file-visiting buffers + belonging to the current repository may be saved before running + commands, before creating new Magit buffers, and before explicitly + refreshing such buffers. If this is ‘dontask’ then this is done + without user intervention. If it is ‘t’ then the user has to + confirm each save. + + +File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers + +4.1.6 Automatic Reverting of File-Visiting Buffers +-------------------------------------------------- + +By default Magit automatically reverts buffers that are visiting files +that are being tracked in a Git repository, after they have changed on +disk. When using Magit one often changes files on disk by running Git, +i.e., "outside Emacs", making this a rather important feature. + + For example, if you discard a change in the status buffer, then that +is done by running ‘git apply --reverse ...’, and Emacs considers the +file to have "changed on disk". If Magit did not automatically revert +the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in +the visiting buffer before you could continue making changes. + + -- User Option: magit-auto-revert-mode + When this mode is enabled, then buffers that visit tracked files + are automatically reverted after the visited files change on disk. + + -- User Option: global-auto-revert-mode + When this mode is enabled, then any file-visiting buffer is + automatically reverted after the visited file changes on disk. + + If you like buffers that visit tracked files to be automatically + reverted, then you might also like any buffer to be reverted, not + just those visiting tracked files. If that is the case, then + enable this mode _instead of_ ‘magit-auto-revert-mode’. + + -- User Option: magit-auto-revert-immediately + This option controls whether Magit reverts buffers immediately. + + If this is non-nil and either ‘global-auto-revert-mode’ or + ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts + buffers by explicitly calling ‘auto-revert-buffers’ after running + Git for side-effects. + + If ‘auto-revert-use-notify’ is non-nil (and file notifications are + actually supported), then ‘magit-auto-revert-immediately’ does not + have to be non-nil, because the reverts happen immediately anyway. + + If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are + both ‘nil’, then reverts happen after ‘auto-revert-interval’ + seconds of user inactivity. That is not desirable. + + -- User Option: auto-revert-use-notify + This option controls whether file notification functions should be + used. Note that this variable unfortunately defaults to ‘t’ even + on systems on which file notifications cannot be used. + + -- User Option: magit-auto-revert-tracked-only + This option controls whether ‘magit-auto-revert-mode’ only reverts + tracked files or all files that are located inside Git + repositories, including untracked files and files located inside + Git’s control directory. + + -- User Option: auto-revert-mode + The global mode ‘magit-auto-revert-mode’ works by turning on this + local mode in the appropriate buffers (but + ‘global-auto-revert-mode’ is implemented differently). You can + also turn it on or off manually, which might be necessary if Magit + does not notice that a previously untracked file now is being + tracked or vice-versa. + + -- User Option: auto-revert-stop-on-user-input + This option controls whether the arrival of user input suspends the + automatic reverts for ‘auto-revert-interval’ seconds. + + -- User Option: auto-revert-interval + This option controls how many seconds Emacs waits for before + resuming suspended reverts. + + -- User Option: auto-revert-buffer-list-filter + This option specifies an additional filter used by + ‘auto-revert-buffers’ to determine whether a buffer should be + reverted or not. + + This option is provided by Magit, which also advises + ‘auto-revert-buffers’ to respect it. Magit users who do not turn + on the local mode ‘auto-revert-mode’ themselves, are best served by + setting the value to ‘magit-auto-revert-repository-buffer-p’. + + However the default is nil, so as not to disturb users who do use + the local mode directly. If you experience delays when running + Magit commands, then you should consider using one of the + predicates provided by Magit - especially if you also use Tramp. + + Users who do turn on ‘auto-revert-mode’ in buffers in which Magit + doesn’t do that for them, should likely not use any filter. Users + who turn on ‘global-auto-revert-mode’, do not have to worry about + this option, because it is disregarded if the global mode is + enabled. + + -- User Option: auto-revert-verbose + This option controls whether Emacs reports when a buffer has been + reverted. + + The options with the ‘auto-revert-’ prefix are located in the Custom +group named ‘auto-revert’. The other, Magit-specific, options are +located in the ‘magit’ group. + +* Menu: + +* Risk of Reverting Automatically:: + + +File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers + +Risk of Reverting Automatically +............................... + +For the vast majority of users, automatically reverting file-visiting +buffers after they have changed on disk is harmless. + + If a buffer is modified (i.e., it contains changes that haven’t been +saved yet), then Emacs will refuse to automatically revert it. If you +save a previously modified buffer, then that results in what is seen by +Git as an uncommitted change. Git will then refuse to carry out any +commands that would cause these changes to be lost. In other words, if +there is anything that could be lost, then either Git or Emacs will +refuse to discard the changes. + + However, if you use file-visiting buffers as a sort of ad hoc +"staging area", then the automatic reverts could potentially cause data +loss. So far I have heard from only one user who uses such a workflow. + + An example: You visit some file in a buffer, edit it, and save the +changes. Then, outside of Emacs (or at least not using Magit or by +saving the buffer) you change the file on disk again. At this point the +buffer is the only place where the intermediate version still exists. +You have saved the changes to disk, but that has since been overwritten. +Meanwhile Emacs considers the buffer to be unmodified (because you have +not made any changes to it since you last saved it to the visited file) +and therefore would not object to it being automatically reverted. At +this point an Auto-Revert mode would kick in. It would check whether +the buffer is modified and since that is not the case it would revert +it. The intermediate version would be lost. (Actually you could still +get it back using the ‘undo’ command.) + + If your workflow depends on Emacs preserving the intermediate version +in the buffer, then you have to disable all Auto-Revert modes. But +please consider that such a workflow would be dangerous even without +using an Auto-Revert mode, and should therefore be avoided. If Emacs +crashes or if you quit Emacs by mistake, then you would also lose the +buffer content. There would be no autosave file still containing the +intermediate version (because that was deleted when you saved the +buffer) and you would not be asked whether you want to save the buffer +(because it isn’t modified). + + +File: magit.info, Node: Sections, Next: Transient Commands, Prev: Modes and Buffers, Up: Interface Concepts + +4.2 Sections +============ + +Magit buffers are organized into nested sections, which can be collapsed +and expanded, similar to how sections are handled in Org mode. Each +section also has a type, and some sections also have a value. For each +section type there can also be a local keymap, shared by all sections of +that type. + + Taking advantage of the section value and type, many commands operate +on the current section, or when the region is active and selects +sections of the same type, all of the selected sections. Commands that +only make sense for a particular section type (as opposed to just +behaving differently depending on the type) are usually bound in section +type keymaps. + +* Menu: + +* Section Movement:: +* Section Visibility:: +* Section Hooks:: +* Section Types and Values:: +* Section Options:: + + +File: magit.info, Node: Section Movement, Next: Section Visibility, Up: Sections + +4.2.1 Section Movement +---------------------- + +To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’ +etc), whose global bindings are not shadowed. To move to another +section use the following commands. + +‘p’ (‘magit-section-backward’) + When not at the beginning of a section, then move to the beginning + of the current section. At the beginning of a section, instead + move to the beginning of the previous visible section. + +‘n’ (‘magit-section-forward’) + Move to the beginning of the next visible section. + +‘M-p’ (‘magit-section-backward-siblings’) + Move to the beginning of the previous sibling section. If there is + no previous sibling section, then move to the parent section + instead. + +‘M-n’ (‘magit-section-forward-siblings’) + Move to the beginning of the next sibling section. If there is no + next sibling section, then move to the parent section instead. + +‘^’ (‘magit-section-up’) + Move to the beginning of the parent of the current section. + + The above commands all call the hook ‘magit-section-movement-hook’. +Any of the functions listed below can be used as members of this hook. + + You might want to remove some of the functions that Magit adds using +‘add-hook’. In doing so you have to make sure you do not attempt to +remove function that haven’t even been added yet, for example: + + (with-eval-after-load 'magit-diff + (remove-hook 'magit-section-movement-hook + 'magit-hunk-set-window-start)) + + -- Variable: magit-section-movement-hook + This hook is run by all of the above movement commands, after + arriving at the destination. + + -- Function: magit-hunk-set-window-start + This hook function ensures that the beginning of the current + section is visible, provided it is a ‘hunk’ section. Otherwise, it + does nothing. + + Loading ‘magit-diff’ adds this function to the hook. + + -- Function: magit-section-set-window-start + This hook function ensures that the beginning of the current + section is visible, regardless of the section’s type. If you add + this to ‘magit-section-movement-hook’, then you must remove the + hunk-only variant in turn. + + -- Function: magit-log-maybe-show-more-commits + This hook function only has an effect in log buffers, and ‘point’ + is on the "show more" section. If that is the case, then it + doubles the number of commits that are being shown. + + Loading ‘magit-log’ adds this function to the hook. + + -- Function: magit-log-maybe-update-revision-buffer + When moving inside a log buffer, then this function updates the + revision buffer, provided it is already being displayed in another + window of the same frame. + + Loading ‘magit-log’ adds this function to the hook. + + -- Function: magit-log-maybe-update-blob-buffer + When moving inside a log buffer and another window of the same + frame displays a blob buffer, then this function instead displays + the blob buffer for the commit at point in that window. + + -- Function: magit-status-maybe-update-revision-buffer + When moving inside a status buffer, then this function updates the + revision buffer, provided it is already being displayed in another + window of the same frame. + + -- Function: magit-status-maybe-update-stash-buffer + When moving inside a status buffer, then this function updates the + stash buffer, provided it is already being displayed in another + window of the same frame. + + -- Function: magit-status-maybe-update-blob-buffer + When moving inside a status buffer and another window of the same + frame displays a blob buffer, then this function instead displays + the blob buffer for the commit at point in that window. + + -- Function: magit-stashes-maybe-update-stash-buffer + When moving inside a buffer listing stashes, then this function + updates the stash buffer, provided it is already being displayed in + another window of the same frame. + + -- User Option: magit-update-other-window-delay + Delay before automatically updating the other window. + + When moving around in certain buffers, then certain other buffers, + which are being displayed in another window, may optionally be + updated to display information about the section at point. + + When holding down a key to move by more than just one section, then + that would update that buffer for each section on the way. To + prevent that, updating the revision buffer is delayed, and this + option controls for how long. For optimal experience you might + have to adjust this delay and/or the keyboard repeat rate and delay + of your graphical environment or operating system. + + +File: magit.info, Node: Section Visibility, Next: Section Hooks, Prev: Section Movement, Up: Sections + +4.2.2 Section Visibility +------------------------ + +Magit provides many commands for changing the visibility of sections, +but all you need to get started are the next two. + +‘<TAB>’ (‘magit-section-toggle’) + Toggle the visibility of the body of the current section. + +‘C-c <TAB>’ (‘magit-section-cycle’) +‘C-<tab>’ (‘magit-section-cycle’) + Cycle the visibility of current section and its children. + + If this command is invoked using ‘C-<tab>’ and that is globally + bound to ‘tab-next’, then this command pivots to behave like that + command, and you must instead use ‘C-c TAB’ to cycle section + visibility. + + If you would like to keep using ‘C-<tab>’ to cycle section + visibility but also want to use ‘tab-bar-mode’, then you have to + prevent that mode from using this key and instead bind another key + to ‘tab-next’. Because ‘tab-bar-mode’ does not use a mode map but + instead manipulates the global map, this involves advising + ‘tab-bar--define-keys’. + +‘M-<tab>’ (‘magit-section-cycle-diffs’) + Cycle the visibility of diff-related sections in the current + buffer. + +‘S-<tab>’ (‘magit-section-cycle-global’) + Cycle the visibility of all sections in the current buffer. + +‘1’ (‘magit-section-show-level-1’) +‘2’ (‘magit-section-show-level-2’) +‘3’ (‘magit-section-show-level-3’) +‘4’ (‘magit-section-show-level-4’) + Show sections surrounding the current section up to level N. + +‘M-1’ (‘magit-section-show-level-1-all’) +‘M-2’ (‘magit-section-show-level-2-all’) +‘M-3’ (‘magit-section-show-level-3-all’) +‘M-4’ (‘magit-section-show-level-4-all’) + Show all sections up to level N. + + Some functions, which are used to implement the above commands, are +also exposed as commands themselves. By default no keys are bound to +these commands, as they are generally perceived to be much less useful. +But your mileage may vary. + + -- Command: magit-section-show + Show the body of the current section. + + -- Command: magit-section-hide + Hide the body of the current section. + + -- Command: magit-section-show-headings + Recursively show headings of children of the current section. Only + show the headings. Previously shown text-only bodies are hidden. + + -- Command: magit-section-show-children + Recursively show the bodies of children of the current section. + With a prefix argument show children down to the level of the + current section, and hide deeper children. + + -- Command: magit-section-hide-children + Recursively hide the bodies of children of the current section. + + -- Command: magit-section-toggle-children + Toggle visibility of bodies of children of the current section. + + When a buffer is first created then some sections are shown expanded +while others are not. This is hard coded. When a buffer is refreshed +then the previous visibility is preserved. The initial visibility of +certain sections can also be overwritten using the hook +‘magit-section-set-visibility-hook’. + + -- User Option: magit-section-initial-visibility-alist + This options can be used to override the initial visibility of + sections. In the future it will also be used to define the + defaults, but currently a section’s default is still hardcoded. + + The value is an alist. Each element maps a section type or lineage + to the initial visibility state for such sections. The state has + to be one of ‘show’ or ‘hide’, or a function that returns one of + these symbols. A function is called with the section as the only + argument. + + Use the command ‘magit-describe-section-briefly’ to determine a + section’s lineage or type. The vector in the output is the section + lineage and the type is the first element of that vector. + Wildcards can be used, see ‘magit-section-match’. + + -- User Option: magit-section-cache-visibility + This option controls for which sections the previous visibility + state should be restored if a section disappears and later appears + again. The value is a boolean or a list of section types. If t, + then the visibility of all sections is cached. Otherwise this is + only done for sections whose type matches one of the listed types. + + This requires that the function ‘magit-section-cached-visibility’ + is a member of ‘magit-section-set-visibility-hook’. + + -- Variable: magit-section-set-visibility-hook + This hook is run when first creating a buffer and also when + refreshing an existing buffer, and is used to determine the + visibility of the section currently being inserted. + + Each function is called with one argument, the section being + inserted. It should return ‘hide’ or ‘show’, or to leave the + visibility undefined ‘nil’. If no function decides on the + visibility and the buffer is being refreshed, then the visibility + is preserved; or if the buffer is being created, then the hard + coded default is used. + + Usually this should only be used to set the initial visibility but + not during refreshes. If ‘magit-insert-section--oldroot’ is + non-nil, then the buffer is being refreshed and these functions + should immediately return ‘nil’. + + -- User Option: magit-section-visibility-indicator + This option controls whether and how to indicate that a section can + be expanded/collapsed. + + If nil, then no visibility indicators are shown. Otherwise the + value has to have one of these two forms: + + • ‘(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)’ + + Both values have to be variables whose values are fringe + bitmaps. In this case every section that can be expanded or + collapsed gets an indicator in the left fringe. + + To provide extra padding around the indicator, set + ‘left-fringe-width’ in ‘magit-mode-hook’, e.g.: + + (add-hook 'magit-mode-hook (lambda () + (setq left-fringe-width 20))) + + • ‘(STRING . BOOLEAN)’ + + In this case STRING (usually an ellipsis) is shown at the end + of the heading of every collapsed section. Expanded sections + get no indicator. The cdr controls whether the appearance of + these ellipsis take section highlighting into account. Doing + so might potentially have an impact on performance, while not + doing so is kinda ugly. + + +File: magit.info, Node: Section Hooks, Next: Section Types and Values, Prev: Section Visibility, Up: Sections + +4.2.3 Section Hooks +------------------- + +Which sections are inserted into certain buffers is controlled with +hooks. This includes the status and the refs buffers. For other +buffers, e.g., log and diff buffers, this is not possible. The command +‘magit-describe-section’ can be used to see which hook (if any) was +responsible for inserting the section at point. + + For buffers whose sections can be customized by the user, a hook +variable called ‘magit-TYPE-sections-hook’ exists. This hook should be +changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the +Custom interface. + + The various available section hook variables are described later in +this manual along with the appropriate "section inserter functions". + + -- Function: magit-add-section-hook hook function &optional at append + local + Add the function FUNCTION to the value of section hook HOOK. + + Add FUNCTION at the beginning of the hook list unless optional + APPEND is non-nil, in which case FUNCTION is added at the end. If + FUNCTION already is a member then move it to the new location. + + If optional AT is non-nil and a member of the hook list, then add + FUNCTION next to that instead. Add before or after AT, or replace + AT with FUNCTION depending on APPEND. If APPEND is the symbol + ‘replace’, then replace AT with FUNCTION. For any other non-nil + value place FUNCTION right after AT. If nil, then place FUNCTION + right before AT. If FUNCTION already is a member of the list but + AT is not, then leave FUNCTION where ever it already is. + + If optional LOCAL is non-nil, then modify the hook’s buffer-local + value rather than its global value. This makes the hook local by + copying the default value. That copy is then modified. + + HOOK should be a symbol. If HOOK is void, it is first set to nil. + HOOK’s value must not be a single hook function. FUNCTION should + be a function that takes no arguments and inserts one or multiple + sections at point, moving point forward. FUNCTION may choose not + to insert its section(s), when doing so would not make sense. It + should not be abused for other side-effects. + + To remove a function from a section hook, use ‘remove-hook’. + + +File: magit.info, Node: Section Types and Values, Next: Section Options, Prev: Section Hooks, Up: Sections + +4.2.4 Section Types and Values +------------------------------ + +Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’. +Instances of certain section types also have a value. The value of a +section of type ‘file’, for example, is a file name. + + Users usually do not have to worry about a section’s type and value, +but knowing them can be handy at times. + +‘H’ (‘magit-describe-section’) + This command shows information about the section at point in a + separate buffer. + + -- Command: magit-describe-section-briefly + This command shows information about the section at point in the + echo area, as ‘#<magit-section VALUE [TYPE PARENT-TYPE...] + BEGINNING-END>’. + + Many commands behave differently depending on the type of the section +at point and/or somehow consume the value of that section. But that is +only one of the reasons why the same key may do something different, +depending on what section is current. + + Additionally for each section type a keymap *might* be defined, named +‘magit-TYPE-section-map’. That keymap is used as text property keymap +of all text belonging to any section of the respective type. If such a +map does not exist for a certain type, then you can define it yourself, +and it will automatically be used. + + +File: magit.info, Node: Section Options, Prev: Section Types and Values, Up: Sections + +4.2.5 Section Options +--------------------- + +This section describes options that have an effect on more than just a +certain type of sections. As you can see there are not many of those. + + -- User Option: magit-section-show-child-count + Whether to append the number of children to section headings. This + only affects sections that could benefit from this information. + + +File: magit.info, Node: Transient Commands, Next: Transient Arguments and Buffer Variables, Prev: Sections, Up: Interface Concepts + +4.3 Transient Commands +====================== + +Many Magit commands are implemented as *transient* commands. First the +user invokes a *prefix* command, which causes its *infix* arguments and +*suffix* commands to be displayed in the echo area. The user then +optionally sets some infix arguments and finally invokes one of the +suffix commands. + + This is implemented in the library ‘transient’. Earlier Magit +releases used the package ‘magit-popup’ and even earlier versions +library ‘magit-key-mode’. + + Transient is documented in *note (transient)Top::. + +‘C-x M-g’ (‘magit-dispatch’) +‘C-c g’ (‘magit-dispatch’) + This transient prefix command binds most of Magit’s other prefix + commands as suffix commands and displays them in a temporary buffer + until one of them is invoked. Invoking such a sub-prefix causes + the suffixes of that command to be bound and displayed instead of + those of ‘magit-dispatch’. + + This command is also, or especially, useful outside Magit buffers, + so Magit by default binds it to ‘C-c M-g’ in the global keymap. + ‘C-c g’ would be a better binding, but we cannot use that by + default, because that key sequence is reserved for the user. See + *note Global Bindings:: to learn more default and recommended key + bindings. + + +File: magit.info, Node: Transient Arguments and Buffer Variables, Next: Completion Confirmation and the Selection, Prev: Transient Commands, Up: Interface Concepts + +4.4 Transient Arguments and Buffer Variables +============================================ + +The infix arguments of many of Magit’s transient prefix commands cease +to have an effect once the ‘git’ command that is called with those +arguments has returned. Commands that create a commit are a good +example for this. If the user changes the arguments, then that only +affects the next invocation of a suffix command. If the same transient +prefix command is later invoked again, then the arguments are initially +reset to the default value. This default value can be set for the +current Emacs session or saved permanently, see *note (transient)Saving +Values::. It is also possible to cycle through previously used sets of +arguments using ‘C-M-p’ and ‘C-M-n’, see *note (transient)Using +History::. + + However the infix arguments of many other transient commands continue +to have an effect even after the ‘git’ command that was called with +those arguments has returned. The most important commands like this are +those that display a diff or log in a dedicated buffer. Their arguments +obviously continue to have an effect for as long as the respective diff +or log is being displayed. Furthermore the used arguments are stored in +buffer-local variables for future reference. + + For commands in the second group it isn’t always desirable to reset +their arguments to the global value when the transient prefix command is +invoked again. + + As mentioned above, it is possible to cycle through previously used +sets of arguments while a transient popup is visible. That means that +we could always reset the infix arguments to the default because the set +of arguments that is active in the existing buffer is only a few ‘C-M-p’ +away. Magit can be configured to behave like that, but because I expect +that most users would not find that very convenient, it is not the +default. + + Also note that it is possible to change the diff and log arguments +used in the current buffer (including the status buffer, which contains +both diff and log sections) using the respective "refresh" transient +prefix commands on ‘D’ and ‘L’. (‘d’ and ‘l’ on the other hand are +intended to change *what* diff or log is being displayed. It is +possible to also change *how* the diff or log is being displayed at the +same time, but if you only want to do the latter, then you should use +the refresh variants.) Because these secondary diff and log transient +prefixes are about *changing* the arguments used in the current buffer, +they *always* start out with the set of arguments that are currently in +effect in that buffer. + + Some commands are usually invoked directly even though they can also +be invoked as the suffix of a transient prefix command. Most +prominently ‘magit-show-commit’ is usually invoked by typing ‘RET’ while +point is on a commit in a log, but it can also be invoked from the +‘magit-diff’ transient prefix. + + When such a command is invoked directly, then it is important to +reuse the arguments as specified by the respective buffer-local values, +instead of using the default arguments. Imagine you press ‘RET’ in a +log to display the commit at point in a different buffer and then use +‘D’ to change how the diff is displayed in that buffer. And then you +press ‘RET’ on another commit to show that instead and the diff +arguments are reset to the default. Not cool; so Magit does not do that +by default. + + -- User Option: magit-prefix-use-buffer-arguments + This option controls whether the infix arguments initially shown in + certain transient prefix commands are based on the arguments that + are currently in effect in the buffer that their suffixes update. + + The ‘magit-diff’ and ‘magit-log’ transient prefix commands are + affected by this option. + + -- User Option: magit-direct-use-buffer-arguments + This option controls whether certain commands, when invoked + directly (i.e., not as the suffix of a transient prefix command), + use the arguments that are currently active in the buffer that they + are about to update. The alternative is to use the default value + for these arguments, which might change the arguments that are used + in the buffer. + +Valid values for both of the above options are: + + • ‘always’: Always use the set of arguments that is currently active + in the respective buffer, provided that buffer exists of course. + • ‘selected’ or ‘t’: Use the set of arguments from the respective + buffer, but only if it is displayed in a window of the current + frame. This is the default for both variables. + • ‘current’: Use the set of arguments from the respective buffer, but + only if it is the current buffer. + • ‘never’: Never use the set of arguments from the respective buffer. + +I am afraid it gets more complicated still: + + • The global diff and log arguments are set for each supported mode + individually. The diff arguments for example have different values + in ‘magit-diff-mode’, ‘magit-revision-mode’, + ‘magit-merge-preview-mode’ and ‘magit-status-mode’ buffers. + Setting or saving the value for one mode does not change the value + for other modes. The history however is shared. + + • When ‘magit-show-commit’ is invoked directly from a log buffer, + then the file filter is picked up from that buffer, not from the + revision buffer or the mode’s global diff arguments. + + • Even though they are suffixes of the diff prefix + ‘magit-show-commit’ and ‘magit-stash-show’ do not use the diff + buffer used by the diff commands, instead they use the dedicated + revision and stash buffers. + + At the time you invoke the diff prefix it is unknown to Magit which + of the suffix commands you are going to invoke. While not certain, + more often than not users invoke one of the commands that use the + diff buffer, so the initial infix arguments are those used in that + buffer. However if you invoke one of these commands directly, then + Magit knows that it should use the arguments from the revision + resp. stash buffer. + + • The log prefix also features reflog commands, but these commands do + not use the log arguments. + + • If ‘magit-show-refs’ is invoked from a ‘magit-refs-mode’ buffer, + then it acts as a refresh prefix and therefore unconditionally uses + the buffer’s arguments as initial arguments. If it is invoked + elsewhere with a prefix argument, then it acts as regular prefix + and therefore respects ‘magit-prefix-use-buffer-arguments’. If it + is invoked elsewhere without a prefix argument, then it acts as a + direct command and therefore respects + ‘magit-direct-use-buffer-arguments’. + + +File: magit.info, Node: Completion Confirmation and the Selection, Next: Mouse Support, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts + +4.5 Completion, Confirmation and the Selection +============================================== + +* Menu: + +* Action Confirmation:: +* Completion and Confirmation:: +* The Selection:: +* The hunk-internal region:: +* Support for Completion Frameworks:: +* Additional Completion Options:: + + +File: magit.info, Node: Action Confirmation, Next: Completion and Confirmation, Up: Completion Confirmation and the Selection + +4.5.1 Action Confirmation +------------------------- + +By default many actions that could potentially lead to data loss have to +be confirmed. This includes many very common actions, so this can +quickly become annoying. Many of these actions can be undone and if you +have thought about how to undo certain mistakes, then it should be safe +to disable confirmation for the respective actions. + + The option ‘magit-no-confirm’ can be used to tell Magit to perform +certain actions without the user having to confirm them. Note that +while this option can only be used to disable confirmation for a +specific set of actions, the next section explains another way of +telling Magit to ask fewer questions. + + -- User Option: magit-no-confirm + The value of this option is a list of symbols, representing actions + that do not have to be confirmed by the user before being carried + out. + + By default many potentially dangerous commands ask the user for + confirmation. Each of the below symbols stands for an action + which, when invoked unintentionally or without being fully aware of + the consequences, could lead to tears. In many cases there are + several commands that perform variations of a certain action, so we + don’t use the command names but more generic symbols. + + • Applying changes: + + • ‘discard’ Discarding one or more changes (i.e., hunks or + the complete diff for a file) loses that change, + obviously. + + • ‘reverse’ Reverting one or more changes can usually be + undone by reverting the reversion. + + • ‘stage-all-changes’, ‘unstage-all-changes’ When there are + both staged and unstaged changes, then un-/staging + everything would destroy that distinction. Of course + that also applies when un-/staging a single change, but + then less is lost and one does that so often that having + to confirm every time would be unacceptable. + + • Files: + + • ‘delete’ When a file that isn’t yet tracked by Git is + deleted, then it is completely lost, not just the last + changes. Very dangerous. + + • ‘trash’ Instead of deleting a file it can also be move to + the system trash. Obviously much less dangerous than + deleting it. + + Also see option ‘magit-delete-by-moving-to-trash’. + + • ‘resurrect’ A deleted file can easily be resurrected by + "deleting" the deletion, which is done using the same + command that was used to delete the same file in the + first place. + + • ‘untrack’ Untracking a file can be undone by tracking it + again. + + • ‘rename’ Renaming a file can easily be undone. + + • Sequences: + + • ‘reset-bisect’ Aborting (known to Git as "resetting") a + bisect operation loses all information collected so far. + + • ‘abort-cherry-pick’ Aborting a cherry-pick throws away + all conflict resolutions which have already been carried + out by the user. + + • ‘abort-revert’ Aborting a revert throws away all conflict + resolutions which have already been carried out by the + user. + + • ‘abort-rebase’ Aborting a rebase throws away all already + modified commits, but it’s possible to restore those from + the reflog. + + • ‘abort-merge’ Aborting a merge throws away all conflict + resolutions which have already been carried out by the + user. + + • ‘merge-dirty’ Merging with a dirty worktree can make it + hard to go back to the state before the merge was + initiated. + + • References: + + • ‘delete-unmerged-branch’ Once a branch has been deleted, + it can only be restored using low-level recovery tools + provided by Git. And even then the reflog is gone. The + user always has to confirm the deletion of a branch by + accepting the default choice (or selecting another + branch), but when a branch has not been merged yet, also + make sure the user is aware of that. + + • ‘delete-pr-remote’ When deleting a branch that was + created from a pull-request and if no other branches + still exist on that remote, then ‘magit-branch-delete’ + offers to delete the remote as well. This should be safe + because it only happens if no other refs exist in the + remotes namespace, and you can recreate the remote if + necessary. + + • ‘drop-stashes’ Dropping a stash is dangerous because Git + stores stashes in the reflog. Once a stash is removed, + there is no going back without using low-level recovery + tools provided by Git. When a single stash is dropped, + then the user always has to confirm by accepting the + default (or selecting another). This action only + concerns the deletion of multiple stashes at once. + + • Publishing: + + • ‘set-and-push’ When pushing to the upstream or the + push-remote and that isn’t actually configured yet, then + the user can first set the target. If s/he confirms the + default too quickly, then s/he might end up pushing to + the wrong branch and if the remote repository is + configured to disallow fixing such mistakes, then that + can be quite embarrassing and annoying. + + • Edit published history: + + Without adding these symbols here, you will be warned before + editing commits that have already been pushed to one of the + branches listed in ‘magit-published-branches’. + + • ‘amend-published’ Affects most commands that amend to + "HEAD". + + • ‘rebase-published’ Affects commands that perform + interactive rebases. This includes commands from the + commit transient that modify a commit other than "HEAD", + namely the various fixup and squash variants. + + • ‘edit-published’ Affects the commands + ‘magit-edit-line-commit’ and + ‘magit-diff-edit-hunk-commit’. These two commands make + it quite easy to accidentally edit a published commit, so + you should think twice before configuring them not to ask + for confirmation. + + To disable confirmation completely, add all three symbols here + or set ‘magit-published-branches’ to ‘nil’. + + • Various: + + • ‘stash-apply-3way’ When a stash cannot be applied using + ‘git stash apply’, then Magit uses ‘git apply’ instead, + possibly using the ‘--3way’ argument, which isn’t always + perfectly safe. See also ‘magit-stash-apply’. + + • ‘kill-process’ There seldom is a reason to kill a + process. + + • Global settings: + + Instead of adding all of the above symbols to the value of + this option, you can also set it to the atom ‘t’, which has + the same effect as adding all of the above symbols. Doing + that most certainly is a bad idea, especially because other + symbols might be added in the future. So even if you don’t + want to be asked for confirmation for any of these actions, + you are still better of adding all of the respective symbols + individually. + + When ‘magit-wip-before-change-mode’ is enabled, then the + following actions can be undone fairly easily: ‘discard’, + ‘reverse’, ‘stage-all-changes’, and ‘unstage-all-changes’. If + and only if this mode is enabled, then ‘safe-with-wip’ has the + same effect as adding all of these symbols individually. + + +File: magit.info, Node: Completion and Confirmation, Next: The Selection, Prev: Action Confirmation, Up: Completion Confirmation and the Selection + +4.5.2 Completion and Confirmation +--------------------------------- + +Many Magit commands ask the user to select from a list of possible +things to act on, while offering the most likely choice as the default. +For many of these commands the default is the thing at point, provided +that it actually is a valid thing to act on. For many commands that act +on a branch, the current branch serves as the default if there is no +branch at point. + + These commands combine asking for confirmation and asking for a +target to act on into a single action. The user can confirm the default +target using ‘RET’ or abort using ‘C-g’. This is similar to a +‘y-or-n-p’ prompt, but the keys to confirm or abort differ. + + At the same time the user is also given the opportunity to select +another target, which is useful because for some commands and/or in some +situations you might want to select the action before selecting the +target by moving to it. + + However you might find that for some commands you always want to use +the default target, if any, or even that you want the command to act on +the default without requiring any confirmation at all. The option +‘magit-dwim-selection’ can be used to configure certain commands to that +effect. + + Note that when the region is active then many commands act on the +things that are selected using a mechanism based on the region, in many +cases after asking for confirmation. This region-based mechanism is +called the "selection" and is described in detail in the next section. +When a selection exists that is valid for the invoked command, then that +command never offers to act on something else, and whether it asks for +confirmation is not controlled by this option. + + Also note that Magit asks for confirmation of certain actions that +are not coupled with completion (or the selection). Such dialogs are +also not affected by this option and are described in the previous +section. + + -- User Option: magit-dwim-selection + This option can be used to tell certain commands to use the thing at +point instead of asking the user to select a candidate to act on, with +or without confirmation. + + The value has the form ‘((COMMAND nil|PROMPT DEFAULT)...)’. + + • COMMAND is the command that should not prompt for a choice. To + have an effect, the command has to use the function + ‘magit-completing-read’ or a utility function which in turn uses + that function. + + • If the command uses ‘magit-completing-read’ multiple times, then + PROMPT can be used to only affect one of these uses. PROMPT, if + non-nil, is a regular expression that is used to match against the + PROMPT argument passed to ‘magit-completing-read’. + + • DEFAULT specifies how to use the default. If it is ‘t’, then the + DEFAULT argument passed to ‘magit-completing-read’ is used without + confirmation. If it is ‘ask’, then the user is given a chance to + abort. DEFAULT can also be ‘nil’, in which case the entry has no + effect. + + +File: magit.info, Node: The Selection, Next: The hunk-internal region, Prev: Completion and Confirmation, Up: Completion Confirmation and the Selection + +4.5.3 The Selection +------------------- + +If the region is active, then many Magit commands act on the things that +are selected using a mechanism based on the region instead of one single +thing. When the region is not active, then these commands act on the +thing at point or read a single thing to act on. This is described in +the previous section — this section only covers how multiple things are +selected, how that is visualized, and how certain commands behave when +that is the case. + + Magit’s mechanism for selecting multiple things, or rather sections +that represent these things, is based on the Emacs region, but the area +that Magit considers to be selected is typically larger than the region +and additional restrictions apply. + + Magit makes a distinction between a region that qualifies as forming +a valid Magit selection and a region that does not. If the region does +not qualify, then it is displayed as it is in other Emacs buffers. If +the region does qualify as a Magit selection, then the selection is +always visualized, while the region itself is only visualized if it +begins and ends on the same line. + + For a region to qualify as a Magit selection, it must begin in the +heading of one section and end in the heading of a sibling section. +Note that if the end of the region is at the very beginning of section +heading (i.e., at the very beginning of a line) then that section is +considered to be *inside* the selection. + + This is not consistent with how the region is normally treated in +Emacs — if the region ends at the beginning of a line, then that line is +outside the region. Due to how Magit visualizes the selection, it +should be obvious that this difference exists. + + Not every command acts on every valid selection. Some commands do +not even consider the location of point, others may act on the section +at point but not support acting on the selection, and even commands that +do support the selection of course only do so if it selects things that +they can act on. + + This is the main reason why the selection must include the section at +point. Even if a selection exists, the invoked command may disregard +it, in which case it may act on the current section only. It is much +safer to only act on the current section but not the other selected +sections than it is to act on the current section *instead* of the +selected sections. The latter would be much more surprising and if the +current section always is part of the selection, then that cannot +happen. + + -- Variable: magit-keep-region-overlay + This variable controls whether the region is visualized as usual + even when a valid Magit selection or a hunk-internal region exists. + See the doc-string for more information. + + +File: magit.info, Node: The hunk-internal region, Next: Support for Completion Frameworks, Prev: The Selection, Up: Completion Confirmation and the Selection + +4.5.4 The hunk-internal region +------------------------------ + +Somewhat related to the Magit selection described in the previous +section is the hunk-internal region. + + Like the selection, the hunk-internal region is based on the Emacs +region but causes that region to not be visualized as it would in other +Emacs buffers, and includes the line on which the region ends even if it +ends at the very beginning of that line. + + Unlike the selection, which is based on a region that must begin in +the heading of one section and ends in the section of a sibling section, +the hunk-internal region must begin inside the *body* of a hunk section +and end in the body of the *same* section. + + The hunk-internal region is honored by "apply" commands, which can, +among other targets, act on a hunk. If the hunk-internal region is +active, then such commands act only on the marked part of the hunk +instead of on the complete hunk. + + +File: magit.info, Node: Support for Completion Frameworks, Next: Additional Completion Options, Prev: The hunk-internal region, Up: Completion Confirmation and the Selection + +4.5.5 Support for Completion Frameworks +--------------------------------------- + +The built-in option ‘completing-read-function’ specifies the low-level +function used by ‘completing-read’ to ask a user to select from a list +of choices. Its default value is ‘completing-read-default’. +Alternative completion frameworks typically activate themselves by +substituting their own implementation. + + Mostly for historic reasons Magit provides a similar option named +‘magit-completing-read-function’, which only controls the low-level +function used by ‘magit-completing-read’. This option also makes it +possible to use a different completing mechanism for Magit than for the +rest of Emacs, but doing that is not recommend. + + You most likely don’t have to customize the magit-specific option to +use an alternative completion framework. For example, if you enable +‘ivy-mode’, then Magit will respect that, and if you enable ‘helm-mode’, +then you are done too. + + However if you want to use Ido, then ‘ido-mode’ won’t do the trick. +You will also have to install the ‘ido-completing-read+’ package and use +‘magit-ido-completing-read’ as ‘magit-completing-read-function’. + + -- User Option: magit-completing-read-function + The value of this variable is the low-level function used to + perform completion by code that uses ‘magit-completing-read’ (as + opposed to the built-in ‘completing-read’). + + The default value, ‘magit-builtin-completing-read’, is suitable for + the standard completion mechanism, ‘ivy-mode’, and ‘helm-mode’ at + least. + + The built-in ‘completing-read’ and ‘completing-read-default’ are + *not* suitable to be used here. ‘magit-builtin-completing-read’ + performs some additional work, and any function used in its place + has to do the same. + + -- Function: magit-builtin-completing-read prompt choices &optional + predicate require-match initial-input hist def + This function performs completion using the built-in + ‘completing-read’ and does some additional magit-specific work. + + -- Function: magit-ido-completing-read prompt choices &optional + predicate require-match initial-input hist def + This function performs completion using ‘ido-completing-read+’ from + the package by the same name (which you have to explicitly install) + and does some additional magit-specific work. + + We have to use ‘ido-completing-read+’ instead of the + ‘ido-completing-read’ that comes with Ido itself, because the + latter, while intended as a drop-in replacement, cannot serve that + purpose because it violates too many of the implicit conventions. + + -- Function: magit-completing-read prompt choices &optional predicate + require-match initial-input hist def fallback + This is the function that Magit commands use when they need the + user to select a single thing to act on. The arguments have the + same meaning as for ‘completing-read’, except for FALLBACK, which + is unique to this function and is described below. + + Instead of asking the user to choose from a list of possible + candidates, this function may just return the default specified by + DEF, with or without requiring user confirmation. Whether that is + the case depends on PROMPT, ‘this-command’ and + ‘magit-dwim-selection’. See the documentation of the latter for + more information. + + If it does read a value in the minibuffer, then this function acts + similar to ‘completing-read’, except for the following: + + • COLLECTION must be a list of choices. A function is not + supported. + + • If REQUIRE-MATCH is ‘nil’ and the user exits without a choice, + then ‘nil’ is returned instead of an empty string. + + • If REQUIRE-MATCH is non-nil and the users exits without a + choice, an user-error is raised. + + • FALLBACK specifies a secondary default that is only used if + the primary default DEF is ‘nil’. The secondary default is + not subject to ‘magit-dwim-selection’ — if DEF is ‘nil’ but + FALLBACK is not, then this function always asks the user to + choose a candidate, just as if both defaults were ‘nil’. + + • ‘format-prompt’ is called on PROMPT and DEF (or FALLBACK if + DEF is ‘nil’). This appends ": " to the prompt and may also + add the default to the prompt, using the format specified by + ‘minibuffer-default-prompt-format’ and depending on + ‘magit-completing-read-default-prompt-predicate’. + + +File: magit.info, Node: Additional Completion Options, Prev: Support for Completion Frameworks, Up: Completion Confirmation and the Selection + +4.5.6 Additional Completion Options +----------------------------------- + + -- User Option: magit-list-refs-sortby + For many commands that read a ref or refs from the user, the value + of this option can be used to control the order of the refs. Valid + values include any key accepted by the ‘--sort’ flag of ‘git + for-each-ref’. By default, refs are sorted alphabetically by their + full name (e.g., "refs/heads/master"). + + +File: magit.info, Node: Mouse Support, Next: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts + +4.6 Mouse Support +================= + +Double clicking on a section heading toggles the visibility of its body, +if any. Likewise clicking in the left fringe toggles the visibility of +the appropriate section. + + A context menu is provided but has to be enabled explicitly. In +Emacs 28 and greater, enable the global mode ‘context-menu-mode’. If +you use an older Emacs release, set +‘magit-section-show-context-menu-for-emacs<28’. + + +File: magit.info, Node: Running Git, Prev: Mouse Support, Up: Interface Concepts + +4.7 Running Git +=============== + +* Menu: + +* Viewing Git Output:: +* Git Process Status:: +* Running Git Manually:: +* Git Executable:: +* Global Git Arguments:: + + +File: magit.info, Node: Viewing Git Output, Next: Git Process Status, Up: Running Git + +4.7.1 Viewing Git Output +------------------------ + +Magit runs Git either for side-effects (e.g., when pushing) or to get +some value (e.g., the name of the current branch). + + When Git is run for side-effects, the process output is logged in a +per-repository log buffer, which can be consulted using the +‘magit-process’ command when things don’t go as expected. + + The output/errors for up to ‘magit-process-log-max’ Git commands are +retained. + +‘$’ (‘magit-process’) + This commands displays the process buffer for the current + repository. + + Inside that buffer, the usual key bindings for navigating and showing +sections are available. There is one additional command. + +‘k’ (‘magit-process-kill’) + This command kills the process represented by the section at point. + + -- Variable: magit-git-debug + This option controls whether additional reporting of git errors is + enabled. + + Magit basically calls git for one of these two reasons: for + side-effects or to do something with its standard output. + + When git is run for side-effects then its output, including error + messages, go into the process buffer which is shown when using ‘$’. + + When git’s output is consumed in some way, then it would be too + expensive to also insert it into this buffer, but when this option + is non-nil and git returns with a non-zero exit status, then at + least its standard error is inserted into this buffer. + + This is only intended for debugging purposes. Do not enable this + permanently, that would negatively affect performance. + + This is only intended for debugging purposes. Do not enable this + permanently, that would negatively affect performance. Also note + that just because git exits with a non-zero exit status and prints + an error message that usually doesn’t mean that it is an error as + far as Magit is concerned, which is another reason we usually hide + these error messages. Whether some error message is relevant in + the context of some unexpected behavior has to be judged on a case + by case basis. + + The command ‘magit-toggle-git-debug’ changes the value of this + variable. + + -- Variable: magit-process-extreme-logging + This option controls whether ‘magit-process-file’ logs to the + ‘*Messages*’ buffer. + + Only intended for temporary use when you try to figure out how + Magit uses Git behind the scene. Output that normally goes to the + magit-process buffer continues to go there. Not all output goes to + either of these two buffers. + + +File: magit.info, Node: Git Process Status, Next: Running Git Manually, Prev: Viewing Git Output, Up: Running Git + +4.7.2 Git Process Status +------------------------ + +When a Git process is running for side-effects, Magit displays an +indicator in the mode line, using the ‘magit-mode-line-process’ face. + + If the Git process exits successfully, the process indicator is +removed from the mode line immediately. + + In the case of a Git error, the process indicator is not removed, but +is instead highlighted with the ‘magit-mode-line-process-error’ face, +and the error details from the process buffer are provided as a tooltip +for mouse users. This error indicator persists in the mode line until +the next magit buffer refresh. + + If you do not wish process errors to be indicated in the mode line, +customize the ‘magit-process-display-mode-line-error’ user option. + + Process errors are additionally indicated at the top of the status +buffer. + + +File: magit.info, Node: Running Git Manually, Next: Git Executable, Prev: Git Process Status, Up: Running Git + +4.7.3 Running Git Manually +-------------------------- + +While Magit provides many Emacs commands to interact with Git, it does +not cover everything. In those cases your existing Git knowledge will +come in handy. Magit provides some commands for running arbitrary Git +commands by typing them into the minibuffer, instead of having to switch +to a shell. + +‘!’ (‘magit-run’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘! !’ (‘magit-git-command-topdir’) + This command reads a command from the user and executes it in the + top-level directory of the current working tree. + + The string "git " is used as initial input when prompting the user + for the command. It can be removed to run another command. + +‘:’ (‘magit-git-command’) +‘! p’ + This command reads a command from the user and executes it in + ‘default-directory’. With a prefix argument the command is + executed in the top-level directory of the current working tree + instead. + + The string "git " is used as initial input when prompting the user + for the command. It can be removed to run another command. + +‘! s’ (‘magit-shell-command-topdir’) + This command reads a command from the user and executes it in the + top-level directory of the current working tree. + +‘! S’ (‘magit-shell-command’) + This command reads a command from the user and executes it in + ‘default-directory’. With a prefix argument the command is + executed in the top-level directory of the current working tree + instead. + + -- User Option: magit-shell-command-verbose-prompt + Whether the prompt, used by the above commands when reading a shell + command, shows the directory in which it will be run. + + These suffix commands start external gui tools. + +‘! k’ (‘magit-run-gitk’) + This command runs ‘gitk’ in the current repository. + +‘! a’ (‘magit-run-gitk-all’) + This command runs ‘gitk --all’ in the current repository. + +‘! b’ (‘magit-run-gitk-branches’) + This command runs ‘gitk --branches’ in the current repository. + +‘! g’ (‘magit-run-git-gui’) + This command runs ‘git gui’ in the current repository. + +‘! m’ (‘magit-git-mergetool’) + This command runs ‘git mergetool --gui’ in the current repository. + + With a prefix argument this acts as a transient prefix command, + allowing the user to select the mergetool and change some settings. + + +File: magit.info, Node: Git Executable, Next: Global Git Arguments, Prev: Running Git Manually, Up: Running Git + +4.7.4 Git Executable +-------------------- + +When Magit calls Git, then it may do so using the absolute path to the +‘git’ executable, or using just its name. + + When running ‘git’ locally and the ‘system-type’ is ‘windows-nt’ (any +Windows version) or ‘darwin’ (macOS) then ‘magit-git-executable’ is set +to an absolute path when Magit is loaded. + + On Windows it is necessary to use an absolute path because Git comes +with several wrapper scripts for the actual ‘git’ binary, which are also +placed on ‘$PATH’, and using one of these wrappers instead of the binary +would degrade performance horribly. For some macOS users using just the +name of the executable also performs horribly, so we avoid doing that on +that platform as well. On other platforms, using just the name seems to +work just fine. + + Using an absolute path when running ‘git’ on a remote machine over +Tramp, would be problematic to use an absolute path that is suitable on +the local machine, so a separate option is used to control the name or +path that is used on remote machines. + + -- User Option: magit-git-executable + The ‘git’ executable used by Magit on the local host. This should + be either the absolute path to the executable, or the string "git" + to let Emacs find the executable itself, using the standard + mechanism for doing such things. + + -- User Option: magit-remote-git-executable + The ‘git’ executable used by Magit on remote machines over Tramp. + Normally this should be just the string "git". Consider + customizing ‘tramp-remote-path’ instead of this option. + + If Emacs is unable to find the correct executable, then you can work +around that by explicitly setting the value of one of these two options. +Doing that should be considered a kludge; it is better to make sure that +the order in ‘exec-path’ or ‘tramp-remote-path’ is correct. + + Note that ‘exec-path’ is set based on the value of the ‘PATH’ +environment variable that is in effect when Emacs is started. If you +set ‘PATH’ in your shell’s init files, then that only has an effect on +Emacs if you start it from that shell (because the environment of a +process is only passed to its child processes, not to arbitrary other +processes). If that is not how you start Emacs, then the +‘exec-path-from-shell’ package can help; though honestly I consider that +a kludge too. + + The command ‘magit-debug-git-executable’ can be useful to find out +where Emacs is searching for ‘git’. + +‘M-x magit-debug-git-executable’ + This command displays a buffer with information about + ‘magit-git-executable’ and ‘magit-remote-git-executable’. + +‘M-x magit-version’ + This command shows the currently used versions of Magit, Git, and + Emacs in the echo area. Non-interactively this just returns the + Magit version. + + +File: magit.info, Node: Global Git Arguments, Prev: Git Executable, Up: Running Git + +4.7.5 Global Git Arguments +-------------------------- + + -- User Option: magit-git-global-arguments + The arguments set here are used every time the git executable is + run as a subprocess. They are placed right after the executable + itself and before the git command - as in ‘git HERE... COMMAND + REST’. For valid arguments see *note (gitman)git::. + + Be careful what you add here, especially if you are using Tramp to + connect to servers with ancient Git versions. Never remove + anything that is part of the default value, unless you really know + what you are doing. And think very hard before adding something; + it will be used every time Magit runs Git for any purpose. + + +File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface Concepts, Up: Top + +5 Inspecting +************ + +The functionality provided by Magit can be roughly divided into three +groups: inspecting existing data, manipulating existing data or adding +new data, and transferring data. Of course that is a rather crude +distinction that often falls short, but it’s more useful than no +distinction at all. This section is concerned with inspecting data, the +next two with manipulating and transferring it. Then follows a section +about miscellaneous functionality, which cannot easily be fit into this +distinction. + + Of course other distinctions make sense too, e.g., Git’s distinction +between porcelain and plumbing commands, which for the most part is +equivalent to Emacs’ distinction between interactive commands and +non-interactive functions. All of the sections mentioned before are +mainly concerned with the porcelain – Magit’s plumbing layer is +described later. + +* Menu: + +* Status Buffer:: +* Repository List:: +* Logging:: +* Diffing:: +* Ediffing:: +* References Buffer:: +* Bisecting:: +* Visiting Files and Blobs:: +* Blaming:: + + +File: magit.info, Node: Status Buffer, Next: Repository List, Up: Inspecting + +5.1 Status Buffer +================= + +While other Magit buffers contain, e.g., one particular diff or one +particular log, the status buffer contains the diffs for staged and +unstaged changes, logs for unpushed and unpulled commits, lists of +stashes and untracked files, and information related to the current +branch. + + During certain incomplete operations – for example when a merge +resulted in a conflict – additional information is displayed that helps +proceeding with or aborting the operation. + + The command ‘magit-status’ displays the status buffer belonging to +the current repository in another window. This command is used so often +that it should be bound globally. We recommend using ‘C-x g’: + + (global-set-key (kbd "C-x g") 'magit-status) + +‘C-x g’ (‘magit-status’) + When invoked from within an existing Git repository, then this + command shows the status of that repository in a buffer. + + If the current directory isn’t located within a Git repository, + then this command prompts for an existing repository or an + arbitrary directory, depending on the option + ‘magit-repository-directories’, and the status for the selected + repository is shown instead. + + • If that option specifies any existing repositories, then the + user is asked to select one of them. + + • Otherwise the user is asked to select an arbitrary directory + using regular file-name completion. If the selected directory + is the top-level directory of an existing working tree, then + the status buffer for that is shown. + + • Otherwise the user is offered to initialize the selected + directory as a new repository. After creating the repository + its status buffer is shown. + + These fallback behaviors can also be forced using one or more + prefix arguments: + + • With two prefix arguments (or more precisely a numeric prefix + value of 16 or greater) an arbitrary directory is read, which + is then acted on as described above. The same could be + accomplished using the command ‘magit-init’. + + • With a single prefix argument an existing repository is read + from the user, or if no repository can be found based on the + value of ‘magit-repository-directories’, then the behavior is + the same as with two prefix arguments. + + -- User Option: magit-repository-directories + List of directories that are Git repositories or contain Git + repositories. + + Each element has the form ‘(DIRECTORY . DEPTH)’. DIRECTORY has to + be a directory or a directory file-name, a string. DEPTH, an + integer, specifies the maximum depth to look for Git repositories. + If it is 0, then only add DIRECTORY itself. + + This option controls which repositories are being listed by + ‘magit-list-repositories’. It also affects ‘magit-status’ (which + see) in potentially surprising ways (see above). + + -- Command: magit-status-quick + This command is an alternative to ‘magit-status’ that usually + avoids refreshing the status buffer. + + If the status buffer of the current Git repository exists but isn’t + being displayed in the selected frame, then it is displayed without + being refreshed. + + If the status buffer is being displayed in the selected frame, then + this command refreshes it. + + Prefix arguments have the same meaning as for ‘magit-status’, and + additionally cause the buffer to be refresh. + + To use this command add this to your init file: + + (global-set-key (kbd "C-x g") 'magit-status-quick). + + If you do that and then for once want to redisplay the buffer and + also immediately refresh it, then type ‘C-x g’ followed by ‘g’. + + A possible alternative command is + ‘magit-display-repository-buffer’. It supports displaying any + existing Magit buffer that belongs to the current repository; not + just the status buffer. + + -- Command: ido-enter-magit-status + From an Ido prompt used to open a file, instead drop into + ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which, + despite its name, usually causes a Dired buffer to be created. + + To make this command available, use something like: + + (add-hook 'ido-setup-hook + (lambda () + (define-key ido-completion-map + (kbd \"C-x g\") 'ido-enter-magit-status))) + + Starting with Emacs 25.1 the Ido keymaps are defined just once + instead of every time Ido is invoked, so now you can modify it like + pretty much every other keymap: + + (define-key ido-common-completion-map + (kbd \"C-x g\") 'ido-enter-magit-status) + +* Menu: + +* Status Sections:: +* Status Header Sections:: +* Status Module Sections:: +* Status Options:: + + +File: magit.info, Node: Status Sections, Next: Status Header Sections, Up: Status Buffer + +5.1.1 Status Sections +--------------------- + +The contents of status buffers is controlled using the hook +‘magit-status-sections-hook’. See *note Section Hooks:: to learn about +such hooks and how to customize them. + + -- User Option: magit-status-sections-hook + Hook run to insert sections into a status buffer. + + The first function on that hook by default is +‘magit-insert-status-headers’; it is described in the next section. By +default the following functions are also members of that hook: + + -- Function: magit-insert-merge-log + Insert section for the on-going merge. Display the heads that are + being merged. If no merge is in progress, do nothing. + + -- Function: magit-insert-rebase-sequence + Insert section for the on-going rebase sequence. If no such + sequence is in progress, do nothing. + + -- Function: magit-insert-am-sequence + Insert section for the on-going patch applying sequence. If no + such sequence is in progress, do nothing. + + -- Function: magit-insert-sequencer-sequence + Insert section for the on-going cherry-pick or revert sequence. If + no such sequence is in progress, do nothing. + + -- Function: magit-insert-bisect-output + While bisecting, insert section with output from ‘git bisect’. + + -- Function: magit-insert-bisect-rest + While bisecting, insert section visualizing the bisect state. + + -- Function: magit-insert-bisect-log + While bisecting, insert section logging bisect progress. + + -- Function: magit-insert-untracked-files + Maybe insert a list or tree of untracked files. + + Do so depending on the value of ‘status.showUntrackedFiles’. Note + that even if the value is ‘all’, Magit still initially only shows + directories. But the directory sections can then be expanded using + ‘TAB’. + + -- Function: magit-insert-unstaged-changes + Insert section showing unstaged changes. + + -- Function: magit-insert-staged-changes + Insert section showing staged changes. + + -- Function: magit-insert-stashes &optional ref heading + Insert the ‘stashes’ section showing reflog for "refs/stash". If + optional REF is non-nil show reflog for that instead. If optional + HEADING is non-nil use that as section heading instead of + "Stashes:". + + -- Function: magit-insert-unpulled-from-upstream + Insert section showing commits that haven’t been pulled from the + upstream branch yet. + + -- Function: magit-insert-unpulled-from-pushremote + Insert section showing commits that haven’t been pulled from the + push-remote branch yet. + + -- Function: magit-insert-unpushed-to-upstream + Insert section showing commits that haven’t been pushed to the + upstream yet. + + -- Function: magit-insert-unpushed-to-pushremote + Insert section showing commits that haven’t been pushed to the + push-remote yet. + + The following functions can also be added to the above hook: + + -- Function: magit-insert-tracked-files + Insert a tree of tracked files. + + -- Function: magit-insert-ignored-files + Insert a tree of ignored files. Its possible to limit the logs in + the current buffer to a certain directory using ‘D = f <DIRECTORY> + RET g’. If you do that, then that that also affects this command. + + The log filter can be used to limit to multiple files. In that + case this function only respects the first of the files and only if + it is a directory. + + -- Function: magit-insert-skip-worktree-files + Insert a tree of skip-worktree files. If the first element of + ‘magit-buffer-diff-files’ is a directory, then limit the list to + files below that. The value of that variable can be set using ‘D + -- DIRECTORY RET g’. + + -- Function: magit-insert-assumed-unchanged-files + Insert a tree of files that are assumed to be unchanged. If the + first element of ‘magit-buffer-diff-files’ is a directory, then + limit the list to files below that. The value of that variable can + be set using ‘D -- DIRECTORY RET g’. + + -- Function: magit-insert-unpulled-or-recent-commits + Insert section showing unpulled or recent commits. If an upstream + is configured for the current branch and it is ahead of the current + branch, then show the missing commits. Otherwise, show the last + ‘magit-log-section-commit-count’ commits. + + -- Function: magit-insert-recent-commits + Insert section showing the last ‘magit-log-section-commit-count’ + commits. + + -- User Option: magit-log-section-commit-count + How many recent commits ‘magit-insert-recent-commits’ and + ‘magit-insert-unpulled-or-recent-commits’ (provided there are no + unpulled commits) show. + + -- Function: magit-insert-unpulled-cherries + Insert section showing unpulled commits. Like + ‘magit-insert-unpulled-commits’ but prefix each commit that has not + been applied yet (i.e., a commit with a patch-id not shared with + any local commit) with "+", and all others with "-". + + -- Function: magit-insert-unpushed-cherries + Insert section showing unpushed commits. Like + ‘magit-insert-unpushed-commits’ but prefix each commit which has + not been applied to upstream yet (i.e., a commit with a patch-id + not shared with any upstream commit) with "+" and all others with + "-". + + See *note References Buffer:: for some more section inserters, which +could be used here. + + +File: magit.info, Node: Status Header Sections, Next: Status Module Sections, Prev: Status Sections, Up: Status Buffer + +5.1.2 Status Header Sections +---------------------------- + +The contents of status buffers is controlled using the hook +‘magit-status-sections-hook’ (see *note Status Sections::). + + By default ‘magit-insert-status-headers’ is the first member of that +hook variable. + + -- Function: magit-insert-status-headers + Insert headers sections appropriate for ‘magit-status-mode’ + buffers. The sections are inserted by running the functions on the + hook ‘magit-status-headers-hook’. + + -- User Option: magit-status-headers-hook + Hook run to insert headers sections into the status buffer. + + This hook is run by ‘magit-insert-status-headers’, which in turn + has to be a member of ‘magit-status-sections-hook’ to be used at + all. + + By default the following functions are members of the above hook: + + -- Function: magit-insert-error-header + Insert a header line showing the message about the Git error that + just occurred. + + This function is only aware of the last error that occur when Git + was run for side-effects. If, for example, an error occurs while + generating a diff, then that error won’t be inserted. Refreshing + the status buffer causes this section to disappear again. + + -- Function: magit-insert-diff-filter-header + Insert a header line showing the effective diff filters. + + -- Function: magit-insert-head-branch-header + Insert a header line about the current branch or detached ‘HEAD’. + + -- Function: magit-insert-upstream-branch-header + Insert a header line about the branch that is usually pulled into + the current branch. + + -- Function: magit-insert-push-branch-header + Insert a header line about the branch that the current branch is + usually pushed to. + + -- Function: magit-insert-tags-header + Insert a header line about the current and/or next tag, along with + the number of commits between the tag and ‘HEAD’. + + The following functions can also be added to the above hook: + + -- Function: magit-insert-repo-header + Insert a header line showing the path to the repository top-level. + + -- Function: magit-insert-remote-header + Insert a header line about the remote of the current branch. + + If no remote is configured for the current branch, then fall back + showing the "origin" remote, or if that does not exist the first + remote in alphabetic order. + + -- Function: magit-insert-user-header + Insert a header line about the current user. + + +File: magit.info, Node: Status Module Sections, Next: Status Options, Prev: Status Header Sections, Up: Status Buffer + +5.1.3 Status Module Sections +---------------------------- + +The contents of status buffers is controlled using the hook +‘magit-status-sections-hook’ (see *note Status Sections::). + + By default ‘magit-insert-modules’ is _not_ a member of that hook +variable. + + -- Function: magit-insert-modules + Insert submodule sections. + + Hook ‘magit-module-sections-hook’ controls which module sections + are inserted, and option ‘magit-module-sections-nested’ controls + whether they are wrapped in an additional section. + + -- User Option: magit-module-sections-hook + Hook run by ‘magit-insert-modules’. + + -- User Option: magit-module-sections-nested + This option controls whether ‘magit-insert-modules’ wraps inserted + sections in an additional section. + + If this is non-nil, then only a single top-level section is + inserted. If it is nil, then all sections listed in + ‘magit-module-sections-hook’ become top-level sections. + + -- Function: magit-insert-modules-overview + Insert sections for all submodules. For each section insert the + path, the branch, and the output of ‘git describe --tags’, or, + failing that, the abbreviated HEAD commit hash. + + Press ‘RET’ on such a submodule section to show its own status + buffer. Press ‘RET’ on the "Modules" section to display a list of + submodules in a separate buffer. This shows additional information + not displayed in the super-repository’s status buffer. + + -- Function: magit-insert-modules-unpulled-from-upstream + Insert sections for modules that haven’t been pulled from the + upstream yet. These sections can be expanded to show the + respective commits. + + -- Function: magit-insert-modules-unpulled-from-pushremote + Insert sections for modules that haven’t been pulled from the + push-remote yet. These sections can be expanded to show the + respective commits. + + -- Function: magit-insert-modules-unpushed-to-upstream + Insert sections for modules that haven’t been pushed to the + upstream yet. These sections can be expanded to show the + respective commits. + + -- Function: magit-insert-modules-unpushed-to-pushremote + Insert sections for modules that haven’t been pushed to the + push-remote yet. These sections can be expanded to show the + respective commits. + + +File: magit.info, Node: Status Options, Prev: Status Module Sections, Up: Status Buffer + +5.1.4 Status Options +-------------------- + + -- User Option: magit-status-margin + This option specifies whether the margin is initially shown in + Magit-Status mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + Also see the proceeding section for more options concerning status +buffers. + + +File: magit.info, Node: Repository List, Next: Logging, Prev: Status Buffer, Up: Inspecting + +5.2 Repository List +=================== + + -- Command: magit-list-repositories + This command displays a list of repositories in a separate buffer. + + The option ‘magit-repository-directories’ controls which + repositories are displayed. + + -- User Option: magit-repolist-columns + This option controls what columns are displayed by the command + ‘magit-list-repositories’ and how they are displayed. + + Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. + + HEADER is the string displayed in the header. WIDTH is the width + of the column. FORMAT is a function that is called with one + argument, the repository identification (usually its basename), and + with ‘default-directory’ bound to the toplevel of its working tree. + It has to return a string to be inserted or nil. PROPS is an alist + that supports the keys ‘:right-align’, ‘:pad-right’ and ‘:sort’. + + The ‘:sort’ function has a weird interface described in the + docstring of ‘tabulated-list--get-sort’. Alternatively ‘<’ and + ‘magit-repolist-version<’ can be used as those functions are + automatically replaced with functions that satisfy the interface. + Set ‘:sort’ to ‘nil’ to inhibit sorting; if unspecified, then the + column is sortable using the default sorter. + + You may wish to display a range of numeric columns using just one + character per column and without any padding between columns, in + which case you should use an appropriate HEADER, set WIDTH to 1, + and set ‘:pad-right’ to 9. ‘+’ is substituted for numbers higher + than 9. + +The following functions can be added to the above option: + + -- Function: magit-repolist-column-ident + This function inserts the identification of the repository. + Usually this is just its basename. + + -- Function: magit-repolist-column-path + This function inserts the absolute path of the repository. + + -- Function: magit-repolist-column-version + This function inserts a description of the repository’s ‘HEAD’ + revision. + + -- Function: magit-repolist-column-branch + This function inserts the name of the current branch. + + -- Function: magit-repolist-column-upstream + This function inserts the name of the upstream branch of the + current branch. + + -- Function: magit-repolist-column-branches + This function inserts the number of branches. + + -- Function: magit-repolist-column-stashes + This function inserts the number of stashes. + + -- Function: magit-repolist-column-flag + This function inserts a flag as specified by + ‘magit-repolist-column-flag-alist’. + + By default this indicates whether there are uncommitted changes. + + • ‘N’ if there is at least one untracked file. + • ‘U’ if there is at least one unstaged file. + • ‘S’ if there is at least one staged file. + + Only the first one of these that applies is shown. + + -- Function: magit-repolist-column-flags + This functions insert all flags as specified by + ‘magit-repolist-column-flag-alist’. + + This is an alternative to function ‘magit-repolist-column-flag’, + which only lists the first one found. + + -- Function: magit-repolist-column-unpulled-from-upstream + This function inserts the number of upstream commits not in the + current branch. + + -- Function: magit-repolist-column-unpulled-from-pushremote + This function inserts the number of commits in the push branch but + not the current branch. + + -- Function: magit-repolist-column-unpushed-to-upstream + This function inserts the number of commits in the current branch + but not its upstream. + + -- Function: magit-repolist-column-unpushed-to-pushremote + This function inserts the number of commits in the current branch + but not its push branch. + +The following commands are available in repolist buffers: + +‘<RET>’ (‘magit-repolist-status’) + This command shows the status for the repository at point. + +‘m’ (‘magit-repolist-mark’) + This command marks the repository at point. + +‘u’ (‘magit-repolist-unmark’) + This command unmarks the repository at point. + +‘f’ (‘magit-repolist-fetch’) + This command fetches all marked repositories. If no repositories + are marked, then it offers to fetch all displayed repositories. + +‘5’ (‘magit-repolist-find-file-other-frame’) + This command reads a relative file-name (without completion) and + opens the respective file in each marked repository in a new frame. + If no repositories are marked, then it offers to do this for all + displayed repositories. + + +File: magit.info, Node: Logging, Next: Diffing, Prev: Repository List, Up: Inspecting + +5.3 Logging +=========== + +The status buffer contains logs for the unpushed and unpulled commits, +but that obviously isn’t enough. The transient prefix command +‘magit-log’, on ‘l’, features several suffix commands, which show a +specific log in a separate log buffer. + + Like other transient prefix commands, ‘magit-log’ also features +several infix arguments that can be changed before invoking one of the +suffix commands. However, in the case of the log transient, these +arguments may be taken from those currently in use in the current +repository’s log buffer, depending on the value of +‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and +Buffer Variables::). + + For information about the various arguments, see *note +(gitman)git-log::. + + The switch ‘++order=VALUE’ is converted to one of +‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being +passed to ‘git log’. + + The log transient also features several reflog commands. See *note +Reflog::. + +‘l’ (‘magit-log’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘l l’ (‘magit-log-current’) + Show log for the current branch. When ‘HEAD’ is detached or with a + prefix argument, show log for one or more revs read from the + minibuffer. + +‘l h’ (‘magit-log-head’) + Show log for ‘HEAD’. + +‘l u’ (‘magit-log-related’) + Show log for the current branch, its upstream and its push target. + When the upstream is a local branch, then also show its own + upstream. When ‘HEAD’ is detached, then show log for that, the + previously checked out branch and its upstream and push-target. + +‘l o’ (‘magit-log-other’) + Show log for one or more revs read from the minibuffer. The user + can input any revision or revisions separated by a space, or even + ranges, but only branches, tags, and a representation of the commit + at point are available as completion candidates. + +‘l L’ (‘magit-log-branches’) + Show log for all local branches and ‘HEAD’. + +‘l b’ (‘magit-log-all-branches’) + Show log for all local and remote branches and ‘HEAD’. + +‘l a’ (‘magit-log-all’) + Show log for all references and ‘HEAD’. + + Two additional commands that show the log for the file or blob that +is being visited in the current buffer exists, see *note Commands for +Buffers Visiting Files::. The command ‘magit-cherry’ also shows a log, +see *note Cherries::. + +* Menu: + +* Refreshing Logs:: +* Log Buffer:: +* Log Margin:: +* Select from Log:: +* Reflog:: +* Cherries:: + + +File: magit.info, Node: Refreshing Logs, Next: Log Buffer, Up: Logging + +5.3.1 Refreshing Logs +--------------------- + +The transient prefix command ‘magit-log-refresh’, on ‘L’, can be used to +change the log arguments used in the current buffer, without changing +which log is shown. This works in dedicated log buffers, but also in +the status buffer. + +‘L’ (‘magit-log-refresh’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘L g’ (‘magit-log-refresh’) + This suffix command sets the local log arguments for the current + buffer. + +‘L s’ (‘magit-log-set-default-arguments’) + This suffix command sets the default log arguments for buffers of + the same type as that of the current buffer. Other existing + buffers of the same type are not affected because their local + values have already been initialized. + +‘L w’ (‘magit-log-save-default-arguments’) + This suffix command sets the default log arguments for buffers of + the same type as that of the current buffer, and saves the value + for future sessions. Other existing buffers of the same type are + not affected because their local values have already been + initialized. + +‘L L’ (‘magit-toggle-margin’) + Show or hide the margin. + + +File: magit.info, Node: Log Buffer, Next: Log Margin, Prev: Refreshing Logs, Up: Logging + +5.3.2 Log Buffer +---------------- + +‘L’ (‘magit-log-refresh’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + See *note Refreshing Logs::. + +‘q’ (‘magit-log-bury-buffer’) + Bury the current buffer or the revision buffer in the same frame. + Like ‘magit-mode-bury-buffer’ (which see) but with a negative + prefix argument instead bury the revision buffer, provided it is + displayed in the current frame. + +‘C-c C-b’ (‘magit-go-backward’) + Move backward in current buffer’s history. + +‘C-c C-f’ (‘magit-go-forward’) + Move forward in current buffer’s history. + +‘C-c C-n’ (‘magit-log-move-to-parent’) + Move to a parent of the current commit. By default, this is the + first parent, but a numeric prefix can be used to specify another + parent. + +‘j’ (‘magit-log-move-to-revision’) + Read a revision and move to it in current log buffer. + + If the chosen reference or revision isn’t being displayed in the + current log buffer, then inform the user about that and do nothing + else. + + If invoked outside any log buffer, then display the log buffer of + the current repository first; creating it if necessary. + +‘<SPC>’ (‘magit-diff-show-or-scroll-up’) + Update the commit or diff buffer for the thing at point. + + Either show the commit or stash at point in the appropriate buffer, + or if that buffer is already being displayed in the current frame + and contains information about that commit or stash, then instead + scroll the buffer up. If there is no commit or stash at point, + then prompt for a commit. + +‘<DEL>’ (‘magit-diff-show-or-scroll-down’) + Update the commit or diff buffer for the thing at point. + + Either show the commit or stash at point in the appropriate buffer, + or if that buffer is already being displayed in the current frame + and contains information about that commit or stash, then instead + scroll the buffer down. If there is no commit or stash at point, + then prompt for a commit. + +‘=’ (‘magit-log-toggle-commit-limit’) + Toggle the number of commits the current log buffer is limited to. + If the number of commits is currently limited, then remove that + limit. Otherwise set it to 256. + +‘+’ (‘magit-log-double-commit-limit’) + Double the number of commits the current log buffer is limited to. + +‘-’ (‘magit-log-half-commit-limit’) + Half the number of commits the current log buffer is limited to. + + -- User Option: magit-log-auto-more + Insert more log entries automatically when moving past the last + entry. Only considered when moving past the last entry with + ‘magit-goto-*-section’ commands. + + -- User Option: magit-log-show-refname-after-summary + Whether to show the refnames after the commit summaries. This is + useful if you use really long branch names. + + -- User Option: magit-log-show-color-graph-limit + When showing more commits than specified by this option, then the + ‘--color’ argument, if specified, is silently dropped. This is + necessary because the ‘ansi-color’ library, which is used to turn + control sequences into faces, is just too slow. + + -- User Option: magit-log-show-signatures-limit + When showing more commits than specified by this option, then the + ‘--show-signature’ argument, if specified, is silently dropped. + This is necessary because checking the signature of a large number + of commits is just too slow. + + Magit displays references in logs a bit differently from how Git does +it. + + Local branches are blue and remote branches are green. Of course +that depends on the used theme, as do the colors used for other types of +references. The current branch has a box around it, as do remote +branches that are their respective remote’s ‘HEAD’ branch. + + If a local branch and its push-target point at the same commit, then +their names are combined to preserve space and to make that relationship +visible. For example: + + origin/feature + [green][blue-] + + instead of + + feature origin/feature + [blue-] [green-------] + + Also note that while the transient features the ‘--show-signature’ +argument, that won’t actually be used when enabled, because Magit +defaults to use just one line per commit. Instead the commit colorized +to indicate the validity of the signed commit object, using the faces +named ‘magit-signature-*’ (which see). + + For a description of ‘magit-log-margin’ see *note Log Margin::. + + +File: magit.info, Node: Log Margin, Next: Select from Log, Prev: Log Buffer, Up: Logging + +5.3.3 Log Margin +---------------- + +In buffers which show one or more logs, it is possible to show +additional information about each commit in the margin. The options +used to configure the margin are named ‘magit-INFIX-margin’, where INFIX +is the same as in the respective major-mode ‘magit-INFIX-mode’. In +regular log buffers that would be ‘magit-log-margin’. + + -- User Option: magit-log-margin + This option specifies whether the margin is initially shown in + Magit-Log mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + You can change the STYLE and AUTHOR-WIDTH of all ‘magit-INFIX-margin’ +options to the same values by customizing ‘magit-log-margin’ *before* +‘magit’ is loaded. If you do that, then the respective values for the +other options will default to what you have set for that variable. +Likewise if you set INIT in ‘magit-log-margin’ to ‘nil’, then that is +used in the default of all other options. But setting it to ‘t’, i.e. +re-enforcing the default for that option, does not carry to other +options. + + -- User Option: magit-log-margin-show-committer-date + This option specifies whether to show the committer date in the + margin. This option only controls whether the committer date is + displayed instead of the author date. Whether some date is + displayed in the margin and whether the margin is displayed at all + is controlled by other options. + +‘L’ (‘magit-margin-settings’) + This transient prefix command binds the following suffix commands, + each of which changes the appearance of the margin in some way. + + In some buffers that support the margin, ‘L’ is instead bound to +‘magit-log-refresh’, but that transient features the same commands, and +then some other unrelated commands. + +‘L L’ (‘magit-toggle-margin’) + This command shows or hides the margin. + +‘L l’ (‘magit-cycle-margin-style’) + This command cycles the style used for the margin. + +‘L d’ (‘magit-toggle-margin-details’) + This command shows or hides details in the margin. + + +File: magit.info, Node: Select from Log, Next: Reflog, Prev: Log Margin, Up: Logging + +5.3.4 Select from Log +--------------------- + +When the user has to select a recent commit that is reachable from +‘HEAD’, using regular completion would be inconvenient (because most +humans cannot remember hashes or "HEAD~5", at least not without double +checking). Instead a log buffer is used to select the commit, which has +the advantage that commits are presented in order and with the commit +message. + + Such selection logs are used when selecting the beginning of a rebase +and when selecting the commit to be squashed into. + + In addition to the key bindings available in all log buffers, the +following additional key bindings are available in selection log +buffers: + +‘C-c C-c’ (‘magit-log-select-pick’) + Select the commit at point and act on it. Call + ‘magit-log-select-pick-function’ with the selected commit as + argument. + +‘C-c C-k’ (‘magit-log-select-quit’) + Abort selecting a commit, don’t act on any commit. + + -- User Option: magit-log-select-margin + This option specifies whether the margin is initially shown in + Magit-Log-Select mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Reflog, Next: Cherries, Prev: Select from Log, Up: Logging + +5.3.5 Reflog +------------ + +Also see *note (gitman)git-reflog::. + + These reflog commands are available from the log transient. See +*note Logging::. + +‘l r’ (‘magit-reflog-current’) + Display the reflog of the current branch. + +‘l O’ (‘magit-reflog-other’) + Display the reflog of a branch or another ref. + +‘l H’ (‘magit-reflog-head’) + Display the ‘HEAD’ reflog. + + -- User Option: magit-reflog-margin + This option specifies whether the margin is initially shown in + Magit-Reflog mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Cherries, Prev: Reflog, Up: Logging + +5.3.6 Cherries +-------------- + +Cherries are commits that haven’t been applied upstream (yet), and are +usually visualized using a log. Each commit is prefixed with ‘-’ if it +has an equivalent in the upstream and ‘+’ if it does not, i.e., if it is +a cherry. + + The command ‘magit-cherry’ shows cherries for a single branch, but +the references buffer (see *note References Buffer::) can show cherries +for multiple "upstreams" at once. + + Also see *note (gitman)git-reflog::. + +‘Y’ (‘magit-cherry’) + Show commits that are in a certain branch but that have not been + merged in the upstream branch. + + -- User Option: magit-cherry-margin + This option specifies whether the margin is initially shown in + Magit-Cherry mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting + +5.4 Diffing +=========== + +The status buffer contains diffs for the staged and unstaged commits, +but that obviously isn’t enough. The transient prefix command +‘magit-diff’, on ‘d’, features several suffix commands, which show a +specific diff in a separate diff buffer. + + Like other transient prefix commands, ‘magit-diff’ also features +several infix arguments that can be changed before invoking one of the +suffix commands. However, in the case of the diff transient, these +arguments may be taken from those currently in use in the current +repository’s diff buffer, depending on the value of +‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and +Buffer Variables::). + + Also see *note (gitman)git-diff::. + +‘d’ (‘magit-diff’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘d d’ (‘magit-diff-dwim’) + Show changes for the thing at point. + +‘d r’ (‘magit-diff-range’) + Show differences between two commits. + + RANGE should be a range (A..B or A...B) but can also be a single + commit. If one side of the range is omitted, then it defaults to + ‘HEAD’. If just a commit is given, then changes in the working + tree relative to that commit are shown. + + If the region is active, use the revisions on the first and last + line of the region. With a prefix argument, instead of diffing the + revisions, choose a revision to view changes along, starting at the + common ancestor of both revisions (i.e., use a "..." range). + +‘d w’ (‘magit-diff-working-tree’) + Show changes between the current working tree and the ‘HEAD’ + commit. With a prefix argument show changes between the working + tree and a commit read from the minibuffer. + +‘d s’ (‘magit-diff-staged’) + Show changes between the index and the ‘HEAD’ commit. With a + prefix argument show changes between the index and a commit read + from the minibuffer. + +‘d u’ (‘magit-diff-unstaged’) + Show changes between the working tree and the index. + +‘d p’ (‘magit-diff-paths’) + Show changes between any two files on disk. + + All of the above suffix commands update the repository’s diff buffer. +The diff transient also features two commands which show differences in +another buffer: + +‘d c’ (‘magit-show-commit’) + Show the commit at point. If there is no commit at point or with a + prefix argument, prompt for a commit. + +‘d t’ (‘magit-stash-show’) + Show all diffs of a stash in a buffer. + + Two additional commands that show the diff for the file or blob that +is being visited in the current buffer exists, see *note Commands for +Buffers Visiting Files::. + +* Menu: + +* Refreshing Diffs:: +* Commands Available in Diffs:: +* Diff Options:: +* Revision Buffer:: + + +File: magit.info, Node: Refreshing Diffs, Next: Commands Available in Diffs, Up: Diffing + +5.4.1 Refreshing Diffs +---------------------- + +The transient prefix command ‘magit-diff-refresh’, on ‘D’, can be used +to change the diff arguments used in the current buffer, without +changing which diff is shown. This works in dedicated diff buffers, but +also in the status buffer. + + (There is one exception; diff arguments cannot be changed in buffers +created by ‘magit-merge-preview’ because the underlying Git command does +not support these arguments.) + +‘D’ (‘magit-diff-refresh’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘D g’ (‘magit-diff-refresh’) + This suffix command sets the local diff arguments for the current + buffer. + +‘D s’ (‘magit-diff-set-default-arguments’) + This suffix command sets the default diff arguments for buffers of + the same type as that of the current buffer. Other existing + buffers of the same type are not affected because their local + values have already been initialized. + +‘D w’ (‘magit-diff-save-default-arguments’) + This suffix command sets the default diff arguments for buffers of + the same type as that of the current buffer, and saves the value + for future sessions. Other existing buffers of the same type are + not affected because their local values have already been + initialized. + +‘D t’ (‘magit-diff-toggle-refine-hunk’) + This command toggles hunk refinement on or off. + +‘D r’ (‘magit-diff-switch-range-type’) + This command converts the diff range type from "revA..revB" to + "revB...revA", or vice versa. + +‘D f’ (‘magit-diff-flip-revs’) + This command swaps revisions in the diff range from "revA..revB" to + "revB..revA", or vice versa. + +‘D F’ (‘magit-diff-toggle-file-filter’) + This command toggles the file restriction of the diffs in the + current buffer, allowing you to quickly switch between viewing all + the changes in the commit and the restricted subset. As a special + case, when this command is called from a log buffer, it toggles the + file restriction in the repository’s revision buffer, which is + useful when you display a revision from a log buffer that is + restricted to a file or files. + + In addition to the above transient, which allows changing any of the +supported arguments, there also exist some commands that change only a +particular argument. + +‘-’ (‘magit-diff-less-context’) + This command decreases the context for diff hunks by COUNT lines. + +‘+’ (‘magit-diff-more-context’) + This command increases the context for diff hunks by COUNT lines. + +‘0’ (‘magit-diff-default-context’) + This command resets the context for diff hunks to the default + height. + + The following commands quickly change what diff is being displayed +without having to using one of the diff transient. + +‘C-c C-d’ (‘magit-diff-while-committing’) + While committing, this command shows the changes that are about to + be committed. While amending, invoking the command again toggles + between showing just the new changes or all the changes that will + be committed. + + This binding is available in the diff buffer as well as the commit + message buffer. + +‘C-c C-b’ (‘magit-go-backward’) + This command moves backward in current buffer’s history. + +‘C-c C-f’ (‘magit-go-forward’) + This command moves forward in current buffer’s history. + + +File: magit.info, Node: Commands Available in Diffs, Next: Diff Options, Prev: Refreshing Diffs, Up: Diffing + +5.4.2 Commands Available in Diffs +--------------------------------- + +Some commands are only available if point is inside a diff. + + ‘magit-diff-visit-file’ and related commands visit the appropriate +version of the file that the diff at point is about. Likewise +‘magit-diff-visit-worktree-file’ and related commands visit the worktree +version of the file that the diff at point is about. See *note Visiting +Files and Blobs from a Diff:: for more information and the key bindings. + +‘C-c C-t’ (‘magit-diff-trace-definition’) + This command shows a log for the definition at point. + + -- User Option: magit-log-trace-definition-function + The function specified by this option is used by + ‘magit-log-trace-definition’ to determine the function at point. + For major-modes that have special needs, you could set the local + value using the mode’s hook. + +‘C-c C-e’ (‘magit-diff-edit-hunk-commit’) + From a hunk, this command edits the respective commit and visits + the file. + + First it visits the file being modified by the hunk at the correct + location using ‘magit-diff-visit-file’. This actually visits a + blob. When point is on a diff header, not within an individual + hunk, then this visits the blob the first hunk is about. + + Then it invokes ‘magit-edit-line-commit’, which uses an interactive + rebase to make the commit editable, or if that is not possible + because the commit is not reachable from ‘HEAD’ by checking out + that commit directly. This also causes the actual worktree file to + be visited. + + Neither the blob nor the file buffer are killed when finishing the + rebase. If that is undesirable, then it might be better to use + ‘magit-rebase-edit-commit’ instead of this command. + +‘j’ (‘magit-jump-to-diffstat-or-diff’) + This command jumps to the diffstat or diff. When point is on a + file inside the diffstat section, then jump to the respective diff + section. Otherwise, jump to the diffstat section or a child + thereof. + + The next two commands are not specific to Magit-Diff mode (or and +Magit buffer for that matter), but it might be worth pointing out that +they are available here too. + +‘<SPC>’ (‘scroll-up’) + This command scrolls text upward. + +‘<DEL>’ (‘scroll-down’) + This command scrolls text downward. + + +File: magit.info, Node: Diff Options, Next: Revision Buffer, Prev: Commands Available in Diffs, Up: Diffing + +5.4.3 Diff Options +------------------ + + -- User Option: magit-diff-refine-hunk + Whether to show word-granularity differences within diff hunks. + + • ‘nil’ Never show fine differences. + • ‘t’ Show fine differences for the current diff hunk only. + • ‘all’ Show fine differences for all displayed diff hunks. + + -- User Option: magit-diff-refine-ignore-whitespace + Whether to ignore whitespace changes in word-granularity + differences. + + -- User Option: magit-diff-adjust-tab-width + Whether to adjust the width of tabs in diffs. + + Determining the correct width can be expensive if it requires + opening large and/or many files, so the widths are cached in the + variable ‘magit-diff--tab-width-cache’. Set that to nil to + invalidate the cache. + + • ‘nil’ Never adjust tab width. Use ‘tab-width’s value from the + Magit buffer itself instead. + + • ‘t’ If the corresponding file-visiting buffer exits, then use + ‘tab-width’’s value from that buffer. Doing this is cheap, so + this value is used even if a corresponding cache entry exists. + + • ‘always’ If there is no such buffer, then temporarily visit + the file to determine the value. + + • NUMBER Like ‘always’, but don’t visit files larger than NUMBER + bytes. + + -- User Option: magit-diff-paint-whitespace + Specify where to highlight whitespace errors. + + See ‘magit-diff-highlight-trailing’, + ‘magit-diff-highlight-indentation’. The symbol ‘t’ means in all + diffs, ‘status’ means only in the status buffer, and nil means + nowhere. + + • ‘nil’ Never highlight whitespace errors. + • ‘t’ Highlight whitespace errors everywhere. + • ‘uncommitted’ Only highlight whitespace errors in diffs + showing uncommitted changes. For backward compatibility + ‘status’ is treated as a synonym. + + -- User Option: magit-diff-paint-whitespace-lines + Specify in what kind of lines to highlight whitespace errors. + + • ‘t’ Highlight only in added lines. + • ‘both’ Highlight in added and removed lines. + • ‘all’ Highlight in added, removed and context lines. + + -- User Option: magit-diff-highlight-trailing + Whether to highlight whitespace at the end of a line in diffs. + Used only when ‘magit-diff-paint-whitespace’ is non-nil. + + -- User Option: magit-diff-highlight-indentation + This option controls whether to highlight the indentation in case + it used the "wrong" indentation style. Indentation is only + highlighted if ‘magit-diff-paint-whitespace’ is also non-nil. + + The value is an alist of the form ‘((REGEXP . INDENT)...)’. The + path to the current repository is matched against each element in + reverse order. Therefore if a REGEXP matches, then earlier + elements are not tried. + + If the used INDENT is ‘tabs’, highlight indentation with tabs. If + INDENT is an integer, highlight indentation with at least that many + spaces. Otherwise, highlight neither. + + -- User Option: magit-diff-hide-trailing-cr-characters + Whether to hide ^M characters at the end of a line in diffs. + + -- User Option: magit-diff-highlight-hunk-region-functions + This option specifies the functions used to highlight the + hunk-internal region. + + ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside + of the hunk internal selection with a face that causes the added + and removed lines to have the same background color as context + lines. This function should not be removed from the value of this + option. + + ‘magit-diff-highlight-hunk-region-using-overlays’ and + ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the + region by placing delimiting horizontal lines before and after it. + Both of these functions have glitches which cannot be fixed due to + limitations of Emacs’ display engine. For more information see + <https://github.com/magit/magit/issues/2758> ff. + + Instead of, or in addition to, using delimiting horizontal lines, + to emphasize the boundaries, you may wish to emphasize the text + itself, using ‘magit-diff-highlight-hunk-region-using-face’. + + In terminal frames it’s not possible to draw lines as the overlay + and underline variants normally do, so there they fall back to + calling the face function instead. + + -- User Option: magit-diff-unmarked-lines-keep-foreground + This option controls whether added and removed lines outside the + hunk-internal region only lose their distinct background color or + also the foreground color. Whether the outside of the region is + dimmed at all depends on + ‘magit-diff-highlight-hunk-region-functions’. + + -- User Option: magit-diff-extra-stat-arguments + This option specifies additional arguments to be used alongside + ‘--stat’. + + The value is a list of zero or more arguments or a function that + takes no argument and returns such a list. These arguments are + allowed here: ‘--stat-width’, ‘--stat-name-width’, + ‘--stat-graph-width’ and ‘--compact-summary’. Also see *note + (gitman)git-diff::. + + +File: magit.info, Node: Revision Buffer, Prev: Diff Options, Up: Diffing + +5.4.4 Revision Buffer +--------------------- + + -- User Option: magit-revision-insert-related-refs + Whether to show related branches in revision buffers. + + • ‘nil’ Don’t show any related branches. + • ‘t’ Show related local branches. + • ‘all’ Show related local and remote branches. + • ‘mixed’ Show all containing branches and local merged + branches. + + -- User Option: magit-revision-show-gravatars + Whether to show gravatar images in revision buffers. + + If ‘nil’, then don’t insert any gravatar images. If ‘t’, then + insert both images. If ‘author’ or ‘committer’, then insert only + the respective image. + + If you have customized the option ‘magit-revision-headers-format’ + and want to insert the images then you might also have to specify + where to do so. In that case the value has to be a cons-cell of + two regular expressions. The car specifies where to insert the + author’s image. The top half of the image is inserted right after + the matched text, the bottom half on the next line in the same + column. The cdr specifies where to insert the committer’s image, + accordingly. Either the car or the cdr may be nil." + + -- User Option: magit-revision-use-hash-sections + Whether to turn hashes inside the commit message into sections. + + If non-nil, then hashes inside the commit message are turned into + ‘commit’ sections. There is a trade off to be made between + performance and reliability: + + • ‘slow’ calls git for every word to be absolutely sure. + • ‘quick’ skips words less than seven characters long. + • ‘quicker’ additionally skips words that don’t contain a + number. + • ‘quickest’ uses all words that are at least seven characters + long and which contain at least one number as well as at least + one letter. + + If nil, then no hashes are turned into sections, but you can still + visit the commit at point using "RET". + + The diffs shown in the revision buffer may be automatically +restricted to a subset of the changed files. If the revision buffer is +displayed from a log buffer, the revision buffer will share the same +file restriction as that log buffer (also see the command +‘magit-diff-toggle-file-filter’). + + -- User Option: magit-revision-filter-files-on-follow + Whether showing a commit from a log buffer honors the log’s file + filter when the log arguments include ‘--follow’. + + When this option is nil, displaying a commit from a log ignores the + log’s file filter if the log arguments include ‘--follow’. Doing + so avoids showing an empty diff in revision buffers for commits + before a rename event. In such cases, the ‘--patch’ argument of + the log transient can be used to show the file-restricted diffs + inline. + + Set this option to non-nil to keep the log’s file restriction even + if ‘--follow’ is present in the log arguments. + + If the revision buffer is not displayed from a log buffer, the file +restriction is determined as usual (see *note Transient Arguments and +Buffer Variables::). + + +File: magit.info, Node: Ediffing, Next: References Buffer, Prev: Diffing, Up: Inspecting + +5.5 Ediffing +============ + +This section describes how to enter Ediff from Magit buffers. For +information on how to use Ediff itself, see *note (ediff)Top::. + +‘e’ (‘magit-ediff-dwim’) + Compare, stage, or resolve using Ediff. + + This command tries to guess what file, and what commit or range the + user wants to compare, stage, or resolve using Ediff. It might + only be able to guess either the file, or range/commit, in which + case the user is asked about the other. It might not always guess + right, in which case the appropriate ‘magit-ediff-*’ command has to + be used explicitly. If it cannot read the user’s mind at all, then + it asks the user for a command to run. + +‘E’ (‘magit-ediff’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘E r’ (‘magit-ediff-compare’) + Compare two revisions of a file using Ediff. + + If the region is active, use the revisions on the first and last + line of the region. With a prefix argument, instead of diffing the + revisions, choose a revision to view changes along, starting at the + common ancestor of both revisions (i.e., use a "..." range). + +‘E m’ (‘magit-ediff-resolve-rest’) + This command allows you to resolve outstanding conflicts in the + file at point using Ediff. If there is no file at point or if it + doesn’t have any unmerged changes, then this command prompts for a + file. + + Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you + can view the file’s merge-base revision using ‘/’ in the Ediff + control buffer. + + The A, B and Ancestor buffers are constructed from the conflict + markers in the worktree file. Because you and/or Git may have + already resolved some conflicts, that means that these buffers may + not contain the actual versions from the respective blobs. + +‘E M’ (‘magit-ediff-resolve-all’) + This command allows you to resolve all conflicts in the file at + point using Ediff. If there is no file at point or if it doesn’t + have any unmerged changes, then this command prompts for a file. + + Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you + can view the file’s merge-base revision using ‘/’ in the Ediff + control buffer. + + First the file in the worktree is moved aside, appending the suffix + ‘.ORIG’, so that you could later go back to that version. Then it + is reconstructed from the two sides of the conflict and the + merge-base, if available. + + It would be nice if the worktree file were just used as-is, but + Ediff does not support that. This means that all conflicts, that + Git has already resolved, are restored. On the other hand Ediff + also tries to resolve conflicts, and in many cases Ediff and Git + should produce similar results. + + However if you have already resolved some conflicts manually, then + those changes are discarded (though you can recover them from the + backup file). In such cases ‘magit-ediff-resolve-rest’ might be + more suitable. + + The advantage that this command has over ‘magit-ediff-resolve-rest’ + is that the A, B and Ancestor buffers correspond to blobs from the + respective commits, allowing you to inspect a side in context and + to use Magit commands in these buffers to do so. Blame and log + commands are particularly useful here. + +‘E t’ (‘magit-git-mergetool’) + This command does not actually use Ediff. While it serves the same + purpose as ‘magit-ediff-resolve-rest’, it uses ‘git mergetool + --gui’ to resolve conflicts. + + With a prefix argument this acts as a transient prefix command, + allowing the user to select the mergetool and change some settings. + +‘E s’ (‘magit-ediff-stage’) + Stage and unstage changes to a file using Ediff, defaulting to the + file at point. + +‘E u’ (‘magit-ediff-show-unstaged’) + Show unstaged changes to a file using Ediff. + +‘E i’ (‘magit-ediff-show-staged’) + Show staged changes to a file using Ediff. + +‘E w’ (‘magit-ediff-show-working-tree’) + Show changes in a file between ‘HEAD’ and working tree using Ediff. + +‘E c’ (‘magit-ediff-show-commit’) + Show changes to a file introduced by a commit using Ediff. + +‘E z’ (‘magit-ediff-show-stash’) + Show changes to a file introduced by a stash using Ediff. + + -- User Option: magit-ediff-dwim-resolve-function + This option controls which function ‘magit-ediff-dwim’ uses to + resolve conflicts. One of ‘magit-ediff-resolve-rest’, + ‘magit-ediff-resolve-all’ or ‘magit-git-mergetool’; which are all + discussed above. + + -- User Option: magit-ediff-dwim-show-on-hunks + This option controls what command ‘magit-ediff-dwim’ calls when + point is on uncommitted hunks. When nil, always run + ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and + ‘magit-ediff-show-unstaged’ to show staged and unstaged changes, + respectively. + + -- User Option: magit-ediff-show-stash-with-index + This option controls whether ‘magit-ediff-show-stash’ includes a + buffer containing the file’s state in the index at the time the + stash was created. This makes it possible to tell which changes in + the stash were staged. + + -- User Option: magit-ediff-quit-hook + This hook is run after quitting an Ediff session that was created + using a Magit command. The hook functions are run inside the Ediff + control buffer, and should not change the current buffer. + + This is similar to ‘ediff-quit-hook’ but takes the needs of Magit + into account. The regular ‘ediff-quit-hook’ is ignored by Ediff + sessions that were created using a Magit command. + + +File: magit.info, Node: References Buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting + +5.6 References Buffer +===================== + +‘y’ (‘magit-show-refs’) + This command lists branches and tags in a dedicated buffer. + + However if this command is invoked again from this buffer or if it + is invoked with a prefix argument, then it acts as a transient + prefix command, which binds the following suffix commands and some + infix arguments. + + All of the following suffix commands list exactly the same branches +and tags. The only difference the optional feature that can be enabled +by changing the value of ‘magit-refs-show-commit-count’ (see below). +These commands specify a different branch or commit against which all +the other references are compared. + +‘y y’ (‘magit-show-refs-head’) + This command lists branches and tags in a dedicated buffer. Each + reference is being compared with ‘HEAD’. + +‘y c’ (‘magit-show-refs-current’) + This command lists branches and tags in a dedicated buffer. Each + reference is being compared with the current branch or ‘HEAD’ if it + is detached. + +‘y o’ (‘magit-show-refs-other’) + This command lists branches and tags in a dedicated buffer. Each + reference is being compared with a branch read from the user. + +‘y r’ (‘magit-refs-set-show-commit-count’) + This command changes for which refs the commit count is shown. + + -- User Option: magit-refs-show-commit-count + Whether to show commit counts in Magit-Refs mode buffers. + + • ‘all’ Show counts for branches and tags. + • ‘branch’ Show counts for branches only. + • ‘nil’ Never show counts. + + The default is ‘nil’ because anything else can be very expensive. + + -- User Option: magit-refs-pad-commit-counts + Whether to pad all commit counts on all sides in Magit-Refs mode + buffers. + + If this is nil, then some commit counts are displayed right next to + one of the branches that appear next to the count, without any + space in between. This might look bad if the branch name faces + look too similar to ‘magit-dimmed’. + + If this is non-nil, then spaces are placed on both sides of all + commit counts. + + -- User Option: magit-refs-show-remote-prefix + Whether to show the remote prefix in lists of remote branches. + + Showing the prefix is redundant because the name of the remote is + already shown in the heading preceding the list of its branches. + + -- User Option: magit-refs-primary-column-width + Width of the primary column in ‘magit-refs-mode’ buffers. The + primary column is the column that contains the name of the branch + that the current row is about. + + If this is an integer, then the column is that many columns wide. + Otherwise it has to be a cons-cell of two integers. The first + specifies the minimal width, the second the maximal width. In that + case the actual width is determined using the length of the names + of the shown local branches. (Remote branches and tags are not + taken into account when calculating to optimal width.) + + -- User Option: magit-refs-focus-column-width + Width of the focus column in ‘magit-refs-mode’ buffers. + + The focus column is the first column, which marks one branch + (usually the current branch) as the focused branch using ‘*’ or + ‘@’. For each other reference, this column optionally shows how + many commits it is ahead of the focused branch and ‘<’, or if it + isn’t ahead then the commits it is behind and ‘>’, or if it isn’t + behind either, then a ‘=’. + + This column may also display only ‘*’ or ‘@’ for the focused + branch, in which case this option is ignored. Use ‘L v’ to change + the verbosity of this column. + + -- User Option: magit-refs-margin + This option specifies whether the margin is initially shown in + Magit-Refs mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + -- User Option: magit-refs-margin-for-tags + This option specifies whether to show information about tags in the + margin. This is disabled by default because it is slow if there + are many tags. + + The following variables control how individual refs are displayed. +If you change one of these variables (especially the "%c" part), then +you should also change the others to keep things aligned. The following +%-sequences are supported: + + • ‘%a’ Number of commits this ref has over the one we compare to. + • ‘%b’ Number of commits the ref we compare to has over this one. + • ‘%c’ Number of commits this ref has over the one we compare to. + For the ref which all other refs are compared this is instead "@", + if it is the current branch, or "#" otherwise. + • ‘%C’ For the ref which all other refs are compared this is "@", if + it is the current branch, or "#" otherwise. For all other refs " + ". + • ‘%h’ Hash of this ref’s tip. + • ‘%m’ Commit summary of the tip of this ref. + • ‘%n’ Name of this ref. + • ‘%u’ Upstream of this local branch. + • ‘%U’ Upstream of this local branch and additional local vs. + upstream information. + + -- User Option: magit-refs-filter-alist + The purpose of this option is to forgo displaying certain refs + based on their name. If you want to not display any refs of a + certain type, then you should remove the appropriate function from + ‘magit-refs-sections-hook’ instead. + + This alist controls which tags and branches are omitted from being + displayed in ‘magit-refs-mode’ buffers. If it is ‘nil’, then all + refs are displayed (subject to ‘magit-refs-sections-hook’). + + All keys are tried in order until one matches. Then its value is + used and subsequent elements are ignored. If the value is non-nil, + then the reference is displayed, otherwise it is not. If no + element matches, then the reference is displayed. + + A key can either be a regular expression that the refname has to + match, or a function that takes the refname as only argument and + returns a boolean. A remote branch such as "origin/master" is + displayed as just "master", however for this comparison the former + is used. + +‘<RET>’ (‘magit-visit-ref’) + This command visits the reference or revision at point in another + buffer. If there is no revision at point or with a prefix argument + then it prompts for a revision. + + This command behaves just like ‘magit-show-commit’ as described + above, except if point is on a reference in a ‘magit-refs-mode’ + buffer, in which case the behavior may be different, but only if + you have customized the option ‘magit-visit-ref-behavior’. + + -- User Option: magit-visit-ref-behavior + This option controls how ‘magit-visit-ref’ behaves in + ‘magit-refs-mode’ buffers. + + By default ‘magit-visit-ref’ behaves like ‘magit-show-commit’, in + all buffers, including ‘magit-refs-mode’ buffers. When the type of + the section at point is ‘commit’ then "RET" is bound to + ‘magit-show-commit’, and when the type is either ‘branch’ or ‘tag’ + then it is bound to ‘magit-visit-ref’. + + "RET" is one of Magit’s most essential keys and at least by default + it should behave consistently across all of Magit, especially + because users quickly learn that it does something very harmless; + it shows more information about the thing at point in another + buffer. + + However "RET" used to behave differently in ‘magit-refs-mode’ + buffers, doing surprising things, some of which cannot really be + described as "visit this thing". If you’ve grown accustomed this + behavior, you can restore it by adding one or more of the below + symbols to the value of this option. But keep in mind that by + doing so you don’t only introduce inconsistencies, you also lose + some functionality and might have to resort to ‘M-x + magit-show-commit’ to get it back. + + ‘magit-visit-ref’ looks for these symbols in the order in which + they are described here. If the presence of a symbol applies to + the current situation, then the symbols that follow do not affect + the outcome. + + • ‘focus-on-ref’ + + With a prefix argument update the buffer to show commit counts + and lists of cherry commits relative to the reference at point + instead of relative to the current buffer or ‘HEAD’. + + Instead of adding this symbol, consider pressing "C-u y o + RET". + + • ‘create-branch’ + + If point is on a remote branch, then create a new local branch + with the same name, use the remote branch as its upstream, and + then check out the local branch. + + Instead of adding this symbol, consider pressing "b c RET + RET", like you would do in other buffers. + + • ‘checkout-any’ + + Check out the reference at point. If that reference is a tag + or a remote branch, then this results in a detached ‘HEAD’. + + Instead of adding this symbol, consider pressing "b b RET", + like you would do in other buffers. + + • ‘checkout-branch’ + + Check out the local branch at point. + + Instead of adding this symbol, consider pressing "b b RET", + like you would do in other buffers. + +* Menu: + +* References Sections:: + + +File: magit.info, Node: References Sections, Up: References Buffer + +5.6.1 References Sections +------------------------- + +The contents of references buffers is controlled using the hook +‘magit-refs-sections-hook’. See *note Section Hooks:: to learn about +such hooks and how to customize them. All of the below functions are +members of the default value. Note that it makes much less sense to +customize this hook than it does for the respective hook used for the +status buffer. + + -- User Option: magit-refs-sections-hook + Hook run to insert sections into a references buffer. + + -- Function: magit-insert-local-branches + Insert sections showing all local branches. + + -- Function: magit-insert-remote-branches + Insert sections showing all remote-tracking branches. + + -- Function: magit-insert-tags + Insert sections showing all tags. + + +File: magit.info, Node: Bisecting, Next: Visiting Files and Blobs, Prev: References Buffer, Up: Inspecting + +5.7 Bisecting +============= + +Also see *note (gitman)git-bisect::. + +‘B’ (‘magit-bisect’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + + When bisecting is not in progress, then the transient features the +following suffix commands. + +‘B B’ (‘magit-bisect-start’) + Start a bisect session. + + Bisecting a bug means to find the commit that introduced it. This + command starts such a bisect session by asking for a known good + commit and a known bad commit. If you’re bisecting a change that + isn’t a regression, you can select alternate terms that are + conceptually more fitting than "bad" and "good", but the infix + arguments to do so are disabled by default. + +‘B s’ (‘magit-bisect-run’) + Bisect automatically by running commands after each step. + + When bisecting in progress, then the transient instead features the +following suffix commands. + +‘B b’ (‘magit-bisect-bad’) + Mark the current commit as bad. Use this after you have asserted + that the commit does contain the bug in question. + +‘B g’ (‘magit-bisect-good’) + Mark the current commit as good. Use this after you have asserted + that the commit does not contain the bug in question. + +‘B m’ (‘magit-bisect-mark’) + Mark the current commit with one of the bisect terms. This command + provides an alternative to ‘magit-bisect-bad’ and + ‘magit-bisect-good’ and is useful when using terms other than "bad" + and "good". This suffix is disabled by default. + +‘B k’ (‘magit-bisect-skip’) + Skip the current commit. Use this if for some reason the current + commit is not a good one to test. This command lets Git choose a + different one. + +‘B r’ (‘magit-bisect-reset’) + After bisecting, cleanup bisection state and return to original + ‘HEAD’. + + By default the status buffer shows information about the ongoing +bisect session. + + -- User Option: magit-bisect-show-graph + This option controls whether a graph is displayed for the log of + commits that still have to be bisected. + + +File: magit.info, Node: Visiting Files and Blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting + +5.8 Visiting Files and Blobs +============================ + +Magit provides several commands that visit a file or blob (the version +of a file that is stored in a certain commit). Actually it provides +several *groups* of such commands and the several *variants* within each +group. + + Also see *note Commands for Buffers Visiting Files::. + +* Menu: + +* General-Purpose Visit Commands:: +* Visiting Files and Blobs from a Diff:: + + +File: magit.info, Node: General-Purpose Visit Commands, Next: Visiting Files and Blobs from a Diff, Up: Visiting Files and Blobs + +5.8.1 General-Purpose Visit Commands +------------------------------------ + +These commands can be used anywhere to open any blob. Currently no keys +are bound to these commands by default, but that is likely to change. + + -- Command: magit-find-file + This command reads a filename and revision from the user and visits + the respective blob in a buffer. The buffer is displayed in the + selected window. + + -- Command: magit-find-file-other-window + This command reads a filename and revision from the user and visits + the respective blob in a buffer. The buffer is displayed in + another window. + + -- Command: magit-find-file-other-frame + This command reads a filename and revision from the user and visits + the respective blob in a buffer. The buffer is displayed in + another frame. + + +File: magit.info, Node: Visiting Files and Blobs from a Diff, Prev: General-Purpose Visit Commands, Up: Visiting Files and Blobs + +5.8.2 Visiting Files and Blobs from a Diff +------------------------------------------ + +These commands can only be used when point is inside a diff. + +‘<RET>’ (‘magit-diff-visit-file’) + This command visits the appropriate version of the file that the + diff at point is about. + + This commands visits the worktree version of the appropriate file. + The location of point inside the diff determines which file is + being visited. The visited version depends on what changes the + diff is about. + + 1. If the diff shows uncommitted changes (i.e., staged or + unstaged changes), then visit the file in the working tree + (i.e., the same "real" file that ‘find-file’ would visit. In + all other cases visit a "blob" (i.e., the version of a file as + stored in some commit). + + 2. If point is on a removed line, then visit the blob for the + first parent of the commit that removed that line, i.e., the + last commit where that line still exists. + + 3. If point is on an added or context line, then visit the blob + that adds that line, or if the diff shows from more than a + single commit, then visit the blob from the last of these + commits. + + In the file-visiting buffer this command goes to the line that + corresponds to the line that point is on in the diff. + + The buffer is displayed in the selected window. With a prefix + argument the buffer is displayed in another window instead. + + -- User Option: magit-diff-visit-previous-blob + This option controls whether ‘magit-diff-visit-file’ may visit the + previous blob. When this is ‘t’ (the default) and point is on a + removed line in a diff for a committed change, then + ‘magit-diff-visit-file’ visits the blob from the last revision + which still had that line. + + Currently this is only supported for committed changes, for staged + and unstaged changes ‘magit-diff-visit-file’ always visits the file + in the working tree. + +‘C-<return>’ (‘magit-diff-visit-file-worktree’) + This command visits the worktree version of the appropriate file. + The location of point inside the diff determines which file is + being visited. Unlike ‘magit-diff-visit-file’ it always visits the + "real" file in the working tree, i.e the "current version" of the + file. + + In the file-visiting buffer this command goes to the line that + corresponds to the line that point is on in the diff. Lines that + were added or removed in the working tree, the index and other + commits in between are automatically accounted for. + + The buffer is displayed in the selected window. With a prefix + argument the buffer is displayed in another window instead. + + Variants of the above two commands exist that instead visit the file +in another window or in another frame. If you prefer such behavior, +then you may want to change the above key bindings, but note that the +above commands also use another window when invoked with a prefix +argument. + + -- Command: magit-diff-visit-file-other-window + -- Command: magit-diff-visit-file-other-frame + -- Command: magit-diff-visit-worktree-file-other-window + -- Command: magit-diff-visit-worktree-file-other-frame + + +File: magit.info, Node: Blaming, Prev: Visiting Files and Blobs, Up: Inspecting + +5.9 Blaming +=========== + +Also see *note (gitman)git-blame::. + + To start blaming, invoke the ‘magit-file-dispatch’ transient prefix +command. When using the default key bindings, that can be done by +pressing ‘C-c M-g’. When using the recommended bindings, this command +is instead bound to ‘C-c f’. Also see *note Global Bindings::. + + The blaming suffix commands can be invoked directly from the file +dispatch transient. However if you want to set an infix argument, then +you have to enter the blaming sub-prefix first. + +‘C-c f B’ (‘magit-blame’) +‘C-c f b’ (‘magit-blame-addition’) +‘C-c f B b’ +‘C-c f r’ (‘magit-blame-removal’) +‘C-c f B r’ +‘C-c f f’ (‘magit-blame-reverse’) +‘C-c f B f’ +‘C-c f e’ (‘magit-blame-echo’) +‘C-c f B e’ +‘C-c f q’ (‘magit-blame-quit’) +‘C-c f B q’ + Each of these commands is documented individually right below, + alongside their default key bindings. The bindings shown above are + the recommended bindings, which you can enable by following the + instructions in *note Global Bindings::. + +‘C-c M-g B’ (‘magit-blame’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + Note that not all of the following suffixes are available at all +times. For example if ‘magit-blame-mode’ is not enabled, then the +command whose purpose is to turn off that mode would not be of any use +and therefore isn’t available. + +‘C-c M-g b’ (‘magit-blame-addition’) +‘C-c M-g B b’ + This command augments each line or chunk of lines in the current + file-visiting or blob-visiting buffer with information about what + commits last touched these lines. + + If the buffer visits a revision of that file, then history up to + that revision is considered. Otherwise, the file’s full history is + considered, including uncommitted changes. + + If Magit-Blame mode is already turned on in the current buffer then + blaming is done recursively, by visiting REVISION:FILE (using + ‘magit-find-file’), where REVISION is a parent of the revision that + added the current line or chunk of lines. + +‘C-c M-g r’ (‘magit-blame-removal’) +‘C-c M-g B r’ + This command augments each line or chunk of lines in the current + blob-visiting buffer with information about the revision that + removes it. It cannot be used in file-visiting buffers. + + Like ‘magit-blame-addition’, this command can be used recursively. + +‘C-c M-g f’ (‘magit-blame-reverse’) +‘C-c M-g B f’ + This command augments each line or chunk of lines in the current + file-visiting or blob-visiting buffer with information about the + last revision in which a line still existed. + + Like ‘magit-blame-addition’, this command can be used recursively. + +‘C-c M-g e’ (‘magit-blame-echo’) +‘C-c M-g B e’ + This command is like ‘magit-blame-addition’ except that it doesn’t + turn on ‘read-only-mode’ and that it initially uses the + visualization style specified by option ‘magit-blame-echo-style’. + + The following key bindings are available when Magit-Blame mode is +enabled and Read-Only mode is not enabled. These commands are also +available in other buffers; here only the behavior is described that is +relevant in file-visiting buffers that are being blamed. + +‘C-c M-g q’ (‘magit-blame-quit’) +‘C-c M-g B q’ + This command turns off Magit-Blame mode. If the buffer was created + during a recursive blame, then it also kills the buffer. + +‘<RET>’ (‘magit-show-commit’) + This command shows the commit that last touched the line at point. + +‘<SPC>’ (‘magit-diff-show-or-scroll-up’) + This command updates the commit buffer. + + This either shows the commit that last touched the line at point in + the appropriate buffer, or if that buffer is already being + displayed in the current frame and if that buffer contains + information about that commit, then the buffer is scrolled up + instead. + +‘<DEL>’ (‘magit-diff-show-or-scroll-down’) + This command updates the commit buffer. + + This either shows the commit that last touched the line at point in + the appropriate buffer, or if that buffer is already being + displayed in the current frame and if that buffer contains + information about that commit, then the buffer is scrolled down + instead. + + The following key bindings are available when both Magit-Blame mode +and Read-Only mode are enabled. + +‘b’ (‘magit-blame’) + See above. + +‘n’ (‘magit-blame-next-chunk’) + This command moves to the next chunk. + +‘N’ (‘magit-blame-next-chunk-same-commit’) + This command moves to the next chunk from the same commit. + +‘p’ (‘magit-blame-previous-chunk’) + This command moves to the previous chunk. + +‘P’ (‘magit-blame-previous-chunk-same-commit’) + This command moves to the previous chunk from the same commit. + +‘q’ (‘magit-blame-quit’) + This command turns off Magit-Blame mode. If the buffer was created + during a recursive blame, then it also kills the buffer. + +‘M-w’ (‘magit-blame-copy-hash’) + This command saves the hash of the current chunk’s commit to the + kill ring. + + When the region is active, the command saves the region’s content + instead of the hash, like ‘kill-ring-save’ would. + +‘c’ (‘magit-blame-cycle-style’) + This command changes how blame information is visualized in the + current buffer by cycling through the styles specified using the + option ‘magit-blame-styles’. + + Blaming is also controlled using the following options. + + -- User Option: magit-blame-styles + This option defines a list of styles used to visualize blame + information. For now see its doc-string to learn more. + + -- User Option: magit-blame-echo-style + This option specifies the blame visualization style used by the + command ‘magit-blame-echo’. This must be a symbol that is used as + the identifier for one of the styles defined in + ‘magit-blame-styles’. + + -- User Option: magit-blame-time-format + This option specifies the format string used to display times when + showing blame information. + + -- User Option: magit-blame-read-only + This option controls whether blaming a buffer also makes + temporarily read-only. + + -- User Option: magit-blame-disable-modes + This option lists incompatible minor-modes that should be disabled + temporarily when a buffer contains blame information. They are + enabled again when the buffer no longer shows blame information. + + -- User Option: magit-blame-goto-chunk-hook + This hook is run when moving between chunks. + + +File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top + +6 Manipulating +************** + +* Menu: + +* Creating Repository:: +* Cloning Repository:: +* Staging and Unstaging:: +* Applying:: +* Committing:: +* Branching:: +* Merging:: +* Resolving Conflicts:: +* Rebasing:: +* Cherry Picking:: +* Resetting:: +* Stashing:: + + +File: magit.info, Node: Creating Repository, Next: Cloning Repository, Up: Manipulating + +6.1 Creating Repository +======================= + +‘I’ (‘magit-init’) + This command initializes a repository and then shows the status + buffer for the new repository. + + If the directory is below an existing repository, then the user has + to confirm that a new one should be created inside. If the + directory is the root of the existing repository, then the user has + to confirm that it should be reinitialized. + + +File: magit.info, Node: Cloning Repository, Next: Staging and Unstaging, Prev: Creating Repository, Up: Manipulating + +6.2 Cloning Repository +====================== + +To clone a remote or local repository use ‘C’, which is bound to the +command ‘magit-clone’. This command either act as a transient prefix +command, which binds several infix arguments and suffix commands, or it +can invoke ‘git clone’ directly, depending on whether a prefix argument +is used and on the value of ‘magit-clone-always-transient’. + + -- User Option: magit-clone-always-transient + This option controls whether the command ‘magit-clone’ always acts + as a transient prefix command, regardless of whether a prefix + argument is used or not. If ‘t’, then that command always acts as + a transient prefix. If ‘nil’, then a prefix argument has to be + used for it to act as a transient. + +‘C’ (‘magit-clone’) + This command either acts as a transient prefix command as described + above or does the same thing as ‘transient-clone-regular’ as + described below. + + If it acts as a transient prefix, then it binds the following + suffix commands and several infix arguments. + +‘C C’ (‘magit-clone-regular’) + This command creates a regular clone of an existing repository. + The repository and the target directory are read from the user. + +‘C s’ (‘magit-clone-shallow’) + This command creates a shallow clone of an existing repository. + The repository and the target directory are read from the user. By + default the depth of the cloned history is a single commit, but + with a prefix argument the depth is read from the user. + +‘C >’ (‘magit-clone-sparse’) + This command creates a clone of an existing repository and + initializes a sparse checkout, avoiding a checkout of the full + working tree. To add more directories, use the + ‘magit-sparse-checkout’ transient (see *note Sparse checkouts::). + +‘C b’ (‘magit-clone-bare’) + This command creates a bare clone of an existing repository. The + repository and the target directory are read from the user. + +‘C m’ (‘magit-clone-mirror’) + This command creates a mirror of an existing repository. The + repository and the target directory are read from the user. + + The following suffixes are disabled by default. See *note +(transient)Enabling and Disabling Suffixes:: for how to enable them. + +‘C d’ (‘magit-clone-shallow-since’) + This command creates a shallow clone of an existing repository. + Only commits that were committed after a date are cloned, which is + read from the user. The repository and the target directory are + also read from the user. + +‘C e’ (‘magit-clone-shallow-exclude’) + This command creates a shallow clone of an existing repository. + This reads a branch or tag from the user. Commits that are + reachable from that are not cloned. The repository and the target + directory are also read from the user. + + -- User Option: magit-clone-set-remote-head + This option controls whether cloning causes the reference + ‘refs/remotes/<remote>/HEAD’ to be created in the clone. The + default is to delete the reference after running ‘git clone’, which + insists on creating it. This is because the reference has not been + found to be particularly useful as it is not automatically updated + when the ‘HEAD’ of the remote changes. Setting this option to ‘t’ + preserves Git’s default behavior of creating the reference. + + -- User Option: magit-clone-set-remote.pushDefault + This option controls whether the value of the Git variable + ‘remote.pushDefault’ is set after cloning. + + • If ‘t’, then it is always set without asking. + • If ‘ask’, then the users are asked every time they clone a + repository. + • If ‘nil’, then it is never set. + + -- User Option: magit-clone-default-directory + This option control the default directory name used when reading + the destination for a cloning operation. + + • If ‘nil’ (the default), then the value of ‘default-directory’ + is used. + • If a directory, then that is used. + • If a function, then that is called with the remote url as the + only argument and the returned value is used. + + -- User Option: magit-clone-name-alist + This option maps regular expressions, which match repository names, + to repository urls, making it possible for users to enter short + names instead of urls when cloning repositories. + + Each element has the form ‘(REGEXP HOSTNAME USER)’. When the user + enters a name when a cloning command asks for a name or url, then + that is looked up in this list. The first element whose REGEXP + matches is used. + + The format specified by option ‘magit-clone-url-format’ is used to + turn the name into an url, using HOSTNAME and the repository name. + If the provided name contains a slash, then that is used. + Otherwise if the name omits the owner of the repository, then the + default user specified in the matched entry is used. + + If USER contains a dot, then it is treated as a Git variable and + the value of that is used as the username. Otherwise it is used as + the username itself. + + -- User Option: magit-clone-url-format + The format specified by this option is used when turning repository + names into urls. ‘%h’ is the hostname and ‘%n’ is the repository + name, including the name of the owner. The value can be a string + (representing a single static format) or an alist with elements + ‘(HOSTNAME . FORMAT)’ mapping hostnames to formats. When an alist + is used, the ‘t’ key represents the default format. + + Example of a single format string: + + (setq magit-clone-url-format + "git@%h:%n.git") + + Example of by-hostname format strings: + + (setq magit-clone-url-format + '(("git.example.com" . "git@%h:~%n") + (nil . "git@%h:%n.git"))) + + -- User Option: magit-post-clone-hook + Hook run after the Git process has successfully finished cloning + the repository. When the hook is called, ‘default-directory’ is + let-bound to the directory where the repository has been cloned. + + +File: magit.info, Node: Staging and Unstaging, Next: Applying, Prev: Cloning Repository, Up: Manipulating + +6.3 Staging and Unstaging +========================= + +Like Git, Magit can of course stage and unstage complete files. Unlike +Git, it also allows users to gracefully un-/stage individual hunks and +even just part of a hunk. To stage individual hunks and parts of hunks +using Git directly, one has to use the very modal and rather clumsy +interface of a ‘git add --interactive’ session. + + With Magit, on the other hand, one can un-/stage individual hunks by +just moving point into the respective section inside a diff displayed in +the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To +operate on just parts of a hunk, mark the changes that should be +un-/staged using the region and then press the same key that would be +used to un-/stage. To stage multiple files or hunks at once use a +region that starts inside the heading of such a section and ends inside +the heading of a sibling section of the same type. + + Besides staging and unstaging, Magit also provides several other +"apply variants" that can also operate on a file, multiple files at +once, a hunk, multiple hunks at once, and on parts of a hunk. These +apply variants are described in the next section. + + You can also use Ediff to stage and unstage. See *note Ediffing::. + +‘s’ (‘magit-stage’) + Add the change at point to the staging area. + + With a prefix argument and an untracked file (or files) at point, + stage the file but not its content. This makes it possible to + stage only a subset of the new file’s changes. + +‘S’ (‘magit-stage-modified’) + Stage all changes to files modified in the worktree. Stage all new + content of tracked files and remove tracked files that no longer + exist in the working tree from the index also. With a prefix + argument also stage previously untracked (but not ignored) files. + +‘u’ (‘magit-unstage’) + Remove the change at point from the staging area. + + Only staged changes can be unstaged. But by default this command + performs an action that is somewhat similar to unstaging, when it + is called on a committed change: it reverses the change in the + index but not in the working tree. + +‘U’ (‘magit-unstage-all’) + Remove all changes from the staging area. + + -- User Option: magit-unstage-committed + This option controls whether ‘magit-unstage’ "unstages" committed + changes by reversing them in the index but not the working tree. + The alternative is to raise an error. + +‘M-x magit-reverse-in-index’ + This command reverses the committed change at point in the index + but not the working tree. By default no key is bound directly to + this command, but it is indirectly called when ‘u’ + (‘magit-unstage’) is pressed on a committed change. + + This allows extracting a change from ‘HEAD’, while leaving it in + the working tree, so that it can later be committed using a + separate commit. A typical workflow would be: + + 1. Optionally make sure that there are no uncommitted changes. + 2. Visit the ‘HEAD’ commit and navigate to the change that should + not have been included in that commit. + 3. Type ‘u’ (‘magit-unstage’) to reverse it in the index. This + assumes that ‘magit-unstage-committed’ is non-nil. + 4. Type ‘c e’ to extend ‘HEAD’ with the staged changes, including + those that were already staged before. + 5. Optionally stage the remaining changes using ‘s’ or ‘S’ and + then type ‘c c’ to create a new commit. + +‘M-x magit-reset-index’ + Reset the index to some commit. The commit is read from the user + and defaults to the commit at point. If there is no commit at + point, then it defaults to ‘HEAD’. + +* Menu: + +* Staging from File-Visiting Buffers:: + + +File: magit.info, Node: Staging from File-Visiting Buffers, Up: Staging and Unstaging + +6.3.1 Staging from File-Visiting Buffers +---------------------------------------- + +Fine-grained un-/staging has to be done from the status or a diff +buffer, but it’s also possible to un-/stage all changes made to the file +visited in the current buffer right from inside that buffer. + +‘M-x magit-stage-file’ + When invoked inside a file-visiting buffer, then stage all changes + to that file. In a Magit buffer, stage the file at point if any. + Otherwise prompt for a file to be staged. With a prefix argument + always prompt the user for a file, even in a file-visiting buffer + or when there is a file section at point. + +‘M-x magit-unstage-file’ + When invoked inside a file-visiting buffer, then unstage all + changes to that file. In a Magit buffer, unstage the file at point + if any. Otherwise prompt for a file to be unstaged. With a prefix + argument always prompt the user for a file, even in a file-visiting + buffer or when there is a file section at point. + + +File: magit.info, Node: Applying, Next: Committing, Prev: Staging and Unstaging, Up: Manipulating + +6.4 Applying +============ + +Magit provides several "apply variants": stage, unstage, discard, +reverse, and "regular apply". At least when operating on a hunk they +are all implemented using ‘git apply’, which is why they are called +"apply variants". + + • Stage. Apply a change from the working tree to the index. The + change also remains in the working tree. + + • Unstage. Remove a change from the index. The change remains in + the working tree. + + • Discard. On a staged change, remove it from the working tree and + the index. On an unstaged change, remove it from the working tree + only. + + • Reverse. Reverse a change in the working tree. Both committed and + staged changes can be reversed. Unstaged changes cannot be + reversed. Discard them instead. + + • Apply. Apply a change to the working tree. Both committed and + staged changes can be applied. Unstaged changes cannot be applied + - as they already have been applied. + + The previous section described the staging and unstaging commands. +What follows are the commands which implement the remaining apply +variants. + +‘a’ (‘magit-apply’) + Apply the change at point to the working tree. + + With a prefix argument fallback to a 3-way merge. Doing so causes + the change to be applied to the index as well. + +‘k’ (‘magit-discard’) + Remove the change at point from the working tree. + + On a hunk or file with unresolved conflicts prompt which side to + keep (while discarding the other). If point is within the text of + a side, then keep that side without prompting. + +‘v’ (‘magit-reverse’) + Reverse the change at point in the working tree. + + With a prefix argument fallback to a 3-way merge. Doing so causes + the change to be applied to the index as well. + + With a prefix argument all apply variants attempt a 3-way merge when +appropriate (i.e., when ‘git apply’ is used internally). + + +File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating + +6.5 Committing +============== + +When the user initiates a commit, Magit calls ‘git commit’ without any +arguments, so Git has to get it from the user. It creates the file +‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit +arranges for that editor to be the Emacsclient. Once the user finishes +the editing session, the Emacsclient exits and Git creates the commit +using the file’s content as message. + +* Menu: + +* Initiating a Commit:: +* Editing Commit Messages:: + + +File: magit.info, Node: Initiating a Commit, Next: Editing Commit Messages, Up: Committing + +6.5.1 Initiating a Commit +------------------------- + +Also see *note (gitman)git-commit::. + +‘c’ (‘magit-commit’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘c c’ (‘magit-commit-create’) + Create a new commit on ‘HEAD’. With a prefix argument amend to the + commit at ‘HEAD’ instead. + +‘c a’ (‘magit-commit-amend’) + Amend the last commit. + +‘c e’ (‘magit-commit-extend’) + Amend the last commit, without editing the message. With a prefix + argument keep the committer date, otherwise change it. The option + ‘magit-commit-extend-override-date’ can be used to inverse the + meaning of the prefix argument. + + Non-interactively respect the optional OVERRIDE-DATE argument and + ignore the option. + +‘c w’ (‘magit-commit-reword’) + Reword the last commit, ignoring staged changes. With a prefix + argument keep the committer date, otherwise change it. The option + ‘magit-commit-reword-override-date’ can be used to inverse the + meaning of the prefix argument. + + Non-interactively respect the optional OVERRIDE-DATE argument and + ignore the option. + +‘c f’ (‘magit-commit-fixup’) + Create a fixup commit. + + With a prefix argument the target commit has to be confirmed. + Otherwise the commit at point may be used without confirmation + depending on the value of option ‘magit-commit-squash-confirm’. + +‘c F’ (‘magit-commit-instant-fixup’) + Create a fixup commit and instantly rebase. + +‘c s’ (‘magit-commit-squash’) + Create a squash commit, without editing the squash message. + + With a prefix argument the target commit has to be confirmed. + Otherwise the commit at point may be used without confirmation + depending on the value of option ‘magit-commit-squash-confirm’. + +‘c S’ (‘magit-commit-instant-squash’) + Create a squash commit and instantly rebase. + +‘c A’ (‘magit-commit-augment’) + Create a squash commit, editing the squash message. + + With a prefix argument the target commit has to be confirmed. + Otherwise the commit at point may be used without confirmation + depending on the value of option ‘magit-commit-squash-confirm’. + + -- User Option: magit-commit-ask-to-stage + Whether to ask to stage all unstaged changes when committing and + nothing is staged. + + -- User Option: magit-commit-show-diff + Whether the relevant diff is automatically shown when committing. + + -- User Option: magit-commit-extend-override-date + Whether using ‘magit-commit-extend’ changes the committer date. + + -- User Option: magit-commit-reword-override-date + Whether using ‘magit-commit-reword’ changes the committer date. + + -- User Option: magit-commit-squash-confirm + Whether the commit targeted by squash and fixup has to be + confirmed. When non-nil then the commit at point (if any) is used + as default choice. Otherwise it has to be confirmed. This option + only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The + "instant" variants always require confirmation because making an + error while using those is harder to recover from. + + -- User Option: magit-post-commit-hook + Hook run after creating a commit without the user editing a + message. + + This hook is run by ‘magit-refresh’ if ‘this-command’ is a member + of ‘magit-post-commit-hook-commands’. This only includes commands + named ‘magit-commit-*’ that do *not* require that the user edits + the commit message in a buffer. + + Also see ‘git-commit-post-finish-hook’. + + -- User Option: magit-commit-diff-inhibit-same-window + Whether to inhibit use of same window when showing diff while + committing. + + When writing a commit, then a diff of the changes to be committed + is automatically shown. The idea is that the diff is shown in a + different window of the same frame and for most users that just + works. In other words most users can completely ignore this option + because its value doesn’t make a difference for them. + + However for users who configured Emacs to never create a new window + even when the package explicitly tries to do so, then displaying + two new buffers necessarily means that the first is immediately + replaced by the second. In our case the message buffer is + immediately replaced by the diff buffer, which is of course highly + undesirable. + + A workaround is to suppress this user configuration in this + particular case. Users have to explicitly opt-in by toggling this + option. We cannot enable the workaround unconditionally because + that again causes issues for other users: if the frame is too tiny + or the relevant settings too aggressive, then the diff buffer would + end up being displayed in a new frame. + + Also see <https://github.com/magit/magit/issues/4132>. + + +File: magit.info, Node: Editing Commit Messages, Prev: Initiating a Commit, Up: Committing + +6.5.2 Editing Commit Messages +----------------------------- + +After initiating a commit as described in the previous section, two new +buffers appear. One shows the changes that are about to be committed, +while the other is used to write the message. + + Commit messages are edited in an edit session - in the background +‘git’ is waiting for the editor, in our case ‘emacsclient’, to save the +commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then +return. If the editor returns with a non-zero exit status then ‘git’ +does not create the commit. So the most important commands are those +for finishing and aborting the commit. + +‘C-c C-c’ (‘with-editor-finish’) + Finish the current editing session by returning with exit code 0. + Git then creates the commit using the message it finds in the file. + +‘C-c C-k’ (‘with-editor-cancel’) + Cancel the current editing session by returning with exit code 1. + Git then cancels the commit, but leaves the file untouched. + + In addition to being used by ‘git commit’, messages may also be +stored in a ring that persists until Emacs is closed. By default the +message is stored at the beginning and the end of an edit session +(regardless of whether the session is finished successfully or was +canceled). It is sometimes useful to bring back messages from that +ring. + +‘C-c M-s’ (‘git-commit-save-message’) + Save the current buffer content to the commit message ring. + +‘M-p’ (‘git-commit-prev-message’) + Cycle backward through the commit message ring, after saving the + current message to the ring. With a numeric prefix ARG, go back + ARG comments. + +‘M-n’ (‘git-commit-next-message’) + Cycle forward through the commit message ring, after saving the + current message to the ring. With a numeric prefix ARG, go back + ARG comments. + + By default the diff for the changes that are about to be committed +are automatically shown when invoking the commit. To prevent that, +remove ‘magit-commit-diff’ from ‘server-switch-hook’. + + When amending to an existing commit it may be useful to show either +the changes that are about to be added to that commit or to show those +changes alongside those that have already been committed. + +‘C-c C-d’ (‘magit-diff-while-committing’) + While committing, show the changes that are about to be committed. + While amending, invoking the command again toggles between showing + just the new changes or all the changes that will be committed. + +* Menu: + +* Using the Revision Stack:: +* Commit Pseudo Headers:: +* Commit Mode and Hooks:: +* Commit Message Conventions:: + + +File: magit.info, Node: Using the Revision Stack, Next: Commit Pseudo Headers, Up: Editing Commit Messages + +Using the Revision Stack +........................ + +‘C-c C-w’ (‘magit-pop-revision-stack’) + This command inserts a representation of a revision into the + current buffer. It can be used inside buffers used to write commit + messages but also in other buffers such as buffers used to edit + emails or ChangeLog files. + + By default this command pops the revision which was last added to + the ‘magit-revision-stack’ and inserts it into the current buffer + according to ‘magit-pop-revision-stack-format’. Revisions can be + put on the stack using ‘magit-copy-section-value’ and + ‘magit-copy-buffer-revision’. + + If the stack is empty or with a prefix argument it instead reads a + revision in the minibuffer. By using the minibuffer history this + allows selecting an item which was popped earlier or to insert an + arbitrary reference or revision without first pushing it onto the + stack. + + When reading the revision from the minibuffer, then it might not be + possible to guess the correct repository. When this command is + called inside a repository (e.g., while composing a commit + message), then that repository is used. Otherwise (e.g., while + composing an email) then the repository recorded for the top + element of the stack is used (even though we insert another + revision). If not called inside a repository and with an empty + stack, or with two prefix arguments, then read the repository in + the minibuffer too. + + -- User Option: magit-pop-revision-stack-format + This option controls how the command ‘magit-pop-revision-stack’ + inserts a revision into the current buffer. + + The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this + option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all + of which may be nil or a string (though either one of EOB-FORMAT or + POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil, + then the two formats should be too). + + First INDEX-REGEXP is used to find the previously inserted entry, + by searching backward from point. The first submatch must match + the index number. That number is incremented by one, and becomes + the index number of the entry to be inserted. If you don’t want to + number the inserted revisions, then use nil for INDEX-REGEXP. + + If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT + should contain \"%N\", which is replaced with the number that was + determined in the previous step. + + Both formats, if non-nil and after removing %N, are then expanded + using ‘git show --format=FORMAT ...’ inside TOPLEVEL. + + The expansion of POINT-FORMAT is inserted at point, and the + expansion of EOB-FORMAT is inserted at the end of the buffer (if + the buffer ends with a comment, then it is inserted right before + that). + + +File: magit.info, Node: Commit Pseudo Headers, Next: Commit Mode and Hooks, Prev: Using the Revision Stack, Up: Editing Commit Messages + +Commit Pseudo Headers +..................... + +Some projects use pseudo headers in commit messages. Magit colorizes +such headers and provides some commands to insert such headers. + + -- User Option: git-commit-known-pseudo-headers + A list of Git pseudo headers to be highlighted. + +‘C-c C-i’ (‘git-commit-insert-pseudo-header’) + Insert a commit message pseudo header. + +‘C-c C-a’ (‘git-commit-ack’) + Insert a header acknowledging that you have looked at the commit. + +‘C-c C-r’ (‘git-commit-review’) + Insert a header acknowledging that you have reviewed the commit. + +‘C-c C-s’ (‘git-commit-signoff’) + Insert a header to sign off the commit. + +‘C-c C-t’ (‘git-commit-test’) + Insert a header acknowledging that you have tested the commit. + +‘C-c C-o’ (‘git-commit-cc’) + Insert a header mentioning someone who might be interested. + +‘C-c C-p’ (‘git-commit-reported’) + Insert a header mentioning the person who reported the issue being + fixed by the commit. + +‘C-c M-i’ (‘git-commit-suggested’) + Insert a header mentioning the person who suggested the change. + + +File: magit.info, Node: Commit Mode and Hooks, Next: Commit Message Conventions, Prev: Commit Pseudo Headers, Up: Editing Commit Messages + +Commit Mode and Hooks +..................... + +‘git-commit-mode’ is a minor mode that is only used to establish certain +key bindings. This makes it possible to use an arbitrary major mode in +buffers used to edit commit messages. It is even possible to use +different major modes in different repositories, which is useful when +different projects impose different commit message conventions. + + -- User Option: git-commit-major-mode + The value of this option is the major mode used to edit Git commit + messages. + + Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook +to setup the buffer, except for the key bindings. All other setup +happens in the function ‘git-commit-setup’, which among other things +runs the hook ‘git-commit-setup-hook’. + + -- User Option: git-commit-setup-hook + Hook run at the end of ‘git-commit-setup’. + +The following functions are suitable for this hook: + + -- Function: git-commit-save-message + Save the current buffer content to the commit message ring. + + -- Function: git-commit-setup-changelog-support + After this function is called, ChangeLog entries are treated as + paragraphs. + + -- Function: git-commit-turn-on-auto-fill + Turn on ‘auto-fill-mode’. + + -- Function: git-commit-turn-on-flyspell + Turn on Flyspell mode. Also prevent comments from being checked + and finally check current non-comment text. + + -- Function: git-commit-propertize-diff + Propertize the diff shown inside the commit message buffer. Git + inserts such diffs into the commit message template when the + ‘--verbose’ argument is used. ‘magit-commit’ by default does not + offer that argument because the diff that is shown in a separate + buffer is more useful. But some users disagree, which is why this + function exists. + + -- Function: bug-reference-mode + Hyperlink bug references in the buffer. + + -- Function: with-editor-usage-message + Show usage information in the echo area. + + -- User Option: git-commit-post-finish-hook + Hook run after the user finished writing a commit message. + + This hook is only run after pressing ‘C-c C-c’ in a buffer used to + edit a commit message. If a commit is created without the user + typing a message into a buffer, then this hook is not run. + + This hook is not run until the new commit has been created. If + doing so takes Git longer than one second, then this hook isn’t run + at all. For certain commands such as ‘magit-rebase-continue’ this + hook is never run because doing so would lead to a race condition. + + This hook is only run if ‘magit’ is available. + + Also see ‘magit-post-commit-hook’. + + +File: magit.info, Node: Commit Message Conventions, Prev: Commit Mode and Hooks, Up: Editing Commit Messages + +Commit Message Conventions +.......................... + +Git-Commit highlights certain violations of commonly accepted commit +message conventions. Certain violations even cause Git-Commit to ask +you to confirm that you really want to do that. This nagging can of +course be turned off, but the result of doing that usually is that +instead of some code it’s now the human who is reviewing your commits +who has to waste some time telling you to fix your commits. + + -- User Option: git-commit-summary-max-length + The intended maximal length of the summary line of commit messages. + Characters beyond this column are colorized to indicate that this + preference has been violated. + + -- User Option: git-commit-finish-query-functions + List of functions called to query before performing commit. + + The commit message buffer is current while the functions are + called. If any of them returns nil, then the commit is not + performed and the buffer is not killed. The user should then fix + the issue and try again. + + The functions are called with one argument. If it is non-nil then + that indicates that the user used a prefix argument to force + finishing the session despite issues. Functions should usually + honor this wish and return non-nil. + + By default the only member is ‘git-commit-check-style-conventions’. + + -- Function: git-commit-check-style-conventions + This function checks for violations of certain basic style + conventions. For each violation it asks users if they want to + proceed anyway. + + -- User Option: git-commit-style-convention-checks + This option controls what conventions the function by the same name + tries to enforce. The value is a list of self-explanatory symbols + identifying certain conventions; ‘non-empty-second-line’ and + ‘overlong-summary-line’. + + +File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating + +6.6 Branching +============= + +* Menu: + +* The Two Remotes:: +* Branch Commands:: +* Branch Git Variables:: +* Auxiliary Branch Commands:: + + +File: magit.info, Node: The Two Remotes, Next: Branch Commands, Up: Branching + +6.6.1 The Two Remotes +--------------------- + +The upstream branch of some local branch is the branch into which the +commits on that local branch should eventually be merged, usually +something like ‘origin/master’. For the ‘master’ branch itself the +upstream branch and the branch it is being pushed to, are usually the +same remote branch. But for a feature branch the upstream branch and +the branch it is being pushed to should differ. + + The commits on feature branches too should _eventually_ end up in a +remote branch such as ‘origin/master’ or ‘origin/maint’. Such a branch +should therefore be used as the upstream. But feature branches +shouldn’t be pushed directly to such branches. Instead a feature branch +‘my-feature’ is usually pushed to ‘my-fork/my-feature’ or if you are a +contributor ‘origin/my-feature’. After the new feature has been +reviewed, the maintainer merges the feature into ‘master’. And finally +‘master’ (not ‘my-feature’ itself) is pushed to ‘origin/master’. + + But new features seldom are perfect on the first try, and so feature +branches usually have to be reviewed, improved, and re-pushed several +times. Pushing should therefore be easy to do, and for that reason many +Git users have concluded that it is best to use the remote branch to +which the local feature branch is being pushed as its upstream. + + But luckily Git has long ago gained support for a push-remote which +can be configured separately from the upstream branch, using the +variables ‘branch.<name>.pushRemote’ and ‘remote.pushDefault’. So we no +longer have to choose which of the two remotes should be used as "the +remote". + + Each of the fetching, pulling, and pushing transient commands +features three suffix commands that act on the current branch and some +other branch. Of these, ‘p’ is bound to a command which acts on the +push-remote, ‘u’ is bound to a command which acts on the upstream, and +‘e’ is bound to a command which acts on any other branch. The status +buffer shows unpushed and unpulled commits for both the push-remote and +the upstream. + + It’s fairly simple to configure these two remotes. The values of all +the variables that are related to fetching, pulling, and pushing (as +well as some other branch-related variables) can be inspected and +changed using the command ‘magit-branch-configure’, which is available +from many transient prefix commands that deal with branches. It is also +possible to set the push-remote or upstream while pushing (see *note +Pushing::). + + +File: magit.info, Node: Branch Commands, Next: Branch Git Variables, Prev: The Two Remotes, Up: Branching + +6.6.2 Branch Commands +--------------------- + +The transient prefix command ‘magit-branch’ is used to create and +checkout branches, and to make changes to existing branches. It is not +used to fetch, pull, merge, rebase, or push branches, i.e., this command +deals with branches themselves, not with the commits reachable from +them. Those features are available from separate transient command. + +‘b’ (‘magit-branch’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + + By default it also binds and displays the values of some + branch-related Git variables and allows changing their values. + + -- User Option: magit-branch-direct-configure + This option controls whether the transient command ‘magit-branch’ + can be used to directly change the values of Git variables. This + defaults to ‘t’ (to avoid changing key bindings). When set to + ‘nil’, then no variables are displayed by that transient command, + and its suffix command ‘magit-branch-configure’ has to be used + instead to view and change branch related variables. + +‘b C’ (‘magit-branch-configure’) +‘f C’ +‘F C’ +‘P C’ + This transient prefix command binds commands that set the value of + branch-related variables and displays them in a temporary buffer + until the transient is exited. + + With a prefix argument, this command always prompts for a branch. + + Without a prefix argument this depends on whether it was invoked as + a suffix of ‘magit-branch’ and on the + ‘magit-branch-direct-configure’ option. If ‘magit-branch’ already + displays the variables for the current branch, then it isn’t useful + to invoke another transient that displays them for the same branch. + In that case this command prompts for a branch. + + The variables are described in *note Branch Git Variables::. + +‘b b’ (‘magit-checkout’) + Checkout a revision read in the minibuffer and defaulting to the + branch or arbitrary revision at point. If the revision is a local + branch then that becomes the current branch. If it is something + else then ‘HEAD’ becomes detached. Checkout fails if the working + tree or the staging area contain changes. + +‘b n’ (‘magit-branch-create’) + Create a new branch. The user is asked for a branch or arbitrary + revision to use as the starting point of the new branch. When a + branch name is provided, then that becomes the upstream branch of + the new branch. The name of the new branch is also read in the + minibuffer. + + Also see option ‘magit-branch-prefer-remote-upstream’. + +‘b c’ (‘magit-branch-and-checkout’) + This command creates a new branch like ‘magit-branch-create’, but + then also checks it out. + + Also see option ‘magit-branch-prefer-remote-upstream’. + +‘b l’ (‘magit-branch-checkout’) + This command checks out an existing or new local branch. It reads + a branch name from the user offering all local branches and a + subset of remote branches as candidates. Remote branches for which + a local branch by the same name exists are omitted from the list of + candidates. The user can also enter a completely new branch name. + + • If the user selects an existing local branch, then that is + checked out. + + • If the user selects a remote branch, then it creates and + checks out a new local branch with the same name, and + configures the selected remote branch as the push target. + + • If the user enters a new branch name, then it creates and + checks that out, after also reading the starting-point from + the user. + + In the latter two cases the upstream is also set. Whether it is + set to the chosen starting point or something else depends on the + value of ‘magit-branch-adjust-remote-upstream-alist’. + +‘b s’ (‘magit-branch-spinoff’) + This command creates and checks out a new branch starting at and + tracking the current branch. That branch in turn is reset to the + last commit it shares with its upstream. If the current branch has + no upstream or no unpushed commits, then the new branch is created + anyway and the previously current branch is not touched. + + This is useful to create a feature branch after work has already + began on the old branch (likely but not necessarily "master"). + + If the current branch is a member of the value of option + ‘magit-branch-prefer-remote-upstream’ (which see), then the current + branch will be used as the starting point as usual, but the + upstream of the starting-point may be used as the upstream of the + new branch, instead of the starting-point itself. + + If optional FROM is non-nil, then the source branch is reset to + ‘FROM~’, instead of to the last commit it shares with its upstream. + Interactively, FROM is only ever non-nil, if the region selects + some commits, and among those commits, FROM is the commit that is + the fewest commits ahead of the source branch. + + The commit at the other end of the selection actually does not + matter, all commits between FROM and ‘HEAD’ are moved to the new + branch. If FROM is not reachable from ‘HEAD’ or is reachable from + the source branch’s upstream, then an error is raised. + +‘b S’ (‘magit-branch-spinout’) + This command behaves like ‘magit-branch-spinoff’, except that it + does not change the current branch. If there are any uncommitted + changes, then it behaves exactly like ‘magit-branch-spinoff’. + +‘b x’ (‘magit-branch-reset’) + This command resets a branch, defaulting to the branch at point, to + the tip of another branch or any other commit. + + When the branch being reset is the current branch, then a hard + reset is performed. If there are any uncommitted changes, then the + user has to confirm the reset because those changes would be lost. + + This is useful when you have started work on a feature branch but + realize it’s all crap and want to start over. + + When resetting to another branch and a prefix argument is used, + then the target branch is set as the upstream of the branch that is + being reset. + +‘b k’ (‘magit-branch-delete’) + Delete one or multiple branches. If the region marks multiple + branches, then offer to delete those. Otherwise, prompt for a + single branch to be deleted, defaulting to the branch at point. + + Require confirmation when deleting branches is dangerous in some + way. Option ‘magit-no-confirm’ can be customized to not require + confirmation in certain cases. See its docstring to learn why + confirmation is required by default in certain cases or if a prompt + is confusing. + +‘b m’ (‘magit-branch-rename’) + Rename a branch. The branch and the new name are read in the + minibuffer. With prefix argument the branch is renamed even if + that name conflicts with an existing branch. + + -- User Option: magit-branch-read-upstream-first + When creating a branch, whether to read the upstream branch before + the name of the branch that is to be created. The default is ‘t’, + and I recommend you leave it at that. + + -- User Option: magit-branch-prefer-remote-upstream + This option specifies whether remote upstreams are favored over + local upstreams when creating new branches. + + When a new branch is created, then the branch, commit, or stash at + point is suggested as the starting point of the new branch, or if + there is no such revision at point the current branch. In either + case the user may choose another starting point. + + If the chosen starting point is a branch, then it may also be set + as the upstream of the new branch, depending on the value of the + Git variable ‘branch.autoSetupMerge’. By default this is done for + remote branches, but not for local branches. + + You might prefer to always use some remote branch as upstream. If + the chosen starting point is (1) a local branch, (2) whose name + matches a member of the value of this option, (3) the upstream of + that local branch is a remote branch with the same name, and (4) + that remote branch can be fast-forwarded to the local branch, then + the chosen branch is used as starting point, but its own upstream + is used as the upstream of the new branch. + + Members of this option’s value are treated as branch names that + have to match exactly unless they contain a character that makes + them invalid as a branch name. Recommended characters to use to + trigger interpretation as a regexp are "*" and "^". Some other + characters which you might expect to be invalid, actually are not, + e.g., ".+$" are all perfectly valid. More precisely, if ‘git + check-ref-format --branch STRING’ exits with a non-zero status, + then treat STRING as a regexp. + + Assuming the chosen branch matches these conditions you would end + up with with e.g.: + + feature --upstream--> origin/master + + instead of + + feature --upstream--> master --upstream--> origin/master + + Which you prefer is a matter of personal preference. If you do + prefer the former, then you should add branches such as ‘master’, + ‘next’, and ‘maint’ to the value of this options. + + -- User Option: magit-branch-adjust-remote-upstream-alist + The value of this option is an alist of branches to be used as the + upstream when branching a remote branch. + + When creating a local branch from an ephemeral branch located on a + remote, e.g., a feature or hotfix branch, then that remote branch + should usually not be used as the upstream branch, since the + push-remote already allows accessing it and having both the + upstream and the push-remote reference the same related branch + would be wasteful. Instead a branch like "maint" or "master" + should be used as the upstream. + + This option allows specifying the branch that should be used as the + upstream when branching certain remote branches. The value is an + alist of the form ‘((UPSTREAM . RULE)...)’. The first matching + element is used, the following elements are ignored. + + UPSTREAM is the branch to be used as the upstream for branches + specified by RULE. It can be a local or a remote branch. + + RULE can either be a regular expression, matching branches whose + upstream should be the one specified by UPSTREAM. Or it can be a + list of the only branches that should *not* use UPSTREAM; all other + branches will. Matching is done after stripping the remote part of + the name of the branch that is being branched from. + + If you use a finite set of non-ephemeral branches across all your + repositories, then you might use something like: + + (("origin/master" . ("master" "next" "maint"))) + + Or if the names of all your ephemeral branches contain a slash, at + least in some repositories, then a good value could be: + + (("origin/master" . "/")) + + Of course you can also fine-tune: + + (("origin/maint" . "\\`hotfix/") + ("origin/master" . "\\`feature/")) + + UPSTREAM can be a local branch: + + (("master" . ("master" "next" "maint"))) + + Because the main branch is no longer almost always named "master" you +should also account for other common names: + + (("main" . ("main" "master" "next" "maint")) + ("master" . ("main" "master" "next" "maint"))) + + -- Command: magit-branch-orphan + This command creates and checks out a new orphan branch with + contents from a given revision. + + -- Command: magit-branch-or-checkout + This command is a hybrid between ‘magit-checkout’ and + ‘magit-branch-and-checkout’ and is intended as a replacement for + the former in ‘magit-branch’. + + It first asks the user for an existing branch or revision. If the + user input actually can be resolved as a branch or revision, then + it checks that out, just like ‘magit-checkout’ would. + + Otherwise it creates and checks out a new branch using the input as + its name. Before doing so it reads the starting-point for the new + branch. This is similar to what ‘magit-branch-and-checkout’ does. + + To use this command instead of ‘magit-checkout’ add this to your + init file: + + (transient-replace-suffix 'magit-branch 'magit-checkout + '("b" "dwim" magit-branch-or-checkout)) + + +File: magit.info, Node: Branch Git Variables, Next: Auxiliary Branch Commands, Prev: Branch Commands, Up: Branching + +6.6.3 Branch Git Variables +-------------------------- + +These variables can be set from the transient prefix command +‘magit-branch-configure’. By default they can also be set from +‘magit-branch’. See *note Branch Commands::. + + -- Variable: branch.NAME.merge + Together with ‘branch.NAME.remote’ this variable defines the + upstream branch of the local branch named NAME. The value of this + variable is the full reference of the upstream _branch_. + + -- Variable: branch.NAME.remote + Together with ‘branch.NAME.merge’ this variable defines the + upstream branch of the local branch named NAME. The value of this + variable is the name of the upstream _remote_. + + -- Variable: branch.NAME.rebase + This variable controls whether pulling into the branch named NAME + is done by rebasing or by merging the fetched branch. + + • When ‘true’ then pulling is done by rebasing. + • When ‘false’ then pulling is done by merging. + • When undefined then the value of ‘pull.rebase’ is used. The + default of that variable is ‘false’. + + -- Variable: branch.NAME.pushRemote + This variable specifies the remote that the branch named NAME is + usually pushed to. The value has to be the name of an existing + remote. + + It is not possible to specify the name of _branch_ to push the + local branch to. The name of the remote branch is always the same + as the name of the local branch. + + If this variable is undefined but ‘remote.pushDefault’ is defined, + then the value of the latter is used. By default + ‘remote.pushDefault’ is undefined. + + -- Variable: branch.NAME.description + This variable can be used to describe the branch named NAME. That + description is used, e.g., when turning the branch into a series of + patches. + + The following variables specify defaults which are used if the above +branch-specific variables are not set. + + -- Variable: pull.rebase + This variable specifies whether pulling is done by rebasing or by + merging. It can be overwritten using ‘branch.NAME.rebase’. + + • When ‘true’ then pulling is done by rebasing. + • When ‘false’ (the default) then pulling is done by merging. + + Since it is never a good idea to merge the upstream branch into a + feature or hotfix branch and most branches are such branches, you + should consider setting this to ‘true’, and ‘branch.master.rebase’ + to ‘false’. + + -- Variable: remote.pushDefault + This variable specifies what remote the local branches are usually + pushed to. This can be overwritten per branch using + ‘branch.NAME.pushRemote’. + + The following variables are used during the creation of a branch and +control whether the various branch-specific variables are automatically +set at this time. + + -- Variable: branch.autoSetupMerge + This variable specifies under what circumstances creating a branch + NAME should result in the variables ‘branch.NAME.merge’ and + ‘branch.NAME.remote’ being set according to the starting point used + to create the branch. If the starting point isn’t a branch, then + these variables are never set. + + • When ‘always’ then the variables are set regardless of whether + the starting point is a local or a remote branch. + • When ‘true’ (the default) then the variables are set when the + starting point is a remote branch, but not when it is a local + branch. + • When ‘false’ then the variables are never set. + + -- Variable: branch.autoSetupRebase + This variable specifies whether creating a branch NAME should + result in the variable ‘branch.NAME.rebase’ being set to ‘true’. + + • When ‘always’ then the variable is set regardless of whether + the starting point is a local or a remote branch. + • When ‘local’ then the variable are set when the starting point + is a local branch, but not when it is a remote branch. + • When ‘remote’ then the variable are set when the starting + point is a remote branch, but not when it is a local branch. + • When ‘never’ (the default) then the variable is never set. + + Note that the respective commands always change the repository-local +values. If you want to change the global value, which is used when the +local value is undefined, then you have to do so on the command line, +e.g.: + + git config --global remote.autoSetupMerge always + + For more information about these variables you should also see + + *note (gitman)git-config::. Also see *note (gitman)git-branch::. , +*note (gitman)git-checkout::. and *note Pushing::. + + -- User Option: magit-prefer-remote-upstream + This option controls whether commands that read a branch from the + user and then set it as the upstream branch, offer a local or a + remote branch as default completion candidate, when they have the + choice. + + This affects all commands that use ‘magit-read-upstream-branch’ or + ‘magit-read-starting-point’, which includes all commands that + change the upstream and many which create new branches. + + +File: magit.info, Node: Auxiliary Branch Commands, Prev: Branch Git Variables, Up: Branching + +6.6.4 Auxiliary Branch Commands +------------------------------- + +These commands are not available from the transient ‘magit-branch’ by +default. + + -- Command: magit-branch-shelve + This command shelves a branch. This is done by deleting the + branch, and creating a new reference "refs/shelved/BRANCH-NAME" + pointing at the same commit as the branch pointed at. If the + deleted branch had a reflog, then that is preserved as the reflog + of the new reference. + + This is useful if you want to move a branch out of sight, but are + not ready to completely discard it yet. + + -- Command: magit-branch-unshelve + This command unshelves a branch that was previously shelved using + ‘magit-branch-shelve’. This is done by deleting the reference + "refs/shelved/BRANCH-NAME" and creating a branch "BRANCH-NAME" + pointing at the same commit as the deleted reference pointed at. + If the deleted reference had a reflog, then that is restored as the + reflog of the branch. + + +File: magit.info, Node: Merging, Next: Resolving Conflicts, Prev: Branching, Up: Manipulating + +6.7 Merging +=========== + +Also see *note (gitman)git-merge::. For information on how to resolve +merge conflicts see the next section. + +‘m’ (‘magit-merge’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no merge is in progress, then the transient features the +following suffix commands. + +‘m m’ (‘magit-merge-plain’) + This command merges another branch or an arbitrary revision into + the current branch. The branch or revision to be merged is read in + the minibuffer and defaults to the branch at point. + + Unless there are conflicts or a prefix argument is used, then the + resulting merge commit uses a generic commit message, and the user + does not get a chance to inspect or change it before the commit is + created. With a prefix argument this does not actually create the + merge commit, which makes it possible to inspect how conflicts were + resolved and to adjust the commit message. + +‘m e’ (‘magit-merge-editmsg’) + This command merges another branch or an arbitrary revision into + the current branch and opens a commit message buffer, so that the + user can make adjustments. The commit is not actually created + until the user finishes with ‘C-c C-c’. + +‘m n’ (‘magit-merge-nocommit’) + This command merges another branch or an arbitrary revision into + the current branch, but does not actually create the merge commit. + The user can then further adjust the merge, even when automatic + conflict resolution succeeded and/or adjust the commit message. + +‘m a’ (‘magit-merge-absorb’) + This command merges another local branch into the current branch + and then removes the former. + + Before the source branch is merged, it is first force pushed to its + push-remote, provided the respective remote branch already exists. + This ensures that the respective pull-request (if any) won’t get + stuck on some obsolete version of the commits that are being + merged. Finally, if ‘magit-branch-pull-request’ was used to create + the merged branch, then the respective remote branch is also + removed. + +‘m i’ (‘magit-merge-into’) + This command merges the current branch into another local branch + and then removes the former. The latter becomes the new current + branch. + + Before the source branch is merged, it is first force pushed to its + push-remote, provided the respective remote branch already exists. + This ensures that the respective pull-request (if any) won’t get + stuck on some obsolete version of the commits that are being + merged. Finally, if ‘magit-branch-pull-request’ was used to create + the merged branch, then the respective remote branch is also + removed. + +‘m s’ (‘magit-merge-squash’) + This command squashes the changes introduced by another branch or + an arbitrary revision into the current branch. This only applies + the changes made by the squashed commits. No information is + preserved that would allow creating an actual merge commit. + Instead of this command you should probably use a command from the + apply transient. + +‘m p’ (‘magit-merge-preview’) + This command shows a preview of merging another branch or an + arbitrary revision into the current branch. + + Note that commands, that normally change how a diff is displayed, + do not work in buffers created by this command, because the + underlying Git command does not support diff arguments. + + When a merge is in progress, then the transient instead features the +following suffix commands. + +‘m m’ (‘magit-merge’) + After the user resolved conflicts, this command proceeds with the + merge. If some conflicts weren’t resolved, then this command + fails. + +‘m a’ (‘magit-merge-abort’) + This command aborts the current merge operation. + + +File: magit.info, Node: Resolving Conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating + +6.8 Resolving Conflicts +======================= + +When merging branches (or otherwise combining or changing history) +conflicts can occur. If you edited two completely different parts of +the same file in two branches and then merge one of these branches into +the other, then Git can resolve that on its own, but if you edit the +same area of a file, then a human is required to decide how the two +versions, or "sides of the conflict", are to be combined into one. + + Here we can only provide a brief introduction to the subject and +point you toward some tools that can help. If you are new to this, then +please also consult Git’s own documentation as well as other resources. + + If a file has conflicts and Git cannot resolve them by itself, then +it puts both versions into the affected file along with special markers +whose purpose is to denote the boundaries of the unresolved part of the +file and between the different versions. These boundary lines begin +with the strings consisting of seven times the same character, one of +‘<’, ‘|’, ‘=’ and ‘>’, and are followed by information about the source +of the respective versions, e.g.: + + <<<<<<< HEAD + Take the blue pill. + ======= + Take the red pill. + >>>>>>> feature + + In this case you have chosen to take the red pill on one branch and +on another you picked the blue pill. Now that you are merging these two +diverging branches, Git cannot possibly know which pill you want to +take. + + To resolve that conflict you have to create a version of the affected +area of the file by keeping only one of the sides, possibly by editing +it in order to bring in the changes from the other side, remove the +other versions as well as the markers, and then stage the result. A +possible resolution might be: + + Take both pills. + + Often it is useful to see not only the two sides of the conflict but +also the "original" version from before the same area of the file was +modified twice on different branches. Instruct Git to insert that +version as well by running this command once: + + git config --global merge.conflictStyle diff3 + + The above conflict might then have looked like this: + + <<<<<<< HEAD + Take the blue pill. + ||||||| merged common ancestors + Take either the blue or the red pill, but not both. + ======= + Take the red pill. + >>>>>>> feature + + If that were the case, then the above conflict resolution would not +have been correct, which demonstrates why seeing the original version +alongside the conflicting versions can be useful. + + You can perform the conflict resolution completely by hand, but Emacs +also provides some packages that help in the process: Smerge, Ediff +(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does +not provide its own tools for conflict resolution, but it does make +using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so +you probably don’t want to use the latter anyway.) + + In the Magit status buffer, files with unresolved conflicts are +listed in the "Unstaged changes" and/or "Staged changes" sections. They +are prefixed with the word "unmerged", which in this context essentially +is a synonym for "unresolved". + + Pressing ‘RET’ while point is on such a file section shows a buffer +visiting that file, turns on ‘smerge-mode’ in that buffer, and places +point inside the first area with conflicts. You should then resolve +that conflict using regular edit commands and/or Smerge commands. + + Unfortunately Smerge does not have a manual, but you can get a list +of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a +command name to read its documentation. + + Normally you would edit one version and then tell Smerge to keep only +that version. Use ‘C-c ^ m’ (‘smerge-keep-mine’) to keep the ‘HEAD’ +version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that +follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting +area in the same file. Once you are done resolving conflicts, return to +the Magit status buffer. The file should now be shown as "modified", no +longer as "unmerged", because Smerge automatically stages the file when +you save the buffer after resolving the last conflict. + + Magit now wraps the mentioned Smerge commands, allowing you to use +these key bindings without having to go to the file-visiting buffer. +Additionally ‘k’ (‘magit-discard’) on a hunk with unresolved conflicts +asks which side to keep or, if point is on a side, then it keeps it +without prompting. Similarly ‘k’ on a unresolved file ask which side to +keep. + + Alternatively you could use Ediff, which uses separate buffers for +the different versions of the file. To resolve conflicts in a file +using Ediff press ‘e’ while point is on such a file in the status +buffer. + + Ediff can be used for other purposes as well. For more information +on how to enter Ediff from Magit, see *note Ediffing::. Explaining how +to use Ediff is beyond the scope of this manual, instead see *note +(ediff)Top::. + + If you are unsure whether you should Smerge or Ediff, then use the +former. It is much easier to understand and use, and except for truly +complex conflicts, the latter is usually overkill. + + +File: magit.info, Node: Rebasing, Next: Cherry Picking, Prev: Resolving Conflicts, Up: Manipulating + +6.9 Rebasing +============ + +Also see *note (gitman)git-rebase::. For information on how to resolve +conflicts that occur during rebases see the preceding section. + +‘r’ (‘magit-rebase’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no rebase is in progress, then the transient features the +following suffix commands. + + Using one of these commands _starts_ a rebase sequence. Git might +then stop somewhere along the way, either because you told it to do so, +or because applying a commit failed due to a conflict. When that +happens, then the status buffer shows information about the rebase +sequence which is in progress in a section similar to a log section. +See *note Information About In-Progress Rebase::. + + For information about the upstream and the push-remote, see *note The +Two Remotes::. + +‘r p’ (‘magit-rebase-onto-pushremote’) + This command rebases the current branch onto its push-remote. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘r u’ (‘magit-rebase-onto-upstream’) + This command rebases the current branch onto its upstream branch. + + With a prefix argument or when the upstream is either not + configured or unusable, then let the user first configure the + upstream. + +‘r e’ (‘magit-rebase-branch’) + This command rebases the current branch onto a branch read in the + minibuffer. All commits that are reachable from head but not from + the selected branch TARGET are being rebased. + +‘r s’ (‘magit-rebase-subset’) + This command starts a non-interactive rebase sequence to transfer + commits from START to ‘HEAD’ onto NEWBASE. START has to be + selected from a list of recent commits. + + By default Magit uses the ‘--autostash’ argument, which causes +uncommitted changes to be stored in a stash before the rebase begins. +These changes are restored after the rebase completes and if possible +the stash is removed. If the stash does not apply cleanly, then the +stash is not removed. In case something goes wrong when resolving the +conflicts, this allows you to start over. + + Even though one of the actions is dedicated to interactive rebases, +the transient also features the infix argument ‘--interactive’. This +can be used to turn one of the other, non-interactive rebase variants +into an interactive rebase. + + For example if you want to clean up a feature branch and at the same +time rebase it onto ‘master’, then you could use ‘r-iu’. But we +recommend that you instead do that in two steps. First use ‘ri’ to +cleanup the feature branch, and then in a second step ‘ru’ to rebase it +onto ‘master’. That way if things turn out to be more complicated than +you thought and/or you make a mistake and have to start over, then you +only have to redo half the work. + + Explicitly enabling ‘--interactive’ won’t have an effect on the +following commands as they always use that argument anyway, even if it +is not enabled in the transient. + +‘r i’ (‘magit-rebase-interactive’) + This command starts an interactive rebase sequence. + +‘r f’ (‘magit-rebase-autosquash’) + This command combines squash and fixup commits with their intended + targets. + +‘r m’ (‘magit-rebase-edit-commit’) + This command starts an interactive rebase sequence that lets the + user edit a single older commit. + +‘r w’ (‘magit-rebase-reword-commit’) + This command starts an interactive rebase sequence that lets the + user reword a single older commit. + +‘r k’ (‘magit-rebase-remove-commit’) + This command removes a single older commit using rebase. + + When a rebase is in progress, then the transient instead features the +following suffix commands. + +‘r r’ (‘magit-rebase-continue’) + This command restart the current rebasing operation. + + In some cases this pops up a commit message buffer for you do edit. + With a prefix argument the old message is reused as-is. + +‘r s’ (‘magit-rebase-skip’) + This command skips the current commit and restarts the current + rebase operation. + +‘r e’ (‘magit-rebase-edit’) + This command lets the user edit the todo list of the current rebase + operation. + +‘r a’ (‘magit-rebase-abort’) + This command aborts the current rebase operation, restoring the + original branch. + +* Menu: + +* Editing Rebase Sequences:: +* Information About In-Progress Rebase:: + + +File: magit.info, Node: Editing Rebase Sequences, Next: Information About In-Progress Rebase, Up: Rebasing + +6.9.1 Editing Rebase Sequences +------------------------------ + +‘C-c C-c’ (‘with-editor-finish’) + Finish the current editing session by returning with exit code 0. + Git then uses the rebase instructions it finds in the file. + +‘C-c C-k’ (‘with-editor-cancel’) + Cancel the current editing session by returning with exit code 1. + Git then forgoes starting the rebase sequence. + +‘<RET>’ (‘git-rebase-show-commit’) + Show the commit on the current line in another buffer and select + that buffer. + +‘<SPC>’ (‘git-rebase-show-or-scroll-up’) + Show the commit on the current line in another buffer without + selecting that buffer. If the revision buffer is already visible + in another window of the current frame, then instead scroll that + window up. + +‘<DEL>’ (‘git-rebase-show-or-scroll-down’) + Show the commit on the current line in another buffer without + selecting that buffer. If the revision buffer is already visible + in another window of the current frame, then instead scroll that + window down. + +‘p’ (‘git-rebase-backward-line’) + Move to previous line. + +‘n’ (‘forward-line’) + Move to next line. + +‘M-p’ (‘git-rebase-move-line-up’) + Move the current commit (or command) up. + +‘M-n’ (‘git-rebase-move-line-down’) + Move the current commit (or command) down. + +‘r’ (‘git-rebase-reword’) + Edit message of commit on current line. + +‘e’ (‘git-rebase-edit’) + Stop at the commit on the current line. + +‘s’ (‘git-rebase-squash’) + Meld commit on current line into previous commit, and edit message. + +‘f’ (‘git-rebase-fixup’) + Meld commit on current line into previous commit, discarding the + current commit’s message. + +‘k’ (‘git-rebase-kill-line’) + Kill the current action line. + +‘c’ (‘git-rebase-pick’) + Use commit on current line. + +‘x’ (‘git-rebase-exec’) + Insert a shell command to be run after the proceeding commit. + + If there already is such a command on the current line, then edit + that instead. With a prefix argument insert a new command even + when there already is one on the current line. With empty input + remove the command on the current line, if any. + +‘b’ (‘git-rebase-break’) + Insert a break action before the current line, instructing Git to + return control to the user. + +‘y’ (‘git-rebase-insert’) + Read an arbitrary commit and insert it below current line. + +‘C-x u’ (‘git-rebase-undo’) + Undo some previous changes. Like ‘undo’ but works in read-only + buffers. + + -- User Option: git-rebase-auto-advance + Whether to move to next line after changing a line. + + -- User Option: git-rebase-show-instructions + Whether to show usage instructions inside the rebase buffer. + + -- User Option: git-rebase-confirm-cancel + Whether confirmation is required to cancel. + + When a rebase is performed with the ‘--rebase-merges’ option, the +sequence will include a few other types of actions and the following +commands become relevant. + +‘l’ (‘git-rebase-label’) + This commands inserts a label action or edits the one at point. + +‘t’ (‘git-rebase-reset’) + This command inserts a reset action or edits the one at point. The + prompt will offer the labels that are currently present in the + buffer. + +‘MM’ (‘git-rebase-merge’) + The command inserts a merge action or edits the one at point. The + prompt will offer the labels that are currently present in the + buffer. Specifying a message to reuse via ‘-c’ or ‘-C’ is not + supported; an editor will always be invoked for the merge. + +‘Mt’ (‘git-rebase-merge-toggle-editmsg’) + This command toggles between the ‘-C’ and ‘-c’ options of the merge + action at point. These options both specify a commit whose message + should be reused. The lower-case variant instructs Git to invoke + the editor when creating the merge, allowing the user to edit the + message. + + +File: magit.info, Node: Information About In-Progress Rebase, Prev: Editing Rebase Sequences, Up: Rebasing + +6.9.2 Information About In-Progress Rebase +------------------------------------------ + +While a rebase sequence is in progress, the status buffer features a +section that lists the commits that have already been applied as well as +the commits that still have to be applied. + + The commits are split in two halves. When rebase stops at a commit, +either because the user has to deal with a conflict or because s/he +explicitly requested that rebase stops at that commit, then point is +placed on the commit that separates the two groups, i.e., on ‘HEAD’. +The commits above it have not been applied yet, while the ‘HEAD’ and the +commits below it have already been applied. In between these two groups +of applied and yet-to-be applied commits, there sometimes is a commit +which has been dropped. + + Each commit is prefixed with a word and these words are additionally +shown in different colors to indicate the status of the commits. + + The following colors are used: + + • Commits that use the same foreground color as the ‘default’ face + have not been applied yet. + + • Yellow commits have some special relationship to the commit rebase + stopped at. This is used for the words "join", "goal", "same" and + "work" (see below). + + • Gray commits have already been applied. + + • The blue commit is the ‘HEAD’ commit. + + • The green commit is the commit the rebase sequence stopped at. If + this is the same commit as ‘HEAD’ (e.g., because you haven’t done + anything yet after rebase stopped at the commit, then this commit + is shown in blue, not green). There can only be a green *and* a + blue commit at the same time, if you create one or more new commits + after rebase stops at a commit. + + • Red commits have been dropped. They are shown for reference only, + e.g., to make it easier to diff. + + Of course these colors are subject to the color-theme in use. + + The following words are used: + + • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and + ‘fixup’ have not been applied yet. These words have the same + meaning here as they do in the buffer used to edit the rebase + sequence. See *note Editing Rebase Sequences::. When the + ‘--rebase-merges’ option was specified, ‘reset’, ‘label’, and + ‘merge’ lines may also be present. + + • Commits prefixed with ‘done’ and ‘onto’ have already been applied. + It is possible for such a commit to be the ‘HEAD’, in which case it + is blue. Otherwise it is grey. + + • The commit prefixed with ‘onto’ is the commit on top of which + all the other commits are being re-applied. This commit + itself did not have to be re-applied, it is the commit rebase + did rewind to before starting to re-apply other commits. + + • Commits prefixed with ‘done’ have already been re-applied. + This includes commits that have been re-applied but also new + commits that you have created during the rebase. + + • All other commits, those not prefixed with any of the above words, + are in some way related to the commit at which rebase stopped. + + To determine whether a commit is related to the stopped-at commit + their hashes, trees and patch-ids (1) are being compared. The + commit message is not used for this purpose. + + Generally speaking commits that are related to the stopped-at + commit can have any of the used colors, though not all color/word + combinations are possible. + + Words used for stopped-at commits are: + + • When a commit is prefixed with ‘void’, then that indicates + that Magit knows for sure that all the changes in that commit + have been applied using several new commits. This commit is + no longer reachable from ‘HEAD’, and it also isn’t one of the + commits that will be applied when resuming the session. + + • When a commit is prefixed with ‘join’, then that indicates + that the rebase sequence stopped at that commit due to a + conflict - you now have to join (merge) the changes with what + has already been applied. In a sense this is the commit + rebase stopped at, but while its effect is already in the + index and in the worktree (with conflict markers), the commit + itself has not actually been applied yet (it isn’t the + ‘HEAD’). So it is shown in yellow, like the other commits + that still have to be applied. + + • When a commit is prefixed with ‘stop’ or a _blue_ or _green_ + ‘same’, then that indicates that rebase stopped at this + commit, that it is still applied or has been applied again, + and that at least its patch-id is unchanged. + + • When a commit is prefixed with ‘stop’, then that + indicates that rebase stopped at that commit because you + requested that earlier, and its patch-id is unchanged. + It might even still be the exact same commit. + + • When a commit is prefixed with a _blue_ or _green_ + ‘same’, then that indicates that while its tree or hash + changed, its patch-id did not. If it is blue, then it is + the ‘HEAD’ commit (as always for blue). When it is + green, then it no longer is ‘HEAD’ because other commit + have been created since (but before continuing the + rebase). + + • When a commit is prefixed with ‘goal’, a _yellow_ ‘same,’ or + ‘work’, then that indicates that rebase applied that commit + but that you then reset ‘HEAD’ to an earlier commit (likely to + split it up into multiple commits), and that there are some + uncommitted changes remaining which likely (but not + necessarily) originate from that commit. + + • When a commit is prefixed with ‘goal’, then that + indicates that it is still possible to create a new + commit with the exact same tree (the "goal") without + manually editing any files, by committing the index, or + by staging all changes and then committing that. This is + the case when the original tree still exists in the index + or worktree in untainted form. + + • When a commit is prefixed with a yellow ‘same’, then that + indicates that it is no longer possible to create a + commit with the exact same tree, but that it is still + possible to create a commit with the same patch-id. This + would be the case if you created a new commit with other + changes, but the changes from the original commit still + exist in the index or working tree in untainted form. + + • When a commit is prefixed with ‘work’, then that + indicates that you reset ‘HEAD’ to an earlier commit, and + that there are some staged and/or unstaged changes + (likely, but not necessarily) originating from that + commit. However it is no longer possible to create a new + commit with the same tree or at least the same patch-id + because you have already made other changes. + + • When a commit is prefixed with ‘poof’ or ‘gone’, then that + indicates that rebase applied that commit but that you then + reset ‘HEAD’ to an earlier commit (likely to split it up into + multiple commits), and that there are no uncommitted changes. + + • When a commit is prefixed with ‘poof’, then that + indicates that it is no longer reachable from ‘HEAD’, but + that it has been replaced with one or more commits, which + together have the exact same effect. + + • When a commit is prefixed with ‘gone’, then that + indicates that it is no longer reachable from ‘HEAD’ and + that we also cannot determine whether its changes are + still in effect in one or more new commits. They might + be, but if so, then there must also be other changes + which makes it impossible to know for sure. + + Do not worry if you do not fully understand the above. That’s okay, +you will acquire a good enough understanding through practice. + + For other sequence operations such as cherry-picking, a similar +section is displayed, but they lack some of the features described +above, due to limitations in the git commands used to implement them. +Most importantly these sequences only support "picking" a commit but not +other actions such as "rewording", and they do not keep track of the +commits which have already been applied. + + ---------- Footnotes ---------- + + (1) The patch-id is a hash of the _changes_ introduced by a commit. +It differs from the hash of the commit itself, which is a hash of the +result of applying that change (i.e., the resulting trees and blobs) as +well as author and committer information, the commit message, and the +hashes of the parents of the commit. The patch-id hash on the other +hand is created only from the added and removed lines, even line numbers +and whitespace changes are ignored when calculating this hash. The +patch-ids of two commits can be used to answer the question "Do these +commits make the same change?". + + +File: magit.info, Node: Cherry Picking, Next: Resetting, Prev: Rebasing, Up: Manipulating + +6.10 Cherry Picking +=================== + +Also see *note (gitman)git-cherry-pick::. + +‘A’ (‘magit-cherry-pick’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no cherry-pick or revert is in progress, then the transient +features the following suffix commands. + +‘A A’ (‘magit-cherry-copy’) + This command copies COMMITS from another branch onto the current + branch. If the region selects multiple commits, then those are + copied, without prompting. Otherwise the user is prompted for a + commit or range, defaulting to the commit at point. + +‘A a’ (‘magit-cherry-apply’) + This command applies the changes in COMMITS from another branch + onto the current branch. If the region selects multiple commits, + then those are used, without prompting. Otherwise the user is + prompted for a commit or range, defaulting to the commit at point. + + This command also has a top-level binding, which can be invoked + without using the transient by typing ‘a’ at the top-level. + + The following commands not only apply some commits to some branch, +but also remove them from some other branch. The removal is performed +using either ‘git-update-ref’ or if necessary ‘git-rebase’. Both +applying commits as well as removing them using ‘git-rebase’ can lead to +conflicts. If that happens, then these commands abort and you not only +have to resolve the conflicts but also finish the process the same way +you would have to if these commands didn’t exist at all. + +‘A h’ (‘magit-cherry-harvest’) + This command moves the selected COMMITS that must be located on + another BRANCH onto the current branch instead, removing them from + the former. When this command succeeds, then the same branch is + current as before. + + Applying the commits on the current branch or removing them from + the other branch can lead to conflicts. When that happens, then + this command stops and you have to resolve the conflicts and then + finish the process manually. + +‘A d’ (‘magit-cherry-donate’) + This command moves the selected COMMITS from the current branch + onto another existing BRANCH, removing them from the former. When + this command succeeds, then the same branch is current as before. + ‘HEAD’ is allowed to be detached initially. + + Applying the commits on the other branch or removing them from the + current branch can lead to conflicts. When that happens, then this + command stops and you have to resolve the conflicts and then finish + the process manually. + +‘A n’ (‘magit-cherry-spinout’) + This command moves the selected COMMITS from the current branch + onto a new branch BRANCH, removing them from the former. When this + command succeeds, then the same branch is current as before. + + Applying the commits on the other branch or removing them from the + current branch can lead to conflicts. When that happens, then this + command stops and you have to resolve the conflicts and then finish + the process manually. + +‘A s’ (‘magit-cherry-spinoff’) + This command moves the selected COMMITS from the current branch + onto a new branch BRANCH, removing them from the former. When this + command succeeds, then the new branch is checked out. + + Applying the commits on the other branch or removing them from the + current branch can lead to conflicts. When that happens, then this + command stops and you have to resolve the conflicts and then finish + the process manually. + + When a cherry-pick or revert is in progress, then the transient +instead features the following suffix commands. + +‘A A’ (‘magit-sequence-continue’) + Resume the current cherry-pick or revert sequence. + +‘A s’ (‘magit-sequence-skip’) + Skip the stopped at commit during a cherry-pick or revert sequence. + +‘A a’ (‘magit-sequence-abort’) + Abort the current cherry-pick or revert sequence. This discards + all changes made since the sequence started. + +* Menu: + +* Reverting:: + + +File: magit.info, Node: Reverting, Up: Cherry Picking + +6.10.1 Reverting +---------------- + +‘V’ (‘magit-revert’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no cherry-pick or revert is in progress, then the transient +features the following suffix commands. + +‘V V’ (‘magit-revert-and-commit’) + Revert a commit by creating a new commit. Prompt for a commit, + defaulting to the commit at point. If the region selects multiple + commits, then revert all of them, without prompting. + +‘V v’ (‘magit-revert-no-commit’) + Revert a commit by applying it in reverse to the working tree. + Prompt for a commit, defaulting to the commit at point. If the + region selects multiple commits, then revert all of them, without + prompting. + + When a cherry-pick or revert is in progress, then the transient +instead features the following suffix commands. + +‘V V’ (‘magit-sequence-continue’) + Resume the current cherry-pick or revert sequence. + +‘V s’ (‘magit-sequence-skip’) + Skip the stopped at commit during a cherry-pick or revert sequence. + +‘V a’ (‘magit-sequence-abort’) + Abort the current cherry-pick or revert sequence. This discards + all changes made since the sequence started. + + +File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry Picking, Up: Manipulating + +6.11 Resetting +============== + +Also see *note (gitman)git-reset::. + +‘x’ (‘magit-reset-quickly’) + Reset the ‘HEAD’ and index to some commit read from the user and + defaulting to the commit at point, and possibly also reset the + working tree. With a prefix argument reset the working tree + otherwise don’t. + +‘X m’ (‘magit-reset-mixed’) + Reset the ‘HEAD’ and index to some commit read from the user and + defaulting to the commit at point. The working tree is kept as-is. + +‘X s’ (‘magit-reset-soft’) + Reset the ‘HEAD’ to some commit read from the user and defaulting + to the commit at point. The index and the working tree are kept + as-is. + +‘X h’ (‘magit-reset-hard’) + Reset the ‘HEAD’, index, and working tree to some commit read from + the user and defaulting to the commit at point. + +‘X k’ (‘magit-reset-keep’) + Reset the ‘HEAD’, index, and working tree to some commit read from + the user and defaulting to the commit at point. Uncommitted + changes are kept as-is. + +‘X i’ (‘magit-reset-index’) + Reset the index to some commit read from the user and defaulting to + the commit at point. Keep the ‘HEAD’ and working tree as-is, so if + the commit refers to the ‘HEAD’, then this effectively unstages all + changes. + +‘X w’ (‘magit-reset-worktree’) + Reset the working tree to some commit read from the user and + defaulting to the commit at point. Keep the ‘HEAD’ and index + as-is. + +‘X f’ (‘magit-file-checkout’) + Update file in the working tree and index to the contents from a + revision. Both the revision and file are read from the user. + + +File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating + +6.12 Stashing +============= + +Also see *note (gitman)git-stash::. + +‘z’ (‘magit-stash’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘z z’ (‘magit-stash-both’) + Create a stash of the index and working tree. Untracked files are + included according to infix arguments. One prefix argument is + equivalent to ‘--include-untracked’ while two prefix arguments are + equivalent to ‘--all’. + +‘z i’ (‘magit-stash-index’) + Create a stash of the index only. Unstaged and untracked changes + are not stashed. + +‘z w’ (‘magit-stash-worktree’) + Create a stash of unstaged changes in the working tree. Untracked + files are included according to infix arguments. One prefix + argument is equivalent to ‘--include-untracked’ while two prefix + arguments are equivalent to ‘--all’. + +‘z x’ (‘magit-stash-keep-index’) + Create a stash of the index and working tree, keeping index intact. + Untracked files are included according to infix arguments. One + prefix argument is equivalent to ‘--include-untracked’ while two + prefix arguments are equivalent to ‘--all’. + +‘z Z’ (‘magit-snapshot-both’) + Create a snapshot of the index and working tree. Untracked files + are included according to infix arguments. One prefix argument is + equivalent to ‘--include-untracked’ while two prefix arguments are + equivalent to ‘--all’. + +‘z I’ (‘magit-snapshot-index’) + Create a snapshot of the index only. Unstaged and untracked + changes are not stashed. + +‘z W’ (‘magit-snapshot-worktree’) + Create a snapshot of unstaged changes in the working tree. + Untracked files are included according to infix arguments. One + prefix argument is equivalent to ‘--include-untracked’ while two + prefix arguments are equivalent to ‘--all’-. + +‘z a’ (‘magit-stash-apply’) + Apply a stash to the working tree. + + First try ‘git stash apply --index’, which tries to preserve the + index stored in the stash, if any. This may fail because applying + the stash could result in conflicts and those have to be stored in + the index, making it impossible to also store the stash’s index + there as well. + + If the above failed, then try ‘git stash apply’. This fails (with + or without ‘--index’) if there are any uncommitted changes to files + that are also modified in the stash. + + If both of the above failed, then apply using ‘git apply’. If + there are no conflicting files, use ‘--3way’. If there are + conflicting files, then using ‘--3way’ requires that those files + are staged first, which may be undesirable, so prompt the user + whether to use ‘--3way’ or ‘--reject’. + + Customize ‘magit-no-confirm’ if you want to always use ‘--3way’, + without being prompted. + +‘z p’ (‘magit-stash-pop’) + Apply a stash to the working tree. On complete success (if the + stash can be applied without any conflicts, and while preserving + the stash’s index) then remove the stash from stash list. + + First try ‘git stash pop --index’, which tries to preserve the + index stored in the stash, if any. This may fail because applying + the stash could result in conflicts and those have to be stored in + the index, making it impossible to also store the stash’s index + there as well. + + If the above failed, then try ‘git stash apply’. This fails (with + or without ‘--index’) if there are any uncommitted changes to files + that are also modified in the stash. + + If both of the above failed, then apply using ‘git apply’. If + there are no conflicting files, use ‘--3way’. If there are + conflicting files, then using ‘--3way’ requires that those files + are staged first, which may be undesirable, so prompt the user + whether to use ‘--3way’ or ‘--reject’. + + Customize ‘magit-no-confirm’ if you want to always use ‘--3way’, + without being prompted. + +‘z k’ (‘magit-stash-drop’) + Remove a stash from the stash list. When the region is active, + offer to drop all contained stashes. + +‘z v’ (‘magit-stash-show’) + Show all diffs of a stash in a buffer. + +‘z b’ (‘magit-stash-branch’) + Create and checkout a new branch from an existing stash. The new + branch starts at the commit that was current when the stash was + created. + +‘z B’ (‘magit-stash-branch-here’) + Create and checkout a new branch from an existing stash. Use the + current branch or ‘HEAD’ as the starting-point of the new branch. + Then apply the stash, dropping it if it applies cleanly. + +‘z f’ (‘magit-stash-format-patch’) + Create a patch from STASH. + +‘k’ (‘magit-stash-clear’) + Remove all stashes saved in REF’s reflog by deleting REF. + +‘z l’ (‘magit-stash-list’) + List all stashes in a buffer. + + -- User Option: magit-stashes-margin + This option specifies whether the margin is initially shown in + stashes buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top + +7 Transferring +************** + +* Menu: + +* Remotes:: +* Fetching:: +* Pulling:: +* Pushing:: +* Plain Patches:: +* Maildir Patches:: + + +File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring + +7.1 Remotes +=========== + +* Menu: + +* Remote Commands:: +* Remote Git Variables:: + + +File: magit.info, Node: Remote Commands, Next: Remote Git Variables, Up: Remotes + +7.1.1 Remote Commands +--------------------- + +The transient prefix command ‘magit-remote’ is used to add remotes and +to make changes to existing remotes. This command only deals with +remotes themselves, not with branches or the transfer of commits. Those +features are available from separate transient commands. + + Also see *note (gitman)git-remote::. + +‘M’ (‘magit-remote’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + + By default it also binds and displays the values of some + remote-related Git variables and allows changing their values. + + -- User Option: magit-remote-direct-configure + This option controls whether remote-related Git variables are + accessible directly from the transient ‘magit-remote’. + + If ‘t’ (the default) and a local branch is checked out, then + ‘magit-remote’ features the variables for the upstream remote of + that branch, or if ‘HEAD’ is detached, for ‘origin’, provided that + exists. + + If ‘nil’, then ‘magit-remote-configure’ has to be used to do so. + +‘M C’ (‘magit-remote-configure’) + This transient prefix command binds commands that set the value of + remote-related variables and displays them in a temporary buffer + until the transient is exited. + + With a prefix argument, this command always prompts for a remote. + + Without a prefix argument this depends on whether it was invoked as + a suffix of ‘magit-remote’ and on the + ‘magit-remote-direct-configure’ option. If ‘magit-remote’ already + displays the variables for the upstream, then it does not make + sense to invoke another transient that displays them for the same + remote. In that case this command prompts for a remote. + + The variables are described in *note Remote Git Variables::. + +‘M a’ (‘magit-remote-add’) + This command add a remote and fetches it. The remote name and url + are read in the minibuffer. + +‘M r’ (‘magit-remote-rename’) + This command renames a remote. Both the old and the new names are + read in the minibuffer. + +‘M u’ (‘magit-remote-set-url’) + This command changes the url of a remote. Both the remote and the + new url are read in the minibuffer. + +‘M k’ (‘magit-remote-remove’) + This command deletes a remote, read in the minibuffer. + +‘M p’ (‘magit-remote-prune’) + This command removes stale remote-tracking branches for a remote + read in the minibuffer. + +‘M P’ (‘magit-remote-prune-refspecs’) + This command removes stale refspecs for a remote read in the + minibuffer. + + A refspec is stale if there no longer exists at least one branch on + the remote that would be fetched due to that refspec. A stale + refspec is problematic because its existence causes Git to refuse + to fetch according to the remaining non-stale refspecs. + + If only stale refspecs remain, then this command offers to either + delete the remote or to replace the stale refspecs with the default + refspec ("+refs/heads/*:refs/remotes/REMOTE/*"). + + This command also removes the remote-tracking branches that were + created due to the now stale refspecs. Other stale branches are + not removed. + + -- User Option: magit-remote-add-set-remote.pushDefault + This option controls whether the user is asked whether they want to + set ‘remote.pushDefault’ after adding a remote. + + If ‘ask’, then users is always ask. If ‘ask-if-unset’, then the + user is only if the variable isn’t set already. If ‘nil’, then the + user isn’t asked and the variable isn’t set. If the value is a + string, then the variable is set without the user being asked, + provided that the name of the added remote is equal to that string + and the variable isn’t already set. + + +File: magit.info, Node: Remote Git Variables, Prev: Remote Commands, Up: Remotes + +7.1.2 Remote Git Variables +-------------------------- + +These variables can be set from the transient prefix command +‘magit-remote-configure’. By default they can also be set from +‘magit-remote’. See *note Remote Commands::. + + -- Variable: remote.NAME.url + This variable specifies the url of the remote named NAME. It can + have multiple values. + + -- Variable: remote.NAME.fetch + The refspec used when fetching from the remote named NAME. It can + have multiple values. + + -- Variable: remote.NAME.pushurl + This variable specifies the url used for pushing to the remote + named NAME. If it is not specified, then ‘remote.NAME.url’ is used + instead. It can have multiple values. + + -- Variable: remote.NAME.push + The refspec used when pushing to the remote named NAME. It can + have multiple values. + + -- Variable: remote.NAME.tagOpts + This variable specifies what tags are fetched by default. If the + value is ‘--no-tags’ then no tags are fetched. If the value is + ‘--tags’, then all tags are fetched. If this variable has no + value, then only tags are fetched that are reachable from fetched + branches. + + +File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring + +7.2 Fetching +============ + +Also see *note (gitman)git-fetch::. For information about the upstream +and the push-remote, see *note The Two Remotes::. + +‘f’ (‘magit-fetch’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘f p’ (‘magit-fetch-from-pushremote’) + This command fetches from the current push-remote. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘f u’ (‘magit-fetch-from-upstream’) + This command fetch from the upstream of the current branch. + + If the upstream is configured for the current branch and names an + existing remote, then use that. Otherwise try to use another + remote: If only a single remote is configured, then use that. + Otherwise if a remote named "origin" exists, then use that. + + If no remote can be determined, then this command is not available + from the ‘magit-fetch’ transient prefix and invoking it directly + results in an error. + +‘f e’ (‘magit-fetch-other’) + This command fetch from a repository read from the minibuffer. + +‘f o’ (‘magit-fetch-branch’) + This command fetches a branch from a remote, both of which are read + from the minibuffer. + +‘f r’ (‘magit-fetch-refspec’) + This command fetches from a remote using an explicit refspec, both + of which are read from the minibuffer. + +‘f a’ (‘magit-fetch-all’) + This command fetches from all remotes. + +‘f m’ (‘magit-fetch-modules’) + This command fetches all submodules. With a prefix argument, it + acts as a transient prefix command, allowing the caller to set + options. + + -- User Option: magit-pull-or-fetch + By default fetch and pull commands are available from separate + transient prefix command. Setting this to ‘t’ adds some (but not + all) of the above suffix commands to the ‘magit-pull’ transient. + + If you do that, then you might also want to change the key binding + for these prefix commands, e.g.: + + (setq magit-pull-or-fetch t) + (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch + (define-key magit-mode-map "F" nil) ; was magit-pull + + +File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring + +7.3 Pulling +=========== + +Also see *note (gitman)git-pull::. For information about the upstream +and the push-remote, see *note The Two Remotes::. + +‘F’ (‘magit-pull’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘F p’ (‘magit-pull-from-pushremote’) + This command pulls from the push-remote of the current branch. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘F u’ (‘magit-pull-from-upstream’) + This command pulls from the upstream of the current branch. + + With a prefix argument or when the upstream is either not + configured or unusable, then let the user first configure the + upstream. + +‘F e’ (‘magit-pull-branch’) + This command pulls from a branch read in the minibuffer. + + +File: magit.info, Node: Pushing, Next: Plain Patches, Prev: Pulling, Up: Transferring + +7.4 Pushing +=========== + +Also see *note (gitman)git-push::. For information about the upstream +and the push-remote, see *note The Two Remotes::. + +‘P’ (‘magit-push’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘P p’ (‘magit-push-current-to-pushremote’) + This command pushes the current branch to its push-remote. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘P u’ (‘magit-push-current-to-upstream’) + This command pushes the current branch to its upstream branch. + + With a prefix argument or when the upstream is either not + configured or unusable, then let the user first configure the + upstream. + +‘P e’ (‘magit-push-current’) + This command pushes the current branch to a branch read in the + minibuffer. + +‘P o’ (‘magit-push-other’) + This command pushes an arbitrary branch or commit somewhere. Both + the source and the target are read in the minibuffer. + +‘P r’ (‘magit-push-refspecs’) + This command pushes one or multiple refspecs to a remote, both of + which are read in the minibuffer. + + To use multiple refspecs, separate them with commas. Completion is + only available for the part before the colon, or when no colon is + used. + +‘P m’ (‘magit-push-matching’) + This command pushes all matching branches to another repository. + + If only one remote exists, then push to that. Otherwise prompt for + a remote, offering the remote configured for the current branch as + default. + +‘P t’ (‘magit-push-tags’) + This command pushes all tags to another repository. + + If only one remote exists, then push to that. Otherwise prompt for + a remote, offering the remote configured for the current branch as + default. + +‘P T’ (‘magit-push-tag’) + This command pushes a tag to another repository. + + One of the infix arguments, ‘--force-with-lease’, deserves a word of +caution. It is passed without a value, which means "permit a force push +as long as the remote-tracking branches match their counterparts on the +remote end". If you’ve set up a tool to do automatic fetches (Magit +itself does not provide such functionality), using ‘--force-with-lease’ +can be dangerous because you don’t actually control or know the state of +the remote-tracking refs. In that case, you should consider setting +‘push.useForceIfIncludes’ to ‘true’ (available since Git 2.30). + + Two more push commands exist, which by default are not available from +the push transient. See their doc-strings for instructions on how to +add them to the transient. + + -- Command: magit-push-implicitly args + This command pushes somewhere without using an explicit refspec. + + This command simply runs ‘git push -v [ARGS]’. ARGS are the infix + arguments. No explicit refspec arguments are used. Instead the + behavior depends on at least these Git variables: ‘push.default’, + ‘remote.pushDefault’, ‘branch.<branch>.pushRemote’, + ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and + ‘remote.<remote>.push’. + + If you add this suffix to a transient prefix without explicitly + specifying the description, then an attempt is made to predict what + this command will do. For example: + + (transient-insert-suffix 'magit-push \"p\" + '(\"i\" magit-push-implicitly))" + + -- Command: magit-push-to-remote remote args + This command pushes to the remote REMOTE without using an explicit + refspec. The remote is read in the minibuffer. + + This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the + infix arguments. No refspec arguments are used. Instead the + behavior depends on at least these Git variables: ‘push.default’, + ‘remote.pushDefault’, ‘branch.<branch>.pushRemote’, + ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and + ‘remote.<remote>.push’. + + +File: magit.info, Node: Plain Patches, Next: Maildir Patches, Prev: Pushing, Up: Transferring + +7.5 Plain Patches +================= + +‘W’ (‘magit-patch’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘W c’ (‘magit-patch-create’) + This command creates patches for a set commits. If the region + marks several commits, then it creates patches for all of them. + Otherwise it functions as a transient prefix command, which + features several infix arguments and binds itself as a suffix + command. When this command is invoked as a suffix of itself, then + it creates a patch using the specified infix arguments. + +‘w a’ (‘magit-patch-apply’) + This command applies a patch. This is a transient prefix command, + which features several infix arguments and binds itself as a suffix + command. When this command is invoked as a suffix of itself, then + it applies a patch using the specified infix arguments. + +‘W s’ (‘magit-patch-save’) + This command creates a patch from the current diff. + + Inside ‘magit-diff-mode’ or ‘magit-revision-mode’ buffers, ‘C-x + C-w’ is also bound to this command. + + It is also possible to save a plain patch file by using ‘C-x C-w’ +inside a ‘magit-diff-mode’ or ‘magit-revision-mode’ buffer. + + +File: magit.info, Node: Maildir Patches, Prev: Plain Patches, Up: Transferring + +7.6 Maildir Patches +=================== + +Also see *note (gitman)git-am::. and *note (gitman)git-apply::. + +‘w’ (‘magit-am’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘w w’ (‘magit-am-apply-patches’) + This command applies one or more patches. If the region marks + files, then those are applied as patches. Otherwise this command + reads a file-name in the minibuffer, defaulting to the file at + point. + +‘w m’ (‘magit-am-apply-maildir’) + This command applies patches from a maildir. + +‘w a’ (‘magit-patch-apply’) + This command applies a plain patch. For a longer description see + *note Plain Patches::. This command is only available from the + ‘magit-am’ transient for historic reasons. + + When an "am" operation is in progress, then the transient instead +features the following suffix commands. + +‘w w’ (‘magit-am-continue’) + This command resumes the current patch applying sequence. + +‘w s’ (‘magit-am-skip’) + This command skips the stopped at patch during a patch applying + sequence. + +‘w a’ (‘magit-am-abort’) + This command aborts the current patch applying sequence. This + discards all changes made since the sequence started. + + +File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top + +8 Miscellaneous +*************** + +* Menu: + +* Tagging:: +* Notes:: +* Submodules:: +* Subtree:: +* Worktree:: +* Sparse checkouts:: +* Bundle:: +* Common Commands:: +* Wip Modes:: +* Commands for Buffers Visiting Files:: +* Minor Mode for Buffers Visiting Blobs:: + + +File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous + +8.1 Tagging +=========== + +Also see *note (gitman)git-tag::. + +‘t’ (‘magit-tag’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘t t’ (‘magit-tag-create’) + This command creates a new tag with the given NAME at REV. With a + prefix argument it creates an annotated tag. + +‘t r’ (‘magit-tag-release’) + This commands creates a release tag. It assumes that release tags + match ‘magit-release-tag-regexp’. + + First it prompts for the name of the new tag using the highest + existing tag as initial input and leaving it to the user to + increment the desired part of the version string. If you use + unconventional release tags or version numbers (e.g., + ‘v1.2.3-custom.1’), you can set the ‘magit-release-tag-regexp’ and + ‘magit-tag-version-regexp-alist’ variables. + + If ‘--annotate’ is enabled then it prompts for the message of the + new tag. The proposed tag message is based on the message of the + highest tag, provided that that contains the corresponding version + string and substituting the new version string for that. Otherwise + it proposes something like "Foo-Bar 1.2.3", given, for example, a + TAG "v1.2.3" and a repository located at something like + "/path/to/foo-bar". + +‘t k’ (‘magit-tag-delete’) + This command deletes one or more tags. If the region marks + multiple tags (and nothing else), then it offers to delete those. + Otherwise, it prompts for a single tag to be deleted, defaulting to + the tag at point. + +‘t p’ (‘magit-tag-prune’) + This command offers to delete tags missing locally from REMOTE, and + vice versa. + + +File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous + +8.2 Notes +========= + +Also see *note (gitman)git-notes::. + +‘T’ (‘magit-notes’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘T T’ (‘magit-notes-edit’) + Edit the note attached to a commit, defaulting to the commit at + point. + + By default use the value of Git variable ‘core.notesRef’ or + "refs/notes/commits" if that is undefined. + +‘T r’ (‘magit-notes-remove’) + Remove the note attached to a commit, defaulting to the commit at + point. + + By default use the value of Git variable ‘core.notesRef’ or + "refs/notes/commits" if that is undefined. + +‘T p’ (‘magit-notes-prune’) + Remove notes about unreachable commits. + + It is possible to merge one note ref into another. That may result +in conflicts which have to resolved in the temporary worktree +".git/NOTES_MERGE_WORKTREE". + +‘T m’ (‘magit-notes-merge’) + Merge the notes of a ref read from the user into the current notes + ref. The current notes ref is the value of Git variable + ‘core.notesRef’ or "refs/notes/commits" if that is undefined. + + When a notes merge is in progress then the transient features the +following suffix commands, instead of those listed above. + +‘T c’ (‘magit-notes-merge-commit’) + Commit the current notes ref merge, after manually resolving + conflicts. + +‘T a’ (‘magit-notes-merge-abort’) + Abort the current notes ref merge. + + The following variables control what notes reference ‘magit-notes-*’, +‘git notes’ and ‘git show’ act on and display. Both the local and +global values are displayed and can be modified. + + -- Variable: core.notesRef + This variable specifies the notes ref that is displayed by default + and which commands act on by default. + + -- Variable: notes.displayRef + This variable specifies additional notes ref to be displayed in + addition to the ref specified by ‘core.notesRef’. It can have + multiple values and may end with ‘*’ to display all refs in the + ‘refs/notes/’ namespace (or ‘**’ if some names contain slashes). + + +File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous + +8.3 Submodules +============== + +Also see *note (gitman)git-submodule::. + +* Menu: + +* Listing Submodules:: +* Submodule Transient:: + + +File: magit.info, Node: Listing Submodules, Next: Submodule Transient, Up: Submodules + +8.3.1 Listing Submodules +------------------------ + +The command ‘magit-list-submodules’ displays a list of the current +repository’s submodules in a separate buffer. It’s also possible to +display information about submodules directly in the status buffer of +the super-repository by adding ‘magit-insert-modules’ to the hook +‘magit-status-sections-hook’ as described in *note Status Module +Sections::. + + -- Command: magit-list-submodules + This command displays a list of the current repository’s populated + submodules in a separate buffer. + + It can be invoked by pressing ‘RET’ on the section titled + "Modules". + + -- User Option: magit-submodule-list-columns + This option controls what columns are displayed by the command + ‘magit-list-submodules’ and how they are displayed. + + Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. + + HEADER is the string displayed in the header. WIDTH is the width + of the column. FORMAT is a function that is called with one + argument, the repository identification (usually its basename), and + with ‘default-directory’ bound to the toplevel of its working tree. + It has to return a string to be inserted or nil. PROPS is an alist + that supports the keys ‘:right-align’, ‘:pad-right’ and ‘:sort’. + + The ‘:sort’ function has a weird interface described in the + docstring of ‘tabulated-list--get-sort’. Alternatively ‘<’ and + ‘magit-repolist-version<’ can be used as those functions are + automatically replaced with functions that satisfy the interface. + Set ‘:sort’ to ‘nil’ to inhibit sorting; if unspecified, then the + column is sortable using the default sorter. + + You may wish to display a range of numeric columns using just one + character per column and without any padding between columns, in + which case you should use an appropriate HEADER, set WIDTH to 1, + and set ‘:pad-right’ to 9. ‘+’ is substituted for numbers higher + than 9. + + +File: magit.info, Node: Submodule Transient, Prev: Listing Submodules, Up: Submodules + +8.3.2 Submodule Transient +------------------------- + +‘o’ (‘magit-submodule’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + Some of the below commands default to act on the modules that are +selected using the region. For brevity their description talk about +"the selected modules", but if no modules are selected, then they act on +the current module instead, or if point isn’t on a module, then the read +a single module to act on. With a prefix argument these commands ignore +the selection and the current module and instead act on all suitable +modules. + +‘o a’ (‘magit-submodule-add’) + This commands adds the repository at URL as a module. Optional + PATH is the path to the module relative to the root of the + super-project. If it is nil then the path is determined based on + URL. + +‘o r’ (‘magit-submodule-register’) + This command registers the selected modules by copying their urls + from ".gitmodules" to "$GIT_DIR/config". These values can then be + edited before running ‘magit-submodule-populate’. If you don’t + need to edit any urls, then use the latter directly. + +‘o p’ (‘magit-submodule-populate’) + This command creates the working directory or directories of the + selected modules, checking out the recorded commits. + +‘o u’ (‘magit-submodule-update’) + This command updates the selected modules checking out the recorded + commits. + +‘o s’ (‘magit-submodule-synchronize’) + This command synchronizes the urls of the selected modules, copying + the values from ".gitmodules" to the ".git/config" of the + super-project as well those of the modules. + +‘o d’ (‘magit-submodule-unpopulate’) + This command removes the working directory of the selected modules. + +‘o l’ (‘magit-list-submodules’) + This command displays a list of the current repository’s modules. + +‘o f’ (‘magit-fetch-modules’) + This command fetches all populated modules. With a prefix + argument, it acts as a transient prefix command, allowing the + caller to set options. + + Also fetch the super-repository, because ‘git fetch’ does not + support not doing that. + + +File: magit.info, Node: Subtree, Next: Worktree, Prev: Submodules, Up: Miscellaneous + +8.4 Subtree +=========== + +Also see *note (gitman)git-subtree::. + +‘O’ (‘magit-subtree’) + This transient prefix command binds the two sub-transients; one for + importing a subtree and one for exporting a subtree. + +‘O i’ (‘magit-subtree-import’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + The suffixes of this command import subtrees. + + If the ‘--prefix’ argument is set, then the suffix commands use + that prefix without prompting the user. If it is unset, then they + read the prefix in the minibuffer. + +‘O i a’ (‘magit-subtree-add’) + This command adds COMMIT from REPOSITORY as a new subtree at + PREFIX. + +‘O i c’ (‘magit-subtree-add-commit’) + This command add COMMIT as a new subtree at PREFIX. + +‘O i m’ (‘magit-subtree-merge’) + This command merges COMMIT into the PREFIX subtree. + +‘O i f’ (‘magit-subtree-pull’) + This command pulls COMMIT from REPOSITORY into the PREFIX subtree. + +‘O e’ (‘magit-subtree-export’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + The suffixes of this command export subtrees. + + If the ‘--prefix’ argument is set, then the suffix commands use + that prefix without prompting the user. If it is unset, then they + read the prefix in the minibuffer. + +‘O e p’ (‘magit-subtree-push’) + This command extract the history of the subtree PREFIX and pushes + it to REF on REPOSITORY. + +‘O e s’ (‘magit-subtree-split’) + This command extracts the history of the subtree PREFIX. + + +File: magit.info, Node: Worktree, Next: Sparse checkouts, Prev: Subtree, Up: Miscellaneous + +8.5 Worktree +============ + +Also see *note (gitman)git-worktree::. + +‘Z’ (‘magit-worktree’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘Z b’ (‘magit-worktree-checkout’) + Checkout BRANCH in a new worktree at PATH. + +‘Z c’ (‘magit-worktree-branch’) + Create a new BRANCH and check it out in a new worktree at PATH. + +‘Z m’ (‘magit-worktree-move’) + Move an existing worktree to a new PATH. + +‘Z k’ (‘magit-worktree-delete’) + Delete a worktree, defaulting to the worktree at point. The + primary worktree cannot be deleted. + +‘Z g’ (‘magit-worktree-status’) + Show the status for the worktree at point. + + If there is no worktree at point, then read one in the minibuffer. + If the worktree at point is the one whose status is already being + displayed in the current buffer, then show it in Dired instead. + + +File: magit.info, Node: Sparse checkouts, Next: Bundle, Prev: Worktree, Up: Miscellaneous + +8.6 Sparse checkouts +==================== + +Sparse checkouts provide a way to restrict the working tree to a subset +of directories. See *note (gitman)git-sparse-checkout::. + + *Warning*: Git introduced the ‘git sparse-checkout’ command in +version 2.25 and still advertises it as experimental and subject to +change. Magit’s interface should be considered the same. In +particular, if Git introduces a backward incompatible change, Magit’s +sparse checkout functionality may be updated in a way that requires a +more recent Git version. + +‘>’ (‘magit-sparse-checkout’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘> e’ (‘magit-sparse-checkout-enable’) + This command initializes a sparse checkout that includes only the + files in the top-level directory. + + Note that ‘magit-sparse-checkout-set’ and + ‘magit-sparse-checkout-add’ automatically initialize a sparse + checkout if necessary. However, you may want to call + ‘magit-sparse-checkout-enable’ explicitly to re-initialize a sparse + checkout after calling ‘magit-sparse-checkout-disable’, to pass + additional arguments to ‘git sparse-checkout init’, or to execute + the initialization asynchronously. + +‘> s’ (‘magit-sparse-checkout-set’) + This command takes a list of directories and configures the sparse + checkout to include only files in those subdirectories. Any + previously included directories are excluded unless they are in the + provided list of directories. + +‘> a’ (‘magit-sparse-checkout-add’) + This command is like ‘magit-sparse-checkout-set’, but instead adds + the specified list of directories to the set of directories that is + already included in the sparse checkout. + +‘> r’ (‘magit-sparse-checkout-reapply’) + This command applies the currently configured sparse checkout + patterns to the working tree. This is useful to call if excluded + files have been checked out after operations such as merging or + rebasing. + +‘> d’ (‘magit-sparse-checkout-disable’) + This command restores the full checkout. To return to the previous + sparse checkout, call ‘magit-sparse-checkout-enable’. + + A sparse checkout can also be initiated when cloning a repository by +using the ‘magit-clone-sparse’ command in the ‘magit-clone’ transient +(see *note Cloning Repository::). + + If you want the status buffer to indicate when a sparse checkout is +enabled, add the function ‘magit-sparse-checkout-insert-header’ to +‘magit-status-headers-hook’. + + +File: magit.info, Node: Bundle, Next: Common Commands, Prev: Sparse checkouts, Up: Miscellaneous + +8.7 Bundle +========== + +Also see *note (gitman)git-bundle::. + + -- Command: magit-bundle + This transient prefix command binds several suffix commands for + running ‘git bundle’ subcommands and displays them in a temporary + buffer until a suffix is invoked. + + +File: magit.info, Node: Common Commands, Next: Wip Modes, Prev: Bundle, Up: Miscellaneous + +8.8 Common Commands +=================== + + -- Command: magit-switch-to-repository-buffer + -- Command: magit-switch-to-repository-buffer-other-window + -- Command: magit-switch-to-repository-buffer-other-frame + -- Command: magit-display-repository-buffer + These commands read any existing Magit buffer that belongs to the + current repository from the user and then switch to the selected + buffer (without refreshing it). + + The last variant uses ‘magit-display-buffer’ to do so and thus + respects ‘magit-display-buffer-function’. + + These are some of the commands that can be used in all buffers whose +major-modes derive from ‘magit-mode’. There are other common commands +beside the ones below, but these didn’t fit well anywhere else. + +‘C-w’ (‘magit-copy-section-value’) + This command saves the value of the current section to the + ‘kill-ring’, and, provided that the current section is a commit, + branch, or tag section, it also pushes the (referenced) revision to + the ‘magit-revision-stack’. + + When the current section is a branch or a tag, and a prefix + argument is used, then it saves the revision at its tip to the + ‘kill-ring’ instead of the reference name. + + When the region is active, this command saves that to the + ‘kill-ring’, like ‘kill-ring-save’ would, instead of behaving as + described above. If a prefix argument is used and the region is + within a hunk, then it strips the diff marker column and keeps only + either the added or removed lines, depending on the sign of the + prefix argument. + +‘M-w’ (‘magit-copy-buffer-revision’) + This command saves the revision being displayed in the current + buffer to the ‘kill-ring’ and also pushes it to the + ‘magit-revision-stack’. It is mainly intended for use in + ‘magit-revision-mode’ buffers, the only buffers where it is always + unambiguous exactly which revision should be saved. + + Most other Magit buffers usually show more than one revision, in + some way or another, so this command has to select one of them, and + that choice might not always be the one you think would have been + the best pick. + + Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to +‘kill-ring-save’ and ‘kill-region’, and these commands would also be +useful in Magit buffers. Therefore when the region is active, then both +of these commands behave like ‘kill-ring-save’ instead of as described +above. + + +File: magit.info, Node: Wip Modes, Next: Commands for Buffers Visiting Files, Prev: Common Commands, Up: Miscellaneous + +8.9 Wip Modes +============= + +Git keeps *committed* changes around long enough for users to recover +changes they have accidentally deleted. It does so by not garbage +collecting any committed but no longer referenced objects for a certain +period of time, by default 30 days. + + But Git does *not* keep track of *uncommitted* changes in the working +tree and not even the index (the staging area). Because Magit makes it +so convenient to modify uncommitted changes, it also makes it easy to +shoot yourself in the foot in the process. + + For that reason Magit provides a global mode that saves *tracked* +files to work-in-progress references after or before certain actions. +(At present untracked files are never saved and for technical reasons +nothing is saved before the first commit has been created). + + Two separate work-in-progress references are used to track the state +of the index and of the working tree: ‘refs/wip/index/<branchref>’ and +‘refs/wip/wtree/<branchref>’, where ‘<branchref>’ is the full ref of the +current branch, e.g., ‘refs/heads/master’. When the ‘HEAD’ is detached +then ‘HEAD’ is used in place of ‘<branchref>’. + + Checking out another branch (or detaching ‘HEAD’) causes the use of +different wip refs for subsequent changes. + + -- User Option: magit-wip-mode + When this mode is enabled, then uncommitted changes are committed + to dedicated work-in-progress refs whenever appropriate (i.e., when + dataloss would be a possibility otherwise). + + Setting this variable directly does not take effect; either use the + Custom interface to do so or call the respective mode function. + + For historic reasons this mode is implemented on top of four other + ‘magit-wip-*’ modes, which can also be used individually, if you + want finer control over when the wip refs are updated; but that is + discouraged. See *note Legacy Wip Modes::. + + To view the log for a branch and its wip refs use the commands +‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’ +when using these commands. + + -- Command: magit-wip-log + This command shows the log for a branch and its wip refs. With a + negative prefix argument only the worktree wip ref is shown. + + The absolute numeric value of the prefix argument controls how many + "branches" of each wip ref are shown. This is only relevant if the + value of ‘magit-wip-merge-branch’ is ‘nil’. + + -- Command: magit-wip-log-current + This command shows the log for the current branch and its wip refs. + With a negative prefix argument only the worktree wip ref is shown. + + The absolute numeric value of the prefix argument controls how many + "branches" of each wip ref are shown. This is only relevant if the + value of ‘magit-wip-merge-branch’ is ‘nil’. + +‘X w’ (‘magit-reset-worktree’) + This command resets the working tree to some commit read from the + user and defaulting to the commit at point, while keeping the + ‘HEAD’ and index as-is. + + This can be used to restore files to the state committed to a wip + ref. Note that this will discard any unstaged changes that might + have existed before invoking this command (but of course only after + committing that to the working tree wip ref). + + Note that even if you enable ‘magit-wip-mode’ this won’t give you +perfect protection. The most likely scenario for losing changes despite +the use of ‘magit-wip-mode’ is making a change outside Emacs and then +destroying it also outside Emacs. In some such a scenario, Magit, being +an Emacs package, didn’t get the opportunity to keep you from shooting +yourself in the foot. + + When you are unsure whether Magit did commit a change to the wip +refs, then you can explicitly request that all changes to all tracked +files are being committed. + +‘M-x magit-wip-commit’ + This command commits all changes to all tracked files to the index + and working tree work-in-progress refs. Like the modes described + above, it does not commit untracked files, but it does check all + tracked files for changes. Use this command when you suspect that + the modes might have overlooked a change made outside Emacs/Magit. + + -- User Option: magit-wip-namespace + The namespace used for work-in-progress refs. It has to end with a + slash. The wip refs are named ‘<namespace>index/<branchref>’ and + ‘<namespace>wtree/<branchref>’. When snapshots are created while + the ‘HEAD’ is detached then ‘HEAD’ is used in place of + ‘<branchref>’. + + -- User Option: magit-wip-mode-lighter + Mode-line lighter for ‘magit-wip--mode’. + +* Menu: + +* Wip Graph:: +* Legacy Wip Modes:: + + +File: magit.info, Node: Wip Graph, Next: Legacy Wip Modes, Up: Wip Modes + +8.9.1 Wip Graph +--------------- + + -- User Option: magit-wip-merge-branch + This option controls whether the current branch is merged into the + wip refs after a new commit was created on the branch. + + If non-nil and the current branch has new commits, then it is + merged into the wip ref before creating a new wip commit. This + makes it easier to inspect wip history and the wip commits are + never garbage collected. + + If nil and the current branch has new commits, then the wip ref is + reset to the tip of the branch before creating a new wip commit. + With this setting wip commits are eventually garbage collected. + + When ‘magit-wip-merge-branch’ is ‘t’, then the history looks like +this: + + *--*--*--*--*--* refs/wip/index/refs/heads/master + / / / + A-----B-----C refs/heads/master + + When ‘magit-wip-merge-branch’ is ‘nil’, then creating a commit on the +real branch and then making a change causes the wip refs to be recreated +to fork from the new commit. But the old commits on the wip refs are +not lost. They are still available from the reflog. To make it easier +to see when the fork point of a wip ref was changed, an additional +commit with the message "restart autosaving" is created on it (‘xxO’ +commits below are such boundary commits). + + Starting with + + BI0---BI1 refs/wip/index/refs/heads/master + / + A---B refs/heads/master + \ + BW0---BW1 refs/wip/wtree/refs/heads/master + + and committing the staged changes and editing and saving a file would +result in + + BI0---BI1 refs/wip/index/refs/heads/master + / + A---B---C refs/heads/master + \ \ + \ CW0---CW1 refs/wip/wtree/refs/heads/master + \ + BW0---BW1 refs/wip/wtree/refs/heads/master@{2} + + The fork-point of the index wip ref is not changed until some change +is being staged. Likewise just checking out a branch or creating a +commit does not change the fork-point of the working tree wip ref. The +fork-points are not adjusted until there actually is a change that +should be committed to the respective wip ref. + + +File: magit.info, Node: Legacy Wip Modes, Prev: Wip Graph, Up: Wip Modes + +8.9.2 Legacy Wip Modes +---------------------- + +It is recommended that you use the mode ‘magit-wip-mode’ (which see) and +ignore the existence of the following modes, which are preserved for +historic reasons. + + Setting the following variables directly does not take effect; either +use the Custom interface to do so or call the respective mode functions. + + -- User Option: magit-wip-after-save-mode + When this mode is enabled, then saving a buffer that visits a file + tracked in a Git repository causes its current state to be + committed to the working tree wip ref for the current branch. + + -- User Option: magit-wip-after-apply-mode + When this mode is enabled, then applying (i.e., staging, unstaging, + discarding, reversing, and regularly applying) a change to a file + tracked in a Git repository causes its current state to be + committed to the index and/or working tree wip refs for the current + branch. + + If you only ever edit files using Emacs and only ever interact with +Git using Magit, then the above two modes should be enough to protect +each and every change from accidental loss. In practice nobody does +that. Two additional modes exists that do commit to the wip refs before +making changes that could cause the loss of earlier changes. + + -- User Option: magit-wip-before-change-mode + When this mode is enabled, then certain commands commit the + existing changes to the files they are about to make changes to. + + -- User Option: magit-wip-initial-backup-mode + When this mode is enabled, then the current version of a file is + committed to the worktree wip ref before the buffer visiting that + file is saved for the first time since the buffer was created. + + This backs up the same version of the file that ‘backup-buffer’ + would save. While ‘backup-buffer’ uses a backup file, this mode + uses the same worktree wip ref as used by the other Magit Wip + modes. Like ‘backup-buffer’, it only does this once; unless you + kill the buffer and visit the file again only one backup will be + created per Emacs session. + + This mode ignores the variables that affect ‘backup-buffer’ and can + be used along-side that function, which is recommended because it + only backs up files that are tracked in a Git repository. + + -- User Option: magit-wip-after-save-local-mode-lighter + Mode-line lighter for ‘magit-wip-after-save-local-mode’. + + -- User Option: magit-wip-after-apply-mode-lighter + Mode-line lighter for ‘magit-wip-after-apply-mode’. + + -- User Option: magit-wip-before-change-mode-lighter + Mode-line lighter for ‘magit-wip-before-change-mode’. + + -- User Option: magit-wip-initial-backup-mode-lighter + Mode-line lighter for ‘magit-wip-initial-backup-mode’. + + +File: magit.info, Node: Commands for Buffers Visiting Files, Next: Minor Mode for Buffers Visiting Blobs, Prev: Wip Modes, Up: Miscellaneous + +8.10 Commands for Buffers Visiting Files +======================================== + +By default Magit defines a few global key bindings. These bindings are +a compromise between providing no bindings at all and providing the +better bindings I would have liked to use instead. Magit cannot provide +the set of recommended bindings by default because those key sequences +are strictly reserved for bindings added by the user. Also see *note +Global Bindings:: and *note (elisp)Key Binding Conventions::. + + To use the recommended bindings, add this to your init file and +restart Emacs. + + (setq magit-define-global-key-bindings 'recommended) + + If you don’t want Magit to add any bindings to the global keymap at +all, add this to your init file and restart Emacs. + + (setq magit-define-global-key-bindings nil) + +‘C-c f’ (‘magit-file-dispatch’) +‘C-c f s’ (‘magit-stage-file’) +‘C-c f s’ (‘magit-stage-buffer-file’) +‘C-c f u’ (‘magit-unstage-file’) +‘C-c f u’ (‘magit-unstage-buffer-file’) +‘C-c f , x’ (‘magit-file-untrack’) +‘C-c f , r’ (‘magit-file-rename’) +‘C-c f , k’ (‘magit-file-delete’) +‘C-c f , c’ (‘magit-file-checkout’) +‘C-c f D’ (‘magit-diff’) +‘C-c f d’ (‘magit-diff-buffer-file’) +‘C-c f L’ (‘magit-log’) +‘C-c f l’ (‘magit-log-buffer-file’) +‘C-c f t’ (‘magit-log-trace-definition’) +‘C-c f M’ (‘magit-log-merged’) +‘C-c f B’ (‘magit-blame’) +‘C-c f b’ (‘magit-blame-additions’) +‘C-c f r’ (‘magit-blame-removal’) +‘C-c f f’ (‘magit-blame-reverse’) +‘C-c f m’ (‘magit-blame-echo’) +‘C-c f q’ (‘magit-blame-quit’) +‘C-c f p’ (‘magit-blob-previous’) +‘C-c f n’ (‘magit-blob-next’) +‘C-c f v’ (‘magit-find-file’) +‘C-c f V’ (‘magit-blob-visit-file’) +‘C-c f g’ (‘magit-status-here’) +‘C-c f G’ (‘magit-display-repository-buffer’) +‘C-c f c’ (‘magit-commit’) +‘C-c f e’ (‘magit-edit-line-commit’) + Each of these commands is documented individually right below, + alongside their default key bindings. The bindings shown above are + the recommended bindings, which you can enable by following the + instructions further up. + +‘C-c M-g’ (‘magit-file-dispatch’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘C-c M-g s’ (‘magit-stage-file’) +‘C-c M-g s’ (‘magit-stage-buffer-file’) + Stage all changes to the file being visited in the current buffer. + When not visiting a file, then the first command is used, which + prompts for a file. + +‘C-c M-g u’ (‘magit-unstage-file’) +‘C-c M-g u’ (‘magit-unstage-buffer-file’) + Unstage all changes to the file being visited in the current + buffer. When not visiting a file, then the first command is used, + which prompts for a file. + +‘C-c M-g , x’ (‘magit-file-untrack’) + This command untracks a file read from the user, defaulting to the + visited file. + +‘C-c M-g , r’ (‘magit-file-rename’) + This command renames a file read from the user, defaulting to the + visited file. + +‘C-c M-g , k’ (‘magit-file-delete’) + This command deletes a file read from the user, defaulting to the + visited file. + +‘C-c M-g , c’ (‘magit-file-checkout’) + This command updates a file in the working tree and index to the + contents from a revision. Both the revision and file are read from + the user. + +‘C-c M-g D’ (‘magit-diff’) + This transient prefix command binds several diff suffix commands + and infix arguments and displays them in a temporary buffer until a + suffix is invoked. See *note Diffing::. + + This is the same command that ‘d’ is bound to in Magit buffers. If + this command is invoked from a file-visiting buffer, then the + initial value of the option (‘--’) that limits the diff to certain + file(s) is set to the visited file. + +‘C-c M-g d’ (‘magit-diff-buffer-file’) + This command shows the diff for the file of blob that the current + buffer visits. + + -- User Option: magit-diff-buffer-file-locked + This option controls whether ‘magit-diff-buffer-file’ uses a + dedicated buffer. See *note Modes and Buffers::. + +‘C-c M-g L’ (‘magit-log’) + This transient prefix command binds several log suffix commands and + infix arguments and displays them in a temporary buffer until a + suffix is invoked. See *note Logging::. + + This is the same command that ‘l’ is bound to in Magit buffers. If + this command is invoked from a file-visiting buffer, then the + initial value of the option (‘--’) that limits the log to certain + file(s) is set to the visited file. + +‘C-c M-g l’ (‘magit-log-buffer-file’) + This command shows the log for the file of blob that the current + buffer visits. Renames are followed when a prefix argument is used + or when ‘--follow’ is an active log argument. When the region is + active, the log is restricted to the selected line range. + + -- User Option: magit-log-buffer-file-locked + This option controls whether ‘magit-log-buffer-file’ uses a + dedicated buffer. See *note Modes and Buffers::. + +‘C-c M-g t’ (‘magit-log-trace-definition’) + This command shows the log for the definition at point. + +‘C-c M-g M’ (‘magit-log-merged’) + This command reads a commit and a branch in shows a log concerning + the merge of the former into the latter. This shows multiple + commits even in case of a fast-forward merge. + +‘C-c M-g B’ (‘magit-blame’) + This transient prefix command binds all blaming suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + For more information about this and the following commands also see + *note Blaming::. + + In addition to the ‘magit-blame’ sub-transient, the dispatch + transient also binds several blaming suffix commands directly. See + *note Blaming:: for information about those commands and bindings. + +‘C-c M-g p’ (‘magit-blob-previous’) + This command visits the previous blob which modified the current + file. + +‘C-c M-g n’ (‘magit-blob-next’) + This command visits the next blob which modified the current file. + +‘C-c M-g v’ (‘magit-find-file’) + This command reads a revision and file and visits the respective + blob. + +‘C-c M-g V’ (‘magit-blob-visit-file’) + This command visits the file from the working tree, corresponding + to the current blob. When visiting a blob or the version from the + index, then it goes to the same location in the respective file in + the working tree. + +‘C-c M-g g’ (‘magit-status-here’) + This command displays the status of the current repository in a + buffer, like ‘magit-status’ does. Additionally it tries to go to + the position in that buffer, which corresponds to the position in + the current file-visiting buffer (if any). + +‘C-c M-g G’ (‘magit-display-repository-buffer’) + This command reads and displays a Magit buffer belonging to the + current repository, without refreshing it. + +‘C-c M-g c’ (‘magit-commit’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. See *note Initiating a + Commit::. + +‘C-c M-g e’ (‘magit-edit-line-commit’) + This command makes the commit editable that added the current line. + + With a prefix argument it makes the commit editable that removes + the line, if any. The commit is determined using ‘git blame’ and + made editable using ‘git rebase --interactive’ if it is reachable + from ‘HEAD’, or by checking out the commit (or a branch that points + at it) otherwise. + + +File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous + +8.11 Minor Mode for Buffers Visiting Blobs +========================================== + +The ‘magit-blob-mode’ enables certain Magit features in blob-visiting +buffers. Such buffers can be created using ‘magit-find-file’ and some +of the commands mentioned below, which also take care of turning on this +minor mode. Currently this mode only establishes a few key bindings, +but this might be extended. + +‘p’ (‘magit-blob-previous’) + Visit the previous blob which modified the current file. + +‘n’ (‘magit-blob-next’) + Visit the next blob which modified the current file. + +‘q’ (‘magit-kill-this-buffer’) + Kill the current buffer. + + +File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top + +9 Customizing +************* + +Both Git and Emacs are highly customizable. Magit is both a Git +porcelain as well as an Emacs package, so it makes sense to customize it +using both Git variables as well as Emacs options. However this +flexibility doesn’t come without problems, including but not limited to +the following. + + • Some Git variables automatically have an effect in Magit without + requiring any explicit support. Sometimes that is desirable - in + other cases, it breaks Magit. + + When a certain Git setting breaks Magit but you want to keep using + that setting on the command line, then that can be accomplished by + overriding the value for Magit only by appending something like + ‘("-c" "some.variable=compatible-value")’ to + ‘magit-git-global-arguments’. + + • Certain settings like ‘fetch.prune=true’ are respected by Magit + commands (because they simply call the respective Git command) but + their value is not reflected in the respective transient buffers. + In this case the ‘--prune’ argument in ‘magit-fetch’ might be + active or inactive, but that doesn’t keep the Git variable from + being honored by the suffix commands anyway. So pruning might + happen despite the ‘--prune’ arguments being displayed in a way + that seems to indicate that no pruning will happen. + + I intend to address these and similar issues in a future release. + +* Menu: + +* Per-Repository Configuration:: +* Essential Settings:: + + +File: magit.info, Node: Per-Repository Configuration, Next: Essential Settings, Up: Customizing + +9.1 Per-Repository Configuration +================================ + +Magit can be configured on a per-repository level using both Git +variables as well as Emacs options. + + To set a Git variable for one repository only, simply set it in +‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or +‘/etc/gitconfig’. See *note (gitman)git-config::. + + Similarly, Emacs options can be set for one repository only by +editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory +Variables::. For example to disable automatic refreshes of +file-visiting buffers in just one huge repository use this: + + • ‘/path/to/huge/repo/.dir-locals.el’ + + ((nil . ((magit-refresh-buffers . nil)))) + + It might only be costly to insert certain information into Magit +buffers for repositories that are exceptionally large, in which case you +can disable the respective section inserters just for that repository: + + • ‘/path/to/tag/invested/repo/.dir-locals.el’ + + ((magit-status-mode + . ((eval . (magit-disable-section-inserter 'magit-insert-tags-header))))) + + -- Function: magit-disable-section-inserter fn + This function disables the section inserter FN in the current + repository. It is only intended for use in ‘.dir-locals.el’ and + ‘.dir-locals-2.el’. + + If you want to apply the same settings to several, but not all, +repositories then keeping the repository-local config files in sync +would quickly become annoying. To avoid that you can create config +files for certain classes of repositories (e.g., "huge repositories") +and then include those files in the per-repository config files. For +example: + + • ‘/path/to/huge/repo/.git/config’ + + [include] + path = /path/to/huge-gitconfig + + • ‘/path/to/huge-gitconfig’ + + [status] + showUntrackedFiles = no + + • ‘$HOME/.emacs.d/init.el’ + + (dir-locals-set-class-variables 'huge-git-repository + '((nil . ((magit-refresh-buffers . nil))))) + + (dir-locals-set-directory-class + "/path/to/huge/repo/" 'huge-git-repository) + + +File: magit.info, Node: Essential Settings, Prev: Per-Repository Configuration, Up: Customizing + +9.2 Essential Settings +====================== + +The next three sections list and discuss several variables that many +users might want to customize, for safety and/or performance reasons. + +* Menu: + +* Safety:: +* Performance:: +* Global Bindings:: + + +File: magit.info, Node: Safety, Next: Performance, Up: Essential Settings + +9.2.1 Safety +------------ + +This section discusses various variables that you might want to change +(or *not* change) for safety reasons. + + Git keeps *committed* changes around long enough for users to recover +changes they have accidentally been deleted. It does not do the same +for *uncommitted* changes in the working tree and not even the index +(the staging area). Because Magit makes it so easy to modify +uncommitted changes, it also makes it easy to shoot yourself in the foot +in the process. For that reason Magit provides three global modes that +save *tracked* files to work-in-progress references after or before +certain actions. See *note Wip Modes::. + + These modes are not enabled by default because of performance +concerns. Instead a lot of potentially destructive commands require +confirmation every time they are used. In many cases this can be +disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion +and Confirmation::). If you enable the various wip modes then you +should add ‘safe-with-wip’ to this list. + + Similarly it isn’t necessary to require confirmation before moving a +file to the system trash - if you trashed a file by mistake then you can +recover it from there. Option ‘magit-delete-by-moving-to-trash’ +controls whether the system trash is used, which is the case by default. +Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might +want to change that. + + By default buffers visiting files are automatically reverted when the +visited file changes on disk. This isn’t as risky as it might seem, but +to make an informed decision you should see *note Risk of Reverting +Automatically::. + + +File: magit.info, Node: Performance, Next: Global Bindings, Prev: Safety, Up: Essential Settings + +9.2.2 Performance +----------------- + +After Magit has run ‘git’ for side-effects, it also refreshes the +current Magit buffer and the respective status buffer. This is +necessary because otherwise outdated information might be displayed +without the user noticing. Magit buffers are updated by recreating +their content from scratch, which makes updating simpler and less +error-prone, but also more costly. Keeping it simple and just +re-creating everything from scratch is an old design decision and +departing from that will require major refactoring. + + Meanwhile you can tell Magit to only automatically refresh the +current Magit buffer, but not the status buffer. If you do that, then +the status buffer is only refreshed automatically if it is the current +buffer. + + (setq magit-refresh-status-buffer nil) + + You should also check whether any third-party packages have added +anything to ‘magit-refresh-buffer-hook’, ‘magit-pre-refresh-hook’, and +‘magit-post-refresh-hook’. If so, then check whether those additions +impact performance significantly. + + Magit can be told to refresh buffers verbosely using ‘M-x +magit-toggle-verbose-refresh’. Enabling this helps figuring out which +sections are bottlenecks. Each line printed to the ‘*Messages*’ buffer +contains a section name, the number of seconds it took to show this +section, and from 0 to 2 exclamation marks: the more exclamation marks +the slower the section is. + + Magit also reverts buffers for visited files located inside the +current repository when the visited file changes on disk. That is +implemented on top of ‘auto-revert-mode’ from the built-in library +‘autorevert’. To figure out whether that impacts performance, check +whether performance is significantly worse, when many buffers exist +and/or when some buffers visit files using TRAMP. If so, then this +should help. + + (setq auto-revert-buffer-list-filter + 'magit-auto-revert-repository-buffer-p) + + For alternative approaches see *note Automatic Reverting of +File-Visiting Buffers::. + + If you have enabled any features that are disabled by default, then +you should check whether they impact performance significantly. It’s +likely that they were not enabled by default because it is known that +they reduce performance at least in large repositories. + + If performance is only slow inside certain unusually large +repositories, then you might want to disable certain features on a +per-repository or per-repository-class basis only. See *note +Per-Repository Configuration::. For example it takes a long time to +determine the next and current tag in repository with exceptional +numbers of tags. It would therefore be a good idea to disable +‘magit-insert-tags-headers’, as explained at the mentioned node. + +* Menu: + +* Microsoft Windows Performance:: +* MacOS Performance:: + +Log Performance +............... + +When showing logs, Magit limits the number of commits initially shown in +the hope that this avoids unnecessary work. When ‘--graph’ is used, +then this unfortunately does not have the desired effect for large +histories. Junio, Git’s maintainer, said on the Git mailing list +(<https://www.spinics.net/lists/git/msg232230.html>): "‘--graph’ wants +to compute the whole history and the max-count only affects the output +phase after ‘--graph’ does its computation". + + In other words, it’s not that Git is slow at outputting the +differences, or that Magit is slow at parsing the output - the problem +is that Git first goes outside and has a smoke. + + We actually work around this issue by limiting the number of commits +not only by using ‘-<N>’ but by also using a range. But unfortunately +that’s not always possible. + + When more than a few thousand commits are shown, then the use of +‘--graph’ can slow things down. + + Using ‘--color --graph’ is even slower. Magit uses code that is part +of Emacs to turn control characters into faces. That code is pretty +slow and this is quite noticeable when showing a log with many branches +and merges. For that reason ‘--color’ is not enabled by default +anymore. Consider leaving it at that. + +Diff Performance +................ + +If diffs are slow, then consider turning off some optional diff features +by setting all or some of the following variables to ‘nil’: +‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’, +‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and +‘magit-diff-refine-hunk’. + + When showing a commit instead of some arbitrary diff, then some +additional information is displayed. Calculating this information can +be quite expensive given certain circumstances. If looking at a commit +using ‘magit-revision-mode’ takes considerably more time than looking at +the same commit in ‘magit-diff-mode’, then consider setting +‘magit-revision-insert-related-refs’ to ‘nil’. + + When you are often confronted with diffs that contain deleted files, +then you might want to enable the ‘--irreversible-delete’ argument. If +you do that then diffs still show that a file was deleted but without +also showing the complete deleted content of the file. This argument is +not available by default, see *note (transient)Enabling and Disabling +Suffixes::. Once you have done that you should enable it and save that +setting, see *note (transient)Saving Values::. You should do this in +both the diff (‘d’) and the diff refresh (‘D’) transient popups. + +Refs Buffer Performance +....................... + +When refreshing the "references buffer" is slow, then that’s usually +because several hundred refs are being displayed. The best way to +address that is to display fewer refs, obviously. + + If you are not, or only mildly, interested in seeing the list of +tags, then start by not displaying them: + + (remove-hook 'magit-refs-sections-hook 'magit-insert-tags) + + Then you should also make sure that the listed remote branches +actually all exist. You can do so by pruning branches which no longer +exist using ‘f-pa’. + +Committing Performance +...................... + +When you initiate a commit, then Magit by default automatically shows a +diff of the changes you are about to commit. For large commits this can +take a long time, which is especially distracting when you are +committing large amounts of generated data which you don’t actually +intend to inspect before committing. This behavior can be turned off +using: + + (remove-hook 'server-switch-hook 'magit-commit-diff) + (remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff) + + Then you can type ‘C-c C-d’ to show the diff when you actually want +to see it, but only then. Alternatively you can leave the hook alone +and just type ‘C-g’ in those cases when it takes too long to generate +the diff. If you do that, then you will end up with a broken diff +buffer, but doing it this way has the advantage that you usually get to +see the diff, which is useful because it increases the odds that you +spot potential issues. + + +File: magit.info, Node: Microsoft Windows Performance, Next: MacOS Performance, Up: Performance + +Microsoft Windows Performance +............................. + +In order to update the status buffer, ‘git’ has to be run a few dozen +times. That is problematic on Microsoft Windows, because that operating +system is exceptionally slow at starting processes. Sadly this is an +issue that can only be fixed by Microsoft itself, and they don’t appear +to be particularly interested in doing so. + + Beside the subprocess issue, there are also other Windows-specific +performance issues. Some of these have workarounds. The maintainers of +"Git for Windows" try to improve performance on Windows. Always use the +latest release in order to benefit from the latest performance tweaks. +Magit too tries to work around some Windows-specific issues. + + According to some sources, setting the following Git variables can +also help. + + git config --global core.preloadindex true # default since v2.1 + git config --global core.fscache true # default since v2.8 + git config --global gc.auto 256 + + You should also check whether an anti-virus program is affecting +performance. + + +File: magit.info, Node: MacOS Performance, Prev: Microsoft Windows Performance, Up: Performance + +MacOS Performance +................. + +Before Emacs 26.1 child processes were created using ‘fork’ on macOS. +That needlessly copied GUI resources, which is expensive. The result +was that forking took about 30 times as long on Darwin than on Linux, +and because Magit starts many ‘git’ processes that made quite a +difference. + + So make sure that you are using at least Emacs 26.1, in which case +the faster ‘vfork’ will be used. (The creation of child processes still +takes about twice as long on Darwin compared to Linux.) See (1) for +more information. + + Additionally, ‘git’ installed from a package manager like ‘brew’ or +‘nix’ seems to be slower than the native executable. Profile the ‘git’ +executable you’re running against the one at ‘/usr/bin/git’, and if you +notice a notable difference try using the latter as +‘magit-git-executable’. + + ---------- Footnotes ---------- + + (1) +<https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html> + + +File: magit.info, Node: Global Bindings, Prev: Performance, Up: Essential Settings + +9.2.3 Global Bindings +--------------------- + + -- User Option: magit-define-global-key-bindings + This option controls which set of Magit key bindings, if any, may + be added to the global keymap, even before Magit is first used in + the current Emacs session. + + • If the value is ‘nil’, no bindings are added. + + • If ‘default’, maybe add: + + ‘C-x g’ ‘magit-status’ + ‘C-x M-g’ ‘magit-dispatch’ + ‘C-c M-g’ ‘magit-file-dispatch’ + + • If ‘recommended’, maybe add: + + ‘C-x g’ ‘magit-status’ + ‘C-c g’ ‘magit-dispatch’ + ‘C-c f’ ‘magit-file-dispatch’ + + These bindings are strongly recommended, but we cannot use + them by default, because the ‘C-c <LETTER>’ namespace is + strictly reserved for bindings added by the user (see *note + (elisp)Key Binding Conventions::). + + The bindings in the chosen set may be added when ‘after-init-hook’ + is run. Each binding is added if, and only if, at that time no + other key is bound to the same command, and no other command is + bound to the same key. In other words we try to avoid adding + bindings that are unnecessary, as well as bindings that conflict + with other bindings. + + Adding these bindings is delayed until ‘after-init-hook’ is run to + allow users to set the variable anywhere in their init file + (without having to make sure to do so before ‘magit’ is loaded or + autoloaded) and to increase the likelihood that all the potentially + conflicting user bindings have already been added. + + To set this variable use either ‘setq’ or the Custom interface. Do + not use the function ‘customize-set-variable’ because doing that + would cause Magit to be loaded immediately, when that form is + evaluated (this differs from ‘custom-set-variables’, which doesn’t + load the libraries that define the customized variables). + + Setting this variable has no effect if ‘after-init-hook’ has + already been run. + + +File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top + +10 Plumbing +*********** + +The following sections describe how to use several of Magit’s core +abstractions to extend Magit itself or implement a separate extension. + + A few of the low-level features used by Magit have been factored out +into separate libraries/packages, so that they can be used by other +packages, without having to depend on Magit. See *note +(with-editor)Top:: for information about ‘with-editor’. ‘transient’ +doesn’t have a manual yet. + + If you are trying to find an unused key that you can bind to a +command provided by your own Magit extension, then checkout +<https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry>. + +* Menu: + +* Calling Git:: +* Section Plumbing:: +* Refreshing Buffers:: +* Conventions:: + + +File: magit.info, Node: Calling Git, Next: Section Plumbing, Up: Plumbing + +10.1 Calling Git +================ + +Magit provides many specialized functions for calling Git. All of these +functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and +have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or +‘magit-git-’ (which is also used for other things). + + All of these functions accept an indefinite number of arguments, +which are strings that specify command line arguments for Git (or in +some cases an arbitrary executable). These arguments are flattened +before being passed on to the executable; so instead of strings they can +also be lists of strings and arguments that are ‘nil’ are silently +dropped. Some of these functions also require a single mandatory +argument before these command line arguments. + + Roughly speaking, these functions run Git either to get some value or +for side-effects. The functions that return a value are useful to +collect the information necessary to populate a Magit buffer, while the +others are used to implement Magit commands. + + The functions in the value-only group always run synchronously, and +they never trigger a refresh. The function in the side-effect group can +be further divided into subgroups depending on whether they run Git +synchronously or asynchronously, and depending on whether they trigger a +refresh when the executable has finished. + +* Menu: + +* Getting a Value from Git:: +* Calling Git for Effect:: + + +File: magit.info, Node: Getting a Value from Git, Next: Calling Git for Effect, Up: Calling Git + +10.1.1 Getting a Value from Git +------------------------------- + +These functions run Git in order to get a value, an exit status, or +output. Of course you could also use them to run Git commands that have +side-effects, but that should be avoided. + + -- Function: magit-git-exit-code &rest args + Executes git with ARGS and returns its exit code. + + -- Function: magit-git-success &rest args + Executes git with ARGS and returns ‘t’ if the exit code is ‘0’, + ‘nil’ otherwise. + + -- Function: magit-git-failure &rest args + Executes git with ARGS and returns ‘t’ if the exit code is ‘1’, + ‘nil’ otherwise. + + -- Function: magit-git-true &rest args + Executes git with ARGS and returns ‘t’ if the first line printed by + git is the string "true", ‘nil’ otherwise. + + -- Function: magit-git-false &rest args + Executes git with ARGS and returns ‘t’ if the first line printed by + git is the string "false", ‘nil’ otherwise. + + -- Function: magit-git-insert &rest args + Executes git with ARGS and inserts its output at point. + + -- Function: magit-git-string &rest args + Executes git with ARGS and returns the first line of its output. + If there is no output or if it begins with a newline character, + then this returns ‘nil’. + + -- Function: magit-git-lines &rest args + Executes git with ARGS and returns its output as a list of lines. + Empty lines anywhere in the output are omitted. + + -- Function: magit-git-items &rest args + Executes git with ARGS and returns its null-separated output as a + list. Empty items anywhere in the output are omitted. + + If the value of option ‘magit-git-debug’ is non-nil and git exits + with a non-zero exit status, then warn about that in the echo area + and add a section containing git’s standard error in the current + repository’s process buffer. + + -- Function: magit-process-git destination &rest args + Calls Git synchronously in a separate process, returning its exit + code. DESTINATION specifies how to handle the output, like for + ‘call-process’, except that file handlers are supported. Enables + Cygwin’s "noglob" option during the call and ensures unix eol + conversion. + + -- Function: magit-process-file process &optional infile buffer display + &rest args + Processes files synchronously in a separate process. Identical to + ‘process-file’ but temporarily enables Cygwin’s "noglob" option + during the call and ensures unix eol conversion. + + If an error occurs when using one of the above functions, then that +is usually due to a bug, i.e., using an argument which is not actually +supported. Such errors are usually not reported, but when they occur we +need to be able to debug them. + + -- User Option: magit-git-debug + Whether to report errors that occur when using ‘magit-git-insert’, + ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This + does not actually raise an error. Instead a message is shown in + the echo area, and git’s standard error is insert into a new + section in the current repository’s process buffer. + + -- Function: magit-git-str &rest args + This is a variant of ‘magit-git-string’ that ignores the option + ‘magit-git-debug’. It is mainly intended to be used while handling + errors in functions that do respect that option. Using such a + function while handing an error could cause yet another error and + therefore lead to an infinite recursion. You probably won’t ever + need to use this function. + + +File: magit.info, Node: Calling Git for Effect, Prev: Getting a Value from Git, Up: Calling Git + +10.1.2 Calling Git for Effect +----------------------------- + +These functions are used to run git to produce some effect. Most Magit +commands that actually run git do so by using such a function. + + Because we do not need to consume git’s output when using these +functions, their output is instead logged into a per-repository buffer, +which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’ +elsewhere. + + These functions can have an effect in two distinct ways. Firstly, +running git may change something, i.e., create or push a new commit. +Secondly, that change may require that Magit buffers are refreshed to +reflect the changed state of the repository. But refreshing isn’t +always desirable, so only some of these functions do perform such a +refresh after git has returned. + + Sometimes it is useful to run git asynchronously. For example, when +the user has just initiated a push, then there is no reason to make her +wait until that has completed. In other cases it makes sense to wait +for git to complete before letting the user do something else. For +example after staging a change it is useful to wait until after the +refresh because that also automatically moves to the next change. + + -- Function: magit-call-git &rest args + Calls git synchronously with ARGS. + + -- Function: magit-call-process program &rest args + Calls PROGRAM synchronously with ARGS. + + -- Function: magit-run-git &rest args + Calls git synchronously with ARGS and then refreshes. + + -- Function: magit-run-git-with-input &rest args + Calls git synchronously with ARGS and sends it the content of the + current buffer on standard input. + + If the current buffer’s ‘default-directory’ is on a remote + filesystem, this function actually runs git asynchronously. But + then it waits for the process to return, so the function itself is + synchronous. + + -- Function: magit-git &rest args + Calls git synchronously with ARGS for side-effects only. This + function does not refresh the buffer. + + -- Function: magit-git-wash washer &rest args + Execute Git with ARGS, inserting washed output at point. Actually + first insert the raw output at point. If there is no output call + ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to + the inserted text, move to its beginning, and then call function + WASHER with ARGS as its sole argument. + + And now for the asynchronous variants. + + -- Function: magit-run-git-async &rest args + Start Git, prepare for refresh, and return the process object. + ARGS is flattened and then used as arguments to Git. + + Display the command line arguments in the echo area. + + After Git returns some buffers are refreshed: the buffer that was + current when this function was called (if it is a Magit buffer and + still alive), as well as the respective Magit status buffer. + Unmodified buffers visiting files that are tracked in the current + repository are reverted if ‘magit-revert-buffers’ is non-nil. + + -- Function: magit-run-git-with-editor &rest args + Export GIT_EDITOR and start Git. Also prepare for refresh and + return the process object. ARGS is flattened and then used as + arguments to Git. + + Display the command line arguments in the echo area. + + After Git returns some buffers are refreshed: the buffer that was + current when this function was called (if it is a Magit buffer and + still alive), as well as the respective Magit status buffer. + + -- Function: magit-start-git input &rest args + Start Git, prepare for refresh, and return the process object. + + If INPUT is non-nil, it has to be a buffer or the name of an + existing buffer. The buffer content becomes the processes standard + input. + + Option ‘magit-git-executable’ specifies the Git executable and + option ‘magit-git-global-arguments’ specifies constant arguments. + The remaining arguments ARGS specify arguments to Git. They are + flattened before use. + + After Git returns, some buffers are refreshed: the buffer that was + current when this function was called (if it is a Magit buffer and + still alive), as well as the respective Magit status buffer. + Unmodified buffers visiting files that are tracked in the current + repository are reverted if ‘magit-revert-buffers’ is non-nil. + + -- Function: magit-start-process &rest args + Start PROGRAM, prepare for refresh, and return the process object. + + If optional argument INPUT is non-nil, it has to be a buffer or the + name of an existing buffer. The buffer content becomes the + processes standard input. + + The process is started using ‘start-file-process’ and then setup to + use the sentinel ‘magit-process-sentinel’ and the filter + ‘magit-process-filter’. Information required by these functions is + stored in the process object. When this function returns the + process has not started to run yet so it is possible to override + the sentinel and filter. + + After the process returns, ‘magit-process-sentinel’ refreshes the + buffer that was current when ‘magit-start-process’ was called (if + it is a Magit buffer and still alive), as well as the respective + Magit status buffer. Unmodified buffers visiting files that are + tracked in the current repository are reverted if + ‘magit-revert-buffers’ is non-nil. + + -- Variable: magit-this-process + The child process which is about to start. This can be used to + change the filter and sentinel. + + -- Variable: magit-process-raise-error + When this is non-nil, then ‘magit-process-sentinel’ raises an error + if git exits with a non-zero exit status. For debugging purposes. + + +File: magit.info, Node: Section Plumbing, Next: Refreshing Buffers, Prev: Calling Git, Up: Plumbing + +10.2 Section Plumbing +===================== + +* Menu: + +* Creating Sections:: +* Section Selection:: +* Matching Sections:: + + +File: magit.info, Node: Creating Sections, Next: Section Selection, Up: Section Plumbing + +10.2.1 Creating Sections +------------------------ + + -- Macro: magit-insert-section &rest args + Insert a section at point. + + TYPE is the section type, a symbol. Many commands that act on the + current section behave differently depending on that type. Also if + a variable ‘magit-TYPE-section-map’ exists, then use that as the + text-property ‘keymap’ of all text belonging to the section (but + this may be overwritten in subsections). TYPE can also have the + form ‘(eval FORM)’ in which case FORM is evaluated at runtime. + + Optional VALUE is the value of the section, usually a string that + is required when acting on the section. + + When optional HIDE is non-nil collapse the section body by default, + i.e., when first creating the section, but not when refreshing the + buffer. Otherwise, expand it by default. This can be overwritten + using ‘magit-section-set-visibility-hook’. When a section is + recreated during a refresh, then the visibility of predecessor is + inherited and HIDE is ignored (but the hook is still honored). + + BODY is any number of forms that actually insert the section’s + heading and body. Optional NAME, if specified, has to be a symbol, + which is then bound to the struct of the section being inserted. + + Before BODY is evaluated the ‘start’ of the section object is set + to the value of ‘point’ and after BODY was evaluated its ‘end’ is + set to the new value of ‘point’; BODY is responsible for moving + ‘point’ forward. + + If it turns out inside BODY that the section is empty, then + ‘magit-cancel-section’ can be used to abort and remove all traces + of the partially inserted section. This can happen when creating a + section by washing Git’s output and Git didn’t actually output + anything this time around. + + -- Function: magit-insert-heading &rest args + Insert the heading for the section currently being inserted. + + This function should only be used inside ‘magit-insert-section’. + + When called without any arguments, then just set the ‘content’ slot + of the object representing the section being inserted to a marker + at ‘point’. The section should only contain a single line when + this function is used like this. + + When called with arguments ARGS, which have to be strings, then + insert those strings at point. The section should not contain any + text before this happens and afterwards it should again only + contain a single line. If the ‘face’ property is set anywhere + inside any of these strings, then insert all of them unchanged. + Otherwise use the ‘magit-section-heading’ face for all inserted + text. + + The ‘content’ property of the section struct is the end of the + heading (which lasts from ‘start’ to ‘content’) and the beginning + of the body (which lasts from ‘content’ to ‘end’). If the value of + ‘content’ is nil, then the section has no heading and its body + cannot be collapsed. If a section does have a heading then its + height must be exactly one line, including a trailing newline + character. This isn’t enforced; you are responsible for getting it + right. The only exception is that this function does insert a + newline character if necessary. + + -- Function: magit-cancel-section + Cancel the section currently being inserted. This exits the + innermost call to ‘magit-insert-section’ and removes all traces of + what has already happened inside that call. + + -- Function: magit-define-section-jumper sym title &optional value + Define an interactive function to go to section SYM. TITLE is the + displayed title of the section. + + +File: magit.info, Node: Section Selection, Next: Matching Sections, Prev: Creating Sections, Up: Section Plumbing + +10.2.2 Section Selection +------------------------ + + -- Function: magit-current-section + Return the section at point. + + -- Function: magit-region-sections &optional condition multiple + Return a list of the selected sections. + + When the region is active and constitutes a valid section + selection, then return a list of all selected sections. This is + the case when the region begins in the heading of a section and + ends in the heading of the same section or in that of a sibling + section. If optional MULTIPLE is non-nil, then the region cannot + begin and end in the same section. + + When the selection is not valid, then return nil. In this case, + most commands that can act on the selected sections will instead + act on the section at point. + + When the region looks like it would in any other buffer then the + selection is invalid. When the selection is valid then the region + uses the ‘magit-section-highlight’ face. This does not apply to + diffs where things get a bit more complicated, but even here if the + region looks like it usually does, then that’s not a valid + selection as far as this function is concerned. + + If optional CONDITION is non-nil, then the selection not only has + to be valid; all selected sections additionally have to match + CONDITION, or nil is returned. See ‘magit-section-match’ for the + forms CONDITION can take. + + -- Function: magit-region-values &optional condition multiple + Return a list of the values of the selected sections. + + Return the values that themselves would be returned by + ‘magit-region-sections’ (which see). + + +File: magit.info, Node: Matching Sections, Prev: Section Selection, Up: Section Plumbing + +10.2.3 Matching Sections +------------------------ + +‘M-x magit-describe-section-briefly’ + Show information about the section at point. This command is + intended for debugging purposes. + + -- Function: magit-section-ident section + Return an unique identifier for SECTION. The return value has the + form ‘((TYPE . VALUE)...)’. + + -- Function: magit-get-section ident &optional root + Return the section identified by IDENT. IDENT has to be a list as + returned by ‘magit-section-ident’. + + -- Function: magit-section-match condition &optional section + Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the + section at point. If SECTION is not specified and there also is no + section at point, then return ‘nil’. + + CONDITION can take the following forms: + • ‘(CONDITION...)’ + + matches if any of the CONDITIONs matches. + + • ‘[CLASS...]’ + + matches if the section’s class is the same as the first CLASS + or a subclass of that; the section’s parent class matches the + second CLASS; and so on. + + • ‘[* CLASS...]’ + + matches sections that match ‘[CLASS...]’ and also recursively + all their child sections. + + • ‘CLASS’ + + matches if the section’s class is the same as CLASS or a + subclass of that; regardless of the classes of the parent + sections. + + Each CLASS should be a class symbol, identifying a class that + derives from ‘magit-section’. For backward compatibility CLASS can + also be a "type symbol". A section matches such a symbol if the + value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in + ‘magit--section-type-alist’, then a section also matches that type + if its class is a subclass of the class that corresponds to the + type as per that alist. + + Note that it is not necessary to specify the complete section + lineage as printed by ‘magit-describe-section-briefly’, unless of + course you want to be that precise. + + -- Function: magit-section-value-if condition &optional section + If the section at point matches CONDITION, then return its value. + + If optional SECTION is non-nil then test whether that matches + instead. If there is no section at point and SECTION is nil, then + return nil. If the section does not match, then return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + + -- Function: magit-section-case &rest clauses + Choose among clauses on the type of the section at point. + + Each clause looks like (CONDITION BODY...). The type of the + section is compared against each CONDITION; the BODY forms of the + first match are evaluated sequentially and the value of the last + form is returned. Inside BODY the symbol ‘it’ is bound to the + section at point. If no clause succeeds or if there is no section + at point return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + Additionally a CONDITION of t is allowed in the final clause and + matches if no other CONDITION match, even if there is no section at + point. + + -- Variable: magit-root-section + The root section in the current buffer. All other sections are + descendants of this section. The value of this variable is set by + ‘magit-insert-section’ and you should never modify it. + + For diff related sections a few additional tools exist. + + -- Function: magit-diff-type &optional section + Return the diff type of SECTION. + + The returned type is one of the symbols ‘staged’, ‘unstaged’, + ‘committed’, or ‘undefined’. This type serves a similar purpose as + the general type common to all sections (which is stored in the + ‘type’ slot of the corresponding ‘magit-section’ struct) but takes + additional information into account. When the SECTION isn’t + related to diffs and the buffer containing it also isn’t a + diff-only buffer, then return nil. + + Currently the type can also be one of ‘tracked’ and ‘untracked’, + but these values are not handled explicitly in every place they + should be. A possible fix could be to just return nil here. + + The section has to be a ‘diff’ or ‘hunk’ section, or a section + whose children are of type ‘diff’. If optional SECTION is nil, + return the diff type for the current section. In buffers whose + major mode is ‘magit-diff-mode’ SECTION is ignored and the type is + determined using other means. In ‘magit-revision-mode’ buffers the + type is always ‘committed’. + + -- Function: magit-diff-scope &optional section strict + Return the diff scope of SECTION or the selected section(s). + + A diff’s "scope" describes what part of a diff is selected, it is a + symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or + ‘list’. Do not confuse this with the diff "type", as returned by + ‘magit-diff-type’. + + If optional SECTION is non-nil, then return the scope of that, + ignoring the sections selected by the region. Otherwise return the + scope of the current section, or if the region is active and + selects a valid group of diff related sections, the type of these + sections, i.e., ‘hunks’ or ‘files’. If SECTION (or if the current + section that is nil) is a ‘hunk’ section and the region starts and + ends inside the body of a that section, then the type is ‘region’. + + If optional STRICT is non-nil then return nil if the diff type of + the section at point is ‘untracked’ or the section at point is not + actually a ‘diff’ but a ‘diffstat’ section. + + +File: magit.info, Node: Refreshing Buffers, Next: Conventions, Prev: Section Plumbing, Up: Plumbing + +10.3 Refreshing Buffers +======================= + +All commands that create a new Magit buffer or change what is being +displayed in an existing buffer do so by calling ‘magit-mode-setup’. +Among other things, that function sets the buffer local values of +‘default-directory’ (to the top-level of the repository), +‘magit-refresh-function’, and ‘magit-refresh-args’. + + Buffers are refreshed by calling the function that is the local value +of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’, +where ‘*’ may be something like ‘diff’) with the value of +‘magit-refresh-args’ as arguments. + + -- Macro: magit-mode-setup buffer switch-func mode refresh-func + &optional refresh-args + This function displays and selects BUFFER, turns on MODE, and + refreshes a first time. + + This function displays and optionally selects BUFFER by calling + ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as + arguments. Then it sets the local value of + ‘magit-refresh-function’ to REFRESH-FUNC and that of + ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the + buffer content by calling REFRESH-FUNC with REFRESH-ARGS as + arguments. + + All arguments are evaluated before switching to BUFFER. + + -- Function: magit-mode-display-buffer buffer mode &optional + switch-function + This function display BUFFER in some window and select it. BUFFER + may be a buffer or a string, the name of a buffer. The buffer is + returned. + + Unless BUFFER is already displayed in the selected frame, store the + previous window configuration as a buffer local value, so that it + can later be restored by ‘magit-mode-bury-buffer’. + + The buffer is displayed and selected using SWITCH-FUNCTION. If + that is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s + major mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ + is used. + + -- Variable: magit-refresh-function + The value of this buffer-local variable is the function used to + refresh the current buffer. It is called with ‘magit-refresh-args’ + as arguments. + + -- Variable: magit-refresh-args + The list of arguments used by ‘magit-refresh-function’ to refresh + the current buffer. ‘magit-refresh-function’ is called with these + arguments. + + The value is usually set using ‘magit-mode-setup’, but in some + cases it’s also useful to provide commands that can change the + value. For example, the ‘magit-diff-refresh’ transient can be used + to change any of the arguments used to display the diff, without + having to specify again which differences should be shown, but + ‘magit-diff-more-context’, ‘magit-diff-less-context’ and + ‘magit-diff-default-context’ change just the ‘-U<N>’ argument. In + both case this is done by changing the value of this variable and + then calling this ‘magit-refresh-function’. + + +File: magit.info, Node: Conventions, Prev: Refreshing Buffers, Up: Plumbing + +10.4 Conventions +================ + +Also see *note Completion and Confirmation::. + +* Menu: + +* Theming Faces:: + + +File: magit.info, Node: Theming Faces, Up: Conventions + +10.4.1 Theming Faces +-------------------- + +The default theme uses blue for local branches, green for remote +branches, and goldenrod (brownish yellow) for tags. When creating a new +theme, you should probably follow that example. If your theme already +uses other colors, then stick to that. + + In older releases these reference faces used to have a background +color and a box around them. The basic default faces no longer do so, +to make Magit buffers much less noisy, and you should follow that +example at least with regards to boxes. (Boxes were used in the past to +work around a conflict between the highlighting overlay and text +property backgrounds. That’s no longer necessary because highlighting +no longer causes other background colors to disappear.) Alternatively +you can keep the background color and/or box, but then have to take +special care to adjust ‘magit-branch-current’ accordingly. By default +it looks mostly like ‘magit-branch-local’, but with a box (by default +the former is the only face that uses a box, exactly so that it sticks +out). If the former also uses a box, then you have to make sure that it +differs in some other way from the latter. + + The most difficult faces to theme are those related to diffs, +headings, highlighting, and the region. There are faces that fall into +all four groups - expect to spend some time getting this right. + + The ‘region’ face in the default theme, in both the light and dark +variants, as well as in many other themes, distributed with Emacs or by +third-parties, is very ugly. It is common to use a background color +that really sticks out, which is ugly but if that were the only problem +then it would be acceptable. Unfortunately many themes also set the +foreground color, which ensures that all text within the region is +readable. Without doing that there might be cases where some foreground +color is too close to the region background color to still be readable. +But it also means that text within the region loses all syntax +highlighting. + + I consider the work that went into getting the ‘region’ face right to +be a good indicator for the general quality of a theme. My +recommendation for the ‘region’ face is this: use a background color +slightly different from the background color of the ‘default’ face, and +do not set the foreground color at all. So for a light theme you might +use a light (possibly tinted) gray as the background color of ‘default’ +and a somewhat darker gray for the background of ‘region’. That should +usually be enough to not collide with the foreground color of any other +face. But if some other faces also set a light gray as background +color, then you should also make sure it doesn’t collide with those (in +some cases it might be acceptable though). + + Magit only uses the ‘region’ face when the region is "invalid" by its +own definition. In a Magit buffer the region is used to either select +multiple sibling sections, so that commands which support it act on all +of these sections instead of just the current section, or to select +lines within a single hunk section. In all other cases, the section is +considered invalid and Magit won’t act on it. But such invalid sections +happen, either because the user has not moved point enough yet to make +it valid or because she wants to use a non-magit command to act on the +region, e.g., ‘kill-region’. + + So using the regular ‘region’ face for invalid sections is a feature. +It tells the user that Magit won’t be able to act on it. It’s +acceptable if that face looks a bit odd and even (but less so) if it +collides with the background colors of section headings and other things +that have a background color. + + Magit highlights the current section. If a section has subsections, +then all of them are highlighted. This is done using faces that have +"highlight" in their names. For most sections, +‘magit-section-highlight’ is used for both the body and the heading. +Like the ‘region’ face, it should only set the background color to +something similar to that of ‘default’. The highlight background color +must be different from both the ‘region’ background color and the +‘default’ background color. + + For diff related sections Magit uses various faces to highlight +different parts of the selected section(s). Note that hunk headings, +unlike all other section headings, by default have a background color, +because it is useful to have very visible separators between hunks. +That face ‘magit-diff-hunk-heading’, should be different from both +‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as +well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’. +By default we do that by changing the foreground color. Changing the +background color would lead to complications, and there are already +enough we cannot get around. (Also note that it is generally a good +idea for section headings to always be bold, but only for sections that +have subsections). + + When there is a valid region selecting diff-related sibling sections, +i.e., multiple files or hunks, then the bodies of all these sections use +the respective highlight faces, but additionally the headings instead +use one of the faces ‘magit-diff-file-heading-selection’ or +‘magit-diff-hunk-heading-selection’. These faces have to be different +from the regular highlight variants to provide explicit visual +indication that the region is active. + + When theming diff related faces, start by setting the option +‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only +refine the current hunk or not use hunk refinement at all, but some of +the users of your theme want all hunks to be refined, so you have to +cater to that. + + (Also turn on ‘magit-diff-highlight-indentation’, +‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and +insert some whitespace errors into the code you use for testing.) + + For added lines you have to adjust three faces: ‘magit-diff-added’, +‘magit-diff-added-highlight’, and ‘diff-refined-added’. Make sure that +the latter works well with both of the former, as well as ‘smerge-other’ +and ‘diff-added’. Then do the same for the removed lines, context +lines, lines added by us, and lines added by them. Also make sure the +respective added, removed, and context faces use approximately the same +saturation for both the highlighted and unhighlighted variants. Also +make sure the file and diff headings work nicely with context lines +(e.g., make them look different). Line faces should set both the +foreground and the background color. For example, for added lines use +two different greens. + + It’s best if the foreground color of both the highlighted and the +unhighlighted variants are the same, so you will need to have to find a +color that works well on the highlight and unhighlighted background, the +refine background, and the highlight context background. When there is +an hunk internal region, then the added- and removed-lines background +color is used only within that region. Outside the region the +highlighted context background color is used. This makes it easier to +see what is being staged. With an hunk internal region the hunk heading +is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin +lines that are added around the lines that fall within the region. The +background color of that has to be distinct enough from the various +other involved background colors. + + Nobody said this would be easy. If your theme restricts itself to a +certain set of colors, then you should make an exception here. +Otherwise it would be impossible to make the diffs look good in each and +every variation. Actually you might want to just stick to the default +definitions for these faces. You have been warned. Also please note +that if you do not get this right, this will in some cases look to users +like bugs in Magit - so please do it right or not at all. + + +File: magit.info, Node: FAQ, Next: Debugging Tools, Prev: Plumbing, Up: Top + +Appendix A FAQ +************** + +The next two nodes lists frequently asked questions. For a list of +frequently *and recently* asked questions, i.e., questions that haven’t +made it into the manual yet, see +<https://github.com/magit/magit/wiki/FAQ>. + + Please also see *note Debugging Tools::. + +* Menu: + +* FAQ - How to ...?:: +* FAQ - Issues and Errors:: + + +File: magit.info, Node: FAQ - How to ...?, Next: FAQ - Issues and Errors, Up: FAQ + +A.1 FAQ - How to ...? +===================== + +* Menu: + +* How to pronounce Magit?:: +* How to show git's output?:: +* How to install the gitman info manual?:: +* How to show diffs for gpg-encrypted files?:: +* How does branching and pushing work?:: +* Should I disable VC?:: + + +File: magit.info, Node: How to pronounce Magit?, Next: How to show git's output?, Up: FAQ - How to ...? + +A.1.1 How to pronounce Magit? +----------------------------- + +Either ‘mu[m's] git’ or ‘magi{c => t}’ is fine. + + The slogan is "It’s Magit! The magical Git client", so it makes +sense to pronounce Magit like magic, while taking into account that C +and T do not sound the same. + + The German "Magie" is not pronounced the same as the English "magic", +so if you speak German then you can use the above rationale to justify +using the former pronunciation; ‘Mag{ie => it}’. + + You can also choose to use the former pronunciation just because you +like it better. + + Also see <https://magit.vc/assets/videos/magic.mp4>. Also see +<https://emacs.stackexchange.com/questions/13696>. + + +File: magit.info, Node: How to show git's output?, Next: How to install the gitman info manual?, Prev: How to pronounce Magit?, Up: FAQ - How to ...? + +A.1.2 How to show git’s output? +------------------------------- + +To show the output of recently run git commands, press ‘$’ (or, if that +isn’t available, ‘M-x magit-process-buffer’). This will show a buffer +containing a section per git invocation; as always press ‘TAB’ to expand +or collapse them. + + By default, git’s output is only inserted into the process buffer if +it is run for side-effects. When the output is consumed in some way, +also inserting it into the process buffer would be too expensive. For +debugging purposes, it’s possible to do so anyway by setting +‘magit-git-debug’ to ‘t’. + + +File: magit.info, Node: How to install the gitman info manual?, Next: How to show diffs for gpg-encrypted files?, Prev: How to show git's output?, Up: FAQ - How to ...? + +A.1.3 How to install the gitman info manual? +-------------------------------------------- + +Git’s manpages can be exported as an info manual called ‘gitman’. +Magit’s own info manual links to nodes in that manual instead of the +actual manpages because Info doesn’t support linking to manpages. + + Unfortunately some distributions do not install the ‘gitman’ manual +by default and you will have to install a separate documentation package +to get it. + + Magit patches Info adding the ability to visit links to the ‘gitman’ +Info manual by instead viewing the respective manpage. If you prefer +that approach, then set the value of ‘magit-view-git-manual-method’ to +one of the supported packages ‘man’ or ‘woman’, e.g.: + + (setq magit-view-git-manual-method 'man) + + +File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: How does branching and pushing work?, Prev: How to install the gitman info manual?, Up: FAQ - How to ...? + +A.1.4 How to show diffs for gpg-encrypted files? +------------------------------------------------ + +Git supports showing diffs for encrypted files, but has to be told to do +so. Since Magit just uses Git to get the diffs, configuring Git also +affects the diffs displayed inside Magit. + + git config --global diff.gpg.textconv "gpg --no-tty --decrypt" + echo "*.gpg filter=gpg diff=gpg" > .gitattributes + + +File: magit.info, Node: How does branching and pushing work?, Next: Should I disable VC?, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ - How to ...? + +A.1.5 How does branching and pushing work? +------------------------------------------ + +Please see *note Branching:: and +<https://emacsair.me/2016/01/17/magit-2.4> + + +File: magit.info, Node: Should I disable VC?, Prev: How does branching and pushing work?, Up: FAQ - How to ...? + +A.1.6 Should I disable VC? +-------------------------- + +If you don’t use VC (the built-in version control interface) then you +might be tempted to disable it, not least because we used to recommend +that you do that. + + We no longer recommend that you disable VC. Doing so would break +useful third-party packages (such as ‘diff-hl’), which depend on VC +being enabled. + + If you choose to disable VC anyway, then you can do so by changing +the value of ‘vc-handled-backends’. + + +File: magit.info, Node: FAQ - Issues and Errors, Prev: FAQ - How to ...?, Up: FAQ + +A.2 FAQ - Issues and Errors +=========================== + +* Menu: + +* Magit is slow:: +* I changed several thousand files at once and now Magit is unusable:: +* I am having problems committing:: +* I am using MS Windows and cannot push with Magit:: +* I am using macOS and SOMETHING works in shell, but not in Magit: I am using macOS and SOMETHING works in shell but not in Magit. +* Expanding a file to show the diff causes it to disappear:: +* Point is wrong in the COMMIT_EDITMSG buffer:: +* The mode-line information isn't always up-to-date:: +* A branch and tag sharing the same name breaks SOMETHING:: +* My Git hooks work on the command-line but not inside Magit:: +* git-commit-mode isn't used when committing from the command-line:: +* Point ends up inside invisible text when jumping to a file-visiting buffer:: +* I am no longer able to save popup defaults:: + + +File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors + +A.2.1 Magit is slow +------------------- + +See *note Performance:: and *note I changed several thousand files at +once and now Magit is unusable::. + + +File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ - Issues and Errors + +A.2.2 I changed several thousand files at once and now Magit is unusable +------------------------------------------------------------------------ + +Magit is currently not expected to work well under such conditions. It +sure would be nice if it did. Reaching satisfactory performance under +such conditions will require some heavy refactoring. This is no small +task but I hope to eventually find the time to make it happen. + + But for now we recommend you use the command line to complete this +one commit. Also see *note Performance::. + + +File: magit.info, Node: I am having problems committing, Next: I am using MS Windows and cannot push with Magit, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors + +A.2.3 I am having problems committing +------------------------------------- + +That likely means that Magit is having problems finding an appropriate +emacsclient executable. See *note (with-editor)Configuring +With-Editor:: and *note (with-editor)Debugging::. + + +File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using macOS and SOMETHING works in shell but not in Magit, Prev: I am having problems committing, Up: FAQ - Issues and Errors + +A.2.4 I am using MS Windows and cannot push with Magit +------------------------------------------------------ + +It’s almost certain that Magit is only incidental to this issue. It is +much more likely that this is a configuration issue, even if you can +push on the command line. + + Detailed setup instructions can be found at +<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>. + + +File: magit.info, Node: I am using macOS and SOMETHING works in shell but not in Magit, Next: Expanding a file to show the diff causes it to disappear, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ - Issues and Errors + +A.2.5 I am using macOS and SOMETHING works in shell, but not in Magit +--------------------------------------------------------------------- + +This usually occurs because Emacs doesn’t have the same environment +variables as your shell. Try installing and configuring +<https://github.com/purcell/exec-path-from-shell>. By default it +synchronizes ‘$PATH’, which helps Magit find the same ‘git’ as the one +you are using on the shell. + + If SOMETHING is "passphrase caching with gpg-agent for commit and/or +tag signing", then you’ll also need to synchronize ‘$GPG_AGENT_INFO’. + + +File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: I am using macOS and SOMETHING works in shell but not in Magit, Up: FAQ - Issues and Errors + +A.2.6 Expanding a file to show the diff causes it to disappear +-------------------------------------------------------------- + +This is probably caused by a customization of a ‘diff.*’ Git variable. +You probably set that variable for a reason, and should therefore only +undo that setting in Magit by customizing ‘magit-git-global-arguments’. + + +File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ - Issues and Errors + +A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer +--------------------------------------------------- + +Neither Magit nor ‘git-commit.el’ fiddle with point in the buffer used +to write commit messages, so something else must be doing it. + + You have probably globally enabled a mode which restores point in +file-visiting buffers. It might be a bit surprising, but when you write +a commit message, then you are actually editing a file. + + So you have to figure out which package is doing it. ‘saveplace’, +‘pointback’, and ‘session’ are likely candidates. These snippets might +help: + + (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)") + + (with-eval-after-load 'pointback + (lambda () + (when (or git-commit-mode git-rebase-mode) + (pointback-mode -1)))) + + +File: magit.info, Node: The mode-line information isn't always up-to-date, Next: A branch and tag sharing the same name breaks SOMETHING, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ - Issues and Errors + +A.2.8 The mode-line information isn’t always up-to-date +------------------------------------------------------- + +Magit is not responsible for the version control information that is +being displayed in the mode-line and looks something like ‘Git-master’. +The built-in "Version Control" package, also known as "VC", updates that +information, and can be told to do so more often: + + (setq auto-revert-check-vc-info t) + + But doing so isn’t good for performance. For more (overly +optimistic) information see *note (emacs)VC Mode Line::. + + If you don’t really care about seeing this information in the +mode-line, but just don’t want to see _incorrect_ information, then +consider simply not displaying it in the mode-line: + + (setq-default mode-line-format + (delete '(vc-mode vc-mode) mode-line-format)) + + +File: magit.info, Node: A branch and tag sharing the same name breaks SOMETHING, Next: My Git hooks work on the command-line but not inside Magit, Prev: The mode-line information isn't always up-to-date, Up: FAQ - Issues and Errors + +A.2.9 A branch and tag sharing the same name breaks SOMETHING +------------------------------------------------------------- + +Or more generally, ambiguous refnames break SOMETHING. + + Magit assumes that refs are named non-ambiguously across the +"refs/heads/", "refs/tags/", and "refs/remotes/" namespaces (i.e., all +the names remain unique when those prefixes are stripped). We consider +ambiguous refnames unsupported and recommend that you use a +non-ambiguous naming scheme. However, if you do work with a repository +that has ambiguous refnames, please report any issues you encounter, so +that we can investigate whether there is a simple fix. + + +File: magit.info, Node: My Git hooks work on the command-line but not inside Magit, Next: git-commit-mode isn't used when committing from the command-line, Prev: A branch and tag sharing the same name breaks SOMETHING, Up: FAQ - Issues and Errors + +A.2.10 My Git hooks work on the command-line but not inside Magit +----------------------------------------------------------------- + +When Magit calls ‘git’ it adds a few global arguments including +‘--literal-pathspecs’ and the ‘git’ process started by Magit then passes +that setting on to other ‘git’ process it starts itself. It does so by +setting the environment variable ‘GIT_LITERAL_PATHSPECS’, not by calling +subprocesses with the ‘--literal-pathspecs’ argument. You can therefore +override this setting in hook scripts using ‘unset +GIT_LITERAL_PATHSPECS’. + + +File: magit.info, Node: git-commit-mode isn't used when committing from the command-line, Next: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: My Git hooks work on the command-line but not inside Magit, Up: FAQ - Issues and Errors + +A.2.11 ‘git-commit-mode’ isn’t used when committing from the command-line +------------------------------------------------------------------------- + +The reason for this is that ‘git-commit.el’ has not been loaded yet +and/or that the server has not been started yet. These things have +always already been taken care of when you commit from Magit because in +order to do so, Magit has to be loaded and doing that involves loading +‘git-commit’ and starting the server. + + If you want to commit from the command-line, then you have to take +care of these things yourself. Your ‘init.el’ file should contain: + + (require 'git-commit) + (server-mode) + + Instead of ‘(require ’git-commit)‘ you may also use: + + (load "/path/to/magit-autoloads.el") + + You might want to do that because loading ‘git-commit’ causes large +parts of Magit to be loaded. + + There are also some variations of ‘(server-mode)’ that you might want +to try. Personally I use: + + (use-package server + :config (or (server-running-p) (server-mode))) + + Now you can use: + + $ emacs& + $ EDITOR=emacsclient git commit + + However you cannot use: + + $ killall emacs + $ EDITOR="emacsclient --alternate-editor emacs" git commit + + This will actually end up using ‘emacs’, not ‘emacsclient’. If you +do this, then you can still edit the commit message but +‘git-commit-mode’ won’t be used and you have to exit ‘emacs’ to finish +the process. + + Tautology ahead. If you want to be able to use ‘emacsclient’ to +connect to a running ‘emacs’ instance, even though no ‘emacs’ instance +is running, then you cannot use ‘emacsclient’ directly. + + Instead you have to create a script that does something like this: + + Try to use ‘emacsclient’ (without using ‘--alternate-editor’). If +that succeeds, do nothing else. Otherwise start ‘emacs &’ (and +‘init.el’ must call ‘server-start’) and try to use ‘emacsclient’ again. + + +File: magit.info, Node: Point ends up inside invisible text when jumping to a file-visiting buffer, Next: I am no longer able to save popup defaults, Prev: git-commit-mode isn't used when committing from the command-line, Up: FAQ - Issues and Errors + +A.2.12 Point ends up inside invisible text when jumping to a file-visiting buffer +--------------------------------------------------------------------------------- + +This can happen when you type ‘RET’ on a hunk to visit the respective +file at the respective position. One solution to this problem is to use +‘global-reveal-mode’. It makes sure that text around point is always +visible. If that is too drastic for your taste, then you may instead +use ‘magit-diff-visit-file-hook’ to reveal the text, possibly using +‘reveal-post-command’ or for Org buffers ‘org-reveal’. + + +File: magit.info, Node: I am no longer able to save popup defaults, Prev: Point ends up inside invisible text when jumping to a file-visiting buffer, Up: FAQ - Issues and Errors + +A.2.13 I am no longer able to save popup defaults +------------------------------------------------- + +Magit used to use Magit-Popup to implement the transient popup menus. +Now it used Transient instead, which is Magit-Popup’s successor. + + In the older Magit-Popup menus, it was possible to save user settings +(e.g., setting the gpg signing key for commits) by using ‘C-c C-c’ in +the popup buffer. This would dismiss the popup, but save the settings +as the defaults for future popups. + + When switching to Transient menus, this functionality is now +available via ‘C-x C-s’ instead; the ‘C-x’ prefix has other options as +well when using Transient, which will be displayed when it is typed. +See <https://magit.vc/manual/transient/Saving-Values.html#Saving-Values> +for more details. + + +File: magit.info, Node: Debugging Tools, Next: Keystroke Index, Prev: FAQ, Up: Top + +B Debugging Tools +***************** + +Magit and its dependencies provide a few debugging tools, and we +appreciate it very much if you use those tools before reporting an +issue. Please include all relevant output when reporting an issue. + +‘M-x magit-version’ + This command shows the currently used versions of Magit, Git, and + Emacs in the echo area. Non-interactively this just returns the + Magit version. + +‘M-x magit-emacs-Q-command’ + This command shows a debugging shell command in the echo area and + adds it to the kill ring. Paste that command into a shell and run + it. + + This shell command starts ‘emacs’ with only ‘magit’ and its + dependencies loaded. Neither your configuration nor other + installed packages are loaded. This makes it easier to determine + whether some issue lays with Magit or something else. + + If you run Magit from its Git repository, then you should be able + to use ‘make emacs-Q’ instead of the output of this command. + +‘M-x magit-toggle-git-debug’ + This command toggles whether additional git errors are reported. + + Magit basically calls git for one of these two reasons: for + side-effects or to do something with its standard output. + + When git is run for side-effects then its output, including error + messages, go into the process buffer which is shown when using ‘$’. + + When git’s output is consumed in some way, then it would be too + expensive to also insert it into this buffer, but when this option + is non-nil and git returns with a non-zero exit status, then at + least its standard error is inserted into this buffer. + + This is only intended for debugging purposes. Do not enable this + permanently, that would negatively affect performance. Also note + that just because git exits with a non-zero exit status and prints + an error message that usually doesn’t mean that it is an error as + far as Magit is concerned, which is another reason we usually hide + these error messages. Whether some error message is relevant in + the context of some unexpected behavior has to be judged on a case + by case basis. + +‘M-x magit-toggle-verbose-refresh’ + This command toggles whether Magit refreshes buffers verbosely. + Enabling this helps figuring out which sections are bottlenecks. + The additional output can be found in the ‘*Messages*’ buffer. + +‘M-x magit-debug-git-executable’ + This command displays a buffer containing information about the + available and used ‘git’ executable(s), and can be useful when + investigating ‘exec-path’ issues. + + Also see *note Git Executable::. + +‘M-x with-editor-debug’ + This command displays a buffer containing information about the + available and used ‘emacsclient’ executable(s), and can be useful + when investigating why Magit (or rather ‘with-editor’) cannot find + an appropriate ‘emacsclient’ executable. + + Also see *note (with-editor)Debugging::. + +Please also see *note FAQ::. + + +File: magit.info, Node: Keystroke Index, Next: Function and Command Index, Prev: Debugging Tools, Up: Top + +Appendix C Keystroke Index +************************** + + +* Menu: + +* !: Running Git Manually. + (line 13) +* ! !: Running Git Manually. + (line 17) +* ! a: Running Git Manually. + (line 53) +* ! b: Running Git Manually. + (line 56) +* ! g: Running Git Manually. + (line 59) +* ! k: Running Git Manually. + (line 50) +* ! m: Running Git Manually. + (line 62) +* ! p: Running Git Manually. + (line 25) +* ! s: Running Git Manually. + (line 34) +* ! S: Running Git Manually. + (line 38) +* $: Viewing Git Output. (line 17) +* +: Log Buffer. (line 64) +* + <1>: Refreshing Diffs. (line 65) +* -: Log Buffer. (line 67) +* - <1>: Refreshing Diffs. (line 62) +* 0: Refreshing Diffs. (line 68) +* 1: Section Visibility. (line 39) +* 2: Section Visibility. (line 39) +* 3: Section Visibility. (line 39) +* 4: Section Visibility. (line 39) +* 5: Repository List. (line 115) +* :: Running Git Manually. + (line 25) +* =: Log Buffer. (line 59) +* >: Sparse checkouts. (line 17) +* > a: Sparse checkouts. (line 39) +* > d: Sparse checkouts. (line 50) +* > e: Sparse checkouts. (line 21) +* > r: Sparse checkouts. (line 44) +* > s: Sparse checkouts. (line 33) +* ^: Section Movement. (line 28) +* a: Applying. (line 34) +* A: Cherry Picking. (line 9) +* A A: Cherry Picking. (line 17) +* A a: Cherry Picking. (line 23) +* A A <1>: Cherry Picking. (line 85) +* A a <1>: Cherry Picking. (line 91) +* A d: Cherry Picking. (line 51) +* A h: Cherry Picking. (line 40) +* A n: Cherry Picking. (line 62) +* A s: Cherry Picking. (line 72) +* A s <1>: Cherry Picking. (line 88) +* B: Bisecting. (line 9) +* b: Blaming. (line 115) +* b <1>: Branch Commands. (line 13) +* b <2>: Editing Rebase Sequences. + (line 70) +* B B: Bisecting. (line 16) +* B b: Bisecting. (line 32) +* b b: Branch Commands. (line 47) +* b C: Branch Commands. (line 31) +* b c: Branch Commands. (line 63) +* B g: Bisecting. (line 36) +* B k: Bisecting. (line 46) +* b k: Branch Commands. (line 138) +* b l: Branch Commands. (line 69) +* B m: Bisecting. (line 40) +* b m: Branch Commands. (line 149) +* b n: Branch Commands. (line 54) +* B r: Bisecting. (line 51) +* B s: Bisecting. (line 26) +* b s: Branch Commands. (line 91) +* b S: Branch Commands. (line 118) +* b x: Branch Commands. (line 123) +* c: Blaming. (line 141) +* C: Cloning Repository. (line 20) +* c <1>: Initiating a Commit. (line 9) +* c <2>: Editing Rebase Sequences. + (line 59) +* C >: Cloning Repository. (line 38) +* c a: Initiating a Commit. (line 18) +* c A: Initiating a Commit. (line 59) +* C b: Cloning Repository. (line 44) +* C C: Cloning Repository. (line 28) +* c c: Initiating a Commit. (line 14) +* C d: Cloning Repository. (line 55) +* C e: Cloning Repository. (line 61) +* c e: Initiating a Commit. (line 21) +* c f: Initiating a Commit. (line 39) +* c F: Initiating a Commit. (line 46) +* C m: Cloning Repository. (line 48) +* C s: Cloning Repository. (line 32) +* c s: Initiating a Commit. (line 49) +* c S: Initiating a Commit. (line 56) +* c w: Initiating a Commit. (line 30) +* C-<return>: Visiting Files and Blobs from a Diff. + (line 50) +* C-<tab>: Section Visibility. (line 14) +* C-c C-a: Commit Pseudo Headers. + (line 16) +* C-c C-b: Log Buffer. (line 20) +* C-c C-b <1>: Refreshing Diffs. (line 84) +* C-c C-c: Select from Log. (line 21) +* C-c C-c <1>: Editing Commit Messages. + (line 18) +* C-c C-c <2>: Editing Rebase Sequences. + (line 7) +* C-c C-d: Refreshing Diffs. (line 75) +* C-c C-d <1>: Editing Commit Messages. + (line 54) +* C-c C-e: Commands Available in Diffs. + (line 24) +* C-c C-f: Log Buffer. (line 23) +* C-c C-f <1>: Refreshing Diffs. (line 87) +* C-c C-i: Commit Pseudo Headers. + (line 13) +* C-c C-k: Select from Log. (line 26) +* C-c C-k <1>: Editing Commit Messages. + (line 22) +* C-c C-k <2>: Editing Rebase Sequences. + (line 11) +* C-c C-n: Log Buffer. (line 26) +* C-c C-o: Commit Pseudo Headers. + (line 28) +* C-c C-p: Commit Pseudo Headers. + (line 31) +* C-c C-r: Commit Pseudo Headers. + (line 19) +* C-c C-s: Commit Pseudo Headers. + (line 22) +* C-c C-t: Commands Available in Diffs. + (line 15) +* C-c C-t <1>: Commit Pseudo Headers. + (line 25) +* C-c C-w: Using the Revision Stack. + (line 7) +* C-c f: Commands for Buffers Visiting Files. + (line 52) +* C-c f , c: Commands for Buffers Visiting Files. + (line 52) +* C-c f , k: Commands for Buffers Visiting Files. + (line 52) +* C-c f , r: Commands for Buffers Visiting Files. + (line 52) +* C-c f , x: Commands for Buffers Visiting Files. + (line 52) +* C-c f B: Blaming. (line 28) +* C-c f b: Blaming. (line 28) +* C-c f B <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f b <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f B b: Blaming. (line 28) +* C-c f B e: Blaming. (line 28) +* C-c f B f: Blaming. (line 28) +* C-c f B q: Blaming. (line 28) +* C-c f B r: Blaming. (line 28) +* C-c f c: Commands for Buffers Visiting Files. + (line 52) +* C-c f D: Commands for Buffers Visiting Files. + (line 52) +* C-c f d: Commands for Buffers Visiting Files. + (line 52) +* C-c f e: Blaming. (line 28) +* C-c f e <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f f: Blaming. (line 28) +* C-c f f <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f g: Commands for Buffers Visiting Files. + (line 52) +* C-c f G: Commands for Buffers Visiting Files. + (line 52) +* C-c f L: Commands for Buffers Visiting Files. + (line 52) +* C-c f l: Commands for Buffers Visiting Files. + (line 52) +* C-c f M: Commands for Buffers Visiting Files. + (line 52) +* C-c f m: Commands for Buffers Visiting Files. + (line 52) +* C-c f n: Commands for Buffers Visiting Files. + (line 52) +* C-c f p: Commands for Buffers Visiting Files. + (line 52) +* C-c f q: Blaming. (line 28) +* C-c f q <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f r: Blaming. (line 28) +* C-c f r <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f s: Commands for Buffers Visiting Files. + (line 52) +* C-c f s <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f t: Commands for Buffers Visiting Files. + (line 52) +* C-c f u: Commands for Buffers Visiting Files. + (line 52) +* C-c f u <1>: Commands for Buffers Visiting Files. + (line 52) +* C-c f v: Commands for Buffers Visiting Files. + (line 52) +* C-c f V: Commands for Buffers Visiting Files. + (line 52) +* C-c g: Transient Commands. (line 20) +* C-c M-g: Commands for Buffers Visiting Files. + (line 58) +* C-c M-g , c: Commands for Buffers Visiting Files. + (line 86) +* C-c M-g , k: Commands for Buffers Visiting Files. + (line 82) +* C-c M-g , r: Commands for Buffers Visiting Files. + (line 78) +* C-c M-g , x: Commands for Buffers Visiting Files. + (line 74) +* C-c M-g B: Blaming. (line 34) +* C-c M-g b: Blaming. (line 45) +* C-c M-g B <1>: Commands for Buffers Visiting Files. + (line 137) +* C-c M-g B b: Blaming. (line 45) +* C-c M-g B e: Blaming. (line 76) +* C-c M-g B f: Blaming. (line 68) +* C-c M-g B q: Blaming. (line 87) +* C-c M-g B r: Blaming. (line 60) +* C-c M-g c: Commands for Buffers Visiting Files. + (line 176) +* C-c M-g D: Commands for Buffers Visiting Files. + (line 91) +* C-c M-g d: Commands for Buffers Visiting Files. + (line 101) +* C-c M-g e: Blaming. (line 76) +* C-c M-g e <1>: Commands for Buffers Visiting Files. + (line 182) +* C-c M-g f: Blaming. (line 68) +* C-c M-g g: Commands for Buffers Visiting Files. + (line 166) +* C-c M-g G: Commands for Buffers Visiting Files. + (line 172) +* C-c M-g L: Commands for Buffers Visiting Files. + (line 109) +* C-c M-g l: Commands for Buffers Visiting Files. + (line 119) +* C-c M-g M: Commands for Buffers Visiting Files. + (line 132) +* C-c M-g n: Commands for Buffers Visiting Files. + (line 153) +* C-c M-g p: Commands for Buffers Visiting Files. + (line 149) +* C-c M-g q: Blaming. (line 87) +* C-c M-g r: Blaming. (line 60) +* C-c M-g s: Commands for Buffers Visiting Files. + (line 63) +* C-c M-g s <1>: Commands for Buffers Visiting Files. + (line 63) +* C-c M-g t: Commands for Buffers Visiting Files. + (line 129) +* C-c M-g u: Commands for Buffers Visiting Files. + (line 69) +* C-c M-g u <1>: Commands for Buffers Visiting Files. + (line 69) +* C-c M-g v: Commands for Buffers Visiting Files. + (line 156) +* C-c M-g V: Commands for Buffers Visiting Files. + (line 160) +* C-c M-i: Commit Pseudo Headers. + (line 35) +* C-c M-s: Editing Commit Messages. + (line 33) +* C-c TAB: Section Visibility. (line 14) +* C-w: Common Commands. (line 22) +* C-x g: Status Buffer. (line 23) +* C-x M-g: Transient Commands. (line 20) +* C-x u: Editing Rebase Sequences. + (line 77) +* d: Diffing. (line 22) +* D: Refreshing Diffs. (line 16) +* d c: Diffing. (line 63) +* d d: Diffing. (line 27) +* D f: Refreshing Diffs. (line 45) +* D F: Refreshing Diffs. (line 49) +* D g: Refreshing Diffs. (line 21) +* d p: Diffing. (line 56) +* d r: Diffing. (line 30) +* D r: Refreshing Diffs. (line 41) +* d s: Diffing. (line 48) +* D s: Refreshing Diffs. (line 25) +* d t: Diffing. (line 67) +* D t: Refreshing Diffs. (line 38) +* d u: Diffing. (line 53) +* d w: Diffing. (line 43) +* D w: Refreshing Diffs. (line 31) +* DEL: Log Buffer. (line 50) +* DEL <1>: Commands Available in Diffs. + (line 56) +* DEL <2>: Blaming. (line 103) +* DEL <3>: Editing Rebase Sequences. + (line 25) +* e: Ediffing. (line 10) +* E: Ediffing. (line 21) +* e <1>: Editing Rebase Sequences. + (line 46) +* E c: Ediffing. (line 100) +* E i: Ediffing. (line 94) +* E m: Ediffing. (line 33) +* E M: Ediffing. (line 48) +* E r: Ediffing. (line 25) +* E s: Ediffing. (line 87) +* E t: Ediffing. (line 79) +* E u: Ediffing. (line 91) +* E w: Ediffing. (line 97) +* E z: Ediffing. (line 103) +* f: Repository List. (line 111) +* f <1>: Editing Rebase Sequences. + (line 52) +* f <2>: Fetching. (line 10) +* F: Pulling. (line 10) +* f a: Fetching. (line 45) +* f C: Branch Commands. (line 31) +* F C: Branch Commands. (line 31) +* f e: Fetching. (line 34) +* F e: Pulling. (line 28) +* f m: Fetching. (line 48) +* f o: Fetching. (line 37) +* f p: Fetching. (line 15) +* F p: Pulling. (line 14) +* f r: Fetching. (line 41) +* f u: Fetching. (line 22) +* F u: Pulling. (line 21) +* g: Automatic Refreshing of Magit Buffers. + (line 26) +* G: Automatic Refreshing of Magit Buffers. + (line 34) +* H: Section Types and Values. + (line 14) +* I: Creating Repository. (line 7) +* j: Log Buffer. (line 31) +* j <1>: Commands Available in Diffs. + (line 43) +* k: Viewing Git Output. (line 24) +* k <1>: Applying. (line 40) +* k <2>: Editing Rebase Sequences. + (line 56) +* k <3>: Stashing. (line 118) +* l: Logging. (line 30) +* L: Refreshing Logs. (line 12) +* L <1>: Log Buffer. (line 7) +* L <2>: Log Margin. (line 52) +* l <1>: Editing Rebase Sequences. + (line 94) +* l a: Logging. (line 61) +* l b: Logging. (line 58) +* L d: Log Margin. (line 66) +* L g: Refreshing Logs. (line 17) +* l h: Logging. (line 40) +* l H: Reflog. (line 18) +* l l: Logging. (line 35) +* l L: Logging. (line 55) +* L L: Refreshing Logs. (line 34) +* L L <1>: Log Margin. (line 60) +* L l: Log Margin. (line 63) +* l o: Logging. (line 49) +* l O: Reflog. (line 15) +* l r: Reflog. (line 12) +* L s: Refreshing Logs. (line 21) +* l u: Logging. (line 43) +* L w: Refreshing Logs. (line 27) +* m: Repository List. (line 105) +* m <1>: Merging. (line 10) +* M: Remote Commands. (line 14) +* m a: Merging. (line 42) +* m a <1>: Merging. (line 91) +* M a: Remote Commands. (line 48) +* M C: Remote Commands. (line 32) +* m e: Merging. (line 30) +* m i: Merging. (line 54) +* M k: Remote Commands. (line 60) +* m m: Merging. (line 18) +* m m <1>: Merging. (line 86) +* m n: Merging. (line 36) +* m p: Merging. (line 75) +* M p: Remote Commands. (line 63) +* M P: Remote Commands. (line 67) +* M r: Remote Commands. (line 52) +* m s: Merging. (line 67) +* M u: Remote Commands. (line 56) +* M-1: Section Visibility. (line 45) +* M-2: Section Visibility. (line 45) +* M-3: Section Visibility. (line 45) +* M-4: Section Visibility. (line 45) +* M-<tab>: Section Visibility. (line 29) +* M-n: Section Movement. (line 24) +* M-n <1>: Editing Commit Messages. + (line 41) +* M-n <2>: Editing Rebase Sequences. + (line 40) +* M-p: Section Movement. (line 19) +* M-p <1>: Editing Commit Messages. + (line 36) +* M-p <2>: Editing Rebase Sequences. + (line 37) +* M-w: Blaming. (line 134) +* M-w <1>: Common Commands. (line 39) +* MM: Editing Rebase Sequences. + (line 102) +* Mt: Editing Rebase Sequences. + (line 108) +* n: Section Movement. (line 16) +* n <1>: Blaming. (line 118) +* N: Blaming. (line 121) +* n <2>: Editing Rebase Sequences. + (line 34) +* n <3>: Minor Mode for Buffers Visiting Blobs. + (line 16) +* o: Submodule Transient. (line 7) +* O: Subtree. (line 9) +* o a: Submodule Transient. (line 20) +* o d: Submodule Transient. (line 45) +* O e: Subtree. (line 37) +* O e p: Subtree. (line 48) +* O e s: Subtree. (line 52) +* o f: Submodule Transient. (line 51) +* O i: Subtree. (line 13) +* O i a: Subtree. (line 24) +* O i c: Subtree. (line 28) +* O i f: Subtree. (line 34) +* O i m: Subtree. (line 31) +* o l: Submodule Transient. (line 48) +* o p: Submodule Transient. (line 32) +* o r: Submodule Transient. (line 26) +* o s: Submodule Transient. (line 40) +* o u: Submodule Transient. (line 36) +* p: Section Movement. (line 11) +* p <1>: Blaming. (line 124) +* P: Blaming. (line 127) +* p <2>: Editing Rebase Sequences. + (line 31) +* P <1>: Pushing. (line 10) +* p <3>: Minor Mode for Buffers Visiting Blobs. + (line 13) +* P C: Branch Commands. (line 31) +* P e: Pushing. (line 29) +* P m: Pushing. (line 45) +* P o: Pushing. (line 33) +* P p: Pushing. (line 15) +* P r: Pushing. (line 37) +* P t: Pushing. (line 52) +* P T: Pushing. (line 59) +* P u: Pushing. (line 22) +* q: Quitting Windows. (line 7) +* q <1>: Log Buffer. (line 14) +* q <2>: Blaming. (line 130) +* q <3>: Minor Mode for Buffers Visiting Blobs. + (line 19) +* r: Rebasing. (line 10) +* r <1>: Editing Rebase Sequences. + (line 43) +* r a: Rebasing. (line 111) +* r e: Rebasing. (line 42) +* r e <1>: Rebasing. (line 107) +* r f: Rebasing. (line 79) +* r i: Rebasing. (line 76) +* r k: Rebasing. (line 91) +* r m: Rebasing. (line 83) +* r p: Rebasing. (line 28) +* r r: Rebasing. (line 97) +* r s: Rebasing. (line 47) +* r s <1>: Rebasing. (line 103) +* r u: Rebasing. (line 35) +* r w: Rebasing. (line 87) +* RET: Repository List. (line 102) +* RET <1>: References Buffer. (line 159) +* RET <2>: Visiting Files and Blobs from a Diff. + (line 9) +* RET <3>: Blaming. (line 91) +* RET <4>: Editing Rebase Sequences. + (line 15) +* s: Staging and Unstaging. + (line 29) +* S: Staging and Unstaging. + (line 36) +* s <1>: Editing Rebase Sequences. + (line 49) +* S-<tab>: Section Visibility. (line 33) +* SPC: Log Buffer. (line 41) +* SPC <1>: Commands Available in Diffs. + (line 53) +* SPC <2>: Blaming. (line 94) +* SPC <3>: Editing Rebase Sequences. + (line 19) +* t: Editing Rebase Sequences. + (line 97) +* t <1>: Tagging. (line 9) +* T: Notes. (line 9) +* T a: Notes. (line 47) +* T c: Notes. (line 43) +* t k: Tagging. (line 37) +* T m: Notes. (line 35) +* t p: Tagging. (line 43) +* T p: Notes. (line 28) +* t r: Tagging. (line 18) +* T r: Notes. (line 21) +* t t: Tagging. (line 14) +* T T: Notes. (line 14) +* TAB: Section Visibility. (line 10) +* u: Repository List. (line 108) +* u <1>: Staging and Unstaging. + (line 42) +* U: Staging and Unstaging. + (line 50) +* v: Applying. (line 47) +* V: Reverting. (line 7) +* V a: Reverting. (line 35) +* V s: Reverting. (line 32) +* V V: Reverting. (line 15) +* V v: Reverting. (line 20) +* V V <1>: Reverting. (line 29) +* W: Plain Patches. (line 7) +* w: Maildir Patches. (line 9) +* w a: Plain Patches. (line 20) +* w a <1>: Maildir Patches. (line 23) +* w a <2>: Maildir Patches. (line 38) +* W c: Plain Patches. (line 12) +* w m: Maildir Patches. (line 20) +* W s: Plain Patches. (line 26) +* w s: Maildir Patches. (line 34) +* w w: Maildir Patches. (line 14) +* w w <1>: Maildir Patches. (line 31) +* x: Editing Rebase Sequences. + (line 62) +* x <1>: Resetting. (line 9) +* X f: Resetting. (line 44) +* X h: Resetting. (line 24) +* X i: Resetting. (line 33) +* X k: Resetting. (line 28) +* X m: Resetting. (line 15) +* X s: Resetting. (line 19) +* X w: Resetting. (line 39) +* X w <1>: Wip Modes. (line 64) +* Y: Cherries. (line 18) +* y: References Buffer. (line 7) +* y <1>: Editing Rebase Sequences. + (line 74) +* y c: References Buffer. (line 25) +* y o: References Buffer. (line 30) +* y r: References Buffer. (line 34) +* y y: References Buffer. (line 21) +* z: Stashing. (line 9) +* Z: Worktree. (line 9) +* z a: Stashing. (line 52) +* z b: Stashing. (line 105) +* z B: Stashing. (line 110) +* Z b: Worktree. (line 13) +* Z c: Worktree. (line 16) +* z f: Stashing. (line 115) +* Z g: Worktree. (line 26) +* z i: Stashing. (line 20) +* z I: Stashing. (line 42) +* z k: Stashing. (line 98) +* Z k: Worktree. (line 22) +* z l: Stashing. (line 121) +* Z m: Worktree. (line 19) +* z p: Stashing. (line 74) +* z v: Stashing. (line 102) +* z w: Stashing. (line 24) +* z W: Stashing. (line 46) +* z x: Stashing. (line 30) +* z z: Stashing. (line 14) +* z Z: Stashing. (line 36) + + +File: magit.info, Node: Function and Command Index, Next: Variable Index, Prev: Keystroke Index, Up: Top + +Appendix D Function and Command Index +************************************* + + +* Menu: + +* bug-reference-mode: Commit Mode and Hooks. + (line 48) +* forward-line: Editing Rebase Sequences. + (line 34) +* git-commit-ack: Commit Pseudo Headers. + (line 16) +* git-commit-cc: Commit Pseudo Headers. + (line 28) +* git-commit-check-style-conventions: Commit Message Conventions. + (line 33) +* git-commit-insert-pseudo-header: Commit Pseudo Headers. + (line 13) +* git-commit-next-message: Editing Commit Messages. + (line 41) +* git-commit-prev-message: Editing Commit Messages. + (line 36) +* git-commit-propertize-diff: Commit Mode and Hooks. + (line 40) +* git-commit-reported: Commit Pseudo Headers. + (line 31) +* git-commit-review: Commit Pseudo Headers. + (line 19) +* git-commit-save-message: Editing Commit Messages. + (line 33) +* git-commit-save-message <1>: Commit Mode and Hooks. + (line 26) +* git-commit-setup-changelog-support: Commit Mode and Hooks. + (line 29) +* git-commit-signoff: Commit Pseudo Headers. + (line 22) +* git-commit-suggested: Commit Pseudo Headers. + (line 35) +* git-commit-test: Commit Pseudo Headers. + (line 25) +* git-commit-turn-on-auto-fill: Commit Mode and Hooks. + (line 33) +* git-commit-turn-on-flyspell: Commit Mode and Hooks. + (line 36) +* git-rebase-backward-line: Editing Rebase Sequences. + (line 31) +* git-rebase-break: Editing Rebase Sequences. + (line 70) +* git-rebase-edit: Editing Rebase Sequences. + (line 46) +* git-rebase-exec: Editing Rebase Sequences. + (line 62) +* git-rebase-fixup: Editing Rebase Sequences. + (line 52) +* git-rebase-insert: Editing Rebase Sequences. + (line 74) +* git-rebase-kill-line: Editing Rebase Sequences. + (line 56) +* git-rebase-label: Editing Rebase Sequences. + (line 94) +* git-rebase-merge: Editing Rebase Sequences. + (line 102) +* git-rebase-merge-toggle-editmsg: Editing Rebase Sequences. + (line 108) +* git-rebase-move-line-down: Editing Rebase Sequences. + (line 40) +* git-rebase-move-line-up: Editing Rebase Sequences. + (line 37) +* git-rebase-pick: Editing Rebase Sequences. + (line 59) +* git-rebase-reset: Editing Rebase Sequences. + (line 97) +* git-rebase-reword: Editing Rebase Sequences. + (line 43) +* git-rebase-show-commit: Editing Rebase Sequences. + (line 15) +* git-rebase-show-or-scroll-down: Editing Rebase Sequences. + (line 25) +* git-rebase-show-or-scroll-up: Editing Rebase Sequences. + (line 19) +* git-rebase-squash: Editing Rebase Sequences. + (line 49) +* git-rebase-undo: Editing Rebase Sequences. + (line 77) +* ido-enter-magit-status: Status Buffer. (line 96) +* magit-add-section-hook: Section Hooks. (line 20) +* magit-after-save-refresh-status: Automatic Refreshing of Magit Buffers. + (line 55) +* magit-am: Maildir Patches. (line 9) +* magit-am-abort: Maildir Patches. (line 38) +* magit-am-apply-maildir: Maildir Patches. (line 20) +* magit-am-apply-patches: Maildir Patches. (line 14) +* magit-am-continue: Maildir Patches. (line 31) +* magit-am-skip: Maildir Patches. (line 34) +* magit-apply: Applying. (line 34) +* magit-bisect: Bisecting. (line 9) +* magit-bisect-bad: Bisecting. (line 32) +* magit-bisect-good: Bisecting. (line 36) +* magit-bisect-mark: Bisecting. (line 40) +* magit-bisect-reset: Bisecting. (line 51) +* magit-bisect-run: Bisecting. (line 26) +* magit-bisect-skip: Bisecting. (line 46) +* magit-bisect-start: Bisecting. (line 16) +* magit-blame: Blaming. (line 28) +* magit-blame <1>: Blaming. (line 34) +* magit-blame <2>: Blaming. (line 115) +* magit-blame <3>: Commands for Buffers Visiting Files. + (line 52) +* magit-blame <4>: Commands for Buffers Visiting Files. + (line 137) +* magit-blame-addition: Blaming. (line 28) +* magit-blame-addition <1>: Blaming. (line 45) +* magit-blame-additions: Commands for Buffers Visiting Files. + (line 52) +* magit-blame-copy-hash: Blaming. (line 134) +* magit-blame-cycle-style: Blaming. (line 141) +* magit-blame-echo: Blaming. (line 28) +* magit-blame-echo <1>: Blaming. (line 76) +* magit-blame-echo <2>: Commands for Buffers Visiting Files. + (line 52) +* magit-blame-next-chunk: Blaming. (line 118) +* magit-blame-next-chunk-same-commit: Blaming. (line 121) +* magit-blame-previous-chunk: Blaming. (line 124) +* magit-blame-previous-chunk-same-commit: Blaming. (line 127) +* magit-blame-quit: Blaming. (line 28) +* magit-blame-quit <1>: Blaming. (line 87) +* magit-blame-quit <2>: Blaming. (line 130) +* magit-blame-quit <3>: Commands for Buffers Visiting Files. + (line 52) +* magit-blame-removal: Blaming. (line 28) +* magit-blame-removal <1>: Blaming. (line 60) +* magit-blame-removal <2>: Commands for Buffers Visiting Files. + (line 52) +* magit-blame-reverse: Blaming. (line 28) +* magit-blame-reverse <1>: Blaming. (line 68) +* magit-blame-reverse <2>: Commands for Buffers Visiting Files. + (line 52) +* magit-blob-next: Commands for Buffers Visiting Files. + (line 52) +* magit-blob-next <1>: Commands for Buffers Visiting Files. + (line 153) +* magit-blob-next <2>: Minor Mode for Buffers Visiting Blobs. + (line 16) +* magit-blob-previous: Commands for Buffers Visiting Files. + (line 52) +* magit-blob-previous <1>: Commands for Buffers Visiting Files. + (line 149) +* magit-blob-previous <2>: Minor Mode for Buffers Visiting Blobs. + (line 13) +* magit-blob-visit-file: Commands for Buffers Visiting Files. + (line 52) +* magit-blob-visit-file <1>: Commands for Buffers Visiting Files. + (line 160) +* magit-branch: Branch Commands. (line 13) +* magit-branch-and-checkout: Branch Commands. (line 63) +* magit-branch-checkout: Branch Commands. (line 69) +* magit-branch-configure: Branch Commands. (line 31) +* magit-branch-create: Branch Commands. (line 54) +* magit-branch-delete: Branch Commands. (line 138) +* magit-branch-or-checkout: Branch Commands. (line 257) +* magit-branch-orphan: Branch Commands. (line 253) +* magit-branch-rename: Branch Commands. (line 149) +* magit-branch-reset: Branch Commands. (line 123) +* magit-branch-shelve: Auxiliary Branch Commands. + (line 9) +* magit-branch-spinoff: Branch Commands. (line 91) +* magit-branch-spinout: Branch Commands. (line 118) +* magit-branch-unshelve: Auxiliary Branch Commands. + (line 19) +* magit-builtin-completing-read: Support for Completion Frameworks. + (line 41) +* magit-bundle: Bundle. (line 8) +* magit-call-git: Calling Git for Effect. + (line 28) +* magit-call-process: Calling Git for Effect. + (line 31) +* magit-cancel-section: Creating Sections. (line 69) +* magit-checkout: Branch Commands. (line 47) +* magit-cherry: Cherries. (line 18) +* magit-cherry-apply: Cherry Picking. (line 23) +* magit-cherry-copy: Cherry Picking. (line 17) +* magit-cherry-donate: Cherry Picking. (line 51) +* magit-cherry-harvest: Cherry Picking. (line 40) +* magit-cherry-pick: Cherry Picking. (line 9) +* magit-cherry-spinoff: Cherry Picking. (line 72) +* magit-cherry-spinout: Cherry Picking. (line 62) +* magit-clone: Cloning Repository. (line 20) +* magit-clone-bare: Cloning Repository. (line 44) +* magit-clone-mirror: Cloning Repository. (line 48) +* magit-clone-regular: Cloning Repository. (line 28) +* magit-clone-shallow: Cloning Repository. (line 32) +* magit-clone-shallow-exclude: Cloning Repository. (line 61) +* magit-clone-shallow-since: Cloning Repository. (line 55) +* magit-clone-sparse: Cloning Repository. (line 38) +* magit-commit: Initiating a Commit. (line 9) +* magit-commit <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-commit <2>: Commands for Buffers Visiting Files. + (line 176) +* magit-commit-amend: Initiating a Commit. (line 18) +* magit-commit-augment: Initiating a Commit. (line 59) +* magit-commit-create: Initiating a Commit. (line 14) +* magit-commit-extend: Initiating a Commit. (line 21) +* magit-commit-fixup: Initiating a Commit. (line 39) +* magit-commit-instant-fixup: Initiating a Commit. (line 46) +* magit-commit-instant-squash: Initiating a Commit. (line 56) +* magit-commit-reword: Initiating a Commit. (line 30) +* magit-commit-squash: Initiating a Commit. (line 49) +* magit-completing-read: Support for Completion Frameworks. + (line 57) +* magit-copy-buffer-revision: Common Commands. (line 39) +* magit-copy-section-value: Common Commands. (line 22) +* magit-current-section: Section Selection. (line 6) +* magit-cycle-margin-style: Log Margin. (line 63) +* magit-debug-git-executable: Git Executable. (line 55) +* magit-debug-git-executable <1>: Debugging Tools. (line 57) +* magit-define-section-jumper: Creating Sections. (line 74) +* magit-describe-section: Section Types and Values. + (line 14) +* magit-describe-section-briefly: Section Types and Values. + (line 17) +* magit-describe-section-briefly <1>: Matching Sections. (line 7) +* magit-diff: Diffing. (line 22) +* magit-diff <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-diff <2>: Commands for Buffers Visiting Files. + (line 91) +* magit-diff-buffer-file: Commands for Buffers Visiting Files. + (line 52) +* magit-diff-buffer-file <1>: Commands for Buffers Visiting Files. + (line 101) +* magit-diff-default-context: Refreshing Diffs. (line 68) +* magit-diff-dwim: Diffing. (line 27) +* magit-diff-edit-hunk-commit: Commands Available in Diffs. + (line 24) +* magit-diff-flip-revs: Refreshing Diffs. (line 45) +* magit-diff-less-context: Refreshing Diffs. (line 62) +* magit-diff-more-context: Refreshing Diffs. (line 65) +* magit-diff-paths: Diffing. (line 56) +* magit-diff-range: Diffing. (line 30) +* magit-diff-refresh: Refreshing Diffs. (line 16) +* magit-diff-refresh <1>: Refreshing Diffs. (line 21) +* magit-diff-save-default-arguments: Refreshing Diffs. (line 31) +* magit-diff-scope: Matching Sections. (line 110) +* magit-diff-set-default-arguments: Refreshing Diffs. (line 25) +* magit-diff-show-or-scroll-down: Log Buffer. (line 50) +* magit-diff-show-or-scroll-down <1>: Blaming. (line 103) +* magit-diff-show-or-scroll-up: Log Buffer. (line 41) +* magit-diff-show-or-scroll-up <1>: Blaming. (line 94) +* magit-diff-staged: Diffing. (line 48) +* magit-diff-switch-range-type: Refreshing Diffs. (line 41) +* magit-diff-toggle-file-filter: Refreshing Diffs. (line 49) +* magit-diff-toggle-refine-hunk: Refreshing Diffs. (line 38) +* magit-diff-trace-definition: Commands Available in Diffs. + (line 15) +* magit-diff-type: Matching Sections. (line 88) +* magit-diff-unstaged: Diffing. (line 53) +* magit-diff-visit-file: Visiting Files and Blobs from a Diff. + (line 9) +* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff. + (line 71) +* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff. + (line 70) +* magit-diff-visit-file-worktree: Visiting Files and Blobs from a Diff. + (line 50) +* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff. + (line 73) +* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff. + (line 72) +* magit-diff-while-committing: Refreshing Diffs. (line 75) +* magit-diff-while-committing <1>: Editing Commit Messages. + (line 54) +* magit-diff-working-tree: Diffing. (line 43) +* magit-disable-section-inserter: Per-Repository Configuration. + (line 31) +* magit-discard: Applying. (line 40) +* magit-dispatch: Transient Commands. (line 20) +* magit-display-buffer: Switching Buffers. (line 6) +* magit-display-buffer-fullcolumn-most-v1: Switching Buffers. (line 68) +* magit-display-buffer-fullframe-status-topleft-v1: Switching Buffers. + (line 59) +* magit-display-buffer-fullframe-status-v1: Switching Buffers. + (line 54) +* magit-display-buffer-same-window-except-diff-v1: Switching Buffers. + (line 49) +* magit-display-buffer-traditional: Switching Buffers. (line 42) +* magit-display-repository-buffer: Common Commands. (line 9) +* magit-display-repository-buffer <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-display-repository-buffer <2>: Commands for Buffers Visiting Files. + (line 172) +* magit-ediff: Ediffing. (line 21) +* magit-ediff-compare: Ediffing. (line 25) +* magit-ediff-dwim: Ediffing. (line 10) +* magit-ediff-resolve-all: Ediffing. (line 48) +* magit-ediff-resolve-rest: Ediffing. (line 33) +* magit-ediff-show-commit: Ediffing. (line 100) +* magit-ediff-show-staged: Ediffing. (line 94) +* magit-ediff-show-stash: Ediffing. (line 103) +* magit-ediff-show-unstaged: Ediffing. (line 91) +* magit-ediff-show-working-tree: Ediffing. (line 97) +* magit-ediff-stage: Ediffing. (line 87) +* magit-edit-line-commit: Commands for Buffers Visiting Files. + (line 52) +* magit-edit-line-commit <1>: Commands for Buffers Visiting Files. + (line 182) +* magit-emacs-Q-command: Debugging Tools. (line 16) +* magit-fetch: Fetching. (line 10) +* magit-fetch-all: Fetching. (line 45) +* magit-fetch-branch: Fetching. (line 37) +* magit-fetch-from-pushremote: Fetching. (line 15) +* magit-fetch-from-upstream: Fetching. (line 22) +* magit-fetch-modules: Fetching. (line 48) +* magit-fetch-modules <1>: Submodule Transient. (line 51) +* magit-fetch-other: Fetching. (line 34) +* magit-fetch-refspec: Fetching. (line 41) +* magit-file-checkout: Resetting. (line 44) +* magit-file-checkout <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-file-checkout <2>: Commands for Buffers Visiting Files. + (line 86) +* magit-file-delete: Commands for Buffers Visiting Files. + (line 52) +* magit-file-delete <1>: Commands for Buffers Visiting Files. + (line 82) +* magit-file-dispatch: Commands for Buffers Visiting Files. + (line 52) +* magit-file-dispatch <1>: Commands for Buffers Visiting Files. + (line 58) +* magit-file-rename: Commands for Buffers Visiting Files. + (line 52) +* magit-file-rename <1>: Commands for Buffers Visiting Files. + (line 78) +* magit-file-untrack: Commands for Buffers Visiting Files. + (line 52) +* magit-file-untrack <1>: Commands for Buffers Visiting Files. + (line 74) +* magit-find-file: General-Purpose Visit Commands. + (line 9) +* magit-find-file <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-find-file <2>: Commands for Buffers Visiting Files. + (line 156) +* magit-find-file-other-frame: General-Purpose Visit Commands. + (line 19) +* magit-find-file-other-window: General-Purpose Visit Commands. + (line 14) +* magit-generate-buffer-name-default-function: Naming Buffers. + (line 16) +* magit-get-section: Matching Sections. (line 14) +* magit-git: Calling Git for Effect. + (line 46) +* magit-git-command: Running Git Manually. + (line 25) +* magit-git-command-topdir: Running Git Manually. + (line 17) +* magit-git-exit-code: Getting a Value from Git. + (line 10) +* magit-git-failure: Getting a Value from Git. + (line 17) +* magit-git-false: Getting a Value from Git. + (line 25) +* magit-git-insert: Getting a Value from Git. + (line 29) +* magit-git-items: Getting a Value from Git. + (line 41) +* magit-git-lines: Getting a Value from Git. + (line 37) +* magit-git-mergetool: Running Git Manually. + (line 62) +* magit-git-mergetool <1>: Ediffing. (line 79) +* magit-git-str: Getting a Value from Git. + (line 75) +* magit-git-string: Getting a Value from Git. + (line 32) +* magit-git-success: Getting a Value from Git. + (line 13) +* magit-git-true: Getting a Value from Git. + (line 21) +* magit-git-wash: Calling Git for Effect. + (line 50) +* magit-go-backward: Log Buffer. (line 20) +* magit-go-backward <1>: Refreshing Diffs. (line 84) +* magit-go-forward: Log Buffer. (line 23) +* magit-go-forward <1>: Refreshing Diffs. (line 87) +* magit-hunk-set-window-start: Section Movement. (line 45) +* magit-ido-completing-read: Support for Completion Frameworks. + (line 46) +* magit-init: Creating Repository. (line 7) +* magit-insert-am-sequence: Status Sections. (line 25) +* magit-insert-assumed-unchanged-files: Status Sections. (line 98) +* magit-insert-bisect-log: Status Sections. (line 39) +* magit-insert-bisect-output: Status Sections. (line 33) +* magit-insert-bisect-rest: Status Sections. (line 36) +* magit-insert-diff-filter-header: Status Header Sections. + (line 35) +* magit-insert-error-header: Status Header Sections. + (line 26) +* magit-insert-head-branch-header: Status Header Sections. + (line 38) +* magit-insert-heading: Creating Sections. (line 41) +* magit-insert-ignored-files: Status Sections. (line 83) +* magit-insert-local-branches: References Sections. (line 16) +* magit-insert-merge-log: Status Sections. (line 17) +* magit-insert-modules: Status Module Sections. + (line 12) +* magit-insert-modules-overview: Status Module Sections. + (line 30) +* magit-insert-modules-unpulled-from-pushremote: Status Module Sections. + (line 45) +* magit-insert-modules-unpulled-from-upstream: Status Module Sections. + (line 40) +* magit-insert-modules-unpushed-to-pushremote: Status Module Sections. + (line 55) +* magit-insert-modules-unpushed-to-upstream: Status Module Sections. + (line 50) +* magit-insert-push-branch-header: Status Header Sections. + (line 45) +* magit-insert-rebase-sequence: Status Sections. (line 21) +* magit-insert-recent-commits: Status Sections. (line 110) +* magit-insert-remote-branches: References Sections. (line 19) +* magit-insert-remote-header: Status Header Sections. + (line 58) +* magit-insert-repo-header: Status Header Sections. + (line 55) +* magit-insert-section: Creating Sections. (line 6) +* magit-insert-sequencer-sequence: Status Sections. (line 29) +* magit-insert-skip-worktree-files: Status Sections. (line 92) +* magit-insert-staged-changes: Status Sections. (line 53) +* magit-insert-stashes: Status Sections. (line 56) +* magit-insert-status-headers: Status Header Sections. + (line 12) +* magit-insert-tags: References Sections. (line 22) +* magit-insert-tags-header: Status Header Sections. + (line 49) +* magit-insert-tracked-files: Status Sections. (line 80) +* magit-insert-unpulled-cherries: Status Sections. (line 119) +* magit-insert-unpulled-from-pushremote: Status Sections. (line 66) +* magit-insert-unpulled-from-upstream: Status Sections. (line 62) +* magit-insert-unpulled-or-recent-commits: Status Sections. (line 104) +* magit-insert-unpushed-cherries: Status Sections. (line 125) +* magit-insert-unpushed-to-pushremote: Status Sections. (line 74) +* magit-insert-unpushed-to-upstream: Status Sections. (line 70) +* magit-insert-unstaged-changes: Status Sections. (line 50) +* magit-insert-untracked-files: Status Sections. (line 42) +* magit-insert-upstream-branch-header: Status Header Sections. + (line 41) +* magit-insert-user-header: Status Header Sections. + (line 65) +* magit-jump-to-diffstat-or-diff: Commands Available in Diffs. + (line 43) +* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs. + (line 19) +* magit-list-repositories: Repository List. (line 6) +* magit-list-submodules: Listing Submodules. (line 13) +* magit-list-submodules <1>: Submodule Transient. (line 48) +* magit-log: Logging. (line 30) +* magit-log <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-log <2>: Commands for Buffers Visiting Files. + (line 109) +* magit-log-all: Logging. (line 61) +* magit-log-all-branches: Logging. (line 58) +* magit-log-branches: Logging. (line 55) +* magit-log-buffer-file: Commands for Buffers Visiting Files. + (line 52) +* magit-log-buffer-file <1>: Commands for Buffers Visiting Files. + (line 119) +* magit-log-bury-buffer: Log Buffer. (line 14) +* magit-log-current: Logging. (line 35) +* magit-log-double-commit-limit: Log Buffer. (line 64) +* magit-log-half-commit-limit: Log Buffer. (line 67) +* magit-log-head: Logging. (line 40) +* magit-log-maybe-show-more-commits: Section Movement. (line 58) +* magit-log-maybe-update-blob-buffer: Section Movement. (line 72) +* magit-log-maybe-update-revision-buffer: Section Movement. (line 65) +* magit-log-merged: Commands for Buffers Visiting Files. + (line 52) +* magit-log-merged <1>: Commands for Buffers Visiting Files. + (line 132) +* magit-log-move-to-parent: Log Buffer. (line 26) +* magit-log-move-to-revision: Log Buffer. (line 31) +* magit-log-other: Logging. (line 49) +* magit-log-refresh: Refreshing Logs. (line 12) +* magit-log-refresh <1>: Refreshing Logs. (line 17) +* magit-log-refresh <2>: Log Buffer. (line 7) +* magit-log-related: Logging. (line 43) +* magit-log-save-default-arguments: Refreshing Logs. (line 27) +* magit-log-select-pick: Select from Log. (line 21) +* magit-log-select-quit: Select from Log. (line 26) +* magit-log-set-default-arguments: Refreshing Logs. (line 21) +* magit-log-toggle-commit-limit: Log Buffer. (line 59) +* magit-log-trace-definition: Commands for Buffers Visiting Files. + (line 52) +* magit-log-trace-definition <1>: Commands for Buffers Visiting Files. + (line 129) +* magit-margin-settings: Log Margin. (line 52) +* magit-maybe-set-dedicated: Switching Buffers. (line 89) +* magit-merge: Merging. (line 10) +* magit-merge <1>: Merging. (line 86) +* magit-merge-abort: Merging. (line 91) +* magit-merge-absorb: Merging. (line 42) +* magit-merge-editmsg: Merging. (line 30) +* magit-merge-into: Merging. (line 54) +* magit-merge-nocommit: Merging. (line 36) +* magit-merge-plain: Merging. (line 18) +* magit-merge-preview: Merging. (line 75) +* magit-merge-squash: Merging. (line 67) +* magit-mode-bury-buffer: Quitting Windows. (line 7) +* magit-mode-display-buffer: Refreshing Buffers. (line 32) +* magit-mode-quit-window: Quitting Windows. (line 34) +* magit-mode-setup: Refreshing Buffers. (line 17) +* magit-notes: Notes. (line 9) +* magit-notes-edit: Notes. (line 14) +* magit-notes-merge: Notes. (line 35) +* magit-notes-merge-abort: Notes. (line 47) +* magit-notes-merge-commit: Notes. (line 43) +* magit-notes-prune: Notes. (line 28) +* magit-notes-remove: Notes. (line 21) +* magit-patch: Plain Patches. (line 7) +* magit-patch-apply: Plain Patches. (line 20) +* magit-patch-apply <1>: Maildir Patches. (line 23) +* magit-patch-create: Plain Patches. (line 12) +* magit-patch-save: Plain Patches. (line 26) +* magit-pop-revision-stack: Using the Revision Stack. + (line 7) +* magit-process: Viewing Git Output. (line 17) +* magit-process-file: Getting a Value from Git. + (line 57) +* magit-process-git: Getting a Value from Git. + (line 50) +* magit-process-kill: Viewing Git Output. (line 24) +* magit-pull: Pulling. (line 10) +* magit-pull-branch: Pulling. (line 28) +* magit-pull-from-pushremote: Pulling. (line 14) +* magit-pull-from-upstream: Pulling. (line 21) +* magit-push: Pushing. (line 10) +* magit-push-current: Pushing. (line 29) +* magit-push-current-to-pushremote: Pushing. (line 15) +* magit-push-current-to-upstream: Pushing. (line 22) +* magit-push-implicitly: Pushing. (line 74) +* magit-push-matching: Pushing. (line 45) +* magit-push-other: Pushing. (line 33) +* magit-push-refspecs: Pushing. (line 37) +* magit-push-tag: Pushing. (line 59) +* magit-push-tags: Pushing. (line 52) +* magit-push-to-remote: Pushing. (line 91) +* magit-rebase: Rebasing. (line 10) +* magit-rebase-abort: Rebasing. (line 111) +* magit-rebase-autosquash: Rebasing. (line 79) +* magit-rebase-branch: Rebasing. (line 42) +* magit-rebase-continue: Rebasing. (line 97) +* magit-rebase-edit: Rebasing. (line 107) +* magit-rebase-edit-commit: Rebasing. (line 83) +* magit-rebase-interactive: Rebasing. (line 76) +* magit-rebase-onto-pushremote: Rebasing. (line 28) +* magit-rebase-onto-upstream: Rebasing. (line 35) +* magit-rebase-remove-commit: Rebasing. (line 91) +* magit-rebase-reword-commit: Rebasing. (line 87) +* magit-rebase-skip: Rebasing. (line 103) +* magit-rebase-subset: Rebasing. (line 47) +* magit-reflog-current: Reflog. (line 12) +* magit-reflog-head: Reflog. (line 18) +* magit-reflog-other: Reflog. (line 15) +* magit-refresh: Automatic Refreshing of Magit Buffers. + (line 26) +* magit-refresh-all: Automatic Refreshing of Magit Buffers. + (line 34) +* magit-refs-set-show-commit-count: References Buffer. (line 34) +* magit-region-sections: Section Selection. (line 9) +* magit-region-values: Section Selection. (line 35) +* magit-remote: Remote Commands. (line 14) +* magit-remote-add: Remote Commands. (line 48) +* magit-remote-configure: Remote Commands. (line 32) +* magit-remote-prune: Remote Commands. (line 63) +* magit-remote-prune-refspecs: Remote Commands. (line 67) +* magit-remote-remove: Remote Commands. (line 60) +* magit-remote-rename: Remote Commands. (line 52) +* magit-remote-set-url: Remote Commands. (line 56) +* magit-repolist-column-branch: Repository List. (line 51) +* magit-repolist-column-branches: Repository List. (line 58) +* magit-repolist-column-flag: Repository List. (line 64) +* magit-repolist-column-flags: Repository List. (line 76) +* magit-repolist-column-ident: Repository List. (line 40) +* magit-repolist-column-path: Repository List. (line 44) +* magit-repolist-column-stashes: Repository List. (line 61) +* magit-repolist-column-unpulled-from-pushremote: Repository List. + (line 87) +* magit-repolist-column-unpulled-from-upstream: Repository List. + (line 83) +* magit-repolist-column-unpushed-to-pushremote: Repository List. + (line 95) +* magit-repolist-column-unpushed-to-upstream: Repository List. + (line 91) +* magit-repolist-column-upstream: Repository List. (line 54) +* magit-repolist-column-version: Repository List. (line 47) +* magit-repolist-fetch: Repository List. (line 111) +* magit-repolist-find-file-other-frame: Repository List. (line 115) +* magit-repolist-mark: Repository List. (line 105) +* magit-repolist-status: Repository List. (line 102) +* magit-repolist-unmark: Repository List. (line 108) +* magit-reset-hard: Resetting. (line 24) +* magit-reset-index: Staging and Unstaging. + (line 78) +* magit-reset-index <1>: Resetting. (line 33) +* magit-reset-keep: Resetting. (line 28) +* magit-reset-mixed: Resetting. (line 15) +* magit-reset-quickly: Resetting. (line 9) +* magit-reset-soft: Resetting. (line 19) +* magit-reset-worktree: Resetting. (line 39) +* magit-reset-worktree <1>: Wip Modes. (line 64) +* magit-restore-window-configuration: Quitting Windows. (line 24) +* magit-reverse: Applying. (line 47) +* magit-reverse-in-index: Staging and Unstaging. + (line 58) +* magit-revert: Reverting. (line 7) +* magit-revert-and-commit: Reverting. (line 15) +* magit-revert-no-commit: Reverting. (line 20) +* magit-run: Running Git Manually. + (line 13) +* magit-run-git: Calling Git for Effect. + (line 34) +* magit-run-git-async: Calling Git for Effect. + (line 59) +* magit-run-git-gui: Running Git Manually. + (line 59) +* magit-run-git-with-editor: Calling Git for Effect. + (line 71) +* magit-run-git-with-input: Calling Git for Effect. + (line 37) +* magit-run-gitk: Running Git Manually. + (line 50) +* magit-run-gitk-all: Running Git Manually. + (line 53) +* magit-run-gitk-branches: Running Git Manually. + (line 56) +* magit-save-window-configuration: Switching Buffers. (line 80) +* magit-section-backward: Section Movement. (line 11) +* magit-section-backward-siblings: Section Movement. (line 19) +* magit-section-case: Matching Sections. (line 66) +* magit-section-cycle: Section Visibility. (line 14) +* magit-section-cycle-diffs: Section Visibility. (line 29) +* magit-section-cycle-global: Section Visibility. (line 33) +* magit-section-forward: Section Movement. (line 16) +* magit-section-forward-siblings: Section Movement. (line 24) +* magit-section-hide: Section Visibility. (line 55) +* magit-section-hide-children: Section Visibility. (line 67) +* magit-section-ident: Matching Sections. (line 10) +* magit-section-match: Matching Sections. (line 18) +* magit-section-set-window-start: Section Movement. (line 52) +* magit-section-show: Section Visibility. (line 52) +* magit-section-show-children: Section Visibility. (line 62) +* magit-section-show-headings: Section Visibility. (line 58) +* magit-section-show-level-1: Section Visibility. (line 39) +* magit-section-show-level-1-all: Section Visibility. (line 45) +* magit-section-show-level-2: Section Visibility. (line 39) +* magit-section-show-level-2-all: Section Visibility. (line 45) +* magit-section-show-level-3: Section Visibility. (line 39) +* magit-section-show-level-3-all: Section Visibility. (line 45) +* magit-section-show-level-4: Section Visibility. (line 39) +* magit-section-show-level-4-all: Section Visibility. (line 45) +* magit-section-toggle: Section Visibility. (line 10) +* magit-section-toggle-children: Section Visibility. (line 70) +* magit-section-up: Section Movement. (line 28) +* magit-section-value-if: Matching Sections. (line 57) +* magit-sequence-abort: Cherry Picking. (line 91) +* magit-sequence-abort <1>: Reverting. (line 35) +* magit-sequence-continue: Cherry Picking. (line 85) +* magit-sequence-continue <1>: Reverting. (line 29) +* magit-sequence-skip: Cherry Picking. (line 88) +* magit-sequence-skip <1>: Reverting. (line 32) +* magit-shell-command: Running Git Manually. + (line 38) +* magit-shell-command-topdir: Running Git Manually. + (line 34) +* magit-show-commit: Diffing. (line 63) +* magit-show-commit <1>: Blaming. (line 91) +* magit-show-refs: References Buffer. (line 7) +* magit-show-refs-current: References Buffer. (line 25) +* magit-show-refs-head: References Buffer. (line 21) +* magit-show-refs-other: References Buffer. (line 30) +* magit-snapshot-both: Stashing. (line 36) +* magit-snapshot-index: Stashing. (line 42) +* magit-snapshot-worktree: Stashing. (line 46) +* magit-sparse-checkout: Sparse checkouts. (line 17) +* magit-sparse-checkout-add: Sparse checkouts. (line 39) +* magit-sparse-checkout-disable: Sparse checkouts. (line 50) +* magit-sparse-checkout-enable: Sparse checkouts. (line 21) +* magit-sparse-checkout-reapply: Sparse checkouts. (line 44) +* magit-sparse-checkout-set: Sparse checkouts. (line 33) +* magit-stage: Staging and Unstaging. + (line 29) +* magit-stage-buffer-file: Commands for Buffers Visiting Files. + (line 52) +* magit-stage-buffer-file <1>: Commands for Buffers Visiting Files. + (line 63) +* magit-stage-file: Staging from File-Visiting Buffers. + (line 11) +* magit-stage-file <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-stage-file <2>: Commands for Buffers Visiting Files. + (line 63) +* magit-stage-modified: Staging and Unstaging. + (line 36) +* magit-start-git: Calling Git for Effect. + (line 82) +* magit-start-process: Calling Git for Effect. + (line 100) +* magit-stash: Stashing. (line 9) +* magit-stash-apply: Stashing. (line 52) +* magit-stash-both: Stashing. (line 14) +* magit-stash-branch: Stashing. (line 105) +* magit-stash-branch-here: Stashing. (line 110) +* magit-stash-clear: Stashing. (line 118) +* magit-stash-drop: Stashing. (line 98) +* magit-stash-format-patch: Stashing. (line 115) +* magit-stash-index: Stashing. (line 20) +* magit-stash-keep-index: Stashing. (line 30) +* magit-stash-list: Stashing. (line 121) +* magit-stash-pop: Stashing. (line 74) +* magit-stash-show: Diffing. (line 67) +* magit-stash-show <1>: Stashing. (line 102) +* magit-stash-worktree: Stashing. (line 24) +* magit-stashes-maybe-update-stash-buffer: Section Movement. (line 92) +* magit-status: Status Buffer. (line 23) +* magit-status-here: Commands for Buffers Visiting Files. + (line 52) +* magit-status-here <1>: Commands for Buffers Visiting Files. + (line 166) +* magit-status-maybe-update-blob-buffer: Section Movement. (line 87) +* magit-status-maybe-update-revision-buffer: Section Movement. + (line 77) +* magit-status-maybe-update-stash-buffer: Section Movement. (line 82) +* magit-status-quick: Status Buffer. (line 70) +* magit-submodule: Submodule Transient. (line 7) +* magit-submodule-add: Submodule Transient. (line 20) +* magit-submodule-populate: Submodule Transient. (line 32) +* magit-submodule-register: Submodule Transient. (line 26) +* magit-submodule-synchronize: Submodule Transient. (line 40) +* magit-submodule-unpopulate: Submodule Transient. (line 45) +* magit-submodule-update: Submodule Transient. (line 36) +* magit-subtree: Subtree. (line 9) +* magit-subtree-add: Subtree. (line 24) +* magit-subtree-add-commit: Subtree. (line 28) +* magit-subtree-export: Subtree. (line 37) +* magit-subtree-import: Subtree. (line 13) +* magit-subtree-merge: Subtree. (line 31) +* magit-subtree-pull: Subtree. (line 34) +* magit-subtree-push: Subtree. (line 48) +* magit-subtree-split: Subtree. (line 52) +* magit-switch-to-repository-buffer: Common Commands. (line 6) +* magit-switch-to-repository-buffer-other-frame: Common Commands. + (line 8) +* magit-switch-to-repository-buffer-other-window: Common Commands. + (line 7) +* magit-tag: Tagging. (line 9) +* magit-tag-create: Tagging. (line 14) +* magit-tag-delete: Tagging. (line 37) +* magit-tag-prune: Tagging. (line 43) +* magit-tag-release: Tagging. (line 18) +* magit-toggle-buffer-lock: Modes and Buffers. (line 18) +* magit-toggle-git-debug: Debugging Tools. (line 29) +* magit-toggle-margin: Refreshing Logs. (line 34) +* magit-toggle-margin <1>: Log Margin. (line 60) +* magit-toggle-margin-details: Log Margin. (line 66) +* magit-toggle-verbose-refresh: Debugging Tools. (line 52) +* magit-unstage: Staging and Unstaging. + (line 42) +* magit-unstage-all: Staging and Unstaging. + (line 50) +* magit-unstage-buffer-file: Commands for Buffers Visiting Files. + (line 52) +* magit-unstage-buffer-file <1>: Commands for Buffers Visiting Files. + (line 69) +* magit-unstage-file: Staging from File-Visiting Buffers. + (line 18) +* magit-unstage-file <1>: Commands for Buffers Visiting Files. + (line 52) +* magit-unstage-file <2>: Commands for Buffers Visiting Files. + (line 69) +* magit-version: Git Executable. (line 59) +* magit-version <1>: Debugging Tools. (line 11) +* magit-visit-ref: References Buffer. (line 159) +* magit-wip-commit: Wip Modes. (line 85) +* magit-wip-log: Wip Modes. (line 47) +* magit-wip-log-current: Wip Modes. (line 55) +* magit-worktree: Worktree. (line 9) +* magit-worktree-branch: Worktree. (line 16) +* magit-worktree-checkout: Worktree. (line 13) +* magit-worktree-delete: Worktree. (line 22) +* magit-worktree-move: Worktree. (line 19) +* magit-worktree-status: Worktree. (line 26) +* scroll-down: Commands Available in Diffs. + (line 56) +* scroll-up: Commands Available in Diffs. + (line 53) +* with-editor-cancel: Editing Commit Messages. + (line 22) +* with-editor-cancel <1>: Editing Rebase Sequences. + (line 11) +* with-editor-debug: Debugging Tools. (line 64) +* with-editor-finish: Editing Commit Messages. + (line 18) +* with-editor-finish <1>: Editing Rebase Sequences. + (line 7) +* with-editor-usage-message: Commit Mode and Hooks. + (line 51) + + +File: magit.info, Node: Variable Index, Prev: Function and Command Index, Up: Top + +Appendix E Variable Index +************************* + + +* Menu: + +* auto-revert-buffer-list-filter: Automatic Reverting of File-Visiting Buffers. + (line 73) +* auto-revert-interval: Automatic Reverting of File-Visiting Buffers. + (line 69) +* auto-revert-mode: Automatic Reverting of File-Visiting Buffers. + (line 57) +* auto-revert-stop-on-user-input: Automatic Reverting of File-Visiting Buffers. + (line 65) +* auto-revert-use-notify: Automatic Reverting of File-Visiting Buffers. + (line 46) +* auto-revert-verbose: Automatic Reverting of File-Visiting Buffers. + (line 94) +* branch.autoSetupMerge: Branch Git Variables. + (line 71) +* branch.autoSetupRebase: Branch Git Variables. + (line 85) +* branch.NAME.description: Branch Git Variables. + (line 42) +* branch.NAME.merge: Branch Git Variables. + (line 10) +* branch.NAME.pushRemote: Branch Git Variables. + (line 29) +* branch.NAME.rebase: Branch Git Variables. + (line 20) +* branch.NAME.remote: Branch Git Variables. + (line 15) +* core.notesRef: Notes. (line 53) +* git-commit-finish-query-functions: Commit Message Conventions. + (line 18) +* git-commit-known-pseudo-headers: Commit Pseudo Headers. + (line 9) +* git-commit-major-mode: Commit Mode and Hooks. + (line 12) +* git-commit-post-finish-hook: Commit Mode and Hooks. + (line 54) +* git-commit-setup-hook: Commit Mode and Hooks. + (line 21) +* git-commit-style-convention-checks: Commit Message Conventions. + (line 38) +* git-commit-summary-max-length: Commit Message Conventions. + (line 13) +* git-rebase-auto-advance: Editing Rebase Sequences. + (line 80) +* git-rebase-confirm-cancel: Editing Rebase Sequences. + (line 86) +* git-rebase-show-instructions: Editing Rebase Sequences. + (line 83) +* global-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. + (line 21) +* magit-auto-revert-immediately: Automatic Reverting of File-Visiting Buffers. + (line 30) +* magit-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. + (line 17) +* magit-auto-revert-tracked-only: Automatic Reverting of File-Visiting Buffers. + (line 51) +* magit-bisect-show-graph: Bisecting. (line 57) +* magit-blame-disable-modes: Blaming. (line 165) +* magit-blame-echo-style: Blaming. (line 151) +* magit-blame-goto-chunk-hook: Blaming. (line 170) +* magit-blame-read-only: Blaming. (line 161) +* magit-blame-styles: Blaming. (line 147) +* magit-blame-time-format: Blaming. (line 157) +* magit-branch-adjust-remote-upstream-alist: Branch Commands. (line 202) +* magit-branch-direct-configure: Branch Commands. (line 19) +* magit-branch-prefer-remote-upstream: Branch Commands. (line 158) +* magit-branch-read-upstream-first: Branch Commands. (line 153) +* magit-buffer-name-format: Naming Buffers. (line 25) +* magit-bury-buffer-function: Quitting Windows. (line 16) +* magit-cherry-margin: Cherries. (line 21) +* magit-clone-always-transient: Cloning Repository. (line 12) +* magit-clone-default-directory: Cloning Repository. (line 84) +* magit-clone-name-alist: Cloning Repository. (line 94) +* magit-clone-set-remote-head: Cloning Repository. (line 66) +* magit-clone-set-remote.pushDefault: Cloning Repository. (line 75) +* magit-clone-url-format: Cloning Repository. (line 114) +* magit-commit-ask-to-stage: Initiating a Commit. (line 65) +* magit-commit-diff-inhibit-same-window: Initiating a Commit. (line 97) +* magit-commit-extend-override-date: Initiating a Commit. (line 72) +* magit-commit-reword-override-date: Initiating a Commit. (line 75) +* magit-commit-show-diff: Initiating a Commit. (line 69) +* magit-commit-squash-confirm: Initiating a Commit. (line 78) +* magit-completing-read-function: Support for Completion Frameworks. + (line 27) +* magit-define-global-key-bindings: Global Bindings. (line 6) +* magit-diff-adjust-tab-width: Diff Options. (line 17) +* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files. + (line 104) +* magit-diff-extra-stat-arguments: Diff Options. (line 112) +* magit-diff-hide-trailing-cr-characters: Diff Options. (line 77) +* magit-diff-highlight-hunk-region-functions: Diff Options. (line 80) +* magit-diff-highlight-indentation: Diff Options. (line 63) +* magit-diff-highlight-trailing: Diff Options. (line 59) +* magit-diff-paint-whitespace: Diff Options. (line 38) +* magit-diff-paint-whitespace-lines: Diff Options. (line 52) +* magit-diff-refine-hunk: Diff Options. (line 6) +* magit-diff-refine-ignore-whitespace: Diff Options. (line 13) +* magit-diff-unmarked-lines-keep-foreground: Diff Options. (line 105) +* magit-diff-visit-previous-blob: Visiting Files and Blobs from a Diff. + (line 38) +* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables. + (line 73) +* magit-display-buffer-function: Switching Buffers. (line 25) +* magit-display-buffer-noselect: Switching Buffers. (line 17) +* magit-dwim-selection: Completion and Confirmation. + (line 42) +* magit-ediff-dwim-resolve-function: Ediffing. (line 105) +* magit-ediff-dwim-show-on-hunks: Ediffing. (line 111) +* magit-ediff-quit-hook: Ediffing. (line 124) +* magit-ediff-show-stash-with-index: Ediffing. (line 118) +* magit-generate-buffer-name-function: Naming Buffers. (line 6) +* magit-git-debug: Viewing Git Output. (line 26) +* magit-git-debug <1>: Getting a Value from Git. + (line 68) +* magit-git-executable: Git Executable. (line 26) +* magit-git-global-arguments: Global Git Arguments. + (line 6) +* magit-keep-region-overlay: The Selection. (line 52) +* magit-list-refs-sortby: Additional Completion Options. + (line 6) +* magit-log-auto-more: Log Buffer. (line 69) +* magit-log-buffer-file-locked: Commands for Buffers Visiting Files. + (line 124) +* magit-log-margin: Log Margin. (line 12) +* magit-log-margin-show-committer-date: Log Margin. (line 44) +* magit-log-section-commit-count: Status Sections. (line 114) +* magit-log-select-margin: Select from Log. (line 28) +* magit-log-show-color-graph-limit: Log Buffer. (line 78) +* magit-log-show-refname-after-summary: Log Buffer. (line 74) +* magit-log-show-signatures-limit: Log Buffer. (line 84) +* magit-log-trace-definition-function: Commands Available in Diffs. + (line 17) +* magit-module-sections-hook: Status Module Sections. + (line 19) +* magit-module-sections-nested: Status Module Sections. + (line 22) +* magit-no-confirm: Action Confirmation. (line 18) +* magit-pop-revision-stack-format: Using the Revision Stack. + (line 34) +* magit-post-clone-hook: Cloning Repository. (line 133) +* magit-post-commit-hook: Initiating a Commit. (line 86) +* magit-post-display-buffer-hook: Switching Buffers. (line 85) +* magit-pre-display-buffer-hook: Switching Buffers. (line 76) +* magit-prefer-remote-upstream: Branch Git Variables. + (line 109) +* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables. + (line 65) +* magit-process-extreme-logging: Viewing Git Output. (line 56) +* magit-process-raise-error: Calling Git for Effect. + (line 125) +* magit-pull-or-fetch: Fetching. (line 52) +* magit-reflog-margin: Reflog. (line 20) +* magit-refresh-args: Refreshing Buffers. (line 52) +* magit-refresh-buffer-hook: Automatic Refreshing of Magit Buffers. + (line 41) +* magit-refresh-function: Refreshing Buffers. (line 47) +* magit-refresh-status-buffer: Automatic Refreshing of Magit Buffers. + (line 46) +* magit-refs-filter-alist: References Buffer. (line 137) +* magit-refs-focus-column-width: References Buffer. (line 75) +* magit-refs-margin: References Buffer. (line 89) +* magit-refs-margin-for-tags: References Buffer. (line 112) +* magit-refs-pad-commit-counts: References Buffer. (line 45) +* magit-refs-primary-column-width: References Buffer. (line 63) +* magit-refs-sections-hook: References Sections. (line 13) +* magit-refs-show-commit-count: References Buffer. (line 36) +* magit-refs-show-remote-prefix: References Buffer. (line 57) +* magit-remote-add-set-remote.pushDefault: Remote Commands. (line 83) +* magit-remote-direct-configure: Remote Commands. (line 20) +* magit-remote-git-executable: Git Executable. (line 32) +* magit-repolist-columns: Repository List. (line 12) +* magit-repository-directories: Status Buffer. (line 57) +* magit-revision-filter-files-on-follow: Revision Buffer. (line 55) +* magit-revision-insert-related-refs: Revision Buffer. (line 6) +* magit-revision-show-gravatars: Revision Buffer. (line 15) +* magit-revision-use-hash-sections: Revision Buffer. (line 31) +* magit-root-section: Matching Sections. (line 81) +* magit-save-repository-buffers: Automatic Saving of File-Visiting Buffers. + (line 13) +* magit-section-cache-visibility: Section Visibility. (line 95) +* magit-section-initial-visibility-alist: Section Visibility. (line 79) +* magit-section-movement-hook: Section Movement. (line 41) +* magit-section-set-visibility-hook: Section Visibility. (line 105) +* magit-section-show-child-count: Section Options. (line 9) +* magit-section-visibility-indicator: Section Visibility. (line 122) +* magit-shell-command-verbose-prompt: Running Git Manually. + (line 43) +* magit-stashes-margin: Stashing. (line 123) +* magit-status-headers-hook: Status Header Sections. + (line 17) +* magit-status-margin: Status Options. (line 6) +* magit-status-sections-hook: Status Sections. (line 10) +* magit-submodule-list-columns: Listing Submodules. (line 20) +* magit-this-process: Calling Git for Effect. + (line 121) +* magit-uniquify-buffer-names: Naming Buffers. (line 65) +* magit-unstage-committed: Staging and Unstaging. + (line 52) +* magit-update-other-window-delay: Section Movement. (line 97) +* magit-visit-ref-behavior: References Buffer. (line 168) +* magit-wip-after-apply-mode: Legacy Wip Modes. (line 18) +* magit-wip-after-apply-mode-lighter: Legacy Wip Modes. (line 54) +* magit-wip-after-save-local-mode-lighter: Legacy Wip Modes. (line 51) +* magit-wip-after-save-mode: Legacy Wip Modes. (line 13) +* magit-wip-before-change-mode: Legacy Wip Modes. (line 31) +* magit-wip-before-change-mode-lighter: Legacy Wip Modes. (line 57) +* magit-wip-initial-backup-mode: Legacy Wip Modes. (line 35) +* magit-wip-initial-backup-mode-lighter: Legacy Wip Modes. (line 60) +* magit-wip-merge-branch: Wip Graph. (line 6) +* magit-wip-mode: Wip Modes. (line 30) +* magit-wip-mode-lighter: Wip Modes. (line 98) +* magit-wip-namespace: Wip Modes. (line 91) +* notes.displayRef: Notes. (line 57) +* pull.rebase: Branch Git Variables. + (line 50) +* remote.NAME.fetch: Remote Git Variables. + (line 14) +* remote.NAME.push: Remote Git Variables. + (line 23) +* remote.NAME.pushurl: Remote Git Variables. + (line 18) +* remote.NAME.tagOpts: Remote Git Variables. + (line 27) +* remote.NAME.url: Remote Git Variables. + (line 10) +* remote.pushDefault: Branch Git Variables. + (line 62) + + + +Tag Table: +Node: Top774 +Node: Introduction6565 +Node: Installation11281 +Node: Installing from Melpa11611 +Node: Installing from the Git Repository12686 +Node: Post-Installation Tasks15500 +Node: Getting Started16785 +Node: Interface Concepts22596 +Node: Modes and Buffers22975 +Node: Switching Buffers24686 +Node: Naming Buffers29425 +Node: Quitting Windows32500 +Node: Automatic Refreshing of Magit Buffers34435 +Node: Automatic Saving of File-Visiting Buffers37316 +Node: Automatic Reverting of File-Visiting Buffers38500 +Node: Risk of Reverting Automatically43485 +Node: Sections45867 +Node: Section Movement46793 +Node: Section Visibility51667 +Node: Section Hooks58354 +Node: Section Types and Values60760 +Node: Section Options62175 +Node: Transient Commands62646 +Node: Transient Arguments and Buffer Variables64122 +Node: Completion Confirmation and the Selection71139 +Node: Action Confirmation71585 +Node: Completion and Confirmation80090 +Node: The Selection83275 +Node: The hunk-internal region86173 +Node: Support for Completion Frameworks87262 +Node: Additional Completion Options92147 +Node: Mouse Support92745 +Node: Running Git93321 +Node: Viewing Git Output93566 +Node: Git Process Status96270 +Node: Running Git Manually97235 +Node: Git Executable99925 +Node: Global Git Arguments102933 +Node: Inspecting103738 +Node: Status Buffer104895 +Node: Status Sections109906 +Node: Status Header Sections115433 +Node: Status Module Sections118052 +Node: Status Options120549 +Node: Repository List121912 +Node: Logging126690 +Node: Refreshing Logs129532 +Node: Log Buffer130953 +Node: Log Margin135776 +Node: Select from Log138929 +Node: Reflog141139 +Node: Cherries142776 +Node: Diffing144614 +Node: Refreshing Diffs147648 +Node: Commands Available in Diffs151337 +Node: Diff Options153850 +Node: Revision Buffer159313 +Node: Ediffing162633 +Node: References Buffer168683 +Node: References Sections179277 +Node: Bisecting180134 +Node: Visiting Files and Blobs182445 +Node: General-Purpose Visit Commands182973 +Node: Visiting Files and Blobs from a Diff183926 +Node: Blaming187370 +Node: Manipulating194358 +Node: Creating Repository194700 +Node: Cloning Repository195237 +Node: Staging and Unstaging201678 +Node: Staging from File-Visiting Buffers205651 +Node: Applying206757 +Node: Committing208830 +Node: Initiating a Commit209413 +Node: Editing Commit Messages214603 +Node: Using the Revision Stack217376 +Node: Commit Pseudo Headers220421 +Node: Commit Mode and Hooks221716 +Node: Commit Message Conventions224574 +Node: Branching226561 +Node: The Two Remotes226787 +Node: Branch Commands229440 +Node: Branch Git Variables242290 +Node: Auxiliary Branch Commands247664 +Node: Merging248780 +Node: Resolving Conflicts252936 +Node: Rebasing258310 +Node: Editing Rebase Sequences263099 +Node: Information About In-Progress Rebase267315 +Ref: Information About In-Progress Rebase-Footnote-1276428 +Node: Cherry Picking277024 +Node: Reverting281358 +Node: Resetting282777 +Node: Stashing284603 +Node: Transferring290984 +Node: Remotes291206 +Node: Remote Commands291358 +Node: Remote Git Variables295397 +Node: Fetching296668 +Node: Pulling299151 +Node: Pushing300177 +Node: Plain Patches304468 +Node: Maildir Patches305939 +Node: Miscellaneous307418 +Node: Tagging307764 +Node: Notes309657 +Node: Submodules311992 +Node: Listing Submodules312210 +Node: Submodule Transient314358 +Node: Subtree316803 +Node: Worktree318734 +Node: Sparse checkouts319810 +Node: Bundle322586 +Node: Common Commands322961 +Node: Wip Modes325589 +Node: Wip Graph330480 +Node: Legacy Wip Modes332793 +Node: Commands for Buffers Visiting Files335680 +Node: Minor Mode for Buffers Visiting Blobs343907 +Node: Customizing344705 +Node: Per-Repository Configuration346301 +Node: Essential Settings348555 +Node: Safety348901 +Node: Performance350662 +Ref: Log Performance353625 +Ref: Diff Performance354930 +Ref: Refs Buffer Performance356271 +Ref: Committing Performance356846 +Node: Microsoft Windows Performance357828 +Node: MacOS Performance359019 +Ref: MacOS Performance-Footnote-1360042 +Node: Global Bindings360124 +Node: Plumbing362352 +Node: Calling Git363181 +Node: Getting a Value from Git364706 +Node: Calling Git for Effect368434 +Node: Section Plumbing374328 +Node: Creating Sections374556 +Node: Section Selection378452 +Node: Matching Sections380248 +Node: Refreshing Buffers386169 +Node: Conventions389313 +Node: Theming Faces389505 +Node: FAQ397610 +Node: FAQ - How to ...?398048 +Node: How to pronounce Magit?398405 +Node: How to show git's output?399208 +Node: How to install the gitman info manual?399994 +Node: How to show diffs for gpg-encrypted files?400964 +Node: How does branching and pushing work?401560 +Node: Should I disable VC?401893 +Node: FAQ - Issues and Errors402496 +Node: Magit is slow403441 +Node: I changed several thousand files at once and now Magit is unusable403734 +Node: I am having problems committing404460 +Node: I am using MS Windows and cannot push with Magit404941 +Node: I am using macOS and SOMETHING works in shell but not in Magit405559 +Node: Expanding a file to show the diff causes it to disappear406393 +Node: Point is wrong in the COMMIT_EDITMSG buffer406981 +Node: The mode-line information isn't always up-to-date408029 +Node: A branch and tag sharing the same name breaks SOMETHING409092 +Node: My Git hooks work on the command-line but not inside Magit409979 +Node: git-commit-mode isn't used when committing from the command-line410825 +Node: Point ends up inside invisible text when jumping to a file-visiting buffer413096 +Node: I am no longer able to save popup defaults413945 +Node: Debugging Tools414926 +Node: Keystroke Index418100 +Node: Function and Command Index459714 +Node: Variable Index517915 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/emacs/elpa/magit-section-20240811.1419/magit-section-pkg.el b/emacs/elpa/magit-section-20240811.1419/magit-section-pkg.el @@ -1,14 +0,0 @@ -(define-package "magit-section" "20240811.1419" "Sections for read-only buffers." - '((emacs "26.1") - (compat "30.0.0.0") - (dash "20240510")) - :commit "a2739d7db1fdf19b95f36f6ddd15b0c1f523bd26" :authors - '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) - :maintainer - '("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") - :keywords - '("tools") - :url "https://github.com/magit/magit") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/magit-section-20240811.1419/magit-section.info b/emacs/elpa/magit-section-20240811.1419/magit-section.info @@ -1,317 +0,0 @@ -This is magit-section.info, produced by makeinfo version 6.8 from -magit-section.texi. - - Copyright (C) 2015-2024 Jonas Bernoulli - <emacs.magit@jonas.bernoulli.dev> - - You can redistribute this document 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 document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit-Section: (magit-section). Use Magit sections in your own packages. -END-INFO-DIR-ENTRY - - -File: magit-section.info, Node: Top, Next: Introduction, Up: (dir) - -Magit-Section Developer Manual -****************************** - -This package implements the main user interface of Magit — the -collapsible sections that make up its buffers. This package used to be -distributed as part of Magit but how it can also be used by other -packages that have nothing to do with Magit or Git. - - To learn more about the section abstraction and available commands -and user options see *note (magit)Sections::. This manual documents how -you can use sections in your own packages. - -This manual is for Magit-Section version 3.3.0.50-git. - - Copyright (C) 2015-2024 Jonas Bernoulli - <emacs.magit@jonas.bernoulli.dev> - - You can redistribute this document 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 document 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. - -* Menu: - -* Introduction:: -* Creating Sections:: -* Core Functions:: -* Matching Functions:: - - -File: magit-section.info, Node: Introduction, Next: Creating Sections, Prev: Top, Up: Top - -1 Introduction -************** - -This package implements the main user interface of Magit — the -collapsible sections that make up its buffers. This package used to be -distributed as part of Magit but how it can also be used by other -packages that have nothing to do with Magit or Git. - - To learn more about the section abstraction and available commands -and user options see *note (magit)Sections::. This manual documents how -you can use sections in your own packages. - - When the documentation leaves something unaddressed, then please -consider that Magit uses this library extensively and search its source -for suitable examples before asking me for help. Thanks! - - -File: magit-section.info, Node: Creating Sections, Next: Core Functions, Prev: Introduction, Up: Top - -2 Creating Sections -******************* - - -- Macro: magit-insert-section [name] (type &optional value hide) &rest - body - Create a section object of type CLASS, storing VALUE in its ‘value’ - slot, and insert the section at point. CLASS is a subclass of - ‘magit-section’ or has the form ‘(eval FORM)’, in which case FORM - is evaluated at runtime and should return a subclass. In other - places a sections class is often referred to as its "type". - - Many commands behave differently depending on the class of the - current section and sections of a certain class can have their own - keymap, which is specified using the ‘keymap’ class slot. The - value of that slot should be a variable whose value is a keymap. - - For historic reasons Magit and Forge in most cases use symbols as - CLASS that don’t actually identify a class and that lack the - appropriate package prefix. This works due to some undocumented - kludges, which are not available to other packages. - - When optional HIDE is non-nil collapse the section body by default, - i.e., when first creating the section, but not when refreshing the - buffer. Else expand it by default. This can be overwritten using - ‘magit-section-set-visibility-hook’. When a section is recreated - during a refresh, then the visibility of predecessor is inherited - and HIDE is ignored (but the hook is still honored). - - BODY is any number of forms that actually insert the section’s - heading and body. Optional NAME, if specified, has to be a symbol, - which is then bound to the object of the section being inserted. - - Before BODY is evaluated the ‘start’ of the section object is set - to the value of ‘point’ and after BODY was evaluated its ‘end’ is - set to the new value of ‘point’; BODY is responsible for moving - ‘point’ forward. - - If it turns out inside BODY that the section is empty, then - ‘magit-cancel-section’ can be used to abort and remove all traces - of the partially inserted section. This can happen when creating a - section by washing Git’s output and Git didn’t actually output - anything this time around. - - -- Function: magit-insert-heading [child-count] &rest args - Insert the heading for the section currently being inserted. - - This function should only be used inside ‘magit-insert-section’. - - When called without any arguments, then just set the ‘content’ slot - of the object representing the section being inserted to a marker - at ‘point’. The section should only contain a single line when - this function is used like this. - - When called with arguments ARGS, which have to be strings, or nil, - then insert those strings at point. The section should not contain - any text before this happens and afterwards it should again only - contain a single line. If the ‘face’ property is set anywhere - inside any of these strings, then insert all of them unchanged. - Otherwise use the ‘magit-section-heading’ face for all inserted - text. - - The ‘content’ property of the section object is the end of the - heading (which lasts from ‘start’ to ‘content’) and the beginning - of the the body (which lasts from ‘content’ to ‘end’). If the - value of ‘content’ is nil, then the section has no heading and its - body cannot be collapsed. If a section does have a heading, then - its height must be exactly one line, including a trailing newline - character. This isn’t enforced, you are responsible for getting it - right. The only exception is that this function does insert a - newline character if necessary. - - If provided, optional CHILD-COUNT must evaluate to an integer or - boolean. If t, then the count is determined once the children have - been inserted, using ‘magit-insert-child-count’ (which see). For - historic reasons, if the heading ends with ":", the count is - substituted for that, at this time as well. If - ‘magit-section-show-child-count’ is nil, no counts are inserted - - -- Macro: magit-insert-section-body &rest body - Use BODY to insert the section body, once the section is expanded. - If the section is expanded when it is created, then this is like - ‘progn’. Otherwise BODY isn’t evaluated until the section is - explicitly expanded. - - -- Function: magit-cancel-section - Cancel inserting the section that is currently being inserted. - Remove all traces of that section. - - -- Function: magit-wash-sequence function - Repeatedly call FUNCTION until it returns ‘nil’ or the end of the - buffer is reached. FUNCTION has to move point forward or return - ‘nil’. - - -File: magit-section.info, Node: Core Functions, Next: Matching Functions, Prev: Creating Sections, Up: Top - -3 Core Functions -**************** - - -- Function: magit-current-section - Return the section at point or where the context menu was invoked. - When using the context menu, return the section that the user - clicked on, provided the current buffer is the buffer in which the - click occurred. Otherwise return the section at point. - -Function magit-section-at &optional position - Return the section at POSITION, defaulting to point. Default to - point even when the context menu is used. - - -- Function: magit-section-ident section - Return an unique identifier for SECTION. The return value has the - form ‘((TYPE . VALUE)...)’. - - -- Function: magit-section-ident-value value - Return a constant representation of VALUE. - - VALUE is the value of a ‘magit-section’ object. If that is an - object itself, then that is not suitable to be used to identify the - section because two objects may represent the same thing but not be - equal. If possible a method should be added for such objects, - which returns a value that is equal. Otherwise the catch-all - method is used, which just returns the argument itself. - - -- Function: magit-get-section ident &optional root - Return the section identified by IDENT. IDENT has to be a list as - returned by ‘magit-section-ident’. If optional ROOT is non-nil, - then search in that section tree instead of in the one whose root - ‘magit-root-section’ is. - - -- Function: magit-section-lineage section &optional raw - Return the lineage of SECTION. If optional RAW is non-nil, return - a list of section objects, beginning with SECTION, otherwise return - a list of section types. - - -- Function: magit-section-content-p section - Return non-nil if SECTION has content or an unused washer function. - - The next two functions are replacements for the Emacs functions that -have the same name except for the ‘magit-’ prefix. Like -‘magit-current-section’ they do not act on point, the cursors position, -but on the position where the user clicked to invoke the context menu. - - If your package provides a context menu and some of its commands act -on the "thing at point", even if just as a default, then use the -prefixed functions to teach them to instead use the click location when -appropriate. - -Function magit-point - Return point or the position where the context menu was invoked. - When using the context menu, return the position the user clicked - on, provided the current buffer is the buffer in which the click - occurred. Otherwise return the same value as ‘point’. - -Function magit-thing-at-point thing &optional no-properties - Return the THING at point or where the context menu was invoked. - When using the context menu, return the thing the user clicked on, - provided the current buffer is the buffer in which the click - occurred. Otherwise return the same value as ‘thing-at-point’. - For the meaning of THING and NO-PROPERTIES see that function. - - -File: magit-section.info, Node: Matching Functions, Prev: Core Functions, Up: Top - -4 Matching Functions -******************** - - -- Function: magit-section-match condition &optional (section - (magit-current-section)) - Return t if SECTION matches CONDITION. - - SECTION defaults to the section at point. If SECTION is not - specified and there also is no section at point, then return nil. - - CONDITION can take the following forms: - - • ‘(CONDITION...)’ matches if any of the CONDITIONs matches. - • ‘[CLASS...]’ matches if the section’s class is the same as the - first CLASS or a subclass of that; the section’s parent class - matches the second CLASS; and so on. - - • ‘[* CLASS...]’ matches sections that match [CLASS...] and also - recursively all their child sections. - • ‘CLASS’ matches if the section’s class is the same as CLASS or - a subclass of that; regardless of the classes of the parent - sections. - - Each CLASS should be a class symbol, identifying a class that - derives from ‘magit-section’. For backward compatibility CLASS can - also be a "type symbol". A section matches such a symbol if the - value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in - ‘magit--section-type-alist’, then a section also matches that type - if its class is a subclass of the class that corresponds to the - type as per that alist. - - Note that it is not necessary to specify the complete section - lineage as printed by ‘magit-describe-section-briefly’, unless of - course you want to be that precise. - - -- Function: magit-section-value-if condition &optional section - If the section at point matches CONDITION, then return its value. - - If optional SECTION is non-nil then test whether that matches - instead. If there is no section at point and SECTION is nil, then - return nil. If the section does not match, then return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - - -- Macro: magit-section-case &rest clauses - Choose among clauses on the type of the section at point. - - Each clause looks like ‘(CONDITION BODY...)’. The type of the - section is compared against each CONDITION; the BODY forms of the - first match are evaluated sequentially and the value of the last - form is returned. Inside BODY the symbol ‘it’ is bound to the - section at point. If no clause succeeds or if there is no section - at point, return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - Additionally a CONDITION of t is allowed in the final clause, and - matches if no other CONDITION match, even if there is no section at - point. - - - -Tag Table: -Node: Top808 -Node: Introduction2116 -Node: Creating Sections2886 -Node: Core Functions7819 -Node: Matching Functions10971 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/emacs/elpa/magit-section-20240811.1419/dir b/emacs/elpa/magit-section-20240818.1037/dir diff --git a/emacs/elpa/magit-section-20240811.1419/magit-section-autoloads.el b/emacs/elpa/magit-section-20240818.1037/magit-section-autoloads.el diff --git a/emacs/elpa/magit-section-20240818.1037/magit-section-pkg.el b/emacs/elpa/magit-section-20240818.1037/magit-section-pkg.el @@ -0,0 +1,14 @@ +(define-package "magit-section" "20240818.1037" "Sections for read-only buffers." + '((emacs "26.1") + (compat "30.0.0.0") + (dash "20240510")) + :commit "61f6a778ab5b0ca97069778a5955ae527996cd0f" :authors + '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) + :maintainer + '("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") + :keywords + '("tools") + :url "https://github.com/magit/magit") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/magit-section-20240811.1419/magit-section.el b/emacs/elpa/magit-section-20240818.1037/magit-section.el diff --git a/emacs/elpa/magit-section-20240811.1419/magit-section.elc b/emacs/elpa/magit-section-20240818.1037/magit-section.elc Binary files differ. diff --git a/emacs/elpa/magit-section-20240818.1037/magit-section.info b/emacs/elpa/magit-section-20240818.1037/magit-section.info @@ -0,0 +1,317 @@ +This is magit-section.info, produced by makeinfo version 6.8 from +magit-section.texi. + + Copyright (C) 2015-2024 Jonas Bernoulli + <emacs.magit@jonas.bernoulli.dev> + + You can redistribute this document 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 document 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. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Magit-Section: (magit-section). Use Magit sections in your own packages. +END-INFO-DIR-ENTRY + + +File: magit-section.info, Node: Top, Next: Introduction, Up: (dir) + +Magit-Section Developer Manual +****************************** + +This package implements the main user interface of Magit — the +collapsible sections that make up its buffers. This package used to be +distributed as part of Magit but how it can also be used by other +packages that have nothing to do with Magit or Git. + + To learn more about the section abstraction and available commands +and user options see *note (magit)Sections::. This manual documents how +you can use sections in your own packages. + +This manual is for Magit-Section v4.0.0-13-g85bffbbf. + + Copyright (C) 2015-2024 Jonas Bernoulli + <emacs.magit@jonas.bernoulli.dev> + + You can redistribute this document 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 document 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. + +* Menu: + +* Introduction:: +* Creating Sections:: +* Core Functions:: +* Matching Functions:: + + +File: magit-section.info, Node: Introduction, Next: Creating Sections, Prev: Top, Up: Top + +1 Introduction +************** + +This package implements the main user interface of Magit — the +collapsible sections that make up its buffers. This package used to be +distributed as part of Magit but how it can also be used by other +packages that have nothing to do with Magit or Git. + + To learn more about the section abstraction and available commands +and user options see *note (magit)Sections::. This manual documents how +you can use sections in your own packages. + + When the documentation leaves something unaddressed, then please +consider that Magit uses this library extensively and search its source +for suitable examples before asking me for help. Thanks! + + +File: magit-section.info, Node: Creating Sections, Next: Core Functions, Prev: Introduction, Up: Top + +2 Creating Sections +******************* + + -- Macro: magit-insert-section [name] (type &optional value hide) &rest + body + Create a section object of type CLASS, storing VALUE in its ‘value’ + slot, and insert the section at point. CLASS is a subclass of + ‘magit-section’ or has the form ‘(eval FORM)’, in which case FORM + is evaluated at runtime and should return a subclass. In other + places a sections class is often referred to as its "type". + + Many commands behave differently depending on the class of the + current section and sections of a certain class can have their own + keymap, which is specified using the ‘keymap’ class slot. The + value of that slot should be a variable whose value is a keymap. + + For historic reasons Magit and Forge in most cases use symbols as + CLASS that don’t actually identify a class and that lack the + appropriate package prefix. This works due to some undocumented + kludges, which are not available to other packages. + + When optional HIDE is non-nil collapse the section body by default, + i.e., when first creating the section, but not when refreshing the + buffer. Else expand it by default. This can be overwritten using + ‘magit-section-set-visibility-hook’. When a section is recreated + during a refresh, then the visibility of predecessor is inherited + and HIDE is ignored (but the hook is still honored). + + BODY is any number of forms that actually insert the section’s + heading and body. Optional NAME, if specified, has to be a symbol, + which is then bound to the object of the section being inserted. + + Before BODY is evaluated the ‘start’ of the section object is set + to the value of ‘point’ and after BODY was evaluated its ‘end’ is + set to the new value of ‘point’; BODY is responsible for moving + ‘point’ forward. + + If it turns out inside BODY that the section is empty, then + ‘magit-cancel-section’ can be used to abort and remove all traces + of the partially inserted section. This can happen when creating a + section by washing Git’s output and Git didn’t actually output + anything this time around. + + -- Function: magit-insert-heading [child-count] &rest args + Insert the heading for the section currently being inserted. + + This function should only be used inside ‘magit-insert-section’. + + When called without any arguments, then just set the ‘content’ slot + of the object representing the section being inserted to a marker + at ‘point’. The section should only contain a single line when + this function is used like this. + + When called with arguments ARGS, which have to be strings, or nil, + then insert those strings at point. The section should not contain + any text before this happens and afterwards it should again only + contain a single line. If the ‘face’ property is set anywhere + inside any of these strings, then insert all of them unchanged. + Otherwise use the ‘magit-section-heading’ face for all inserted + text. + + The ‘content’ property of the section object is the end of the + heading (which lasts from ‘start’ to ‘content’) and the beginning + of the the body (which lasts from ‘content’ to ‘end’). If the + value of ‘content’ is nil, then the section has no heading and its + body cannot be collapsed. If a section does have a heading, then + its height must be exactly one line, including a trailing newline + character. This isn’t enforced, you are responsible for getting it + right. The only exception is that this function does insert a + newline character if necessary. + + If provided, optional CHILD-COUNT must evaluate to an integer or + boolean. If t, then the count is determined once the children have + been inserted, using ‘magit-insert-child-count’ (which see). For + historic reasons, if the heading ends with ":", the count is + substituted for that, at this time as well. If + ‘magit-section-show-child-count’ is nil, no counts are inserted + + -- Macro: magit-insert-section-body &rest body + Use BODY to insert the section body, once the section is expanded. + If the section is expanded when it is created, then this is like + ‘progn’. Otherwise BODY isn’t evaluated until the section is + explicitly expanded. + + -- Function: magit-cancel-section + Cancel inserting the section that is currently being inserted. + Remove all traces of that section. + + -- Function: magit-wash-sequence function + Repeatedly call FUNCTION until it returns ‘nil’ or the end of the + buffer is reached. FUNCTION has to move point forward or return + ‘nil’. + + +File: magit-section.info, Node: Core Functions, Next: Matching Functions, Prev: Creating Sections, Up: Top + +3 Core Functions +**************** + + -- Function: magit-current-section + Return the section at point or where the context menu was invoked. + When using the context menu, return the section that the user + clicked on, provided the current buffer is the buffer in which the + click occurred. Otherwise return the section at point. + +Function magit-section-at &optional position + Return the section at POSITION, defaulting to point. Default to + point even when the context menu is used. + + -- Function: magit-section-ident section + Return an unique identifier for SECTION. The return value has the + form ‘((TYPE . VALUE)...)’. + + -- Function: magit-section-ident-value value + Return a constant representation of VALUE. + + VALUE is the value of a ‘magit-section’ object. If that is an + object itself, then that is not suitable to be used to identify the + section because two objects may represent the same thing but not be + equal. If possible a method should be added for such objects, + which returns a value that is equal. Otherwise the catch-all + method is used, which just returns the argument itself. + + -- Function: magit-get-section ident &optional root + Return the section identified by IDENT. IDENT has to be a list as + returned by ‘magit-section-ident’. If optional ROOT is non-nil, + then search in that section tree instead of in the one whose root + ‘magit-root-section’ is. + + -- Function: magit-section-lineage section &optional raw + Return the lineage of SECTION. If optional RAW is non-nil, return + a list of section objects, beginning with SECTION, otherwise return + a list of section types. + + -- Function: magit-section-content-p section + Return non-nil if SECTION has content or an unused washer function. + + The next two functions are replacements for the Emacs functions that +have the same name except for the ‘magit-’ prefix. Like +‘magit-current-section’ they do not act on point, the cursors position, +but on the position where the user clicked to invoke the context menu. + + If your package provides a context menu and some of its commands act +on the "thing at point", even if just as a default, then use the +prefixed functions to teach them to instead use the click location when +appropriate. + +Function magit-point + Return point or the position where the context menu was invoked. + When using the context menu, return the position the user clicked + on, provided the current buffer is the buffer in which the click + occurred. Otherwise return the same value as ‘point’. + +Function magit-thing-at-point thing &optional no-properties + Return the THING at point or where the context menu was invoked. + When using the context menu, return the thing the user clicked on, + provided the current buffer is the buffer in which the click + occurred. Otherwise return the same value as ‘thing-at-point’. + For the meaning of THING and NO-PROPERTIES see that function. + + +File: magit-section.info, Node: Matching Functions, Prev: Core Functions, Up: Top + +4 Matching Functions +******************** + + -- Function: magit-section-match condition &optional (section + (magit-current-section)) + Return t if SECTION matches CONDITION. + + SECTION defaults to the section at point. If SECTION is not + specified and there also is no section at point, then return nil. + + CONDITION can take the following forms: + + • ‘(CONDITION...)’ matches if any of the CONDITIONs matches. + • ‘[CLASS...]’ matches if the section’s class is the same as the + first CLASS or a subclass of that; the section’s parent class + matches the second CLASS; and so on. + + • ‘[* CLASS...]’ matches sections that match [CLASS...] and also + recursively all their child sections. + • ‘CLASS’ matches if the section’s class is the same as CLASS or + a subclass of that; regardless of the classes of the parent + sections. + + Each CLASS should be a class symbol, identifying a class that + derives from ‘magit-section’. For backward compatibility CLASS can + also be a "type symbol". A section matches such a symbol if the + value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in + ‘magit--section-type-alist’, then a section also matches that type + if its class is a subclass of the class that corresponds to the + type as per that alist. + + Note that it is not necessary to specify the complete section + lineage as printed by ‘magit-describe-section-briefly’, unless of + course you want to be that precise. + + -- Function: magit-section-value-if condition &optional section + If the section at point matches CONDITION, then return its value. + + If optional SECTION is non-nil then test whether that matches + instead. If there is no section at point and SECTION is nil, then + return nil. If the section does not match, then return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + + -- Macro: magit-section-case &rest clauses + Choose among clauses on the type of the section at point. + + Each clause looks like ‘(CONDITION BODY...)’. The type of the + section is compared against each CONDITION; the BODY forms of the + first match are evaluated sequentially and the value of the last + form is returned. Inside BODY the symbol ‘it’ is bound to the + section at point. If no clause succeeds or if there is no section + at point, return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + Additionally a CONDITION of t is allowed in the final clause, and + matches if no other CONDITION match, even if there is no section at + point. + + + +Tag Table: +Node: Top808 +Node: Introduction2115 +Node: Creating Sections2885 +Node: Core Functions7818 +Node: Matching Functions10970 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons-pkg.el b/emacs/elpa/nerd-icons-20240808.625/nerd-icons-pkg.el @@ -1,16 +0,0 @@ -(define-package "nerd-icons" "20240808.625" "Emacs Nerd Font Icons Library" - '((emacs "24.3")) - :commit "dcfc64152ada7514bcdd1c6ce45590c359445ec6" :authors - '(("Hongyu Ding" . "rainstormstudio@yahoo.com") - ("Vincent Zhang" . "seagle0128@gmail.com")) - :maintainers - '(("Hongyu Ding" . "rainstormstudio@yahoo.com") - ("Vincent Zhang" . "seagle0128@gmail.com")) - :maintainer - '("Hongyu Ding" . "rainstormstudio@yahoo.com") - :keywords - '("lisp") - :url "https://github.com/rainstormstudio/nerd-icons.el") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons.el b/emacs/elpa/nerd-icons-20240808.625/nerd-icons.el @@ -1,1316 +0,0 @@ -;;; nerd-icons.el --- Emacs Nerd Font Icons Library -*- lexical-binding: t -*- - -;; Copyright (C) 2023 Hongyu Ding <rainstormstudio@yahoo.com> - -;; Author: Hongyu Ding <rainstormstudio@yahoo.com>, Vincent Zhang <seagle0128@gmail.com> -;; Keywords: lisp -;; Version: 0.1.0 -;; Package-Requires: ((emacs "24.3")) -;; URL: https://github.com/rainstormstudio/nerd-icons.el -;; Keywords: convenient, lisp - -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <http://www.gnu.org/licenses/>. - -;;; Commentary: - -;; This package was inspired by - -;; - `all-the-icons', found at https://github.com/Alexander-Miller/treemacs/blob/master/src/extra/treemacs-all-the-icons.el -;; - `vim-devicons' for Vim, found at https://github.com/ryanoasis/vim-devicons -;; - `nvim-web-devicons' for NeoVim, found at https://github.com/nvim-tree/nvim-web-devicons - -;; This package provides an interface to the Nerd Fonts - -;; - `nerd-fonts', found at https://github.com/ryanoasis/nerd-fonts - -;;; Code: - -(require 'cl-lib) - -(require 'nerd-icons-data) -(require 'nerd-icons-faces) - -(declare-function set-fontset-font "src/fontset.c") - -(defgroup nerd-icons nil - "Manage how Nerd Fonts formats icons." - :prefix "nerd-icons-" - :group 'appearance - :group 'convenience) - -(defcustom nerd-icons-color-icons t - "Whether or not to include a foreground color when formatting the icon." - :group 'nerd-icons - :type 'boolean) - -(defcustom nerd-icons-scale-factor 1.0 - "The base Scale Factor for the `height' face property of an icon." - :group 'nerd-icons - :type 'number) - -(defcustom nerd-icons-default-adjust 0.0 - "The default adjustment to be made to the `raise' display property of an icon." - :group 'nerd-icons - :type 'number) - -(defcustom nerd-icons--cache-limit 2048 - "Maximum cache size for functions cached by `nerd-icons-cache'." - :group 'nerd-icons - :type 'integer) - -(defcustom nerd-icons-font-family "Symbols Nerd Font Mono" - "The Nerd Font for display icons." - :group 'nerd-icons - :type 'string) - -(defcustom nerd-icons-fonts-subdirectory nil - "The subdirectory within the system fonts folder where the icons are installed." - :group 'nerd-icons - :type 'directory) - -(defvar nerd-icons-font-names '("NFM.ttf") - "List of defined font file names.") - -(defvar nerd-icons-glyph-sets '() "List of defined icon glyph sets.") - -(defvar nerd-icons-extension-icon-alist - '( - ("fish" nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-lpink) - ("zsh" nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-lcyan) - ("sh" nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) - ("bat" nerd-icons-codicon "nf-cod-terminal_cmd" :face nerd-icons-lsilver) - ("cmd" nerd-icons-codicon "nf-cod-terminal_cmd" :face nerd-icons-lsilver) - ;; Meta - ("tags" nerd-icons-octicon "nf-oct-tag" :face nerd-icons-blue) - ("log" nerd-icons-octicon "nf-oct-log" :face nerd-icons-maroon) - ;; Config - ("node" nerd-icons-devicon "nf-dev-nodejs_small" :face nerd-icons-green) - ("babelrc" nerd-icons-mdicon "nf-md-babel" :face nerd-icons-yellow) - ("bashrc" nerd-icons-mdicon "nf-md-bash" :face nerd-icons-dpink) - ("bowerrc" nerd-icons-devicon "nf-dev-bower" :face nerd-icons-silver) - ("cr" nerd-icons-sucicon "nf-seti-crystal" :face nerd-icons-yellow) - ("ecr" nerd-icons-sucicon "nf-seti-crystal" :face nerd-icons-yellow) - ("ini" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - ("properties" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - ("eslintignore" nerd-icons-mdicon "nf-md-eslint" :face nerd-icons-purple) - ("eslint" nerd-icons-mdicon "nf-md-eslint" :face nerd-icons-lpurple) - ("git" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) - ("gitattributes" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) - ("gitignore" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) - ("gitmodules" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) - ("mk" nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-dorange) - ;; ("cmake" nerd-icons-devicon "cmake") TODO: cmake - ("dockerignore" nerd-icons-devicon "nf-dev-docker" :face nerd-icons-dblue) - ("xml" nerd-icons-faicon "nf-fa-file_code_o" :face nerd-icons-lorange) - ("json" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - ("jsonl" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - ("cson" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - ("yml" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) - ("yaml" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) - ("toml" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) - ("conf" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dorange) - ("editorconfig" nerd-icons-sucicon "nf-seti-editorconfig" :face nerd-icons-silver) - ;; ? - ("pkg" nerd-icons-octicon "nf-oct-package" :face nerd-icons-dsilver) - ("rpm" nerd-icons-octicon "nf-oct-package" :face nerd-icons-dsilver) - ("pkgbuild" nerd-icons-octicon "nf-oct-package" :face nerd-icons-dsilver) - ("elc" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) - ("eln" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) - ("gz" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-lmaroon) - ("zip" nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) - ("7z" nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) - ("zst" nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) - ("dat" nerd-icons-faicon "nf-fa-bar_chart" :face nerd-icons-cyan) - ("dmg" nerd-icons-octicon "nf-oct-tools" :face nerd-icons-lsilver) - ("dll" nerd-icons-faicon "nf-fa-cogs" :face nerd-icons-silver) - ("ds_store" nerd-icons-faicon "nf-fa-cogs" :face nerd-icons-silver) - ("exe" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) - ("msg" nerd-icons-octicon "nf-oct-mail" :face nerd-icons-dsilver) - ;; Source Codes - ("ada" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) - ("adb" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) - ("adc" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) - ("ads" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) - ("gpr" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) - ("cgpr" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) - ("scpt" nerd-icons-devicon "nf-dev-apple" :face nerd-icons-pink) - ;; ("aup" nerd-icons-fileicon "audacity") TODO: audacity - ("elm" nerd-icons-sucicon "nf-seti-elm" :face nerd-icons-blue) - ("erl" nerd-icons-devicon "nf-dev-erlang" :face nerd-icons-red) - ("hrl" nerd-icons-devicon "nf-dev-erlang" :face nerd-icons-dred) - ("eex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) - ("leex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) - ("heex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) - ("ex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lpurple) - ("exs" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lred) - ("livemd" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lblue) - ("java" nerd-icons-devicon "nf-dev-java" :face nerd-icons-purple) - ("groovy" nerd-icons-devicon "nf-dev-groovy" :face nerd-icons-cyan) - ("gradle" nerd-icons-sucicon "nf-seti-gradle" :face nerd-icons-silver) - ("ebuild" nerd-icons-mdicon "nf-md-gentoo" :face nerd-icons-cyan) - ("eclass" nerd-icons-mdicon "nf-md-gentoo" :face nerd-icons-blue) - ("go" nerd-icons-devicon "nf-dev-go" :face nerd-icons-blue) - ("jl" nerd-icons-sucicon "nf-seti-julia" :face nerd-icons-purple) - ("magik" nerd-icons-faicon "nf-fa-magic" :face nerd-icons-blue) - ;; ("matlab" nerd-icons-devicon "matlab") TODO: matlab - ("nix" nerd-icons-mdicon "nf-md-nix" :face nerd-icons-blue) - ("pl" nerd-icons-sucicon "nf-seti-perl" :face nerd-icons-lorange) - ("pm" nerd-icons-sucicon "nf-seti-perl" :face nerd-icons-lorange) - ;; ("pl6" nerd-icons-devicon"raku") TODO: raku - ;; ("pm6" nerd-icons-devicon "raku") TODO: raku - ("pod" nerd-icons-devicon "nf-dev-perl" :face nerd-icons-lgreen) - ("php" nerd-icons-devicon "nf-dev-php" :face nerd-icons-lsilver) - ;; ("pony" nerd-icons-devicon "pony") TODO: pony - ("ps1" nerd-icons-mdicon "nf-md-powershell" :face nerd-icons-blue) - ("pro" nerd-icons-sucicon "nf-seti-prolog" :face nerd-icons-lmaroon) - ("proog" nerd-icons-sucicon "nf-seti-prolog" :face nerd-icons-lmaroon) - ("py" nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) - ;; ("idr" nerd-icons-devicon "idris") TODO: idris - ;; ("ipynb" nerd-icons-devicon "jupyter") TODO: jupyter - ("gem" nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) - ;; ("raku" nerd-icons-devicon "raku") TODO: raku - ;; ("rakumod" nerd-icons-devicon "raku") TODO: raku - ("rb" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-lred) - ("rs" nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) - ("rlib" nerd-icons-devicon "nf-dev-rust" :face nerd-icons-dmaroon) - ("r" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) - ("rd" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) - ("rdx" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) - ("rsx" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) - ("svelte" nerd-icons-sucicon "nf-seti-svelte" :face nerd-icons-red) - ("gql" nerd-icons-mdicon "nf-md-graphql" :face nerd-icons-dpink) - ("graphql" nerd-icons-mdicon "nf-md-graphql" :face nerd-icons-dpink) - ;; There seems to be a a bug with this font icon which does not - ;; let you propertise it without it reverting to being a lower - ;; case phi - ("c" nerd-icons-sucicon "nf-custom-c" :face nerd-icons-blue) - ("h" nerd-icons-faicon "nf-fa-h_square" :face nerd-icons-purple) - ("m" nerd-icons-devicon "nf-dev-apple" ) - ("mm" nerd-icons-devicon "nf-dev-apple" ) - ;; - ("cc" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) - ("cpp" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) - ("cxx" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) - ("hh" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-purple) - ("hpp" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-purple) - ("hxx" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-purple) - ;; Lisps - ("cl" nerd-icons-sucicon "nf-custom-common_lisp" :face nerd-icons-lorange) - ("l" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-orange) - ("lisp" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-orange) - ;; ("hy" nerd-icons-sucicon "nf-custom-hy" :face nerd-icons-blue) - ("el" nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple) - ("clj" nerd-icons-devicon "nf-dev-clojure" :face nerd-icons-blue) - ("cljc" nerd-icons-devicon "nf-dev-clojure" :face nerd-icons-blue) - ("cljs" nerd-icons-devicon "nf-dev-clojure" :face nerd-icons-lyellow) - ("coffee" nerd-icons-devicon "nf-dev-coffeescript" :face nerd-icons-maroon) - ("iced" nerd-icons-devicon "nf-dev-coffeescript" :face nerd-icons-lmaroon) - ("dart" nerd-icons-devicon "nf-dev-dart" :face nerd-icons-blue) - ("ledger" nerd-icons-mdicon "nf-md-file_table_box_multiple" :face nerd-icons-green) - ("rkt" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-red) - ("scrbl" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-blue) - ;; Stylesheeting - ("css" nerd-icons-devicon "nf-dev-css3" :face nerd-icons-yellow) - ("scss" nerd-icons-mdicon "nf-md-sass" :face nerd-icons-pink) - ("sass" nerd-icons-mdicon "nf-md-sass" :face nerd-icons-dpink) - ("less" nerd-icons-devicon "nf-dev-less" :face nerd-icons-dyellow) - ;; ("postcss" nerd-icons-devicon "postcss") TODO: postcss - ;; ("sss" nerd-icons-devicon "postcss") TODO: postcss - ("styl" nerd-icons-devicon "nf-dev-stylus" :face nerd-icons-lgreen) - ("csv" nerd-icons-octicon "nf-oct-graph" :face nerd-icons-dblue) - ;; haskell - ("hs" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - ("chs" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - ("lhs" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - ("hsc" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - ;; Web modes - ("inky-haml" nerd-icons-sucicon "nf-seti-haml" :face nerd-icons-lyellow) - ("haml" nerd-icons-sucicon "nf-seti-haml" :face nerd-icons-lyellow) - ("htm" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) - ("html" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) - ("inky-er" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) - ("inky-erb" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) - ("erb" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) - ;; ("hbs" nerd-icons-fileicon "moustache") TODO: moustache - ("inky-slim" nerd-icons-codicon "nf-cod-dashboard" :face nerd-icons-yellow) - ("slim" nerd-icons-codicon "nf-cod-dashboard" :face nerd-icons-yellow) - ("jade" nerd-icons-sucicon "nf-seti-jade" :face nerd-icons-red) - ("pug" nerd-icons-sucicon "nf-seti-pug" :face nerd-icons-red) - ;; Javascript - ;; ("d3js" nerd-icons-devicon "d3") TODO: d3 - ("re" nerd-icons-sucicon "nf-seti-reasonml" :face nerd-icons-red-alt) - ("rei" nerd-icons-sucicon "nf-seti-reasonml" :face nerd-icons-dred) - ("ml" nerd-icons-sucicon "nf-seti-ocaml" :face nerd-icons-lpink) - ("mli" nerd-icons-sucicon "nf-seti-ocaml" :face nerd-icons-dpink) - ("react" nerd-icons-devicon "nf-dev-react" :face nerd-icons-lblue) - ("ts" nerd-icons-sucicon "nf-seti-typescript" :face nerd-icons-blue-alt) - ("js" nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - ("es" nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - ("jsx" nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-cyan-alt) - ("tsx" nerd-icons-sucicon "nf-seti-typescript" :face nerd-icons-blue-alt) - ("njs" nerd-icons-mdicon "nf-md-nodejs" :face nerd-icons-lgreen) - ("vue" nerd-icons-sucicon "nf-seti-vue" :face nerd-icons-lgreen) - - ("sbt" nerd-icons-sucicon "nf-seti-sbt" :face nerd-icons-red) - ("scala" nerd-icons-devicon "nf-dev-scala" :face nerd-icons-red) - ("scm" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-red) - ("swift" nerd-icons-devicon "nf-dev-swift" :face nerd-icons-green) - - ("tcl" nerd-icons-mdicon "nf-md-feather" :face nerd-icons-dred) - ("exp" nerd-icons-mdicon "nf-md-feather" :face nerd-icons-dred) - - ("tf" nerd-icons-mdicon "nf-md-terraform" :face nerd-icons-purple-alt) - ("tfvars" nerd-icons-mdicon "nf-md-terraform" :face nerd-icons-purple-alt) - ("tfstate" nerd-icons-mdicon "nf-md-terraform" :face nerd-icons-purple-alt) - - ("asm" nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) - ;; Verilog(-AMS) and SystemVerilog(-AMS ;; Verilog(-AMS) and SystemVerilog(-AMS) - ("v" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - ("vams" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - ("sv" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - ("sva" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - ("svh" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - ("svams" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - ;; VHDL(-AMS ;; VHDL(-AMS) - ("vhd" nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) - ("vhdl" nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) - ("vhms" nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) - ;; Cabal - ;; ("cabal" nerd-icons-devicon "cabal") TODO: cabal - ;; Kotlin - ("kt" nerd-icons-sucicon "nf-seti-kotlin" :face nerd-icons-orange) - ("kts" nerd-icons-sucicon "nf-seti-kotlin" :face nerd-icons-orange) - ;; Nimrod - ("nim" nerd-icons-sucicon "nf-seti-nim" :face nerd-icons-yellow) - ("nims" nerd-icons-sucicon "nf-seti-nim" :face nerd-icons-yellow) - ;; SQL - ("sql" nerd-icons-octicon "nf-oct-database" :face nerd-icons-silver) - ;; Styles - ;; ("styles" nerd-icons-devicon "style") TODO: style - ;; Lua - ("lua" nerd-icons-sucicon "nf-seti-lua" :face nerd-icons-dblue) - ;; ASCII doc - ;; ("adoc" nerd-icons-devicon "asciidoc") TODO: asciidoc - ;; ("asciidoc" nerd-icons-devicon "asciidoc") TODO: asciidoc - ;; Puppet - ("pp" nerd-icons-sucicon "nf-seti-puppet" :face nerd-icons-yellow) - ;; Jinja - ("j2" nerd-icons-sucicon "nf-seti-jinja" :face nerd-icons-silver) - ("jinja2" nerd-icons-sucicon "nf-seti-jinja" :face nerd-icons-silver) - ;; Docker - ("dockerfile" nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-cyan) - ;; Vagrant - ;; ("vagrantfile" nerd-icons-fileicon "vagrant") TODO: vagrant - ;; GLSL - ("glsl" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-blue) - ("vert" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-blue) - ("tesc" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-purple) - ("tese" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-dpurple) - ("geom" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-green) - ("frag" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-red) - ("comp" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-dblue) - ;; CUDA - ("cu" nerd-icons-sucicon "nf-custom-c" :face nerd-icons-green) - ("cuh" nerd-icons-faicon "nf-fa-h_square" :face nerd-icons-green) - ;; Fortran - ("f90" nerd-icons-mdicon "nf-md-language_fortran" :face nerd-icons-purple) - ;; C# - ("cs" nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) - ("csx" nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) - ;; F# - ("fs" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) - ("fsi" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) - ("fsx" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) - ("fsscript" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) - ;; Godot / GDScript - ("gd" nerd-icons-sucicon "nf-seti-godot" :face nerd-icons-blue) - ("tscn" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) - ("tres" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) - ;; zig - ("zig" nerd-icons-sucicon "nf-seti-zig" :face nerd-icons-orange) - ;; odin - ;; ("odin" nerd-icons-fileicon "odin") TODO: odin - ;; File Types - ("ico" nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-blue) - ("png" nerd-icons-mdicon "nf-md-file_png_box" :face nerd-icons-orange) - ("gif" nerd-icons-mdicon "nf-md-file_gif_box" :face nerd-icons-green) - ("jpeg" nerd-icons-mdicon "nf-md-file_jpg_box" :face nerd-icons-dblue) - ("jpg" nerd-icons-mdicon "nf-md-file_jpg_box" :face nerd-icons-dblue) - ("webp" nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-dblue) - ("xpm" nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-dgreen) - ;; Audio - ("mp3" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("wav" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("m4a" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("ogg" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("flac" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("opus" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("au" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("aif" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("aifc" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("aiff" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) - ("svg" nerd-icons-sucicon "nf-seti-svg" :face nerd-icons-lgreen) - ;; Video - ("mov" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ("mp4" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ("ogv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-dblue) - ("mpg" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ("mpeg" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ("flv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ("ogv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-dblue) - ("mkv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ("webm" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) - ;; Fonts - ("ttf" nerd-icons-faicon "nf-fa-font" :face nerd-icons-dcyan) - ("woff" nerd-icons-faicon "nf-fa-font" :face nerd-icons-cyan) - ("woff2" nerd-icons-faicon "nf-fa-font" :face nerd-icons-cyan) - ;; Archives - ("iso" nerd-icons-mdicon "nf-md-disc" :face nerd-icons-orange) - ("tar" nerd-icons-mdicon "nf-md-zip_box" :face nerd-icons-orange) - ("rar" nerd-icons-mdicon "nf-md-zip_box" :face nerd-icons-orange) - ("tgz" nerd-icons-mdicon "nf-md-zip_box" :face nerd-icons-orange) - ("jar" nerd-icons-devicon "nf-dev-java" :face nerd-icons-dpurple) - ;; Doc - ("pdf" nerd-icons-codicon "nf-cod-file_pdf" :face nerd-icons-dred) - ("text" nerd-icons-faicon "nf-fa-file_text" :face nerd-icons-cyan) - ("txt" nerd-icons-faicon "nf-fa-file_text" :face nerd-icons-cyan) - ("doc" nerd-icons-mdicon "nf-md-file_word" :face nerd-icons-blue) - ("docx" nerd-icons-mdicon "nf-md-file_word" :face nerd-icons-blue) - ("docm" nerd-icons-mdicon "nf-md-file_word" :face nerd-icons-blue) - ("texi" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - ("tex" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - ("ltx" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - ("dtx" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - ("sty" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - ("md" nerd-icons-octicon "nf-oct-markdown" :face nerd-icons-lblue) - ("bib" nerd-icons-mdicon "nf-md-book" :face nerd-icons-lblue) - ("org" nerd-icons-sucicon "nf-custom-orgmode" :face nerd-icons-lgreen) - ("org_archive" nerd-icons-sucicon "nf-custom-orgmode" :face nerd-icons-lgreen) - ("pps" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) - ("ppt" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) - ("pptx" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) - ("pptsx" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) - ("ppttx" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) - ("knt" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-cyan) - ("xlsx" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) - ("xlsm" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) - ("xlsb" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) - ("xltx" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) - ("xltm" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) - ("epub" nerd-icons-mdicon "nf-md-book_open" :face nerd-icons-green) - ("ly" nerd-icons-faicon "nf-fa-music" :face nerd-icons-green) - ;; - ("key" nerd-icons-octicon "nf-oct-key" :face nerd-icons-lblue) - ("pem" nerd-icons-octicon "nf-oct-key" :face nerd-icons-orange) - ("p12" nerd-icons-octicon "nf-oct-key" :face nerd-icons-dorange) - ("crt" nerd-icons-octicon "nf-oct-key" :face nerd-icons-lblue) - ("pub" nerd-icons-octicon "nf-oct-key" :face nerd-icons-blue) - ("gpg" nerd-icons-octicon "nf-oct-key" :face nerd-icons-lblue) - ("kdbx" nerd-icons-octicon "nf-oct-key" :face nerd-icons-green) - ("cache" nerd-icons-octicon "nf-oct-database" :face nerd-icons-green) - ;; backup - ("backup" nerd-icons-mdicon "nf-md-file_restore" :face nerd-icons-lblue) - ("old" nerd-icons-mdicon "nf-md-file_restore" :face nerd-icons-lblue) - ("bak" nerd-icons-mdicon "nf-md-file_restore" :face nerd-icons-lblue))) - -(defvar nerd-icons-regexp-icon-alist - '( - ;; - ("^TAGS$" nerd-icons-octicon "nf-oct-tag" :face nerd-icons-blue) - ("^TODO$" nerd-icons-octicon "nf-oct-checklist" :face nerd-icons-lyellow) - ("^LICENSE$" nerd-icons-octicon "nf-oct-book" :face nerd-icons-blue) - ("^readme" nerd-icons-octicon "nf-oct-book" :face nerd-icons-lcyan) - - ;; Config - ("nginx$" nerd-icons-devicon "nf-dev-nginx" :face nerd-icons-dgreen) - ;; ("apache$" nerd-icons-alltheicon "apache") TODO: apache - - ;; C - ("^Makefile$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-dorange) - ("^CMakeLists.txt$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-red) ;; TODO: cmake - ("^CMakeCache.txt$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-blue) ;; TODO: cmakecache - ("^meson.build$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-purple) ;; TODO: meson - ("^meson_options.txt$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-purple) ;; TODO: meson - - ;; Docker - ("^\\.?Dockerfile" nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-blue) - - ;; Homebrew - ("^Brewfile$" nerd-icons-faicon "nf-fa-beer" :face nerd-icons-lsilver) - - ;; ;; AWS - ("^stack.*.json$" nerd-icons-devicon "nf-dev-aws" :face nerd-icons-orange) - ("^serverless\\.yml$" nerd-icons-faicon "nf-fa-bolt" :face nerd-icons-yellow) - - ;; lock files - ("~$" nerd-icons-octicon "nf-oct-lock" :face nerd-icons-maroon) - - ;; Source Codes - ("^mix.lock$" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lyellow) - - ;; Ruby - ("^Gemfile\\(\\.lock\\)?$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-red) - ("_?test\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-red) - ("_?test_helper\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-dred) - ("_?spec\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-red) - ("_?spec_helper\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-dred) - - ("-?spec\\.ts$" nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue) - ("-?test\\.ts$" nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue) - ("-?spec\\.js$" nerd-icons-mdicon "nf-md-language_javascript" :face nerd-icons-lpurple) - ("-?test\\.js$" nerd-icons-mdicon "nf-md-language_javascript" :face nerd-icons-lpurple) - ("-?spec\\.jsx$" nerd-icons-mdicon "nf-md-react" :face nerd-icons-blue-alt) - ("-?test\\.jsx$" nerd-icons-mdicon "nf-md-react" :face nerd-icons-blue-alt) - - ;; Git - ("^MERGE_" nerd-icons-octicon "nf-oct-git_merge" :face nerd-icons-red) - ("^COMMIT_EDITMSG" nerd-icons-octicon "nf-oct-git_commit" :face nerd-icons-red) - - ;; Stylesheeting - ("^stylelint" nerd-icons-sucicon "nf-seti-stylelint" :face nerd-icons-lyellow) - - ;; JavaScript - ("^package.json$" nerd-icons-devicon "nf-dev-npm" :face nerd-icons-red) - ("^package.lock.json$" nerd-icons-devicon "nf-dev-npm" :face nerd-icons-dred) - ("^yarn\\.lock" nerd-icons-sucicon "nf-seti-yarn" :face nerd-icons-blue-alt) - ("\\.npmignore$" nerd-icons-devicon "nf-dev-npm" :face nerd-icons-dred) - ("^bower.json$" nerd-icons-devicon "nf-dev-bower" :face nerd-icons-lorange) - ("^gulpfile" nerd-icons-devicon "nf-dev-gulp" :face nerd-icons-lred) - ("^gruntfile" nerd-icons-devicon "nf-dev-grunt" :face nerd-icons-lyellow) - ("^webpack" nerd-icons-mdicon "nf-md-webpack" :face nerd-icons-lblue) - - ;; Go - ("^go.mod$" nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) - ("^go.work$" nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) - - ;; Groovy - ("Jenkinsfile\\'" nerd-icons-devicon "nf-dev-groovy" :face nerd-icons-cyan-alt) - - ;; Emacs - ("^bookmark" nerd-icons-octicon "nf-oct-bookmark" :face nerd-icons-lpink) - - ("^\\*scratch\\*$" nerd-icons-faicon "nf-fa-sticky_note" :face nerd-icons-lyellow) - ("^\\*scratch.*" nerd-icons-faicon "nf-fa-sticky_note" :face nerd-icons-yellow) - ("^\\*new-tab\\*$" nerd-icons-mdicon "nf-md-star" :face nerd-icons-cyan) - ("Cask\\'" nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) - ("Eask\\'" nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) - - ("^\\." nerd-icons-octicon "nf-oct-gear"))) - -(defvar nerd-icons-default-file-icon - '(nerd-icons-faicon "nf-fa-file_o")) - -(defvar nerd-icons-dir-icon-alist - '( - ("trash" nerd-icons-faicon "nf-fa-trash_o") - ("dropbox" nerd-icons-faicon "nf-fa-dropbox") - ("google[ _-]drive" nerd-icons-mdicon "nf-md-folder_google_drive") - ("github" nerd-icons-sucicon "nf-custom-folder_github") - ("^atom$" nerd-icons-devicon "nf-dev-atom") - ("documents" nerd-icons-mdicon "nf-md-folder_file") - ("download" nerd-icons-mdicon "nf-md-folder_download") - ("desktop" nerd-icons-octicon "nf-oct-device_desktop") - ("pictures" nerd-icons-mdicon "nf-md-folder_image") - ("photos" nerd-icons-faicon "nf-fa-camera_retro") - ("music" nerd-icons-mdicon "nf-md-folder_music") - ("movies" nerd-icons-faicon "nf-fa-film") - ("code" nerd-icons-octicon "nf-oct-code") - ("workspace" nerd-icons-octicon "nf-oct-code") - ;; ("test" nerd-icons-devicon "test-dir") - ("\\.git" nerd-icons-sucicon "nf-custom-folder_git") - ("\\.config" nerd-icons-sucicon "nf-custom-folder_config") - (".?" nerd-icons-sucicon "nf-custom-folder_oct"))) - -(defvar nerd-icons-weather-icon-alist - '( - ("tornado" nerd-icons-wicon "nf-weather-tornado") - ("hurricane" nerd-icons-wicon "nf-weather-hurricane") - ("thunderstorms" nerd-icons-wicon "nf-weather-thunderstorm") - ("sunny" nerd-icons-wicon "nf-weather-day_sunny") - ("rain.*snow" nerd-icons-wicon "nf-weather-rain_mix") - ("rain.*hail" nerd-icons-wicon "nf-weather-rain_mix") - ("sleet" nerd-icons-wicon "nf-weather-sleet") - ("hail" nerd-icons-wicon "nf-weather-hail") - ("drizzle" nerd-icons-wicon "nf-weather-sprinkle") - ("rain" nerd-icons-wicon "nf-weather-showers") - ("showers" nerd-icons-wicon "nf-weather-showers") - ("blowing.*snow" nerd-icons-wicon "nf-weather-snow_wind") - ("snow" nerd-icons-wicon "nf-weather-snow") - ("dust" nerd-icons-wicon "nf-weather-dust") - ("fog" nerd-icons-wicon "nf-weather-fog") - ("haze" nerd-icons-wicon "nf-weather-day_haze") - ("smoky" nerd-icons-wicon "nf-weather-smoke") - ("blustery" nerd-icons-wicon "nf-weather-cloudy_windy") - ("windy" nerd-icons-wicon "nf-weather-cloudy_gusts") - ("cold" nerd-icons-wicon "nf-weather-snowflake_cold") - ("partly.*cloudy.*night" nerd-icons-wicon "nf-weather-night_alt_partly_cloudy") - ("partly.*cloudy" nerd-icons-wicon "nf-weather-day_cloudy_high") - ("cloudy.*night" nerd-icons-wicon "nf-weather-night_alt_cloudy") - ("cxloudy.*day" nerd-icons-wicon "nf-weather-day_cloudy") - ("cloudy" nerd-icons-wicon "nf-weather-cloudy") - ("clear.*night" nerd-icons-wicon "nf-weather-night_clear") - ("fair.*night" nerd-icons-wicon "nf-weather-stars") - ("fair.*day" nerd-icons-wicon "nf-weather-horizon") - ("hot" nerd-icons-wicon "nf-weather-hot") - ("not.*available" nerd-icons-wicon "nf-weather-na"))) - -(defvar nerd-icons-mode-icon-alist - '( - (emacs-lisp-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple) - (circe-server-mode nerd-icons-faicon "nf-fa-commenting_o") - (circe-channel-mode nerd-icons-faicon "nf-fa-commenting_o") - (circe-query-mode nerd-icons-faicon "nf-fa-commenting_o") - (crystal-mode nerd-icons-sucicon "nf-custom-crystal" :face nerd-icons-yellow) - (erc-mode nerd-icons-faicon "nf-fa-commenting_o") - (inferior-emacs-lisp-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-lblue) - (dired-mode nerd-icons-octicon "nf-oct-file_directory") - (lisp-interaction-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-orange) - (sly-mrepl-mode nerd-icons-sucicon "nf-custom-common_lisp" :face nerd-icons-orange) - (slime-repl-mode nerd-icons-sucicon "nf-custom-common_lisp" :face nerd-icons-orange) - (org-mode nerd-icons-sucicon "nf-custom-orgmode" :face nerd-icons-lgreen) - (ledger-mode nerd-icons-mdicon "nf-md-file_table_box_multiple" :face nerd-icons-green) - (typescript-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) - (typescript-ts-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) - (typescript-tsx-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) - (tsx-ts-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) - (js-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - (js-ts-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - (js-jsx-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - (js2-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - (js3-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) - (rjsx-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-cyan-alt) - (term-mode nerd-icons-devicon "nf-dev-terminal") - (vterm-mode nerd-icons-devicon "nf-dev-terminal") - (eshell-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) - (magit-refs-mode nerd-icons-devicon "nf-dev-git_branch" :face nerd-icons-red) - (magit-process-mode nerd-icons-octicon "nf-oct-mark_github") - (magit-diff-mode nerd-icons-devicon "nf-dev-git_compare" :face nerd-icons-lblue) - (ediff-mode nerd-icons-devicon "nf-dev-git_compare" :face nerd-icons-red) - (diff-mode nerd-icons-devicon "nf-dev-git_compare" :face nerd-icons-lred) - (comint-mode nerd-icons-faicon "nf-fa-terminal" :face nerd-icons-lblue) - (eww-mode nerd-icons-faicon "nf-fa-firefox" :face nerd-icons-red) - (xwidget-webkit-mode nerd-icons-faicon "nf-fa-chrome" :face nerd-icons-blue) - (org-agenda-mode nerd-icons-octicon "nf-oct-checklist" :face nerd-icons-lgreen) - (cfw:calendar-mode nerd-icons-octicon "nf-oct-calendar") - (ibuffer-mode nerd-icons-faicon "nf-fa-files_o" :face nerd-icons-dsilver) - (messages-buffer-mode nerd-icons-faicon "nf-fa-file_o" :face nerd-icons-dsilver) - (help-mode nerd-icons-faicon "nf-fa-info" :face nerd-icons-purple) - (helpful-mode nerd-icons-faicon "nf-fa-info" :face nerd-icons-purple) - (Info-mode nerd-icons-faicon "nf-fa-info" :face nerd-icons-blue) - (benchmark-init/tree-mode nerd-icons-faicon "nf-fa-dashboard") - (jenkins-mode nerd-icons-devicon "nf-dev-jenkins" :face nerd-icons-blue) - (magit-popup-mode nerd-icons-sucicon "nf-seti-git" :face nerd-icons-red) - (magit-status-mode nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) - (magit-log-mode nerd-icons-sucicon "nf-seti-git" :face nerd-icons-green) - (mu4e-compose-mode nerd-icons-octicon "nf-oct-pencil") - (mu4e-headers-mode nerd-icons-octicon "nf-oct-mail") - (mu4e-main-mode nerd-icons-octicon "nf-oct-mail") - (mu4e-view-mode nerd-icons-codicon "nf-cod-mail_read") - (sieve-mode nerd-icons-octicon "nf-oct-mail") - (gnus-group-mode nerd-icons-octicon "nf-oct-mail") - (gnus-summary-mode nerd-icons-octicon "nf-oct-mail") - (gnus-article-mode nerd-icons-codicon "nf-cod-mail_read") - (message-mode nerd-icons-octicon "nf-oct-pencil") - (package-menu-mode nerd-icons-faicon "nf-fa-archive" :face nerd-icons-silver) - (paradox-menu-mode nerd-icons-faicon "nf-fa-archive" :face nerd-icons-silver) - (Custom-mode nerd-icons-codicon "nf-cod-settings") - - ;; Special matcher for Web Mode based on the `web-mode-content-type' of the current buffer - (web-mode nerd-icons--web-mode-icon) - - (fundamental-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-dsilver) - (special-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-yellow) - (cask-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) - (eask-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) - (text-mode nerd-icons-faicon "nf-fa-file_text" :face nerd-icons-cyan) - (enh-ruby-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-lred) - (ruby-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-lred) - (ruby-ts-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-lred) - (inf-ruby-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) - (projectile-rails-compilation-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) - (rspec-compilation-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) - (rake-compilation-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) - (sh-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) - (bash-ts-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) - (shell-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) - (fish-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-lpink) - (bat-mode nerd-icons-codicon "nf-cod-terminal_cmd" :face nerd-icons-lsilver) - (nginx-mode nerd-icons-devicon "nf-dev-nginx" :face nerd-icons-dgreen) - ;; (apache-mode nerd-icons-alltheicon "apache" :face nerd-icons-dgreen) - (makefile-mode nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-dorange) - (makefile-ts-mode nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-dorange) - ;; (cmake-mode nerd-icons-fileicon "cmake" :face nerd-icons-red) - ;; (cmake-ts-mode nerd-icons-fileicon "cmake" :face nerd-icons-red) - (dockerfile-mode nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-blue) - (dockerfile-ts-mode nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-blue) - (docker-compose-mode nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-lblue) - (nxml-mode nerd-icons-faicon "nf-fa-file_code_o" :face nerd-icons-lorange) - (conf-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-lyellow) - (json-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - (json-ts-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - (jsonian-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) - (yaml-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) - (yaml-ts-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) - (toml-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) - (toml-ts-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) - (elisp-byte-code-mode nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) - (archive-mode nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) - (elm-mode nerd-icons-sucicon "nf-custom-elm" :face nerd-icons-blue) - (erlang-mode nerd-icons-devicon "nf-dev-erlang" :face nerd-icons-red) - (elixir-mode nerd-icons-sucicon "nf-custom-elixir" :face nerd-icons-lorange) - (elixir-ts-mode nerd-icons-sucicon "nf-custom-elixir" :face nerd-icons-lorange) - (java-mode nerd-icons-devicon "nf-dev-java" :face nerd-icons-purple) - (groovy-mode nerd-icons-devicon "nf-dev-groovy" :face nerd-icons-cyan) - (java-ts-mode nerd-icons-devicon "nf-dev-java" :face nerd-icons-purple) - (go-mode nerd-icons-devicon "nf-dev-go" :face nerd-icons-blue) - (go-ts-mode nerd-icons-devicon "nf-dev-go" :face nerd-icons-blue) - (go-dot-mod-mode nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) - (go-mod-ts-mode nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) - (go-dot-work-mode nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) - (graphql-mode nerd-icons-sucicon "nf-seti-graphql" :face nerd-icons-dpink) - ;; (matlab-mode nerd-icons-fileicon "matlab" :face nerd-icons-orange) - (nix-mode nerd-icons-mdicon "nf-md-nix" :face nerd-icons-blue) - (perl-mode nerd-icons-devicon "nf-dev-perl" :face nerd-icons-lorange) - (cperl-mode nerd-icons-devicon "nf-dev-perl" :face nerd-icons-lorange) - (php-mode nerd-icons-devicon "nf-dev-php" :face nerd-icons-lsilver) - (php-ts-mode nerd-icons-devicon "nf-dev-php" :face nerd-icons-lsilver) - (prolog-mode nerd-icons-devicon "nf-dev-prolog" :face nerd-icons-lmaroon) - (python-mode nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) - (python-ts-mode nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) - (inferior-python-mode nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) - ;; (racket-mode nerd-icons-fileicon "racket" :face nerd-icons-red) - (rust-mode nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) - (rustic-mode nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) - (rust-ts-mode nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) - (scala-mode nerd-icons-devicon "nf-dev-scala" :face nerd-icons-red) - ;; (scheme-mode nerd-icons-fileicon "scheme" :face nerd-icons-red) - (swift-mode nerd-icons-devicon "nf-dev-swift" :face nerd-icons-green) - (svelte-mode nerd-icons-sucicon "nf-seti-svelte" :face nerd-icons-red) - (ada-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) - (ada-ts-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) - (gpr-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) - (gpr-ts-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) - (c-mode nerd-icons-sucicon "nf-custom-c" :face nerd-icons-blue) - (c-ts-mode nerd-icons-sucicon "nf-custom-c" :face nerd-icons-blue) - (c++-mode nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) - (c++-ts-mode nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) - (csharp-mode nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) - (csharp-ts-mode nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) - (clojure-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-blue) - (clojure-ts-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-blue) - (cider-repl-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-green) - (clojurec-mode nerd-icons-sucicon "nf-seti-clojure" :face nerd-icons-blue) - (clojurec-ts-mode nerd-icons-sucicon "nf-seti-clojure" :face nerd-icons-blue) - (clojurescript-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-lyellow) - (clojurescript-ts-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-lyellow) - (coffee-mode nerd-icons-devicon "nf-dev-coffeescript" :face nerd-icons-maroon) - (lisp-mode nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-orange) - (css-mode nerd-icons-devicon "nf-dev-css3" :face nerd-icons-yellow) - (css-ts-mode nerd-icons-devicon "nf-dev-css3" :face nerd-icons-yellow) - (scss-mode nerd-icons-mdicon "nf-md-sass" :face nerd-icons-pink) - (sass-mode nerd-icons-mdicon "nf-md-sass" :face nerd-icons-dpink) - (less-css-mode nerd-icons-devicon "nf-dev-less" :face nerd-icons-dyellow) - (stylus-mode nerd-icons-devicon "nf-dev-stylus" :face nerd-icons-lgreen) - (csv-mode nerd-icons-octicon "nf-oct-graph" :face nerd-icons-dblue) - (gdscript-mode nerd-icons-sucicon "nf-seti-godot" :face nerd-icons-blue) - (gdscript-ts-mode nerd-icons-sucicon "nf-seti-godot" :face nerd-icons-blue) - (haskell-mode nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - (haskell-c2hs-mode nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - (literate-haskell-mode nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) - (haml-mode nerd-icons-sucicon "nf-seti-haml" :face nerd-icons-lyellow) - (html-mode nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) - (html-ts-mode nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) - (rhtml-mode nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) - ;; (mustache-mode nerd-icons-fileicon "moustache" :face nerd-icons-green) - (slim-mode nerd-icons-codicon "nf-cod-dashboard" :face nerd-icons-yellow) - (jade-mode nerd-icons-sucicon "nf-seti-jade" :face nerd-icons-red) - (pug-mode nerd-icons-sucicon "nf-seti-pug" :face nerd-icons-red) - (react-mode nerd-icons-devicon "nf-dev-react" :face nerd-icons-lblue) - (image-mode nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-blue) - (texinfo-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (markdown-mode nerd-icons-octicon "nf-oct-markdown" :face nerd-icons-lblue) - (markdown-ts-mode nerd-icons-octicon "nf-oct-markdown" :face nerd-icons-lblue) - ;; (bibtex-mode nerd-icons-fileicon "bib" :face nerd-icons-maroon) - (compilation-mode nerd-icons-faicon "nf-fa-cogs") - (objc-mode nerd-icons-faicon "nf-fa-apple") - (tuareg-mode nerd-icons-sucicon "nf-seti-ocaml") - (purescript-mode nerd-icons-sucicon "nf-seti-purescript") - (verilog-mode nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - (verilog-ts-mode nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) - (vhdl-mode nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) - (vhdl-ts-mode nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) - ;; (haskell-cabal-mode nerd-icons-fileicon "cabal" :face nerd-icons-lblue) - (kotlin-mode nerd-icons-sucicon "nf-custom-kotlin" :face nerd-icons-orange) - (kotlin-ts-mode nerd-icons-sucicon "nf-custom-kotlin" :face nerd-icons-orange) - (nim-mode nerd-icons-sucicon "nf-seti-nim" :face nerd-icons-yellow) - (sql-mode nerd-icons-devicon "nf-dev-database" :face nerd-icons-silver) - (lua-mode nerd-icons-sucicon "nf-seti-lua" :face nerd-icons-dblue) - (lua-ts-mode nerd-icons-sucicon "nf-seti-lua" :face nerd-icons-dblue) - ;; (adoc-mode nerd-icons-fileicon "asciidoc" :face nerd-icons-lblue) - (puppet-mode nerd-icons-sucicon "nf-custom-puppet" :face nerd-icons-yellow) - (jinja2-mode nerd-icons-sucicon "nf-seti-jinja" :face nerd-icons-silver) - (powershell-mode nerd-icons-mdicon "nf-md-powershell" :face nerd-icons-blue) - (tex-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (latex-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (latex-ts-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (doctex-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - ;; Modes provided by AUCTeX 14.1 and higher - (TeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (LaTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (docTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (ConTeXt-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (AmSTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (plain-TeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (Texinfo-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (japanese-plain-TeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (japanese-LaTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) - (dart-mode nerd-icons-devicon "nf-dev-dart" :face nerd-icons-blue) - (fsharp-mode nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue) - (asm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) - (fasm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) - (masm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) - (nasm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) - (gas-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) - ;; (tcl-mode nerd-icons-fileicon "tcl" :face nerd-icons-dred) - ;; (cuda-mode nerd-icons-fileicon "nvidia" :face nerd-icons-green) - (f90-mode nerd-icons-mdicon "nf-md-language_fortran" :face nerd-icons-purple) - ;; (hy-mode nerd-icons-fileicon "hy" :face nerd-icons-blue) - (glsl-mode nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-green) - (zig-mode nerd-icons-sucicon "nf-seti-zig" :face nerd-icons-orange) - ;; (odin-mode nerd-icons-fileicon "odin" :face nerd-icons-lblue) - (pdf-view-mode nerd-icons-codicon "nf-cod-file_pdf" :face nerd-icons-dred) - (doc-view-mode nerd-icons-mdicon "nf-md-file_document" :face nerd-icons-lred) - (calibre-library-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-dblue) - (calibre-edit-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lred) - (calibredb-search-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-dblue) - (calibredb-show-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lblue) - (osm-mode nerd-icons-mdicon "nf-md-map_search" :face nerd-icons-lgreen) - (spacemacs-buffer-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple) - - (elfeed-search-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-orange) - (elfeed-summary-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-orange) - (elfeed-show-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-yellow) - (newsticker-treeview-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-orange) - (newsticker-treeview-list-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-lorange) - (newsticker-treeview-item-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-yellow) - - (emms-browser-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (emms-lyrics-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (emms-show-all-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (emms-metaplaylist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (emms-tag-editor-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (emms-playlist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (lilypond-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-green) - (bongo-playlist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (bongo-library-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (mingus-playlist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (mingus-help-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (mingus-browse-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (mingus-burn-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (simple-mpc-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) - (telega-root-mode nerd-icons-faicon "nf-fae-telegram" :face nerd-icons-purple) - (telega-chat-mode nerd-icons-faicon "nf-fae-telegram" :face nerd-icons-blue) - (mastodon-mode nerd-icons-mdicon "nf-md-mastodon" :face nerd-icons-blue) - - (fanyi-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lcyan) - (osx-dictionary-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lcyan) - (youdao-dictionary-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lcyan) - - (magik-mode nerd-icons-faicon "nf-fa-magic" :face nerd-icons-blue) - (magik-ts-mode nerd-icons-faicon "nf-fa-magic" :face nerd-icons-blue) - (magik-session-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-blue) - (magik-cb-mode nerd-icons-faicon "nf-fa-book" :face nerd-icons-blue) - ;; (meson-mode nerd-icons-fileicon "meson" :face nerd-icons-purple) - ;; (man-common nerd-icons-fileicon "man-page" :face nerd-icons-blue) - (heex-mode nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) - (heex-ts-mode nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) - (julia-mode nerd-icons-sucicon "nf-seti-julia" :face nerd-icons-purple) - (julia-ts-mode nerd-icons-sucicon "nf-seti-julia" :face nerd-icons-purple) - (flycheck-error-list nerd-icons-faicon "nf-fa-list_alt" :face nerd-icons-lred))) - -(defvar nerd-icons-url-alist - '( - ;; Social media and communities - ("^\\(https?://\\)?\\(www\\.\\)?del\\.icio\\.us" nerd-icons-faicon "nf-fa-delicious") - ("^\\(https?://\\)?\\(www\\.\\)?behance\\.net" nerd-icons-faicon "nf-fa-behance") - ("^\\(https?://\\)?\\(www\\.\\)?dribbble\\.com" nerd-icons-faicon "nf-fa-dribbble") - ("^\\(https?://\\)?\\(www\\.\\)?facebook\\.com" nerd-icons-faicon "nf-fa-facebook_official") - ("^\\(https?://\\)?\\(www\\.\\)?glide\\.me" nerd-icons-faicon "nf-fa-glide_g") - ("^\\(https?://\\)?\\(www\\.\\)?plus\\.google\\.com" nerd-icons-faicon "nf-fa-google_plus") - ("linkedin\\.com" nerd-icons-faicon "nf-fa-linkedin") - ("^\\(https?://\\)?\\(www\\.\\)?ok\\.ru" nerd-icons-faicon "nf-fa-odnoklassniki") - ("^\\(https?://\\)?\\(www\\.\\)?reddit\\.com" nerd-icons-faicon "nf-fa-reddit_alien") - ("^\\(https?://\\)?\\(www\\.\\)?slack\\.com" nerd-icons-faicon "nf-fa-slack") - ("^\\(https?://\\)?\\(www\\.\\)?snapchat\\.com" nerd-icons-faicon "nf-fa-snapchat_ghost") - ("^\\(https?://\\)?\\(www\\.\\)?weibo\\.com" nerd-icons-faicon "nf-fa-weibo") - ("^\\(https?://\\)?\\(www\\.\\)?twitter\\.com" nerd-icons-faicon "nf-fa-twitter") - ;; Blogging - ("joomla\\.org" nerd-icons-faicon "nf-fa-joomla") - ("^\\(https?://\\)?\\(www\\.\\)?medium\\.com" nerd-icons-faicon "nf-fa-medium") - ("tumblr\\.com" nerd-icons-faicon "nf-fa-tumblr") - ("^wordpress\\.com" nerd-icons-faicon "nf-fa-wordpress") - ;; Programming - ("^\\(https?://\\)?\\(www\\.\\)?bitbucket\\.org" nerd-icons-faicon "nf-fa-bitbucket") - ("^\\(https?://\\)?\\(www\\.\\)?codepen\\.io" nerd-icons-faicon "nf-fa-codepen") - ("^\\(https?://\\)?\\(www\\.\\)?codiepie\\.com" nerd-icons-faicon "nf-fa-codiepie") - ("^\\(https?://\\)?\\(www\\.\\)?gist\\.github\\.com" nerd-icons-octicon "nf-oct-logo_gist") - ("^\\(https?://\\)?\\(www\\.\\)?github\\.com" nerd-icons-octicon "nf-oct-mark_github") - ("^\\(https?://\\)?\\(www\\.\\)?gitlab\\.com" nerd-icons-faicon "nf-fa-gitlab") - ("^\\(https?://\\)?\\(www\\.\\)?news\\.ycombinator\\.com" nerd-icons-faicon "nf-fa-hacker_news") - ("^\\(https?://\\)?\\(www\\.\\)?jsfiddle\\.net" nerd-icons-faicon "nf-fa-jsfiddle") - ("^\\(https?://\\)?\\(www\\.\\)?maxcdn\\.com" nerd-icons-faicon "nf-fa-maxcdn") - ("^\\(https?://\\)?\\(www\\.\\)?stackoverflow\\.com" nerd-icons-faicon "nf-fa-stack_overflow") - ;; Video - ("^\\(https?://\\)?\\(www\\.\\)?twitch\\.tv" nerd-icons-faicon "nf-fa-twitch") - ("^\\(https?://\\)?\\(www\\.\\)?vimeo\\.com" nerd-icons-faicon "nf-fa-vimeo") - ("^\\(https?://\\)?\\(www\\.\\)?youtube\\.com" nerd-icons-faicon "nf-fa-youtube") - ("^\\(https?://\\)?\\(www\\.\\)?youtu\\.be" nerd-icons-faicon "nf-fa-youtube") - ("^\\(https?://\\)?\\(www\\.\\)?vine\\.co" nerd-icons-faicon "nf-fa-vine") - ;; Sound - ("^\\(https?://\\)?\\(www\\.\\)?last\\.fm" nerd-icons-faicon "nf-fa-lastfm") - ("^\\(https?://\\)?\\(www\\.\\)?mixcloud\\.com" nerd-icons-faicon "nf-fa-mixcloud") - ("^\\(https?://\\)?\\(www\\.\\)?soundcloud\\.com" nerd-icons-faicon "nf-fa-soundcloud") - ("spotify\\.com" nerd-icons-faicon "nf-fa-spotify") - ;; Shopping - ("^\\(https?://\\)?\\(www\\.\\)?amazon\\." nerd-icons-faicon "nf-fa-amazon") - ("^\\(https?://\\)?\\(www\\.\\)?opencart\\.com" nerd-icons-faicon "nf-fa-opencart") - ("^\\(https?://\\)?\\(www\\.\\)?paypal\\.com" nerd-icons-faicon "nf-fa-paypal") - ("^\\(https?://\\)?\\(www\\.\\)?shirtsinbulk\\.com" nerd-icons-faicon "nf-fa-shitsinbulk") - ;; Images - ("^\\(https?://\\)?\\(www\\.\\)?500px\\.com" nerd-icons-faicon "nf-fa-500px") - ("^\\(https?://\\)?\\(www\\.\\)?deviantart\\.com" nerd-icons-faicon "nf-fa-deviantart") - ("^\\(https?://\\)?\\(www\\.\\)?flickr\\.com" nerd-icons-faicon "nf-fa-flickr") - ("^\\(https?://\\)?\\(www\\.\\)?instagram\\.com" nerd-icons-faicon "nf-fa-instagram") - ("^\\(https?://\\)?\\(www\\.\\)?pinterest\\." nerd-icons-faicon "nf-fa-pinterest") - ;; Information and books - ("^\\(https?://\\)?\\(www\\.\\)?digg\\.com" nerd-icons-faicon "nf-fa-digg") - ("^\\(https?://\\)?\\(www\\.\\)?foursquare\\.com" nerd-icons-faicon "nf-fa-foursquare") - ("^\\(https?://\\)?\\(www\\.\\)?getpocket\\.com" nerd-icons-faicon "nf-fa-get_pocket") - ("^\\(https?://\\)?\\(www\\.\\)?scribd\\.com" nerd-icons-faicon "nf-fa-scribd") - ("^\\(https?://\\)?\\(www\\.\\)?slideshare\\.net" nerd-icons-faicon "nf-fa-slideshare") - ("stackexchange\\.com" nerd-icons-faicon "nf-fa-stack_exchange") - ("^\\(https?://\\)?\\(www\\.\\)?stumbleupon\\.com" nerd-icons-faicon "nf-fa-stumbleupon") - ("^\\(https?://\\)?\\(www\\.\\)?tripadvisor\\." nerd-icons-faicon "nf-fa-tripadvisor") - ("^\\(https?://\\)?\\(www\\.\\)?yelp\\." nerd-icons-faicon "nf-fa-yelp") - - ("wikipedia\\.org" nerd-icons-faicon "nf-fa-wikipedia_w") - ;; Various companies and tools - ("^\\(https?://\\)?\\(www\\.\\)?angel\\.co" nerd-icons-faicon "nf-fa-angellist") - ("^\\(https?://\\)?\\(www\\.\\)?apple\\.com" nerd-icons-faicon "nf-fa-apple") - ("^\\(https?://\\)?\\(www\\.\\)?buysellads\\.com" nerd-icons-faicon "nf-fa-buysellads") - ("^\\(https?://\\)?\\(www\\.\\)?connectdevelop\\.com" nerd-icons-faicon "nf-fa-connectdevelop") - ("^\\(https?://\\)?\\(www\\.\\)?dashcube\\.com" nerd-icons-faicon "nf-fa-dashcube") - ("^\\(https?://\\)?\\(www\\.\\)?dropbox\\.com" nerd-icons-faicon "nf-fa-dropbox") - ("^\\(https?://\\)?\\(www\\.\\)?enviragallery\\.com" nerd-icons-faicon "nf-fa-envira") - ("^\\(https?://\\)?\\(www\\.\\)?fortawesome\\.com" nerd-icons-faicon "nf-fa-fort_awesome") - ("^\\(https?://\\)?\\(www\\.\\)?forumbee\\.com" nerd-icons-faicon "nf-fa-forumbee") - ("^\\(https?://\\)?\\(www\\.\\)?gratipay\\.com" nerd-icons-faicon "nf-fa-gratipay") - ("^\\(https?://\\)?\\(www\\.\\)?modx\\.com" nerd-icons-faicon "nf-fa-modx") - ("^\\(https?://\\)?\\(www\\.\\)?pagelines\\.com" nerd-icons-faicon "nf-fa-pagelines") - ("^\\(https?://\\)?\\(www\\.\\)?producthunt\\.com" nerd-icons-faicon "nf-fa-product_hunt") - ("sellsy\\.com" nerd-icons-faicon "nf-fa-sellsy") - ("^\\(https?://\\)?\\(www\\.\\)?simplybuilt\\.com" nerd-icons-faicon "nf-fa-simplybuilt") - ("^\\(https?://\\)?\\(www\\.\\)?skyatlas\\.com" nerd-icons-faicon "nf-fa-skyatlas") - ("^\\(https?://\\)?\\(www\\.\\)?skype\\.com" nerd-icons-faicon "nf-fa-skype") - ("steampowered\\.com" nerd-icons-faicon "nf-fa-steam") - ("^\\(https?://\\)?\\(www\\.\\)?themeisle\\.com" nerd-icons-faicon "nf-fa-themeisle") - ("^\\(https?://\\)?\\(www\\.\\)?trello\\.com" nerd-icons-faicon "nf-fa-trello") - ("^\\(https?://\\)?\\(www\\.\\)?whatsapp\\.com" nerd-icons-faicon "nf-fa-whatsapp") - ("^\\(https?://\\)?\\(www\\.\\)?ycombinator\\.com" nerd-icons-faicon "nf-fa-y_combinator") - ("yahoo\\.com" nerd-icons-faicon "nf-fa-yahoo") - ("^\\(https?://\\)?\\(www\\.\\)?yoast\\.com" nerd-icons-faicon "nf-fa-yoast") - ;; Catch all - ("android" nerd-icons-faicon "nf-fa-android") - ("creativecommons" nerd-icons-faicon "nf-fa-creative_commons") - ("forums?" nerd-icons-codicon "nf-cod-comment_discussion") - ("\\.pdf$" nerd-icons-codicon "nf-cod-file_pdf" :face nerd-icons-dred) - ("google" nerd-icons-faicon "nf-fa-google") - ("\\.rss" nerd-icons-faicon "nf-fa-rss"))) - -(defun nerd-icons-auto-mode-match? (&optional file) - "Whether or not FILE's `major-mode' match against its `auto-mode-alist'." - (let* ((file (or file (buffer-file-name) (buffer-name))) - (auto-mode (nerd-icons-match-to-alist file auto-mode-alist))) - (eq major-mode auto-mode))) - -(defun nerd-icons-match-to-alist (file alist) - "Match FILE against an entry in ALIST using `string-match'." - (cdr (cl-find-if (lambda (it) (string-match (car it) file)) alist))) - -(defun nerd-icons-dir-is-submodule (dir) - "Checker whether or not DIR is a git submodule." - (let* ((gitmodule-dir (locate-dominating-file dir ".gitmodules")) - (modules-file (expand-file-name (format "%s.gitmodules" gitmodule-dir))) - (module-search (format "submodule \".*?%s\"" (file-name-base dir)))) - - (when (and gitmodule-dir (file-exists-p (format "%s/.git" dir))) - (with-temp-buffer - (insert-file-contents modules-file) - (search-forward-regexp module-search (point-max) t))))) - -(defun nerd-icons--read-candidates () - "Helper to build a list of candidates for all glyph sets." - (cl-reduce 'append (mapcar (lambda (it) (nerd-icons--read-candidates-for-glyph-set it t)) nerd-icons-glyph-sets))) - -(defun nerd-icons--read-candidates-for-glyph-set (glyph-set &optional show-glyph-set) - "Helper to build read candidates for GLYPH-SET. - -If SHOW-GLYPH-SET is non-nil, displays the icons glyph set in the candidate -string." - (let ((data (funcall (nerd-icons--data-name glyph-set))) - (icon-f (nerd-icons--function-name glyph-set))) - (mapcar - (lambda (it) - (let* ((icon-name (car it)) - - (icon-display (funcall icon-f icon-name)) - (icon-glyph-set (if show-glyph-set (format "\t[%s]" glyph-set) "")) - - (candidate-name (format "%s\t%s%s" icon-display icon-name icon-glyph-set)) - (candidate-icon (funcall (nerd-icons--function-name glyph-set) icon-name))) - (cons candidate-name candidate-icon))) - data))) - -;;;###autoload -(defun nerd-icons-install-fonts (&optional pfx) - "Helper function to download and install the latests fonts based on OS. -The provided Nerd Font is Symbols Nerd Font Mono. -When PFX is non-nil, ignore the prompt and just install" - (interactive "P") - (when (or pfx (yes-or-no-p "This will download and install fonts, are you sure you want to do this?")) - (let* ((url-format "https://raw.githubusercontent.com/rainstormstudio/nerd-icons.el/main/fonts/%s") - (font-dest (cond - ;; Default Linux install directories - ((member system-type '(gnu gnu/linux gnu/kfreebsd)) - (concat (or (getenv "XDG_DATA_HOME") - (concat (getenv "HOME") "/.local/share")) - "/fonts/" - nerd-icons-fonts-subdirectory)) - ;; Default MacOS install directory - ((eq system-type 'darwin) - (concat (getenv "HOME") - "/Library/Fonts/" - nerd-icons-fonts-subdirectory)))) - (known-dest? (stringp font-dest)) - (font-dest (or font-dest (read-directory-name "Font installation directory: " "~/")))) - - (unless (file-directory-p font-dest) (mkdir font-dest t)) - - (mapc (lambda (font) - (url-copy-file (format url-format font) (expand-file-name font font-dest) t)) - nerd-icons-font-names) - (when known-dest? - (message "Fonts downloaded, updating font cache... <fc-cache -f -v> ") - (shell-command-to-string (format "fc-cache -f -v"))) - (message "%s Successfully %s `nerd-icons' fonts to `%s'!" - (nerd-icons-wicon "nf-weather-stars" :v-adjust 0.0) - (if known-dest? "installed" "downloaded") - font-dest)))) - -;;;###autoload -(defun nerd-icons-insert (&optional arg glyph-set) - "Interactive icon insertion function. -When Prefix ARG is non-nil, insert the propertized icon. -When GLYPH-SET is non-nil, limit the candidates to the icon set matching it." - (interactive "P") - (let* ((standard-output (current-buffer)) - (candidates (if glyph-set - (nerd-icons--read-candidates-for-glyph-set glyph-set) - (nerd-icons--read-candidates))) - (prompt (if glyph-set - (format "%s Icon: " (funcall (nerd-icons--glyph-set-name glyph-set))) - "Icon : ")) - (selection (completing-read prompt candidates nil t)) - (result (cdr (assoc selection candidates)))) - - (if arg (prin1 result) (insert result)))) - -;;;###autoload -(defun nerd-icons-icon-for-dir (dir &rest arg-overrides) - "Get the formatted icon for DIR. -ARG-OVERRIDES should be a plist containining `:height', -`:v-adjust' or `:face' properties like in the normal icon -inserting functions." - (let* ((dir (or dir default-directory "/")) - (dirname (file-name-base (directory-file-name dir))) - (path (if (file-name-absolute-p dir) dir (expand-file-name dir))) - (icon (nerd-icons-match-to-alist dirname nerd-icons-dir-icon-alist)) - (args (cdr icon))) - (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) - (cond - ((file-remote-p path) - (apply #'nerd-icons-codicon "nf-cod-remote" (cdr args))) - ((file-symlink-p path) - (apply #'nerd-icons-codicon "nf-cod-file_symlink_directory" (cdr args))) - ((nerd-icons-dir-is-submodule path) - (apply #'nerd-icons-codicon "nf-cod-file_submodule" (cdr args))) - ((file-exists-p (format "%s/.git" path)) - (apply #'nerd-icons-octicon "nf-oct-repo" (cdr args))) - (t (apply (car icon) args))))) - -;;;###autoload -(defun nerd-icons-icon-for-file (file &rest arg-overrides) - "Get the formatted icon for FILE. -ARG-OVERRIDES should be a plist containining `:height', -`:v-adjust' or `:face' properties like in the normal icon -inserting functions." - (let* ((name (file-name-nondirectory file)) - (ext (file-name-extension name)) - (icon (or (nerd-icons-match-to-alist name nerd-icons-regexp-icon-alist) - (and ext - (cdr (assoc (downcase ext) - nerd-icons-extension-icon-alist))) - nerd-icons-default-file-icon)) - (args (cdr icon))) - (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) - (apply (car icon) args))) - -;;;###autoload -(defun nerd-icons-icon-for-extension (ext &rest arg-overrides) - "Get the formatted icon for EXT. -ARG-OVERRIDES should be a plist containining `:height', -`:v-adjust' or `:face' properties like in the normal icon -inserting functions." - (let* ((icon (or - (and ext - (cdr (assoc (downcase ext) - nerd-icons-extension-icon-alist))) - nerd-icons-default-file-icon)) - (args (cdr icon))) - (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) - (apply (car icon) args))) - -;;;###autoload -(defun nerd-icons-icon-for-mode (mode &rest arg-overrides) - "Get the formatted icon for MODE. -ARG-OVERRIDES should be a plist containining `:height', -`:v-adjust' or `:face' properties like in the normal icon -inserting functions." - (let* ((icon (or (cdr (or (assoc mode nerd-icons-mode-icon-alist) - (assoc (get mode 'derived-mode-parent) nerd-icons-mode-icon-alist))) - nerd-icons-default-file-icon)) - (args (cdr icon))) - (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) - (if icon (apply (car icon) args) mode))) - -;;;###autoload -(defun nerd-icons-icon-for-url (url &rest arg-overrides) - "Get the formatted icon for URL. -If an icon for URL isn't found in `nerd-icons-url-alist', a globe is used. -ARG-OVERRIDES should be a plist containining `:height', -`:v-adjust' or `:face' properties like in the normal icon -inserting functions." - (let* ((icon (nerd-icons-match-to-alist url nerd-icons-url-alist)) - (args (cdr icon))) - (unless icon - (setq icon '(nerd-icons-faicon "nf-fa-globe")) - (setq args (cdr icon))) - (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) - (apply (car icon) args))) - -;;;###autoload -(defun nerd-icons-icon-for-buffer () - "Get the formatted icon for the current buffer. - -This function prioritises the use of the buffers file extension to -discern the icon when its `major-mode' matches its auto mode, -otherwise it will use the buffers `major-mode' to decide its -icon." - (nerd-icons--icon-info-for-buffer)) - -(defun nerd-icons-cache (func) - "Set a cache for FUNC. Does not work on interactive functions." - (unless (get func 'nerd-icons--cached) - (let ((cache (make-hash-table :test #'equal - :size nerd-icons--cache-limit)) - (orig-fn (symbol-function func))) - (fset func - (lambda (&rest args) - (or (gethash args cache) - (progn - (when (> (hash-table-count cache) - nerd-icons--cache-limit) - (clrhash cache)) - (puthash args (apply orig-fn args) cache))))))) - - (put func 'nerd-icons--cached t)) - -(nerd-icons-cache #'nerd-icons-icon-for-dir) -(nerd-icons-cache #'nerd-icons-icon-for-file) -(nerd-icons-cache #'nerd-icons-icon-for-extension) -(nerd-icons-cache #'nerd-icons-icon-for-mode) -(nerd-icons-cache #'nerd-icons-icon-for-url) - -(defun nerd-icons--icon-info-for-buffer (&optional f) - "Get icon info for the current buffer. -When F is provided, the info function is calculated with the format -`nerd-icons-icon-%s-for-file' or `nerd-icons-icon-%s-for-mode'." - (let* ((base-f (concat "nerd-icons-icon" (when f (format "-%s" f)))) - (file-f (intern (concat base-f "-for-file"))) - (mode-f (intern (concat base-f "-for-mode")))) - (if (and (buffer-file-name) - (nerd-icons-auto-mode-match?)) - (funcall file-f (file-name-nondirectory (buffer-file-name))) - (funcall mode-f major-mode)))) - -;; Weather icons -(defun nerd-icons-icon-for-weather (weather) - "Get an icon for a WEATHER status." - (let ((icon (nerd-icons-match-to-alist weather nerd-icons-weather-icon-alist))) - (if icon (apply (car icon) (cdr icon)) weather))) - -;; For `web-mode' -(defun nerd-icons--web-mode-icon (&rest arg-overrides) - "Get icon for a `web-mode' buffer with ARG-OVERRIDES." - (nerd-icons--web-mode arg-overrides)) -(defun nerd-icons--web-mode-icon-family () - "Get icon family for a `web-mode' buffer." - (nerd-icons--web-mode t)) - -(defvar web-mode-content-type) ; external -(defun nerd-icons--web-mode (&optional arg-overrides) - "Return icon or FAMILY for `web-mode' based on `web-mode-content-type'. -Providing ARG-OVERRIDES will modify the creation of the icon." - (let ((non-nil-args (cl-reduce (lambda (acc it) (if it (append acc (list it)) acc)) - arg-overrides :initial-value '()))) - (cond - ((equal web-mode-content-type "jsx") - (apply 'nerd-icons-devicon (append '("javascript") non-nil-args))) - ((equal web-mode-content-type "javascript") - (apply 'nerd-icons-devicon (append '("javascript") non-nil-args))) - ((equal web-mode-content-type "json") - (apply 'nerd-icons-devicon (append '("nf-dev-less") non-nil-args))) - ((equal web-mode-content-type "xml") - (apply 'nerd-icons-faicon (append '("nf-fa-file_code_o") non-nil-args))) - ((equal web-mode-content-type "css") - (apply 'nerd-icons-devicon (append '("nf-dev-css3") non-nil-args))) - (t - (apply 'nerd-icons-devicon (append '("nf-dev-html5") non-nil-args)))))) - -(eval-and-compile - (defun nerd-icons--function-name (name) - "Get the symbol for an icon function name for icon set NAME." - (intern (concat "nerd-icons-" (downcase (symbol-name name))))) - - (defun nerd-icons--family-name (name) - "Get the symbol for an icon family function for icon set NAME." - (intern (concat "nerd-icons-" (downcase (symbol-name name)) "-family"))) - - (defun nerd-icons--glyph-set-name (name) - "Get the symbol for an icon glyph set function for icon set NAME." - (intern (concat "nerd-icons-" (downcase (symbol-name name)) "-glyph-set"))) - - (defun nerd-icons--data-name (name) - "Get the symbol for an icon family function for icon set NAME." - (intern (concat "nerd-icons-" (downcase (symbol-name name)) "-data"))) - - (defun nerd-icons--insert-function-name (name) - "Get the symbol for an icon insert function for icon set NAME." - (intern (concat "nerd-icons-insert-" (downcase (symbol-name name)))))) - -(defun nerd-icons-insert-icons-for (family &optional height duration) - "Insert all of the available icons associated with FAMILY. -If a HEIGHT is provided it will render the icons at this height. -This is useful both to see the icons more clearly and to test -different height rendering. If DURATION is provided, it will -pause for DURATION seconds between printing each character." - (let* ((data-f (nerd-icons--data-name family)) - (insert-f (nerd-icons--function-name family)) - - (height (or height 1.0)) - (data (funcall data-f))) - (mapc - (lambda (it) - (insert (format "%s - %s\n" (funcall insert-f (car it) :height height) (car it))) - (when duration (sit-for duration))) - data))) - -(defun nerd-icons-set-font (&optional font-family frame) - "Modify nerd font charsets to use FONT-FAMILY for FRAME." - (let ((font-f (or font-family nerd-icons-font-family)) - (charsets '((#xe5fa . #xe6b2) ;; Seti-UI + Custom - (#xe700 . #xe7c5) ;; Devicons - (#xf000 . #xf2e0) ;; Font Awesome - (#xe200 . #xe2a9) ;; Font Awesome Extension - (#xf500 . #xfd46) (#xf0001 . #xf1af0) ;; Material Design Icons - (#xe300 . #xe3eb) ;; Weather - (#xf400 . #xf4a8) #x2665 #x26a1 #xf27c ;; Octicons - (#xe0a0 . #xe0a2) (#xe0b0 . #xe0b3) ;; Powerline Symbols - #xe0a3 (#xe0b4 . #xe0c8) (#xe0cc . #xe0d2) #xe0d4 ;; Powerline Extra Symbols - (#x23fb . #x23fe) #x2b58 ;; IEC Power Symbols - (#xf300 . #xf372) ;; Font Logos - (#xe000 . #xe00a) ;; Pomicons - (#xea60 . #xebeb)))) ;; Codicons - (cl-loop for charset in charsets do - (set-fontset-font - (frame-parameter nil 'font) - charset - (font-spec :family font-f - :weight nil - :size nil) - frame - 'prepend)))) - -(defmacro nerd-icons-define-icon (name alist family glyph-set) - "Macro to generate functions for inserting icons for icon set NAME. - -NAME defines is the name of the iconset and will produce a -function of the for `nerd-icon-NAME'. - -ALIST is the alist containing maps between icon names and the -UniCode for the character. All of these can be found in the data -directory of this package. - -FAMILY is the font family to use for the icons. -GLYPH-SET is the glyph set of the icon." - `(progn - (add-to-list 'nerd-icons-glyph-sets (quote ,name)) - (defun ,(nerd-icons--family-name name) () ,family) - (defun ,(nerd-icons--glyph-set-name name) () ,glyph-set) - (defun ,(nerd-icons--data-name name) () ,alist) - (defun ,(nerd-icons--function-name name) (icon-name &rest args) - (let ((icon (cdr (assoc icon-name ,alist))) - (other-face (when nerd-icons-color-icons (plist-get args :face))) - (height (* nerd-icons-scale-factor (or (plist-get args :height) 1.0))) - (v-adjust (* nerd-icons-scale-factor (or (plist-get args :v-adjust) nerd-icons-default-adjust))) - (family ,family)) - (unless icon - (error "Unable to find icon with name `%s' in icon set `%s'" icon-name (quote ,name))) - (let ((face (if other-face - `(:family ,family :height ,height :inherit ,other-face) - `(:family ,family :height ,height)))) - (propertize icon - 'face face - 'font-lock-face face - 'display `(raise ,v-adjust) - 'rear-nonsticky t)))) - (defun ,(nerd-icons--insert-function-name name) (&optional arg) - ,(format "Insert a %s icon at point." glyph-set) - (interactive "P") - (nerd-icons-insert arg (quote ,name))))) - -(nerd-icons-define-icon ipsicon nerd-icons/ipsicon-alist nerd-icons-font-family "IEC Power Symbols") -(nerd-icons-define-icon octicon nerd-icons/octicon-alist nerd-icons-font-family "Octicons") -(nerd-icons-define-icon pomicon nerd-icons/pomicon-alist nerd-icons-font-family "Pomicons") -(nerd-icons-define-icon powerline nerd-icons/powerline-alist nerd-icons-font-family "Powerline Symbols") -(nerd-icons-define-icon faicon nerd-icons/faicon-alist nerd-icons-font-family "Font Awesome") -(nerd-icons-define-icon wicon nerd-icons/wicon-alist nerd-icons-font-family "Weather") -(nerd-icons-define-icon sucicon nerd-icons/sucicon-alist nerd-icons-font-family "Seti-UI + Custom") -(nerd-icons-define-icon devicon nerd-icons/devicon-alist nerd-icons-font-family "Devicons") -(nerd-icons-define-icon codicon nerd-icons/codicon-alist nerd-icons-font-family "Codicons") -(nerd-icons-define-icon flicon nerd-icons/flicon-alist nerd-icons-font-family "Font Logos") -(nerd-icons-define-icon mdicon nerd-icons/mdicon-alist nerd-icons-font-family "Material Design Icons") - -(provide 'nerd-icons) -;;; nerd-icons.el ends here diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons.elc b/emacs/elpa/nerd-icons-20240808.625/nerd-icons.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-codicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-codicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-codicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-codicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-devicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-devicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-devicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-devicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-faicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-faicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-faicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-faicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-flicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-flicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-flicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-flicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-ipsicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-ipsicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-ipsicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-ipsicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-mdicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-mdicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-mdicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-mdicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-octicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-octicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-octicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-octicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-pomicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-pomicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-pomicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-pomicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-powerline.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-powerline.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-powerline.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-powerline.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-sucicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-sucicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-sucicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-sucicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-wicon.el b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-wicon.el diff --git a/emacs/elpa/nerd-icons-20240808.625/data/nerd-icons-data-wicon.elc b/emacs/elpa/nerd-icons-20240816.1555/data/nerd-icons-data-wicon.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons-autoloads.el b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-autoloads.el diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons-data.el b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-data.el diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons-data.elc b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-data.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons-faces.el b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-faces.el diff --git a/emacs/elpa/nerd-icons-20240808.625/nerd-icons-faces.elc b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-faces.elc Binary files differ. diff --git a/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-pkg.el b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons-pkg.el @@ -0,0 +1,16 @@ +(define-package "nerd-icons" "20240816.1555" "Emacs Nerd Font Icons Library" + '((emacs "24.3")) + :commit "c3d641d8e14bd11b5f98372da34ee5313636e363" :authors + '(("Hongyu Ding" . "rainstormstudio@yahoo.com") + ("Vincent Zhang" . "seagle0128@gmail.com")) + :maintainers + '(("Hongyu Ding" . "rainstormstudio@yahoo.com") + ("Vincent Zhang" . "seagle0128@gmail.com")) + :maintainer + '("Hongyu Ding" . "rainstormstudio@yahoo.com") + :keywords + '("lisp") + :url "https://github.com/rainstormstudio/nerd-icons.el") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/nerd-icons-20240816.1555/nerd-icons.el b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons.el @@ -0,0 +1,1320 @@ +;;; nerd-icons.el --- Emacs Nerd Font Icons Library -*- lexical-binding: t -*- + +;; Copyright (C) 2023 Hongyu Ding <rainstormstudio@yahoo.com> + +;; Author: Hongyu Ding <rainstormstudio@yahoo.com>, Vincent Zhang <seagle0128@gmail.com> +;; Keywords: lisp +;; Version: 0.1.0 +;; Package-Requires: ((emacs "24.3")) +;; URL: https://github.com/rainstormstudio/nerd-icons.el +;; Keywords: convenient, lisp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package was inspired by + +;; - `all-the-icons', found at https://github.com/Alexander-Miller/treemacs/blob/master/src/extra/treemacs-all-the-icons.el +;; - `vim-devicons' for Vim, found at https://github.com/ryanoasis/vim-devicons +;; - `nvim-web-devicons' for NeoVim, found at https://github.com/nvim-tree/nvim-web-devicons + +;; This package provides an interface to the Nerd Fonts + +;; - `nerd-fonts', found at https://github.com/ryanoasis/nerd-fonts + +;;; Code: + +(require 'cl-lib) + +(require 'nerd-icons-data) +(require 'nerd-icons-faces) + +(declare-function set-fontset-font "src/fontset.c") + +(defgroup nerd-icons nil + "Manage how Nerd Fonts formats icons." + :prefix "nerd-icons-" + :group 'appearance + :group 'convenience) + +(defcustom nerd-icons-color-icons t + "Whether or not to include a foreground color when formatting the icon." + :group 'nerd-icons + :type 'boolean) + +(defcustom nerd-icons-scale-factor 1.0 + "The base Scale Factor for the `height' face property of an icon." + :group 'nerd-icons + :type 'number) + +(defcustom nerd-icons-default-adjust 0.0 + "The default adjustment to be made to the `raise' display property of an icon." + :group 'nerd-icons + :type 'number) + +(defcustom nerd-icons--cache-limit 2048 + "Maximum cache size for functions cached by `nerd-icons-cache'." + :group 'nerd-icons + :type 'integer) + +(defcustom nerd-icons-font-family "Symbols Nerd Font Mono" + "The Nerd Font for display icons." + :group 'nerd-icons + :type 'string) + +(defcustom nerd-icons-fonts-subdirectory nil + "The subdirectory within the system fonts folder where the icons are installed." + :group 'nerd-icons + :type 'directory) + +(defvar nerd-icons-font-names '("NFM.ttf") + "List of defined font file names.") + +(defvar nerd-icons-glyph-sets '() "List of defined icon glyph sets.") + +(defvar nerd-icons-extension-icon-alist + '( + ("fish" nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-lpink) + ("zsh" nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-lcyan) + ("sh" nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) + ("bat" nerd-icons-codicon "nf-cod-terminal_cmd" :face nerd-icons-lsilver) + ("cmd" nerd-icons-codicon "nf-cod-terminal_cmd" :face nerd-icons-lsilver) + ;; Meta + ("tags" nerd-icons-octicon "nf-oct-tag" :face nerd-icons-blue) + ("log" nerd-icons-octicon "nf-oct-log" :face nerd-icons-maroon) + ;; Config + ("node" nerd-icons-devicon "nf-dev-nodejs_small" :face nerd-icons-green) + ("babelrc" nerd-icons-mdicon "nf-md-babel" :face nerd-icons-yellow) + ("bashrc" nerd-icons-mdicon "nf-md-bash" :face nerd-icons-dpink) + ("bowerrc" nerd-icons-devicon "nf-dev-bower" :face nerd-icons-silver) + ("cr" nerd-icons-sucicon "nf-seti-crystal" :face nerd-icons-yellow) + ("ecr" nerd-icons-sucicon "nf-seti-crystal" :face nerd-icons-yellow) + ("ini" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + ("properties" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + ("eslintignore" nerd-icons-mdicon "nf-md-eslint" :face nerd-icons-purple) + ("eslint" nerd-icons-mdicon "nf-md-eslint" :face nerd-icons-lpurple) + ("git" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) + ("gitattributes" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) + ("gitignore" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) + ("gitmodules" nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) + ("mk" nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-dorange) + ;; ("cmake" nerd-icons-devicon "cmake") TODO: cmake + ("dockerignore" nerd-icons-devicon "nf-dev-docker" :face nerd-icons-dblue) + ("xml" nerd-icons-faicon "nf-fa-file_code_o" :face nerd-icons-lorange) + ("json" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + ("jsonl" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + ("cson" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + ("yml" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) + ("yaml" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) + ("toml" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) + ("conf" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dorange) + ("editorconfig" nerd-icons-sucicon "nf-seti-editorconfig" :face nerd-icons-silver) + ;; ? + ("pkg" nerd-icons-octicon "nf-oct-package" :face nerd-icons-dsilver) + ("rpm" nerd-icons-octicon "nf-oct-package" :face nerd-icons-dsilver) + ("pkgbuild" nerd-icons-octicon "nf-oct-package" :face nerd-icons-dsilver) + ("elc" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) + ("eln" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) + ("gz" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-lmaroon) + ("zip" nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) + ("7z" nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) + ("zst" nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) + ("dat" nerd-icons-faicon "nf-fa-bar_chart" :face nerd-icons-cyan) + ("dmg" nerd-icons-octicon "nf-oct-tools" :face nerd-icons-lsilver) + ("dll" nerd-icons-faicon "nf-fa-cogs" :face nerd-icons-silver) + ("ds_store" nerd-icons-faicon "nf-fa-cogs" :face nerd-icons-silver) + ("exe" nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) + ("msg" nerd-icons-octicon "nf-oct-mail" :face nerd-icons-dsilver) + ;; Source Codes + ("ada" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) + ("adb" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) + ("adc" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) + ("ads" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) + ("gpr" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) + ("cgpr" nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) + ("scpt" nerd-icons-devicon "nf-dev-apple" :face nerd-icons-pink) + ;; ("aup" nerd-icons-fileicon "audacity") TODO: audacity + ("elm" nerd-icons-sucicon "nf-seti-elm" :face nerd-icons-blue) + ("erl" nerd-icons-devicon "nf-dev-erlang" :face nerd-icons-red) + ("hrl" nerd-icons-devicon "nf-dev-erlang" :face nerd-icons-dred) + ("eex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) + ("leex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) + ("heex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) + ("ex" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lpurple) + ("exs" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lred) + ("livemd" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lblue) + ("java" nerd-icons-devicon "nf-dev-java" :face nerd-icons-purple) + ("groovy" nerd-icons-devicon "nf-dev-groovy" :face nerd-icons-cyan) + ("gradle" nerd-icons-sucicon "nf-seti-gradle" :face nerd-icons-silver) + ("ebuild" nerd-icons-mdicon "nf-md-gentoo" :face nerd-icons-cyan) + ("eclass" nerd-icons-mdicon "nf-md-gentoo" :face nerd-icons-blue) + ("go" nerd-icons-devicon "nf-dev-go" :face nerd-icons-blue) + ("jl" nerd-icons-sucicon "nf-seti-julia" :face nerd-icons-purple) + ("magik" nerd-icons-faicon "nf-fa-magic" :face nerd-icons-blue) + ;; ("matlab" nerd-icons-devicon "matlab") TODO: matlab + ("nix" nerd-icons-mdicon "nf-md-nix" :face nerd-icons-blue) + ("pl" nerd-icons-sucicon "nf-seti-perl" :face nerd-icons-lorange) + ("pm" nerd-icons-sucicon "nf-seti-perl" :face nerd-icons-lorange) + ;; ("pl6" nerd-icons-devicon"raku") TODO: raku + ;; ("pm6" nerd-icons-devicon "raku") TODO: raku + ("pod" nerd-icons-devicon "nf-dev-perl" :face nerd-icons-lgreen) + ("php" nerd-icons-devicon "nf-dev-php" :face nerd-icons-lsilver) + ;; ("pony" nerd-icons-devicon "pony") TODO: pony + ("ps1" nerd-icons-mdicon "nf-md-powershell" :face nerd-icons-blue) + ("pro" nerd-icons-sucicon "nf-seti-prolog" :face nerd-icons-lmaroon) + ("proog" nerd-icons-sucicon "nf-seti-prolog" :face nerd-icons-lmaroon) + ("py" nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) + ;; ("idr" nerd-icons-devicon "idris") TODO: idris + ;; ("ipynb" nerd-icons-devicon "jupyter") TODO: jupyter + ("gem" nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) + ;; ("raku" nerd-icons-devicon "raku") TODO: raku + ;; ("rakumod" nerd-icons-devicon "raku") TODO: raku + ("rb" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-lred) + ("rs" nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) + ("rlib" nerd-icons-devicon "nf-dev-rust" :face nerd-icons-dmaroon) + ("r" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) + ("rd" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) + ("rdx" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) + ("rsx" nerd-icons-sucicon "nf-seti-r" :face nerd-icons-lblue) + ("svelte" nerd-icons-sucicon "nf-seti-svelte" :face nerd-icons-red) + ("gql" nerd-icons-mdicon "nf-md-graphql" :face nerd-icons-dpink) + ("graphql" nerd-icons-mdicon "nf-md-graphql" :face nerd-icons-dpink) + ;; There seems to be a a bug with this font icon which does not + ;; let you propertise it without it reverting to being a lower + ;; case phi + ("c" nerd-icons-sucicon "nf-custom-c" :face nerd-icons-blue) + ("h" nerd-icons-faicon "nf-fa-h_square" :face nerd-icons-purple) + ("m" nerd-icons-devicon "nf-dev-apple" ) + ("mm" nerd-icons-devicon "nf-dev-apple" ) + ;; + ("cc" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) + ("cpp" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) + ("cxx" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) + ("hh" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-purple) + ("hpp" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-purple) + ("hxx" nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-purple) + ;; Lisps + ("cl" nerd-icons-sucicon "nf-custom-common_lisp" :face nerd-icons-lorange) + ("l" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-orange) + ("lisp" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-orange) + ;; ("hy" nerd-icons-sucicon "nf-custom-hy" :face nerd-icons-blue) + ("el" nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple) + ("clj" nerd-icons-devicon "nf-dev-clojure" :face nerd-icons-blue) + ("cljc" nerd-icons-devicon "nf-dev-clojure" :face nerd-icons-blue) + ("cljs" nerd-icons-devicon "nf-dev-clojure" :face nerd-icons-lyellow) + ("coffee" nerd-icons-devicon "nf-dev-coffeescript" :face nerd-icons-maroon) + ("iced" nerd-icons-devicon "nf-dev-coffeescript" :face nerd-icons-lmaroon) + ("dart" nerd-icons-devicon "nf-dev-dart" :face nerd-icons-blue) + ("ledger" nerd-icons-mdicon "nf-md-file_table_box_multiple" :face nerd-icons-green) + ("rkt" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-red) + ("scrbl" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-blue) + ;; Stylesheeting + ("css" nerd-icons-devicon "nf-dev-css3" :face nerd-icons-yellow) + ("scss" nerd-icons-mdicon "nf-md-sass" :face nerd-icons-pink) + ("sass" nerd-icons-mdicon "nf-md-sass" :face nerd-icons-dpink) + ("less" nerd-icons-devicon "nf-dev-less" :face nerd-icons-dyellow) + ;; ("postcss" nerd-icons-devicon "postcss") TODO: postcss + ;; ("sss" nerd-icons-devicon "postcss") TODO: postcss + ("styl" nerd-icons-devicon "nf-dev-stylus" :face nerd-icons-lgreen) + ("csv" nerd-icons-octicon "nf-oct-graph" :face nerd-icons-dblue) + ;; haskell + ("hs" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + ("chs" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + ("lhs" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + ("hsc" nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + ;; Web modes + ("inky-haml" nerd-icons-sucicon "nf-seti-haml" :face nerd-icons-lyellow) + ("haml" nerd-icons-sucicon "nf-seti-haml" :face nerd-icons-lyellow) + ("htm" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) + ("html" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) + ("inky-er" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) + ("inky-erb" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) + ("erb" nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) + ;; ("hbs" nerd-icons-fileicon "moustache") TODO: moustache + ("inky-slim" nerd-icons-codicon "nf-cod-dashboard" :face nerd-icons-yellow) + ("slim" nerd-icons-codicon "nf-cod-dashboard" :face nerd-icons-yellow) + ("jade" nerd-icons-sucicon "nf-seti-jade" :face nerd-icons-red) + ("pug" nerd-icons-sucicon "nf-seti-pug" :face nerd-icons-red) + ;; Javascript + ;; ("d3js" nerd-icons-devicon "d3") TODO: d3 + ("re" nerd-icons-sucicon "nf-seti-reasonml" :face nerd-icons-red-alt) + ("rei" nerd-icons-sucicon "nf-seti-reasonml" :face nerd-icons-dred) + ("ml" nerd-icons-sucicon "nf-seti-ocaml" :face nerd-icons-lpink) + ("mli" nerd-icons-sucicon "nf-seti-ocaml" :face nerd-icons-dpink) + ("react" nerd-icons-devicon "nf-dev-react" :face nerd-icons-lblue) + ("ts" nerd-icons-sucicon "nf-seti-typescript" :face nerd-icons-blue-alt) + ("js" nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + ("es" nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + ("jsx" nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-cyan-alt) + ("tsx" nerd-icons-sucicon "nf-seti-typescript" :face nerd-icons-blue-alt) + ("njs" nerd-icons-mdicon "nf-md-nodejs" :face nerd-icons-lgreen) + ("vue" nerd-icons-sucicon "nf-seti-vue" :face nerd-icons-lgreen) + + ("sbt" nerd-icons-sucicon "nf-seti-sbt" :face nerd-icons-red) + ("scala" nerd-icons-devicon "nf-dev-scala" :face nerd-icons-red) + ("scm" nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-red) + ("swift" nerd-icons-devicon "nf-dev-swift" :face nerd-icons-green) + + ("tcl" nerd-icons-mdicon "nf-md-feather" :face nerd-icons-dred) + ("exp" nerd-icons-mdicon "nf-md-feather" :face nerd-icons-dred) + + ("tf" nerd-icons-mdicon "nf-md-terraform" :face nerd-icons-purple-alt) + ("tfvars" nerd-icons-mdicon "nf-md-terraform" :face nerd-icons-purple-alt) + ("tfstate" nerd-icons-mdicon "nf-md-terraform" :face nerd-icons-purple-alt) + + ("asm" nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) + ;; Verilog(-AMS) and SystemVerilog(-AMS ;; Verilog(-AMS) and SystemVerilog(-AMS) + ("v" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + ("vams" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + ("sv" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + ("sva" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + ("svh" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + ("svams" nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + ;; VHDL(-AMS ;; VHDL(-AMS) + ("vhd" nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) + ("vhdl" nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) + ("vhms" nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) + ;; Cabal + ;; ("cabal" nerd-icons-devicon "cabal") TODO: cabal + ;; Kotlin + ("kt" nerd-icons-sucicon "nf-seti-kotlin" :face nerd-icons-orange) + ("kts" nerd-icons-sucicon "nf-seti-kotlin" :face nerd-icons-orange) + ;; Nimrod + ("nim" nerd-icons-sucicon "nf-seti-nim" :face nerd-icons-yellow) + ("nims" nerd-icons-sucicon "nf-seti-nim" :face nerd-icons-yellow) + ;; SQL + ("sql" nerd-icons-octicon "nf-oct-database" :face nerd-icons-silver) + ;; Styles + ;; ("styles" nerd-icons-devicon "style") TODO: style + ;; Lua + ("lua" nerd-icons-sucicon "nf-seti-lua" :face nerd-icons-dblue) + ;; ASCII doc + ;; ("adoc" nerd-icons-devicon "asciidoc") TODO: asciidoc + ;; ("asciidoc" nerd-icons-devicon "asciidoc") TODO: asciidoc + ;; Puppet + ("pp" nerd-icons-sucicon "nf-seti-puppet" :face nerd-icons-yellow) + ;; Jinja + ("j2" nerd-icons-sucicon "nf-seti-jinja" :face nerd-icons-silver) + ("jinja2" nerd-icons-sucicon "nf-seti-jinja" :face nerd-icons-silver) + ;; Docker + ("dockerfile" nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-cyan) + ;; Vagrant + ;; ("vagrantfile" nerd-icons-fileicon "vagrant") TODO: vagrant + ;; GLSL + ("glsl" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-blue) + ("vert" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-blue) + ("tesc" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-purple) + ("tese" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-dpurple) + ("geom" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-green) + ("frag" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-red) + ("comp" nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-dblue) + ;; CUDA + ("cu" nerd-icons-sucicon "nf-custom-c" :face nerd-icons-green) + ("cuh" nerd-icons-faicon "nf-fa-h_square" :face nerd-icons-green) + ;; Fortran + ("f90" nerd-icons-mdicon "nf-md-language_fortran" :face nerd-icons-purple) + ;; C# + ("cs" nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) + ("csx" nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) + ;; F# + ("fs" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) + ("fsi" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) + ("fsx" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) + ("fsscript" nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue-alt) + ;; Godot / GDScript + ("gd" nerd-icons-sucicon "nf-seti-godot" :face nerd-icons-blue) + ("tscn" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) + ("tres" nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) + ;; zig + ("zig" nerd-icons-sucicon "nf-seti-zig" :face nerd-icons-orange) + ;; odin + ;; ("odin" nerd-icons-fileicon "odin") TODO: odin + ;; File Types + ("ico" nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-blue) + ("png" nerd-icons-mdicon "nf-md-file_png_box" :face nerd-icons-orange) + ("gif" nerd-icons-mdicon "nf-md-file_gif_box" :face nerd-icons-green) + ("jpeg" nerd-icons-mdicon "nf-md-file_jpg_box" :face nerd-icons-dblue) + ("jpg" nerd-icons-mdicon "nf-md-file_jpg_box" :face nerd-icons-dblue) + ("webp" nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-dblue) + ("xpm" nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-dgreen) + ;; Audio + ("mp3" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("wav" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("m4a" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("ogg" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("flac" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("opus" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("au" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("aif" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("aifc" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("aiff" nerd-icons-faicon "nf-fa-music" :face nerd-icons-dred) + ("svg" nerd-icons-sucicon "nf-seti-svg" :face nerd-icons-lgreen) + ;; Video + ("mov" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ("mp4" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ("ogv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-dblue) + ("mpg" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ("mpeg" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ("flv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ("ogv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-dblue) + ("mkv" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ("webm" nerd-icons-faicon "nf-fa-film" :face nerd-icons-blue) + ;; Fonts + ("ttf" nerd-icons-faicon "nf-fa-font" :face nerd-icons-dcyan) + ("woff" nerd-icons-faicon "nf-fa-font" :face nerd-icons-cyan) + ("woff2" nerd-icons-faicon "nf-fa-font" :face nerd-icons-cyan) + ;; Archives + ("iso" nerd-icons-mdicon "nf-md-disc" :face nerd-icons-orange) + ("tar" nerd-icons-mdicon "nf-md-zip_box" :face nerd-icons-orange) + ("rar" nerd-icons-mdicon "nf-md-zip_box" :face nerd-icons-orange) + ("tgz" nerd-icons-mdicon "nf-md-zip_box" :face nerd-icons-orange) + ("jar" nerd-icons-devicon "nf-dev-java" :face nerd-icons-dpurple) + ;; Doc + ("pdf" nerd-icons-codicon "nf-cod-file_pdf" :face nerd-icons-dred) + ("text" nerd-icons-faicon "nf-fa-file_text" :face nerd-icons-cyan) + ("txt" nerd-icons-faicon "nf-fa-file_text" :face nerd-icons-cyan) + ("doc" nerd-icons-mdicon "nf-md-file_word" :face nerd-icons-blue) + ("docx" nerd-icons-mdicon "nf-md-file_word" :face nerd-icons-blue) + ("docm" nerd-icons-mdicon "nf-md-file_word" :face nerd-icons-blue) + ("texi" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + ("tex" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + ("ltx" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + ("dtx" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + ("sty" nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + ("md" nerd-icons-octicon "nf-oct-markdown" :face nerd-icons-lblue) + ("bib" nerd-icons-mdicon "nf-md-book" :face nerd-icons-lblue) + ("org" nerd-icons-sucicon "nf-custom-orgmode" :face nerd-icons-lgreen) + ("org_archive" nerd-icons-sucicon "nf-custom-orgmode" :face nerd-icons-lgreen) + ("pps" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) + ("ppt" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) + ("pptx" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) + ("pptsx" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) + ("ppttx" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-orange) + ("knt" nerd-icons-mdicon "nf-md-file_powerpoint" :face nerd-icons-cyan) + ("xlsx" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) + ("xlsm" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) + ("xlsb" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) + ("xltx" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) + ("xltm" nerd-icons-mdicon "nf-md-file_excel" :face nerd-icons-dgreen) + ("epub" nerd-icons-mdicon "nf-md-book_open" :face nerd-icons-green) + ("ly" nerd-icons-faicon "nf-fa-music" :face nerd-icons-green) + ;; + ("key" nerd-icons-octicon "nf-oct-key" :face nerd-icons-lblue) + ("pem" nerd-icons-octicon "nf-oct-key" :face nerd-icons-orange) + ("p12" nerd-icons-octicon "nf-oct-key" :face nerd-icons-dorange) + ("crt" nerd-icons-octicon "nf-oct-key" :face nerd-icons-lblue) + ("pub" nerd-icons-octicon "nf-oct-key" :face nerd-icons-blue) + ("gpg" nerd-icons-octicon "nf-oct-key" :face nerd-icons-lblue) + ("kdbx" nerd-icons-octicon "nf-oct-key" :face nerd-icons-green) + ("cache" nerd-icons-octicon "nf-oct-database" :face nerd-icons-green) + ;; backup + ("backup" nerd-icons-mdicon "nf-md-file_restore" :face nerd-icons-lblue) + ("old" nerd-icons-mdicon "nf-md-file_restore" :face nerd-icons-lblue) + ("bak" nerd-icons-mdicon "nf-md-file_restore" :face nerd-icons-lblue))) + +(defvar nerd-icons-regexp-icon-alist + '( + ;; + ("^TAGS$" nerd-icons-octicon "nf-oct-tag" :face nerd-icons-blue) + ("^TODO$" nerd-icons-octicon "nf-oct-checklist" :face nerd-icons-lyellow) + ("^LICENSE$" nerd-icons-octicon "nf-oct-book" :face nerd-icons-blue) + ("^readme" nerd-icons-octicon "nf-oct-book" :face nerd-icons-lcyan) + + ;; Config + ("nginx$" nerd-icons-devicon "nf-dev-nginx" :face nerd-icons-dgreen) + ;; ("apache$" nerd-icons-alltheicon "apache") TODO: apache + + ;; C + ("^Makefile$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-dorange) + ("^CMakeLists.txt$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-red) ;; TODO: cmake + ("^CMakeCache.txt$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-blue) ;; TODO: cmakecache + ("^meson.build$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-purple) ;; TODO: meson + ("^meson_options.txt$" nerd-icons-sucicon "nf-seti-makefile" :face nerd-icons-purple) ;; TODO: meson + + ;; Docker + ("^\\.?Dockerfile" nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-blue) + + ;; Homebrew + ("^Brewfile$" nerd-icons-faicon "nf-fa-beer" :face nerd-icons-lsilver) + + ;; ;; AWS + ("^stack.*.json$" nerd-icons-devicon "nf-dev-aws" :face nerd-icons-orange) + ("^serverless\\.yml$" nerd-icons-faicon "nf-fa-bolt" :face nerd-icons-yellow) + + ;; lock files + ("~$" nerd-icons-octicon "nf-oct-lock" :face nerd-icons-maroon) + + ;; Source Codes + ("^mix.lock$" nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lyellow) + + ;; Ruby + ("^Gemfile\\(\\.lock\\)?$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-red) + ("_?test\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-red) + ("_?test_helper\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-dred) + ("_?spec\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-red) + ("_?spec_helper\\.rb$" nerd-icons-octicon "nf-oct-ruby" :face nerd-icons-dred) + + ("-?spec\\.ts$" nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue) + ("-?test\\.ts$" nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue) + ("-?spec\\.js$" nerd-icons-mdicon "nf-md-language_javascript" :face nerd-icons-lpurple) + ("-?test\\.js$" nerd-icons-mdicon "nf-md-language_javascript" :face nerd-icons-lpurple) + ("-?spec\\.jsx$" nerd-icons-mdicon "nf-md-react" :face nerd-icons-blue-alt) + ("-?test\\.jsx$" nerd-icons-mdicon "nf-md-react" :face nerd-icons-blue-alt) + + ;; Git + ("^MERGE_" nerd-icons-octicon "nf-oct-git_merge" :face nerd-icons-red) + ("^COMMIT_EDITMSG" nerd-icons-octicon "nf-oct-git_commit" :face nerd-icons-red) + + ;; Stylesheeting + ("^stylelint" nerd-icons-sucicon "nf-seti-stylelint" :face nerd-icons-lyellow) + + ;; JavaScript + ("^package.json$" nerd-icons-devicon "nf-dev-npm" :face nerd-icons-red) + ("^package.lock.json$" nerd-icons-devicon "nf-dev-npm" :face nerd-icons-dred) + ("^yarn\\.lock" nerd-icons-sucicon "nf-seti-yarn" :face nerd-icons-blue-alt) + ("\\.npmignore$" nerd-icons-devicon "nf-dev-npm" :face nerd-icons-dred) + ("^bower.json$" nerd-icons-devicon "nf-dev-bower" :face nerd-icons-lorange) + ("^gulpfile" nerd-icons-devicon "nf-dev-gulp" :face nerd-icons-lred) + ("^gruntfile" nerd-icons-devicon "nf-dev-grunt" :face nerd-icons-lyellow) + ("^webpack" nerd-icons-mdicon "nf-md-webpack" :face nerd-icons-lblue) + + ;; Go + ("^go.mod$" nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) + ("^go.work$" nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) + + ;; Groovy + ("Jenkinsfile\\'" nerd-icons-devicon "nf-dev-groovy" :face nerd-icons-cyan-alt) + + ;; Emacs + ("^bookmark" nerd-icons-octicon "nf-oct-bookmark" :face nerd-icons-lpink) + + ("^\\*scratch\\*$" nerd-icons-faicon "nf-fa-sticky_note" :face nerd-icons-lyellow) + ("^\\*scratch.*" nerd-icons-faicon "nf-fa-sticky_note" :face nerd-icons-yellow) + ("^\\*new-tab\\*$" nerd-icons-mdicon "nf-md-star" :face nerd-icons-cyan) + ("Cask\\'" nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) + ("Eask\\'" nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) + + ("^\\." nerd-icons-octicon "nf-oct-gear"))) + +(defvar nerd-icons-default-file-icon + '(nerd-icons-faicon "nf-fa-file_o")) + +(defvar nerd-icons-dir-icon-alist + '( + ("trash" nerd-icons-faicon "nf-fa-trash_o") + ("dropbox" nerd-icons-faicon "nf-fa-dropbox") + ("google[ _-]drive" nerd-icons-mdicon "nf-md-folder_google_drive") + ("github" nerd-icons-sucicon "nf-custom-folder_github") + ("^atom$" nerd-icons-devicon "nf-dev-atom") + ("documents" nerd-icons-mdicon "nf-md-folder_file") + ("download" nerd-icons-mdicon "nf-md-folder_download") + ("desktop" nerd-icons-octicon "nf-oct-device_desktop") + ("pictures" nerd-icons-mdicon "nf-md-folder_image") + ("photos" nerd-icons-faicon "nf-fa-camera_retro") + ("music" nerd-icons-mdicon "nf-md-folder_music") + ("movies" nerd-icons-faicon "nf-fa-film") + ("code" nerd-icons-octicon "nf-oct-code") + ("workspace" nerd-icons-octicon "nf-oct-code") + ;; ("test" nerd-icons-devicon "test-dir") + ("\\.git" nerd-icons-sucicon "nf-custom-folder_git") + ("\\.config" nerd-icons-sucicon "nf-custom-folder_config") + (".?" nerd-icons-sucicon "nf-custom-folder_oct"))) + +(defvar nerd-icons-weather-icon-alist + '( + ("tornado" nerd-icons-wicon "nf-weather-tornado") + ("hurricane" nerd-icons-wicon "nf-weather-hurricane") + ("thunderstorms" nerd-icons-wicon "nf-weather-thunderstorm") + ("sunny" nerd-icons-wicon "nf-weather-day_sunny") + ("rain.*snow" nerd-icons-wicon "nf-weather-rain_mix") + ("rain.*hail" nerd-icons-wicon "nf-weather-rain_mix") + ("sleet" nerd-icons-wicon "nf-weather-sleet") + ("hail" nerd-icons-wicon "nf-weather-hail") + ("drizzle" nerd-icons-wicon "nf-weather-sprinkle") + ("rain" nerd-icons-wicon "nf-weather-showers") + ("showers" nerd-icons-wicon "nf-weather-showers") + ("blowing.*snow" nerd-icons-wicon "nf-weather-snow_wind") + ("snow" nerd-icons-wicon "nf-weather-snow") + ("dust" nerd-icons-wicon "nf-weather-dust") + ("fog" nerd-icons-wicon "nf-weather-fog") + ("haze" nerd-icons-wicon "nf-weather-day_haze") + ("smoky" nerd-icons-wicon "nf-weather-smoke") + ("blustery" nerd-icons-wicon "nf-weather-cloudy_windy") + ("windy" nerd-icons-wicon "nf-weather-cloudy_gusts") + ("cold" nerd-icons-wicon "nf-weather-snowflake_cold") + ("partly.*cloudy.*night" nerd-icons-wicon "nf-weather-night_alt_partly_cloudy") + ("partly.*cloudy" nerd-icons-wicon "nf-weather-day_cloudy_high") + ("cloudy.*night" nerd-icons-wicon "nf-weather-night_alt_cloudy") + ("cxloudy.*day" nerd-icons-wicon "nf-weather-day_cloudy") + ("cloudy" nerd-icons-wicon "nf-weather-cloudy") + ("clear.*night" nerd-icons-wicon "nf-weather-night_clear") + ("fair.*night" nerd-icons-wicon "nf-weather-stars") + ("fair.*day" nerd-icons-wicon "nf-weather-horizon") + ("hot" nerd-icons-wicon "nf-weather-hot") + ("not.*available" nerd-icons-wicon "nf-weather-na"))) + +(defvar nerd-icons-mode-icon-alist + '( + (emacs-lisp-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple) + (circe-server-mode nerd-icons-faicon "nf-fa-commenting_o") + (circe-channel-mode nerd-icons-faicon "nf-fa-commenting_o") + (circe-query-mode nerd-icons-faicon "nf-fa-commenting_o") + (crystal-mode nerd-icons-sucicon "nf-custom-crystal" :face nerd-icons-yellow) + (erc-mode nerd-icons-faicon "nf-fa-commenting_o") + (inferior-emacs-lisp-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-lblue) + (dired-mode nerd-icons-octicon "nf-oct-file_directory") + (lisp-interaction-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-orange) + (sly-mrepl-mode nerd-icons-sucicon "nf-custom-common_lisp" :face nerd-icons-orange) + (slime-repl-mode nerd-icons-sucicon "nf-custom-common_lisp" :face nerd-icons-orange) + (org-mode nerd-icons-sucicon "nf-custom-orgmode" :face nerd-icons-lgreen) + (ledger-mode nerd-icons-mdicon "nf-md-file_table_box_multiple" :face nerd-icons-green) + (typescript-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) + (typescript-ts-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) + (typescript-tsx-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) + (tsx-ts-mode nerd-icons-mdicon "nf-md-language_typescript" :face nerd-icons-blue-alt) + (js-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + (js-ts-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + (js-jsx-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + (js2-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + (js3-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-yellow) + (rjsx-mode nerd-icons-devicon "nf-dev-javascript" :face nerd-icons-cyan-alt) + (term-mode nerd-icons-devicon "nf-dev-terminal") + (vterm-mode nerd-icons-devicon "nf-dev-terminal") + (eshell-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) + (magit-refs-mode nerd-icons-devicon "nf-dev-git_branch" :face nerd-icons-red) + (magit-process-mode nerd-icons-octicon "nf-oct-mark_github") + (magit-diff-mode nerd-icons-devicon "nf-dev-git_compare" :face nerd-icons-lblue) + (ediff-mode nerd-icons-devicon "nf-dev-git_compare" :face nerd-icons-red) + (diff-mode nerd-icons-devicon "nf-dev-git_compare" :face nerd-icons-lred) + (comint-mode nerd-icons-faicon "nf-fa-terminal" :face nerd-icons-lblue) + (eww-mode nerd-icons-faicon "nf-fa-firefox" :face nerd-icons-red) + (xwidget-webkit-mode nerd-icons-faicon "nf-fa-chrome" :face nerd-icons-blue) + (org-agenda-mode nerd-icons-octicon "nf-oct-checklist" :face nerd-icons-lgreen) + (cfw:calendar-mode nerd-icons-octicon "nf-oct-calendar") + (ibuffer-mode nerd-icons-faicon "nf-fa-files_o" :face nerd-icons-dsilver) + (messages-buffer-mode nerd-icons-faicon "nf-fa-file_o" :face nerd-icons-dsilver) + (help-mode nerd-icons-faicon "nf-fa-info" :face nerd-icons-purple) + (helpful-mode nerd-icons-faicon "nf-fa-info" :face nerd-icons-purple) + (Info-mode nerd-icons-faicon "nf-fa-info" :face nerd-icons-blue) + (benchmark-init/tree-mode nerd-icons-faicon "nf-fa-dashboard") + (jenkins-mode nerd-icons-devicon "nf-dev-jenkins" :face nerd-icons-blue) + (magit-popup-mode nerd-icons-sucicon "nf-seti-git" :face nerd-icons-red) + (magit-status-mode nerd-icons-sucicon "nf-seti-git" :face nerd-icons-lred) + (magit-log-mode nerd-icons-sucicon "nf-seti-git" :face nerd-icons-green) + (mu4e-compose-mode nerd-icons-octicon "nf-oct-pencil") + (mu4e-headers-mode nerd-icons-octicon "nf-oct-mail") + (mu4e-main-mode nerd-icons-octicon "nf-oct-mail") + (mu4e-view-mode nerd-icons-codicon "nf-cod-mail_read") + (notmuch-hello-mode nerd-icons-octicon "nf-oct-mail") + (notmuch-search-mode nerd-icons-octicon "nf-oct-mail") + (notmuch-tree-mode nerd-icons-octicon "nf-oct-mail") + (notmuch-show-mode nerd-icons-codicon "nf-cod-mail_read") + (sieve-mode nerd-icons-octicon "nf-oct-mail") + (gnus-group-mode nerd-icons-octicon "nf-oct-mail") + (gnus-summary-mode nerd-icons-octicon "nf-oct-mail") + (gnus-article-mode nerd-icons-codicon "nf-cod-mail_read") + (message-mode nerd-icons-octicon "nf-oct-pencil") + (package-menu-mode nerd-icons-faicon "nf-fa-archive" :face nerd-icons-silver) + (paradox-menu-mode nerd-icons-faicon "nf-fa-archive" :face nerd-icons-silver) + (Custom-mode nerd-icons-codicon "nf-cod-settings") + + ;; Special matcher for Web Mode based on the `web-mode-content-type' of the current buffer + (web-mode nerd-icons--web-mode-icon) + + (fundamental-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-dsilver) + (special-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-yellow) + (cask-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) + (eask-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-blue) + (text-mode nerd-icons-faicon "nf-fa-file_text" :face nerd-icons-cyan) + (enh-ruby-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-lred) + (ruby-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-lred) + (ruby-ts-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-lred) + (inf-ruby-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) + (projectile-rails-compilation-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) + (rspec-compilation-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) + (rake-compilation-mode nerd-icons-devicon "nf-dev-ruby" :face nerd-icons-red) + (sh-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) + (bash-ts-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) + (shell-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-purple) + (fish-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-lpink) + (bat-mode nerd-icons-codicon "nf-cod-terminal_cmd" :face nerd-icons-lsilver) + (nginx-mode nerd-icons-devicon "nf-dev-nginx" :face nerd-icons-dgreen) + ;; (apache-mode nerd-icons-alltheicon "apache" :face nerd-icons-dgreen) + (makefile-mode nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-dorange) + (makefile-ts-mode nerd-icons-devicon "nf-dev-gnu" :face nerd-icons-dorange) + ;; (cmake-mode nerd-icons-fileicon "cmake" :face nerd-icons-red) + ;; (cmake-ts-mode nerd-icons-fileicon "cmake" :face nerd-icons-red) + (dockerfile-mode nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-blue) + (dockerfile-ts-mode nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-blue) + (docker-compose-mode nerd-icons-sucicon "nf-seti-docker" :face nerd-icons-lblue) + (nxml-mode nerd-icons-faicon "nf-fa-file_code_o" :face nerd-icons-lorange) + (conf-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-lyellow) + (json-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + (json-ts-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + (jsonian-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-yellow) + (yaml-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) + (yaml-ts-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-dyellow) + (toml-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) + (toml-ts-mode nerd-icons-codicon "nf-cod-settings" :face nerd-icons-orange) + (elisp-byte-code-mode nerd-icons-octicon "nf-oct-file_binary" :face nerd-icons-dsilver) + (archive-mode nerd-icons-octicon "nf-oct-file_zip" :face nerd-icons-lmaroon) + (elm-mode nerd-icons-sucicon "nf-custom-elm" :face nerd-icons-blue) + (erlang-mode nerd-icons-devicon "nf-dev-erlang" :face nerd-icons-red) + (elixir-mode nerd-icons-sucicon "nf-custom-elixir" :face nerd-icons-lorange) + (elixir-ts-mode nerd-icons-sucicon "nf-custom-elixir" :face nerd-icons-lorange) + (java-mode nerd-icons-devicon "nf-dev-java" :face nerd-icons-purple) + (groovy-mode nerd-icons-devicon "nf-dev-groovy" :face nerd-icons-cyan) + (java-ts-mode nerd-icons-devicon "nf-dev-java" :face nerd-icons-purple) + (go-mode nerd-icons-devicon "nf-dev-go" :face nerd-icons-blue) + (go-ts-mode nerd-icons-devicon "nf-dev-go" :face nerd-icons-blue) + (go-dot-mod-mode nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) + (go-mod-ts-mode nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) + (go-dot-work-mode nerd-icons-sucicon "nf-seti-config" :face nerd-icons-blue-alt) + (graphql-mode nerd-icons-sucicon "nf-seti-graphql" :face nerd-icons-dpink) + ;; (matlab-mode nerd-icons-fileicon "matlab" :face nerd-icons-orange) + (nix-mode nerd-icons-mdicon "nf-md-nix" :face nerd-icons-blue) + (perl-mode nerd-icons-devicon "nf-dev-perl" :face nerd-icons-lorange) + (cperl-mode nerd-icons-devicon "nf-dev-perl" :face nerd-icons-lorange) + (php-mode nerd-icons-devicon "nf-dev-php" :face nerd-icons-lsilver) + (php-ts-mode nerd-icons-devicon "nf-dev-php" :face nerd-icons-lsilver) + (prolog-mode nerd-icons-devicon "nf-dev-prolog" :face nerd-icons-lmaroon) + (python-mode nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) + (python-ts-mode nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) + (inferior-python-mode nerd-icons-devicon "nf-dev-python" :face nerd-icons-dblue) + ;; (racket-mode nerd-icons-fileicon "racket" :face nerd-icons-red) + (rust-mode nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) + (rustic-mode nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) + (rust-ts-mode nerd-icons-devicon "nf-dev-rust" :face nerd-icons-maroon) + (scala-mode nerd-icons-devicon "nf-dev-scala" :face nerd-icons-red) + ;; (scheme-mode nerd-icons-fileicon "scheme" :face nerd-icons-red) + (swift-mode nerd-icons-devicon "nf-dev-swift" :face nerd-icons-green) + (svelte-mode nerd-icons-sucicon "nf-seti-svelte" :face nerd-icons-red) + (ada-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) + (ada-ts-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-blue) + (gpr-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) + (gpr-ts-mode nerd-icons-sucicon "nf-custom-ada" :face nerd-icons-green) + (c-mode nerd-icons-sucicon "nf-custom-c" :face nerd-icons-blue) + (c-ts-mode nerd-icons-sucicon "nf-custom-c" :face nerd-icons-blue) + (c++-mode nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) + (c++-ts-mode nerd-icons-sucicon "nf-custom-cpp" :face nerd-icons-blue) + (csharp-mode nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) + (csharp-ts-mode nerd-icons-mdicon "nf-md-language_csharp" :face nerd-icons-dblue) + (clojure-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-blue) + (clojure-ts-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-blue) + (cider-repl-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-green) + (clojurec-mode nerd-icons-sucicon "nf-seti-clojure" :face nerd-icons-blue) + (clojurec-ts-mode nerd-icons-sucicon "nf-seti-clojure" :face nerd-icons-blue) + (clojurescript-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-lyellow) + (clojurescript-ts-mode nerd-icons-devicon "nf-dev-clojure_alt" :face nerd-icons-lyellow) + (coffee-mode nerd-icons-devicon "nf-dev-coffeescript" :face nerd-icons-maroon) + (lisp-mode nerd-icons-sucicon "nf-custom-scheme" :face nerd-icons-orange) + (css-mode nerd-icons-devicon "nf-dev-css3" :face nerd-icons-yellow) + (css-ts-mode nerd-icons-devicon "nf-dev-css3" :face nerd-icons-yellow) + (scss-mode nerd-icons-mdicon "nf-md-sass" :face nerd-icons-pink) + (sass-mode nerd-icons-mdicon "nf-md-sass" :face nerd-icons-dpink) + (less-css-mode nerd-icons-devicon "nf-dev-less" :face nerd-icons-dyellow) + (stylus-mode nerd-icons-devicon "nf-dev-stylus" :face nerd-icons-lgreen) + (csv-mode nerd-icons-octicon "nf-oct-graph" :face nerd-icons-dblue) + (gdscript-mode nerd-icons-sucicon "nf-seti-godot" :face nerd-icons-blue) + (gdscript-ts-mode nerd-icons-sucicon "nf-seti-godot" :face nerd-icons-blue) + (haskell-mode nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + (haskell-c2hs-mode nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + (literate-haskell-mode nerd-icons-devicon "nf-dev-haskell" :face nerd-icons-red) + (haml-mode nerd-icons-sucicon "nf-seti-haml" :face nerd-icons-lyellow) + (html-mode nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) + (html-ts-mode nerd-icons-devicon "nf-dev-html5" :face nerd-icons-orange) + (rhtml-mode nerd-icons-devicon "nf-dev-html5" :face nerd-icons-lred) + ;; (mustache-mode nerd-icons-fileicon "moustache" :face nerd-icons-green) + (slim-mode nerd-icons-codicon "nf-cod-dashboard" :face nerd-icons-yellow) + (jade-mode nerd-icons-sucicon "nf-seti-jade" :face nerd-icons-red) + (pug-mode nerd-icons-sucicon "nf-seti-pug" :face nerd-icons-red) + (react-mode nerd-icons-devicon "nf-dev-react" :face nerd-icons-lblue) + (image-mode nerd-icons-octicon "nf-oct-file_media" :face nerd-icons-blue) + (texinfo-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (markdown-mode nerd-icons-octicon "nf-oct-markdown" :face nerd-icons-lblue) + (markdown-ts-mode nerd-icons-octicon "nf-oct-markdown" :face nerd-icons-lblue) + ;; (bibtex-mode nerd-icons-fileicon "bib" :face nerd-icons-maroon) + (compilation-mode nerd-icons-faicon "nf-fa-cogs") + (objc-mode nerd-icons-faicon "nf-fa-apple") + (tuareg-mode nerd-icons-sucicon "nf-seti-ocaml") + (purescript-mode nerd-icons-sucicon "nf-seti-purescript") + (verilog-mode nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + (verilog-ts-mode nerd-icons-mdicon "nf-md-chip" :face nerd-icons-red) + (vhdl-mode nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) + (vhdl-ts-mode nerd-icons-octicon "nf-oct-cpu" :face nerd-icons-blue) + ;; (haskell-cabal-mode nerd-icons-fileicon "cabal" :face nerd-icons-lblue) + (kotlin-mode nerd-icons-sucicon "nf-custom-kotlin" :face nerd-icons-orange) + (kotlin-ts-mode nerd-icons-sucicon "nf-custom-kotlin" :face nerd-icons-orange) + (nim-mode nerd-icons-sucicon "nf-seti-nim" :face nerd-icons-yellow) + (sql-mode nerd-icons-devicon "nf-dev-database" :face nerd-icons-silver) + (lua-mode nerd-icons-sucicon "nf-seti-lua" :face nerd-icons-dblue) + (lua-ts-mode nerd-icons-sucicon "nf-seti-lua" :face nerd-icons-dblue) + ;; (adoc-mode nerd-icons-fileicon "asciidoc" :face nerd-icons-lblue) + (puppet-mode nerd-icons-sucicon "nf-custom-puppet" :face nerd-icons-yellow) + (jinja2-mode nerd-icons-sucicon "nf-seti-jinja" :face nerd-icons-silver) + (powershell-mode nerd-icons-mdicon "nf-md-powershell" :face nerd-icons-blue) + (tex-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (latex-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (latex-ts-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (doctex-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + ;; Modes provided by AUCTeX 14.1 and higher + (TeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (LaTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (docTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (ConTeXt-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (AmSTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (plain-TeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (Texinfo-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (japanese-plain-TeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (japanese-LaTeX-mode nerd-icons-sucicon "nf-seti-tex" :face nerd-icons-lred) + (dart-mode nerd-icons-devicon "nf-dev-dart" :face nerd-icons-blue) + (fsharp-mode nerd-icons-devicon "nf-dev-fsharp" :face nerd-icons-blue) + (asm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) + (fasm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) + (masm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) + (nasm-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) + (gas-mode nerd-icons-sucicon "nf-seti-asm" :face nerd-icons-blue) + ;; (tcl-mode nerd-icons-fileicon "tcl" :face nerd-icons-dred) + ;; (cuda-mode nerd-icons-fileicon "nvidia" :face nerd-icons-green) + (f90-mode nerd-icons-mdicon "nf-md-language_fortran" :face nerd-icons-purple) + ;; (hy-mode nerd-icons-fileicon "hy" :face nerd-icons-blue) + (glsl-mode nerd-icons-faicon "nf-fa-paint_brush" :face nerd-icons-green) + (zig-mode nerd-icons-sucicon "nf-seti-zig" :face nerd-icons-orange) + ;; (odin-mode nerd-icons-fileicon "odin" :face nerd-icons-lblue) + (pdf-view-mode nerd-icons-codicon "nf-cod-file_pdf" :face nerd-icons-dred) + (doc-view-mode nerd-icons-mdicon "nf-md-file_document" :face nerd-icons-lred) + (calibre-library-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-dblue) + (calibre-edit-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lred) + (calibredb-search-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-dblue) + (calibredb-show-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lblue) + (osm-mode nerd-icons-mdicon "nf-md-map_search" :face nerd-icons-lgreen) + (spacemacs-buffer-mode nerd-icons-sucicon "nf-custom-emacs" :face nerd-icons-purple) + + (elfeed-search-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-orange) + (elfeed-summary-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-orange) + (elfeed-show-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-yellow) + (newsticker-treeview-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-orange) + (newsticker-treeview-list-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-lorange) + (newsticker-treeview-item-mode nerd-icons-faicon "nf-fa-rss_square" :face nerd-icons-yellow) + + (emms-browser-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (emms-lyrics-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (emms-show-all-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (emms-metaplaylist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (emms-tag-editor-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (emms-playlist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (lilypond-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-green) + (bongo-playlist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (bongo-library-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (mingus-playlist-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (mingus-help-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (mingus-browse-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (mingus-burn-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (simple-mpc-mode nerd-icons-faicon "nf-fa-music" :face nerd-icons-silver) + (telega-root-mode nerd-icons-faicon "nf-fae-telegram" :face nerd-icons-purple) + (telega-chat-mode nerd-icons-faicon "nf-fae-telegram" :face nerd-icons-blue) + (mastodon-mode nerd-icons-mdicon "nf-md-mastodon" :face nerd-icons-blue) + + (fanyi-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lcyan) + (osx-dictionary-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lcyan) + (youdao-dictionary-mode nerd-icons-codicon "nf-cod-library" :face nerd-icons-lcyan) + + (magik-mode nerd-icons-faicon "nf-fa-magic" :face nerd-icons-blue) + (magik-ts-mode nerd-icons-faicon "nf-fa-magic" :face nerd-icons-blue) + (magik-session-mode nerd-icons-devicon "nf-dev-terminal" :face nerd-icons-blue) + (magik-cb-mode nerd-icons-faicon "nf-fa-book" :face nerd-icons-blue) + ;; (meson-mode nerd-icons-fileicon "meson" :face nerd-icons-purple) + ;; (man-common nerd-icons-fileicon "man-page" :face nerd-icons-blue) + (heex-mode nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) + (heex-ts-mode nerd-icons-sucicon "nf-seti-elixir" :face nerd-icons-lorange) + (julia-mode nerd-icons-sucicon "nf-seti-julia" :face nerd-icons-purple) + (julia-ts-mode nerd-icons-sucicon "nf-seti-julia" :face nerd-icons-purple) + (flycheck-error-list nerd-icons-faicon "nf-fa-list_alt" :face nerd-icons-lred))) + +(defvar nerd-icons-url-alist + '( + ;; Social media and communities + ("^\\(https?://\\)?\\(www\\.\\)?del\\.icio\\.us" nerd-icons-faicon "nf-fa-delicious") + ("^\\(https?://\\)?\\(www\\.\\)?behance\\.net" nerd-icons-faicon "nf-fa-behance") + ("^\\(https?://\\)?\\(www\\.\\)?dribbble\\.com" nerd-icons-faicon "nf-fa-dribbble") + ("^\\(https?://\\)?\\(www\\.\\)?facebook\\.com" nerd-icons-faicon "nf-fa-facebook_official") + ("^\\(https?://\\)?\\(www\\.\\)?glide\\.me" nerd-icons-faicon "nf-fa-glide_g") + ("^\\(https?://\\)?\\(www\\.\\)?plus\\.google\\.com" nerd-icons-faicon "nf-fa-google_plus") + ("linkedin\\.com" nerd-icons-faicon "nf-fa-linkedin") + ("^\\(https?://\\)?\\(www\\.\\)?ok\\.ru" nerd-icons-faicon "nf-fa-odnoklassniki") + ("^\\(https?://\\)?\\(www\\.\\)?reddit\\.com" nerd-icons-faicon "nf-fa-reddit_alien") + ("^\\(https?://\\)?\\(www\\.\\)?slack\\.com" nerd-icons-faicon "nf-fa-slack") + ("^\\(https?://\\)?\\(www\\.\\)?snapchat\\.com" nerd-icons-faicon "nf-fa-snapchat_ghost") + ("^\\(https?://\\)?\\(www\\.\\)?weibo\\.com" nerd-icons-faicon "nf-fa-weibo") + ("^\\(https?://\\)?\\(www\\.\\)?twitter\\.com" nerd-icons-faicon "nf-fa-twitter") + ;; Blogging + ("joomla\\.org" nerd-icons-faicon "nf-fa-joomla") + ("^\\(https?://\\)?\\(www\\.\\)?medium\\.com" nerd-icons-faicon "nf-fa-medium") + ("tumblr\\.com" nerd-icons-faicon "nf-fa-tumblr") + ("^wordpress\\.com" nerd-icons-faicon "nf-fa-wordpress") + ;; Programming + ("^\\(https?://\\)?\\(www\\.\\)?bitbucket\\.org" nerd-icons-faicon "nf-fa-bitbucket") + ("^\\(https?://\\)?\\(www\\.\\)?codepen\\.io" nerd-icons-faicon "nf-fa-codepen") + ("^\\(https?://\\)?\\(www\\.\\)?codiepie\\.com" nerd-icons-faicon "nf-fa-codiepie") + ("^\\(https?://\\)?\\(www\\.\\)?gist\\.github\\.com" nerd-icons-octicon "nf-oct-logo_gist") + ("^\\(https?://\\)?\\(www\\.\\)?github\\.com" nerd-icons-octicon "nf-oct-mark_github") + ("^\\(https?://\\)?\\(www\\.\\)?gitlab\\.com" nerd-icons-faicon "nf-fa-gitlab") + ("^\\(https?://\\)?\\(www\\.\\)?news\\.ycombinator\\.com" nerd-icons-faicon "nf-fa-hacker_news") + ("^\\(https?://\\)?\\(www\\.\\)?jsfiddle\\.net" nerd-icons-faicon "nf-fa-jsfiddle") + ("^\\(https?://\\)?\\(www\\.\\)?maxcdn\\.com" nerd-icons-faicon "nf-fa-maxcdn") + ("^\\(https?://\\)?\\(www\\.\\)?stackoverflow\\.com" nerd-icons-faicon "nf-fa-stack_overflow") + ;; Video + ("^\\(https?://\\)?\\(www\\.\\)?twitch\\.tv" nerd-icons-faicon "nf-fa-twitch") + ("^\\(https?://\\)?\\(www\\.\\)?vimeo\\.com" nerd-icons-faicon "nf-fa-vimeo") + ("^\\(https?://\\)?\\(www\\.\\)?youtube\\.com" nerd-icons-faicon "nf-fa-youtube") + ("^\\(https?://\\)?\\(www\\.\\)?youtu\\.be" nerd-icons-faicon "nf-fa-youtube") + ("^\\(https?://\\)?\\(www\\.\\)?vine\\.co" nerd-icons-faicon "nf-fa-vine") + ;; Sound + ("^\\(https?://\\)?\\(www\\.\\)?last\\.fm" nerd-icons-faicon "nf-fa-lastfm") + ("^\\(https?://\\)?\\(www\\.\\)?mixcloud\\.com" nerd-icons-faicon "nf-fa-mixcloud") + ("^\\(https?://\\)?\\(www\\.\\)?soundcloud\\.com" nerd-icons-faicon "nf-fa-soundcloud") + ("spotify\\.com" nerd-icons-faicon "nf-fa-spotify") + ;; Shopping + ("^\\(https?://\\)?\\(www\\.\\)?amazon\\." nerd-icons-faicon "nf-fa-amazon") + ("^\\(https?://\\)?\\(www\\.\\)?opencart\\.com" nerd-icons-faicon "nf-fa-opencart") + ("^\\(https?://\\)?\\(www\\.\\)?paypal\\.com" nerd-icons-faicon "nf-fa-paypal") + ("^\\(https?://\\)?\\(www\\.\\)?shirtsinbulk\\.com" nerd-icons-faicon "nf-fa-shitsinbulk") + ;; Images + ("^\\(https?://\\)?\\(www\\.\\)?500px\\.com" nerd-icons-faicon "nf-fa-500px") + ("^\\(https?://\\)?\\(www\\.\\)?deviantart\\.com" nerd-icons-faicon "nf-fa-deviantart") + ("^\\(https?://\\)?\\(www\\.\\)?flickr\\.com" nerd-icons-faicon "nf-fa-flickr") + ("^\\(https?://\\)?\\(www\\.\\)?instagram\\.com" nerd-icons-faicon "nf-fa-instagram") + ("^\\(https?://\\)?\\(www\\.\\)?pinterest\\." nerd-icons-faicon "nf-fa-pinterest") + ;; Information and books + ("^\\(https?://\\)?\\(www\\.\\)?digg\\.com" nerd-icons-faicon "nf-fa-digg") + ("^\\(https?://\\)?\\(www\\.\\)?foursquare\\.com" nerd-icons-faicon "nf-fa-foursquare") + ("^\\(https?://\\)?\\(www\\.\\)?getpocket\\.com" nerd-icons-faicon "nf-fa-get_pocket") + ("^\\(https?://\\)?\\(www\\.\\)?scribd\\.com" nerd-icons-faicon "nf-fa-scribd") + ("^\\(https?://\\)?\\(www\\.\\)?slideshare\\.net" nerd-icons-faicon "nf-fa-slideshare") + ("stackexchange\\.com" nerd-icons-faicon "nf-fa-stack_exchange") + ("^\\(https?://\\)?\\(www\\.\\)?stumbleupon\\.com" nerd-icons-faicon "nf-fa-stumbleupon") + ("^\\(https?://\\)?\\(www\\.\\)?tripadvisor\\." nerd-icons-faicon "nf-fa-tripadvisor") + ("^\\(https?://\\)?\\(www\\.\\)?yelp\\." nerd-icons-faicon "nf-fa-yelp") + + ("wikipedia\\.org" nerd-icons-faicon "nf-fa-wikipedia_w") + ;; Various companies and tools + ("^\\(https?://\\)?\\(www\\.\\)?angel\\.co" nerd-icons-faicon "nf-fa-angellist") + ("^\\(https?://\\)?\\(www\\.\\)?apple\\.com" nerd-icons-faicon "nf-fa-apple") + ("^\\(https?://\\)?\\(www\\.\\)?buysellads\\.com" nerd-icons-faicon "nf-fa-buysellads") + ("^\\(https?://\\)?\\(www\\.\\)?connectdevelop\\.com" nerd-icons-faicon "nf-fa-connectdevelop") + ("^\\(https?://\\)?\\(www\\.\\)?dashcube\\.com" nerd-icons-faicon "nf-fa-dashcube") + ("^\\(https?://\\)?\\(www\\.\\)?dropbox\\.com" nerd-icons-faicon "nf-fa-dropbox") + ("^\\(https?://\\)?\\(www\\.\\)?enviragallery\\.com" nerd-icons-faicon "nf-fa-envira") + ("^\\(https?://\\)?\\(www\\.\\)?fortawesome\\.com" nerd-icons-faicon "nf-fa-fort_awesome") + ("^\\(https?://\\)?\\(www\\.\\)?forumbee\\.com" nerd-icons-faicon "nf-fa-forumbee") + ("^\\(https?://\\)?\\(www\\.\\)?gratipay\\.com" nerd-icons-faicon "nf-fa-gratipay") + ("^\\(https?://\\)?\\(www\\.\\)?modx\\.com" nerd-icons-faicon "nf-fa-modx") + ("^\\(https?://\\)?\\(www\\.\\)?pagelines\\.com" nerd-icons-faicon "nf-fa-pagelines") + ("^\\(https?://\\)?\\(www\\.\\)?producthunt\\.com" nerd-icons-faicon "nf-fa-product_hunt") + ("sellsy\\.com" nerd-icons-faicon "nf-fa-sellsy") + ("^\\(https?://\\)?\\(www\\.\\)?simplybuilt\\.com" nerd-icons-faicon "nf-fa-simplybuilt") + ("^\\(https?://\\)?\\(www\\.\\)?skyatlas\\.com" nerd-icons-faicon "nf-fa-skyatlas") + ("^\\(https?://\\)?\\(www\\.\\)?skype\\.com" nerd-icons-faicon "nf-fa-skype") + ("steampowered\\.com" nerd-icons-faicon "nf-fa-steam") + ("^\\(https?://\\)?\\(www\\.\\)?themeisle\\.com" nerd-icons-faicon "nf-fa-themeisle") + ("^\\(https?://\\)?\\(www\\.\\)?trello\\.com" nerd-icons-faicon "nf-fa-trello") + ("^\\(https?://\\)?\\(www\\.\\)?whatsapp\\.com" nerd-icons-faicon "nf-fa-whatsapp") + ("^\\(https?://\\)?\\(www\\.\\)?ycombinator\\.com" nerd-icons-faicon "nf-fa-y_combinator") + ("yahoo\\.com" nerd-icons-faicon "nf-fa-yahoo") + ("^\\(https?://\\)?\\(www\\.\\)?yoast\\.com" nerd-icons-faicon "nf-fa-yoast") + ;; Catch all + ("android" nerd-icons-faicon "nf-fa-android") + ("creativecommons" nerd-icons-faicon "nf-fa-creative_commons") + ("forums?" nerd-icons-codicon "nf-cod-comment_discussion") + ("\\.pdf$" nerd-icons-codicon "nf-cod-file_pdf" :face nerd-icons-dred) + ("google" nerd-icons-faicon "nf-fa-google") + ("\\.rss" nerd-icons-faicon "nf-fa-rss"))) + +(defun nerd-icons-auto-mode-match? (&optional file) + "Whether or not FILE's `major-mode' match against its `auto-mode-alist'." + (let* ((file (or file (buffer-file-name) (buffer-name))) + (auto-mode (nerd-icons-match-to-alist file auto-mode-alist))) + (eq major-mode auto-mode))) + +(defun nerd-icons-match-to-alist (file alist) + "Match FILE against an entry in ALIST using `string-match'." + (cdr (cl-find-if (lambda (it) (string-match (car it) file)) alist))) + +(defun nerd-icons-dir-is-submodule (dir) + "Checker whether or not DIR is a git submodule." + (let* ((gitmodule-dir (locate-dominating-file dir ".gitmodules")) + (modules-file (expand-file-name (format "%s.gitmodules" gitmodule-dir))) + (module-search (format "submodule \".*?%s\"" (file-name-base dir)))) + + (when (and gitmodule-dir (file-exists-p (format "%s/.git" dir))) + (with-temp-buffer + (insert-file-contents modules-file) + (search-forward-regexp module-search (point-max) t))))) + +(defun nerd-icons--read-candidates () + "Helper to build a list of candidates for all glyph sets." + (cl-reduce 'append (mapcar (lambda (it) (nerd-icons--read-candidates-for-glyph-set it t)) nerd-icons-glyph-sets))) + +(defun nerd-icons--read-candidates-for-glyph-set (glyph-set &optional show-glyph-set) + "Helper to build read candidates for GLYPH-SET. + +If SHOW-GLYPH-SET is non-nil, displays the icons glyph set in the candidate +string." + (let ((data (funcall (nerd-icons--data-name glyph-set))) + (icon-f (nerd-icons--function-name glyph-set))) + (mapcar + (lambda (it) + (let* ((icon-name (car it)) + + (icon-display (funcall icon-f icon-name)) + (icon-glyph-set (if show-glyph-set (format "\t[%s]" glyph-set) "")) + + (candidate-name (format "%s\t%s%s" icon-display icon-name icon-glyph-set)) + (candidate-icon (funcall (nerd-icons--function-name glyph-set) icon-name))) + (cons candidate-name candidate-icon))) + data))) + +;;;###autoload +(defun nerd-icons-install-fonts (&optional pfx) + "Helper function to download and install the latests fonts based on OS. +The provided Nerd Font is Symbols Nerd Font Mono. +When PFX is non-nil, ignore the prompt and just install" + (interactive "P") + (when (or pfx (yes-or-no-p "This will download and install fonts, are you sure you want to do this?")) + (let* ((url-format "https://raw.githubusercontent.com/rainstormstudio/nerd-icons.el/main/fonts/%s") + (font-dest (cond + ;; Default Linux install directories + ((member system-type '(gnu gnu/linux gnu/kfreebsd)) + (concat (or (getenv "XDG_DATA_HOME") + (concat (getenv "HOME") "/.local/share")) + "/fonts/" + nerd-icons-fonts-subdirectory)) + ;; Default MacOS install directory + ((eq system-type 'darwin) + (concat (getenv "HOME") + "/Library/Fonts/" + nerd-icons-fonts-subdirectory)))) + (known-dest? (stringp font-dest)) + (font-dest (or font-dest (read-directory-name "Font installation directory: " "~/")))) + + (unless (file-directory-p font-dest) (mkdir font-dest t)) + + (mapc (lambda (font) + (url-copy-file (format url-format font) (expand-file-name font font-dest) t)) + nerd-icons-font-names) + (when known-dest? + (message "Fonts downloaded, updating font cache... <fc-cache -f -v> ") + (shell-command-to-string (format "fc-cache -f -v"))) + (message "%s Successfully %s `nerd-icons' fonts to `%s'!" + (nerd-icons-wicon "nf-weather-stars" :v-adjust 0.0) + (if known-dest? "installed" "downloaded") + font-dest)))) + +;;;###autoload +(defun nerd-icons-insert (&optional arg glyph-set) + "Interactive icon insertion function. +When Prefix ARG is non-nil, insert the propertized icon. +When GLYPH-SET is non-nil, limit the candidates to the icon set matching it." + (interactive "P") + (let* ((standard-output (current-buffer)) + (candidates (if glyph-set + (nerd-icons--read-candidates-for-glyph-set glyph-set) + (nerd-icons--read-candidates))) + (prompt (if glyph-set + (format "%s Icon: " (funcall (nerd-icons--glyph-set-name glyph-set))) + "Icon : ")) + (selection (completing-read prompt candidates nil t)) + (result (cdr (assoc selection candidates)))) + + (if arg (prin1 result) (insert result)))) + +;;;###autoload +(defun nerd-icons-icon-for-dir (dir &rest arg-overrides) + "Get the formatted icon for DIR. +ARG-OVERRIDES should be a plist containining `:height', +`:v-adjust' or `:face' properties like in the normal icon +inserting functions." + (let* ((dir (or dir default-directory "/")) + (dirname (file-name-base (directory-file-name dir))) + (path (if (file-name-absolute-p dir) dir (expand-file-name dir))) + (icon (nerd-icons-match-to-alist dirname nerd-icons-dir-icon-alist)) + (args (cdr icon))) + (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) + (cond + ((file-remote-p path) + (apply #'nerd-icons-codicon "nf-cod-remote" (cdr args))) + ((file-symlink-p path) + (apply #'nerd-icons-codicon "nf-cod-file_symlink_directory" (cdr args))) + ((nerd-icons-dir-is-submodule path) + (apply #'nerd-icons-codicon "nf-cod-file_submodule" (cdr args))) + ((file-exists-p (format "%s/.git" path)) + (apply #'nerd-icons-octicon "nf-oct-repo" (cdr args))) + (t (apply (car icon) args))))) + +;;;###autoload +(defun nerd-icons-icon-for-file (file &rest arg-overrides) + "Get the formatted icon for FILE. +ARG-OVERRIDES should be a plist containining `:height', +`:v-adjust' or `:face' properties like in the normal icon +inserting functions." + (let* ((name (file-name-nondirectory file)) + (ext (file-name-extension name)) + (icon (or (nerd-icons-match-to-alist name nerd-icons-regexp-icon-alist) + (and ext + (cdr (assoc (downcase ext) + nerd-icons-extension-icon-alist))) + nerd-icons-default-file-icon)) + (args (cdr icon))) + (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) + (apply (car icon) args))) + +;;;###autoload +(defun nerd-icons-icon-for-extension (ext &rest arg-overrides) + "Get the formatted icon for EXT. +ARG-OVERRIDES should be a plist containining `:height', +`:v-adjust' or `:face' properties like in the normal icon +inserting functions." + (let* ((icon (or + (and ext + (cdr (assoc (downcase ext) + nerd-icons-extension-icon-alist))) + nerd-icons-default-file-icon)) + (args (cdr icon))) + (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) + (apply (car icon) args))) + +;;;###autoload +(defun nerd-icons-icon-for-mode (mode &rest arg-overrides) + "Get the formatted icon for MODE. +ARG-OVERRIDES should be a plist containining `:height', +`:v-adjust' or `:face' properties like in the normal icon +inserting functions." + (let* ((icon (or (cdr (or (assoc mode nerd-icons-mode-icon-alist) + (assoc (get mode 'derived-mode-parent) nerd-icons-mode-icon-alist))) + nerd-icons-default-file-icon)) + (args (cdr icon))) + (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) + (if icon (apply (car icon) args) mode))) + +;;;###autoload +(defun nerd-icons-icon-for-url (url &rest arg-overrides) + "Get the formatted icon for URL. +If an icon for URL isn't found in `nerd-icons-url-alist', a globe is used. +ARG-OVERRIDES should be a plist containining `:height', +`:v-adjust' or `:face' properties like in the normal icon +inserting functions." + (let* ((icon (nerd-icons-match-to-alist url nerd-icons-url-alist)) + (args (cdr icon))) + (unless icon + (setq icon '(nerd-icons-faicon "nf-fa-globe")) + (setq args (cdr icon))) + (when arg-overrides (setq args (append `(,(car args)) arg-overrides (cdr args)))) + (apply (car icon) args))) + +;;;###autoload +(defun nerd-icons-icon-for-buffer () + "Get the formatted icon for the current buffer. + +This function prioritises the use of the buffers file extension to +discern the icon when its `major-mode' matches its auto mode, +otherwise it will use the buffers `major-mode' to decide its +icon." + (nerd-icons--icon-info-for-buffer)) + +(defun nerd-icons-cache (func) + "Set a cache for FUNC. Does not work on interactive functions." + (unless (get func 'nerd-icons--cached) + (let ((cache (make-hash-table :test #'equal + :size nerd-icons--cache-limit)) + (orig-fn (symbol-function func))) + (fset func + (lambda (&rest args) + (or (gethash args cache) + (progn + (when (> (hash-table-count cache) + nerd-icons--cache-limit) + (clrhash cache)) + (puthash args (apply orig-fn args) cache))))))) + + (put func 'nerd-icons--cached t)) + +(nerd-icons-cache #'nerd-icons-icon-for-dir) +(nerd-icons-cache #'nerd-icons-icon-for-file) +(nerd-icons-cache #'nerd-icons-icon-for-extension) +(nerd-icons-cache #'nerd-icons-icon-for-mode) +(nerd-icons-cache #'nerd-icons-icon-for-url) + +(defun nerd-icons--icon-info-for-buffer (&optional f) + "Get icon info for the current buffer. +When F is provided, the info function is calculated with the format +`nerd-icons-icon-%s-for-file' or `nerd-icons-icon-%s-for-mode'." + (let* ((base-f (concat "nerd-icons-icon" (when f (format "-%s" f)))) + (file-f (intern (concat base-f "-for-file"))) + (mode-f (intern (concat base-f "-for-mode")))) + (if (and (buffer-file-name) + (nerd-icons-auto-mode-match?)) + (funcall file-f (file-name-nondirectory (buffer-file-name))) + (funcall mode-f major-mode)))) + +;; Weather icons +(defun nerd-icons-icon-for-weather (weather) + "Get an icon for a WEATHER status." + (let ((icon (nerd-icons-match-to-alist weather nerd-icons-weather-icon-alist))) + (if icon (apply (car icon) (cdr icon)) weather))) + +;; For `web-mode' +(defun nerd-icons--web-mode-icon (&rest arg-overrides) + "Get icon for a `web-mode' buffer with ARG-OVERRIDES." + (nerd-icons--web-mode arg-overrides)) +(defun nerd-icons--web-mode-icon-family () + "Get icon family for a `web-mode' buffer." + (nerd-icons--web-mode t)) + +(defvar web-mode-content-type) ; external +(defun nerd-icons--web-mode (&optional arg-overrides) + "Return icon or FAMILY for `web-mode' based on `web-mode-content-type'. +Providing ARG-OVERRIDES will modify the creation of the icon." + (let ((non-nil-args (cl-reduce (lambda (acc it) (if it (append acc (list it)) acc)) + arg-overrides :initial-value '()))) + (cond + ((equal web-mode-content-type "jsx") + (apply 'nerd-icons-devicon (append '("javascript") non-nil-args))) + ((equal web-mode-content-type "javascript") + (apply 'nerd-icons-devicon (append '("javascript") non-nil-args))) + ((equal web-mode-content-type "json") + (apply 'nerd-icons-devicon (append '("nf-dev-less") non-nil-args))) + ((equal web-mode-content-type "xml") + (apply 'nerd-icons-faicon (append '("nf-fa-file_code_o") non-nil-args))) + ((equal web-mode-content-type "css") + (apply 'nerd-icons-devicon (append '("nf-dev-css3") non-nil-args))) + (t + (apply 'nerd-icons-devicon (append '("nf-dev-html5") non-nil-args)))))) + +(eval-and-compile + (defun nerd-icons--function-name (name) + "Get the symbol for an icon function name for icon set NAME." + (intern (concat "nerd-icons-" (downcase (symbol-name name))))) + + (defun nerd-icons--family-name (name) + "Get the symbol for an icon family function for icon set NAME." + (intern (concat "nerd-icons-" (downcase (symbol-name name)) "-family"))) + + (defun nerd-icons--glyph-set-name (name) + "Get the symbol for an icon glyph set function for icon set NAME." + (intern (concat "nerd-icons-" (downcase (symbol-name name)) "-glyph-set"))) + + (defun nerd-icons--data-name (name) + "Get the symbol for an icon family function for icon set NAME." + (intern (concat "nerd-icons-" (downcase (symbol-name name)) "-data"))) + + (defun nerd-icons--insert-function-name (name) + "Get the symbol for an icon insert function for icon set NAME." + (intern (concat "nerd-icons-insert-" (downcase (symbol-name name)))))) + +(defun nerd-icons-insert-icons-for (family &optional height duration) + "Insert all of the available icons associated with FAMILY. +If a HEIGHT is provided it will render the icons at this height. +This is useful both to see the icons more clearly and to test +different height rendering. If DURATION is provided, it will +pause for DURATION seconds between printing each character." + (let* ((data-f (nerd-icons--data-name family)) + (insert-f (nerd-icons--function-name family)) + + (height (or height 1.0)) + (data (funcall data-f))) + (mapc + (lambda (it) + (insert (format "%s - %s\n" (funcall insert-f (car it) :height height) (car it))) + (when duration (sit-for duration))) + data))) + +(defun nerd-icons-set-font (&optional font-family frame) + "Modify nerd font charsets to use FONT-FAMILY for FRAME." + (let ((font-f (or font-family nerd-icons-font-family)) + (charsets '((#xe5fa . #xe6b2) ;; Seti-UI + Custom + (#xe700 . #xe7c5) ;; Devicons + (#xf000 . #xf2e0) ;; Font Awesome + (#xe200 . #xe2a9) ;; Font Awesome Extension + (#xf500 . #xfd46) (#xf0001 . #xf1af0) ;; Material Design Icons + (#xe300 . #xe3eb) ;; Weather + (#xf400 . #xf4a8) #x2665 #x26a1 #xf27c ;; Octicons + (#xe0a0 . #xe0a2) (#xe0b0 . #xe0b3) ;; Powerline Symbols + #xe0a3 (#xe0b4 . #xe0c8) (#xe0cc . #xe0d2) #xe0d4 ;; Powerline Extra Symbols + (#x23fb . #x23fe) #x2b58 ;; IEC Power Symbols + (#xf300 . #xf372) ;; Font Logos + (#xe000 . #xe00a) ;; Pomicons + (#xea60 . #xebeb)))) ;; Codicons + (cl-loop for charset in charsets do + (set-fontset-font + (frame-parameter nil 'font) + charset + (font-spec :family font-f + :weight nil + :size nil) + frame + 'prepend)))) + +(defmacro nerd-icons-define-icon (name alist family glyph-set) + "Macro to generate functions for inserting icons for icon set NAME. + +NAME defines is the name of the iconset and will produce a +function of the for `nerd-icon-NAME'. + +ALIST is the alist containing maps between icon names and the +UniCode for the character. All of these can be found in the data +directory of this package. + +FAMILY is the font family to use for the icons. +GLYPH-SET is the glyph set of the icon." + `(progn + (add-to-list 'nerd-icons-glyph-sets (quote ,name)) + (defun ,(nerd-icons--family-name name) () ,family) + (defun ,(nerd-icons--glyph-set-name name) () ,glyph-set) + (defun ,(nerd-icons--data-name name) () ,alist) + (defun ,(nerd-icons--function-name name) (icon-name &rest args) + (let ((icon (cdr (assoc icon-name ,alist))) + (other-face (when nerd-icons-color-icons (plist-get args :face))) + (height (* nerd-icons-scale-factor (or (plist-get args :height) 1.0))) + (v-adjust (* nerd-icons-scale-factor (or (plist-get args :v-adjust) nerd-icons-default-adjust))) + (family ,family)) + (unless icon + (error "Unable to find icon with name `%s' in icon set `%s'" icon-name (quote ,name))) + (let ((face (if other-face + `(:family ,family :height ,height :inherit ,other-face) + `(:family ,family :height ,height)))) + (propertize icon + 'face face + 'font-lock-face face + 'display `(raise ,v-adjust) + 'rear-nonsticky t)))) + (defun ,(nerd-icons--insert-function-name name) (&optional arg) + ,(format "Insert a %s icon at point." glyph-set) + (interactive "P") + (nerd-icons-insert arg (quote ,name))))) + +(nerd-icons-define-icon ipsicon nerd-icons/ipsicon-alist nerd-icons-font-family "IEC Power Symbols") +(nerd-icons-define-icon octicon nerd-icons/octicon-alist nerd-icons-font-family "Octicons") +(nerd-icons-define-icon pomicon nerd-icons/pomicon-alist nerd-icons-font-family "Pomicons") +(nerd-icons-define-icon powerline nerd-icons/powerline-alist nerd-icons-font-family "Powerline Symbols") +(nerd-icons-define-icon faicon nerd-icons/faicon-alist nerd-icons-font-family "Font Awesome") +(nerd-icons-define-icon wicon nerd-icons/wicon-alist nerd-icons-font-family "Weather") +(nerd-icons-define-icon sucicon nerd-icons/sucicon-alist nerd-icons-font-family "Seti-UI + Custom") +(nerd-icons-define-icon devicon nerd-icons/devicon-alist nerd-icons-font-family "Devicons") +(nerd-icons-define-icon codicon nerd-icons/codicon-alist nerd-icons-font-family "Codicons") +(nerd-icons-define-icon flicon nerd-icons/flicon-alist nerd-icons-font-family "Font Logos") +(nerd-icons-define-icon mdicon nerd-icons/mdicon-alist nerd-icons-font-family "Material Design Icons") + +(provide 'nerd-icons) +;;; nerd-icons.el ends here diff --git a/emacs/elpa/nerd-icons-20240816.1555/nerd-icons.elc b/emacs/elpa/nerd-icons-20240816.1555/nerd-icons.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-autoloads.el b/emacs/elpa/notmuch-20240809.1318/notmuch-autoloads.el @@ -1,234 +0,0 @@ -;;; notmuch-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from coolj.el - -(register-definition-prefixes "coolj" '("coolj-")) - - -;;; Generated autoloads from make-deps.el - -(register-definition-prefixes "make-deps" '("batch-make-deps" "make-deps")) - - -;;; Generated autoloads from notmuch.el - -(autoload 'notmuch-search "notmuch" "\ -Display threads matching QUERY in a notmuch-search buffer. - -If QUERY is nil, it is read interactively from the minibuffer. -Other optional parameters are used as follows: - - OLDEST-FIRST: A Boolean controlling the sort order of returned threads - HIDE-EXCLUDED: A boolean controlling whether to omit threads with excluded - tags. - TARGET-THREAD: A thread ID (without the thread: prefix) that will be made - current if it appears in the search results. - TARGET-LINE: The line number to move to if the target thread does not - appear in the search results. - NO-DISPLAY: Do not try to foreground the search results buffer. If it is - already foregrounded i.e. displayed in a window, this has no - effect, meaning the buffer will remain visible. - -When called interactively, this will prompt for a query and use -the configured default sort order. - -(fn &optional QUERY OLDEST-FIRST HIDE-EXCLUDED TARGET-THREAD TARGET-LINE NO-DISPLAY)" t) -(autoload 'notmuch "notmuch" "\ -Run notmuch and display saved searches, known tags, etc." t) -(autoload 'notmuch-cycle-notmuch-buffers "notmuch" "\ -Cycle through any existing notmuch buffers (search, show or hello). - -If the current buffer is the only notmuch buffer, bury it. -If no notmuch buffers exist, run `notmuch'." t) -(register-definition-prefixes "notmuch" '("notmuch-")) - - -;;; Generated autoloads from notmuch-address.el - -(register-definition-prefixes "notmuch-address" '("notmuch-address-")) - - -;;; Generated autoloads from notmuch-company.el - -(autoload 'notmuch-company-setup "notmuch-company") -(autoload 'notmuch-company "notmuch-company" "\ -`company-mode' completion back-end for `notmuch'. - -(fn COMMAND &optional ARG &rest IGNORE)" t) -(register-definition-prefixes "notmuch-company" '("notmuch-company-last-prefix")) - - -;;; Generated autoloads from notmuch-compat.el - -(register-definition-prefixes "notmuch-compat" '("notmuch-")) - - -;;; Generated autoloads from notmuch-crypto.el - -(register-definition-prefixes "notmuch-crypto" '("notmuch-crypto-")) - - -;;; Generated autoloads from notmuch-draft.el - -(register-definition-prefixes "notmuch-draft" '("notmuch-draft-")) - - -;;; Generated autoloads from notmuch-hello.el - -(autoload 'notmuch-hello "notmuch-hello" "\ -Run notmuch and display saved searches, known tags, etc. - -(fn &optional NO-DISPLAY)" t) -(register-definition-prefixes "notmuch-hello" '("notmuch-")) - - -;;; Generated autoloads from notmuch-jump.el - -(autoload 'notmuch-jump-search "notmuch-jump" "\ -Jump to a saved search by shortcut key. - -This prompts for and performs a saved search using the shortcut -keys configured in the :key property of `notmuch-saved-searches'. -Typically these shortcuts are a single key long, so this is a -fast way to jump to a saved search from anywhere in Notmuch." t) -(autoload 'notmuch-jump "notmuch-jump" "\ -Interactively prompt for one of the keys in ACTION-MAP. - -Displays a summary of all bindings in ACTION-MAP in the -minibuffer, reads a key from the minibuffer, and performs the -corresponding action. The prompt can be canceled with C-g or -RET. PROMPT must be a string to use for the prompt. PROMPT -should include a space at the end. - -ACTION-MAP must be a list of triples of the form - (KEY LABEL ACTION) -where KEY is a key binding, LABEL is a string label to display in -the buffer, and ACTION is a nullary function to call. LABEL may -be null, in which case the action will still be bound, but will -not appear in the pop-up buffer. - -(fn ACTION-MAP PROMPT)") -(register-definition-prefixes "notmuch-jump" '("notmuch-jump-")) - - -;;; Generated autoloads from notmuch-lib.el - -(register-definition-prefixes "notmuch-lib" '("notmuch-")) - - -;;; Generated autoloads from notmuch-maildir-fcc.el - -(register-definition-prefixes "notmuch-maildir-fcc" '("notmuch-" "with-temporary-notmuch-message-buffer")) - - -;;; Generated autoloads from notmuch-message.el - -(register-definition-prefixes "notmuch-message" '("notmuch-message-")) - - -;;; Generated autoloads from notmuch-mua.el - -(register-definition-prefixes "notmuch-mua" '("notmuch-")) - - -;;; Generated autoloads from notmuch-parser.el - -(register-definition-prefixes "notmuch-parser" '("notmuch-sexp-")) - - -;;; Generated autoloads from notmuch-print.el - -(register-definition-prefixes "notmuch-print" '("notmuch-print-")) - - -;;; Generated autoloads from notmuch-query.el - -(register-definition-prefixes "notmuch-query" '("notmuch-query-")) - - -;;; Generated autoloads from notmuch-show.el - -(autoload 'notmuch-show "notmuch-show" "\ -Run \"notmuch show\" with the given thread ID and display results. - -ELIDE-TOGGLE, if non-nil, inverts the default elide behavior. - -The optional PARENT-BUFFER is the notmuch-search buffer from -which this notmuch-show command was executed, (so that the -next thread from that buffer can be show when done with this -one). - -The optional QUERY-CONTEXT is a notmuch search term. Only -messages from the thread matching this search term are shown if -non-nil. - -The optional BUFFER-NAME provides the name of the buffer in -which the message thread is shown. If it is nil (which occurs -when the command is called interactively) the argument to the -function is used. - -Returns the buffer containing the messages, or NIL if no messages -matched. - -(fn THREAD-ID &optional ELIDE-TOGGLE PARENT-BUFFER QUERY-CONTEXT BUFFER-NAME)" t) -(register-definition-prefixes "notmuch-show" '("notmuch-" "with-current-notmuch-show-message")) - - -;;; Generated autoloads from notmuch-tag.el - -(register-definition-prefixes "notmuch-tag" '("notmuch-")) - - -;;; Generated autoloads from notmuch-tree.el - -(autoload 'notmuch-tree "notmuch-tree" "\ -Display threads matching QUERY in tree view. - -The arguments are: - QUERY: the main query. This can be any query but in many cases will be - a single thread. If nil this is read interactively from the minibuffer. - QUERY-CONTEXT: is an additional term for the query. The query used - is QUERY and QUERY-CONTEXT unless that does not match any messages - in which case we fall back to just QUERY. - TARGET: A message ID (with the id: prefix) that will be made - current if it appears in the tree view results. - BUFFER-NAME: the name of the buffer to display the tree view. If - it is nil \"*notmuch-tree\" followed by QUERY is used. - OPEN-TARGET: If TRUE open the target message in the message pane. - UNTHREADED: If TRUE only show matching messages in an unthreaded view. - -(fn &optional QUERY QUERY-CONTEXT TARGET BUFFER-NAME OPEN-TARGET UNTHREADED PARENT-BUFFER OLDEST-FIRST HIDE-EXCLUDED)" t) -(register-definition-prefixes "notmuch-tree" '("notmuch-")) - - -;;; Generated autoloads from notmuch-wash.el - -(register-definition-prefixes "notmuch-wash" '("notmuch-wash-")) - - -;;; Generated autoloads from rstdoc.el - -(register-definition-prefixes "rstdoc" '("rst")) - -;;; End of scraped data - -(provide 'notmuch-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; notmuch-autoloads.el ends here diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-hello.elc b/emacs/elpa/notmuch-20240809.1318/notmuch-hello.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-maildir-fcc.elc b/emacs/elpa/notmuch-20240809.1318/notmuch-maildir-fcc.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-message.elc b/emacs/elpa/notmuch-20240809.1318/notmuch-message.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-mua.el b/emacs/elpa/notmuch-20240809.1318/notmuch-mua.el @@ -1,679 +0,0 @@ -;;; notmuch-mua.el --- emacs style mail-user-agent -*- lexical-binding: t -*- -;; -;; Copyright © David Edmondson -;; -;; This file is part of Notmuch. -;; -;; Notmuch 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. -;; -;; Notmuch 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 Notmuch. If not, see <https://www.gnu.org/licenses/>. -;; -;; Authors: David Edmondson <dme@dme.org> - -;;; Code: - -(eval-when-compile (require 'subr-x)) - -(require 'message) -(require 'gmm-utils) -(require 'mm-view) -(require 'format-spec) - -(require 'notmuch-lib) -(require 'notmuch-address) -(require 'notmuch-draft) -(require 'notmuch-message) - -(declare-function notmuch-show-insert-body "notmuch-show" (msg body depth)) -(declare-function notmuch-fcc-header-setup "notmuch-maildir-fcc" ()) -(declare-function notmuch-maildir-message-do-fcc "notmuch-maildir-fcc" ()) -(declare-function notmuch-draft-postpone "notmuch-draft" ()) -(declare-function notmuch-draft-save "notmuch-draft" ()) - -(defvar notmuch-show-indent-multipart) -(defvar notmuch-show-insert-header-p-function) -(defvar notmuch-show-max-text-part-size) -(defvar notmuch-show-insert-text/plain-hook) - -;;; Options - -(defcustom notmuch-mua-send-hook nil - "Hook run before sending messages." - :type 'hook - :group 'notmuch-send - :group 'notmuch-hooks) - -(defcustom notmuch-mua-compose-in 'current-window - "Where to create the mail buffer used to compose a new message. -Possible values are `current-window' (default), `new-window' and -`new-frame'. If set to `current-window', the mail buffer will be -displayed in the current window, so the old buffer will be -restored when the mail buffer is killed. If set to `new-window' -or `new-frame', the mail buffer will be displayed in a new -window/frame that will be destroyed when the buffer is killed. -You may want to customize `message-kill-buffer-on-exit' -accordingly." - :group 'notmuch-send - :type '(choice (const :tag "Compose in the current window" current-window) - (const :tag "Compose mail in a new window" new-window) - (const :tag "Compose mail in a new frame" new-frame))) - -(defcustom notmuch-mua-user-agent-function nil - "Function used to generate a `User-Agent:' string. -If this is `nil' then no `User-Agent:' will be generated." - :type '(choice (const :tag "No user agent string" nil) - (const :tag "Full" notmuch-mua-user-agent-full) - (const :tag "Notmuch" notmuch-mua-user-agent-notmuch) - (const :tag "Emacs" notmuch-mua-user-agent-emacs) - (function :tag "Custom user agent function" - :value notmuch-mua-user-agent-full)) - :group 'notmuch-send) - -(defcustom notmuch-mua-hidden-headers nil - "Headers that are added to the `message-mode' hidden headers list." - :type '(repeat string) - :group 'notmuch-send) - -(defcustom notmuch-identities nil - "Identities that can be used as the From: address when composing a new message. - -If this variable is left unset, then a list will be constructed from the -name and addresses configured in the notmuch configuration file." - :type '(repeat string) - :group 'notmuch-send) - -(defcustom notmuch-always-prompt-for-sender nil - "Always prompt for the From: address when composing or forwarding a message. - -This is not taken into account when replying to a message, because in that case -the From: header is already filled in by notmuch." - :type 'boolean - :group 'notmuch-send) - -(defgroup notmuch-reply nil - "Replying to messages in notmuch." - :group 'notmuch) - -(defcustom notmuch-mua-cite-function 'message-cite-original - "Function for citing an original message. - -Predefined functions include `message-cite-original' and -`message-cite-original-without-signature'. Note that these -functions use `mail-citation-hook' if that is non-nil." - :type '(radio (function-item message-cite-original) - (function-item message-cite-original-without-signature) - (function-item sc-cite-original) - (function :tag "Other")) - :link '(custom-manual "(message)Insertion Variables") - :group 'notmuch-reply) - -(defcustom notmuch-mua-reply-insert-header-p-function - 'notmuch-show-reply-insert-header-p-never - "Function to decide which parts get a header when replying. - -This function specifies which parts of a mime message with -multiple parts get a header." - :type '(radio (const :tag "No part headers" - notmuch-show-reply-insert-header-p-never) - (const :tag "All except multipart/* and hidden parts" - notmuch-show-reply-insert-header-p-trimmed) - (const :tag "Only for included text parts" - notmuch-show-reply-insert-header-p-minimal) - (const :tag "Exactly as in show view" - notmuch-show-insert-header-p) - (function :tag "Other")) - :group 'notmuch-reply) - -(defcustom notmuch-mua-attachment-regexp - "\\b\\(attache\?ment\\|attached\\|attach\\|pi[èe]ce\s+jointe?\\)\\b" - "Message body text indicating that an attachment is expected. - -This is not used unless `notmuch-mua-attachment-check' is added -to `notmuch-mua-send-hook'." - :type 'regexp - :group 'notmuch-send) - -(defcustom notmuch-mua-subject-regexp - "[[:blank:]]*$" - "Message subject indicating that something may be amiss. -By default, this checks for empty subject lines. - -This is not used unless `notmuch-mua-subject-check' is added to -`notmuch-mua-send-hook'." - :type 'regexp - :group 'notmuch-send) - -;;; Various functions - -(defun notmuch-mua-attachment-check () - "Signal an error an attachement is expected but missing. - -Signal an error if the message text indicates that an attachment -is expected but no MML referencing an attachment is found. - -Typically this is added to `notmuch-mua-send-hook'." - (when (and - ;; When the message mentions attachment... - (save-excursion - (message-goto-body) - ;; Limit search from reaching other possible parts of the message - (let ((search-limit (search-forward "\n<#" nil t))) - (message-goto-body) - (cl-loop while (re-search-forward notmuch-mua-attachment-regexp - search-limit t) - ;; For every instance of the "attachment" string - ;; found, examine the text properties. If the text - ;; has either a `face' or `syntax-table' property - ;; then it is quoted text and should *not* cause the - ;; user to be asked about a missing attachment. - if (let ((props (text-properties-at (match-beginning 0)))) - (not (or (memq 'syntax-table props) - (memq 'face props)))) - return t - finally return nil))) - ;; ...but doesn't have a part with a filename... - (save-excursion - (message-goto-body) - (not (re-search-forward "^<#part [^>]*filename=" nil t))) - ;; ...and that's not okay... - (not (y-or-n-p "Attachment mentioned, but no attachment - is that okay?"))) - ;; ...signal an error. - (error "Missing attachment"))) - -(defun notmuch-mua-subject-check () - "Signal an error if the subject seems amiss. -More precisely, if the subject conforms to -`notmuch-mua-subject-regexp'. - -Typically this is added to `notmuch-mua-send-hook'." - (or (save-excursion - (message-goto-subject) - (message-beginning-of-header t) - (not (looking-at-p notmuch-mua-subject-regexp))) - (y-or-n-p "Subject may be erroneous – is that okay?") - (error "Erroneous subject"))) - -(defun notmuch-mua-get-switch-function () - "Get a switch function according to `notmuch-mua-compose-in'." - (pcase notmuch-mua-compose-in - ('current-window 'switch-to-buffer) - ('new-window 'switch-to-buffer-other-window) - ('new-frame 'switch-to-buffer-other-frame) - (_ (error "Invalid value for `notmuch-mua-compose-in'")))) - -(defun notmuch-mua-maybe-set-window-dedicated () - "Set the selected window as dedicated according to `notmuch-mua-compose-in'." - (when (or (eq notmuch-mua-compose-in 'new-frame) - (eq notmuch-mua-compose-in 'new-window)) - (set-window-dedicated-p (selected-window) t))) - -(defun notmuch-mua-user-agent-full () - "Generate a `User-Agent:' string suitable for notmuch." - (concat (notmuch-mua-user-agent-notmuch) - " " - (notmuch-mua-user-agent-emacs))) - -(defun notmuch-mua-user-agent-notmuch () - "Generate a `User-Agent:' string suitable for notmuch." - (let ((notmuch-version (if (string= notmuch-emacs-version "unknown") - (notmuch-cli-version) - notmuch-emacs-version))) - (concat "Notmuch/" notmuch-version " (https://notmuchmail.org)"))) - -(defun notmuch-mua-user-agent-emacs () - "Generate a `User-Agent:' string suitable for notmuch." - (concat "Emacs/" emacs-version " (" system-configuration ")")) - -(defun notmuch-mua-add-more-hidden-headers () - "Add some headers to the list that are hidden by default." - (mapc (lambda (header) - (unless (member header message-hidden-headers) - (push header message-hidden-headers))) - notmuch-mua-hidden-headers)) - -(defun notmuch-mua-reply-crypto (parts) - "Add mml sign-encrypt flag if any part of original message is encrypted." - (cl-loop for part in parts - for type = (plist-get part :content-type) - if (notmuch-match-content-type type "multipart/encrypted") - do (mml-secure-message-sign-encrypt) - else if (notmuch-match-content-type type "multipart/*") - do (notmuch-mua-reply-crypto (plist-get part :content)))) - -;; There is a bug in Emacs' message.el that results in a newline -;; not being inserted after the References header, so the next header -;; is concatenated to the end of it. This function fixes the problem, -;; while guarding against the possibility that some current or future -;; version of emacs has the bug fixed. -(defun notmuch-mua-insert-references (original-func header references) - (funcall original-func header references) - (unless (bolp) (insert "\n"))) - -;;; Mua reply - -(defun notmuch-mua-reply (query-string &optional sender reply-all duplicate) - (let* ((duparg (and duplicate (list (format "--duplicate=%d" duplicate)))) - (args `("reply" "--format=sexp" "--format-version=5" ,@duparg)) - (process-crypto notmuch-show-process-crypto) - reply - original) - (when process-crypto - (setq args (append args '("--decrypt=true")))) - (if reply-all - (setq args (append args '("--reply-to=all"))) - (setq args (append args '("--reply-to=sender")))) - (setq args (append args (list query-string))) - ;; Get the reply object as SEXP, and parse it into an elisp object. - (setq reply (apply #'notmuch-call-notmuch-sexp args)) - ;; Extract the original message to simplify the following code. - (setq original (plist-get reply :original)) - ;; Extract the headers of both the reply and the original message. - (let* ((original-headers (plist-get original :headers)) - (reply-headers (plist-get reply :reply-headers))) - ;; If sender is non-nil, set the From: header to its value. - (when sender - (plist-put reply-headers :From sender)) - (let - ;; Overlay the composition window on that being used to read - ;; the original message. - ((same-window-regexps '("\\*mail .*"))) - ;; We modify message-header-format-alist to get around - ;; a bug in message.el. See the comment above on - ;; notmuch-mua-insert-references. - (let ((message-header-format-alist - (cl-loop for pair in message-header-format-alist - if (eq (car pair) 'References) - collect (cons 'References - (apply-partially - 'notmuch-mua-insert-references - (cdr pair))) - else - collect pair))) - (notmuch-mua-mail (plist-get reply-headers :To) - (notmuch-sanitize (plist-get reply-headers :Subject)) - (notmuch-headers-plist-to-alist reply-headers) - nil (notmuch-mua-get-switch-function)))) - ;; Create a buffer-local queue for tag changes triggered when - ;; sending the reply. - (when notmuch-message-replied-tags - (setq notmuch-message-queued-tag-changes - (list (cons query-string notmuch-message-replied-tags)))) - ;; Insert the message body - but put it in front of the signature - ;; if one is present, and after any other content - ;; message*setup-hooks may have added to the message body already. - (save-restriction - (message-goto-body) - (narrow-to-region (point) (point-max)) - (goto-char (point-max)) - (if (re-search-backward message-signature-separator nil t) - (when message-signature-insert-empty-line - (forward-line -1)) - (goto-char (point-max)))) - (let ((from (plist-get original-headers :From)) - (date (plist-get original-headers :Date)) - (start (point))) - ;; notmuch-mua-cite-function constructs a citation line based - ;; on the From and Date headers of the original message, which - ;; are assumed to be in the buffer. - (insert "From: " from "\n") - (insert "Date: " date "\n\n") - (insert - (with-temp-buffer - (let - ;; Don't attempt to clean up messages, excerpt - ;; citations, etc. in the original message before - ;; quoting. - ((notmuch-show-insert-text/plain-hook nil) - ;; Don't omit long parts. - (notmuch-show-max-text-part-size 0) - ;; Insert headers for parts as appropriate for replying. - (notmuch-show-insert-header-p-function - notmuch-mua-reply-insert-header-p-function) - ;; Ensure that any encrypted parts are - ;; decrypted during the generation of the reply - ;; text. - (notmuch-show-process-crypto process-crypto) - ;; Don't indent multipart sub-parts. - (notmuch-show-indent-multipart nil) - ;; Stop certain mime types from being inlined - (mm-inline-override-types (notmuch--inline-override-types))) - ;; We don't want sigstatus buttons (an information leak and usually wrong anyway). - (cl-letf (((symbol-function 'notmuch-crypto-insert-sigstatus-button) #'ignore) - ((symbol-function 'notmuch-crypto-insert-encstatus-button) #'ignore)) - (notmuch-show-insert-body original (plist-get original :body) 0) - (buffer-substring-no-properties (point-min) (point-max)))))) - (set-mark (point)) - (goto-char start) - ;; Quote the original message according to the user's configured style. - (funcall notmuch-mua-cite-function))) - ;; Crypto processing based crypto content of the original message - (when process-crypto - (notmuch-mua-reply-crypto (plist-get original :body)))) - ;; Push mark right before signature, if any. - (message-goto-signature) - (unless (eobp) - (end-of-line -1)) - (push-mark) - (message-goto-body) - (set-buffer-modified-p nil)) - -;;; Mode and keymap - -(defvar notmuch-message-mode-map - (let ((map (make-sparse-keymap))) - (define-key map [remap message-send-and-exit] #'notmuch-mua-send-and-exit) - (define-key map [remap message-send] #'notmuch-mua-send) - (define-key map (kbd "C-c C-p") #'notmuch-draft-postpone) - (define-key map (kbd "C-x C-s") #'notmuch-draft-save) - map) - "Keymap for `notmuch-message-mode'.") - -(define-derived-mode notmuch-message-mode message-mode "Message[Notmuch]" - "Notmuch message composition mode. Mostly like `message-mode'." - (notmuch-address-setup)) - -(put 'notmuch-message-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify) - -;;; New messages - -(defun notmuch-mua-pop-to-buffer (name switch-function) - "Pop to buffer NAME, and warn if it already exists and is modified. -Like `message-pop-to-buffer' but enable `notmuch-message-mode' -instead of `message-mode' and SWITCH-FUNCTION is mandatory." - (let ((buffer (get-buffer name))) - (if (and buffer - (buffer-name buffer)) - (let ((window (get-buffer-window buffer 0))) - (if window - ;; Raise the frame already displaying the message buffer. - (progn - (select-frame-set-input-focus (window-frame window)) - (select-window window)) - (funcall switch-function buffer) - (set-buffer buffer)) - (when (buffer-modified-p) - (if (y-or-n-p "Message already being composed; erase? ") - (message nil) - (error "Message being composed")))) - (funcall switch-function name) - (set-buffer name)) - (erase-buffer) - (notmuch-message-mode))) - -(defun notmuch-mua--remove-dont-reply-to-names () - (when-let* ((nr (if (functionp message-dont-reply-to-names) - message-dont-reply-to-names - (gmm-regexp-concat message-dont-reply-to-names))) - (nr-filter - (if (functionp nr) - (lambda (mail) (and (not (funcall nr mail)) mail)) - (lambda (mail) (and (not (string-match-p nr mail)) mail))))) - (dolist (header '("To" "Cc")) - (when-let ((v (message-fetch-field header))) - (let* ((tokens (mapcar #'string-trim (message-tokenize-header v))) - (good-tokens (delq nil (mapcar nr-filter tokens))) - (addr (and good-tokens (mapconcat #'identity good-tokens ", ")))) - (message-replace-header header addr)))))) - -;;;#autoload -(defun notmuch-mua-mail (&optional to subject other-headers _continue - switch-function yank-action send-actions - return-action &rest _ignored) - "Invoke the notmuch mail composition window. - -The position of point when the function returns differs depending -on the values of TO and SUBJECT. If both are non-nil, point is -moved to the message's body. If SUBJECT is nil but TO isn't, -point is moved to the \"Subject:\" header. Otherwise, point is -moved to the \"To:\" header." - (interactive) - (when notmuch-mua-user-agent-function - (let ((user-agent (funcall notmuch-mua-user-agent-function))) - (unless (string-empty-p user-agent) - (push (cons 'User-Agent user-agent) other-headers)))) - (notmuch-mua-pop-to-buffer (message-buffer-name "mail" to) - (or switch-function - (notmuch-mua-get-switch-function))) - (let ((headers - (append - ;; The following is copied from `message-mail' - `((To . ,(or to "")) (Subject . ,(or subject ""))) - ;; C-h f compose-mail says that headers should be specified as - ;; (string . value); however all the rest of message expects - ;; headers to be symbols, not strings (eg message-header-format-alist). - ;; https://lists.gnu.org/archive/html/emacs-devel/2011-01/msg00337.html - ;; We need to convert any string input, eg from rmail-start-mail. - (dolist (h other-headers other-headers) - (when (stringp (car h)) - (setcar h (intern (capitalize (car h)))))))) - ;; Cause `message-setup-1' to do things relevant for mail, - ;; such as observe `message-default-mail-headers'. - (message-this-is-mail t)) - (unless (assq 'From headers) - (push (cons 'From (message-make-from - (notmuch-user-name) - (notmuch-user-primary-email))) - headers)) - (message-setup-1 headers yank-action send-actions return-action)) - (notmuch-fcc-header-setup) - (notmuch-mua--remove-dont-reply-to-names) - (message-sort-headers) - (message-hide-headers) - (set-buffer-modified-p nil) - (notmuch-mua-maybe-set-window-dedicated) - (cond - ((and to subject) (message-goto-body)) - (to (message-goto-subject)) - (t (message-goto-to)))) - -(defvar notmuch-mua-sender-history nil) - -(defun notmuch-mua-prompt-for-sender () - "Prompt for a sender from the user's configured identities." - (if notmuch-identities - (completing-read "Send mail from: " notmuch-identities - nil nil nil 'notmuch-mua-sender-history - (car notmuch-identities)) - (let* ((name (notmuch-user-name)) - (addrs (cons (notmuch-user-primary-email) - (notmuch-user-other-email))) - (address - (completing-read (concat "Sender address for " name ": ") addrs - nil nil nil 'notmuch-mua-sender-history - (car addrs)))) - (message-make-from name address)))) - -(put 'notmuch-mua-new-mail 'notmuch-prefix-doc "... and prompt for sender") -(defun notmuch-mua-new-mail (&optional prompt-for-sender) - "Compose new mail. - -If PROMPT-FOR-SENDER is non-nil, the user will be prompted for -the From: address first." - (interactive "P") - (let ((other-headers - (and (or prompt-for-sender notmuch-always-prompt-for-sender) - (list (cons 'From (notmuch-mua-prompt-for-sender)))))) - (notmuch-mua-mail nil nil other-headers nil (notmuch-mua-get-switch-function)))) - -(defun notmuch-mua-new-forward-messages (messages &optional prompt-for-sender) - "Compose a new message forwarding MESSAGES. - -If PROMPT-FOR-SENDER is non-nil, the user will be prompteed for -the From: address." - (let* ((other-headers - (and (or prompt-for-sender notmuch-always-prompt-for-sender) - (list (cons 'From (notmuch-mua-prompt-for-sender))))) - ;; Comes from the first message and is applied later. - forward-subject - ;; List of accumulated message-references of forwarded messages. - forward-references - ;; List of corresponding message-query. - forward-queries) - ;; Generate the template for the outgoing message. - (notmuch-mua-mail nil "" other-headers nil (notmuch-mua-get-switch-function)) - (save-excursion - ;; Insert all of the forwarded messages. - (mapc (lambda (id) - (let ((temp-buffer (get-buffer-create - (concat "*notmuch-fwd-raw-" id "*")))) - ;; Get the raw version of this message in the buffer. - (with-current-buffer temp-buffer - (erase-buffer) - (let ((coding-system-for-read 'no-conversion)) - (notmuch--call-process notmuch-command nil t nil - "show" "--format=raw" id)) - ;; Because we process the messages in reverse order, - ;; always generate a forwarded subject, then use the - ;; last (i.e. first) one. - (setq forward-subject (message-make-forward-subject)) - (push (message-fetch-field "Message-ID") forward-references) - (push id forward-queries)) - ;; Make a copy ready to be forwarded in the - ;; composition buffer. - (message-forward-make-body temp-buffer) - ;; Kill the temporary buffer. - (kill-buffer temp-buffer))) - ;; `message-forward-make-body' always puts the message at - ;; the top, so do them in reverse order. - (reverse messages)) - ;; Add in the appropriate subject. - (save-restriction - (message-narrow-to-headers) - (message-remove-header "Subject") - (message-add-header (concat "Subject: " forward-subject)) - (message-remove-header "References") - (message-add-header (concat "References: " - (mapconcat 'identity forward-references " ")))) - ;; Create a buffer-local queue for tag changes triggered when - ;; sending the message. - (when notmuch-message-forwarded-tags - (setq notmuch-message-queued-tag-changes - (cl-loop for id in forward-queries - collect - (cons id notmuch-message-forwarded-tags)))) - ;; `message-forward-make-body' shows the User-agent header. Hide - ;; it again. - (message-hide-headers) - (set-buffer-modified-p nil)))) - -(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender reply-all duplicate) - "Compose a reply to the message identified by QUERY-STRING. - -If PROMPT-FOR-SENDER is non-nil, the user will be prompted for -the From: address first. If REPLY-ALL is non-nil, the message -will be addressed to all recipients of the source message. If -DUPLICATE is non-nil, based the reply on that duplicate file" - ;; `select-active-regions' is t by default. The reply insertion code - ;; sets the region to the quoted message to make it easy to delete - ;; (kill-region or C-w). These two things combine to put the quoted - ;; message in the primary selection. - ;; - ;; This is not what the user wanted and is a privacy risk (accidental - ;; pasting of the quoted message). We can avoid some of the problems - ;; by let-binding select-active-regions to nil. This fixes if the - ;; primary selection was previously in a non-emacs window but not if - ;; it was in an emacs window. To avoid the problem in the latter case - ;; we deactivate mark. - (let ((sender (and prompt-for-sender - (notmuch-mua-prompt-for-sender))) - (select-active-regions nil)) - (notmuch-mua-reply query-string sender reply-all duplicate) - (deactivate-mark))) - -;;; Checks - -(defun notmuch-mua-check-no-misplaced-secure-tag () - "Query user if there is a misplaced secure mml tag. - -Emacs message-send will (probably) ignore a secure mml tag unless -it is at the start of the body. Returns t if there is no such -tag, or the user confirms they mean it." - (save-excursion - (let ((body-start (progn (message-goto-body) (point)))) - (goto-char (point-max)) - (or - ;; We are always fine if there is no secure tag. - (not (search-backward "<#secure" nil t)) - ;; There is a secure tag, so it must be at the start of the - ;; body, with no secure tag earlier (i.e., in the headers). - (and (= (point) body-start) - (not (search-backward "<#secure" nil t))) - ;; The user confirms they means it. - (yes-or-no-p "\ -There is a <#secure> tag not at the start of the body. It is -likely that the message will be sent unsigned and unencrypted. -Really send? "))))) - -(defun notmuch-mua-check-secure-tag-has-newline () - "Query if the secure mml tag has a newline following it. - -Emacs message-send will (probably) ignore a correctly placed -secure mml tag unless it is followed by a newline. Returns t if -any secure tag is followed by a newline, or the user confirms -they mean it." - (save-excursion - (message-goto-body) - (or - ;; There is no (correctly placed) secure tag. - (not (looking-at "<#secure")) - ;; The secure tag is followed by a newline. - (looking-at "<#secure[^\n>]*>\n") - ;; The user confirms they means it. - (yes-or-no-p "\ -The <#secure> tag at the start of the body is not followed by a -newline. It is likely that the message will be sent unsigned and -unencrypted. Really send? ")))) - -;;; Finishing commands - -(defun notmuch-mua-send-common (arg &optional exit) - (interactive "P") - (run-hooks 'notmuch-mua-send-hook) - (when (and (notmuch-mua-check-no-misplaced-secure-tag) - (notmuch-mua-check-secure-tag-has-newline)) - (cl-letf (((symbol-function 'message-do-fcc) - #'notmuch-maildir-message-do-fcc)) - (if exit - (message-send-and-exit arg) - (message-send arg))))) - -;;;#autoload -(defun notmuch-mua-send-and-exit (&optional arg) - (interactive "P") - (notmuch-mua-send-common arg t)) - -;;;#autoload -(defun notmuch-mua-send (&optional arg) - (interactive "P") - (notmuch-mua-send-common arg)) - -;;;#autoload -(defun notmuch-mua-kill-buffer () - (interactive) - (message-kill-buffer)) - -;;; _ - -;;;#autoload -(define-mail-user-agent 'notmuch-user-agent - 'notmuch-mua-mail - 'notmuch-mua-send-and-exit - 'notmuch-mua-kill-buffer - 'notmuch-mua-send-hook) - -;; Add some more headers to the list that `message-mode' hides when -;; composing a message. -(notmuch-mua-add-more-hidden-headers) - -(provide 'notmuch-mua) - -;;; notmuch-mua.el ends here diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-pkg.el b/emacs/elpa/notmuch-20240809.1318/notmuch-pkg.el @@ -1,4 +0,0 @@ -(define-package "notmuch" "20240809.1318" "run notmuch within emacs" 'nil :commit "4e85abda157eac8888809b2dde885f60f312a5fb" :url "https://notmuchmail.org") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-tree.elc b/emacs/elpa/notmuch-20240809.1318/notmuch-tree.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/coolj.el b/emacs/elpa/notmuch-20240816.2039/coolj.el diff --git a/emacs/elpa/notmuch-20240809.1318/coolj.elc b/emacs/elpa/notmuch-20240816.2039/coolj.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/make-deps.el b/emacs/elpa/notmuch-20240816.2039/make-deps.el diff --git a/emacs/elpa/notmuch-20240809.1318/make-deps.elc b/emacs/elpa/notmuch-20240816.2039/make-deps.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-address.el b/emacs/elpa/notmuch-20240816.2039/notmuch-address.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-address.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-address.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-autoloads.el b/emacs/elpa/notmuch-20240816.2039/notmuch-autoloads.el @@ -0,0 +1,254 @@ +;;; notmuch-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from coolj.el + +(register-definition-prefixes "coolj" '("coolj-")) + + +;;; Generated autoloads from make-deps.el + +(register-definition-prefixes "make-deps" '("batch-make-deps" "make-deps")) + + +;;; Generated autoloads from notmuch.el + +(autoload 'notmuch-search "notmuch" "\ +Display threads matching QUERY in a notmuch-search buffer. + +If QUERY is nil, it is read interactively from the minibuffer. +Other optional parameters are used as follows: + + OLDEST-FIRST: A Boolean controlling the sort order of returned threads + HIDE-EXCLUDED: A boolean controlling whether to omit threads with excluded + tags. + TARGET-THREAD: A thread ID (without the thread: prefix) that will be made + current if it appears in the search results. + TARGET-LINE: The line number to move to if the target thread does not + appear in the search results. + NO-DISPLAY: Do not try to foreground the search results buffer. If it is + already foregrounded i.e. displayed in a window, this has no + effect, meaning the buffer will remain visible. + +When called interactively, this will prompt for a query and use +the configured default sort order. + +(fn &optional QUERY OLDEST-FIRST HIDE-EXCLUDED TARGET-THREAD TARGET-LINE NO-DISPLAY)" t) +(autoload 'notmuch "notmuch" "\ +Run notmuch and display saved searches, known tags, etc." t) +(autoload 'notmuch-cycle-notmuch-buffers "notmuch" "\ +Cycle through any existing notmuch buffers (search, show or hello). + +If the current buffer is the only notmuch buffer, bury it. +If no notmuch buffers exist, run `notmuch'." t) +(register-definition-prefixes "notmuch" '("notmuch-")) + + +;;; Generated autoloads from notmuch-address.el + +(register-definition-prefixes "notmuch-address" '("notmuch-address-")) + + +;;; Generated autoloads from notmuch-company.el + +(autoload 'notmuch-company-setup "notmuch-company") +(autoload 'notmuch-company "notmuch-company" "\ +`company-mode' completion back-end for `notmuch'. + +(fn COMMAND &optional ARG &rest IGNORE)" t) +(register-definition-prefixes "notmuch-company" '("notmuch-company-last-prefix")) + + +;;; Generated autoloads from notmuch-compat.el + +(register-definition-prefixes "notmuch-compat" '("notmuch-")) + + +;;; Generated autoloads from notmuch-crypto.el + +(register-definition-prefixes "notmuch-crypto" '("notmuch-crypto-")) + + +;;; Generated autoloads from notmuch-draft.el + +(register-definition-prefixes "notmuch-draft" '("notmuch-draft-")) + + +;;; Generated autoloads from notmuch-hello.el + +(autoload 'notmuch-hello "notmuch-hello" "\ +Run notmuch and display saved searches, known tags, etc. + +(fn &optional NO-DISPLAY)" t) +(register-definition-prefixes "notmuch-hello" '("notmuch-")) + + +;;; Generated autoloads from notmuch-jump.el + +(autoload 'notmuch-jump-search "notmuch-jump" "\ +Jump to a saved search by shortcut key. + +This prompts for and performs a saved search using the shortcut +keys configured in the :key property of `notmuch-saved-searches'. +Typically these shortcuts are a single key long, so this is a +fast way to jump to a saved search from anywhere in Notmuch." t) +(autoload 'notmuch-jump "notmuch-jump" "\ +Interactively prompt for one of the keys in ACTION-MAP. + +Displays a summary of all bindings in ACTION-MAP in the +minibuffer, reads a key from the minibuffer, and performs the +corresponding action. The prompt can be canceled with C-g or +RET. PROMPT must be a string to use for the prompt. PROMPT +should include a space at the end. + +ACTION-MAP must be a list of triples of the form + (KEY LABEL ACTION) +where KEY is a key binding, LABEL is a string label to display in +the buffer, and ACTION is a nullary function to call. LABEL may +be null, in which case the action will still be bound, but will +not appear in the pop-up buffer. + +(fn ACTION-MAP PROMPT)") +(register-definition-prefixes "notmuch-jump" '("notmuch-jump-")) + + +;;; Generated autoloads from notmuch-lib.el + +(register-definition-prefixes "notmuch-lib" '("notmuch-")) + + +;;; Generated autoloads from notmuch-maildir-fcc.el + +(register-definition-prefixes "notmuch-maildir-fcc" '("notmuch-" "with-temporary-notmuch-message-buffer")) + + +;;; Generated autoloads from notmuch-message.el + +(register-definition-prefixes "notmuch-message" '("notmuch-message-")) + + +;;; Generated autoloads from notmuch-mua.el + +(autoload 'notmuch-mua-mail "notmuch-mua" "\ +Invoke the notmuch mail composition window. + +The position of point when the function returns differs depending +on the values of TO and SUBJECT. If both are non-nil, point is +moved to the message's body. If SUBJECT is nil but TO isn't, +point is moved to the \"Subject:\" header. Otherwise, point is +moved to the \"To:\" header. + +(fn &optional TO SUBJECT OTHER-HEADERS CONTINUE SWITCH-FUNCTION YANK-ACTION SEND-ACTIONS RETURN-ACTION &rest IGNORED)" t) +(autoload 'notmuch-mua-send-and-exit "notmuch-mua" "\ + + +(fn &optional ARG)" t) +(autoload 'notmuch-mua-send "notmuch-mua" "\ + + +(fn &optional ARG)" t) +(autoload 'notmuch-mua-kill-buffer "notmuch-mua" nil t) +(define-mail-user-agent 'notmuch-user-agent 'notmuch-mua-mail 'notmuch-mua-send-and-exit 'notmuch-mua-kill-buffer 'notmuch-mua-send-hook) +(register-definition-prefixes "notmuch-mua" '("notmuch-")) + + +;;; Generated autoloads from notmuch-parser.el + +(register-definition-prefixes "notmuch-parser" '("notmuch-sexp-")) + + +;;; Generated autoloads from notmuch-print.el + +(register-definition-prefixes "notmuch-print" '("notmuch-print-")) + + +;;; Generated autoloads from notmuch-query.el + +(register-definition-prefixes "notmuch-query" '("notmuch-query-")) + + +;;; Generated autoloads from notmuch-show.el + +(autoload 'notmuch-show "notmuch-show" "\ +Run \"notmuch show\" with the given thread ID and display results. + +ELIDE-TOGGLE, if non-nil, inverts the default elide behavior. + +The optional PARENT-BUFFER is the notmuch-search buffer from +which this notmuch-show command was executed, (so that the +next thread from that buffer can be show when done with this +one). + +The optional QUERY-CONTEXT is a notmuch search term. Only +messages from the thread matching this search term are shown if +non-nil. + +The optional BUFFER-NAME provides the name of the buffer in +which the message thread is shown. If it is nil (which occurs +when the command is called interactively) the argument to the +function is used. + +Returns the buffer containing the messages, or NIL if no messages +matched. + +(fn THREAD-ID &optional ELIDE-TOGGLE PARENT-BUFFER QUERY-CONTEXT BUFFER-NAME)" t) +(register-definition-prefixes "notmuch-show" '("notmuch-" "with-current-notmuch-show-message")) + + +;;; Generated autoloads from notmuch-tag.el + +(register-definition-prefixes "notmuch-tag" '("notmuch-")) + + +;;; Generated autoloads from notmuch-tree.el + +(autoload 'notmuch-tree "notmuch-tree" "\ +Display threads matching QUERY in tree view. + +The arguments are: + QUERY: the main query. This can be any query but in many cases will be + a single thread. If nil this is read interactively from the minibuffer. + QUERY-CONTEXT: is an additional term for the query. The query used + is QUERY and QUERY-CONTEXT unless that does not match any messages + in which case we fall back to just QUERY. + TARGET: A message ID (with the id: prefix) that will be made + current if it appears in the tree view results. + BUFFER-NAME: the name of the buffer to display the tree view. If + it is nil \"*notmuch-tree\" followed by QUERY is used. + OPEN-TARGET: If TRUE open the target message in the message pane. + UNTHREADED: If TRUE only show matching messages in an unthreaded view. + +(fn &optional QUERY QUERY-CONTEXT TARGET BUFFER-NAME OPEN-TARGET UNTHREADED PARENT-BUFFER OLDEST-FIRST HIDE-EXCLUDED)" t) +(register-definition-prefixes "notmuch-tree" '("notmuch-")) + + +;;; Generated autoloads from notmuch-wash.el + +(register-definition-prefixes "notmuch-wash" '("notmuch-wash-")) + + +;;; Generated autoloads from rstdoc.el + +(register-definition-prefixes "rstdoc" '("rst")) + +;;; End of scraped data + +(provide 'notmuch-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; notmuch-autoloads.el ends here diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-company.el b/emacs/elpa/notmuch-20240816.2039/notmuch-company.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-company.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-company.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-compat.el b/emacs/elpa/notmuch-20240816.2039/notmuch-compat.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-compat.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-compat.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-crypto.el b/emacs/elpa/notmuch-20240816.2039/notmuch-crypto.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-crypto.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-crypto.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-draft.el b/emacs/elpa/notmuch-20240816.2039/notmuch-draft.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-draft.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-draft.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-hello.el b/emacs/elpa/notmuch-20240816.2039/notmuch-hello.el diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-hello.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-hello.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-jump.el b/emacs/elpa/notmuch-20240816.2039/notmuch-jump.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-jump.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-jump.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-lib.el b/emacs/elpa/notmuch-20240816.2039/notmuch-lib.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-lib.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-lib.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-logo.svg b/emacs/elpa/notmuch-20240816.2039/notmuch-logo.svg diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-maildir-fcc.el b/emacs/elpa/notmuch-20240816.2039/notmuch-maildir-fcc.el diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-maildir-fcc.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-maildir-fcc.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-message.el b/emacs/elpa/notmuch-20240816.2039/notmuch-message.el diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-message.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-message.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-mua.el b/emacs/elpa/notmuch-20240816.2039/notmuch-mua.el @@ -0,0 +1,679 @@ +;;; notmuch-mua.el --- emacs style mail-user-agent -*- lexical-binding: t -*- +;; +;; Copyright © David Edmondson +;; +;; This file is part of Notmuch. +;; +;; Notmuch 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. +;; +;; Notmuch 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 Notmuch. If not, see <https://www.gnu.org/licenses/>. +;; +;; Authors: David Edmondson <dme@dme.org> + +;;; Code: + +(eval-when-compile (require 'subr-x)) + +(require 'message) +(require 'gmm-utils) +(require 'mm-view) +(require 'format-spec) + +(require 'notmuch-lib) +(require 'notmuch-address) +(require 'notmuch-draft) +(require 'notmuch-message) + +(declare-function notmuch-show-insert-body "notmuch-show" (msg body depth)) +(declare-function notmuch-fcc-header-setup "notmuch-maildir-fcc" ()) +(declare-function notmuch-maildir-message-do-fcc "notmuch-maildir-fcc" ()) +(declare-function notmuch-draft-postpone "notmuch-draft" ()) +(declare-function notmuch-draft-save "notmuch-draft" ()) + +(defvar notmuch-show-indent-multipart) +(defvar notmuch-show-insert-header-p-function) +(defvar notmuch-show-max-text-part-size) +(defvar notmuch-show-insert-text/plain-hook) + +;;; Options + +(defcustom notmuch-mua-send-hook nil + "Hook run before sending messages." + :type 'hook + :group 'notmuch-send + :group 'notmuch-hooks) + +(defcustom notmuch-mua-compose-in 'current-window + "Where to create the mail buffer used to compose a new message. +Possible values are `current-window' (default), `new-window' and +`new-frame'. If set to `current-window', the mail buffer will be +displayed in the current window, so the old buffer will be +restored when the mail buffer is killed. If set to `new-window' +or `new-frame', the mail buffer will be displayed in a new +window/frame that will be destroyed when the buffer is killed. +You may want to customize `message-kill-buffer-on-exit' +accordingly." + :group 'notmuch-send + :type '(choice (const :tag "Compose in the current window" current-window) + (const :tag "Compose mail in a new window" new-window) + (const :tag "Compose mail in a new frame" new-frame))) + +(defcustom notmuch-mua-user-agent-function nil + "Function used to generate a `User-Agent:' string. +If this is `nil' then no `User-Agent:' will be generated." + :type '(choice (const :tag "No user agent string" nil) + (const :tag "Full" notmuch-mua-user-agent-full) + (const :tag "Notmuch" notmuch-mua-user-agent-notmuch) + (const :tag "Emacs" notmuch-mua-user-agent-emacs) + (function :tag "Custom user agent function" + :value notmuch-mua-user-agent-full)) + :group 'notmuch-send) + +(defcustom notmuch-mua-hidden-headers nil + "Headers that are added to the `message-mode' hidden headers list." + :type '(repeat string) + :group 'notmuch-send) + +(defcustom notmuch-identities nil + "Identities that can be used as the From: address when composing a new message. + +If this variable is left unset, then a list will be constructed from the +name and addresses configured in the notmuch configuration file." + :type '(repeat string) + :group 'notmuch-send) + +(defcustom notmuch-always-prompt-for-sender nil + "Always prompt for the From: address when composing or forwarding a message. + +This is not taken into account when replying to a message, because in that case +the From: header is already filled in by notmuch." + :type 'boolean + :group 'notmuch-send) + +(defgroup notmuch-reply nil + "Replying to messages in notmuch." + :group 'notmuch) + +(defcustom notmuch-mua-cite-function 'message-cite-original + "Function for citing an original message. + +Predefined functions include `message-cite-original' and +`message-cite-original-without-signature'. Note that these +functions use `mail-citation-hook' if that is non-nil." + :type '(radio (function-item message-cite-original) + (function-item message-cite-original-without-signature) + (function-item sc-cite-original) + (function :tag "Other")) + :link '(custom-manual "(message)Insertion Variables") + :group 'notmuch-reply) + +(defcustom notmuch-mua-reply-insert-header-p-function + 'notmuch-show-reply-insert-header-p-never + "Function to decide which parts get a header when replying. + +This function specifies which parts of a mime message with +multiple parts get a header." + :type '(radio (const :tag "No part headers" + notmuch-show-reply-insert-header-p-never) + (const :tag "All except multipart/* and hidden parts" + notmuch-show-reply-insert-header-p-trimmed) + (const :tag "Only for included text parts" + notmuch-show-reply-insert-header-p-minimal) + (const :tag "Exactly as in show view" + notmuch-show-insert-header-p) + (function :tag "Other")) + :group 'notmuch-reply) + +(defcustom notmuch-mua-attachment-regexp + "\\b\\(attache\?ment\\|attached\\|attach\\|pi[èe]ce\s+jointe?\\)\\b" + "Message body text indicating that an attachment is expected. + +This is not used unless `notmuch-mua-attachment-check' is added +to `notmuch-mua-send-hook'." + :type 'regexp + :group 'notmuch-send) + +(defcustom notmuch-mua-subject-regexp + "[[:blank:]]*$" + "Message subject indicating that something may be amiss. +By default, this checks for empty subject lines. + +This is not used unless `notmuch-mua-subject-check' is added to +`notmuch-mua-send-hook'." + :type 'regexp + :group 'notmuch-send) + +;;; Various functions + +(defun notmuch-mua-attachment-check () + "Signal an error an attachement is expected but missing. + +Signal an error if the message text indicates that an attachment +is expected but no MML referencing an attachment is found. + +Typically this is added to `notmuch-mua-send-hook'." + (when (and + ;; When the message mentions attachment... + (save-excursion + (message-goto-body) + ;; Limit search from reaching other possible parts of the message + (let ((search-limit (search-forward "\n<#" nil t))) + (message-goto-body) + (cl-loop while (re-search-forward notmuch-mua-attachment-regexp + search-limit t) + ;; For every instance of the "attachment" string + ;; found, examine the text properties. If the text + ;; has either a `face' or `syntax-table' property + ;; then it is quoted text and should *not* cause the + ;; user to be asked about a missing attachment. + if (let ((props (text-properties-at (match-beginning 0)))) + (not (or (memq 'syntax-table props) + (memq 'face props)))) + return t + finally return nil))) + ;; ...but doesn't have a part with a filename... + (save-excursion + (message-goto-body) + (not (re-search-forward "^<#part [^>]*filename=" nil t))) + ;; ...and that's not okay... + (not (y-or-n-p "Attachment mentioned, but no attachment - is that okay?"))) + ;; ...signal an error. + (error "Missing attachment"))) + +(defun notmuch-mua-subject-check () + "Signal an error if the subject seems amiss. +More precisely, if the subject conforms to +`notmuch-mua-subject-regexp'. + +Typically this is added to `notmuch-mua-send-hook'." + (or (save-excursion + (message-goto-subject) + (message-beginning-of-header t) + (not (looking-at-p notmuch-mua-subject-regexp))) + (y-or-n-p "Subject may be erroneous – is that okay?") + (error "Erroneous subject"))) + +(defun notmuch-mua-get-switch-function () + "Get a switch function according to `notmuch-mua-compose-in'." + (pcase notmuch-mua-compose-in + ('current-window 'switch-to-buffer) + ('new-window 'switch-to-buffer-other-window) + ('new-frame 'switch-to-buffer-other-frame) + (_ (error "Invalid value for `notmuch-mua-compose-in'")))) + +(defun notmuch-mua-maybe-set-window-dedicated () + "Set the selected window as dedicated according to `notmuch-mua-compose-in'." + (when (or (eq notmuch-mua-compose-in 'new-frame) + (eq notmuch-mua-compose-in 'new-window)) + (set-window-dedicated-p (selected-window) t))) + +(defun notmuch-mua-user-agent-full () + "Generate a `User-Agent:' string suitable for notmuch." + (concat (notmuch-mua-user-agent-notmuch) + " " + (notmuch-mua-user-agent-emacs))) + +(defun notmuch-mua-user-agent-notmuch () + "Generate a `User-Agent:' string suitable for notmuch." + (let ((notmuch-version (if (string= notmuch-emacs-version "unknown") + (notmuch-cli-version) + notmuch-emacs-version))) + (concat "Notmuch/" notmuch-version " (https://notmuchmail.org)"))) + +(defun notmuch-mua-user-agent-emacs () + "Generate a `User-Agent:' string suitable for notmuch." + (concat "Emacs/" emacs-version " (" system-configuration ")")) + +(defun notmuch-mua-add-more-hidden-headers () + "Add some headers to the list that are hidden by default." + (mapc (lambda (header) + (unless (member header message-hidden-headers) + (push header message-hidden-headers))) + notmuch-mua-hidden-headers)) + +(defun notmuch-mua-reply-crypto (parts) + "Add mml sign-encrypt flag if any part of original message is encrypted." + (cl-loop for part in parts + for type = (plist-get part :content-type) + if (notmuch-match-content-type type "multipart/encrypted") + do (mml-secure-message-sign-encrypt) + else if (notmuch-match-content-type type "multipart/*") + do (notmuch-mua-reply-crypto (plist-get part :content)))) + +;; There is a bug in Emacs' message.el that results in a newline +;; not being inserted after the References header, so the next header +;; is concatenated to the end of it. This function fixes the problem, +;; while guarding against the possibility that some current or future +;; version of emacs has the bug fixed. +(defun notmuch-mua-insert-references (original-func header references) + (funcall original-func header references) + (unless (bolp) (insert "\n"))) + +;;; Mua reply + +(defun notmuch-mua-reply (query-string &optional sender reply-all duplicate) + (let* ((duparg (and duplicate (list (format "--duplicate=%d" duplicate)))) + (args `("reply" "--format=sexp" "--format-version=5" ,@duparg)) + (process-crypto notmuch-show-process-crypto) + reply + original) + (when process-crypto + (setq args (append args '("--decrypt=true")))) + (if reply-all + (setq args (append args '("--reply-to=all"))) + (setq args (append args '("--reply-to=sender")))) + (setq args (append args (list query-string))) + ;; Get the reply object as SEXP, and parse it into an elisp object. + (setq reply (apply #'notmuch-call-notmuch-sexp args)) + ;; Extract the original message to simplify the following code. + (setq original (plist-get reply :original)) + ;; Extract the headers of both the reply and the original message. + (let* ((original-headers (plist-get original :headers)) + (reply-headers (plist-get reply :reply-headers))) + ;; If sender is non-nil, set the From: header to its value. + (when sender + (plist-put reply-headers :From sender)) + (let + ;; Overlay the composition window on that being used to read + ;; the original message. + ((same-window-regexps '("\\*mail .*"))) + ;; We modify message-header-format-alist to get around + ;; a bug in message.el. See the comment above on + ;; notmuch-mua-insert-references. + (let ((message-header-format-alist + (cl-loop for pair in message-header-format-alist + if (eq (car pair) 'References) + collect (cons 'References + (apply-partially + 'notmuch-mua-insert-references + (cdr pair))) + else + collect pair))) + (notmuch-mua-mail (plist-get reply-headers :To) + (notmuch-sanitize (plist-get reply-headers :Subject)) + (notmuch-headers-plist-to-alist reply-headers) + nil (notmuch-mua-get-switch-function)))) + ;; Create a buffer-local queue for tag changes triggered when + ;; sending the reply. + (when notmuch-message-replied-tags + (setq notmuch-message-queued-tag-changes + (list (cons query-string notmuch-message-replied-tags)))) + ;; Insert the message body - but put it in front of the signature + ;; if one is present, and after any other content + ;; message*setup-hooks may have added to the message body already. + (save-restriction + (message-goto-body) + (narrow-to-region (point) (point-max)) + (goto-char (point-max)) + (if (re-search-backward message-signature-separator nil t) + (when message-signature-insert-empty-line + (forward-line -1)) + (goto-char (point-max)))) + (let ((from (plist-get original-headers :From)) + (date (plist-get original-headers :Date)) + (start (point))) + ;; notmuch-mua-cite-function constructs a citation line based + ;; on the From and Date headers of the original message, which + ;; are assumed to be in the buffer. + (insert "From: " from "\n") + (insert "Date: " date "\n\n") + (insert + (with-temp-buffer + (let + ;; Don't attempt to clean up messages, excerpt + ;; citations, etc. in the original message before + ;; quoting. + ((notmuch-show-insert-text/plain-hook nil) + ;; Don't omit long parts. + (notmuch-show-max-text-part-size 0) + ;; Insert headers for parts as appropriate for replying. + (notmuch-show-insert-header-p-function + notmuch-mua-reply-insert-header-p-function) + ;; Ensure that any encrypted parts are + ;; decrypted during the generation of the reply + ;; text. + (notmuch-show-process-crypto process-crypto) + ;; Don't indent multipart sub-parts. + (notmuch-show-indent-multipart nil) + ;; Stop certain mime types from being inlined + (mm-inline-override-types (notmuch--inline-override-types))) + ;; We don't want sigstatus buttons (an information leak and usually wrong anyway). + (cl-letf (((symbol-function 'notmuch-crypto-insert-sigstatus-button) #'ignore) + ((symbol-function 'notmuch-crypto-insert-encstatus-button) #'ignore)) + (notmuch-show-insert-body original (plist-get original :body) 0) + (buffer-substring-no-properties (point-min) (point-max)))))) + (set-mark (point)) + (goto-char start) + ;; Quote the original message according to the user's configured style. + (funcall notmuch-mua-cite-function))) + ;; Crypto processing based crypto content of the original message + (when process-crypto + (notmuch-mua-reply-crypto (plist-get original :body)))) + ;; Push mark right before signature, if any. + (message-goto-signature) + (unless (eobp) + (end-of-line -1)) + (push-mark) + (message-goto-body) + (set-buffer-modified-p nil)) + +;;; Mode and keymap + +(defvar notmuch-message-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [remap message-send-and-exit] #'notmuch-mua-send-and-exit) + (define-key map [remap message-send] #'notmuch-mua-send) + (define-key map (kbd "C-c C-p") #'notmuch-draft-postpone) + (define-key map (kbd "C-x C-s") #'notmuch-draft-save) + map) + "Keymap for `notmuch-message-mode'.") + +(define-derived-mode notmuch-message-mode message-mode "Message[Notmuch]" + "Notmuch message composition mode. Mostly like `message-mode'." + (notmuch-address-setup)) + +(put 'notmuch-message-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify) + +;;; New messages + +(defun notmuch-mua-pop-to-buffer (name switch-function) + "Pop to buffer NAME, and warn if it already exists and is modified. +Like `message-pop-to-buffer' but enable `notmuch-message-mode' +instead of `message-mode' and SWITCH-FUNCTION is mandatory." + (let ((buffer (get-buffer name))) + (if (and buffer + (buffer-name buffer)) + (let ((window (get-buffer-window buffer 0))) + (if window + ;; Raise the frame already displaying the message buffer. + (progn + (select-frame-set-input-focus (window-frame window)) + (select-window window)) + (funcall switch-function buffer) + (set-buffer buffer)) + (when (buffer-modified-p) + (if (y-or-n-p "Message already being composed; erase? ") + (message nil) + (error "Message being composed")))) + (funcall switch-function name) + (set-buffer name)) + (erase-buffer) + (notmuch-message-mode))) + +(defun notmuch-mua--remove-dont-reply-to-names () + (when-let* ((nr (if (functionp message-dont-reply-to-names) + message-dont-reply-to-names + (gmm-regexp-concat message-dont-reply-to-names))) + (nr-filter + (if (functionp nr) + (lambda (mail) (and (not (funcall nr mail)) mail)) + (lambda (mail) (and (not (string-match-p nr mail)) mail))))) + (dolist (header '("To" "Cc")) + (when-let ((v (message-fetch-field header))) + (let* ((tokens (mapcar #'string-trim (message-tokenize-header v))) + (good-tokens (delq nil (mapcar nr-filter tokens))) + (addr (and good-tokens (mapconcat #'identity good-tokens ", ")))) + (message-replace-header header addr)))))) + +;;;###autoload +(defun notmuch-mua-mail (&optional to subject other-headers _continue + switch-function yank-action send-actions + return-action &rest _ignored) + "Invoke the notmuch mail composition window. + +The position of point when the function returns differs depending +on the values of TO and SUBJECT. If both are non-nil, point is +moved to the message's body. If SUBJECT is nil but TO isn't, +point is moved to the \"Subject:\" header. Otherwise, point is +moved to the \"To:\" header." + (interactive) + (when notmuch-mua-user-agent-function + (let ((user-agent (funcall notmuch-mua-user-agent-function))) + (unless (string-empty-p user-agent) + (push (cons 'User-Agent user-agent) other-headers)))) + (notmuch-mua-pop-to-buffer (message-buffer-name "mail" to) + (or switch-function + (notmuch-mua-get-switch-function))) + (let ((headers + (append + ;; The following is copied from `message-mail' + `((To . ,(or to "")) (Subject . ,(or subject ""))) + ;; C-h f compose-mail says that headers should be specified as + ;; (string . value); however all the rest of message expects + ;; headers to be symbols, not strings (eg message-header-format-alist). + ;; https://lists.gnu.org/archive/html/emacs-devel/2011-01/msg00337.html + ;; We need to convert any string input, eg from rmail-start-mail. + (dolist (h other-headers other-headers) + (when (stringp (car h)) + (setcar h (intern (capitalize (car h)))))))) + ;; Cause `message-setup-1' to do things relevant for mail, + ;; such as observe `message-default-mail-headers'. + (message-this-is-mail t)) + (unless (assq 'From headers) + (push (cons 'From (message-make-from + (notmuch-user-name) + (notmuch-user-primary-email))) + headers)) + (message-setup-1 headers yank-action send-actions return-action)) + (notmuch-fcc-header-setup) + (notmuch-mua--remove-dont-reply-to-names) + (message-sort-headers) + (message-hide-headers) + (set-buffer-modified-p nil) + (notmuch-mua-maybe-set-window-dedicated) + (cond + ((and to subject) (message-goto-body)) + (to (message-goto-subject)) + (t (message-goto-to)))) + +(defvar notmuch-mua-sender-history nil) + +(defun notmuch-mua-prompt-for-sender () + "Prompt for a sender from the user's configured identities." + (if notmuch-identities + (completing-read "Send mail from: " notmuch-identities + nil nil nil 'notmuch-mua-sender-history + (car notmuch-identities)) + (let* ((name (notmuch-user-name)) + (addrs (cons (notmuch-user-primary-email) + (notmuch-user-other-email))) + (address + (completing-read (concat "Sender address for " name ": ") addrs + nil nil nil 'notmuch-mua-sender-history + (car addrs)))) + (message-make-from name address)))) + +(put 'notmuch-mua-new-mail 'notmuch-prefix-doc "... and prompt for sender") +(defun notmuch-mua-new-mail (&optional prompt-for-sender) + "Compose new mail. + +If PROMPT-FOR-SENDER is non-nil, the user will be prompted for +the From: address first." + (interactive "P") + (let ((other-headers + (and (or prompt-for-sender notmuch-always-prompt-for-sender) + (list (cons 'From (notmuch-mua-prompt-for-sender)))))) + (notmuch-mua-mail nil nil other-headers nil (notmuch-mua-get-switch-function)))) + +(defun notmuch-mua-new-forward-messages (messages &optional prompt-for-sender) + "Compose a new message forwarding MESSAGES. + +If PROMPT-FOR-SENDER is non-nil, the user will be prompteed for +the From: address." + (let* ((other-headers + (and (or prompt-for-sender notmuch-always-prompt-for-sender) + (list (cons 'From (notmuch-mua-prompt-for-sender))))) + ;; Comes from the first message and is applied later. + forward-subject + ;; List of accumulated message-references of forwarded messages. + forward-references + ;; List of corresponding message-query. + forward-queries) + ;; Generate the template for the outgoing message. + (notmuch-mua-mail nil "" other-headers nil (notmuch-mua-get-switch-function)) + (save-excursion + ;; Insert all of the forwarded messages. + (mapc (lambda (id) + (let ((temp-buffer (get-buffer-create + (concat "*notmuch-fwd-raw-" id "*")))) + ;; Get the raw version of this message in the buffer. + (with-current-buffer temp-buffer + (erase-buffer) + (let ((coding-system-for-read 'no-conversion)) + (notmuch--call-process notmuch-command nil t nil + "show" "--format=raw" id)) + ;; Because we process the messages in reverse order, + ;; always generate a forwarded subject, then use the + ;; last (i.e. first) one. + (setq forward-subject (message-make-forward-subject)) + (push (message-fetch-field "Message-ID") forward-references) + (push id forward-queries)) + ;; Make a copy ready to be forwarded in the + ;; composition buffer. + (message-forward-make-body temp-buffer) + ;; Kill the temporary buffer. + (kill-buffer temp-buffer))) + ;; `message-forward-make-body' always puts the message at + ;; the top, so do them in reverse order. + (reverse messages)) + ;; Add in the appropriate subject. + (save-restriction + (message-narrow-to-headers) + (message-remove-header "Subject") + (message-add-header (concat "Subject: " forward-subject)) + (message-remove-header "References") + (message-add-header (concat "References: " + (mapconcat 'identity forward-references " ")))) + ;; Create a buffer-local queue for tag changes triggered when + ;; sending the message. + (when notmuch-message-forwarded-tags + (setq notmuch-message-queued-tag-changes + (cl-loop for id in forward-queries + collect + (cons id notmuch-message-forwarded-tags)))) + ;; `message-forward-make-body' shows the User-agent header. Hide + ;; it again. + (message-hide-headers) + (set-buffer-modified-p nil)))) + +(defun notmuch-mua-new-reply (query-string &optional prompt-for-sender reply-all duplicate) + "Compose a reply to the message identified by QUERY-STRING. + +If PROMPT-FOR-SENDER is non-nil, the user will be prompted for +the From: address first. If REPLY-ALL is non-nil, the message +will be addressed to all recipients of the source message. If +DUPLICATE is non-nil, based the reply on that duplicate file" + ;; `select-active-regions' is t by default. The reply insertion code + ;; sets the region to the quoted message to make it easy to delete + ;; (kill-region or C-w). These two things combine to put the quoted + ;; message in the primary selection. + ;; + ;; This is not what the user wanted and is a privacy risk (accidental + ;; pasting of the quoted message). We can avoid some of the problems + ;; by let-binding select-active-regions to nil. This fixes if the + ;; primary selection was previously in a non-emacs window but not if + ;; it was in an emacs window. To avoid the problem in the latter case + ;; we deactivate mark. + (let ((sender (and prompt-for-sender + (notmuch-mua-prompt-for-sender))) + (select-active-regions nil)) + (notmuch-mua-reply query-string sender reply-all duplicate) + (deactivate-mark))) + +;;; Checks + +(defun notmuch-mua-check-no-misplaced-secure-tag () + "Query user if there is a misplaced secure mml tag. + +Emacs message-send will (probably) ignore a secure mml tag unless +it is at the start of the body. Returns t if there is no such +tag, or the user confirms they mean it." + (save-excursion + (let ((body-start (progn (message-goto-body) (point)))) + (goto-char (point-max)) + (or + ;; We are always fine if there is no secure tag. + (not (search-backward "<#secure" nil t)) + ;; There is a secure tag, so it must be at the start of the + ;; body, with no secure tag earlier (i.e., in the headers). + (and (= (point) body-start) + (not (search-backward "<#secure" nil t))) + ;; The user confirms they means it. + (yes-or-no-p "\ +There is a <#secure> tag not at the start of the body. It is +likely that the message will be sent unsigned and unencrypted. +Really send? "))))) + +(defun notmuch-mua-check-secure-tag-has-newline () + "Query if the secure mml tag has a newline following it. + +Emacs message-send will (probably) ignore a correctly placed +secure mml tag unless it is followed by a newline. Returns t if +any secure tag is followed by a newline, or the user confirms +they mean it." + (save-excursion + (message-goto-body) + (or + ;; There is no (correctly placed) secure tag. + (not (looking-at "<#secure")) + ;; The secure tag is followed by a newline. + (looking-at "<#secure[^\n>]*>\n") + ;; The user confirms they means it. + (yes-or-no-p "\ +The <#secure> tag at the start of the body is not followed by a +newline. It is likely that the message will be sent unsigned and +unencrypted. Really send? ")))) + +;;; Finishing commands + +(defun notmuch-mua-send-common (arg &optional exit) + (interactive "P") + (run-hooks 'notmuch-mua-send-hook) + (when (and (notmuch-mua-check-no-misplaced-secure-tag) + (notmuch-mua-check-secure-tag-has-newline)) + (cl-letf (((symbol-function 'message-do-fcc) + #'notmuch-maildir-message-do-fcc)) + (if exit + (message-send-and-exit arg) + (message-send arg))))) + +;;;###autoload +(defun notmuch-mua-send-and-exit (&optional arg) + (interactive "P") + (notmuch-mua-send-common arg t)) + +;;;###autoload +(defun notmuch-mua-send (&optional arg) + (interactive "P") + (notmuch-mua-send-common arg)) + +;;;###autoload +(defun notmuch-mua-kill-buffer () + (interactive) + (message-kill-buffer)) + +;;; _ + +;;;###autoload +(define-mail-user-agent 'notmuch-user-agent + 'notmuch-mua-mail + 'notmuch-mua-send-and-exit + 'notmuch-mua-kill-buffer + 'notmuch-mua-send-hook) + +;; Add some more headers to the list that `message-mode' hides when +;; composing a message. +(notmuch-mua-add-more-hidden-headers) + +(provide 'notmuch-mua) + +;;; notmuch-mua.el ends here diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-mua.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-mua.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-parser.el b/emacs/elpa/notmuch-20240816.2039/notmuch-parser.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-parser.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-parser.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-pkg.el b/emacs/elpa/notmuch-20240816.2039/notmuch-pkg.el @@ -0,0 +1,4 @@ +(define-package "notmuch" "20240816.2039" "run notmuch within emacs" 'nil :commit "2355ff274d3694fc79c655bb45c61245fb9a9302" :url "https://notmuchmail.org") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-print.el b/emacs/elpa/notmuch-20240816.2039/notmuch-print.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-print.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-print.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-query.el b/emacs/elpa/notmuch-20240816.2039/notmuch-query.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-query.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-query.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-show.el b/emacs/elpa/notmuch-20240816.2039/notmuch-show.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-show.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-show.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-tag.el b/emacs/elpa/notmuch-20240816.2039/notmuch-tag.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-tag.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-tag.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-tree.el b/emacs/elpa/notmuch-20240816.2039/notmuch-tree.el diff --git a/emacs/elpa/notmuch-20240816.2039/notmuch-tree.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-tree.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-wash.el b/emacs/elpa/notmuch-20240816.2039/notmuch-wash.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch-wash.elc b/emacs/elpa/notmuch-20240816.2039/notmuch-wash.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch.el b/emacs/elpa/notmuch-20240816.2039/notmuch.el diff --git a/emacs/elpa/notmuch-20240809.1318/notmuch.elc b/emacs/elpa/notmuch-20240816.2039/notmuch.elc Binary files differ. diff --git a/emacs/elpa/notmuch-20240809.1318/rstdoc.el b/emacs/elpa/notmuch-20240816.2039/rstdoc.el diff --git a/emacs/elpa/notmuch-20240809.1318/rstdoc.elc b/emacs/elpa/notmuch-20240816.2039/rstdoc.elc Binary files differ. diff --git a/emacs/elpa/transient-20240805.1231/transient-pkg.el b/emacs/elpa/transient-20240805.1231/transient-pkg.el @@ -1,16 +0,0 @@ -(define-package "transient" "20240805.1231" "Transient commands" - '((emacs "26.1") - (compat "30.0.0.0") - (seq "2.24")) - :commit "b2cb4e578f2362a0354c4a31a6bd89d6c4b63d63" :authors - '(("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) - :maintainers - '(("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) - :maintainer - '("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev") - :keywords - '("extensions") - :url "https://github.com/magit/transient") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/transient-20240805.1231/transient.el b/emacs/elpa/transient-20240805.1231/transient.el @@ -1,4586 +0,0 @@ -;;; transient.el --- Transient commands -*- lexical-binding:t -*- - -;; Copyright (C) 2018-2024 Free Software Foundation, Inc. - -;; Author: Jonas Bernoulli <emacs.transient@jonas.bernoulli.dev> -;; Homepage: https://github.com/magit/transient -;; Keywords: extensions - -;; Package-Version: 0.7.4 -;; Package-Requires: ((emacs "26.1") (compat "30.0.0.0") (seq "2.24")) - -;; SPDX-License-Identifier: GPL-3.0-or-later - -;; This file is part of GNU Emacs. - -;; GNU Emacs 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. -;; -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; Transient is the library used to implement the keyboard-driven menus -;; in Magit. It is distributed as a separate package, so that it can be -;; used to implement similar menus in other packages. - -;;; Code: - -(require 'cl-lib) -(require 'compat) -(require 'eieio) -(require 'edmacro) -(require 'format-spec) - -(eval-and-compile - (when (and (featurep 'seq) - (not (fboundp 'seq-keep))) - (unload-feature 'seq 'force))) -(require 'seq) -(unless (fboundp 'seq-keep) - (display-warning 'transient (substitute-command-keys "\ -Transient requires `seq' >= 2.24, -but due to bad defaults, Emacs's package manager, refuses to -upgrade this and other built-in packages to higher releases -from GNU Elpa, when a package specifies that this is needed. - -To fix this, you have to add this to your init file: - - (setq package-install-upgrade-built-in t) - -Then evaluate that expression by placing the cursor after it -and typing \\[eval-last-sexp]. - -Once you have done that, you have to explicitly upgrade `seq': - - \\[package-upgrade] seq \\`RET' - -Then you also must make sure the updated version is loaded, -by evaluating this form: - - (progn (unload-feature 'seq t) (require 'seq)) - -Until you do this, you will get random errors about `seq-keep' -being undefined while using Transient. - -If you don't use the `package' package manager but still get -this warning, then your chosen package manager likely has a -similar defect.") :emergency)) - -(eval-when-compile (require 'subr-x)) - -(declare-function info "info" (&optional file-or-node buffer)) -(declare-function Man-find-section "man" (section)) -(declare-function Man-next-section "man" (n)) -(declare-function Man-getpage-in-background "man" (topic)) - -(defvar Man-notify-method) -(defvar pp-default-function) ; since Emacs 29.1 - -(defmacro transient--with-emergency-exit (id &rest body) - (declare (indent defun)) - (unless (keywordp id) - (setq body (cons id body)) - (setq id nil)) - `(condition-case err - (let ((debugger #'transient--exit-and-debug)) - ,(macroexp-progn body)) - ((debug error) - (transient--emergency-exit ,id) - (signal (car err) (cdr err))))) - -(defun transient--exit-and-debug (&rest args) - (transient--emergency-exit :debugger) - (apply #'debug args)) - -;;; Options - -(defgroup transient nil - "Transient commands." - :group 'extensions) - -(defcustom transient-show-popup t - "Whether to show the current transient in a popup buffer. -\\<transient-map> -- If t, then show the popup as soon as a transient prefix command - is invoked. - -- If nil, then do not show the popup unless the user explicitly - requests it, by pressing \\[transient-show] or a prefix key. - -- If a number, then delay displaying the popup and instead show - a brief one-line summary. If zero or negative, then suppress - even showing that summary and display the pressed key only. - - Show the popup when the user explicitly requests it by pressing - \\[transient-show] or a prefix key. Unless zero, then also show the popup - after that many seconds of inactivity (using the absolute value)." - :package-version '(transient . "0.1.0") - :group 'transient - :type '(choice (const :tag "instantly" t) - (const :tag "on demand" nil) - (const :tag "on demand (no summary)" 0) - (number :tag "after delay" 1))) - -(defcustom transient-enable-popup-navigation t - "Whether navigation commands are enabled in the transient popup. - -While a transient is active the transient popup buffer is not the -current buffer, making it necessary to use dedicated commands to -act on that buffer itself. If this is non-nil, then the following -bindings are available: - -\\<transient-popup-navigation-map>\ -- \\[transient-backward-button] moves the cursor to the previous suffix. -- \\[transient-forward-button] moves the cursor to the next suffix. -- \\[transient-push-button] invokes the suffix the cursor is on. -\\<transient-button-map>\ -- \\`<mouse-1>' and \\`<mouse-2>' invoke the clicked on suffix. -\\<transient-popup-navigation-map>\ -- \\[transient-isearch-backward]\ - and \\[transient-isearch-forward] start isearch in the popup buffer. - -\\`<mouse-1>' and \\`<mouse-2>' are bound in `transient-push-button'. -All other bindings are in `transient-popup-navigation-map'. - -By default \\`M-RET' is bound to `transient-push-button', instead of -\\`RET', because if a transient allows the invocation of non-suffixes -then it is likely that you would want \\`RET' to do what it would do -if no transient were active." - :package-version '(transient . "0.4.0") - :group 'transient - :type 'boolean) - -(defcustom transient-display-buffer-action - '(display-buffer-in-side-window - (side . bottom) - (dedicated . t) - (inhibit-same-window . t) - (window-parameters (no-other-window . t))) - "The action used to display the transient popup buffer. - -The transient popup buffer is displayed in a window using - - (display-buffer BUFFER transient-display-buffer-action) - -The value of this option has the form (FUNCTION . ALIST), -where FUNCTION is a function or a list of functions. Each such -function should accept two arguments: a buffer to display and an -alist of the same form as ALIST. See info node `(elisp)Choosing -Window' for details. - -The default is: - - (display-buffer-in-side-window - (side . bottom) - (dedicated . t) - (inhibit-same-window . t) - (window-parameters (no-other-window . t))) - -This displays the window at the bottom of the selected frame. -Another useful FUNCTION is `display-buffer-below-selected', which -is what `magit-popup' used by default. For more alternatives see -info node `(elisp)Display Action Functions' and info node -`(elisp)Buffer Display Action Alists'. - -Note that the buffer that was current before the transient buffer -is shown should remain the current buffer. Many suffix commands -act on the thing at point, if appropriate, and if the transient -buffer became the current buffer, then that would change what is -at point. To that effect `inhibit-same-window' ensures that the -selected window is not used to show the transient buffer. - -It may be possible to display the window in another frame, but -whether that works in practice depends on the window-manager. -If the window manager selects the new window (Emacs frame), -then that unfortunately changes which buffer is current. - -If you change the value of this option, then you might also -want to change the value of `transient-mode-line-format'." - :package-version '(transient . "0.3.0") - :group 'transient - :type '(cons (choice function (repeat :tag "Functions" function)) - alist)) - -(defcustom transient-mode-line-format 'line - "The mode-line format for the transient popup buffer. - -If nil, then the buffer has no mode-line. If the buffer is not -displayed right above the echo area, then this probably is not -a good value. - -If `line' (the default) or a natural number, then the buffer -has no mode-line, but a line is drawn is drawn in its place. -If a number is used, that specifies the thickness of the line. -On termcap frames we cannot draw lines, so there `line' and -numbers are synonyms for nil. - -The color of the line is used to indicate if non-suffixes are -allowed and whether they exit the transient. The foreground -color of `transient-key-noop' (if non-suffix are disallowed), -`transient-key-stay' (if allowed and transient stays active), or -`transient-key-exit' (if allowed and they exit the transient) is -used to draw the line. - -Otherwise this can be any mode-line format. -See `mode-line-format' for details." - :package-version '(transient . "0.2.0") - :group 'transient - :type '(choice (const :tag "hide mode-line" nil) - (const :tag "substitute thin line" line) - (number :tag "substitute line with thickness") - (const :tag "name of prefix command" - ("%e" mode-line-front-space - mode-line-buffer-identification)) - (sexp :tag "custom mode-line format"))) - -(defcustom transient-show-common-commands nil - "Whether to show common transient suffixes in the popup buffer. - -These commands are always shown after typing the prefix key -\"C-x\" when a transient command is active. To toggle the value -of this variable use \"C-x t\" when a transient is active." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -(defcustom transient-read-with-initial-input nil - "Whether to use the last history element as initial minibuffer input." - :package-version '(transient . "0.2.0") - :group 'transient - :type 'boolean) - -(defcustom transient-highlight-mismatched-keys nil - "Whether to highlight keys that do not match their argument. - -This only affects infix arguments that represent command-line -arguments. When this option is non-nil, then the key binding -for infix argument are highlighted when only a long argument -\(e.g., \"--verbose\") is specified but no shorthand (e.g., \"-v\"). -In the rare case that a short-hand is specified but does not -match the key binding, then it is highlighted differently. - -The highlighting is done using `transient-mismatched-key' -and `transient-nonstandard-key'." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -(defcustom transient-highlight-higher-levels nil - "Whether to highlight suffixes on higher levels. - -This is primarily intended for package authors. - -When non-nil then highlight the description of suffixes whose -level is above 4, the default of `transient-default-level'. -Assuming you have set that variable to 7, this highlights all -suffixes that won't be available to users without them making -the same customization." - :package-version '(transient . "0.3.6") - :group 'transient - :type 'boolean) - -(defcustom transient-substitute-key-function nil - "Function used to modify key bindings. - -This function is called with one argument, the prefix object, -and must return a key binding description, either the existing -key description it finds in the `key' slot, or a substitution. - -This is intended to let users replace certain prefix keys. It -could also be used to make other substitutions, but that is -discouraged. - -For example, \"=\" is hard to reach using my custom keyboard -layout, so I substitute \"(\" for that, which is easy to reach -using a layout optimized for Lisp. - - (setq transient-substitute-key-function - (lambda (obj) - (let ((key (oref obj key))) - (if (string-match \"\\\\`\\\\(=\\\\)[a-zA-Z]\" key) - (replace-match \"(\" t t key 1) - key)))))" - :package-version '(transient . "0.1.0") - :group 'transient - :type '(choice (const :tag "Transform no keys (nil)" nil) function)) - -(defcustom transient-semantic-coloring t - "Whether to use colors to indicate transient behavior. - -If non-nil, then the key binding of each suffix is colorized to -indicate whether it exits the transient state or not, and the -line that is drawn below the transient popup buffer is used to -indicate the behavior of non-suffix commands." - :package-version '(transient . "0.5.0") - :group 'transient - :type 'boolean) - -(defcustom transient-detect-key-conflicts nil - "Whether to detect key binding conflicts. - -Conflicts are detected when a transient prefix command is invoked -and results in an error, which prevents the transient from being -used." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -(defcustom transient-align-variable-pitch nil - "Whether to align columns pixel-wise in the popup buffer. - -If this is non-nil, then columns are aligned pixel-wise to -support variable-pitch fonts. Keys are not aligned, so you -should use a fixed-pitch font for the `transient-key' face. -Other key faces inherit from that face unless a theme is -used that breaks that relationship. - -This option is intended for users who use a variable-pitch -font for the `default' face. - -Also see `transient-force-fixed-pitch'." - :package-version '(transient . "0.4.0") - :group 'transient - :type 'boolean) - -(defcustom transient-force-fixed-pitch nil - "Whether to force use of monospaced font in the popup buffer. - -Even if you use a proportional font for the `default' face, -you might still want to use a monospaced font in transient's -popup buffer. Setting this option to t causes `default' to -be remapped to `fixed-pitch' in that buffer. - -Also see `transient-align-variable-pitch'." - :package-version '(transient . "0.2.0") - :group 'transient - :type 'boolean) - -(defcustom transient-force-single-column nil - "Whether to force use of a single column to display suffixes. - -This might be useful for users with low vision who use large -text and might otherwise have to scroll in two dimensions." - :package-version '(transient . "0.3.6") - :group 'transient - :type 'boolean) - -(defcustom transient-hide-during-minibuffer-read nil - "Whether to hide the transient buffer while reading in the minibuffer." - :package-version '(transient . "0.4.0") - :group 'transient - :type 'boolean) - -(defconst transient--max-level 7) -(defconst transient--default-child-level 1) -(defconst transient--default-prefix-level 4) - -(defcustom transient-default-level transient--default-prefix-level - "Control what suffix levels are made available by default. - -Each suffix command is placed on a level and each prefix command -has a level, which controls which suffix commands are available. -Integers between 1 and 7 (inclusive) are valid levels. - -The levels of individual transients and/or their individual -suffixes can be changed individually, by invoking the prefix and -then pressing \"C-x l\". - -The default level for both transients and their suffixes is 4. -This option only controls the default for transients. The default -suffix level is always 4. The author of a transient should place -certain suffixes on a higher level if they expect that it won't be -of use to most users, and they should place very important suffixes -on a lower level so that they remain available even if the user -lowers the transient level. - -\(Magit currently places nearly all suffixes on level 4 and lower -levels are not used at all yet. So for the time being you should -not set a lower level here and using a higher level might not -give you as many additional suffixes as you hoped.)" - :package-version '(transient . "0.1.0") - :group 'transient - :type '(choice (const :tag "1 - fewest suffixes" 1) - (const 2) - (const 3) - (const :tag "4 - default" 4) - (const 5) - (const 6) - (const :tag "7 - most suffixes" 7))) - -(defcustom transient-levels-file - (locate-user-emacs-file "transient/levels.el") - "File used to save levels of transients and their suffixes." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'file) - -(defcustom transient-values-file - (locate-user-emacs-file "transient/values.el") - "File used to save values of transients." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'file) - -(defcustom transient-history-file - (locate-user-emacs-file "transient/history.el") - "File used to save history of transients and their infixes." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'file) - -(defcustom transient-history-limit 10 - "Number of history elements to keep when saving to file." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'integer) - -(defcustom transient-save-history t - "Whether to save history of transient commands when exiting Emacs." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -;;; Faces - -(defgroup transient-faces nil - "Faces used by Transient." - :group 'transient) - -(defface transient-heading '((t :inherit font-lock-keyword-face)) - "Face used for headings." - :group 'transient-faces) - -(defface transient-argument '((t :inherit font-lock-string-face :weight bold)) - "Face used for enabled arguments." - :group 'transient-faces) - -(defface transient-inactive-argument '((t :inherit shadow)) - "Face used for inactive arguments." - :group 'transient-faces) - -(defface transient-value '((t :inherit font-lock-string-face :weight bold)) - "Face used for values." - :group 'transient-faces) - -(defface transient-inactive-value '((t :inherit shadow)) - "Face used for inactive values." - :group 'transient-faces) - -(defface transient-unreachable '((t :inherit shadow)) - "Face used for suffixes unreachable from the current prefix sequence." - :group 'transient-faces) - -(defface transient-inapt-suffix '((t :inherit shadow :italic t)) - "Face used for suffixes that are inapt at this time." - :group 'transient-faces) - -(defface transient-active-infix '((t :inherit highlight)) - "Face used for the infix for which the value is being read." - :group 'transient-faces) - -(defface transient-enabled-suffix - '((t :background "green" :foreground "black" :weight bold)) - "Face used for enabled levels while editing suffix levels. -See info node `(transient)Enabling and Disabling Suffixes'." - :group 'transient-faces) - -(defface transient-disabled-suffix - '((t :background "red" :foreground "black" :weight bold)) - "Face used for disabled levels while editing suffix levels. -See info node `(transient)Enabling and Disabling Suffixes'." - :group 'transient-faces) - -(defface transient-higher-level - `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) - :color ,(let ((color (face-attribute 'shadow :foreground nil t))) - (or (and (not (eq color 'unspecified)) color) - "grey60"))))) - "Face optionally used to highlight suffixes on higher levels. -Also see option `transient-highlight-higher-levels'." - :group 'transient-faces) - -(defface transient-delimiter '((t :inherit shadow)) - "Face used for delimiters and separators. -This includes the parentheses around values and the pipe -character used to separate possible values from each other." - :group 'transient-faces) - -(defface transient-key '((t :inherit font-lock-builtin-face)) - "Face used for keys." - :group 'transient-faces) - -(defface transient-key-stay - `((((class color) (background light)) - :inherit transient-key - :foreground "#22aa22") - (((class color) (background dark)) - :inherit transient-key - :foreground "#ddffdd")) - "Face used for keys of suffixes that don't exit transient state." - :group 'transient-faces) - -(defface transient-key-noop - `((((class color) (background light)) - :inherit transient-key - :foreground "grey80") - (((class color) (background dark)) - :inherit transient-key - :foreground "grey30")) - "Face used for keys of suffixes that currently cannot be invoked." - :group 'transient-faces) - -(defface transient-key-return - `((((class color) (background light)) - :inherit transient-key - :foreground "#aaaa11") - (((class color) (background dark)) - :inherit transient-key - :foreground "#ffffcc")) - "Face used for keys of suffixes that return to the parent transient." - :group 'transient-faces) - -(defface transient-key-exit - `((((class color) (background light)) - :inherit transient-key - :foreground "#aa2222") - (((class color) (background dark)) - :inherit transient-key - :foreground "#ffdddd")) - "Face used for keys of suffixes that exit transient state." - :group 'transient-faces) - -(defface transient-unreachable-key - '((t :inherit (shadow transient-key) :weight normal)) - "Face used for keys unreachable from the current prefix sequence." - :group 'transient-faces) - -(defface transient-nonstandard-key - `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) - :color "cyan"))) - "Face optionally used to highlight keys conflicting with short-argument. -Also see option `transient-highlight-mismatched-keys'." - :group 'transient-faces) - -(defface transient-mismatched-key - `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) - :color "magenta"))) - "Face optionally used to highlight keys without a short-argument. -Also see option `transient-highlight-mismatched-keys'." - :group 'transient-faces) - -;;; Persistence - -(defun transient--read-file-contents (file) - (with-demoted-errors "Transient error: %S" - (and (file-exists-p file) - (with-temp-buffer - (insert-file-contents file) - (read (current-buffer)))))) - -(defun transient--pp-to-file (list file) - (make-directory (file-name-directory file) t) - (setq list (cl-sort (copy-sequence list) #'string< :key #'car)) - (with-temp-file file - (let ((print-level nil) - (print-length nil) - (pp-default-function 'pp-28) - (fill-column 999)) - (pp list (current-buffer))))) - -(defvar transient-values - (transient--read-file-contents transient-values-file) - "Values of transient commands. -The value of this variable persists between Emacs sessions -and you usually should not change it manually.") - -(defun transient-save-values () - (transient--pp-to-file transient-values transient-values-file)) - -(defvar transient-levels - (transient--read-file-contents transient-levels-file) - "Levels of transient commands. -The value of this variable persists between Emacs sessions -and you usually should not change it manually.") - -(defun transient-save-levels () - (transient--pp-to-file transient-levels transient-levels-file)) - -(defvar transient-history - (transient--read-file-contents transient-history-file) - "History of transient commands and infix arguments. -The value of this variable persists between Emacs sessions -\(unless `transient-save-history' is nil) and you usually -should not change it manually.") - -(defun transient-save-history () - (setq transient-history - (cl-sort (mapcar (pcase-lambda (`(,key . ,val)) - (cons key (seq-take (delete-dups val) - transient-history-limit))) - transient-history) - #'string< :key #'car)) - (transient--pp-to-file transient-history transient-history-file)) - -(defun transient-maybe-save-history () - "Save the value of `transient-history'. -If `transient-save-history' is nil, then do nothing." - (when transient-save-history - (transient-save-history))) - -(unless noninteractive - (add-hook 'kill-emacs-hook #'transient-maybe-save-history)) - -;;; Classes -;;;; Prefix - -(defclass transient-prefix () - ((prototype :initarg :prototype) - (command :initarg :command) - (level :initarg :level) - (variable :initarg :variable :initform nil) - (init-value :initarg :init-value) - (value) (default-value :initarg :value) - (scope :initarg :scope :initform nil) - (history :initarg :history :initform nil) - (history-pos :initarg :history-pos :initform 0) - (history-key :initarg :history-key :initform nil) - (show-help :initarg :show-help :initform nil) - (info-manual :initarg :info-manual :initform nil) - (man-page :initarg :man-page :initform nil) - (transient-suffix :initarg :transient-suffix :initform nil) - (transient-non-suffix :initarg :transient-non-suffix :initform nil) - (transient-switch-frame :initarg :transient-switch-frame) - (refresh-suffixes :initarg :refresh-suffixes :initform nil) - (incompatible :initarg :incompatible :initform nil) - (suffix-description :initarg :suffix-description) - (variable-pitch :initarg :variable-pitch :initform nil) - (column-widths :initarg :column-widths :initform nil) - (unwind-suffix :documentation "Internal use." :initform nil)) - "Transient prefix command. - -Each transient prefix command consists of a command, which is -stored in a symbol's function slot and an object, which is -stored in the `transient--prefix' property of the same symbol. - -When a transient prefix command is invoked, then a clone of that -object is stored in the global variable `transient--prefix' and -the prototype is stored in the clone's `prototype' slot.") - -;;;; Suffix - -(defclass transient-child () - ((level - :initarg :level - :initform (symbol-value 'transient--default-child-level) - :documentation "Enable if level of prefix is equal or greater.") - (if - :initarg :if - :initform nil - :documentation "Enable if predicate returns non-nil.") - (if-not - :initarg :if-not - :initform nil - :documentation "Enable if predicate returns nil.") - (if-non-nil - :initarg :if-non-nil - :initform nil - :documentation "Enable if variable's value is non-nil.") - (if-nil - :initarg :if-nil - :initform nil - :documentation "Enable if variable's value is nil.") - (if-mode - :initarg :if-mode - :initform nil - :documentation "Enable if major-mode matches value.") - (if-not-mode - :initarg :if-not-mode - :initform nil - :documentation "Enable if major-mode does not match value.") - (if-derived - :initarg :if-derived - :initform nil - :documentation "Enable if major-mode derives from value.") - (if-not-derived - :initarg :if-not-derived - :initform nil - :documentation "Enable if major-mode does not derive from value.") - (inapt - :initform nil) - (inapt-face - :initarg :inapt-face - :initform 'transient-inapt-suffix) - (inapt-if - :initarg :inapt-if - :initform nil - :documentation "Inapt if predicate returns non-nil.") - (inapt-if-not - :initarg :inapt-if-not - :initform nil - :documentation "Inapt if predicate returns nil.") - (inapt-if-non-nil - :initarg :inapt-if-non-nil - :initform nil - :documentation "Inapt if variable's value is non-nil.") - (inapt-if-nil - :initarg :inapt-if-nil - :initform nil - :documentation "Inapt if variable's value is nil.") - (inapt-if-mode - :initarg :inapt-if-mode - :initform nil - :documentation "Inapt if major-mode matches value.") - (inapt-if-not-mode - :initarg :inapt-if-not-mode - :initform nil - :documentation "Inapt if major-mode does not match value.") - (inapt-if-derived - :initarg :inapt-if-derived - :initform nil - :documentation "Inapt if major-mode derives from value.") - (inapt-if-not-derived - :initarg :inapt-if-not-derived - :initform nil - :documentation "Inapt if major-mode does not derive from value.")) - "Abstract superclass for group and suffix classes. - -It is undefined what happens if more than one `if*' predicate -slot is non-nil." - :abstract t) - -(defclass transient-suffix (transient-child) - ((definition :allocation :class :initform nil) - (key :initarg :key) - (command :initarg :command) - (transient :initarg :transient) - (format :initarg :format :initform " %k %d") - (description :initarg :description :initform nil) - (face :initarg :face :initform nil) - (show-help :initarg :show-help :initform nil)) - "Superclass for suffix command.") - -(defclass transient-information (transient-suffix) - ((format :initform " %k %d") - (key :initform " ")) - "Display-only information, aligned with suffix keys. -Technically a suffix object with no associated command.") - -(defclass transient-information* (transient-information) - ((format :initform " %d")) - "Display-only information, aligned with suffix descriptions. -Technically a suffix object with no associated command.") - -(defclass transient-infix (transient-suffix) - ((transient :initform t) - (argument :initarg :argument) - (shortarg :initarg :shortarg) - (value :initform nil) - (init-value :initarg :init-value) - (unsavable :initarg :unsavable :initform nil) - (multi-value :initarg :multi-value :initform nil) - (always-read :initarg :always-read :initform nil) - (allow-empty :initarg :allow-empty :initform nil) - (history-key :initarg :history-key :initform nil) - (reader :initarg :reader :initform nil) - (prompt :initarg :prompt :initform nil) - (choices :initarg :choices :initform nil) - (format :initform " %k %d (%v)")) - "Transient infix command." - :abstract t) - -(defclass transient-argument (transient-infix) () - "Abstract superclass for infix arguments." - :abstract t) - -(defclass transient-switch (transient-argument) () - "Class used for command-line argument that can be turned on and off.") - -(defclass transient-option (transient-argument) () - "Class used for command-line argument that can take a value.") - -(defclass transient-variable (transient-infix) - ((variable :initarg :variable) - (format :initform " %k %d %v")) - "Abstract superclass for infix commands that set a variable." - :abstract t) - -(defclass transient-switches (transient-argument) - ((argument-format :initarg :argument-format) - (argument-regexp :initarg :argument-regexp)) - "Class used for sets of mutually exclusive command-line switches.") - -(defclass transient-files (transient-option) () - ((key :initform "--") - (argument :initform "--") - (multi-value :initform rest) - (reader :initform transient-read-files)) - "Class used for the \"--\" argument or similar. -All remaining arguments are treated as files. -They become the value of this argument.") - -(defclass transient-value-preset (transient-suffix) - ((transient :initform t) - (set :initarg := :initform nil)) - "Class used by the `transient-preset' suffix command.") - -;;;; Group - -(defclass transient-group (transient-child) - ((suffixes :initarg :suffixes :initform nil) - (hide :initarg :hide :initform nil) - (description :initarg :description :initform nil) - (pad-keys :initarg :pad-keys :initform nil) - (info-format :initarg :info-format :initform nil) - (setup-children :initarg :setup-children)) - "Abstract superclass of all group classes." - :abstract t) - -(defclass transient-column (transient-group) () - "Group class that displays each element on a separate line.") - -(defclass transient-row (transient-group) () - "Group class that displays all elements on a single line.") - -(defclass transient-columns (transient-group) () - "Group class that displays elements organized in columns. -Direct elements have to be groups whose elements have to be -commands or strings. Each subgroup represents a column. -This class takes care of inserting the subgroups' elements.") - -(defclass transient-subgroups (transient-group) () - "Group class that wraps other groups. - -Direct elements have to be groups whose elements have to be -commands or strings. This group inserts an empty line between -subgroups. The subgroups are responsible for displaying their -elements themselves.") - -;;; Define - -(defmacro transient-define-prefix (name arglist &rest args) - "Define NAME as a transient prefix command. - -ARGLIST are the arguments that command takes. -DOCSTRING is the documentation string and is optional. - -These arguments can optionally be followed by key-value pairs. -Each key has to be a keyword symbol, either `:class' or a keyword -argument supported by the constructor of that class. The -`transient-prefix' class is used if the class is not specified -explicitly. - -GROUPs add key bindings for infix and suffix commands and specify -how these bindings are presented in the popup buffer. At least -one GROUP has to be specified. See info node `(transient)Binding -Suffix and Infix Commands'. - -The BODY is optional. If it is omitted, then ARGLIST is also -ignored and the function definition becomes: - - (lambda () - (interactive) - (transient-setup \\='NAME)) - -If BODY is specified, then it must begin with an `interactive' -form that matches ARGLIST, and it must call `transient-setup'. -It may however call that function only when some condition is -satisfied; that is one of the reason why you might want to use -an explicit BODY. - -All transients have a (possibly nil) value, which is exported -when suffix commands are called, so that they can consume that -value. For some transients it might be necessary to have a sort -of secondary value, called a scope. Such a scope would usually -be set in the commands `interactive' form and has to be passed -to the setup function: - - (transient-setup \\='NAME nil nil :scope SCOPE) - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])" - (declare (debug ( &define name lambda-list - [&optional lambda-doc] - [&rest keywordp sexp] - [&rest vectorp] - [&optional ("interactive" interactive) def-body])) - (indent defun) - (doc-string 3)) - (pcase-let - ((`(,class ,slots ,suffixes ,docstr ,body ,interactive-only) - (transient--expand-define-args args arglist 'transient-define-prefix))) - `(progn - (defalias ',name - ,(if body - `(lambda ,arglist ,@body) - `(lambda () - (interactive) - (transient-setup ',name)))) - (put ',name 'interactive-only ,interactive-only) - (put ',name 'function-documentation ,docstr) - (put ',name 'transient--prefix - (,(or class 'transient-prefix) :command ',name ,@slots)) - (put ',name 'transient--layout - (list ,@(cl-mapcan (lambda (s) (transient--parse-child name s)) - suffixes)))))) - -(defmacro transient-define-suffix (name arglist &rest args) - "Define NAME as a transient suffix command. - -ARGLIST are the arguments that the command takes. -DOCSTRING is the documentation string and is optional. - -These arguments can optionally be followed by key-value pairs. -Each key has to be a keyword symbol, either `:class' or a -keyword argument supported by the constructor of that class. -The `transient-suffix' class is used if the class is not -specified explicitly. - -The BODY must begin with an `interactive' form that matches -ARGLIST. The infix arguments are usually accessed by using -`transient-args' inside `interactive'. - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... [BODY...])" - (declare (debug ( &define name lambda-list - [&optional lambda-doc] - [&rest keywordp sexp] - [&optional ("interactive" interactive) def-body])) - (indent defun) - (doc-string 3)) - (pcase-let - ((`(,class ,slots ,_ ,docstr ,body ,interactive-only) - (transient--expand-define-args args arglist 'transient-define-suffix))) - `(progn - (defalias ',name - ,(if (and (not body) class (oref-default class definition)) - `(oref-default ',class definition) - `(lambda ,arglist ,@body))) - (put ',name 'interactive-only ,interactive-only) - (put ',name 'function-documentation ,docstr) - (put ',name 'transient--suffix - (,(or class 'transient-suffix) :command ',name ,@slots))))) - -(defmacro transient-augment-suffix (name &rest args) - "Augment existing command NAME with a new transient suffix object. -Similar to `transient-define-suffix' but define a suffix object only. -\n\(fn NAME [KEYWORD VALUE]...)" - (declare (debug (&define name [&rest keywordp sexp])) - (indent defun)) - (pcase-let - ((`(,class ,slots) - (transient--expand-define-args args nil 'transient-augment-suffix t))) - `(put ',name 'transient--suffix - (,(or class 'transient-suffix) :command ',name ,@slots)))) - -(defmacro transient-define-infix (name arglist &rest args) - "Define NAME as a transient infix command. - -ARGLIST is always ignored and reserved for future use. -DOCSTRING is the documentation string and is optional. - -At least one key-value pair is required. All transient infix -commands are equal to each other (but not eq). It is meaning- -less to define an infix command, without providing at least one -keyword argument (usually `:argument' or `:variable', depending -on the class). The suffix class defaults to `transient-switch' -and can be set using the `:class' keyword. - -The function definitions is always: - - (lambda () - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) - -`transient-infix-read' and `transient-infix-set' are generic -functions. Different infix commands behave differently because -the concrete methods are different for different infix command -classes. In rare case the above command function might not be -suitable, even if you define your own infix command class. In -that case you have to use `transient-define-suffix' to define -the infix command and use t as the value of the `:transient' -keyword. - -\(fn NAME ARGLIST [DOCSTRING] KEYWORD VALUE [KEYWORD VALUE]...)" - (declare (debug ( &define name lambda-list - [&optional lambda-doc] - keywordp sexp - [&rest keywordp sexp])) - (indent defun) - (doc-string 3)) - (pcase-let - ((`(,class ,slots ,_ ,docstr ,_ ,interactive-only) - (transient--expand-define-args args arglist 'transient-define-infix t))) - `(progn - (defalias ',name #'transient--default-infix-command) - (put ',name 'interactive-only ,interactive-only) - (put ',name 'completion-predicate #'transient--suffix-only) - (put ',name 'function-documentation ,docstr) - (put ',name 'transient--suffix - (,(or class 'transient-switch) :command ',name ,@slots))))) - -(defalias 'transient-define-argument #'transient-define-infix - "Define NAME as a transient infix command. - -Only use this alias to define an infix command that actually -sets an infix argument. To define a infix command that, for -example, sets a variable, use `transient-define-infix' instead. - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)") - -(defun transient--default-infix-command () - ;; Most infix commands are but an alias for this command. - "Cannot show any documentation for this transient infix command. - -When you request help for an infix command using `transient-help', that -usually shows the respective man-page and tries to jump to the location -where the respective argument is being described. - -If no man-page is specified for the containing transient menu, then the -docstring is displayed instead, if any. - -If the infix command doesn't have a docstring, as is the case here, then -this docstring is displayed instead, because technically infix commands -are aliases for `transient--default-infix-command'. - -`describe-function' also shows the docstring of the infix command, -falling back to that of the same aliased command." - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) -(put 'transient--default-infix-command 'interactive-only t) -(put 'transient--default-infix-command 'completion-predicate - #'transient--suffix-only) - -(define-advice find-function-advised-original - (:around (fn func) transient-default-infix) - "Return nil instead of `transient--default-infix-command'. -When using `find-function' to jump to the definition of a transient -infix command/argument, then we want to actually jump to that, not to -the definition of `transient--default-infix-command', which all infix -commands are aliases for." - (let ((val (funcall fn func))) - (and val (not (eq val 'transient--default-infix-command)) val))) - -(eval-and-compile ;transient--expand-define-args - (defun transient--expand-define-args (args &optional arglist form nobody) - ;; ARGLIST and FORM are only optional for backward compatibility. - ;; This is necessary because "emoji.el" from Emacs 29 calls this - ;; function directly, with just one argument. - (unless (listp arglist) - (error "Mandatory ARGLIST is missing")) - (let (class keys suffixes docstr declare (interactive-only t)) - (when (stringp (car args)) - (setq docstr (pop args))) - (while (keywordp (car args)) - (let ((k (pop args)) - (v (pop args))) - (if (eq k :class) - (setq class v) - (push k keys) - (push v keys)))) - (while (let ((arg (car args))) - (or (vectorp arg) - (and arg (symbolp arg)))) - (push (pop args) suffixes)) - (when (eq (car-safe (car args)) 'declare) - (setq declare (car args)) - (setq args (cdr args)) - (when-let ((int (assq 'interactive-only declare))) - (setq interactive-only (cadr int)) - (delq int declare)) - (unless (cdr declare) - (setq declare nil))) - (cond - ((not args)) - (nobody - (error "%s: No function body allowed" form)) - ((not (eq (car-safe (nth (if declare 1 0) args)) 'interactive)) - (error "%s: Interactive form missing" form))) - (list (if (eq (car-safe class) 'quote) - (cadr class) - class) - (nreverse keys) - (nreverse suffixes) - docstr - (if declare (cons declare args) args) - interactive-only)))) - -(defun transient--parse-child (prefix spec) - (cl-typecase spec - (null (error "Invalid transient--parse-child spec: %s" spec)) - (symbol (let ((value (symbol-value spec))) - (if (and (listp value) - (or (listp (car value)) - (vectorp (car value)))) - (cl-mapcan (lambda (s) (transient--parse-child prefix s)) value) - (transient--parse-child prefix value)))) - (vector (and-let* ((c (transient--parse-group prefix spec))) (list c))) - (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c))) - (string (list spec)) - (t (error "Invalid transient--parse-child spec: %s" spec)))) - -(defun transient--parse-group (prefix spec) - (setq spec (append spec nil)) - (cl-symbol-macrolet - ((car (car spec)) - (pop (pop spec))) - (let (level class args) - (when (integerp car) - (setq level pop)) - (when (stringp car) - (setq args (plist-put args :description pop))) - (while (keywordp car) - (let ((key pop) - (val pop)) - (cond ((eq key :class) - (setq class (macroexp-quote val))) - ((or (symbolp val) - (and (listp val) (not (eq (car val) 'lambda)))) - (setq args (plist-put args key (macroexp-quote val)))) - ((setq args (plist-put args key val)))))) - (unless (or spec class (not (plist-get args :setup-children))) - (message "WARNING: %s: When %s is used, %s must also be specified" - 'transient-define-prefix :setup-children :class)) - (list 'vector - (or level transient--default-child-level) - (cond (class) - ((or (vectorp car) - (and car (symbolp car))) - (quote 'transient-columns)) - ((quote 'transient-column))) - (and args (cons 'list args)) - (cons 'list - (cl-mapcan (lambda (s) (transient--parse-child prefix s)) - spec)))))) - -(defun transient--parse-suffix (prefix spec) - (let (level class args) - (cl-symbol-macrolet - ((car (car spec)) - (pop (pop spec))) - (when (integerp car) - (setq level pop)) - (when (or (stringp car) - (vectorp car)) - (setq args (plist-put args :key pop))) - (cond - ((or (stringp car) - (and (eq (car-safe car) 'lambda) - (not (commandp car)))) - (setq args (plist-put args :description pop))) - ((and (symbolp car) - (not (keywordp car)) - (not (commandp car)) - (commandp (cadr spec))) - (setq args (plist-put args :description (macroexp-quote pop))))) - (cond - ((memq car '(:info :info*))) - ((keywordp car) - (error "Need command, `:info' or `:info*', got `%s'" car)) - ((symbolp car) - (setq args (plist-put args :command (macroexp-quote pop)))) - ((and (commandp car) - (not (stringp car))) - (let ((cmd pop) - (sym (intern - (format "transient:%s:%s" - prefix - (let ((desc (plist-get args :description))) - (if (and (stringp desc) - (length< desc 16)) - desc - (plist-get args :key))))))) - (setq args (plist-put - args :command - `(prog1 ',sym - (put ',sym 'interactive-only t) - (put ',sym 'completion-predicate #'transient--suffix-only) - (defalias ',sym - ,(if (eq (car-safe cmd) 'lambda) - cmd - (macroexp-quote cmd)))))))) - ((or (stringp car) - (and car (listp car))) - (let ((arg pop) - (sym nil)) - (cl-typecase arg - (list - (setq args (plist-put args :shortarg (car arg))) - (setq args (plist-put args :argument (cadr arg))) - (setq arg (cadr arg))) - (string - (when-let ((shortarg (transient--derive-shortarg arg))) - (setq args (plist-put args :shortarg shortarg))) - (setq args (plist-put args :argument arg)))) - (setq sym (intern (format "transient:%s:%s" prefix arg))) - (setq args (plist-put - args :command - `(prog1 ',sym - (put ',sym 'interactive-only t) - (put ',sym 'completion-predicate #'transient--suffix-only) - (defalias ',sym #'transient--default-infix-command)))) - (cond ((and car (not (keywordp car))) - (setq class 'transient-option) - (setq args (plist-put args :reader (macroexp-quote pop)))) - ((not (string-suffix-p "=" arg)) - (setq class 'transient-switch)) - (t - (setq class 'transient-option))))) - (t - (error "Needed command or argument, got %S" car))) - (while (keywordp car) - (let ((key pop) - (val pop)) - (cond ((eq key :class) (setq class val)) - ((eq key :level) (setq level val)) - ((eq key :info) - (setq class 'transient-information) - (setq args (plist-put args :description val))) - ((eq key :info*) - (setq class 'transient-information*) - (setq args (plist-put args :description val))) - ((eq (car-safe val) '\,) - (setq args (plist-put args key (cadr val)))) - ((or (symbolp val) - (and (listp val) (not (eq (car val) 'lambda)))) - (setq args (plist-put args key (macroexp-quote val)))) - ((setq args (plist-put args key val))))))) - (unless (plist-get args :key) - (when-let ((shortarg (plist-get args :shortarg))) - (setq args (plist-put args :key shortarg)))) - (list 'list - (or level transient--default-child-level) - (macroexp-quote (or class 'transient-suffix)) - (cons 'list args)))) - -(defun transient--derive-shortarg (arg) - (save-match-data - (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg) - (match-string 1 arg)))) - -(defun transient-command-completion-not-suffix-only-p (symbol _buffer) - "Say whether SYMBOL should be offered as a completion. -If the value of SYMBOL's `completion-predicate' property is -`transient--suffix-only', then return nil, otherwise return t. -This is the case when a command should only ever be used as a -suffix of a transient prefix command (as opposed to bindings -in regular keymaps or by using `execute-extended-command')." - (not (eq (get symbol 'completion-predicate) 'transient--suffix-only))) - -(defalias 'transient--suffix-only #'ignore - "Ignore ARGUMENTS, do nothing, and return nil. -Also see `transient-command-completion-not-suffix-only-p'. -Only use this alias as the value of the `completion-predicate' -symbol property.") - -(when (and (boundp 'read-extended-command-predicate) ; since Emacs 28.1 - (not read-extended-command-predicate)) - (setq read-extended-command-predicate - #'transient-command-completion-not-suffix-only-p)) - -(defun transient-parse-suffix (prefix suffix) - "Parse SUFFIX, to be added to PREFIX. -PREFIX is a prefix command, a symbol. -SUFFIX is a suffix command or a group specification (of - the same forms as expected by `transient-define-prefix'). -Intended for use in a group's `:setup-children' function." - (cl-assert (and prefix (symbolp prefix))) - (eval (car (transient--parse-child prefix suffix)) t)) - -(defun transient-parse-suffixes (prefix suffixes) - "Parse SUFFIXES, to be added to PREFIX. -PREFIX is a prefix command, a symbol. -SUFFIXES is a list of suffix command or a group specification - (of the same forms as expected by `transient-define-prefix'). -Intended for use in a group's `:setup-children' function." - (cl-assert (and prefix (symbolp prefix))) - (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes)) - -;;; Edit - -(defun transient--insert-suffix (prefix loc suffix action &optional keep-other) - (let* ((suf (cl-etypecase suffix - (vector (transient--parse-group prefix suffix)) - (list (transient--parse-suffix prefix suffix)) - (string suffix))) - (mem (transient--layout-member loc prefix)) - (elt (car mem))) - (setq suf (eval suf t)) - (cond - ((not mem) - (message "Cannot insert %S into %s; %s not found" - suffix prefix loc)) - ((or (and (vectorp suffix) (not (vectorp elt))) - (and (listp suffix) (vectorp elt)) - (and (stringp suffix) (vectorp elt))) - (message "Cannot place %S into %s at %s; %s" - suffix prefix loc - "suffixes and groups cannot be siblings")) - (t - (when-let* ((bindingp (listp suf)) - (key (transient--spec-key suf)) - (conflict (car (transient--layout-member key prefix))) - (conflictp - (and (not (and (eq action 'replace) - (eq conflict elt))) - (or (not keep-other) - (eq (plist-get (nth 2 suf) :command) - (plist-get (nth 2 conflict) :command))) - (equal (transient--suffix-predicate suf) - (transient--suffix-predicate conflict))))) - (transient-remove-suffix prefix key)) - (pcase-exhaustive action - ('insert (setcdr mem (cons elt (cdr mem))) - (setcar mem suf)) - ('append (setcdr mem (cons suf (cdr mem)))) - ('replace (setcar mem suf))))))) - -;;;###autoload -(defun transient-insert-suffix (prefix loc suffix &optional keep-other) - "Insert a SUFFIX into PREFIX before LOC. -PREFIX is a prefix command, a symbol. -SUFFIX is a suffix command or a group specification (of - the same forms as expected by `transient-define-prefix'). -LOC is a command, a key vector, a key description (a string - as returned by `key-description'), or a coordination list - (whose last element may also be a command or key). -Remove a conflicting binding unless optional KEEP-OTHER is - non-nil. -See info node `(transient)Modifying Existing Transients'." - (declare (indent defun)) - (transient--insert-suffix prefix loc suffix 'insert keep-other)) - -;;;###autoload -(defun transient-append-suffix (prefix loc suffix &optional keep-other) - "Insert a SUFFIX into PREFIX after LOC. -PREFIX is a prefix command, a symbol. -SUFFIX is a suffix command or a group specification (of - the same forms as expected by `transient-define-prefix'). -LOC is a command, a key vector, a key description (a string - as returned by `key-description'), or a coordination list - (whose last element may also be a command or key). -Remove a conflicting binding unless optional KEEP-OTHER is - non-nil. -See info node `(transient)Modifying Existing Transients'." - (declare (indent defun)) - (transient--insert-suffix prefix loc suffix 'append keep-other)) - -;;;###autoload -(defun transient-replace-suffix (prefix loc suffix) - "Replace the suffix at LOC in PREFIX with SUFFIX. -PREFIX is a prefix command, a symbol. -SUFFIX is a suffix command or a group specification (of - the same forms as expected by `transient-define-prefix'). -LOC is a command, a key vector, a key description (a string - as returned by `key-description'), or a coordination list - (whose last element may also be a command or key). -See info node `(transient)Modifying Existing Transients'." - (declare (indent defun)) - (transient--insert-suffix prefix loc suffix 'replace)) - -;;;###autoload -(defun transient-remove-suffix (prefix loc) - "Remove the suffix or group at LOC in PREFIX. -PREFIX is a prefix command, a symbol. -LOC is a command, a key vector, a key description (a string - as returned by `key-description'), or a coordination list - (whose last element may also be a command or key). -See info node `(transient)Modifying Existing Transients'." - (declare (indent defun)) - (transient--layout-member loc prefix 'remove)) - -(defun transient-get-suffix (prefix loc) - "Return the suffix or group at LOC in PREFIX. -PREFIX is a prefix command, a symbol. -LOC is a command, a key vector, a key description (a string - as returned by `key-description'), or a coordination list - (whose last element may also be a command or key). -See info node `(transient)Modifying Existing Transients'." - (if-let ((mem (transient--layout-member loc prefix))) - (car mem) - (error "%s not found in %s" loc prefix))) - -(defun transient-suffix-put (prefix loc prop value) - "Edit the suffix at LOC in PREFIX, setting PROP to VALUE. -PREFIX is a prefix command, a symbol. -SUFFIX is a suffix command or a group specification (of - the same forms as expected by `transient-define-prefix'). -LOC is a command, a key vector, a key description (a string - as returned by `key-description'), or a coordination list - (whose last element may also be a command or key). -See info node `(transient)Modifying Existing Transients'." - (let ((suf (transient-get-suffix prefix loc))) - (setf (elt suf 2) - (plist-put (elt suf 2) prop value)))) - -(defun transient--layout-member (loc prefix &optional remove) - (let ((val (or (get prefix 'transient--layout) - (error "%s is not a transient command" prefix)))) - (when (listp loc) - (while (integerp (car loc)) - (let* ((children (if (vectorp val) (aref val 3) val)) - (mem (transient--nthcdr (pop loc) children))) - (if (and remove (not loc)) - (let ((rest (delq (car mem) children))) - (if (vectorp val) - (aset val 3 rest) - (put prefix 'transient--layout rest)) - (setq val nil)) - (setq val (if loc (car mem) mem))))) - (setq loc (car loc))) - (if loc - (transient--layout-member-1 (transient--kbd loc) val remove) - val))) - -(defun transient--layout-member-1 (loc layout remove) - (cond ((listp layout) - (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove)) - layout)) - ((vectorp (car (aref layout 3))) - (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove)) - (aref layout 3))) - (remove - (aset layout 3 - (delq (car (transient--group-member loc layout)) - (aref layout 3))) - nil) - ((transient--group-member loc layout)))) - -(defun transient--group-member (loc group) - (cl-member-if (lambda (suffix) - (and (listp suffix) - (let* ((def (nth 2 suffix)) - (cmd (plist-get def :command))) - (if (symbolp loc) - (eq cmd loc) - (equal (transient--kbd - (or (plist-get def :key) - (transient--command-key cmd))) - loc))))) - (aref group 3))) - -(defun transient--kbd (keys) - (when (vectorp keys) - (setq keys (key-description keys))) - (when (stringp keys) - (setq keys (kbd keys))) - keys) - -(defun transient--spec-key (spec) - (let ((plist (nth 2 spec))) - (or (plist-get plist :key) - (transient--command-key - (plist-get plist :command))))) - -(defun transient--command-key (cmd) - (and-let* ((obj (transient--suffix-prototype cmd))) - (cond ((slot-boundp obj 'key) - (oref obj key)) - ((slot-exists-p obj 'shortarg) - (if (slot-boundp obj 'shortarg) - (oref obj shortarg) - (transient--derive-shortarg (oref obj argument))))))) - -(defun transient--nthcdr (n list) - (nthcdr (if (< n 0) (- (length list) (abs n)) n) list)) - -;;; Variables - -(defvar transient-current-prefix nil - "The transient from which this suffix command was invoked. -This is an object representing that transient, use -`transient-current-command' to get the respective command.") - -(defvar transient-current-command nil - "The transient from which this suffix command was invoked. -This is a symbol representing that transient, use -`transient-current-prefix' to get the respective object.") - -(defvar transient-current-suffixes nil - "The suffixes of the transient from which this suffix command was invoked. -This is a list of objects. Usually it is sufficient to instead -use the function `transient-args', which returns a list of -values. In complex cases it might be necessary to use this -variable instead.") - -(defvar transient-exit-hook nil - "Hook run after exiting a transient.") - -(defvar transient-setup-buffer-hook nil - "Hook run when setting up the transient buffer. -That buffer is current and empty when this hook runs.") - -(defvar transient--prefix nil) -(defvar transient--layout nil) -(defvar transient--suffixes nil) - -(defconst transient--stay t "Do not exit the transient.") -(defconst transient--exit nil "Do exit the transient.") - -(defvar transient--exitp nil "Whether to exit the transient.") -(defvar transient--showp nil "Whether to show the transient popup buffer.") -(defvar transient--helpp nil "Whether help-mode is active.") -(defvar transient--editp nil "Whether edit-mode is active.") - -(defvar transient--refreshp nil - "Whether to refresh the transient completely.") - -(defvar transient--all-levels-p nil - "Whether temporary display of suffixes on all levels is active.") - -(defvar transient--timer nil) - -(defvar transient--stack nil) - -(defvar transient--minibuffer-depth 0) - -(defvar transient--buffer-name " *transient*" - "Name of the transient buffer.") - -(defvar transient--buffer nil - "The transient menu buffer.") - -(defvar transient--window nil - "The window used to display the transient popup buffer.") - -(defvar transient--original-window nil - "The window that was selected before the transient was invoked. -Usually it remains selected while the transient is active.") - -(defvar transient--original-buffer nil - "The buffer that was current before the transient was invoked. -Usually it remains current while the transient is active.") - -(defvar transient--restore-winconf nil - "Window configuration to restore after exiting help.") - -(defvar transient--shadowed-buffer nil - "The buffer that is temporarily shadowed by the transient buffer. -This is bound while the suffix predicate is being evaluated and while -drawing in the transient buffer.") - -(defvar transient--pending-suffix nil - "The suffix that is currently being processed. -This is bound while the suffix predicate is being evaluated, -and while functions that return faces are being evaluated.") - -(defvar transient--pending-group nil - "The group that is currently being processed. -This is bound while the suffixes are drawn in the transient buffer.") - -(defvar transient--debug nil - "Whether to put debug information into *Messages*.") - -(defvar transient--history nil) - -(defvar transient--scroll-commands - '(transient-scroll-up - transient-scroll-down - mwheel-scroll - scroll-bar-toolkit-scroll)) - -;;; Identities - -(defun transient-active-prefix (&optional prefixes) - "Return the active transient object. - -Return nil if there is no active transient, if the transient buffer -isn't shown, and while the active transient is suspended (e.g., while -the minibuffer is in use). - -Unlike `transient-current-prefix', which is only ever non-nil in code -that is run directly by a command that is invoked while a transient -is current, this function is also suitable for use in asynchronous -code, such as timers and callbacks (this function's main use-case). - -If optional PREFIXES is non-nil, it must be a list of prefix command -symbols, in which case the active transient object is only returned -if it matches one of the PREFIXES." - (and transient--showp - transient--prefix - (or (not prefixes) - (memq (oref transient--prefix command) prefixes)) - (or (memq 'transient--pre-command pre-command-hook) - (and (memq t pre-command-hook) - (memq 'transient--pre-command - (default-value 'pre-command-hook)))) - transient--prefix)) - -(defun transient-prefix-object () - "Return the current prefix as an object. - -While a transient is being setup or refreshed (which involves -preparing its suffixes) the variable `transient--prefix' can be -used to access the prefix object. Thus this is what has to be -used in suffix methods such as `transient-format-description', -and in object-specific functions that are stored in suffix slots -such as `description'. - -When a suffix command is invoked (i.e., in its `interactive' form -and function body) then the variable `transient-current-prefix' -has to be used instead. - -Two distinct variables are needed, because any prefix may itself -be used as a suffix of another prefix, and such sub-prefixes have -to be able to tell themselves apart from the prefix they were -invoked from. - -Regular suffix commands, which are not prefixes, do not have to -concern themselves with this distinction, so they can use this -function instead. In the context of a plain suffix, it always -returns the value of the appropriate variable." - (or transient--prefix transient-current-prefix)) - -(defun transient-suffix-object (&optional command) - "Return the object associated with the current suffix command. - -Each suffix commands is associated with an object, which holds -additional information about the suffix, such as its value (in -the case of an infix command, which is a kind of suffix command). - -This function is intended to be called by infix commands, which -are usually aliases of `transient--default-infix-command', which -is defined like this: - - (defun transient--default-infix-command () - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) - -\(User input is read outside of `interactive' to prevent the -command from being added to `command-history'. See #23.) - -Such commands need to be able to access their associated object -to guide how `transient-infix-read' reads the new value and to -store the read value. Other suffix commands (including non-infix -commands) may also need the object to guide their behavior. - -This function attempts to return the object associated with the -current suffix command even if the suffix command was not invoked -from a transient. (For some suffix command that is a valid thing -to do, for others it is not.) In that case nil may be returned, -if the command was not defined using one of the macros intended -to define such commands. - -The optional argument COMMAND is intended for internal use. If -you are contemplating using it in your own code, then you should -probably use this instead: - - (get COMMAND \\='transient--suffix)" - (when command - (cl-check-type command command)) - (cond - (transient--pending-suffix) - ((or transient--prefix - transient-current-prefix) - (let ((suffixes - (cl-remove-if-not - (lambda (obj) - (eq (oref obj command) - (or command - (if (eq this-command 'transient-set-level) - ;; This is how it can look up for which - ;; command it is setting the level. - this-original-command - this-command)))) - (or transient--suffixes - transient-current-suffixes)))) - (or (and (cdr suffixes) - (cl-find-if - (lambda (obj) - (equal (listify-key-sequence (transient--kbd (oref obj key))) - (listify-key-sequence (this-command-keys)))) - suffixes)) - (car suffixes)))) - ((and-let* ((obj (transient--suffix-prototype (or command this-command))) - (obj (clone obj))) - (progn ; work around debbugs#31840 - (transient-init-scope obj) - (transient-init-value obj) - obj))))) - -(defun transient--suffix-prototype (command) - (or (get command 'transient--suffix) - (seq-some (lambda (cmd) (get cmd 'transient--suffix)) - (function-alias-p command)))) - -;;; Keymaps - -(defvar-keymap transient-base-map - :doc "Parent of other keymaps used by Transient. - -This is the parent keymap of all the keymaps that are used in -all transients: `transient-map' (which in turn is the parent -of the transient-specific keymaps), `transient-edit-map' and -`transient-sticky-map'. - -If you change a binding here, then you might also have to edit -`transient-sticky-map' and `transient-common-commands'. While -the latter isn't a proper transient prefix command, it can be -edited using the same functions as used for transients. - -If you add a new command here, then you must also add a binding -to `transient-predicate-map'." - "ESC ESC ESC" #'transient-quit-all - "C-g" #'transient-quit-one - "C-q" #'transient-quit-all - "C-z" #'transient-suspend - "C-v" #'transient-scroll-up - "C-M-v" #'transient-scroll-down - "<next>" #'transient-scroll-up - "<prior>" #'transient-scroll-down) - -(defvar-keymap transient-map - :doc "Top-level keymap used by all transients. - -If you add a new command here, then you must also add a binding -to `transient-predicate-map'. Also see `transient-base-map'." - :parent transient-base-map - "C-u" #'universal-argument - "C--" #'negative-argument - "C-t" #'transient-show - "?" #'transient-help - "C-h" #'transient-help - ;; Also bound to "C-x p" and "C-x n" in transient-common-commands. - "C-M-p" #'transient-history-prev - "C-M-n" #'transient-history-next) - -(defvar-keymap transient-edit-map - :doc "Keymap that is active while a transient in is in \"edit mode\"." - :parent transient-base-map - "?" #'transient-help - "C-h" #'transient-help - "C-x l" #'transient-set-level) - -(defvar-keymap transient-sticky-map - :doc "Keymap that is active while an incomplete key sequence is active." - :parent transient-base-map - "C-g" #'transient-quit-seq) - -(defvar transient--common-command-prefixes '(?\C-x)) - -(put 'transient-common-commands - 'transient--layout - (list - (eval - (car (transient--parse-child - 'transient-common-commands - (vector - :hide - (lambda () - (and (not (memq - (car (bound-and-true-p transient--redisplay-key)) - transient--common-command-prefixes)) - (not transient-show-common-commands))) - (vector - "Value commands" - (list "C-x s " "Set" #'transient-set) - (list "C-x C-s" "Save" #'transient-save) - (list "C-x C-k" "Reset" #'transient-reset) - (list "C-x p " "Previous value" #'transient-history-prev) - (list "C-x n " "Next value" #'transient-history-next)) - (vector - "Sticky commands" - ;; Like `transient-sticky-map' except that - ;; "C-g" has to be bound to a different command. - (list "C-g" "Quit prefix or transient" #'transient-quit-one) - (list "C-q" "Quit transient stack" #'transient-quit-all) - (list "C-z" "Suspend transient stack" #'transient-suspend)) - (vector - "Customize" - (list "C-x t" 'transient-toggle-common :description - (lambda () - (if transient-show-common-commands - "Hide common commands" - "Show common permanently"))) - (list "C-x l" "Show/hide suffixes" #'transient-set-level) - (list "C-x a" #'transient-toggle-level-limit))))) - t))) - -(defvar-keymap transient-popup-navigation-map - :doc "One of the keymaps used when popup navigation is enabled. -See `transient-enable-popup-navigation'." - "<down-mouse-1>" #'transient-noop - "<up>" #'transient-backward-button - "<down>" #'transient-forward-button - "C-r" #'transient-isearch-backward - "C-s" #'transient-isearch-forward - "M-RET" #'transient-push-button) - -(defvar-keymap transient-button-map - :doc "One of the keymaps used when popup navigation is enabled. -See `transient-enable-popup-navigation'." - "<mouse-1>" #'transient-push-button - "<mouse-2>" #'transient-push-button) - -(defvar-keymap transient-resume-mode-map - :doc "Keymap for `transient-resume-mode'. - -This keymap remaps every command that would usually just quit the -documentation buffer to `transient-resume', which additionally -resumes the suspended transient." - "<remap> <Man-quit>" #'transient-resume - "<remap> <Info-exit>" #'transient-resume - "<remap> <quit-window>" #'transient-resume) - -(defvar-keymap transient-predicate-map - :doc "Base keymap used to map common commands to their transient behavior. - -The \"transient behavior\" of a command controls, among other -things, whether invoking the command causes the transient to be -exited or not, and whether infix arguments are exported before -doing so. - -Each \"key\" is a command that is common to all transients and -that is bound in `transient-map', `transient-edit-map', -`transient-sticky-map' and/or `transient-common-command'. - -Each binding is a \"pre-command\", a function that controls the -transient behavior of the respective command. - -For transient commands that are bound in individual transients, -the transient behavior is specified using the `:transient' slot -of the corresponding object." - "<transient-suspend>" #'transient--do-suspend - "<transient-help>" #'transient--do-stay - "<transient-set-level>" #'transient--do-stay - "<transient-history-prev>" #'transient--do-stay - "<transient-history-next>" #'transient--do-stay - "<universal-argument>" #'transient--do-stay - "<universal-argument-more>" #'transient--do-stay - "<negative-argument>" #'transient--do-minus - "<digit-argument>" #'transient--do-stay - "<top-level>" #'transient--do-quit-all - "<transient-quit-all>" #'transient--do-quit-all - "<transient-quit-one>" #'transient--do-quit-one - "<transient-quit-seq>" #'transient--do-stay - "<transient-show>" #'transient--do-stay - "<transient-update>" #'transient--do-stay - "<transient-toggle-common>" #'transient--do-stay - "<transient-set>" #'transient--do-call - "<transient-set-and-exit>" #'transient--do-exit - "<transient-save>" #'transient--do-call - "<transient-save-and-exit>" #'transient--do-exit - "<transient-reset>" #'transient--do-call - "<describe-key-briefly>" #'transient--do-stay - "<describe-key>" #'transient--do-stay - "<transient-scroll-up>" #'transient--do-stay - "<transient-scroll-down>" #'transient--do-stay - "<mwheel-scroll>" #'transient--do-stay - "<scroll-bar-toolkit-scroll>" #'transient--do-stay - "<transient-noop>" #'transient--do-noop - "<transient-mouse-push-button>" #'transient--do-move - "<transient-push-button>" #'transient--do-push-button - "<transient-backward-button>" #'transient--do-move - "<transient-forward-button>" #'transient--do-move - "<transient-isearch-backward>" #'transient--do-move - "<transient-isearch-forward>" #'transient--do-move - ;; If a valid but incomplete prefix sequence is followed by - ;; an unbound key, then Emacs calls the `undefined' command - ;; but does not set `this-command', `this-original-command' - ;; or `real-this-command' accordingly. Instead they are nil. - "<nil>" #'transient--do-warn - ;; Bound to the `mouse-movement' event, this command is similar - ;; to `ignore'. - "<ignore-preserving-kill-region>" #'transient--do-noop) - -(defvar transient--transient-map nil) -(defvar transient--predicate-map nil) -(defvar transient--redisplay-map nil) -(defvar transient--redisplay-key nil) - -(defun transient--push-keymap (var) - (let ((map (symbol-value var))) - (transient--debug " push %s%s" var (if map "" " VOID")) - (when map - (with-demoted-errors "transient--push-keymap: %S" - (internal-push-keymap map 'overriding-terminal-local-map))))) - -(defun transient--pop-keymap (var) - (let ((map (symbol-value var))) - (when map - (transient--debug " pop %s" var) - (with-demoted-errors "transient--pop-keymap: %S" - (internal-pop-keymap map 'overriding-terminal-local-map))))) - -(defun transient--make-transient-map () - (let ((map (make-sparse-keymap))) - (set-keymap-parent map (if transient--editp - transient-edit-map - transient-map)) - (dolist (obj transient--suffixes) - (let ((key (oref obj key))) - (when (vectorp key) - (setq key (key-description key)) - (oset obj key key)) - (when transient-substitute-key-function - (setq key (save-match-data - (funcall transient-substitute-key-function obj))) - (oset obj key key)) - (let* ((kbd (kbd key)) - (cmd (oref obj command)) - (alt (transient--lookup-key map kbd))) - (cond ((not alt) - (define-key map kbd cmd)) - ((eq alt cmd)) - ((transient--inapt-suffix-p obj)) - ((and-let* ((obj (transient-suffix-object alt))) - (transient--inapt-suffix-p obj)) - (define-key map kbd cmd)) - (transient-detect-key-conflicts - (error "Cannot bind %S to %s and also %s" - (string-trim key) cmd alt)) - ((define-key map kbd cmd)))))) - (when-let ((b (keymap-lookup map "-"))) (keymap-set map "<kp-subtract>" b)) - (when-let ((b (keymap-lookup map "="))) (keymap-set map "<kp-equal>" b)) - (when-let ((b (keymap-lookup map "+"))) (keymap-set map "<kp-add>" b)) - (when transient-enable-popup-navigation - ;; `transient--make-redisplay-map' maps only over bindings that are - ;; directly in the base keymap, so that cannot be a composed keymap. - (set-keymap-parent - map (make-composed-keymap - (keymap-parent map) - transient-popup-navigation-map))) - map)) - -(defun transient--make-predicate-map () - (let* ((default (transient--resolve-pre-command - (oref transient--prefix transient-suffix))) - (return (and transient--stack (eq default t))) - (map (make-sparse-keymap))) - (set-keymap-parent map transient-predicate-map) - (when (or (and (slot-boundp transient--prefix 'transient-switch-frame) - (transient--resolve-pre-command - (not (oref transient--prefix transient-switch-frame)))) - (memq (transient--resolve-pre-command - (oref transient--prefix transient-non-suffix)) - '(nil transient--do-warn transient--do-noop))) - (define-key map [handle-switch-frame] #'transient--do-suspend)) - (dolist (obj transient--suffixes) - (let* ((cmd (oref obj command)) - (kind (cond ((get cmd 'transient--prefix) 'prefix) - ((cl-typep obj 'transient-infix) 'infix) - (t 'suffix)))) - (cond - ((oref obj inapt) - (define-key map (vector cmd) #'transient--do-warn-inapt)) - ((slot-boundp obj 'transient) - (define-key map (vector cmd) - (pcase (list kind - (transient--resolve-pre-command (oref obj transient)) - return) - (`(prefix t ,_) #'transient--do-recurse) - (`(prefix nil ,_) #'transient--do-stack) - (`(infix t ,_) #'transient--do-stay) - (`(suffix t ,_) #'transient--do-call) - ('(suffix nil t) #'transient--do-return) - (`(,_ nil ,_) #'transient--do-exit) - (`(,_ ,do ,_) do)))) - ((not (lookup-key transient-predicate-map (vector cmd))) - (define-key map (vector cmd) - (pcase (list kind default return) - (`(prefix ,(or 'transient--do-stay 'transient--do-call) ,_) - #'transient--do-recurse) - (`(prefix t ,_) #'transient--do-recurse) - (`(prefix ,_ ,_) #'transient--do-stack) - (`(infix ,_ ,_) #'transient--do-stay) - (`(suffix t ,_) #'transient--do-call) - ('(suffix nil t) #'transient--do-return) - (`(suffix nil ,_) #'transient--do-exit) - (`(suffix ,do ,_) do))))))) - map)) - -(defun transient--make-redisplay-map () - (setq transient--redisplay-key - (pcase this-command - ('transient-update - (setq transient--showp t) - (setq unread-command-events - (listify-key-sequence (this-single-command-raw-keys)))) - ('transient-quit-seq - (setq unread-command-events - (butlast (listify-key-sequence - (this-single-command-raw-keys)) - 2)) - (butlast transient--redisplay-key)) - (_ nil))) - (let ((topmap (make-sparse-keymap)) - (submap (make-sparse-keymap))) - (when transient--redisplay-key - (define-key topmap (vconcat transient--redisplay-key) submap) - (set-keymap-parent submap transient-sticky-map)) - (map-keymap-internal - (lambda (key def) - (when (and (not (eq key ?\e)) - (listp def) - (keymapp def)) - (define-key topmap (vconcat transient--redisplay-key (list key)) - #'transient-update))) - (if transient--redisplay-key - (let ((key (vconcat transient--redisplay-key))) - (or (lookup-key transient--transient-map key) - (and-let* ((regular (lookup-key local-function-key-map key))) - (lookup-key transient--transient-map (vconcat regular))))) - transient--transient-map)) - topmap)) - -;;; Setup - -(defun transient-setup (&optional name layout edit &rest params) - "Setup the transient specified by NAME. - -This function is called by transient prefix commands to setup the -transient. In that case NAME is mandatory, LAYOUT and EDIT must -be nil and PARAMS may be (but usually is not) used to set, e.g., -the \"scope\" of the transient (see `transient-define-prefix'). - -This function is also called internally, in which case LAYOUT and -EDIT may be non-nil." - (transient--debug 'setup) - (transient--with-emergency-exit :setup - (cond - ((not name) - ;; Switching between regular and edit mode. - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (setq name (oref transient--prefix command)) - (setq params (list :scope (oref transient--prefix scope)))) - (transient--prefix - ;; Invoked as a ":transient-non-suffix 'transient--do-{stay,call}" - ;; of an outer prefix. Unlike the usual `transient--do-stack', - ;; these predicates fail to clean up after the outer prefix. - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map)) - ((not (or layout ; resuming parent/suspended prefix - transient-current-command)) ; entering child prefix - (transient--stack-zap)) ; replace suspended prefix, if any - (edit - ;; Returning from help to edit. - (setq transient--editp t))) - (transient--init-objects name layout params) - (transient--init-keymaps) - (transient--history-init transient--prefix) - (setq transient--original-window (selected-window)) - (setq transient--original-buffer (current-buffer)) - (setq transient--minibuffer-depth (minibuffer-depth)) - (transient--redisplay) - (transient--init-transient) - (transient--suspend-which-key-mode))) - -(cl-defgeneric transient-setup-children (group children) - "Setup the CHILDREN of GROUP. -If the value of the `setup-children' slot is non-nil, then call -that function with CHILDREN as the only argument and return the -value. Otherwise return CHILDREN as is." - (if (slot-boundp group 'setup-children) - (funcall (oref group setup-children) children) - children)) - -(defun transient--init-keymaps () - (setq transient--predicate-map (transient--make-predicate-map)) - (setq transient--transient-map (transient--make-transient-map)) - (setq transient--redisplay-map (transient--make-redisplay-map))) - -(defun transient--init-objects (&optional name layout params) - (if name - (setq transient--prefix (transient--init-prefix name params)) - (setq name (oref transient--prefix command))) - (setq transient--refreshp (oref transient--prefix refresh-suffixes)) - (setq transient--layout (or layout (transient--init-suffixes name))) - (setq transient--suffixes (transient--flatten-suffixes transient--layout))) - -(defun transient--init-prefix (name &optional params) - (let ((obj (let ((proto (get name 'transient--prefix))) - (apply #'clone proto - :prototype proto - :level (or (alist-get t (alist-get name transient-levels)) - transient-default-level) - params)))) - (transient--setup-recursion obj) - (transient-init-value obj) - obj)) - -(defun transient--init-suffixes (name) - (let ((levels (alist-get name transient-levels))) - (cl-mapcan (lambda (c) (transient--init-child levels c nil)) - (append (get name 'transient--layout) - (and (not transient--editp) - (get 'transient-common-commands - 'transient--layout)))))) - -(defun transient--flatten-suffixes (layout) - (cl-labels ((s (def) - (cond - ((stringp def) nil) - ((cl-typep def 'transient-information) nil) - ((listp def) (cl-mapcan #'s def)) - ((cl-typep def 'transient-group) - (cl-mapcan #'s (oref def suffixes))) - ((cl-typep def 'transient-suffix) - (list def))))) - (cl-mapcan #'s layout))) - -(defun transient--init-child (levels spec parent) - (cl-etypecase spec - (vector (transient--init-group levels spec parent)) - (list (transient--init-suffix levels spec parent)) - (string (list spec)))) - -(defun transient--init-group (levels spec parent) - (pcase-let ((`(,level ,class ,args ,children) (append spec nil))) - (and-let* (((transient--use-level-p level)) - (obj (apply class :level level args)) - ((transient--use-suffix-p obj)) - ((prog1 t - (when (or (and parent (oref parent inapt)) - (transient--inapt-suffix-p obj)) - (oset obj inapt t)))) - (suffixes (cl-mapcan - (lambda (c) (transient--init-child levels c obj)) - (transient-setup-children obj children)))) - (progn ; work around debbugs#31840 - (oset obj suffixes suffixes) - (list obj))))) - -(defun transient--init-suffix (levels spec parent) - (pcase-let* ((`(,level ,class ,args) spec) - (cmd (plist-get args :command)) - (key (transient--kbd (plist-get args :key))) - (level (or (alist-get (cons cmd key) levels nil nil #'equal) - (alist-get cmd levels) - level))) - (let ((fn (and (symbolp cmd) - (symbol-function cmd)))) - (when (autoloadp fn) - (transient--debug " autoload %s" cmd) - (autoload-do-load fn))) - (when (transient--use-level-p level) - (let ((obj (if (child-of-class-p class 'transient-information) - (apply class :level level args) - (unless (and cmd (symbolp cmd)) - (error "BUG: Non-symbolic suffix command: %s" cmd)) - (if-let ((proto (and cmd (transient--suffix-prototype cmd)))) - (apply #'clone proto :level level args) - (apply class :command cmd :level level args))))) - (cond ((not cmd)) - ((commandp cmd)) - ((or (cl-typep obj 'transient-switch) - (cl-typep obj 'transient-option)) - ;; As a temporary special case, if the package was compiled - ;; with an older version of Transient, then we must define - ;; "anonymous" switch and option commands here. - (defalias cmd #'transient--default-infix-command)) - ((transient--use-suffix-p obj) - (error "Suffix command %s is not defined or autoloaded" cmd))) - (unless (cl-typep obj 'transient-information) - (transient--init-suffix-key obj)) - (when (transient--use-suffix-p obj) - (if (or (and parent (oref parent inapt)) - (transient--inapt-suffix-p obj)) - (oset obj inapt t) - (transient-init-scope obj) - (transient-init-value obj)) - (list obj)))))) - -(cl-defmethod transient--init-suffix-key ((obj transient-suffix)) - (unless (slot-boundp obj 'key) - (error "No key for %s" (oref obj command)))) - -(cl-defmethod transient--init-suffix-key ((obj transient-argument)) - (if (transient-switches--eieio-childp obj) - (cl-call-next-method obj) - (unless (slot-boundp obj 'shortarg) - (when-let ((shortarg (transient--derive-shortarg (oref obj argument)))) - (oset obj shortarg shortarg))) - (unless (slot-boundp obj 'key) - (if (slot-boundp obj 'shortarg) - (oset obj key (oref obj shortarg)) - (error "No key for %s" (oref obj command)))))) - -(defun transient--use-level-p (level &optional edit) - (or transient--all-levels-p - (and transient--editp (not edit)) - (and (>= level 1) - (<= level (oref transient--prefix level))))) - -(defun transient--use-suffix-p (obj) - (let ((transient--shadowed-buffer (current-buffer)) - (transient--pending-suffix obj)) - (transient--do-suffix-p - (oref obj if) - (oref obj if-not) - (oref obj if-nil) - (oref obj if-non-nil) - (oref obj if-mode) - (oref obj if-not-mode) - (oref obj if-derived) - (oref obj if-not-derived) - t))) - -(defun transient--inapt-suffix-p (obj) - (let ((transient--shadowed-buffer (current-buffer)) - (transient--pending-suffix obj)) - (transient--do-suffix-p - (oref obj inapt-if) - (oref obj inapt-if-not) - (oref obj inapt-if-nil) - (oref obj inapt-if-non-nil) - (oref obj inapt-if-mode) - (oref obj inapt-if-not-mode) - (oref obj inapt-if-derived) - (oref obj inapt-if-not-derived) - nil))) - -(defun transient--do-suffix-p - (if if-not if-nil if-non-nil if-mode if-not-mode if-derived if-not-derived - default) - (cond - (if (funcall if)) - (if-not (not (funcall if-not))) - (if-non-nil (symbol-value if-non-nil)) - (if-nil (not (symbol-value if-nil))) - (if-mode (if (atom if-mode) - (eq major-mode if-mode) - (memq major-mode if-mode))) - (if-not-mode (not (if (atom if-not-mode) - (eq major-mode if-not-mode) - (memq major-mode if-not-mode)))) - (if-derived (if (or (atom if-derived) - (>= emacs-major-version 30)) - (derived-mode-p if-derived) - (apply #'derived-mode-p if-derived))) - (if-not-derived (not (if (or (atom if-not-derived) - (>= emacs-major-version 30)) - (derived-mode-p if-not-derived) - (apply #'derived-mode-p if-not-derived)))) - (default))) - -(defun transient--suffix-predicate (spec) - (let ((plist (nth 2 spec))) - (seq-some (lambda (prop) - (and-let* ((pred (plist-get plist prop))) - (list prop pred))) - '( :if :if-not - :if-nil :if-non-nil - :if-mode :if-not-mode - :if-derived :if-not-derived - :inapt-if :inapt-if-not - :inapt-if-nil :inapt-if-non-nil - :inapt-if-mode :inapt-if-not-mode - :inapt-if-derived :inapt-if-not-derived)))) - -;;; Flow-Control - -(defun transient--init-transient () - (transient--debug 'init-transient) - (transient--push-keymap 'transient--transient-map) - (transient--push-keymap 'transient--redisplay-map) - (add-hook 'pre-command-hook #'transient--pre-command) - (add-hook 'post-command-hook #'transient--post-command) - (advice-add 'recursive-edit :around #'transient--recursive-edit) - (when transient--exitp - ;; This prefix command was invoked as the suffix of another. - ;; Prevent `transient--post-command' from removing the hooks - ;; that we just added. - (setq transient--exitp 'replace))) - -(defun transient--refresh-transient () - (transient--debug 'refresh-transient) - (transient--pop-keymap 'transient--predicate-map) - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (if (eq transient--refreshp 'updated-value) - ;; Preserve the prefix value this once, because the - ;; invoked suffix indicates that it has updated that. - (setq transient--refreshp (oref transient--prefix refresh-suffixes)) - ;; Otherwise update the prefix value from suffix values. - (oset transient--prefix value (transient-get-value))) - (transient--init-objects) - (transient--init-keymaps) - (transient--push-keymap 'transient--transient-map) - (transient--push-keymap 'transient--redisplay-map) - (transient--redisplay)) - -(defun transient--pre-command () - (transient--debug 'pre-command) - (transient--with-emergency-exit :pre-command - ;; The use of `overriding-terminal-local-map' does not prevent the - ;; lookup of command remappings in the overridden maps, which can - ;; lead to a suffix being remapped to a non-suffix. We have to undo - ;; the remapping in that case. However, remapping a non-suffix to - ;; another should remain possible. - (when (and (transient--get-pre-command this-original-command 'suffix) - (not (transient--get-pre-command this-command 'suffix))) - (setq this-command this-original-command)) - (cond - ((memq this-command '(transient-update transient-quit-seq)) - (transient--pop-keymap 'transient--redisplay-map)) - ((and transient--helpp - (not (memq this-command '(transient-quit-one - transient-quit-all)))) - (cond - ((transient-help) - (transient--do-suspend) - (setq this-command 'transient-suspend) - (transient--pre-exit)) - ((not (transient--edebug-command-p)) - (setq this-command 'transient-undefined)))) - ((and transient--editp - (transient-suffix-object) - (not (memq this-command '(transient-quit-one - transient-quit-all - transient-help)))) - (setq this-command 'transient-set-level) - (transient--wrap-command)) - (t - (setq transient--exitp nil) - (let ((exitp (eq (transient--call-pre-command) transient--exit))) - (transient--wrap-command) - (when exitp - (transient--pre-exit))))))) - -(defun transient--pre-exit () - (transient--debug 'pre-exit) - (transient--delete-window) - (transient--timer-cancel) - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (unless transient--showp - (let ((message-log-max nil)) - (message ""))) - (setq transient--transient-map nil) - (setq transient--predicate-map nil) - (setq transient--redisplay-map nil) - (setq transient--redisplay-key nil) - (setq transient--helpp nil) - (setq transient--editp nil) - (setq transient--prefix nil) - (setq transient--layout nil) - (setq transient--suffixes nil) - (setq transient--original-window nil) - (setq transient--original-buffer nil) - (setq transient--window nil)) - -(defun transient--delete-window () - (when (window-live-p transient--window) - (let ((remain-in-minibuffer-window - (and (minibuffer-selected-window) - (selected-window)))) - ;; Only delete the window if it has never shown another buffer. - (unless (eq (car (window-parameter transient--window 'quit-restore)) - 'other) - (with-demoted-errors "Error while exiting transient: %S" - (delete-window transient--window))) - (when (buffer-live-p transient--buffer) - (kill-buffer transient--buffer)) - (setq transient--buffer nil) - (when remain-in-minibuffer-window - (select-window remain-in-minibuffer-window))))) - -(defun transient--export () - (setq transient-current-prefix transient--prefix) - (setq transient-current-command (oref transient--prefix command)) - (setq transient-current-suffixes transient--suffixes) - (transient--history-push transient--prefix)) - -(defun transient--suspend-override (&optional nohide) - (transient--debug 'suspend-override) - (transient--timer-cancel) - (cond ((and (not nohide) transient-hide-during-minibuffer-read) - (transient--delete-window)) - ((and transient--prefix transient--redisplay-key) - (setq transient--redisplay-key nil) - (when transient--showp - (if-let ((win (minibuffer-selected-window))) - (with-selected-window win - (transient--show)) - (transient--show))))) - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (remove-hook 'pre-command-hook #'transient--pre-command) - (remove-hook 'post-command-hook #'transient--post-command)) - -(defun transient--resume-override (&optional _ignore) - (transient--debug 'resume-override) - (when (and transient--showp transient-hide-during-minibuffer-read) - (transient--show)) - (transient--push-keymap 'transient--transient-map) - (transient--push-keymap 'transient--redisplay-map) - (add-hook 'pre-command-hook #'transient--pre-command) - (add-hook 'post-command-hook #'transient--post-command)) - -(defun transient--recursive-edit (fn) - (transient--debug 'recursive-edit) - (if (not transient--prefix) - (funcall fn) - (transient--suspend-override (bound-and-true-p edebug-active)) - (funcall fn) ; Already unwind protected. - (cond ((memq this-command '(top-level abort-recursive-edit)) - (setq transient--exitp t) - (transient--post-exit) - (transient--delete-window)) - (transient--prefix - (transient--resume-override))))) - -(defmacro transient--with-suspended-override (&rest body) - (let ((depth (make-symbol "depth")) - (setup (make-symbol "setup")) - (exit (make-symbol "exit"))) - `(if (and transient--transient-map - (memq transient--transient-map - overriding-terminal-local-map)) - (let ((,depth (1+ (minibuffer-depth))) ,setup ,exit) - (setq ,setup - (lambda () "@transient--with-suspended-override" - (transient--debug 'minibuffer-setup) - (remove-hook 'minibuffer-setup-hook ,setup) - (transient--suspend-override))) - (setq ,exit - (lambda () "@transient--with-suspended-override" - (transient--debug 'minibuffer-exit) - (when (= (minibuffer-depth) ,depth) - (transient--resume-override)))) - (unwind-protect - (progn - (add-hook 'minibuffer-setup-hook ,setup) - (add-hook 'minibuffer-exit-hook ,exit) - ,@body) - (remove-hook 'minibuffer-setup-hook ,setup) - (remove-hook 'minibuffer-exit-hook ,exit))) - ,@body))) - -(static-if (>= emacs-major-version 30) ;transient--wrap-command - (defun transient--wrap-command () - (cl-assert - (>= emacs-major-version 30) nil - "Emacs was downgraded, making it necessary to recompile Transient") - (letrec - ((prefix transient--prefix) - (suffix this-command) - (advice - (lambda (fn &rest args) - (interactive - (lambda (spec) - (let ((abort t)) - (unwind-protect - (prog1 (let ((debugger #'transient--exit-and-debug)) - (advice-eval-interactive-spec spec)) - (setq abort nil)) - (when abort - (when-let ((unwind (oref prefix unwind-suffix))) - (transient--debug 'unwind-interactive) - (funcall unwind suffix)) - (advice-remove suffix advice) - (oset prefix unwind-suffix nil)))))) - (unwind-protect - (let ((debugger #'transient--exit-and-debug)) - (apply fn args)) - (when-let ((unwind (oref prefix unwind-suffix))) - (transient--debug 'unwind-command) - (funcall unwind suffix)) - (advice-remove suffix advice) - (oset prefix unwind-suffix nil))))) - (when (symbolp this-command) - (advice-add suffix :around advice '((depth . -99)))))) - - (defun transient--wrap-command () - (let* ((prefix transient--prefix) - (suffix this-command) - (advice nil) - (advice-interactive - (lambda (spec) - (let ((abort t)) - (unwind-protect - (prog1 (let ((debugger #'transient--exit-and-debug)) - (advice-eval-interactive-spec spec)) - (setq abort nil)) - (when abort - (when-let ((unwind (oref prefix unwind-suffix))) - (transient--debug 'unwind-interactive) - (funcall unwind suffix)) - (advice-remove suffix advice) - (oset prefix unwind-suffix nil)))))) - (advice-body - (lambda (fn &rest args) - (unwind-protect - (let ((debugger #'transient--exit-and-debug)) - (apply fn args)) - (when-let ((unwind (oref prefix unwind-suffix))) - (transient--debug 'unwind-command) - (funcall unwind suffix)) - (advice-remove suffix advice) - (oset prefix unwind-suffix nil))))) - (setq advice `(lambda (fn &rest args) - (interactive ,advice-interactive) - (apply ',advice-body fn args))) - (when (symbolp this-command) - (advice-add suffix :around advice '((depth . -99))))))) - -(defun transient--premature-post-command () - (and (equal (this-command-keys-vector) []) - (= (minibuffer-depth) - (1+ transient--minibuffer-depth)) - (progn - (transient--debug 'premature-post-command) - (transient--suspend-override) - (oset (or transient--prefix transient-current-prefix) - unwind-suffix - (if transient--exitp - #'transient--post-exit - #'transient--resume-override)) - t))) - -(defun transient--post-command () - (unless (transient--premature-post-command) - (transient--debug 'post-command) - (transient--with-emergency-exit :post-command - (cond (transient--exitp (transient--post-exit)) - ;; If `this-command' is the current transient prefix, then we - ;; have already taken care of updating the transient buffer... - ((and (eq this-command (oref transient--prefix command)) - ;; ... but if `prefix-arg' is non-nil, then the values - ;; of `this-command' and `real-this-command' are untrue - ;; because `prefix-command-preserve-state' changes them. - ;; We cannot use `current-prefix-arg' because it is set - ;; too late (in `command-execute'), and if it were set - ;; earlier, then we likely still would not be able to - ;; rely on it, and `prefix-command-preserve-state-hook' - ;; would have to be used to record that a universal - ;; argument is in effect. - (not prefix-arg))) - (transient--refreshp - (transient--refresh-transient)) - ((let ((old transient--redisplay-map) - (new (transient--make-redisplay-map))) - (unless (equal old new) - (transient--pop-keymap 'transient--redisplay-map) - (setq transient--redisplay-map new) - (transient--push-keymap 'transient--redisplay-map)) - (transient--redisplay))))) - (setq transient-current-prefix nil) - (setq transient-current-command nil) - (setq transient-current-suffixes nil))) - -(defun transient--post-exit (&optional command) - (transient--debug 'post-exit) - (unless (and (eq transient--exitp 'replace) - (or transient--prefix - ;; The current command could act as a prefix, - ;; but decided not to call `transient-setup', - ;; or it is prevented from doing so because it - ;; uses the minibuffer and the user aborted - ;; that. - (prog1 nil - (if (let ((obj (transient-suffix-object command))) - (and (slot-boundp obj 'transient) - (oref obj transient))) - ;; This sub-prefix is a transient suffix; - ;; go back to outer prefix, by calling - ;; `transient--stack-pop' further down. - (setq transient--exitp nil) - (transient--stack-zap))))) - (remove-hook 'pre-command-hook #'transient--pre-command) - (remove-hook 'post-command-hook #'transient--post-command) - (advice-remove 'recursive-edit #'transient--recursive-edit)) - (let ((resume (and transient--stack - (not (memq transient--exitp '(replace suspend)))))) - (unless (or resume (eq transient--exitp 'replace)) - (setq transient--showp nil)) - (setq transient--exitp nil) - (setq transient--helpp nil) - (setq transient--editp nil) - (setq transient--all-levels-p nil) - (setq transient--minibuffer-depth 0) - (run-hooks 'transient-exit-hook) - (when resume - (transient--stack-pop)))) - -(defun transient--stack-push () - (transient--debug 'stack-push) - (push (list (oref transient--prefix command) - transient--layout - transient--editp - :transient-suffix (oref transient--prefix transient-suffix) - :scope (oref transient--prefix scope)) - transient--stack)) - -(defun transient--stack-pop () - (transient--debug 'stack-pop) - (and transient--stack - (prog1 t (apply #'transient-setup (pop transient--stack))))) - -(defun transient--stack-zap () - (transient--debug 'stack-zap) - (setq transient--stack nil)) - -(defun transient--redisplay () - (if (or (eq transient-show-popup t) - transient--showp) - (unless - (or (memq this-command transient--scroll-commands) - (and (or (memq this-command '(mouse-drag-region - mouse-set-region)) - (equal (key-description (this-command-keys-vector)) - "<mouse-movement>")) - (and (eq (current-buffer) transient--buffer)))) - (transient--show)) - (when (and (numberp transient-show-popup) - (not (zerop transient-show-popup)) - (not transient--timer)) - (transient--timer-start)) - (transient--show-brief))) - -(defun transient--timer-start () - (setq transient--timer - (run-at-time (abs transient-show-popup) nil - (lambda () - (transient--timer-cancel) - (transient--show) - (let ((message-log-max nil)) - (message "")))))) - -(defun transient--timer-cancel () - (when transient--timer - (cancel-timer transient--timer) - (setq transient--timer nil))) - -(defun transient--debug (arg &rest args) - (when transient--debug - (let ((inhibit-message (not (eq transient--debug 'message)))) - (if (symbolp arg) - (message "-- %-22s (cmd: %s, event: %S, exit: %s%s)" - arg - (cond ((and (symbolp this-command) this-command)) - ((fboundp 'help-fns-function-name) - (help-fns-function-name this-command)) - ((byte-code-function-p this-command) - "#[...]") - (this-command)) - (key-description (this-command-keys-vector)) - transient--exitp - (cond ((keywordp (car args)) - (format ", from: %s" - (substring (symbol-name (car args)) 1))) - ((stringp (car args)) - (concat ", " (apply #'format args))) - ((functionp (car args)) - (concat ", " (apply (car args) (cdr args)))) - (""))) - (apply #'message arg args))))) - -(defun transient--emergency-exit (&optional id) - "Exit the current transient command after an error occurred. -When no transient is active (i.e., when `transient--prefix' is -nil) then do nothing. Optional ID is a keyword identifying the -exit." - (transient--debug 'emergency-exit id) - (when transient--prefix - (setq transient--stack nil) - (setq transient--exitp t) - (transient--pre-exit) - (transient--post-exit))) - -;;; Pre-Commands - -(defun transient--call-pre-command () - (if-let ((fn (transient--get-pre-command this-command))) - (let ((action (funcall fn))) - (when (eq action transient--exit) - (setq transient--exitp (or transient--exitp t))) - action) - (if (let ((keys (this-command-keys-vector))) - (eq (aref keys (1- (length keys))) ?\C-g)) - (setq this-command 'transient-noop) - (unless (transient--edebug-command-p) - (setq this-command 'transient-undefined))) - transient--stay)) - -(defun transient--get-pre-command (&optional cmd enforce-type) - (or (and (not (eq enforce-type 'non-suffix)) - (symbolp cmd) - (lookup-key transient--predicate-map (vector cmd))) - (and (not (eq enforce-type 'suffix)) - (transient--resolve-pre-command - (oref transient--prefix transient-non-suffix) - t)))) - -(defun transient--resolve-pre-command (pre &optional resolve-boolean) - (cond ((booleanp pre) - (if resolve-boolean - (if pre #'transient--do-stay #'transient--do-warn) - pre)) - ((string-match-p "--do-" (symbol-name pre)) pre) - ((let ((sym (intern (format "transient--do-%s" pre)))) - (if (functionp sym) sym pre))))) - -(defun transient--do-stay () - "Call the command without exporting variables and stay transient." - transient--stay) - -(defun transient--do-noop () - "Call `transient-noop' and stay transient." - (setq this-command 'transient-noop) - transient--stay) - -(defun transient--do-warn () - "Call `transient-undefined' and stay transient." - (setq this-command 'transient-undefined) - transient--stay) - -(defun transient--do-warn-inapt () - "Call `transient-inapt' and stay transient." - (setq this-command 'transient-inapt) - transient--stay) - -(defun transient--do-call () - "Call the command after exporting variables and stay transient." - (transient--export) - transient--stay) - -(defun transient--do-return () - "Call the command after exporting variables and return to parent prefix. -If there is no parent prefix, then behave like `transient--do-exit'." - (if (not transient--stack) - (transient--do-exit) - (transient--export) - transient--exit)) - -(defun transient--do-exit () - "Call the command after exporting variables and exit the transient." - (transient--export) - (transient--stack-zap) - transient--exit) - -(defun transient--do-leave () - "Call the command without exporting variables and exit the transient." - (transient--stack-zap) - transient--exit) - -(defun transient--do-push-button () - "Call the command represented by the activated button. -Use that command's pre-command to determine transient behavior." - (if (and (mouse-event-p last-command-event) - (not (eq (posn-window (event-start last-command-event)) - transient--window))) - transient--stay - (setq this-command - (with-selected-window transient--window - (get-text-property (if (mouse-event-p last-command-event) - (posn-point (event-start last-command-event)) - (point)) - 'command))) - (transient--call-pre-command))) - -(defun transient--do-recurse () - "Call the transient prefix command, preparing for return to active transient. -If there is no parent prefix, then just call the command." - (transient--do-stack)) - -(defun transient--setup-recursion (prefix-obj) - (when transient--stack - (let ((command (oref prefix-obj command))) - (when-let ((suffix-obj (transient-suffix-object command))) - (when (memq (if (slot-boundp suffix-obj 'transient) - (oref suffix-obj transient) - (oref transient-current-prefix transient-suffix)) - (list t #'transient--do-recurse)) - (oset prefix-obj transient-suffix t)))))) - -(defun transient--do-stack () - "Call the transient prefix command, stacking the active transient. -Push the active transient to the transient stack." - (transient--export) - (transient--stack-push) - (setq transient--exitp 'replace) - transient--exit) - -(defun transient--do-replace () - "Call the transient prefix command, replacing the active transient. -Do not push the active transient to the transient stack." - (transient--export) - (setq transient--exitp 'replace) - transient--exit) - -(defun transient--do-suspend () - "Suspend the active transient, saving the transient stack." - (transient--stack-push) - (setq transient--exitp 'suspend) - transient--exit) - -(defun transient--do-quit-one () - "If active, quit help or edit mode, else exit the active transient." - (cond (transient--helpp - (setq transient--helpp nil) - transient--stay) - (transient--editp - (setq transient--editp nil) - (transient-setup) - transient--stay) - (prefix-arg - transient--stay) - (transient--exit))) - -(defun transient--do-quit-all () - "Exit all transients without saving the transient stack." - (transient--stack-zap) - transient--exit) - -(defun transient--do-move () - "Call the command if `transient-enable-popup-navigation' is non-nil. -In that case behave like `transient--do-stay', otherwise similar -to `transient--do-warn'." - (unless transient-enable-popup-navigation - (setq this-command 'transient-inhibit-move)) - transient--stay) - -(defun transient--do-minus () - "Call `negative-argument' or pivot to `transient-update'. -If `negative-argument' is invoked using \"-\" then preserve the -prefix argument and pivot to `transient-update'." - (when (equal (this-command-keys) "-") - (setq this-command 'transient-update)) - transient--stay) - -(put 'transient--do-stay 'transient-face 'transient-key-stay) -(put 'transient--do-noop 'transient-face 'transient-key-noop) -(put 'transient--do-warn 'transient-face 'transient-key-noop) -(put 'transient--do-warn-inapt 'transient-face 'transient-key-noop) -(put 'transient--do-call 'transient-face 'transient-key-stay) -(put 'transient--do-return 'transient-face 'transient-key-return) -(put 'transient--do-exit 'transient-face 'transient-key-exit) -(put 'transient--do-leave 'transient-face 'transient-key-exit) - -(put 'transient--do-recurse 'transient-face 'transient-key-stay) -(put 'transient--do-stack 'transient-face 'transient-key-stay) -(put 'transient--do-replace 'transient-face 'transient-key-exit) -(put 'transient--do-suspend 'transient-face 'transient-key-exit) - -(put 'transient--do-quit-one 'transient-face 'transient-key-return) -(put 'transient--do-quit-all 'transient-face 'transient-key-exit) -(put 'transient--do-move 'transient-face 'transient-key-stay) -(put 'transient--do-minus 'transient-face 'transient-key-stay) - -;;; Commands -;;;; Noop - -(defun transient-noop () - "Do nothing at all." - (interactive)) - -(defun transient-undefined () - "Warn the user that the pressed key is not bound to any suffix." - (interactive) - (transient--invalid "Unbound suffix")) - -(defun transient-inapt () - "Warn the user that the invoked command is inapt." - (interactive) - (transient--invalid "Inapt command")) - -(defun transient--invalid (msg) - (ding) - (message "%s: `%s' (Use `%s' to abort, `%s' for help)%s" - msg - (propertize (key-description (this-single-command-keys)) - 'face 'font-lock-warning-face) - (propertize "C-g" 'face 'transient-key) - (propertize "?" 'face 'transient-key) - ;; `this-command' is `transient-undefined' or `transient-inapt'. - ;; Show the command (`this-original-command') the user actually - ;; tried to invoke. - (if-let ((cmd (or (ignore-errors (symbol-name this-original-command)) - (ignore-errors (symbol-name this-command))))) - (format " [%s]" (propertize cmd 'face 'font-lock-warning-face)) - "")) - (unless (and transient--transient-map - (memq transient--transient-map overriding-terminal-local-map)) - (let ((transient--prefix (or transient--prefix 'sic))) - (transient--emergency-exit)) - (view-lossage) - (other-window 1) - (display-warning 'transient "Inconsistent transient state detected. -This should never happen. -Please open an issue and post the shown command log." :error))) - -(defun transient-inhibit-move () - "Warn the user that popup navigation is disabled." - (interactive) - (message "To enable use of `%s', please customize `%s'" - this-original-command - 'transient-enable-popup-navigation)) - -;;;; Core - -(defun transient-quit-all () - "Exit all transients without saving the transient stack." - (interactive)) - -(defun transient-quit-one () - "Exit the current transients, returning to outer transient, if any." - (interactive)) - -(defun transient-quit-seq () - "Abort the current incomplete key sequence." - (interactive)) - -(defun transient-update () - "Redraw the transient's state in the popup buffer." - (interactive) - (setq prefix-arg current-prefix-arg)) - -(defun transient-show () - "Show the transient's state in the popup buffer." - (interactive) - (setq transient--showp t)) - -(defun transient-push-button () - "Invoke the suffix command represented by this button." - (interactive)) - -;;;; Suspend - -(defun transient-suspend () - "Suspend the current transient. -It can later be resumed using `transient-resume', while no other -transient is active." - (interactive)) - -(define-minor-mode transient-resume-mode - "Auxiliary minor-mode used to resume a transient after viewing help.") - -(defun transient-resume () - "Resume a previously suspended stack of transients." - (interactive) - (cond (transient--stack - (let ((winconf transient--restore-winconf)) - (kill-local-variable 'transient--restore-winconf) - (when transient-resume-mode - (transient-resume-mode -1) - (quit-window)) - (when winconf - (set-window-configuration winconf))) - (transient--stack-pop)) - (transient-resume-mode - (kill-local-variable 'transient--restore-winconf) - (transient-resume-mode -1) - (quit-window)) - (t - (message "No suspended transient command")))) - -;;;; Help - -(defun transient-help (&optional interactive) - "Show help for the active transient or one of its suffixes.\n\n(fn)" - (interactive (list t)) - (if interactive - (setq transient--helpp t) - (with-demoted-errors "transient-help: %S" - (when (lookup-key transient--transient-map - (this-single-command-raw-keys)) - (setq transient--helpp nil) - (let ((winconf (current-window-configuration))) - (transient-show-help - (if (eq this-original-command 'transient-help) - transient--prefix - (or (transient-suffix-object) - this-original-command))) - (setq-local transient--restore-winconf winconf)) - (fit-window-to-buffer nil (frame-height) (window-height)) - (transient-resume-mode) - (message (substitute-command-keys - "Type \\`q' to resume transient command.")) - t)))) - -;;;; Level - -(defun transient-set-level (&optional command level) - "Set the level of the transient or one of its suffix commands." - (interactive - (let ((command this-original-command) - (prefix (oref transient--prefix command))) - (and (or (not (eq command 'transient-set-level)) - (and transient--editp - (setq command prefix))) - (list command - (let ((keys (this-single-command-raw-keys))) - (and (lookup-key transient--transient-map keys) - (progn - (transient--show) - (string-to-number - (transient--read-number-N - (format "Set level for `%s': " command) - nil nil (not (eq command prefix))))))))))) - (cond - ((not command) - (setq transient--editp t) - (transient-setup)) - (level - (let* ((prefix (oref transient--prefix command)) - (alist (alist-get prefix transient-levels)) - (akey command)) - (cond ((eq command prefix) - (oset transient--prefix level level) - (setq akey t)) - (t - (oset (transient-suffix-object command) level level) - (when (cdr (cl-remove-if-not (lambda (obj) - (eq (oref obj command) command)) - transient--suffixes)) - (setq akey (cons command (this-command-keys)))))) - (setf (alist-get akey alist) level) - (setf (alist-get prefix transient-levels) alist)) - (transient-save-levels) - (transient--show)) - (t - (transient-undefined)))) - -(transient-define-suffix transient-toggle-level-limit () - "Toggle whether to temporarily displayed suffixes on all levels." - :description - (lambda () - (cond - ((= transient-default-level transient--max-level) - "Always displaying all levels") - (transient--all-levels-p - (format "Hide suffix %s" - (propertize - (format "levels > %s" (oref (transient-prefix-object) level)) - 'face 'transient-higher-level))) - ("Show all suffix levels"))) - :inapt-if (lambda () (= transient-default-level transient--max-level)) - :transient t - (interactive) - (setq transient--all-levels-p (not transient--all-levels-p)) - (setq transient--refreshp t)) - -;;;; Value - -(defun transient-set () - "Set active transient's value for this Emacs session." - (interactive) - (transient-set-value (transient-prefix-object))) - -(defalias 'transient-set-and-exit #'transient-set - "Set active transient's value for this Emacs session and exit.") - -(defun transient-save () - "Save active transient's value for this and future Emacs sessions." - (interactive) - (transient-save-value (transient-prefix-object))) - -(defalias 'transient-save-and-exit #'transient-save - "Save active transient's value for this and future Emacs sessions and exit.") - -(defun transient-reset () - "Clear the set and saved values of the active transient." - (interactive) - (transient-reset-value (transient-prefix-object))) - -(defun transient-history-next () - "Switch to the next value used for the active transient." - (interactive) - (let* ((obj transient--prefix) - (pos (1- (oref obj history-pos))) - (hst (oref obj history))) - (if (< pos 0) - (user-error "End of history") - (oset obj history-pos pos) - (oset obj value (nth pos hst)) - (mapc #'transient-init-value transient--suffixes)))) - -(defun transient-history-prev () - "Switch to the previous value used for the active transient." - (interactive) - (let* ((obj transient--prefix) - (pos (1+ (oref obj history-pos))) - (hst (oref obj history)) - (len (length hst))) - (if (> pos (1- len)) - (user-error "End of history") - (oset obj history-pos pos) - (oset obj value (nth pos hst)) - (mapc #'transient-init-value transient--suffixes)))) - -(transient-define-suffix transient-preset () - "Put this preset into action." - :class transient-value-preset - (interactive) - (transient-prefix-set (oref (transient-suffix-object) set))) - -;;;; Auxiliary - -(defun transient-toggle-common () - "Toggle whether common commands are permanently shown." - (interactive) - (setq transient-show-common-commands (not transient-show-common-commands))) - -(defun transient-toggle-debug () - "Toggle debugging statements for transient commands." - (interactive) - (setq transient--debug (not transient--debug)) - (message "Debugging transient %s" - (if transient--debug "enabled" "disabled"))) - -(transient-define-suffix transient-echo-arguments (arguments) - "Show the transient's active ARGUMENTS in the echo area. -Intended for use in prefixes used for demonstration purposes, -such as when suggesting a new feature or reporting an issue." - :transient t - :description "Echo arguments" - :key "x" - (interactive (list (transient-args transient-current-command))) - (message "%s: %s" - (key-description (this-command-keys)) - (mapconcat (lambda (arg) - (propertize (if (string-match-p " " arg) - (format "%S" arg) - arg) - 'face 'transient-argument)) - arguments " "))) - -;;; Value -;;;; Init - -(cl-defgeneric transient-init-scope (obj) - "Set the scope of the suffix object OBJ. - -The scope is actually a property of the transient prefix, not of -individual suffixes. However it is possible to invoke a suffix -command directly instead of from a transient. In that case, if -the suffix expects a scope, then it has to determine that itself -and store it in its `scope' slot. - -This function is called for all suffix commands, but unless a -concrete method is implemented this falls through to the default -implementation, which is a noop.") - -(cl-defmethod transient-init-scope ((_ transient-suffix)) - "Noop." nil) - -(cl-defgeneric transient-init-value (_) - "Set the initial value of the object OBJ. - -This function is called for all prefix and suffix commands. - -For suffix commands (including infix argument commands) the -default implementation is a noop. Classes derived from the -abstract `transient-infix' class must implement this function. -Non-infix suffix commands usually don't have a value." - nil) - -(cl-defmethod transient-init-value :around ((obj transient-prefix)) - "If bound, then call OBJ's `init-value' function. -Otherwise call the primary method according to object's class." - (if (slot-boundp obj 'init-value) - (funcall (oref obj init-value) obj) - (cl-call-next-method obj))) - -(cl-defmethod transient-init-value :around ((obj transient-infix)) - "If bound, then call OBJ's `init-value' function. -Otherwise call the primary method according to object's class." - (if (slot-boundp obj 'init-value) - (funcall (oref obj init-value) obj) - (cl-call-next-method obj))) - -(cl-defmethod transient-init-value ((obj transient-prefix)) - (if (slot-boundp obj 'value) - (oref obj value) - (oset obj value - (if-let ((saved (assq (oref obj command) transient-values))) - (cdr saved) - (transient-default-value obj))))) - -(cl-defmethod transient-init-value ((obj transient-argument)) - (oset obj value - (let ((value (oref transient--prefix value)) - (argument (and (slot-boundp obj 'argument) - (oref obj argument))) - (multi-value (oref obj multi-value)) - (case-fold-search nil) - (regexp (if (slot-exists-p obj 'argument-regexp) - (oref obj argument-regexp) - (format "\\`%s\\(.*\\)" (oref obj argument))))) - (if (memq multi-value '(t rest)) - (cdr (assoc argument value)) - (let ((match (lambda (v) - (and (stringp v) - (string-match regexp v) - (match-string 1 v))))) - (if multi-value - (delq nil (mapcar match value)) - (cl-some match value))))))) - -(cl-defmethod transient-init-value ((obj transient-switch)) - (oset obj value - (car (member (oref obj argument) - (oref transient--prefix value))))) - -;;;; Default - -(cl-defgeneric transient-default-value (_) - "Return the default value." - nil) - -(cl-defmethod transient-default-value ((obj transient-prefix)) - (if-let ((default (and (slot-boundp obj 'default-value) - (oref obj default-value)))) - (if (functionp default) - (funcall default) - default) - nil)) - -;;;; Read - -(cl-defgeneric transient-infix-read (obj) - "Determine the new value of the infix object OBJ. - -This function merely determines the value; `transient-infix-set' -is used to actually store the new value in the object. - -For most infix classes this is done by reading a value from the -user using the reader specified by the `reader' slot (using the -`transient-infix' method described below). - -For some infix classes the value is changed without reading -anything in the minibuffer, i.e., the mere act of invoking the -infix command determines what the new value should be, based -on the previous value.") - -(cl-defmethod transient-infix-read :around ((obj transient-infix)) - "Refresh the transient buffer and call the next method. - -Also wrap `cl-call-next-method' with two macros: -- `transient--with-suspended-override' allows use of minibuffer. -- `transient--with-emergency-exit' arranges for the transient to - be exited in case of an error." - (transient--show) - (transient--with-emergency-exit :infix-read - (transient--with-suspended-override - (cl-call-next-method obj)))) - -(cl-defmethod transient-infix-read ((obj transient-infix)) - "Read a value while taking care of history. - -This method is suitable for a wide variety of infix commands, -including but not limited to inline arguments and variables. - -If you do not use this method for your own infix class, then -you should likely replicate a lot of the behavior of this -method. If you fail to do so, then users might not appreciate -the lack of history, for example. - -Only for very simple classes that toggle or cycle through a very -limited number of possible values should you replace this with a -simple method that does not handle history. (E.g., for a command -line switch the only possible values are \"use it\" and \"don't use -it\", in which case it is pointless to preserve history.)" - (with-slots (value multi-value always-read allow-empty choices) obj - (if (and value - (not multi-value) - (not always-read) - transient--prefix) - (oset obj value nil) - (let* ((enable-recursive-minibuffers t) - (reader (oref obj reader)) - (choices (if (functionp choices) (funcall choices) choices)) - (prompt (transient-prompt obj)) - (value (if multi-value (string-join value ",") value)) - (history-key (or (oref obj history-key) - (oref obj command))) - (transient--history (alist-get history-key transient-history)) - (transient--history (if (or (null value) - (eq value (car transient--history))) - transient--history - (cons value transient--history))) - (initial-input (and transient-read-with-initial-input - (car transient--history))) - (history (if initial-input - (cons 'transient--history 1) - 'transient--history)) - (value - (cond - (reader (funcall reader prompt initial-input history)) - (multi-value - (completing-read-multiple prompt choices nil nil - initial-input history)) - (choices - (completing-read prompt choices nil t initial-input history)) - ((read-string prompt initial-input history))))) - (cond ((and (equal value "") (not allow-empty)) - (setq value nil)) - ((and (equal value "\"\"") allow-empty) - (setq value ""))) - (when value - (when (and (bound-and-true-p ivy-mode) - (stringp (car transient--history))) - (set-text-properties 0 (length (car transient--history)) nil - (car transient--history))) - (setf (alist-get history-key transient-history) - (delete-dups transient--history))) - value)))) - -(cl-defmethod transient-infix-read ((obj transient-switch)) - "Toggle the switch on or off." - (if (oref obj value) nil (oref obj argument))) - -(cl-defmethod transient-infix-read ((obj transient-switches)) - "Cycle through the mutually exclusive switches. -The last value is \"don't use any of these switches\"." - (let ((choices (mapcar (apply-partially #'format (oref obj argument-format)) - (oref obj choices)))) - (if-let ((value (oref obj value))) - (cadr (member value choices)) - (car choices)))) - -(cl-defmethod transient-infix-read ((command symbol)) - "Elsewhere use the reader of the infix command COMMAND. -Use this if you want to share an infix's history with a regular -stand-alone command." - (if-let ((obj (transient--suffix-prototype command))) - (cl-letf (((symbol-function #'transient--show) #'ignore)) - (transient-infix-read obj)) - (error "Not a suffix command: `%s'" command))) - -;;;; Readers - -(defun transient-read-file (prompt _initial-input _history) - "Read a file." - (file-local-name (expand-file-name (read-file-name prompt)))) - -(defun transient-read-existing-file (prompt _initial-input _history) - "Read an existing file." - (file-local-name (expand-file-name (read-file-name prompt nil nil t)))) - -(defun transient-read-directory (prompt _initial-input _history) - "Read a directory." - (file-local-name (expand-file-name (read-directory-name prompt)))) - -(defun transient-read-existing-directory (prompt _initial-input _history) - "Read an existing directory." - (file-local-name (expand-file-name (read-directory-name prompt nil nil t)))) - -(defun transient-read-number-N0 (prompt initial-input history) - "Read a natural number (including zero) and return it as a string." - (transient--read-number-N prompt initial-input history t)) - -(defun transient-read-number-N+ (prompt initial-input history) - "Read a natural number (excluding zero) and return it as a string." - (transient--read-number-N prompt initial-input history nil)) - -(defun transient--read-number-N (prompt initial-input history include-zero) - (save-match-data - (cl-block nil - (while t - (let ((str (read-from-minibuffer prompt initial-input nil nil history))) - (when (or (string-equal str "") - (string-match-p (if include-zero - "\\`\\(0\\|[1-9][0-9]*\\)\\'" - "\\`[1-9][0-9]*\\'") - str)) - (cl-return str))) - (message "Please enter a natural number (%s zero)." - (if include-zero "including" "excluding")) - (sit-for 1))))) - -(defun transient-read-date (prompt default-time _history) - "Read a date using `org-read-date' (which see)." - (require 'org) - (when (fboundp 'org-read-date) - (org-read-date 'with-time nil nil prompt default-time))) - -;;;; Prompt - -(cl-defgeneric transient-prompt (obj) - "Return the prompt to be used to read infix object OBJ's value.") - -(cl-defmethod transient-prompt ((obj transient-infix)) - "Return the prompt to be used to read infix object OBJ's value. - -This implementation should be suitable for almost all infix -commands. - -If the value of OBJ's `prompt' slot is non-nil, then it must be -a string or a function. If it is a string, then use that. If -it is a function, then call that with OBJ as the only argument. -That function must return a string, which is then used as the -prompt. - -Otherwise, if the value of either the `argument' or `variable' -slot of OBJ is a string, then base the prompt on that (preferring -the former), appending either \"=\" (if it appears to be a -command-line option) or \": \". - -Finally fall through to using \"(BUG: no prompt): \" as the -prompt." - (if-let ((prompt (oref obj prompt))) - (let ((prompt (if (functionp prompt) - (funcall prompt obj) - prompt))) - (if (stringp prompt) - prompt - "(BUG: no prompt): ")) - (or (and-let* ((arg (and (slot-boundp obj 'argument) (oref obj argument)))) - (if (and (stringp arg) (string-suffix-p "=" arg)) - arg - (concat arg ": "))) - (and-let* ((var (and (slot-boundp obj 'variable) (oref obj variable)))) - (and (stringp var) - (concat var ": "))) - "(BUG: no prompt): "))) - -;;;; Set - -(cl-defgeneric transient-infix-set (obj value) - "Set the value of infix object OBJ to VALUE.") - -(cl-defmethod transient-infix-set ((obj transient-infix) value) - "Set the value of infix object OBJ to VALUE." - (oset obj value value)) - -(cl-defmethod transient-infix-set :after ((obj transient-argument) value) - "Unset incompatible infix arguments." - (when-let* ((value) - (val (transient-infix-value obj)) - (arg (if (slot-boundp obj 'argument) - (oref obj argument) - (oref obj argument-format))) - (spec (oref transient--prefix incompatible)) - (filter (lambda (x rule) - (and (member x rule) - (remove x rule)))) - (incomp (nconc - (cl-mapcan (apply-partially filter arg) spec) - (and (not (equal val arg)) - (cl-mapcan (apply-partially filter val) spec))))) - (dolist (obj transient--suffixes) - (when-let* (((cl-typep obj 'transient-argument)) - (val (transient-infix-value obj)) - (arg (if (slot-boundp obj 'argument) - (oref obj argument) - (oref obj argument-format))) - ((if (equal val arg) - (member arg incomp) - (or (member val incomp) - (member arg incomp))))) - (transient-infix-set obj nil))))) - -(defun transient-prefix-set (value) - "Set the value of the active transient prefix to VALUE. -Intended for use by transient suffix commands." - (oset transient--prefix value value) - (setq transient--refreshp 'updated-value)) - -(cl-defgeneric transient-set-value (obj) - "Persist the value of the transient prefix OBJ. -Only intended for use by `transient-set'. -Also see `transient-prefix-set'.") - -(cl-defmethod transient-set-value ((obj transient-prefix)) - (oset (oref obj prototype) value (transient-get-value)) - (transient--history-push obj)) - -;;;; Save - -(cl-defgeneric transient-save-value (obj) - "Save the value of the transient prefix OBJ.") - -(cl-defmethod transient-save-value ((obj transient-prefix)) - (let ((value (transient-get-value))) - (oset (oref obj prototype) value value) - (setf (alist-get (oref obj command) transient-values) value) - (transient-save-values)) - (transient--history-push obj)) - -;;;; Reset - -(cl-defgeneric transient-reset-value (obj) - "Clear the set and saved values of the transient prefix OBJ.") - -(cl-defmethod transient-reset-value ((obj transient-prefix)) - (let ((value (transient-default-value obj))) - (oset obj value value) - (oset (oref obj prototype) value value) - (setf (alist-get (oref obj command) transient-values nil 'remove) nil) - (transient-save-values)) - (transient--history-push obj) - (mapc #'transient-init-value transient--suffixes)) - -;;;; Get - -(defun transient-args (prefix) - "Return the value of the transient prefix command PREFIX. -If the current command was invoked from the transient prefix -command PREFIX, then return the active infix arguments. If -the current command was not invoked from PREFIX, then return -the set, saved or default value for PREFIX." - (cl-mapcan #'transient--get-wrapped-value (transient-suffixes prefix))) - -(defun transient-suffixes (prefix) - "Return the suffix objects of the transient prefix command PREFIX." - (if (eq transient-current-command prefix) - transient-current-suffixes - (let ((transient--prefix (transient--init-prefix prefix))) - (transient--flatten-suffixes - (transient--init-suffixes prefix))))) - -(defun transient-get-value () - (transient--with-emergency-exit :get-value - (cl-mapcan (lambda (obj) - (and (or (not (slot-exists-p obj 'unsavable)) - (not (oref obj unsavable))) - (transient--get-wrapped-value obj))) - (or transient--suffixes transient-current-suffixes)))) - -(defun transient--get-wrapped-value (obj) - (and-let* ((value (transient-infix-value obj))) - (pcase-exhaustive (and (slot-exists-p obj 'multi-value) - (oref obj multi-value)) - ('nil (list value)) - ((or 't 'rest) (list value)) - ('repeat value)))) - -(cl-defgeneric transient-infix-value (obj) - "Return the value of the suffix object OBJ. - -This function is called by `transient-args' (which see), meaning -this function is how the value of a transient is determined so -that the invoked suffix command can use it. - -Currently most values are strings, but that is not set in stone. -Nil is not a value, it means \"no value\". - -Usually only infixes have a value, but see the method for -`transient-suffix'.") - -(cl-defmethod transient-infix-value ((_ transient-suffix)) - "Return nil, which means \"no value\". - -Infix arguments contribute the transient's value while suffix -commands consume it. This function is called for suffixes anyway -because a command that both contributes to the transient's value -and also consumes it is not completely unconceivable. - -If you define such a command, then you must define a derived -class and implement this function because this default method -does nothing." nil) - -(cl-defmethod transient-infix-value ((obj transient-infix)) - "Return the value of OBJ's `value' slot." - (oref obj value)) - -(cl-defmethod transient-infix-value ((obj transient-option)) - "Return ARGUMENT and VALUE as a unit or nil if the latter is nil." - (and-let* ((value (oref obj value))) - (let ((arg (oref obj argument))) - (pcase-exhaustive (oref obj multi-value) - ('nil (concat arg value)) - ((or 't 'rest) (cons arg value)) - ('repeat (mapcar (lambda (v) (concat arg v)) value)))))) - -(cl-defmethod transient-infix-value ((_ transient-variable)) - "Return nil, which means \"no value\". - -Setting the value of a variable is done by, well, setting the -value of the variable. I.e., this is a side-effect and does -not contribute to the value of the transient." - nil) - -;;;; Utilities - -(defun transient-arg-value (arg args) - "Return the value of ARG as it appears in ARGS. - -For a switch return a boolean. For an option return the value as -a string, using the empty string for the empty value, or nil if -the option does not appear in ARGS." - (if (string-suffix-p "=" arg) - (save-match-data - (and-let* ((match (let ((case-fold-search nil) - (re (format "\\`%s\\(?:=\\(.+\\)\\)?\\'" - (substring arg 0 -1)))) - (cl-find-if (lambda (a) - (and (stringp a) - (string-match re a))) - args)))) - (or (match-string 1 match) ""))) - (and (member arg args) t))) - -(defun transient-scope () - "Return the value of the `scope' slot of the current prefix." - (oref (transient-prefix-object) scope)) - -;;; History - -(cl-defgeneric transient--history-key (obj) - "Return OBJ's history key. -If the value of the `history-key' slot is non-nil, then return -that. Otherwise return the value of the `command' slot." - (or (oref obj history-key) - (oref obj command))) - -(cl-defgeneric transient--history-push (obj) - "Push the current value of OBJ to its entry in `transient-history'." - (let ((key (transient--history-key obj))) - (setf (alist-get key transient-history) - (let ((args (transient-get-value))) - (cons args (delete args (alist-get key transient-history))))))) - -(cl-defgeneric transient--history-init (obj) - "Initialize OBJ's `history' slot. -This is the transient-wide history; many individual infixes also -have a history of their own.") - -(cl-defmethod transient--history-init ((obj transient-prefix)) - "Initialize OBJ's `history' slot from the variable `transient-history'." - (let ((val (oref obj value))) - (oset obj history - (cons val (delete val (alist-get (transient--history-key obj) - transient-history)))))) - -;;; Draw - -(defun transient--show-brief () - (let ((message-log-max nil)) - (if (and transient-show-popup (<= transient-show-popup 0)) - (message "%s-" (key-description (this-command-keys))) - (message - "%s- [%s] %s" - (key-description (this-command-keys)) - (oref transient--prefix command) - (mapconcat - #'identity - (sort - (cl-mapcan - (lambda (suffix) - (let ((key (kbd (oref suffix key)))) - ;; Don't list any common commands. - (and (not (memq (oref suffix command) - `(,(lookup-key transient-map key) - ,(lookup-key transient-sticky-map key) - ;; From transient-common-commands: - transient-set - transient-save - transient-history-prev - transient-history-next - transient-quit-one - transient-toggle-common - transient-set-level))) - (list (propertize (oref suffix key) 'face 'transient-key))))) - transient--suffixes) - #'string<) - (propertize "|" 'face 'transient-delimiter)))))) - -(defun transient--show () - (transient--timer-cancel) - (setq transient--showp t) - (let ((transient--shadowed-buffer (current-buffer)) - (focus nil)) - (setq transient--buffer (get-buffer-create transient--buffer-name)) - (with-current-buffer transient--buffer - (when transient-enable-popup-navigation - (setq focus (or (button-get (point) 'command) - (and (not (bobp)) - (button-get (1- (point)) 'command)) - (transient--heading-at-point)))) - (erase-buffer) - (run-hooks 'transient-setup-buffer-hook) - (when transient-force-fixed-pitch - (transient--force-fixed-pitch)) - (setq window-size-fixed t) - (when (bound-and-true-p tab-line-format) - (setq tab-line-format nil)) - (setq header-line-format nil) - (setq mode-line-format - (if (or (natnump transient-mode-line-format) - (eq transient-mode-line-format 'line)) - nil - transient-mode-line-format)) - (setq mode-line-buffer-identification - (symbol-name (oref transient--prefix command))) - (if transient-enable-popup-navigation - (setq-local cursor-in-non-selected-windows 'box) - (setq cursor-type nil)) - (setq display-line-numbers nil) - (setq show-trailing-whitespace nil) - (transient--insert-groups) - (when (or transient--helpp transient--editp) - (transient--insert-help)) - (when-let ((line (transient--separator-line))) - (insert line))) - (unless (window-live-p transient--window) - (setq transient--window - (display-buffer transient--buffer - transient-display-buffer-action))) - (when (window-live-p transient--window) - (with-selected-window transient--window - (goto-char (point-min)) - (when transient-enable-popup-navigation - (transient--goto-button focus)) - (transient--fit-window-to-buffer transient--window))))) - -(defun transient--fit-window-to-buffer (window) - (let ((window-resize-pixelwise t) - (window-size-fixed nil)) - (if (eq (car (window-parameter window 'quit-restore)) 'other) - ;; Grow but never shrink window that previously displayed - ;; another buffer and is going to display that again. - (fit-window-to-buffer window nil (window-height window)) - (fit-window-to-buffer window nil 1)))) - -(defun transient--separator-line () - (and-let* ((height (cond ((not window-system) nil) - ((natnump transient-mode-line-format) - transient-mode-line-format) - ((eq transient-mode-line-format 'line) 1))) - (face `(,@(and (>= emacs-major-version 27) '(:extend t)) - :background - ,(or (face-foreground (transient--key-face nil 'non-suffix) - nil t) - "#gray60")))) - (concat (propertize "__" 'face face 'display `(space :height (,height))) - (propertize "\n" 'face face 'line-height t)))) - -(defmacro transient-with-shadowed-buffer (&rest body) - "While in the transient buffer, temporarily make the shadowed buffer current." - (declare (indent 0) (debug t)) - `(with-current-buffer (or transient--shadowed-buffer (current-buffer)) - ,@body)) - -(defun transient--insert-groups () - (let ((groups (cl-mapcan (lambda (group) - (let ((hide (oref group hide))) - (and (not (and (functionp hide) - (transient-with-shadowed-buffer - (funcall hide)))) - (list group)))) - transient--layout))) - (while-let ((group (pop groups))) - (transient--insert-group group) - (when groups - (insert ?\n))))) - -(defvar transient--max-group-level 1) - -(cl-defgeneric transient--insert-group (group) - "Format GROUP and its elements and insert the result.") - -(cl-defmethod transient--insert-group :around ((group transient-group)) - "Insert GROUP's description, if any." - (when-let ((desc (transient-with-shadowed-buffer - (transient-format-description group)))) - (insert desc ?\n)) - (let ((transient--max-group-level - (max (oref group level) transient--max-group-level)) - (transient--pending-group group)) - (cl-call-next-method group))) - -(cl-defmethod transient--insert-group ((group transient-row)) - (transient--maybe-pad-keys group) - (dolist (suffix (oref group suffixes)) - (insert (transient-with-shadowed-buffer (transient-format suffix))) - (insert " ")) - (insert ?\n)) - -(cl-defmethod transient--insert-group ((group transient-column) - &optional skip-empty) - (transient--maybe-pad-keys group) - (dolist (suffix (oref group suffixes)) - (let ((str (transient-with-shadowed-buffer (transient-format suffix)))) - (unless (and (not skip-empty) (equal str "")) - (insert str) - (unless (string-match-p ".\n\\'" str) - (insert ?\n)))))) - -(cl-defmethod transient--insert-group ((group transient-columns)) - (if transient-force-single-column - (dolist (group (oref group suffixes)) - (transient--insert-group group t)) - (let* ((columns - (mapcar - (lambda (column) - (transient--maybe-pad-keys column group) - (transient-with-shadowed-buffer - `(,@(and-let* ((desc (transient-format-description column))) - (list desc)) - ,@(let ((transient--pending-group column)) - (mapcar #'transient-format (oref column suffixes)))))) - (oref group suffixes))) - (stops (transient--column-stops columns))) - (dolist (row (apply #'transient--mapn #'list columns)) - (let ((stops stops)) - (dolist (cell row) - (let ((stop (pop stops))) - (when cell - (transient--align-to stop) - (insert cell))))) - (insert ?\n))))) - -(cl-defmethod transient--insert-group ((group transient-subgroups)) - (let ((subgroups (oref group suffixes))) - (while-let ((subgroup (pop subgroups))) - (transient--maybe-pad-keys subgroup group) - (transient--insert-group subgroup) - (when subgroups - (insert ?\n))))) - -(cl-defgeneric transient-format (obj) - "Format and return OBJ for display. - -When this function is called, then the current buffer is some -temporary buffer. If you need the buffer from which the prefix -command was invoked to be current, then do so by temporarily -making `transient--original-buffer' current.") - -(cl-defmethod transient-format ((arg string)) - "Return the string ARG after applying the `transient-heading' face." - (propertize arg 'face 'transient-heading)) - -(cl-defmethod transient-format ((_ null)) - "Return a string containing just the newline character." - "\n") - -(cl-defmethod transient-format ((arg integer)) - "Return a string containing just the ARG character." - (char-to-string arg)) - -(cl-defmethod transient-format :around ((obj transient-suffix)) - "Add additional formatting if appropriate. -When reading user input for this infix, then highlight it. -When edit-mode is enabled, then prepend the level information. -When `transient-enable-popup-navigation' is non-nil then format -as a button." - (let ((str (cl-call-next-method obj))) - (when (and (cl-typep obj 'transient-infix) - (eq (oref obj command) this-original-command) - (active-minibuffer-window)) - (setq str (transient--add-face str 'transient-active-infix))) - (when transient--editp - (setq str (concat (let ((level (oref obj level))) - (propertize (format " %s " level) - 'face (if (transient--use-level-p level t) - 'transient-enabled-suffix - 'transient-disabled-suffix))) - str))) - (when (and transient-enable-popup-navigation - (slot-boundp obj 'command)) - (setq str (make-text-button str nil - 'type 'transient - 'command (oref obj command)))) - str)) - -(cl-defmethod transient-format ((obj transient-infix)) - "Return a string generated using OBJ's `format'. -%k is formatted using `transient-format-key'. -%d is formatted using `transient-format-description'. -%v is formatted using `transient-format-value'." - (format-spec (oref obj format) - `((?k . ,(transient-format-key obj)) - (?d . ,(transient-format-description obj)) - (?v . ,(transient-format-value obj))))) - -(cl-defmethod transient-format ((obj transient-suffix)) - "Return a string generated using OBJ's `format'. -%k is formatted using `transient-format-key'. -%d is formatted using `transient-format-description'." - (format-spec (oref obj format) - `((?k . ,(transient-format-key obj)) - (?d . ,(transient-format-description obj))))) - -(cl-defgeneric transient-format-key (obj) - "Format OBJ's `key' for display and return the result.") - -(cl-defmethod transient-format-key :around ((obj transient-suffix)) - "Add `transient-inapt-suffix' face if suffix is inapt." - (let ((str (cl-call-next-method))) - (if (oref obj inapt) - (transient--add-face str 'transient-inapt-suffix) - str))) - -(cl-defmethod transient-format-key ((obj transient-suffix)) - "Format OBJ's `key' for display and return the result." - (let ((key (if (slot-boundp obj 'key) (oref obj key) "")) - (cmd (and (slot-boundp obj 'command) (oref obj command)))) - (when-let ((width (oref transient--pending-group pad-keys))) - (setq key (truncate-string-to-width key width nil ?\s))) - (if transient--redisplay-key - (let ((len (length transient--redisplay-key)) - (seq (cl-coerce (edmacro-parse-keys key t) 'list))) - (cond - ((member (seq-take seq len) - (list transient--redisplay-key - (thread-last transient--redisplay-key - (cl-substitute ?- 'kp-subtract) - (cl-substitute ?= 'kp-equal) - (cl-substitute ?+ 'kp-add)))) - (let ((pre (key-description (vconcat (seq-take seq len)))) - (suf (key-description (vconcat (seq-drop seq len))))) - (setq pre (string-replace "RET" "C-m" pre)) - (setq pre (string-replace "TAB" "C-i" pre)) - (setq suf (string-replace "RET" "C-m" suf)) - (setq suf (string-replace "TAB" "C-i" suf)) - ;; We use e.g., "-k" instead of the more correct "- k", - ;; because the former is prettier. If we did that in - ;; the definition, then we want to drop the space that - ;; is reinserted above. False-positives are possible - ;; for silly bindings like "-C-c C-c". - (unless (string-search " " key) - (setq pre (string-replace " " "" pre)) - (setq suf (string-replace " " "" suf))) - (concat (propertize pre 'face 'transient-unreachable-key) - (and (string-prefix-p (concat pre " ") key) " ") - (propertize suf 'face (transient--key-face cmd)) - (save-excursion - (and (string-match " +\\'" key) - (propertize (match-string 0 key) - 'face 'fixed-pitch)))))) - ((transient--lookup-key transient-sticky-map (kbd key)) - (propertize key 'face (transient--key-face cmd))) - (t - (propertize key 'face 'transient-unreachable-key)))) - (propertize key 'face (transient--key-face cmd))))) - -(cl-defmethod transient-format-key :around ((obj transient-argument)) - "Handle `transient-highlight-mismatched-keys'." - (let ((key (cl-call-next-method obj))) - (cond - ((not transient-highlight-mismatched-keys) key) - ((not (slot-boundp obj 'shortarg)) - (transient--add-face key 'transient-nonstandard-key)) - ((not (string-equal key (oref obj shortarg))) - (transient--add-face key 'transient-mismatched-key)) - (key)))) - -(cl-defgeneric transient-format-description (obj) - "Format OBJ's `description' for display and return the result.") - -(cl-defmethod transient-format-description ((obj transient-suffix)) - "The `description' slot may be a function, in which case that is -called inside the correct buffer (see `transient--insert-group') -and its value is returned to the caller." - (transient--get-description obj)) - -(cl-defmethod transient-format-description ((obj transient-value-preset)) - (pcase-let* (((eieio description key set) obj) - ((eieio value) transient--prefix) - (active (seq-set-equal-p set value))) - (format - "%s %s" - (propertize (or description (format "Preset %s" key)) - 'face (and active 'transient-argument)) - (format (propertize "(%s)" 'face 'transient-delimiter) - (mapconcat (lambda (arg) - (propertize - arg 'face (cond (active 'transient-argument) - ((member arg value) - '((:weight demibold) - transient-inactive-argument)) - ('transient-inactive-argument)))) - set " "))))) - -(cl-defmethod transient-format-description ((obj transient-group)) - "Format the description by calling the next method. -If the result doesn't use the `face' property at all, then apply the -face `transient-heading' to the complete string." - (and-let* ((desc (transient--get-description obj))) - (cond ((oref obj inapt) - (propertize desc 'face 'transient-inapt-suffix)) - ((text-property-not-all 0 (length desc) 'face nil desc) - desc) - ((propertize desc 'face 'transient-heading))))) - -(cl-defmethod transient-format-description :around ((obj transient-suffix)) - "Format the description by calling the next method. -If the result is nil, then use \"(BUG: no description)\" as the -description. If the OBJ's `key' is currently unreachable, then -apply the face `transient-unreachable' to the complete string." - (let ((desc (or (cl-call-next-method obj) - (and (slot-boundp transient--prefix 'suffix-description) - (funcall (oref transient--prefix suffix-description) - obj))))) - (if desc - (when-let ((face (transient--get-face obj 'face))) - (setq desc (transient--add-face desc face t))) - (setq desc (propertize "(BUG: no description)" 'face 'error))) - (when (if transient--all-levels-p - (> (oref obj level) transient--default-prefix-level) - (and transient-highlight-higher-levels - (> (max (oref obj level) transient--max-group-level) - transient--default-prefix-level))) - (setq desc (transient--add-face desc 'transient-higher-level))) - (when-let ((inapt-face (and (oref obj inapt) - (transient--get-face obj 'inapt-face)))) - (setq desc (transient--add-face desc inapt-face))) - (when (and (slot-boundp obj 'key) - (transient--key-unreachable-p obj)) - (setq desc (transient--add-face desc 'transient-unreachable))) - desc)) - -(cl-defgeneric transient-format-value (obj) - "Format OBJ's value for display and return the result.") - -(cl-defmethod transient-format-value ((obj transient-suffix)) - (propertize (oref obj argument) - 'face (if (oref obj value) - 'transient-argument - 'transient-inactive-argument))) - -(cl-defmethod transient-format-value ((obj transient-option)) - (let ((argument (oref obj argument))) - (if-let ((value (oref obj value))) - (pcase-exhaustive (oref obj multi-value) - ('nil - (concat (propertize argument 'face 'transient-argument) - (propertize value 'face 'transient-value))) - ((or 't 'rest) - (concat (propertize (if (string-suffix-p " " argument) - argument - (concat argument " ")) - 'face 'transient-argument) - (propertize (mapconcat #'prin1-to-string value " ") - 'face 'transient-value))) - ('repeat - (mapconcat (lambda (value) - (concat (propertize argument 'face 'transient-argument) - (propertize value 'face 'transient-value))) - value " "))) - (propertize argument 'face 'transient-inactive-argument)))) - -(cl-defmethod transient-format-value ((obj transient-switches)) - (with-slots (value argument-format choices) obj - (format (propertize argument-format - 'face (if value - 'transient-argument - 'transient-inactive-argument)) - (format - (propertize "[%s]" 'face 'transient-delimiter) - (mapconcat - (lambda (choice) - (propertize choice 'face - (if (equal (format argument-format choice) value) - 'transient-value - 'transient-inactive-value))) - choices - (propertize "|" 'face 'transient-delimiter)))))) - -(cl-defmethod transient--get-description ((obj transient-child)) - (and-let* ((desc (oref obj description))) - (if (functionp desc) - (if (= (car (transient--func-arity desc)) 1) - (funcall desc obj) - (funcall desc)) - desc))) - -(cl-defmethod transient--get-face ((obj transient-suffix) slot) - (and-let* (((slot-boundp obj slot)) - (face (slot-value obj slot))) - (if (and (not (facep face)) - (functionp face)) - (let ((transient--pending-suffix obj)) - (if (= (car (transient--func-arity face)) 1) - (funcall face obj) - (funcall face))) - face))) - -(defun transient--add-face (string face &optional append beg end) - (let ((str (copy-sequence string))) - (add-face-text-property (or beg 0) (or end (length str)) face append str) - str)) - -(defun transient--key-face (&optional cmd enforce-type) - (or (and transient-semantic-coloring - (not transient--helpp) - (not transient--editp) - (or (and cmd (get cmd 'transient-face)) - (get (transient--get-pre-command cmd enforce-type) - 'transient-face))) - (if cmd 'transient-key 'transient-key-noop))) - -(defun transient--key-unreachable-p (obj) - (and transient--redisplay-key - (let ((key (oref obj key))) - (not (or (equal (seq-take (cl-coerce (edmacro-parse-keys key t) 'list) - (length transient--redisplay-key)) - transient--redisplay-key) - (transient--lookup-key transient-sticky-map (kbd key))))))) - -(defun transient--lookup-key (keymap key) - (let ((val (lookup-key keymap key))) - (and val (not (integerp val)) val))) - -(defun transient--maybe-pad-keys (group &optional parent) - (when-let ((pad (or (oref group pad-keys) - (and parent (oref parent pad-keys))))) - (oset group pad-keys - (apply #'max - (if (integerp pad) pad 0) - (seq-keep (lambda (suffix) - (and (eieio-object-p suffix) - (slot-boundp suffix 'key) - (length (oref suffix key)))) - (oref group suffixes)))))) - -(defun transient--pixel-width (string) - (save-window-excursion - (with-temp-buffer - (insert string) - (set-window-dedicated-p nil nil) - (set-window-buffer nil (current-buffer)) - (car (window-text-pixel-size - nil (line-beginning-position) (point)))))) - -(defun transient--column-stops (columns) - (let* ((var-pitch (or transient-align-variable-pitch - (oref transient--prefix variable-pitch))) - (char-width (and var-pitch (transient--pixel-width " ")))) - (transient--seq-reductions-from - (apply-partially #'+ (* 2 (if var-pitch char-width 1))) - (transient--mapn - (lambda (cells min) - (apply #'max - (if min (if var-pitch (* min char-width) min) 0) - (mapcar (if var-pitch #'transient--pixel-width #'length) cells))) - columns - (oref transient--prefix column-widths)) - 0))) - -(defun transient--align-to (stop) - (unless (zerop stop) - (insert (if (or transient-align-variable-pitch - (oref transient--prefix variable-pitch)) - (propertize " " 'display `(space :align-to (,stop))) - (make-string (max 0 (- stop (current-column))) ?\s))))) - -(defun transient-command-summary-or-name (obj) - "Return the summary or name of the command represented by OBJ. - -If the command has a doc-string, then return the first line of -that, else its name. - -Intended to be temporarily used as the `:suffix-description' of -a prefix command, while porting a regular keymap to a transient." - (let ((command (oref obj command))) - (if-let ((doc (documentation command))) - (propertize (car (split-string doc "\n")) 'face 'font-lock-doc-face) - (propertize (symbol-name command) 'face 'font-lock-function-name-face)))) - -;;; Help - -(cl-defgeneric transient-show-help (obj) - "Show documentation for the command represented by OBJ.") - -(cl-defmethod transient-show-help ((obj transient-prefix)) - "Call `show-help' if non-nil, else show `info-manual', -if non-nil, else show the `man-page' if non-nil, else use -`describe-function'." - (with-slots (show-help info-manual man-page command) obj - (cond (show-help (funcall show-help obj)) - (info-manual (transient--show-manual info-manual)) - (man-page (transient--show-manpage man-page)) - ((transient--describe-function command))))) - -(cl-defmethod transient-show-help ((obj transient-suffix)) - "Call `show-help' if non-nil, else use `describe-function'. -Also used to dispatch showing documentation for the current -prefix. If the suffix is a sub-prefix, then also call the -prefix method." - (cond - ((eq this-command 'transient-help) - (transient-show-help transient--prefix)) - ((let ((prefix (get (oref obj command) - 'transient--prefix))) - (and prefix (not (eq (oref transient--prefix command) this-command)) - (prog1 t (transient-show-help prefix))))) - ((if-let ((show-help (oref obj show-help))) - (funcall show-help obj) - (transient--describe-function this-command))))) - -(cl-defmethod transient-show-help ((obj transient-infix)) - "Call `show-help' if non-nil, else show the `man-page' -if non-nil, else use `describe-function'. When showing the -manpage, then try to jump to the correct location." - (if-let ((show-help (oref obj show-help))) - (funcall show-help obj) - (if-let ((man-page (oref transient--prefix man-page)) - (argument (and (slot-boundp obj 'argument) - (oref obj argument)))) - (transient--show-manpage man-page argument) - (transient--describe-function this-command)))) - -;; `cl-generic-generalizers' doesn't support `command' et al. -(cl-defmethod transient-show-help (cmd) - "Show the command doc-string." - (transient--describe-function cmd)) - -(defun transient--describe-function (fn) - (describe-function fn) - (unless (derived-mode-p 'help-mode) - (when-let* ((buf (get-buffer "*Help*")) - (win (or (and buf (get-buffer-window buf)) - (cl-find-if (lambda (win) - (with-current-buffer (window-buffer win) - (derived-mode-p 'help-mode))) - (window-list))))) - (select-window win)))) - -(defun transient--show-manual (manual) - (info manual)) - -(defun transient--show-manpage (manpage &optional argument) - (require 'man) - (let* ((Man-notify-method 'meek) - (buf (Man-getpage-in-background manpage)) - (proc (get-buffer-process buf))) - (while (and proc (eq (process-status proc) 'run)) - (accept-process-output proc)) - (switch-to-buffer buf) - (when argument - (transient--goto-argument-description argument)))) - -(defun transient--goto-argument-description (arg) - (goto-char (point-min)) - (let ((case-fold-search nil) - ;; This matches preceding/proceeding options. Options - ;; such as "-a", "-S[<keyid>]", and "--grep=<pattern>" - ;; are matched by this regex without the shy group. - ;; The ". " in the shy group is for options such as - ;; "-m parent-number", and the "-[^[:space:]]+ " is - ;; for options such as "--mainline parent-number" - (others "-\\(?:. \\|-[^[:space:]]+ \\)?[^[:space:]]+")) - (when (re-search-forward - (if (equal arg "--") - ;; Special case. - "^[\t\s]+\\(--\\(?: \\|$\\)\\|\\[--\\]\\)" - ;; Should start with whitespace and may have - ;; any number of options before and/or after. - (format - "^[\t\s]+\\(?:%s, \\)*?\\(?1:%s\\)%s\\(?:, %s\\)*$" - others - ;; Options don't necessarily end in an "=" - ;; (e.g., "--gpg-sign[=<keyid>]") - (string-remove-suffix "=" arg) - ;; Simple options don't end in an "=". Splitting this - ;; into 2 cases should make getting false positives - ;; less likely. - (if (string-suffix-p "=" arg) - ;; "[^[:space:]]*[^.[:space:]]" matches the option - ;; value, which is usually after the option name - ;; and either '=' or '[='. The value can't end in - ;; a period, as that means it's being used at the - ;; end of a sentence. The space is for options - ;; such as '--mainline parent-number'. - "\\(?: \\|\\[?=\\)[^[:space:]]*[^.[:space:]]" - ;; Either this doesn't match anything (e.g., "-a"), - ;; or the option is followed by a value delimited - ;; by a "[", "<", or ":". A space might appear - ;; before this value, as in "-f <file>". The - ;; space alternative is for options such as - ;; "-m parent-number". - "\\(?:\\(?: \\| ?[\\[<:]\\)[^[:space:]]*[^.[:space:]]\\)?") - others)) - nil t) - (goto-char (match-beginning 1))))) - -(defun transient--insert-help () - (unless (looking-back "\n\n" 2) - (insert "\n")) - (when transient--helpp - (insert - (format (propertize "\ -Type a %s to show help for that suffix command, or %s to show manual. -Type %s to exit help.\n" - 'face 'transient-heading) - (propertize "<KEY>" 'face 'transient-key) - (propertize "?" 'face 'transient-key) - (propertize "C-g" 'face 'transient-key)))) - (when transient--editp - (unless transient--helpp - (insert - (format (propertize "\ -Type a %s to set level for that suffix command. -Type %s to set what levels are available for this prefix command.\n" - 'face 'transient-heading) - (propertize "<KEY>" 'face 'transient-key) - (propertize "C-x l" 'face 'transient-key)))) - (with-slots (level) transient--prefix - (insert - (format (propertize " -Suffixes on levels %s are available. -Suffixes on levels %s and %s are unavailable.\n" - 'face 'transient-heading) - (propertize (format "1-%s" level) - 'face 'transient-enabled-suffix) - (propertize " 0 " - 'face 'transient-disabled-suffix) - (propertize (format ">=%s" (1+ level)) - 'face 'transient-disabled-suffix)))))) - -;;; Popup Navigation - -(defun transient-scroll-up (&optional arg) - "Scroll text of transient popup window upward ARG lines. -If ARG is nil scroll near full screen. This is a wrapper -around `scroll-up-command' (which see)." - (interactive "^P") - (with-selected-window transient--window - (scroll-up-command arg))) - -(defun transient-scroll-down (&optional arg) - "Scroll text of transient popup window down ARG lines. -If ARG is nil scroll near full screen. This is a wrapper -around `scroll-down-command' (which see)." - (interactive "^P") - (with-selected-window transient--window - (scroll-down-command arg))) - -(defun transient-backward-button (n) - "Move to the previous button in the transient popup buffer. -See `backward-button' for information about N." - (interactive "p") - (with-selected-window transient--window - (backward-button n t))) - -(defun transient-forward-button (n) - "Move to the next button in the transient popup buffer. -See `forward-button' for information about N." - (interactive "p") - (with-selected-window transient--window - (forward-button n t))) - -(define-button-type 'transient - 'face nil - 'keymap transient-button-map) - -(defun transient--goto-button (command) - (cond - ((stringp command) - (when (re-search-forward (concat "^" (regexp-quote command)) nil t) - (goto-char (match-beginning 0)))) - (command - (while (and (ignore-errors (forward-button 1)) - (not (eq (button-get (button-at (point)) 'command) command)))) - (unless (eq (button-get (button-at (point)) 'command) command) - (goto-char (point-min)) - (forward-button 1))))) - -(defun transient--heading-at-point () - (and (eq (get-text-property (point) 'face) 'transient-heading) - (let ((beg (line-beginning-position))) - (buffer-substring-no-properties - beg (next-single-property-change - beg 'face nil (line-end-position)))))) - -;;; Compatibility -;;;; Popup Isearch - -(defvar-keymap transient--isearch-mode-map - :parent isearch-mode-map - "<remap> <isearch-exit>" #'transient-isearch-exit - "<remap> <isearch-cancel>" #'transient-isearch-cancel - "<remap> <isearch-abort>" #'transient-isearch-abort) - -(defun transient-isearch-backward (&optional regexp-p) - "Do incremental search backward. -With a prefix argument, do an incremental regular expression -search instead." - (interactive "P") - (transient--isearch-setup) - (let ((isearch-mode-map transient--isearch-mode-map)) - (isearch-mode nil regexp-p))) - -(defun transient-isearch-forward (&optional regexp-p) - "Do incremental search forward. -With a prefix argument, do an incremental regular expression -search instead." - (interactive "P") - (transient--isearch-setup) - (let ((isearch-mode-map transient--isearch-mode-map)) - (isearch-mode t regexp-p))) - -(defun transient-isearch-exit () - "Like `isearch-exit' but adapted for `transient'." - (interactive) - (isearch-exit) - (transient--isearch-exit)) - -(defun transient-isearch-cancel () - "Like `isearch-cancel' but adapted for `transient'." - (interactive) - (condition-case nil (isearch-cancel) (quit)) - (transient--isearch-exit)) - -(defun transient-isearch-abort () - "Like `isearch-abort' but adapted for `transient'." - (interactive) - (let ((around (lambda (fn) - (condition-case nil (funcall fn) (quit)) - (transient--isearch-exit)))) - (advice-add 'isearch-cancel :around around) - (unwind-protect - (isearch-abort) - (advice-remove 'isearch-cancel around)))) - -(defun transient--isearch-setup () - (select-window transient--window) - (transient--suspend-override t)) - -(defun transient--isearch-exit () - (select-window transient--original-window) - (transient--resume-override)) - -;;;; Edebug - -(defun transient--edebug-command-p () - (and (bound-and-true-p edebug-active) - (or (memq this-command '(top-level abort-recursive-edit)) - (string-prefix-p "edebug" (symbol-name this-command))))) - -;;;; Miscellaneous - -(cl-pushnew (list nil (concat "^\\s-*(" - (eval-when-compile - (regexp-opt - '("transient-define-prefix" - "transient-define-suffix" - "transient-define-infix" - "transient-define-argument") - t)) - "\\s-+\\(" lisp-mode-symbol-regexp "\\)") - 2) - lisp-imenu-generic-expression :test #'equal) - -(declare-function which-key-mode "which-key" (&optional arg)) - -(defun transient--suspend-which-key-mode () - (when (bound-and-true-p which-key-mode) - (which-key-mode -1) - (add-hook 'transient-exit-hook #'transient--resume-which-key-mode))) - -(defun transient--resume-which-key-mode () - (unless transient--prefix - (which-key-mode 1) - (remove-hook 'transient-exit-hook #'transient--resume-which-key-mode))) - -(defun transient-bind-q-to-quit () - "Modify some keymaps to bind \"q\" to the appropriate quit command. - -\"C-g\" is the default binding for such commands now, but Transient's -predecessor Magit-Popup used \"q\" instead. If you would like to get -that binding back, then call this function in your init file like so: - - (with-eval-after-load \\='transient - (transient-bind-q-to-quit)) - -Individual transients may already bind \"q\" to something else -and such a binding would shadow the quit binding. If that is the -case then \"Q\" is bound to whatever \"q\" would have been bound -to by setting `transient-substitute-key-function' to a function -that does that. Of course \"Q\" may already be bound to something -else, so that function binds \"M-q\" to that command instead. -Of course \"M-q\" may already be bound to something else, but -we stop there." - (keymap-set transient-base-map "q" #'transient-quit-one) - (keymap-set transient-sticky-map "q" #'transient-quit-seq) - (setq transient-substitute-key-function - #'transient-rebind-quit-commands)) - -(defun transient-rebind-quit-commands (obj) - "See `transient-bind-q-to-quit'." - (let ((key (oref obj key))) - (cond ((string-equal key "q") "Q") - ((string-equal key "Q") "M-q") - (key)))) - -(defun transient--force-fixed-pitch () - (require 'face-remap) - (face-remap-reset-base 'default) - (face-remap-add-relative 'default 'fixed-pitch)) - -(defun transient--func-arity (fn) - (func-arity (advice--cd*r (if (symbolp fn) (symbol-function fn) fn)))) - -(defun transient--seq-reductions-from (function sequence initial-value) - (let ((acc (list initial-value))) - (seq-doseq (elt sequence) - (push (funcall function (car acc) elt) acc)) - (nreverse acc))) - -(defun transient--mapn (function &rest lists) - "Apply FUNCTION to elements of LISTS. -Like `cl-mapcar' but while that stops when the shortest list -is exhausted, continue until the longest list is, using nil -as stand-in for elements of exhausted lists." - (let (result) - (while (catch 'more (mapc (lambda (l) (and l (throw 'more t))) lists) nil) - (push (apply function (mapcar #'car-safe lists)) result) - (setq lists (mapcar #'cdr lists))) - (nreverse result))) - -;;; Font-Lock - -(defconst transient-font-lock-keywords - (eval-when-compile - `((,(concat "(" - (regexp-opt (list "transient-define-prefix" - "transient-define-infix" - "transient-define-argument" - "transient-define-suffix") - t) - "\\_>[ \t'(]*" - "\\(\\(?:\\sw\\|\\s_\\)+\\)?") - (1 'font-lock-keyword-face) - (2 'font-lock-function-name-face nil t))))) - -(font-lock-add-keywords 'emacs-lisp-mode transient-font-lock-keywords) - -;;; Auxiliary Classes -;;;; `transient-lisp-variable' - -(defclass transient-lisp-variable (transient-variable) - ((reader :initform #'transient-lisp-variable--reader) - (always-read :initform t) - (set-value :initarg :set-value :initform #'set)) - "[Experimental] Class used for Lisp variables.") - -(cl-defmethod transient-init-value ((obj transient-lisp-variable)) - (oset obj value (symbol-value (oref obj variable)))) - -(cl-defmethod transient-infix-set ((obj transient-lisp-variable) value) - (funcall (oref obj set-value) - (oref obj variable) - (oset obj value value))) - -(cl-defmethod transient-format-description ((obj transient-lisp-variable)) - (or (cl-call-next-method obj) - (symbol-name (oref obj variable)))) - -(cl-defmethod transient-format-value ((obj transient-lisp-variable)) - (propertize (prin1-to-string (oref obj value)) - 'face 'transient-value)) - -(cl-defmethod transient-prompt ((obj transient-lisp-variable)) - (if (and (slot-boundp obj 'prompt) - (oref obj prompt)) - (cl-call-next-method obj) - (format "Set %s: " (oref obj variable)))) - -(defun transient-lisp-variable--reader (prompt initial-input _history) - (read--expression prompt initial-input)) - -;;; _ -(provide 'transient) -;; Local Variables: -;; indent-tabs-mode: nil -;; checkdoc-symbol-words: ("command-line" "edit-mode" "help-mode") -;; End: -;;; transient.el ends here diff --git a/emacs/elpa/transient-20240805.1231/transient.info b/emacs/elpa/transient-20240805.1231/transient.info @@ -1,3318 +0,0 @@ -This is transient.info, produced by makeinfo version 6.8 from -transient.texi. - - Copyright (C) 2018–2024 Free Software Foundation, Inc. - - You can redistribute this document 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 document 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. - -INFO-DIR-SECTION Emacs misc features -START-INFO-DIR-ENTRY -* Transient: (transient). Transient Commands. -END-INFO-DIR-ENTRY - - -File: transient.info, Node: Top, Next: Introduction, Up: (dir) - -Transient User and Developer Manual -*********************************** - -Transient is the library used to implement the keyboard-driven “menus” -in Magit. It is distributed as a separate package, so that it can be -used to implement similar menus in other packages. - - This manual can be bit hard to digest when getting started. A useful -resource to get over that hurdle is Psionic K’s interactive tutorial, -available at <https://github.com/positron-solutions/transient-showcase>. - -This manual is for Transient version 0.7.4. - - Copyright (C) 2018–2024 Free Software Foundation, Inc. - - You can redistribute this document 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 document 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. - -* Menu: - -* Introduction:: -* Usage:: -* Modifying Existing Transients:: -* Defining New Commands:: -* Classes and Methods:: -* FAQ:: -* Keystroke Index:: -* Command and Function Index:: -* Variable Index:: -* Concept Index:: -* GNU General Public License:: - -— The Detailed Node Listing — - -Usage - -* Invoking Transients:: -* Aborting and Resuming Transients:: -* Common Suffix Commands:: -* Saving Values:: -* Using History:: -* Getting Help for Suffix Commands:: -* Enabling and Disabling Suffixes:: -* Other Commands:: -* Configuration:: - -Defining New Commands - -* Technical Introduction:: -* Defining Transients:: -* Binding Suffix and Infix Commands:: -* Defining Suffix and Infix Commands:: -* Using Infix Arguments:: -* Transient State:: - -Binding Suffix and Infix Commands - -* Group Specifications:: -* Suffix Specifications:: - - -Classes and Methods - -* Group Classes:: -* Group Methods:: -* Prefix Classes:: -* Suffix Classes:: -* Suffix Methods:: -* Prefix Slots:: -* Suffix Slots:: -* Predicate Slots:: - -Suffix Methods - -* Suffix Value Methods:: -* Suffix Format Methods:: - - - - -File: transient.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top - -1 Introduction -************** - -Transient is the library used to implement the keyboard-driven “menus” -in Magit. It is distributed as a separate package, so that it can be -used to implement similar menus in other packages. - - This manual can be bit hard to digest when getting started. A useful -resource to get over that hurdle is Psionic K’s interactive tutorial, -available at <https://github.com/positron-solutions/transient-showcase>. - -Some things that Transient can do -================================= - - • Display current state of arguments - • Display and manage lifecycle of modal bindings - • Contextual user interface - • Flow control for wizard-like composition of interactive forms - • History & persistence - • Rendering arguments for controlling CLI programs - -Complexity in CLI programs -========================== - -Complexity tends to grow with time. How do you manage the complexity of -commands? Consider the humble shell command ‘ls’. It now has over -_fifty_ command line options. Some of these are boolean flags (‘ls --l’). Some take arguments (‘ls --sort=s’). Some have no effect unless -paired with other flags (‘ls -lh’). Some are mutually exclusive. Some -shell commands even have so many options that they introduce -_subcommands_ (‘git branch’, ‘git commit’), each with their own rich set -of options (‘git branch -f’). - -Using Transient for composing interactive commands -================================================== - -What about Emacs commands used interactively? How do these handle -options? One solution is to make many versions of the same command, so -you don’t need to! Consider: ‘delete-other-windows’ vs. -‘delete-other-windows-vertically’ (among many similar examples). - - Some Emacs commands will simply prompt you for the next "argument" -(‘M-x switch-to-buffer’). Another common solution is to use prefix -arguments which usually start with ‘C-u’. Sometimes these are sensibly -numerical in nature (‘C-u 4 M-x forward-paragraph’ to move forward 4 -paragraphs). But sometimes they function instead as boolean "switches" -(‘C-u C-SPACE’ to jump to the last mark instead of just setting it, ‘C-u -C-u C-SPACE’ to unconditionally set the mark). Since there aren’t many -standards for the use of prefix options, you have to read the command’s -documentation to find out what the possibilities are. - - But when an Emacs command grows to have a truly large set of options -and arguments, with dependencies between them, lots of option values, -etc., these simple approaches just don’t scale. Transient is designed -to solve this issue. Think of it as the humble prefix argument ‘C-u’, -_raised to the power of 10_. Like ‘C-u’, it is key driven. Like the -shell, it supports boolean "flag" options, options that take arguments, -and even "sub-commands", with their own options. But instead of -searching through a man page or command documentation, well-designed -transients _guide_ their users to the relevant set of options (and even -their possible values!) directly, taking into account any important -pre-existing Emacs settings. And while for shell commands like ‘ls’, -there is only one way to "execute" (hit ‘Return’!), transients can -"execute" using multiple different keys tied to one of many -self-documenting _actions_ (imagine having 5 different colored return -keys on your keyboard!). Transients make navigating and setting large, -complex groups of command options and arguments easy. Fun even. Once -you’ve tried it, it’s hard to go back to the ‘C-u what can I do here -again?’ way. - - -File: transient.info, Node: Usage, Next: Modifying Existing Transients, Prev: Introduction, Up: Top - -2 Usage -******* - -* Menu: - -* Invoking Transients:: -* Aborting and Resuming Transients:: -* Common Suffix Commands:: -* Saving Values:: -* Using History:: -* Getting Help for Suffix Commands:: -* Enabling and Disabling Suffixes:: -* Other Commands:: -* Configuration:: - - -File: transient.info, Node: Invoking Transients, Next: Aborting and Resuming Transients, Up: Usage - -2.1 Invoking Transients -======================= - -A transient prefix command is invoked like any other command by pressing -the key that is bound to that command. The main difference to other -commands is that a transient prefix command activates a transient -keymap, which temporarily binds the transient’s infix and suffix -commands. Bindings from other keymaps may, or may not, be disabled -while the transient state is in effect. - - There are two kinds of commands that are available after invoking a -transient prefix command; infix and suffix commands. Infix commands set -some value (which is then shown in a popup buffer), without leaving the -transient. Suffix commands, on the other hand, usually quit the -transient and they may use the values set by the infix commands, i.e., -the infix *arguments*. - - Instead of setting arguments to be used by a suffix command, infix -commands may also set some value by side-effect, e.g., by setting the -value of some variable. - - -File: transient.info, Node: Aborting and Resuming Transients, Next: Common Suffix Commands, Prev: Invoking Transients, Up: Usage - -2.2 Aborting and Resuming Transients -==================================== - -To quit the transient without invoking a suffix command press ‘C-g’. - - Key bindings in transient keymaps may be longer than a single event. -After pressing a valid prefix key, all commands whose bindings do not -begin with that prefix key are temporarily unavailable and grayed out. -To abort the prefix key press ‘C-g’ (which in this case only quits the -prefix key, but not the complete transient). - - A transient prefix command can be bound as a suffix of another -transient. Invoking such a suffix replaces the current transient state -with a new transient state, i.e., the available bindings change and the -information displayed in the popup buffer is updated accordingly. -Pressing ‘C-g’ while a nested transient is active only quits the -innermost transient, causing a return to the previous transient. - - ‘C-q’ or ‘C-z’ on the other hand always exits all transients. If you -use the latter, then you can later resume the stack of transients using -‘M-x transient-resume’. - -‘C-g’ (‘transient-quit-seq’) -‘C-g’ (‘transient-quit-one’) - This key quits the currently active incomplete key sequence, if - any, or else the current transient. When quitting the current - transient, it returns to the previous transient, if any. - - Transient’s predecessor bound ‘q’ instead of ‘C-g’ to the quit -command. To learn how to get that binding back see -‘transient-bind-q-to-quit’’s documentation string. - -‘C-q’ (‘transient-quit-all’) - This command quits the currently active incomplete key sequence, if - any, and all transients, including the active transient and all - suspended transients, if any. - -‘C-z’ (‘transient-suspend’) - Like ‘transient-quit-all’, this command quits an incomplete key - sequence, if any, and all transients. Additionally, it saves the - stack of transients so that it can easily be resumed (which is - particularly useful if you quickly need to do “something else” and - the stack is deeper than a single transient, and/or you have - already changed the values of some infix arguments). - - Note that only a single stack of transients can be saved at a time. - If another stack is already saved, then saving a new stack discards - the previous stack. - -‘M-x transient-resume’ - This command resumes the previously suspended stack of transients, - if any. - - -File: transient.info, Node: Common Suffix Commands, Next: Saving Values, Prev: Aborting and Resuming Transients, Up: Usage - -2.3 Common Suffix Commands -========================== - -A few shared suffix commands are available in all transients. These -suffix commands are not shown in the popup buffer by default. - - This includes the aborting commands mentioned in the previous -section, as well as some other commands that are all bound to ‘C-x KEY’. -After ‘C-x’ is pressed, a section featuring all these common commands is -temporarily shown in the popup buffer. After invoking one of them, the -section disappears again. Note, however, that one of these commands is -described as “Show common permanently”; invoke that if you want the -common commands to always be shown for all transients. - -‘C-x t’ (‘transient-toggle-common’) - This command toggles whether the generic commands that are common - to all transients are always displayed or only after typing the - incomplete prefix key sequence ‘C-x’. This only affects the - current Emacs session. - - -- User Option: transient-show-common-commands - This option controls whether shared suffix commands are shown - alongside the transient-specific infix and suffix commands. By - default, the shared commands are not shown to avoid overwhelming - the user with too many options. - - While a transient is active, pressing ‘C-x’ always shows the common - commands. The value of this option can be changed for the current - Emacs session by typing ‘C-x t’ while a transient is active. - - The other common commands are described in either the previous or in -one of the following sections. - - Some of Transient’s key bindings differ from the respective bindings -of Magit-Popup; see *note FAQ:: for more information. - - -File: transient.info, Node: Saving Values, Next: Using History, Prev: Common Suffix Commands, Up: Usage - -2.4 Saving Values -================= - -After setting the infix arguments in a transient, the user can save -those arguments for future invocations. - - Most transients will start out with the saved arguments when they are -invoked. There are a few exceptions, though. Some transients are -designed so that the value that they use is stored externally as the -buffer-local value of some variable. Invoking such a transient again -uses the buffer-local value. (1) - - If the user does not save the value and just exits using a regular -suffix command, then the value is merely saved to the transient’s -history. That value won’t be used when the transient is next invoked, -but it is easily accessible (see *note Using History::). - -‘C-x s’ (‘transient-set’) - This command saves the value of the active transient for this Emacs - session. - -‘C-x C-s’ (‘transient-save’) - Save the value of the active transient persistently across Emacs - sessions. - -‘C-x C-k’ (‘transient-reset’) - Clear the set and saved values of the active transient. - - -- User Option: transient-values-file - This option names the file that is used to persist the values of - transients between Emacs sessions. - - ---------- Footnotes ---------- - - (1) ‘magit-diff’ and ‘magit-log’ are two prominent examples, and -their handling of buffer-local values is actually a bit more complicated -than outlined above and even customizable. - - -File: transient.info, Node: Using History, Next: Getting Help for Suffix Commands, Prev: Saving Values, Up: Usage - -2.5 Using History -================= - -Every time the user invokes a suffix command the transient’s current -value is saved to its history. These values can be cycled through the -same way one can cycle through the history of commands that read -user-input in the minibuffer. - -‘C-M-p’ (‘transient-history-prev’) -‘C-x p’ - This command switches to the previous value used for the active - transient. - -‘C-M-n’ (‘transient-history-next’) -‘C-x n’ - This command switches to the next value used for the active - transient. - - In addition to the transient-wide history, Transient of course -supports per-infix history. When an infix reads user-input using the -minibuffer, the user can use the regular minibuffer history commands to -cycle through previously used values. Usually the same keys as those -mentioned above are bound to those commands. - - Authors of transients should arrange for different infix commands -that read the same kind of value to also use the same history key (see -*note Suffix Slots::). - - Both kinds of history are saved to a file when Emacs is exited. - - -- User Option: transient-history-file - This option names the file that is used to persist the history of - transients and their infixes between Emacs sessions. - - -- User Option: transient-history-limit - This option controls how many history elements are kept at the time - the history is saved in ‘transient-history-file’. - - -File: transient.info, Node: Getting Help for Suffix Commands, Next: Enabling and Disabling Suffixes, Prev: Using History, Up: Usage - -2.6 Getting Help for Suffix Commands -==================================== - -Transients can have many suffixes and infixes that the user might not be -familiar with. To make it trivial to get help for these, Transient -provides access to the documentation directly from the active transient. - -‘C-h’ (‘transient-help’) - This command enters help mode. When help mode is active, typing a - key shows information about the suffix command that the key - normally is bound to (instead of invoking it). Pressing ‘C-h’ a - second time shows information about the _prefix_ command. - - After typing a key, the stack of transient states is suspended and - information about the suffix command is shown instead. Typing ‘q’ - in the help buffer buries that buffer and resumes the transient - state. - - What sort of documentation is shown depends on how the transient was -defined. For infix commands that represent command-line arguments this -ideally shows the appropriate manpage. ‘transient-help’ then tries to -jump to the correct location within that. Info manuals are also -supported. The fallback is to show the command’s documentation string, -for non-infix suffixes this is usually appropriate. - - -File: transient.info, Node: Enabling and Disabling Suffixes, Next: Other Commands, Prev: Getting Help for Suffix Commands, Up: Usage - -2.7 Enabling and Disabling Suffixes -=================================== - -The user base of a package that uses transients can be very diverse. -This is certainly the case for Magit; some users have been using it and -Git for a decade, while others are just getting started now. - - For that reason a mechanism is needed that authors can use to -classify a transient’s infixes and suffixes along the -essentials...everything spectrum. We use the term “levels” to describe -that mechanism. - - Each suffix command is placed on a level and each transient has a -level (called “transient-level”), which controls which suffix commands -are available. Integers between 1 and 7 (inclusive) are valid levels. -For suffixes, 0 is also valid; it means that the suffix is not displayed -at any level. - - The levels of individual transients and/or their individual suffixes -can be changed interactively, by invoking the transient and then -pressing ‘C-x l’ to enter the “edit” mode, see below. - - The default level for both transients and their suffixes is 4. The -‘transient-default-level’ option only controls the default for -transients. The default suffix level is always 4. The authors of -transients should place certain suffixes on a higher level, if they -expect that it won’t be of use to most users, and they should place very -important suffixes on a lower level, so that they remain available even -if the user lowers the transient level. - - -- User Option: transient-default-level - This option controls which suffix levels are made available by - default. It sets the transient-level for transients for which the - user has not set that individually. - - -- User Option: transient-levels-file - This option names the file that is used to persist the levels of - transients and their suffixes between Emacs sessions. - -‘C-x l’ (‘transient-set-level’) - This command enters edit mode. When edit mode is active, then all - infixes and suffixes that are currently usable are displayed along - with their levels. The colors of the levels indicate whether they - are enabled or not. The level of the transient is also displayed - along with some usage information. - - In edit mode, pressing the key that would usually invoke a certain - suffix instead prompts the user for the level that suffix should be - placed on. - - Help mode is available in edit mode. - - To change the transient level press ‘C-x l’ again. - - To exit edit mode press ‘C-g’. - - Note that edit mode does not display any suffixes that are not - currently usable. ‘magit-rebase’, for example, shows different - suffixes depending on whether a rebase is already in progress or - not. The predicates also apply in edit mode. - - Therefore, to control which suffixes are available given a certain - state, you have to make sure that that state is currently active. - -‘C-x a’ (‘transient-toggle-level-limit’) - This command toggle whether suffixes that are on levels higher than - the level specified by ‘transient-default-level’ are temporarily - available anyway. - - -File: transient.info, Node: Other Commands, Next: Configuration, Prev: Enabling and Disabling Suffixes, Up: Usage - -2.8 Other Commands -================== - -When invoking a transient in a small frame, the transient window may not -show the complete buffer, making it necessary to scroll, using the -following commands. These commands are never shown in the transient -window, and the key bindings are the same as for ‘scroll-up-command’ and -‘scroll-down-command’ in other buffers. - - -- Command: transient-scroll-up arg - This command scrolls text of transient popup window upward ARG - lines. If ARG is ‘nil’, then it scrolls near full screen. This is - a wrapper around ‘scroll-up-command’ (which see). - - -- Command: transient-scroll-down arg - This command scrolls text of transient popup window down ARG lines. - If ARG is ‘nil’, then it scrolls near full screen. This is a - wrapper around ‘scroll-down-command’ (which see). - - -File: transient.info, Node: Configuration, Prev: Other Commands, Up: Usage - -2.9 Configuration -================= - -More options are described in *note Common Suffix Commands::, in *note -Saving Values::, in *note Using History:: and in *note Enabling and -Disabling Suffixes::. - -Essential Options ------------------ - -Also see *note Common Suffix Commands::. - - -- User Option: transient-show-popup - This option controls whether the current transient’s infix and - suffix commands are shown in the popup buffer. - - • If ‘t’ (the default) then the popup buffer is shown as soon as - a transient prefix command is invoked. - - • If ‘nil’, then the popup buffer is not shown unless the user - explicitly requests it, by pressing an incomplete prefix key - sequence. - - • If a number, then the a brief one-line summary is shown - instead of the popup buffer. If zero or negative, then not - even that summary is shown; only the pressed key itself is - shown. - - The popup is shown when the user explicitly requests it by - pressing an incomplete prefix key sequence. Unless this is - zero, the popup is shown after that many seconds of inactivity - (using the absolute value). - - -- User Option: transient-enable-popup-navigation - This option controls whether navigation commands are enabled in the - transient popup buffer. - - While a transient is active the transient popup buffer is not the - current buffer, making it necessary to use dedicated commands to - act on that buffer itself. This is disabled by default. If this - option is non-‘nil’, then the following features are available: - - • ‘<UP>’ moves the cursor to the previous suffix. - • ‘<DOWN>’ moves the cursor to the next suffix. - • ‘<RET>’ invokes the suffix the cursor is on. - • ‘mouse-1’ invokes the clicked on suffix. - • ‘C-s’ and ‘C-r’ start isearch in the popup buffer. - - -- User Option: transient-display-buffer-action - This option specifies the action used to display the transient - popup buffer. The transient popup buffer is displayed in a window - using ‘(display-buffer BUFFER transient-display-buffer-action)’. - - The value of this option has the form ‘(FUNCTION . ALIST)’, where - FUNCTION is a function or a list of functions. Each such function - should accept two arguments: a buffer to display and an alist of - the same form as ALIST. See *note (elisp)Choosing Window::, for - details. - - The default is: - - (display-buffer-in-side-window - (side . bottom) - (inhibit-same-window . t) - (window-parameters (no-other-window . t))) - - This displays the window at the bottom of the selected frame. - Another useful FUNCTION is ‘display-buffer-below-selected’, which - is what ‘magit-popup’ used by default. For more alternatives see - *note (elisp)Buffer Display Action Functions::, and *note - (elisp)Buffer Display Action Alists::. - - Note that the buffer that was current before the transient buffer - is shown should remain the current buffer. Many suffix commands - act on the thing at point, if appropriate, and if the transient - buffer became the current buffer, then that would change what is at - point. To that effect ‘inhibit-same-window’ ensures that the - selected window is not used to show the transient buffer. - - It may be possible to display the window in another frame, but - whether that works in practice depends on the window-manager. If - the window manager selects the new window (Emacs frame), then that - unfortunately changes which buffer is current. - - If you change the value of this option, then you might also want to - change the value of ‘transient-mode-line-format’. - -Accessibility Options ---------------------- - - -- User Option: transient-force-single-column - This option controls whether the use of a single column to display - suffixes is enforced. This might be useful for users with low - vision who use large text and might otherwise have to scroll in two - dimensions. - -Auxiliary Options ------------------ - - -- User Option: transient-mode-line-format - This option controls whether the transient popup buffer has a - mode-line, separator line, or neither. - - If ‘nil’, then the buffer has no mode-line. If the buffer is not - displayed right above the echo area, then this probably is not a - good value. - - If ‘line’ (the default) or a natural number, then the buffer has no - mode-line, but a line is drawn is drawn in its place. If a number - is used, that specifies the thickness of the line. On termcap - frames we cannot draw lines, so there ‘line’ and numbers are - synonyms for ‘nil’. - - The color of the line is used to indicate if non-suffixes are - allowed and whether they exit the transient. The foreground color - of ‘transient-key-noop’ (if non-suffix are disallowed), - ‘transient-key-stay’ (if allowed and transient stays active), or - ‘transient-key-exit’ (if allowed and they exit the transient) is - used to draw the line. - - Otherwise this can be any mode-line format. See *note (elisp)Mode - Line Format::, for details. - - -- User Option: transient-semantic-coloring - This option controls whether colors are used to indicate the - transient behavior of commands. - - If non-‘nil’, then the key binding of each suffix is colorized to - indicate whether it exits the transient state or not. The color of - the prefix is indicated using the line that is drawn when the value - of ‘transient-mode-line-format’ is ‘line’. - - -- User Option: transient-highlight-mismatched-keys - This option controls whether key bindings of infix commands that do - not match the respective command-line argument should be - highlighted. For other infix commands this option has no effect. - - When this option is non-‘nil’, the key binding for an infix - argument is highlighted when only a long argument (e.g., - ‘--verbose’) is specified but no shorthand (e.g., ‘-v’). In the - rare case that a shorthand is specified but the key binding does - not match, then it is highlighted differently. - - Highlighting mismatched key bindings is useful when learning the - arguments of the underlying command-line tool; you wouldn’t want to - learn any short-hands that do not actually exist. - - The highlighting is done using one of the faces - ‘transient-mismatched-key’ and ‘transient-nonstandard-key’. - - -- User Option: transient-substitute-key-function - This function is used to modify key bindings. If the value of this - option is ‘nil’ (the default), then no substitution is performed. - - This function is called with one argument, the prefix object, and - must return a key binding description, either the existing key - description it finds in the ‘key’ slot, or the key description that - replaces the prefix key. It could be used to make other - substitutions, but that is discouraged. - - For example, ‘=’ is hard to reach using my custom keyboard layout, - so I substitute ‘(’ for that, which is easy to reach using a layout - optimized for lisp. - - (setq transient-substitute-key-function - (lambda (obj) - (let ((key (oref obj key))) - (if (string-match "\\`\\(=\\)[a-zA-Z]" key) - (replace-match "(" t t key 1) - key)))) - - -- User Option: transient-read-with-initial-input - This option controls whether the last history element is used as - the initial minibuffer input when reading the value of an infix - argument from the user. If ‘nil’, there is no initial input and - the first element has to be accessed the same way as the older - elements. - - -- User Option: transient-hide-during-minibuffer-read - This option controls whether the transient buffer is hidden while - user input is being read in the minibuffer. - - -- User Option: transient-align-variable-pitch - This option controls whether columns are aligned pixel-wise in the - popup buffer. - - If this is non-‘nil’, then columns are aligned pixel-wise to - support variable-pitch fonts. Keys are not aligned, so you should - use a fixed-pitch font for the ‘transient-key’ face. Other key - faces inherit from that face unless a theme is used that breaks - that relationship. - - This option is intended for users who use a variable-pitch font for - the ‘default’ face. - - -- User Option: transient-force-fixed-pitch - This option controls whether to force the use of a monospaced font - in popup buffer. Even if you use a proportional font for the - ‘default’ face, you might still want to use a monospaced font in - transient’s popup buffer. Setting this option to ‘t’ causes - ‘default’ to be remapped to ‘fixed-pitch’ in that buffer. - -Developer Options ------------------ - -These options are mainly intended for developers. - - -- User Option: transient-detect-key-conflicts - This option controls whether key binding conflicts should be - detected at the time the transient is invoked. If so, this results - in an error, which prevents the transient from being used. Because - of that, conflicts are ignored by default. - - Conflicts cannot be determined earlier, i.e., when the transient is - being defined and when new suffixes are being added, because at - that time there can be false-positives. It is actually valid for - multiple suffixes to share a common key binding, provided the - predicates of those suffixes prevent that more than one of them is - enabled at a time. - - -- User Option: transient-highlight-higher-levels - This option controls whether suffixes that would not be available - by default are highlighted. - - When non-‘nil’ then the descriptions of suffixes are highlighted if - their level is above 4, the default of ‘transient-default-level’. - Assuming you have set that variable to 7, this highlights all - suffixes that won’t be available to users without them making the - same customization. - - -File: transient.info, Node: Modifying Existing Transients, Next: Defining New Commands, Prev: Usage, Up: Top - -3 Modifying Existing Transients -******************************* - -To an extent, transients can be customized interactively, see *note -Enabling and Disabling Suffixes::. This section explains how existing -transients can be further modified non-interactively. Let’s begin with -an example: - - (transient-append-suffix 'magit-patch-apply "-3" - '("-R" "Apply in reverse" "--reverse")) - - This inserts a new infix argument to toggle the ‘--reverse’ argument -after the infix argument that toggles ‘-3’ in ‘magit-patch-apply’. - - The following functions share a few arguments: - - • PREFIX is a transient prefix command, a symbol. - - • SUFFIX is a transient infix or suffix specification in the same - form as expected by ‘transient-define-prefix’. Note that an infix - is a special kind of suffix. Depending on context “suffixes” means - “suffixes (including infixes)” or “non-infix suffixes”. Here it - means the former. See *note Suffix Specifications::. - - SUFFIX may also be a group in the same form as expected by - ‘transient-define-prefix’. See *note Group Specifications::. - - • LOC is a command, a key vector, a key description (a string as - returned by ‘key-description’), or a list specifying coordinates - (the last element may also be a command or key). For example ‘(1 0 - -1)’ identifies the last suffix (‘-1’) of the first subgroup (‘0’) - of the second group (‘1’). - - If LOC is a list of coordinates, then it can be used to identify a - group, not just an individual suffix command. - - The function ‘transient-get-suffix’ can be useful to determine - whether a certain coordination list identifies the suffix or group - that you expect it to identify. In hairy cases it may be necessary - to look at the definition of the transient prefix command. - - These functions operate on the information stored in the -‘transient--layout’ property of the PREFIX symbol. Suffix entries in -that tree are not objects but have the form ‘(LEVEL CLASS PLIST)’, where -PLIST should set at least ‘:key’, ‘:description’ and ‘:command’. - - -- Function: transient-insert-suffix prefix loc suffix &optional - keep-other - -- Function: transient-append-suffix prefix loc suffix &optional - keep-other - These functions insert the suffix or group SUFFIX into PREFIX - before or after LOC. - - Conceptually adding a binding to a transient prefix is similar to - adding a binding to a keymap, but this is complicated by the fact - that multiple suffix commands can be bound to the same key, - provided they are never active at the same time, see *note - Predicate Slots::. - - Unfortunately both false-positives and false-negatives are - possible. To deal with the former use non-‘nil’ KEEP-OTHER. To - deal with the latter remove the conflicting binding explicitly. - - -- Function: transient-replace-suffix prefix loc suffix - This function replaces the suffix or group at LOC in PREFIX with - suffix or group SUFFIX. - - -- Function: transient-remove-suffix prefix loc - This function removes the suffix or group at LOC in PREFIX. - - -- Function: transient-get-suffix prefix loc - This function returns the suffix or group at LOC in PREFIX. The - returned value has the form mentioned above. - - -- Function: transient-suffix-put prefix loc prop value - This function edits the suffix or group at LOC in PREFIX, by - setting the PROP of its plist to VALUE. - - Most of these functions do not signal an error if they cannot perform -the requested modification. The functions that insert new suffixes show -a warning if LOC cannot be found in PREFIX without signaling an error. -The reason for doing it like this is that establishing a key binding -(and that is what we essentially are trying to do here) should not -prevent the rest of the configuration from loading. Among these -functions only ‘transient-get-suffix’ and ‘transient-suffix-put’ may -signal an error. - - -File: transient.info, Node: Defining New Commands, Next: Classes and Methods, Prev: Modifying Existing Transients, Up: Top - -4 Defining New Commands -*********************** - -* Menu: - -* Technical Introduction:: -* Defining Transients:: -* Binding Suffix and Infix Commands:: -* Defining Suffix and Infix Commands:: -* Using Infix Arguments:: -* Transient State:: - - -File: transient.info, Node: Technical Introduction, Next: Defining Transients, Up: Defining New Commands - -4.1 Technical Introduction -========================== - -Taking inspiration from prefix keys and prefix arguments, Transient -implements a similar abstraction involving a prefix command, infix -arguments and suffix commands. - - When the user calls a transient prefix command, a transient -(temporary) keymap is activated, which binds the transient’s infix and -suffix commands, and functions that control the transient state are -added to ‘pre-command-hook’ and ‘post-command-hook’. The available -suffix and infix commands and their state are shown in a popup buffer -until the transient state is exited by invoking a suffix command. - - Calling an infix command causes its value to be changed. How that is -done depends on the type of the infix command. The simplest case is an -infix command that represents a command-line argument that does not take -a value. Invoking such an infix command causes the switch to be toggled -on or off. More complex infix commands may read a value from the user, -using the minibuffer. - - Calling a suffix command usually causes the transient to be exited; -the transient keymaps and hook functions are removed, the popup buffer -no longer shows information about the (no longer bound) suffix commands, -the values of some public global variables are set, while some internal -global variables are unset, and finally the command is actually called. -Suffix commands can also be configured to not exit the transient. - - A suffix command can, but does not have to, use the infix arguments -in much the same way any command can choose to use or ignore the prefix -arguments. For a suffix command that was invoked from a transient, the -variable ‘transient-current-suffixes’ and the function ‘transient-args’ -serve about the same purpose as the variables ‘prefix-arg’ and -‘current-prefix-arg’ do for any command that was called after the prefix -arguments have been set using a command such as ‘universal-argument’. - - Transient can be used to implement simple “command dispatchers”. The -main benefit then is that the user can see all the available commands in -a popup buffer, which can be thought of as a “menus”. That is useful by -itself because it frees the user from having to remember all the keys -that are valid after a certain prefix key or command. Magit’s -‘magit-dispatch’ (on ‘C-x M-g’) command is an example of using Transient -to merely implement a command dispatcher. - - In addition to that, Transient also allows users to interactively -pass arguments to commands. These arguments can be much more complex -than what is reasonable when using prefix arguments. There is a limit -to how many aspects of a command can be controlled using prefix -arguments. Furthermore, what a certain prefix argument means for -different commands can be completely different, and users have to read -documentation to learn and then commit to memory what a certain prefix -argument means to a certain command. - - Transient suffix commands, on the other hand, can accept dozens of -different arguments without the user having to remember anything. When -using Transient, one can call a command with arguments that are just as -complex as when calling the same function non-interactively from Lisp. - - Invoking a transient suffix command with arguments is similar to -invoking a command in a shell with command-line completion and history -enabled. One benefit of the Transient interface is that it remembers -history not only on a global level (“this command was invoked using -these arguments, and previously it was invoked using those other -arguments”), but also remembers the values of individual arguments -independently. See *note Using History::. - - After a transient prefix command is invoked, ‘C-h KEY’ can be used to -show the documentation for the infix or suffix command that ‘KEY’ is -bound to (see *note Getting Help for Suffix Commands::), and infixes and -suffixes can be removed from the transient using ‘C-x l KEY’. Infixes -and suffixes that are disabled by default can be enabled the same way. -See *note Enabling and Disabling Suffixes::. - - Transient ships with support for a few different types of specialized -infix commands. A command that sets a command line option, for example, -has different needs than a command that merely toggles a boolean flag. -Additionally, Transient provides abstractions for defining new types, -which the author of Transient did not anticipate (or didn’t get around -to implementing yet). - - Note that suffix commands also support regular prefix arguments. A -suffix command may even be called with both infix and prefix arguments -at the same time. If you invoke a command as a suffix of a transient -prefix command, but also want to pass prefix arguments to it, then first -invoke the prefix command, and only after doing that invoke the prefix -arguments, before finally invoking the suffix command. If you instead -began by providing the prefix arguments, then those would apply to the -prefix command, not the suffix command. Likewise, if you want to change -infix arguments before invoking a suffix command with prefix arguments, -then change the infix arguments before invoking the prefix arguments. -In other words, regular prefix arguments always apply to the next -command, and since transient prefix, infix and suffix commands are just -regular commands, the same applies to them. (Regular prefix keys behave -differently because they are not commands at all, instead they are just -incomplete key sequences, and those cannot be interrupted with prefix -commands.) - - -File: transient.info, Node: Defining Transients, Next: Binding Suffix and Infix Commands, Prev: Technical Introduction, Up: Defining New Commands - -4.2 Defining Transients -======================= - -A transient consists of a prefix command and at least one suffix -command, though usually a transient has several infix and suffix -commands. The below macro defines the transient prefix command *and* -binds the transient’s infix and suffix commands. In other words, it -defines the complete transient, not just the transient prefix command -that is used to invoke that transient. - - -- Macro: transient-define-prefix name arglist [docstring] [keyword - value]... group... [body...] - This macro defines NAME as a transient prefix command and binds the - transient’s infix and suffix commands. - - ARGLIST are the arguments that the prefix command takes. DOCSTRING - is the documentation string and is optional. - - These arguments can optionally be followed by keyword-value pairs. - Each key has to be a keyword symbol, either ‘:class’ or a keyword - argument supported by the constructor of that class. The - ‘transient-prefix’ class is used if the class is not specified - explicitly. - - GROUPs add key bindings for infix and suffix commands and specify - how these bindings are presented in the popup buffer. At least one - GROUP has to be specified. See *note Binding Suffix and Infix - Commands::. - - The BODY is optional. If it is omitted, then ARGLIST is ignored - and the function definition becomes: - - (lambda () - (interactive) - (transient-setup 'NAME)) - - If BODY is specified, then it must begin with an ‘interactive’ form - that matches ARGLIST, and it must call ‘transient-setup’. It may, - however, call that function only when some condition is satisfied. - - All transients have a (possibly ‘nil’) value, which is exported - when suffix commands are called, so that they can consume that - value. For some transients it might be necessary to have a sort of - secondary value, called a “scope”. Such a scope would usually be - set in the command’s ‘interactive’ form and has to be passed to the - setup function: - - (transient-setup 'NAME nil nil :scope SCOPE) - - For example, the scope of the ‘magit-branch-configure’ transient is - the branch whose variables are being configured. - - -File: transient.info, Node: Binding Suffix and Infix Commands, Next: Defining Suffix and Infix Commands, Prev: Defining Transients, Up: Defining New Commands - -4.3 Binding Suffix and Infix Commands -===================================== - -The macro ‘transient-define-prefix’ is used to define a transient. This -defines the actual transient prefix command (see *note Defining -Transients::) and adds the transient’s infix and suffix bindings, as -described below. - - Users and third-party packages can add additional bindings using -functions such as ‘transient-insert-suffix’ (see *note Modifying -Existing Transients::). These functions take a “suffix specification” -as one of their arguments, which has the same form as the specifications -used in ‘transient-define-prefix’. - -* Menu: - -* Group Specifications:: -* Suffix Specifications:: - - -File: transient.info, Node: Group Specifications, Next: Suffix Specifications, Up: Binding Suffix and Infix Commands - -4.3.1 Group Specifications --------------------------- - -The suffix and infix commands of a transient are organized in groups. -The grouping controls how the descriptions of the suffixes are outlined -visually but also makes it possible to set certain properties for a set -of suffixes. - - Several group classes exist, some of which organize suffixes in -subgroups. In most cases the class does not have to be specified -explicitly, but see *note Group Classes::. - - Groups are specified in the call to ‘transient-define-prefix’, using -vectors. Because groups are represented using vectors, we cannot use -square brackets to indicate an optional element and instead use curly -brackets to do the latter. - - Group specifications then have this form: - - [{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...] - - The LEVEL is optional and defaults to 4. See *note Enabling and -Disabling Suffixes::. - - The DESCRIPTION is optional. If present, it is used as the heading -of the group. - - The KEYWORD-VALUE pairs are optional. Each keyword has to be a -keyword symbol, either ‘:class’ or a keyword argument supported by the -constructor of that class. - - • One of these keywords, ‘:description’, is equivalent to specifying - DESCRIPTION at the very beginning of the vector. The - recommendation is to use ‘:description’ if some other keyword is - also used, for consistency, or DESCRIPTION otherwise, because it - looks better. - - • Likewise ‘:level’ is equivalent to LEVEL. - - • Other important keywords include the ‘:if...’ keywords. These - keywords control whether the group is available in a certain - situation. - - For example, one group of the ‘magit-rebase’ transient uses ‘:if - magit-rebase-in-progress-p’, which contains the suffixes that are - useful while rebase is already in progress; and another that uses - ‘:if-not magit-rebase-in-progress-p’, which contains the suffixes - that initiate a rebase. - - These predicates can also be used on individual suffixes and are - only documented once, see *note Predicate Slots::. - - • The value of ‘:hide’, if non-‘nil’, is a predicate that controls - whether the group is hidden by default. The key bindings for - suffixes of a hidden group should all use the same prefix key. - Pressing that prefix key should temporarily show the group and its - suffixes, which assumes that a predicate like this is used: - - (lambda () - (eq (car transient--redisplay-key) - ?\C-c)) ; the prefix key shared by all bindings - - • The value of ‘:setup-children’, if non-‘nil’, is a function that - takes one argument, a potentially list of children, and must return - a list of children or an empty list. This can either be used to - somehow transform the group’s children that were defined the normal - way, or to dynamically create the children from scratch. - - The returned children must have the same form as stored in the - prefix’s ‘transient--layout’ property, but it is often more - convenient to use the same form as understood by - ‘transient-define-prefix’, described below. If you use the latter - approach, you can use the ‘transient-parse-suffixes’ and - ‘transient-parse-suffix’ functions to transform them from the - convenient to the expected form. Depending on the used group - class, ‘transient-parse-suffixes’’s SUFFIXES must be a list of - group vectors (for ‘transient-columns’) or a list of suffix lists - (for all other group classes). - - If you explicitly specify children and then transform them using - ‘:setup-children’, then the class of the group is determined as - usual, based on explicitly specified children. - - If you do not explicitly specify children and thus rely solely on - ‘:setup-children’, then you must specify the class using ‘:class’. - For backward compatibility, if you fail to do so, - ‘transient-column’ is used and a warning is displayed. This - warning will eventually be replaced with an error. - - (transient-define-prefix my-finder-by-keyword () - "Select a keyword and list matching packages." - ;; The real `finder-by-keyword' is more convenient - ;; of course, but that is not the point here. - [:class transient-columns - :setup-children - (lambda (_) - (transient-parse-suffixes - 'my-finder-by-keyword - (let ((char (1- ?A))) - (mapcar ; a list ... - (lambda (partition) - (vconcat ; of group vectors ... - (mapcar (lambda (elt) - (let ((keyword (symbol-name (car elt)))) - ; ... where each suffix is a list - (list (format "%c" (cl-incf char)) - keyword - (lambda () - (interactive) - (finder-list-matches keyword))))) - partition))) - (seq-partition finder-known-keywords 7)))))]) - - • The boolean ‘:pad-keys’ argument controls whether keys of all - suffixes contained in a group are right padded, effectively - aligning the descriptions. - - The ELEMENTs are either all subgroups, or all suffixes and strings. -(At least currently no group type exists that would allow mixing -subgroups with commands at the same level, though in principle there is -nothing that prevents that.) - - If the ELEMENTs are not subgroups, then they can be a mixture of -lists, which specify commands, and strings. Strings are inserted -verbatim into the buffer. The empty string can be used to insert gaps -between suffixes, which is particularly useful if the suffixes are -outlined as a table. - - Inside group specifications, including inside contained suffix -specifications, nothing has to be quoted and quoting anyway is invalid. -The value following a keyword, can be explicitly unquoted using ‘,’. -This feature is experimental and should be avoided. - - The form of suffix specifications is documented in the next node. - - -File: transient.info, Node: Suffix Specifications, Prev: Group Specifications, Up: Binding Suffix and Infix Commands - -4.3.2 Suffix Specifications ---------------------------- - -A transient’s suffix and infix commands are bound when the transient -prefix command is defined using ‘transient-define-prefix’, see *note -Defining Transients::. The commands are organized into groups, see -*note Group Specifications::. Here we describe the form used to bind an -individual suffix command. - - The same form is also used when later binding additional commands -using functions such as ‘transient-insert-suffix’, see *note Modifying -Existing Transients::. - - Note that an infix is a special kind of suffix. Depending on context -“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”. -Here it means the former. - - Suffix specifications have this form: - - ([LEVEL] [KEY [DESCRIPTION]] COMMAND|ARGUMENT [KEYWORD VALUE]...) - - LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs -‘:level’, ‘:key’ and ‘:description’. If the object that is associated -with COMMAND sets these properties, then they do not have to be -specified here. You can however specify them here anyway, possibly -overriding the object’s values just for the binding inside this -transient. - - • LEVEL is the suffix level, an integer between 1 and 7. See *note - Enabling and Disabling Suffixes::. - - • KEY is the key binding, either a vector or key description string. - - • DESCRIPTION is the description, either a string or a function that - takes zero or one arguments (the suffix object) and returns a - string. The function should be a lambda expression to avoid - ambiguity. In some cases a symbol that is bound as a function - would also work but to be safe you should use ‘:description’ in - that case. - - The next element is either a command or an argument. This is the -only argument that is mandatory in all cases. - - • COMMAND should be a symbol that is bound as a function, which has - to be defined or at least autoloaded as a command by the time the - containing prefix command is invoked. - - Any command will do; it does not need to have an object associated - with it (as would be the case if ‘transient-define-suffix’ or - ‘transient-define-infix’ were used to define it). - - COMMAND can also be a ‘lambda’ expression. - - As mentioned above, the object that is associated with a command - can be used to set the default for certain values that otherwise - have to be set in the suffix specification. Therefore if there is - no object, then you have to make sure to specify the KEY and the - DESCRIPTION. - - As a special case, if you want to add a command that might be - neither defined nor autoloaded, you can use a workaround like: - - (transient-insert-suffix 'some-prefix "k" - '("!" "Ceci n'est pas une commande" no-command - :if (lambda () (featurep 'no-library)))) - - Instead of ‘featurep’ you could also use ‘require’ with a non-‘nil’ - value for NOERROR. - - • The mandatory argument can also be a command-line argument, a - string. In that case an anonymous command is defined and bound. - - Instead of a string, this can also be a list of two strings, in - which case the first string is used as the short argument (which - can also be specified using ‘:shortarg’) and the second as the long - argument (which can also be specified using ‘:argument’). - - Only the long argument is displayed in the popup buffer. See - ‘transient-detect-key-conflicts’ for how the short argument may be - used. - - Unless the class is specified explicitly, the appropriate class is - guessed based on the long argument. If the argument ends with ‘=’ - (e.g., ‘--format=’) then ‘transient-option’ is used, otherwise - ‘transient-switch’. - - Finally, details can be specified using optional KEYWORD-VALUE pairs. -Each keyword has to be a keyword symbol, either ‘:class’ or a keyword -argument supported by the constructor of that class. See *note Suffix -Slots::. - - -File: transient.info, Node: Defining Suffix and Infix Commands, Next: Using Infix Arguments, Prev: Binding Suffix and Infix Commands, Up: Defining New Commands - -4.4 Defining Suffix and Infix Commands -====================================== - -Note that an infix is a special kind of suffix. Depending on context -“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”. - - -- Macro: transient-define-suffix name arglist [docstring] [keyword - value]... body... - This macro defines NAME as a transient suffix command. - - ARGLIST are the arguments that the command takes. DOCSTRING is the - documentation string and is optional. - - These arguments can optionally be followed by keyword-value pairs. - Each keyword has to be a keyword symbol, either ‘:class’ or a - keyword argument supported by the constructor of that class. The - ‘transient-suffix’ class is used if the class is not specified - explicitly. - - The BODY must begin with an ‘interactive’ form that matches - ARGLIST. The infix arguments are usually accessed by using - ‘transient-args’ inside ‘interactive’. - - -- Macro: transient-define-infix name arglist [docstring] [keyword - value]... - This macro defines NAME as a transient infix command. - - ARGLIST is always ignored (but mandatory never-the-less) and - reserved for future use. DOCSTRING is the documentation string and - is optional. - - At least one key-value pair is required. All transient infix - commands are ‘equal’ to each other (but not ‘eq’). It is - meaningless to define an infix command, without providing at least - one keyword argument (usually ‘:argument’ or ‘:variable’, depending - on the class). The suffix class defaults to ‘transient-switch’ and - can be set using the ‘:class’ keyword. - - The function definition is always: - - (lambda () - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) - - ‘transient-infix-read’ and ‘transient-infix-set’ are generic - functions. Different infix commands behave differently because the - concrete methods are different for different infix command classes. - In rare cases the above command function might not be suitable, - even if you define your own infix command class. In that case you - have to use ‘transient-define-suffix’ to define the infix command - and use ‘t’ as the value of the ‘:transient’ keyword. - - -- Macro: transient-define-argument name arglist [docstring] [keyword - value]... - This macro defines NAME as a transient infix command. - - This is an alias for ‘transient-define-infix’. Only use this alias - to define an infix command that actually sets an infix argument. - To define an infix command that, for example, sets a variable, use - ‘transient-define-infix’ instead. - - -File: transient.info, Node: Using Infix Arguments, Next: Transient State, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands - -4.5 Using Infix Arguments -========================= - -The functions and the variables described below allow suffix commands to -access the value of the transient from which they were invoked; which is -the value of its infix arguments. These variables are set when the user -invokes a suffix command that exits the transient, but before actually -calling the command. - - When returning to the command-loop after calling the suffix command, -the arguments are reset to ‘nil’ (which causes the function to return -‘nil’ too). - - Like for Emacs’s prefix arguments, it is advisable, but not -mandatory, to access the infix arguments inside the command’s -‘interactive’ form. The preferred way of doing that is to call the -‘transient-args’ function, which for infix arguments serves about the -same purpose as ‘prefix-arg’ serves for prefix arguments. - - -- Function: transient-args prefix - This function returns the value of the transient prefix command - PREFIX. - - If the current command was invoked from the transient prefix - command PREFIX, then it returns the active infix arguments. If the - current command was not invoked from PREFIX, then it returns the - set, saved or default value for PREFIX. - - -- Function: transient-arg-value arg args - This function return the value of ARG as it appears in ARGS. - - For a switch a boolean is returned. For an option the value is - returned as a string, using the empty string for the empty value, - or ‘nil’ if the option does not appear in ARGS. - - -- Function: transient-suffixes prefix - This function returns the suffixes of the transient prefix command - PREFIX. This is a list of objects. This function should only be - used if you need the objects (as opposed to just their values) and - if the current command is not being invoked from PREFIX. - - -- Variable: transient-current-suffixes - The suffixes of the transient from which this suffix command was - invoked. This is a list of objects. Usually it is sufficient to - instead use the function ‘transient-args’, which returns a list of - values. In complex cases it might be necessary to use this - variable instead, i.e., if you need access to information beside - the value. - - -- Variable: transient-current-command - The transient from which this suffix command was invoked. The - returned value is a symbol, the transient prefix command. - - -- Variable: transient-current-prefix - The transient from which this suffix command was invoked. The - returned value is a ‘transient-prefix’ object, which holds - information associated with the transient prefix command. - - -- Variable: transient-active-prefix - This function returns the active transient object. Return ‘nil’ if - there is no active transient, if the transient buffer isn’t shown, - and while the active transient is suspended (e.g., while the - minibuffer is in use). - - Unlike ‘transient-current-prefix’, which is only ever non-‘nil’ in - code that is run directly by a command that is invoked while a - transient is current, this function is also suitable for use in - asynchronous code, such as timers and callbacks (this function’s - main use-case). - - If optional PREFIXES is non-‘nil’, it must be a list of prefix - command symbols, in which case the active transient object is only - returned if it matches one of the PREFIXES." - - -File: transient.info, Node: Transient State, Prev: Using Infix Arguments, Up: Defining New Commands - -4.6 Transient State -=================== - -Invoking a transient prefix command “activates” the respective -transient, i.e., it puts a transient keymap into effect, which binds the -transient’s infix and suffix commands. - - The default behavior while a transient is active is as follows: - - • Invoking an infix command does not affect the transient state; the - transient remains active. - - • Invoking a (non-infix) suffix command “deactivates” the transient - state by removing the transient keymap and performing some - additional cleanup. - - • Invoking a command that is bound in a keymap other than the - transient keymap is disallowed and trying to do so results in a - warning. This does not “deactivate” the transient. - - The behavior can be changed for all suffixes of a particular prefix -and/or for individual suffixes. The values should nearly always be -booleans, but certain functions, called “pre-commands”, can also be -used. These functions are named ‘transient--do-VERB’, and the symbol -‘VERB’ can be used as a shorthand. - - A boolean is interpreted as answering the question "does the -transient stay active, when this command is invoked?" ‘t’ means that -the transient stays active, while ‘nil’ means that invoking the command -exits the transient. - - Note that when the suffix is a “sub-prefix”, invoking that command -always activates that sub-prefix, causing the outer prefix to no longer -be active and displayed. Here ‘t’ means that when you exit the inner -prefix, then the outer prefix becomes active again, while ‘nil’ means -that all outer prefixes are exited at once. - - • The behavior for non-suffixes can be set for a particular prefix, - by the prefix’s ‘transient-non-suffix’ slot to a boolean, a - suitable pre-command function, or a shorthand for such a function. - See *note Pre-commands for Non-Suffixes::. - - • The common behavior for the suffixes of a particular prefix can be - set using the prefix’s ‘transient-suffixes’ slot. - - The value specified in this slot does *not* affect infixes. - Because it affects both regular suffixes as well as sub-prefixes, - which have different needs, it is best to avoid explicitly - specifying a function. - - • The behavior of an individual suffix can be changed using its - ‘transient’ slot. While it is usually best to use a boolean, for - this slot it can occasionally make sense to specify a function - explicitly. - - Note that this slot can be set when defining a suffix command using - ‘transient-define-suffix’ and/or in the definition of the prefix. - If set in both places, then the latter takes precedence, as usual. - - The available pre-command functions are documented in the following -sub-sections. They are called by ‘transient--pre-command’, a function -on ‘pre-command-hook’, and the value that they return determines whether -the transient is exited. To do so the value of one of the constants -‘transient--exit’ or ‘transient--stay’ is used (that way we don’t have -to remember if ‘t’ means “exit” or “stay”). - - Additionally, these functions may change the value of ‘this-command’ -(which explains why they have to be called using ‘pre-command-hook’), -call ‘transient-export’, ‘transient--stack-zap’ or -‘transient--stack-push’; and set the values of ‘transient--exitp’, -‘transient--helpp’ or ‘transient--editp’. - - For completeness sake, some notes about complications: - - • The transient-ness of certain built-in suffix commands is specified - using ‘transient-predicate-map’. This is a special keymap, which - binds commands to pre-commands (as opposed to keys to commands) and - takes precedence over the prefix’s ‘transient-suffix’ slot, but not - the suffix’s ‘transient’ slot. - - • While a sub-prefix is active we nearly always want ‘C-g’ to take - the user back to the “super-prefix”, even when the other suffixes - don’t do that. However, in rare cases this may not be desirable, - and that makes the following complication necessary: - - For ‘transient-suffix’ objects the ‘transient’ slot is unbound. We - can ignore that for the most part because ‘nil’ and the slot being - unbound are treated as equivalent, and mean “do exit”. That isn’t - actually true for suffixes that are sub-prefixes though. For such - suffixes unbound means “do exit but allow going back”, which is the - default, while ‘nil’ means “do exit permanently”, which requires - that slot to be explicitly set to that value. - -Pre-commands for Infixes ------------------------- - -The default for infixes is ‘transient--do-stay’. This is also the only -function that makes sense for infixes, which is why this predicate is -used even if the value of the prefix’s ‘transient-suffix’ slot is ‘t’. -In extremely rare cases, one might want to use something else, which can -be done by setting the infix’s ‘transient’ slot directly. - - -- Function: transient--do-stay - Call the command without exporting variables and stay transient. - -Pre-commands for Suffixes -------------------------- - -By default, invoking a suffix causes the transient to be exited. - - The behavior for an individual suffix command can be changed by -setting its ‘transient’ slot to a boolean (which is highly recommended), -or to one of the following pre-commands. - - -- Function: transient--do-exit - Call the command after exporting variables and exit the transient. - - -- Function: transient--do-return - Call the command after exporting variables and return to the parent - prefix. If there is no parent prefix, then call - ‘transient--do-exit’. - - -- Function: transient--do-call - Call the command after exporting variables and stay transient. - - The following pre-commands are only suitable for sub-prefixes. It is -not necessary to explicitly use these predicates because the correct -predicate is automatically picked based on the value of the ‘transient’ -slot for the sub-prefix itself. - - -- Function: transient--do-recurse - Call the transient prefix command, preparing for return to active - transient. - - Whether we actually return to the parent transient is ultimately - under the control of each invoked suffix. The difference between - this pre-command and ‘transient--do-stack’ is that it changes the - value of the ‘transient-suffix’ slot to ‘t’. - - If there is no parent transient, then only call this command and - skip the second step. - - -- Function: transient--do-stack - Call the transient prefix command, stacking the active transient. - Push the active transient to the transient stack. - - Unless ‘transient--do-recurse’ is explicitly used, this pre-command - is automatically used for suffixes that are prefixes themselves, - i.e., for sub-prefixes. - - -- Function: transient--do-replace - Call the transient prefix command, replacing the active transient. - Do not push the active transient to the transient stack. - - Unless ‘transient--do-recurse’ is explicitly used, this pre-command - is automatically used for suffixes that are prefixes themselves, - i.e., for sub-prefixes. - - -- Function: transient--do-suspend - Suspend the active transient, saving the transient stack. - - This is used by the command ‘transient-suspend’ and optionally also - by “external events” such as ‘handle-switch-frame’. Such bindings - should be added to ‘transient-predicate-map’. - -Pre-commands for Non-Suffixes ------------------------------ - -By default, non-suffixes (commands that are bound in other keymaps -beside the transient keymap) cannot be invoked. Trying to invoke such a -command results in a warning and the transient stays active. - - If you want a different behavior, then set the ‘transient-non-suffix’ -slot of the transient prefix command. The value should be a boolean, -answering the question, "is it allowed to invoke non-suffix commands?, a -pre-command function, or a shorthand for such a function. - - If the value is ‘t’, then non-suffixes can be invoked, when it is -‘nil’ (the default) then they cannot be invoked. - - The only other recommended value is ‘leave’. If that is used, then -non-suffixes can be invoked, but if one is invoked, then that exits the -transient. - - -- Function: transient--do-warn - Call ‘transient-undefined’ and stay transient. - - -- Function: transient--do-stay - Call the command without exporting variables and stay transient. - - -- Function: transient--do-leave - Call the command without exporting variables and exit the - transient. - -Special Pre-Commands --------------------- - - -- Function: transient--do-quit-one - If active, quit help or edit mode, else exit the active transient. - - This is used when the user pressed ‘C-g’. - - -- Function: transient--do-quit-all - Exit all transients without saving the transient stack. - - This is used when the user pressed ‘C-q’. - - -- Function: transient--do-suspend - Suspend the active transient, saving the transient stack. - - This is used when the user pressed ‘C-z’. - - -File: transient.info, Node: Classes and Methods, Next: FAQ, Prev: Defining New Commands, Up: Top - -5 Classes and Methods -********************* - -Transient uses classes and generic functions to make it possible to -define new types of suffix commands that are similar to existing types, -but behave differently in some aspects. It does the same for groups and -prefix commands, though at least for prefix commands that *currently* -appears to be less important. - - Every prefix, infix and suffix command is associated with an object, -which holds information that controls certain aspects of its behavior. -This happens in two ways. - - • Associating a command with a certain class gives the command a - type. This makes it possible to use generic functions to do - certain things that have to be done differently depending on what - type of command it acts on. - - That in turn makes it possible for third-parties to add new types - without having to convince the maintainer of Transient that that - new type is important enough to justify adding a special case to a - dozen or so functions. - - • Associating a command with an object makes it possible to easily - store information that is specific to that particular command. - - Two commands may have the same type, but obviously their key - bindings and descriptions still have to be different, for example. - - The values of some slots are functions. The ‘reader’ slot for - example holds a function that is used to read a new value for an - infix command. The values of such slots are regular functions. - - Generic functions are used when a function should do something - different based on the type of the command, i.e., when all commands - of a certain type should behave the same way but different from the - behavior for other types. Object slots that hold a regular - function as value are used when the task that they perform is - likely to differ even between different commands of the same type. - -* Menu: - -* Group Classes:: -* Group Methods:: -* Prefix Classes:: -* Suffix Classes:: -* Suffix Methods:: -* Prefix Slots:: -* Suffix Slots:: -* Predicate Slots:: - - -File: transient.info, Node: Group Classes, Next: Group Methods, Up: Classes and Methods - -5.1 Group Classes -================= - -The type of a group can be specified using the ‘:class’ property at the -beginning of the class specification, e.g., ‘[:class transient-columns -...]’ in a call to ‘transient-define-prefix’. - - • The abstract ‘transient-child’ class is the base class of both - ‘transient-group’ (and therefore all groups) as well as of - ‘transient-suffix’ (and therefore all suffix and infix commands). - - This class exists because the elements (or “children”) of certain - groups can be other groups instead of suffix and infix commands. - - • The abstract ‘transient-group’ class is the superclass of all other - group classes. - - • The ‘transient-column’ class is the simplest group. - - This is the default “flat” group. If the class is not specified - explicitly and the first element is not a vector (i.e., not a - group), then this class is used. - - This class displays each element on a separate line. - - • The ‘transient-row’ class displays all elements on a single line. - - • The ‘transient-columns’ class displays commands organized in - columns. - - Direct elements have to be groups whose elements have to be - commands or strings. Each subgroup represents a column. This - class takes care of inserting the subgroups’ elements. - - This is the default “nested” group. If the class is not specified - explicitly and the first element is a vector (i.e., a group), then - this class is used. - - • The ‘transient-subgroups’ class wraps other groups. - - Direct elements have to be groups whose elements have to be - commands or strings. This group inserts an empty line between - subgroups. The subgroups themselves are responsible for displaying - their elements. - - -File: transient.info, Node: Group Methods, Next: Prefix Classes, Prev: Group Classes, Up: Classes and Methods - -5.2 Group Methods -================= - - -- Function: transient-setup-children group children - This generic function can be used to setup the children or a group. - - The default implementation usually just returns the children - unchanged, but if the ‘setup-children’ slot of GROUP is non-‘nil’, - then it calls that function with CHILDREN as the only argument and - returns the value. - - The children are given as a (potentially empty) list consisting of - either group or suffix specifications. These functions can make - arbitrary changes to the children including constructing new - children from scratch. - - -- Function: transient--insert-group group - This generic function formats the group and its elements and - inserts the result into the current buffer, which is a temporary - buffer. The contents of that buffer are later inserted into the - popup buffer. - - Functions that are called by this function may need to operate in - the buffer from which the transient was called. To do so they can - temporarily make the ‘transient--source-buffer’ the current buffer. - - -File: transient.info, Node: Prefix Classes, Next: Suffix Classes, Prev: Group Methods, Up: Classes and Methods - -5.3 Prefix Classes -================== - -Currently the ‘transient-prefix’ class is being used for all prefix -commands and there is only a single generic function that can be -specialized based on the class of a prefix command. - - -- Function: transient--history-init obj - This generic function is called while setting up the transient and - is responsible for initializing the ‘history’ slot. This is the - transient-wide history; many individual infixes also have a history - of their own. - - The default (and currently only) method extracts the value from the - global variable ‘transient-history’. - - A transient prefix command’s object is stored in the -‘transient--prefix’ property of the command symbol. While a transient -is active, a clone of that object is stored in the variable -‘transient--prefix’. A clone is used because some changes that are made -to the active transient’s object should not affect later invocations. - - -File: transient.info, Node: Suffix Classes, Next: Suffix Methods, Prev: Prefix Classes, Up: Classes and Methods - -5.4 Suffix Classes -================== - - • All suffix and infix classes derive from ‘transient-suffix’, which - in turn derives from ‘transient-child’, from which - ‘transient-group’ also derives (see *note Group Classes::). - - • All infix classes derive from the abstract ‘transient-infix’ class, - which in turn derives from the ‘transient-suffix’ class. - - Infixes are a special type of suffixes. The primary difference is - that infixes always use the ‘transient--do-stay’ pre-command, while - non-infix suffixes use a variety of pre-commands (see *note - Transient State::). Doing that is most easily achieved by using - this class, though theoretically it would be possible to define an - infix class that does not do so. If you do that then you get to - implement many methods. - - Also, infixes and non-infix suffixes are usually defined using - different macros (see *note Defining Suffix and Infix Commands::). - - • Classes used for infix commands that represent arguments should be - derived from the abstract ‘transient-argument’ class. - - • The ‘transient-switch’ class (or a derived class) is used for infix - arguments that represent command-line switches (arguments that do - not take a value). - - • The ‘transient-option’ class (or a derived class) is used for infix - arguments that represent command-line options (arguments that do - take a value). - - • The ‘transient-switches’ class can be used for a set of mutually - exclusive command-line switches. - - • The ‘transient-files’ class can be used for a ‘--’ argument that - indicates that all remaining arguments are files. - - • Classes used for infix commands that represent variables should - derived from the abstract ‘transient-variable’ class. - - • The ‘transient-information’ class is special in that suffixes that - use this class are not associated with a command and thus also not - with any key binding. Such suffixes are only used to display - arbitrary information, and that anywhere a suffix can appear. - Display-only suffix specifications take this form: - - ([LEVEL] :info DESCRIPTION [KEYWORD VALUE]...) - - The ‘:info’ keyword argument replaces the ‘:description’ keyword - used for other suffix classes. Other keyword arguments that you - might want to set, include ‘:face’, predicate keywords (such as - ‘:if’), and ‘:format’. By default the value of ‘:format’ includes - ‘%k’, which for this class is replaced with the empty string or - spaces, if keys are being padded in the containing group. - - Magit defines additional classes, which can serve as examples for the -fancy things you can do without modifying Transient. Some of these -classes will likely get generalized and added to Transient. For now -they are very much subject to change and not documented. - - -File: transient.info, Node: Suffix Methods, Next: Prefix Slots, Prev: Suffix Classes, Up: Classes and Methods - -5.5 Suffix Methods -================== - -To get information about the methods implementing these generic -functions use ‘describe-function’. - -* Menu: - -* Suffix Value Methods:: -* Suffix Format Methods:: - - -File: transient.info, Node: Suffix Value Methods, Next: Suffix Format Methods, Up: Suffix Methods - -5.5.1 Suffix Value Methods --------------------------- - - -- Function: transient-init-value obj - This generic function sets the initial value of the object OBJ. - - This function is called for all suffix commands, but unless a - concrete method is implemented this falls through to the default - implementation, which is a noop. In other words this usually only - does something for infix commands, but note that this is not - implemented for the abstract class ‘transient-infix’, so if your - class derives from that directly, then you must implement a method. - - -- Function: transient-infix-read obj - This generic function determines the new value of the infix object - OBJ. - - This function merely determines the value; ‘transient-infix-set’ is - used to actually store the new value in the object. - - For most infix classes this is done by reading a value from the - user using the reader specified by the ‘reader’ slot (using the - ‘transient-infix-value’ method described below). - - For some infix classes the value is changed without reading - anything in the minibuffer, i.e., the mere act of invoking the - infix command determines what the new value should be, based on the - previous value. - - -- Function: transient-prompt obj - This generic function returns the prompt to be used to read infix - object OBJ’s value. - - -- Function: transient-infix-set obj value - This generic function sets the value of infix object OBJ to VALUE. - - -- Function: transient-infix-value obj - This generic function returns the value of the suffix object OBJ. - - This function is called by ‘transient-args’ (which see), meaning - this function is how the value of a transient is determined so that - the invoked suffix command can use it. - - Currently most values are strings, but that is not set in stone. - ‘nil’ is not a value, it means “no value”. - - Usually only infixes have a value, but see the method for - ‘transient-suffix’. - - -- Function: transient-init-scope obj - This generic function sets the scope of the suffix object OBJ. - - The scope is actually a property of the transient prefix, not of - individual suffixes. However it is possible to invoke a suffix - command directly instead of from a transient. In that case, if the - suffix expects a scope, then it has to determine that itself and - store it in its ‘scope’ slot. - - This function is called for all suffix commands, but unless a - concrete method is implemented this falls through to the default - implementation, which is a noop. - - -File: transient.info, Node: Suffix Format Methods, Prev: Suffix Value Methods, Up: Suffix Methods - -5.5.2 Suffix Format Methods ---------------------------- - - -- Function: transient-format obj - This generic function formats and returns OBJ for display. - - When this function is called, then the current buffer is some - temporary buffer. If you need the buffer from which the prefix - command was invoked to be current, then do so by temporarily making - ‘transient--source-buffer’ current. - - -- Function: transient-format-key obj - This generic function formats OBJ’s ‘key’ for display and returns - the result. - - -- Function: transient-format-description obj - This generic function formats OBJ’s ‘description’ for display and - returns the result. - - -- Function: transient-format-value obj - This generic function formats OBJ’s value for display and returns - the result. - - -- Function: transient-show-help obj - Show help for the prefix, infix or suffix command represented by - OBJ. - - For prefixes, show the info manual, if that is specified using the - ‘info-manual’ slot. Otherwise, show the manpage if that is - specified using the ‘man-page’ slot. Otherwise, show the command’s - documentation string. - - For suffixes, show the command’s documentation string. - - For infixes, show the manpage if that is specified. Otherwise show - the command’s documentation string. - - -File: transient.info, Node: Prefix Slots, Next: Suffix Slots, Prev: Suffix Methods, Up: Classes and Methods - -5.6 Prefix Slots -================ - - • ‘show-help’, ‘man-page’ or ‘info-manual’ can be used to specify the - documentation for the prefix and its suffixes. The command - ‘transient-help’ uses the method ‘transient-show-help’ (which see) - to lookup and use these values. - - • ‘history-key’ If multiple prefix commands should share a single - value, then this slot has to be set to the same value for all of - them. You probably don’t want that. - - • ‘transient-suffix’ and ‘transient-non-suffix’ play a part when - determining whether the currently active transient prefix command - remains active/transient when a suffix or arbitrary non-suffix - command is invoked. See *note Transient State::. - - • ‘refresh-suffixes’ Normally suffix objects and keymaps are only - setup once, when the prefix is invoked. Setting this to ‘t’, - causes them to be recreated after every command. This is useful - when using ‘:if...’ predicates, and those need to be rerun for some - reason. Doing this is somewhat costly, and there is a risk of - losing state, so this is disabled by default and still considered - experimental. - - • ‘incompatible’ A list of lists. Each sub-list specifies a set of - mutually exclusive arguments. Enabling one of these arguments - causes the others to be disabled. An argument may appear in - multiple sub-lists. Arguments must me given in the same form as - used in the ‘argument’ or ‘argument-format’ slot of the respective - suffix objects, usually something like ‘--switch’ or ‘--option=%s’. - For options and ‘transient-switches’ suffixes it is also possible - to match against a specific value, as returned by - ‘transient-infix-value’, for example, ‘--option=one’. - - • ‘scope’ For some transients it might be necessary to have a sort of - secondary value, called a “scope”. See ‘transient-define-prefix’. - -Internal Prefix Slots ---------------------- - -These slots are mostly intended for internal use. They should not be -set in calls to ‘transient-define-prefix’. - - • ‘prototype’ When a transient prefix command is invoked, then a - clone of that object is stored in the global variable - ‘transient--prefix’ and the prototype is stored in the clone’s - ‘prototype’ slot. - - • ‘command’ The command, a symbol. Each transient prefix command - consists of a command, which is stored in a symbol’s function slot - and an object, which is stored in the ‘transient--prefix’ property - of the same symbol. - - • ‘level’ The level of the prefix commands. The suffix commands - whose layer is equal or lower are displayed. See *note Enabling - and Disabling Suffixes::. - - • ‘value’ The likely outdated value of the prefix. Instead of - accessing this slot directly you should use the function - ‘transient-get-value’, which is guaranteed to return the up-to-date - value. - - • ‘history’ and ‘history-pos’ are used to keep track of historic - values. Unless you implement your own ‘transient-infix-read’ - method you should not have to deal with these slots. - - -File: transient.info, Node: Suffix Slots, Next: Predicate Slots, Prev: Prefix Slots, Up: Classes and Methods - -5.7 Suffix Slots -================ - -Here we document most of the slots that are only available for suffix -objects. Some slots are shared by suffix and group objects, they are -documented in *note Predicate Slots::. - - Also see *note Suffix Classes::. - -Slots of ‘transient-suffix’ ---------------------------- - - • ‘key’ The key, a key vector or a key description string. - - • ‘command’ The command, a symbol. - - • ‘transient’ Whether to stay transient. See *note Transient - State::. - - • ‘format’ The format used to display the suffix in the popup buffer. - It must contain the following %-placeholders: - - • ‘%k’ For the key. - • ‘%d’ For the description. - • ‘%v’ For the infix value. Non-infix suffixes don’t have a - value. - - • ‘description’ The description, either a string or a function, which - is called with zero or one argument (the suffix object), and - returns a string. - - • ‘face’ Face used for the description. In simple cases it is easier - to use this instead of using a function as ‘description’ and adding - the styling there. ‘face’ is appended using - ‘add-face-text-property’. - - • ‘show-help’ A function used to display help for the suffix. If - unspecified, the prefix controls how help is displayed for its - suffixes. - -Slots of ‘transient-infix’ --------------------------- - -Some of these slots are only meaningful for some of the subclasses. -They are defined here anyway to allow sharing certain methods. - - • ‘argument’ The long argument, e.g., ‘--verbose’. - - • ‘shortarg’ The short argument, e.g., ‘-v’. - - • ‘value’ The value. Should not be accessed directly. - - • ‘init-value’ Function that is responsible for setting the object’s - value. If bound, then this is called with the object as the only - argument. Usually this is not bound, in which case the object’s - primary ‘transient-init-value’ method is called instead. - - • ‘unsavable’ Whether the value of the suffix is not saved as part of - the prefixes. - - • ‘multi-value’ For options, whether the option can have multiple - values. If this is non-‘nil’, then the values are read using - ‘completing-read-multiple’ by default and if you specify your own - reader, then it should read the values using that function or - similar. - - Supported non-‘nil’ values are: - - • Use ‘rest’ for an option that can have multiple values. This - is useful e.g., for an ‘--’ argument that indicates that all - remaining arguments are files (such as ‘git log -- file1 - file2’). - - In the list returned by ‘transient-args’ such an option and - its values are represented by a single list of the form - ‘(ARGUMENT . VALUES)’. - - • Use ‘repeat’ for an option that can be specified multiple - times. - - In the list returned by ‘transient-args’ each instance of the - option and its value appears separately in the usual from, for - example: ‘("--another-argument" "--option=first" - "--option=second")’. - - In both cases the option’s values have to be specified in the - default value of a prefix using the same format as returned by - ‘transient-args’, e.g., ‘("--other" "--o=1" "--o=2" ("--" "f1" - "f2"))’. - - • ‘always-read’ For options, whether to read a value on every - invocation. If this is ‘nil’, then options that have a value are - simply unset and have to be invoked a second time to set a new - value. - - • ‘allow-empty’ For options, whether the empty string is a valid - value. - - • ‘history-key’ The key used to store the history. This defaults to - the command name. This is useful when multiple infixes should - share the same history because their values are of the same kind. - - • ‘reader’ The function used to read the value of an infix. Not used - for switches. The function takes three arguments, PROMPT, - INITIAL-INPUT and HISTORY, and must return a string. - - • ‘prompt’ The prompt used when reading the value, either a string or - a function that takes the object as the only argument and which - returns a prompt string. - - • ‘choices’ A list of valid values, or a function that returns such a - list. The latter is not implemented for ‘transient-switches’, - because I couldn’t think of a use-case. How exactly the choices - are used varies depending on the class of the suffix. - -Slots of ‘transient-variable’ ------------------------------ - - • ‘variable’ The variable. - -Slots of ‘transient-switches’ ------------------------------ - - • ‘argument-format’ The display format. Must contain ‘%s’, one of - the ‘choices’ is substituted for that. E.g., ‘--%s-order’. - - • ‘argument-regexp’ The regexp used to match any one of the switches. - E.g., ‘\\(--\\(topo\\|author-date\\|date\\)-order\\)’. - - -File: transient.info, Node: Predicate Slots, Prev: Suffix Slots, Up: Classes and Methods - -5.8 Predicate Slots -=================== - -Suffix and group objects share some predicate slots that control whether -a group or suffix should be available depending on some state. Only one -of these slots can be used at the same time. It is undefined what -happens if you use more than one. - - • ‘if’ Enable if predicate returns non-‘nil’. - • ‘if-not’ Enable if predicate returns ‘nil’. - • ‘if-non-nil’ Enable if variable’s value is non-‘nil’. - • ‘if-nil’ Enable if variable’s value is ‘nil’. - • ‘if-mode’ Enable if major-mode matches value. - • ‘if-not-mode’ Enable if major-mode does not match value. - • ‘if-derived’ Enable if major-mode derives from value. - • ‘if-not-derived’ Enable if major-mode does not derive from value. - - By default these predicates run when the prefix command is invoked, -but this can be changes, using the ‘refresh-suffixes’ prefix slot. See -*note Prefix Slots::. - - One more slot is shared between group and suffix classes, ‘level’. -Like the slots documented above, it is a predicate, but it is used for a -different purpose. The value has to be an integer between 1 and 7. -‘level’ controls whether a suffix or a group should be available -depending on user preference. See *note Enabling and Disabling -Suffixes::. - - -File: transient.info, Node: FAQ, Next: Keystroke Index, Prev: Classes and Methods, Up: Top - -Appendix A FAQ -************** - -A.1 Can I control how the popup buffer is displayed? -==================================================== - -Yes, see ‘transient-display-buffer-action’ in *note Configuration::. - -A.2 How can I copy text from the popup buffer? -============================================== - -To be able to mark text in Transient’s popup buffer using the mouse, you -have to add the below binding. Note that for technical reasons, the -region won’t be visualized, while doing so. After you have quit the -transient popup, you will be able to yank it in another buffer. - - (keymap-set transient-predicate-map - "<mouse-set-region>" - #'transient--do-stay) - -A.3 How can I autoload prefix and suffix commands? -================================================== - -If your package only supports Emacs 30, just prefix the definition with -‘;;;###autoload’. If your package supports released versions of Emacs, -you unfortunately have to use a long form autoload comment as described -in *note (elisp)Autoload::. - - ;;;###autoload (autoload 'magit-dispatch "magit" nil t) - (transient-define-prefix magit-dispatch () - ...) - -A.4 How does Transient compare to prefix keys and universal arguments? -====================================================================== - -See -<https://github.com/magit/transient/wiki/Comparison-with-prefix-keys-and-universal-arguments>. - -A.5 How does Transient compare to Magit-Popup and Hydra? -======================================================== - -See -<https://github.com/magit/transient/wiki/Comparison-with-other-packages>. - -A.6 Why did some of the key bindings change? -============================================ - -You may have noticed that the bindings for some of the common commands -do *not* have the prefix ‘C-x’ and that furthermore some of these -commands are grayed out while others are not. That unfortunately is a -bit confusing if the section of common commands is not shown -permanently, making the following explanation necessary. - - The purpose of usually hiding that section but showing it after the -user pressed the respective prefix key is to conserve space and not -overwhelm users with too much noise, while allowing the user to quickly -list common bindings on demand. - - That however should not keep us from using the best possible key -bindings. The bindings that do use a prefix do so to avoid wasting too -many non-prefix bindings, keeping them available for use in individual -transients. The bindings that do not use a prefix and that are *not* -grayed out are very important bindings that are *always* available, even -when invoking the “common command key prefix” or *any other* -transient-specific prefix. The non-prefix keys that *are* grayed out -however, are not available when any incomplete prefix key sequence is -active. They do not use the “common command key prefix” because it is -likely that users want to invoke them several times in a row and e.g., -‘M-p M-p M-p’ is much more convenient than ‘C-x M-p C-x M-p C-x M-p’. - - You may also have noticed that the “Set” command is bound to ‘C-x s’, -while Magit-Popup used to bind ‘C-c C-c’ instead. I have seen several -users praise the latter binding (sic), so I did not change it -willy-nilly. The reason that I changed it is that using different -prefix keys for different common commands, would have made the temporary -display of the common commands even more confusing, i.e., after pressing -‘C-c’ all the bindings that begin with the ‘C-x’ prefix would be grayed -out. - - Using a single prefix for common commands key means that all other -potential prefix keys can be used for transient-specific commands -*without* the section of common commands also popping up. ‘C-c’ in -particular is a prefix that I want to (and already do) use for Magit, -and also using that for a common command would prevent me from doing so. - - (Also see the next question.) - -A.7 Why does ‘q’ not quit popups anymore? -========================================= - -I agree that ‘q’ is a good binding for commands that quit something. -This includes quitting whatever transient is currently active, but it -also includes quitting whatever it is that some specific transient is -controlling. The transient ‘magit-blame’ for example binds ‘q’ to the -command that turns ‘magit-blame-mode’ off. - - So I had to decide if ‘q’ should quit the active transient (like -Magit-Popup used to) or whether ‘C-g’ should do that instead, so that -‘q’ could be bound in individual transient to whatever commands make -sense for them. Because all other letters are already reserved for use -by individual transients, I have decided to no longer make an exception -for ‘q’. - - If you want to get ‘q’’s old binding back then you can do so. Doing -that is a bit more complicated than changing a single key binding, so I -have implemented a function, ‘transient-bind-q-to-quit’ that makes the -necessary changes. See its documentation string for more information. - - -File: transient.info, Node: Keystroke Index, Next: Command and Function Index, Prev: FAQ, Up: Top - -Appendix B Keystroke Index -************************** - - -* Menu: - -* C-g: Aborting and Resuming Transients. - (line 27) -* C-g <1>: Aborting and Resuming Transients. - (line 27) -* C-h: Getting Help for Suffix Commands. - (line 11) -* C-M-n: Using History. (line 18) -* C-M-p: Using History. (line 13) -* C-q: Aborting and Resuming Transients. - (line 36) -* C-x a: Enabling and Disabling Suffixes. - (line 68) -* C-x C-k: Saving Values. (line 29) -* C-x C-s: Saving Values. (line 25) -* C-x l: Enabling and Disabling Suffixes. - (line 43) -* C-x n: Using History. (line 18) -* C-x p: Using History. (line 13) -* C-x s: Saving Values. (line 21) -* C-x t: Common Suffix Commands. - (line 18) -* C-z: Aborting and Resuming Transients. - (line 41) - - -File: transient.info, Node: Command and Function Index, Next: Variable Index, Prev: Keystroke Index, Up: Top - -Appendix C Command and Function Index -************************************* - - -* Menu: - -* transient--do-call: Transient State. (line 125) -* transient--do-exit: Transient State. (line 117) -* transient--do-leave: Transient State. (line 193) -* transient--do-quit-all: Transient State. (line 205) -* transient--do-quit-one: Transient State. (line 200) -* transient--do-recurse: Transient State. (line 133) -* transient--do-replace: Transient State. (line 153) -* transient--do-return: Transient State. (line 120) -* transient--do-stack: Transient State. (line 145) -* transient--do-stay: Transient State. (line 105) -* transient--do-stay <1>: Transient State. (line 190) -* transient--do-suspend: Transient State. (line 161) -* transient--do-suspend <1>: Transient State. (line 210) -* transient--do-warn: Transient State. (line 187) -* transient--history-init: Prefix Classes. (line 10) -* transient--insert-group: Group Methods. (line 19) -* transient-append-suffix: Modifying Existing Transients. - (line 51) -* transient-arg-value: Using Infix Arguments. - (line 31) -* transient-args: Using Infix Arguments. - (line 22) -* transient-define-argument: Defining Suffix and Infix Commands. - (line 57) -* transient-define-infix: Defining Suffix and Infix Commands. - (line 26) -* transient-define-prefix: Defining Transients. (line 13) -* transient-define-suffix: Defining Suffix and Infix Commands. - (line 9) -* transient-format: Suffix Format Methods. - (line 6) -* transient-format-description: Suffix Format Methods. - (line 18) -* transient-format-key: Suffix Format Methods. - (line 14) -* transient-format-value: Suffix Format Methods. - (line 22) -* transient-get-suffix: Modifying Existing Transients. - (line 73) -* transient-help: Getting Help for Suffix Commands. - (line 11) -* transient-history-next: Using History. (line 18) -* transient-history-prev: Using History. (line 13) -* transient-infix-read: Suffix Value Methods. - (line 16) -* transient-infix-set: Suffix Value Methods. - (line 36) -* transient-infix-value: Suffix Value Methods. - (line 39) -* transient-init-scope: Suffix Value Methods. - (line 52) -* transient-init-value: Suffix Value Methods. - (line 6) -* transient-insert-suffix: Modifying Existing Transients. - (line 49) -* transient-prompt: Suffix Value Methods. - (line 32) -* transient-quit-all: Aborting and Resuming Transients. - (line 36) -* transient-quit-one: Aborting and Resuming Transients. - (line 27) -* transient-quit-seq: Aborting and Resuming Transients. - (line 27) -* transient-remove-suffix: Modifying Existing Transients. - (line 70) -* transient-replace-suffix: Modifying Existing Transients. - (line 66) -* transient-reset: Saving Values. (line 29) -* transient-resume: Aborting and Resuming Transients. - (line 53) -* transient-save: Saving Values. (line 25) -* transient-scroll-down: Other Commands. (line 17) -* transient-scroll-up: Other Commands. (line 12) -* transient-set: Saving Values. (line 21) -* transient-set-level: Enabling and Disabling Suffixes. - (line 43) -* transient-setup-children: Group Methods. (line 6) -* transient-show-help: Suffix Format Methods. - (line 26) -* transient-suffix-put: Modifying Existing Transients. - (line 77) -* transient-suffixes: Using Infix Arguments. - (line 38) -* transient-suspend: Aborting and Resuming Transients. - (line 41) -* transient-toggle-common: Common Suffix Commands. - (line 18) -* transient-toggle-level-limit: Enabling and Disabling Suffixes. - (line 68) - - -File: transient.info, Node: Variable Index, Next: Concept Index, Prev: Command and Function Index, Up: Top - -Appendix D Variable Index -************************* - - -* Menu: - -* transient-active-prefix: Using Infix Arguments. - (line 61) -* transient-align-variable-pitch: Configuration. (line 185) -* transient-current-command: Using Infix Arguments. - (line 52) -* transient-current-prefix: Using Infix Arguments. - (line 56) -* transient-current-suffixes: Using Infix Arguments. - (line 44) -* transient-default-level: Enabling and Disabling Suffixes. - (line 33) -* transient-detect-key-conflicts: Configuration. (line 210) -* transient-display-buffer-action: Configuration. (line 51) -* transient-enable-popup-navigation: Configuration. (line 36) -* transient-force-fixed-pitch: Configuration. (line 198) -* transient-force-single-column: Configuration. (line 93) -* transient-hide-during-minibuffer-read: Configuration. (line 181) -* transient-highlight-higher-levels: Configuration. (line 223) -* transient-highlight-mismatched-keys: Configuration. (line 135) -* transient-history-file: Using History. (line 33) -* transient-history-limit: Using History. (line 37) -* transient-levels-file: Enabling and Disabling Suffixes. - (line 38) -* transient-mode-line-format: Configuration. (line 102) -* transient-read-with-initial-input: Configuration. (line 174) -* transient-semantic-coloring: Configuration. (line 126) -* transient-show-common-commands: Common Suffix Commands. - (line 23) -* transient-show-popup: Configuration. (line 15) -* transient-substitute-key-function: Configuration. (line 153) -* transient-values-file: Saving Values. (line 31) - - -File: transient.info, Node: Concept Index, Next: GNU General Public License, Prev: Variable Index, Up: Top - -Appendix E Concept Index -************************ - - -* Menu: - -* aborting transients: Aborting and Resuming Transients. - (line 6) -* classes and methods: Classes and Methods. (line 6) -* command dispatchers: Technical Introduction. - (line 39) -* common suffix commands: Common Suffix Commands. - (line 6) -* defining infix commands: Defining Suffix and Infix Commands. - (line 6) -* defining suffix commands: Defining Suffix and Infix Commands. - (line 6) -* disabling suffixes: Enabling and Disabling Suffixes. - (line 6) -* enabling suffixes: Enabling and Disabling Suffixes. - (line 6) -* getting help: Getting Help for Suffix Commands. - (line 6) -* group specifications: Group Specifications. (line 6) -* invoking transients: Invoking Transients. (line 6) -* levels: Enabling and Disabling Suffixes. - (line 10) -* modifying existing transients: Modifying Existing Transients. - (line 6) -* quit transient: Aborting and Resuming Transients. - (line 6) -* resuming transients: Aborting and Resuming Transients. - (line 6) -* saving values of arguments: Saving Values. (line 6) -* scope of a transient: Defining Transients. (line 43) -* suffix specifications: Suffix Specifications. - (line 6) -* transient state: Transient State. (line 6) -* transient-level: Enabling and Disabling Suffixes. - (line 15) -* value history: Using History. (line 6) - - -File: transient.info, Node: GNU General Public License, Prev: Concept Index, Up: Top - -Appendix F GNU General Public License -************************************* - - Version 3, 29 June 2007 - - Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/> - - 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. - - ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. - Copyright (C) YEAR NAME OF AUTHOR - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or (at - your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. - - 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: - - PROGRAM Copyright (C) YEAR NAME OF AUTHOR - 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 <https://www.gnu.org/licenses/>. - - 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 <https://www.gnu.org/licenses/why-not-lgpl.html>. - - - -Tag Table: -Node: Top763 -Node: Introduction2976 -Ref: Some things that Transient can do3504 -Ref: Complexity in CLI programs3857 -Ref: Using Transient for composing interactive commands4458 -Node: Usage6700 -Node: Invoking Transients7068 -Node: Aborting and Resuming Transients8147 -Node: Common Suffix Commands10768 -Node: Saving Values12604 -Ref: Saving Values-Footnote-113975 -Node: Using History14168 -Node: Getting Help for Suffix Commands15742 -Node: Enabling and Disabling Suffixes17120 -Node: Other Commands20408 -Node: Configuration21384 -Ref: Essential Options21664 -Ref: Accessibility Options25325 -Ref: Auxiliary Options25648 -Ref: Developer Options30611 -Node: Modifying Existing Transients31859 -Node: Defining New Commands36051 -Node: Technical Introduction36414 -Node: Defining Transients42115 -Node: Binding Suffix and Infix Commands44582 -Node: Group Specifications45440 -Node: Suffix Specifications51968 -Node: Defining Suffix and Infix Commands56181 -Node: Using Infix Arguments59229 -Node: Transient State62855 -Ref: Pre-commands for Infixes67670 -Ref: Pre-commands for Suffixes68190 -Ref: Pre-commands for Non-Suffixes70644 -Ref: Special Pre-Commands71780 -Node: Classes and Methods72288 -Node: Group Classes74472 -Node: Group Methods76399 -Node: Prefix Classes77652 -Node: Suffix Classes78743 -Node: Suffix Methods81830 -Node: Suffix Value Methods82151 -Node: Suffix Format Methods84909 -Node: Prefix Slots86388 -Ref: Internal Prefix Slots88523 -Node: Suffix Slots89780 -Ref: Slots of transient-suffix90148 -Ref: Slots of transient-infix91285 -Ref: Slots of transient-variable94581 -Ref: Slots of transient-switches94683 -Node: Predicate Slots95046 -Node: FAQ96481 -Ref: Can I control how the popup buffer is displayed?96610 -Ref: How can I copy text from the popup buffer?96791 -Ref: How can I autoload prefix and suffix commands?97285 -Ref: How does Transient compare to prefix keys and universal arguments?97759 -Ref: How does Transient compare to Magit-Popup and Hydra?98002 -Ref: Why did some of the key bindings change?98196 -Ref: Why does q not quit popups anymore?100549 -Node: Keystroke Index101652 -Node: Command and Function Index103517 -Node: Variable Index110109 -Node: Concept Index112519 -Node: GNU General Public License115255 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/emacs/elpa/transient-20240805.1231/dir b/emacs/elpa/transient-20240817.1959/dir diff --git a/emacs/elpa/transient-20240805.1231/gpl.info b/emacs/elpa/transient-20240817.1959/gpl.info diff --git a/emacs/elpa/transient-20240805.1231/transient-autoloads.el b/emacs/elpa/transient-20240817.1959/transient-autoloads.el diff --git a/emacs/elpa/transient-20240817.1959/transient-pkg.el b/emacs/elpa/transient-20240817.1959/transient-pkg.el @@ -0,0 +1,16 @@ +(define-package "transient" "20240817.1959" "Transient commands" + '((emacs "26.1") + (compat "30.0.0.0") + (seq "2.24")) + :commit "3d3f8711d4f6a6ff7f53bc22e465ec82587c62ed" :authors + '(("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) + :maintainers + '(("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) + :maintainer + '("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev") + :keywords + '("extensions") + :url "https://github.com/magit/transient") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/transient-20240817.1959/transient.el b/emacs/elpa/transient-20240817.1959/transient.el @@ -0,0 +1,4585 @@ +;;; transient.el --- Transient commands -*- lexical-binding:t -*- + +;; Copyright (C) 2018-2024 Free Software Foundation, Inc. + +;; Author: Jonas Bernoulli <emacs.transient@jonas.bernoulli.dev> +;; Homepage: https://github.com/magit/transient +;; Keywords: extensions + +;; Package-Version: 0.7.4 +;; Package-Requires: ((emacs "26.1") (compat "30.0.0.0") (seq "2.24")) + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. +;; +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Transient is the library used to implement the keyboard-driven menus +;; in Magit. It is distributed as a separate package, so that it can be +;; used to implement similar menus in other packages. + +;;; Code: + +(require 'cl-lib) +(require 'compat) +(require 'eieio) +(require 'edmacro) +(require 'format-spec) + +(eval-and-compile + (when (and (featurep 'seq) + (not (fboundp 'seq-keep))) + (unload-feature 'seq 'force))) +(require 'seq) +(unless (fboundp 'seq-keep) + (display-warning 'transient (substitute-command-keys "\ +Transient requires `seq' >= 2.24, +but due to bad defaults, Emacs's package manager, refuses to +upgrade this and other built-in packages to higher releases +from GNU Elpa, when a package specifies that this is needed. + +To fix this, you have to add this to your init file: + + (setq package-install-upgrade-built-in t) + +Then evaluate that expression by placing the cursor after it +and typing \\[eval-last-sexp]. + +Once you have done that, you have to explicitly upgrade `seq': + + \\[package-upgrade] seq \\`RET' + +Then you also must make sure the updated version is loaded, +by evaluating this form: + + (progn (unload-feature 'seq t) (require 'seq)) + +Until you do this, you will get random errors about `seq-keep' +being undefined while using Transient. + +If you don't use the `package' package manager but still get +this warning, then your chosen package manager likely has a +similar defect.") :emergency)) + +(eval-when-compile (require 'subr-x)) + +(declare-function info "info" (&optional file-or-node buffer)) +(declare-function Man-find-section "man" (section)) +(declare-function Man-next-section "man" (n)) +(declare-function Man-getpage-in-background "man" (topic)) + +(defvar Man-notify-method) +(defvar pp-default-function) ; since Emacs 29.1 + +(defmacro transient--with-emergency-exit (id &rest body) + (declare (indent defun)) + (unless (keywordp id) + (setq body (cons id body)) + (setq id nil)) + `(condition-case err + (let ((debugger #'transient--exit-and-debug)) + ,(macroexp-progn body)) + ((debug error) + (transient--emergency-exit ,id) + (signal (car err) (cdr err))))) + +(defun transient--exit-and-debug (&rest args) + (transient--emergency-exit :debugger) + (apply #'debug args)) + +;;; Options + +(defgroup transient nil + "Transient commands." + :group 'extensions) + +(defcustom transient-show-popup t + "Whether to show the current transient in a popup buffer. +\\<transient-map> +- If t, then show the popup as soon as a transient prefix command + is invoked. + +- If nil, then do not show the popup unless the user explicitly + requests it, by pressing \\[transient-show] or a prefix key. + +- If a number, then delay displaying the popup and instead show + a brief one-line summary. If zero or negative, then suppress + even showing that summary and display the pressed key only. + + Show the popup when the user explicitly requests it by pressing + \\[transient-show] or a prefix key. Unless zero, then also show the popup + after that many seconds of inactivity (using the absolute value)." + :package-version '(transient . "0.1.0") + :group 'transient + :type '(choice (const :tag "instantly" t) + (const :tag "on demand" nil) + (const :tag "on demand (no summary)" 0) + (number :tag "after delay" 1))) + +(defcustom transient-enable-popup-navigation t + "Whether navigation commands are enabled in the transient popup. + +While a transient is active the transient popup buffer is not the +current buffer, making it necessary to use dedicated commands to +act on that buffer itself. If this is non-nil, then the following +bindings are available: + +\\<transient-popup-navigation-map>\ +- \\[transient-backward-button] moves the cursor to the previous suffix. +- \\[transient-forward-button] moves the cursor to the next suffix. +- \\[transient-push-button] invokes the suffix the cursor is on. +\\<transient-button-map>\ +- \\`<mouse-1>' and \\`<mouse-2>' invoke the clicked on suffix. +\\<transient-popup-navigation-map>\ +- \\[transient-isearch-backward]\ + and \\[transient-isearch-forward] start isearch in the popup buffer. + +\\`<mouse-1>' and \\`<mouse-2>' are bound in `transient-push-button'. +All other bindings are in `transient-popup-navigation-map'. + +By default \\`M-RET' is bound to `transient-push-button', instead of +\\`RET', because if a transient allows the invocation of non-suffixes +then it is likely that you would want \\`RET' to do what it would do +if no transient were active." + :package-version '(transient . "0.4.0") + :group 'transient + :type 'boolean) + +(defcustom transient-display-buffer-action + '(display-buffer-in-side-window + (side . bottom) + (dedicated . t) + (inhibit-same-window . t) + (window-parameters (no-other-window . t))) + "The action used to display the transient popup buffer. + +The transient popup buffer is displayed in a window using + + (display-buffer BUFFER transient-display-buffer-action) + +The value of this option has the form (FUNCTION . ALIST), +where FUNCTION is a function or a list of functions. Each such +function should accept two arguments: a buffer to display and an +alist of the same form as ALIST. See info node `(elisp)Choosing +Window' for details. + +The default is: + + (display-buffer-in-side-window + (side . bottom) + (dedicated . t) + (inhibit-same-window . t) + (window-parameters (no-other-window . t))) + +This displays the window at the bottom of the selected frame. +Another useful FUNCTION is `display-buffer-below-selected', which +is what `magit-popup' used by default. For more alternatives see +info node `(elisp)Display Action Functions' and info node +`(elisp)Buffer Display Action Alists'. + +Note that the buffer that was current before the transient buffer +is shown should remain the current buffer. Many suffix commands +act on the thing at point, if appropriate, and if the transient +buffer became the current buffer, then that would change what is +at point. To that effect `inhibit-same-window' ensures that the +selected window is not used to show the transient buffer. + +It may be possible to display the window in another frame, but +whether that works in practice depends on the window-manager. +If the window manager selects the new window (Emacs frame), +then that unfortunately changes which buffer is current. + +If you change the value of this option, then you might also +want to change the value of `transient-mode-line-format'." + :package-version '(transient . "0.3.0") + :group 'transient + :type '(cons (choice function (repeat :tag "Functions" function)) + alist)) + +(defcustom transient-mode-line-format 'line + "The mode-line format for the transient popup buffer. + +If nil, then the buffer has no mode-line. If the buffer is not +displayed right above the echo area, then this probably is not +a good value. + +If `line' (the default) or a natural number, then the buffer +has no mode-line, but a line is drawn is drawn in its place. +If a number is used, that specifies the thickness of the line. +On termcap frames we cannot draw lines, so there `line' and +numbers are synonyms for nil. + +The color of the line is used to indicate if non-suffixes are +allowed and whether they exit the transient. The foreground +color of `transient-key-noop' (if non-suffix are disallowed), +`transient-key-stay' (if allowed and transient stays active), or +`transient-key-exit' (if allowed and they exit the transient) is +used to draw the line. + +Otherwise this can be any mode-line format. +See `mode-line-format' for details." + :package-version '(transient . "0.2.0") + :group 'transient + :type '(choice (const :tag "hide mode-line" nil) + (const :tag "substitute thin line" line) + (number :tag "substitute line with thickness") + (const :tag "name of prefix command" + ("%e" mode-line-front-space + mode-line-buffer-identification)) + (sexp :tag "custom mode-line format"))) + +(defcustom transient-show-common-commands nil + "Whether to show common transient suffixes in the popup buffer. + +These commands are always shown after typing the prefix key +\"C-x\" when a transient command is active. To toggle the value +of this variable use \"C-x t\" when a transient is active." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'boolean) + +(defcustom transient-read-with-initial-input nil + "Whether to use the last history element as initial minibuffer input." + :package-version '(transient . "0.2.0") + :group 'transient + :type 'boolean) + +(defcustom transient-highlight-mismatched-keys nil + "Whether to highlight keys that do not match their argument. + +This only affects infix arguments that represent command-line +arguments. When this option is non-nil, then the key binding +for infix argument are highlighted when only a long argument +\(e.g., \"--verbose\") is specified but no shorthand (e.g., \"-v\"). +In the rare case that a short-hand is specified but does not +match the key binding, then it is highlighted differently. + +The highlighting is done using `transient-mismatched-key' +and `transient-nonstandard-key'." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'boolean) + +(defcustom transient-highlight-higher-levels nil + "Whether to highlight suffixes on higher levels. + +This is primarily intended for package authors. + +When non-nil then highlight the description of suffixes whose +level is above 4, the default of `transient-default-level'. +Assuming you have set that variable to 7, this highlights all +suffixes that won't be available to users without them making +the same customization." + :package-version '(transient . "0.3.6") + :group 'transient + :type 'boolean) + +(defcustom transient-substitute-key-function nil + "Function used to modify key bindings. + +This function is called with one argument, the prefix object, +and must return a key binding description, either the existing +key description it finds in the `key' slot, or a substitution. + +This is intended to let users replace certain prefix keys. It +could also be used to make other substitutions, but that is +discouraged. + +For example, \"=\" is hard to reach using my custom keyboard +layout, so I substitute \"(\" for that, which is easy to reach +using a layout optimized for Lisp. + + (setq transient-substitute-key-function + (lambda (obj) + (let ((key (oref obj key))) + (if (string-match \"\\\\`\\\\(=\\\\)[a-zA-Z]\" key) + (replace-match \"(\" t t key 1) + key)))))" + :package-version '(transient . "0.1.0") + :group 'transient + :type '(choice (const :tag "Transform no keys (nil)" nil) function)) + +(defcustom transient-semantic-coloring t + "Whether to use colors to indicate transient behavior. + +If non-nil, then the key binding of each suffix is colorized to +indicate whether it exits the transient state or not, and the +line that is drawn below the transient popup buffer is used to +indicate the behavior of non-suffix commands." + :package-version '(transient . "0.5.0") + :group 'transient + :type 'boolean) + +(defcustom transient-detect-key-conflicts nil + "Whether to detect key binding conflicts. + +Conflicts are detected when a transient prefix command is invoked +and results in an error, which prevents the transient from being +used." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'boolean) + +(defcustom transient-align-variable-pitch nil + "Whether to align columns pixel-wise in the popup buffer. + +If this is non-nil, then columns are aligned pixel-wise to +support variable-pitch fonts. Keys are not aligned, so you +should use a fixed-pitch font for the `transient-key' face. +Other key faces inherit from that face unless a theme is +used that breaks that relationship. + +This option is intended for users who use a variable-pitch +font for the `default' face. + +Also see `transient-force-fixed-pitch'." + :package-version '(transient . "0.4.0") + :group 'transient + :type 'boolean) + +(defcustom transient-force-fixed-pitch nil + "Whether to force use of monospaced font in the popup buffer. + +Even if you use a proportional font for the `default' face, +you might still want to use a monospaced font in transient's +popup buffer. Setting this option to t causes `default' to +be remapped to `fixed-pitch' in that buffer. + +Also see `transient-align-variable-pitch'." + :package-version '(transient . "0.2.0") + :group 'transient + :type 'boolean) + +(defcustom transient-force-single-column nil + "Whether to force use of a single column to display suffixes. + +This might be useful for users with low vision who use large +text and might otherwise have to scroll in two dimensions." + :package-version '(transient . "0.3.6") + :group 'transient + :type 'boolean) + +(defcustom transient-hide-during-minibuffer-read nil + "Whether to hide the transient buffer while reading in the minibuffer." + :package-version '(transient . "0.4.0") + :group 'transient + :type 'boolean) + +(defconst transient--max-level 7) +(defconst transient--default-child-level 1) +(defconst transient--default-prefix-level 4) + +(defcustom transient-default-level transient--default-prefix-level + "Control what suffix levels are made available by default. + +Each suffix command is placed on a level and each prefix command +has a level, which controls which suffix commands are available. +Integers between 1 and 7 (inclusive) are valid levels. + +The levels of individual transients and/or their individual +suffixes can be changed individually, by invoking the prefix and +then pressing \"C-x l\". + +The default level for both transients and their suffixes is 4. +This option only controls the default for transients. The default +suffix level is always 4. The author of a transient should place +certain suffixes on a higher level if they expect that it won't be +of use to most users, and they should place very important suffixes +on a lower level so that they remain available even if the user +lowers the transient level. + +\(Magit currently places nearly all suffixes on level 4 and lower +levels are not used at all yet. So for the time being you should +not set a lower level here and using a higher level might not +give you as many additional suffixes as you hoped.)" + :package-version '(transient . "0.1.0") + :group 'transient + :type '(choice (const :tag "1 - fewest suffixes" 1) + (const 2) + (const 3) + (const :tag "4 - default" 4) + (const 5) + (const 6) + (const :tag "7 - most suffixes" 7))) + +(defcustom transient-levels-file + (locate-user-emacs-file "transient/levels.el") + "File used to save levels of transients and their suffixes." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'file) + +(defcustom transient-values-file + (locate-user-emacs-file "transient/values.el") + "File used to save values of transients." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'file) + +(defcustom transient-history-file + (locate-user-emacs-file "transient/history.el") + "File used to save history of transients and their infixes." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'file) + +(defcustom transient-history-limit 10 + "Number of history elements to keep when saving to file." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'integer) + +(defcustom transient-save-history t + "Whether to save history of transient commands when exiting Emacs." + :package-version '(transient . "0.1.0") + :group 'transient + :type 'boolean) + +;;; Faces + +(defgroup transient-faces nil + "Faces used by Transient." + :group 'transient) + +(defface transient-heading '((t :inherit font-lock-keyword-face)) + "Face used for headings." + :group 'transient-faces) + +(defface transient-argument '((t :inherit font-lock-string-face :weight bold)) + "Face used for enabled arguments." + :group 'transient-faces) + +(defface transient-inactive-argument '((t :inherit shadow)) + "Face used for inactive arguments." + :group 'transient-faces) + +(defface transient-value '((t :inherit font-lock-string-face :weight bold)) + "Face used for values." + :group 'transient-faces) + +(defface transient-inactive-value '((t :inherit shadow)) + "Face used for inactive values." + :group 'transient-faces) + +(defface transient-unreachable '((t :inherit shadow)) + "Face used for suffixes unreachable from the current prefix sequence." + :group 'transient-faces) + +(defface transient-inapt-suffix '((t :inherit shadow :italic t)) + "Face used for suffixes that are inapt at this time." + :group 'transient-faces) + +(defface transient-active-infix '((t :inherit highlight)) + "Face used for the infix for which the value is being read." + :group 'transient-faces) + +(defface transient-enabled-suffix + '((t :background "green" :foreground "black" :weight bold)) + "Face used for enabled levels while editing suffix levels. +See info node `(transient)Enabling and Disabling Suffixes'." + :group 'transient-faces) + +(defface transient-disabled-suffix + '((t :background "red" :foreground "black" :weight bold)) + "Face used for disabled levels while editing suffix levels. +See info node `(transient)Enabling and Disabling Suffixes'." + :group 'transient-faces) + +(defface transient-higher-level + `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) + :color ,(let ((color (face-attribute 'shadow :foreground nil t))) + (or (and (not (eq color 'unspecified)) color) + "grey60"))))) + "Face optionally used to highlight suffixes on higher levels. +Also see option `transient-highlight-higher-levels'." + :group 'transient-faces) + +(defface transient-delimiter '((t :inherit shadow)) + "Face used for delimiters and separators. +This includes the parentheses around values and the pipe +character used to separate possible values from each other." + :group 'transient-faces) + +(defface transient-key '((t :inherit font-lock-builtin-face)) + "Face used for keys." + :group 'transient-faces) + +(defface transient-key-stay + `((((class color) (background light)) + :inherit transient-key + :foreground "#22aa22") + (((class color) (background dark)) + :inherit transient-key + :foreground "#ddffdd")) + "Face used for keys of suffixes that don't exit transient state." + :group 'transient-faces) + +(defface transient-key-noop + `((((class color) (background light)) + :inherit transient-key + :foreground "grey80") + (((class color) (background dark)) + :inherit transient-key + :foreground "grey30")) + "Face used for keys of suffixes that currently cannot be invoked." + :group 'transient-faces) + +(defface transient-key-return + `((((class color) (background light)) + :inherit transient-key + :foreground "#aaaa11") + (((class color) (background dark)) + :inherit transient-key + :foreground "#ffffcc")) + "Face used for keys of suffixes that return to the parent transient." + :group 'transient-faces) + +(defface transient-key-exit + `((((class color) (background light)) + :inherit transient-key + :foreground "#aa2222") + (((class color) (background dark)) + :inherit transient-key + :foreground "#ffdddd")) + "Face used for keys of suffixes that exit transient state." + :group 'transient-faces) + +(defface transient-unreachable-key + '((t :inherit (shadow transient-key) :weight normal)) + "Face used for keys unreachable from the current prefix sequence." + :group 'transient-faces) + +(defface transient-nonstandard-key + `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) + :color "cyan"))) + "Face optionally used to highlight keys conflicting with short-argument. +Also see option `transient-highlight-mismatched-keys'." + :group 'transient-faces) + +(defface transient-mismatched-key + `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) + :color "magenta"))) + "Face optionally used to highlight keys without a short-argument. +Also see option `transient-highlight-mismatched-keys'." + :group 'transient-faces) + +;;; Persistence + +(defun transient--read-file-contents (file) + (with-demoted-errors "Transient error: %S" + (and (file-exists-p file) + (with-temp-buffer + (insert-file-contents file) + (read (current-buffer)))))) + +(defun transient--pp-to-file (list file) + (make-directory (file-name-directory file) t) + (setq list (cl-sort (copy-sequence list) #'string< :key #'car)) + (with-temp-file file + (let ((print-level nil) + (print-length nil) + (pp-default-function 'pp-28) + (fill-column 999)) + (pp list (current-buffer))))) + +(defvar transient-values + (transient--read-file-contents transient-values-file) + "Values of transient commands. +The value of this variable persists between Emacs sessions +and you usually should not change it manually.") + +(defun transient-save-values () + (transient--pp-to-file transient-values transient-values-file)) + +(defvar transient-levels + (transient--read-file-contents transient-levels-file) + "Levels of transient commands. +The value of this variable persists between Emacs sessions +and you usually should not change it manually.") + +(defun transient-save-levels () + (transient--pp-to-file transient-levels transient-levels-file)) + +(defvar transient-history + (transient--read-file-contents transient-history-file) + "History of transient commands and infix arguments. +The value of this variable persists between Emacs sessions +\(unless `transient-save-history' is nil) and you usually +should not change it manually.") + +(defun transient-save-history () + (setq transient-history + (cl-sort (mapcar (pcase-lambda (`(,key . ,val)) + (cons key (seq-take (delete-dups val) + transient-history-limit))) + transient-history) + #'string< :key #'car)) + (transient--pp-to-file transient-history transient-history-file)) + +(defun transient-maybe-save-history () + "Save the value of `transient-history'. +If `transient-save-history' is nil, then do nothing." + (when transient-save-history + (transient-save-history))) + +(unless noninteractive + (add-hook 'kill-emacs-hook #'transient-maybe-save-history)) + +;;; Classes +;;;; Prefix + +(defclass transient-prefix () + ((prototype :initarg :prototype) + (command :initarg :command) + (level :initarg :level) + (variable :initarg :variable :initform nil) + (init-value :initarg :init-value) + (value) (default-value :initarg :value) + (scope :initarg :scope :initform nil) + (history :initarg :history :initform nil) + (history-pos :initarg :history-pos :initform 0) + (history-key :initarg :history-key :initform nil) + (show-help :initarg :show-help :initform nil) + (info-manual :initarg :info-manual :initform nil) + (man-page :initarg :man-page :initform nil) + (transient-suffix :initarg :transient-suffix :initform nil) + (transient-non-suffix :initarg :transient-non-suffix :initform nil) + (transient-switch-frame :initarg :transient-switch-frame) + (refresh-suffixes :initarg :refresh-suffixes :initform nil) + (incompatible :initarg :incompatible :initform nil) + (suffix-description :initarg :suffix-description) + (variable-pitch :initarg :variable-pitch :initform nil) + (column-widths :initarg :column-widths :initform nil) + (unwind-suffix :documentation "Internal use." :initform nil)) + "Transient prefix command. + +Each transient prefix command consists of a command, which is +stored in a symbol's function slot and an object, which is +stored in the `transient--prefix' property of the same symbol. + +When a transient prefix command is invoked, then a clone of that +object is stored in the global variable `transient--prefix' and +the prototype is stored in the clone's `prototype' slot.") + +;;;; Suffix + +(defclass transient-child () + ((level + :initarg :level + :initform (symbol-value 'transient--default-child-level) + :documentation "Enable if level of prefix is equal or greater.") + (if + :initarg :if + :initform nil + :documentation "Enable if predicate returns non-nil.") + (if-not + :initarg :if-not + :initform nil + :documentation "Enable if predicate returns nil.") + (if-non-nil + :initarg :if-non-nil + :initform nil + :documentation "Enable if variable's value is non-nil.") + (if-nil + :initarg :if-nil + :initform nil + :documentation "Enable if variable's value is nil.") + (if-mode + :initarg :if-mode + :initform nil + :documentation "Enable if major-mode matches value.") + (if-not-mode + :initarg :if-not-mode + :initform nil + :documentation "Enable if major-mode does not match value.") + (if-derived + :initarg :if-derived + :initform nil + :documentation "Enable if major-mode derives from value.") + (if-not-derived + :initarg :if-not-derived + :initform nil + :documentation "Enable if major-mode does not derive from value.") + (inapt + :initform nil) + (inapt-face + :initarg :inapt-face + :initform 'transient-inapt-suffix) + (inapt-if + :initarg :inapt-if + :initform nil + :documentation "Inapt if predicate returns non-nil.") + (inapt-if-not + :initarg :inapt-if-not + :initform nil + :documentation "Inapt if predicate returns nil.") + (inapt-if-non-nil + :initarg :inapt-if-non-nil + :initform nil + :documentation "Inapt if variable's value is non-nil.") + (inapt-if-nil + :initarg :inapt-if-nil + :initform nil + :documentation "Inapt if variable's value is nil.") + (inapt-if-mode + :initarg :inapt-if-mode + :initform nil + :documentation "Inapt if major-mode matches value.") + (inapt-if-not-mode + :initarg :inapt-if-not-mode + :initform nil + :documentation "Inapt if major-mode does not match value.") + (inapt-if-derived + :initarg :inapt-if-derived + :initform nil + :documentation "Inapt if major-mode derives from value.") + (inapt-if-not-derived + :initarg :inapt-if-not-derived + :initform nil + :documentation "Inapt if major-mode does not derive from value.")) + "Abstract superclass for group and suffix classes. + +It is undefined what happens if more than one `if*' predicate +slot is non-nil." + :abstract t) + +(defclass transient-suffix (transient-child) + ((definition :allocation :class :initform nil) + (key :initarg :key) + (command :initarg :command) + (transient :initarg :transient) + (format :initarg :format :initform " %k %d") + (description :initarg :description :initform nil) + (face :initarg :face :initform nil) + (show-help :initarg :show-help :initform nil)) + "Superclass for suffix command.") + +(defclass transient-information (transient-suffix) + ((format :initform " %k %d") + (key :initform " ")) + "Display-only information, aligned with suffix keys. +Technically a suffix object with no associated command.") + +(defclass transient-information* (transient-information) + ((format :initform " %d")) + "Display-only information, aligned with suffix descriptions. +Technically a suffix object with no associated command.") + +(defclass transient-infix (transient-suffix) + ((transient :initform t) + (argument :initarg :argument) + (shortarg :initarg :shortarg) + (value :initform nil) + (init-value :initarg :init-value) + (unsavable :initarg :unsavable :initform nil) + (multi-value :initarg :multi-value :initform nil) + (always-read :initarg :always-read :initform nil) + (allow-empty :initarg :allow-empty :initform nil) + (history-key :initarg :history-key :initform nil) + (reader :initarg :reader :initform nil) + (prompt :initarg :prompt :initform nil) + (choices :initarg :choices :initform nil) + (format :initform " %k %d (%v)")) + "Transient infix command." + :abstract t) + +(defclass transient-argument (transient-infix) () + "Abstract superclass for infix arguments." + :abstract t) + +(defclass transient-switch (transient-argument) () + "Class used for command-line argument that can be turned on and off.") + +(defclass transient-option (transient-argument) () + "Class used for command-line argument that can take a value.") + +(defclass transient-variable (transient-infix) + ((variable :initarg :variable) + (format :initform " %k %d %v")) + "Abstract superclass for infix commands that set a variable." + :abstract t) + +(defclass transient-switches (transient-argument) + ((argument-format :initarg :argument-format) + (argument-regexp :initarg :argument-regexp)) + "Class used for sets of mutually exclusive command-line switches.") + +(defclass transient-files (transient-option) () + ((key :initform "--") + (argument :initform "--") + (multi-value :initform rest) + (reader :initform transient-read-files)) + "Class used for the \"--\" argument or similar. +All remaining arguments are treated as files. +They become the value of this argument.") + +(defclass transient-value-preset (transient-suffix) + ((transient :initform t) + (set :initarg := :initform nil)) + "Class used by the `transient-preset' suffix command.") + +;;;; Group + +(defclass transient-group (transient-child) + ((suffixes :initarg :suffixes :initform nil) + (hide :initarg :hide :initform nil) + (description :initarg :description :initform nil) + (pad-keys :initarg :pad-keys :initform nil) + (info-format :initarg :info-format :initform nil) + (setup-children :initarg :setup-children)) + "Abstract superclass of all group classes." + :abstract t) + +(defclass transient-column (transient-group) () + "Group class that displays each element on a separate line.") + +(defclass transient-row (transient-group) () + "Group class that displays all elements on a single line.") + +(defclass transient-columns (transient-group) () + "Group class that displays elements organized in columns. +Direct elements have to be groups whose elements have to be +commands or strings. Each subgroup represents a column. +This class takes care of inserting the subgroups' elements.") + +(defclass transient-subgroups (transient-group) () + "Group class that wraps other groups. + +Direct elements have to be groups whose elements have to be +commands or strings. This group inserts an empty line between +subgroups. The subgroups are responsible for displaying their +elements themselves.") + +;;; Define + +(defmacro transient-define-prefix (name arglist &rest args) + "Define NAME as a transient prefix command. + +ARGLIST are the arguments that command takes. +DOCSTRING is the documentation string and is optional. + +These arguments can optionally be followed by key-value pairs. +Each key has to be a keyword symbol, either `:class' or a keyword +argument supported by the constructor of that class. The +`transient-prefix' class is used if the class is not specified +explicitly. + +GROUPs add key bindings for infix and suffix commands and specify +how these bindings are presented in the popup buffer. At least +one GROUP has to be specified. See info node `(transient)Binding +Suffix and Infix Commands'. + +The BODY is optional. If it is omitted, then ARGLIST is also +ignored and the function definition becomes: + + (lambda () + (interactive) + (transient-setup \\='NAME)) + +If BODY is specified, then it must begin with an `interactive' +form that matches ARGLIST, and it must call `transient-setup'. +It may however call that function only when some condition is +satisfied; that is one of the reason why you might want to use +an explicit BODY. + +All transients have a (possibly nil) value, which is exported +when suffix commands are called, so that they can consume that +value. For some transients it might be necessary to have a sort +of secondary value, called a scope. Such a scope would usually +be set in the commands `interactive' form and has to be passed +to the setup function: + + (transient-setup \\='NAME nil nil :scope SCOPE) + +\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])" + (declare (debug ( &define name lambda-list + [&optional lambda-doc] + [&rest keywordp sexp] + [&rest vectorp] + [&optional ("interactive" interactive) def-body])) + (indent defun) + (doc-string 3)) + (pcase-let + ((`(,class ,slots ,suffixes ,docstr ,body ,interactive-only) + (transient--expand-define-args args arglist 'transient-define-prefix))) + `(progn + (defalias ',name + ,(if body + `(lambda ,arglist ,@body) + `(lambda () + (interactive) + (transient-setup ',name)))) + (put ',name 'interactive-only ,interactive-only) + (put ',name 'function-documentation ,docstr) + (put ',name 'transient--prefix + (,(or class 'transient-prefix) :command ',name ,@slots)) + (put ',name 'transient--layout + (list ,@(cl-mapcan (lambda (s) (transient--parse-child name s)) + suffixes)))))) + +(defmacro transient-define-suffix (name arglist &rest args) + "Define NAME as a transient suffix command. + +ARGLIST are the arguments that the command takes. +DOCSTRING is the documentation string and is optional. + +These arguments can optionally be followed by key-value pairs. +Each key has to be a keyword symbol, either `:class' or a +keyword argument supported by the constructor of that class. +The `transient-suffix' class is used if the class is not +specified explicitly. + +The BODY must begin with an `interactive' form that matches +ARGLIST. The infix arguments are usually accessed by using +`transient-args' inside `interactive'. + +\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... [BODY...])" + (declare (debug ( &define name lambda-list + [&optional lambda-doc] + [&rest keywordp sexp] + [&optional ("interactive" interactive) def-body])) + (indent defun) + (doc-string 3)) + (pcase-let + ((`(,class ,slots ,_ ,docstr ,body ,interactive-only) + (transient--expand-define-args args arglist 'transient-define-suffix))) + `(progn + (defalias ',name + ,(if (and (not body) class (oref-default class definition)) + `(oref-default ',class definition) + `(lambda ,arglist ,@body))) + (put ',name 'interactive-only ,interactive-only) + (put ',name 'function-documentation ,docstr) + (put ',name 'transient--suffix + (,(or class 'transient-suffix) :command ',name ,@slots))))) + +(defmacro transient-augment-suffix (name &rest args) + "Augment existing command NAME with a new transient suffix object. +Similar to `transient-define-suffix' but define a suffix object only. +\n\(fn NAME [KEYWORD VALUE]...)" + (declare (debug (&define name [&rest keywordp sexp])) + (indent defun)) + (pcase-let + ((`(,class ,slots) + (transient--expand-define-args args nil 'transient-augment-suffix t))) + `(put ',name 'transient--suffix + (,(or class 'transient-suffix) :command ',name ,@slots)))) + +(defmacro transient-define-infix (name arglist &rest args) + "Define NAME as a transient infix command. + +ARGLIST is always ignored and reserved for future use. +DOCSTRING is the documentation string and is optional. + +At least one key-value pair is required. All transient infix +commands are equal to each other (but not eq). It is meaning- +less to define an infix command, without providing at least one +keyword argument (usually `:argument' or `:variable', depending +on the class). The suffix class defaults to `transient-switch' +and can be set using the `:class' keyword. + +The function definitions is always: + + (lambda () + (interactive) + (let ((obj (transient-suffix-object))) + (transient-infix-set obj (transient-infix-read obj))) + (transient--show)) + +`transient-infix-read' and `transient-infix-set' are generic +functions. Different infix commands behave differently because +the concrete methods are different for different infix command +classes. In rare case the above command function might not be +suitable, even if you define your own infix command class. In +that case you have to use `transient-define-suffix' to define +the infix command and use t as the value of the `:transient' +keyword. + +\(fn NAME ARGLIST [DOCSTRING] KEYWORD VALUE [KEYWORD VALUE]...)" + (declare (debug ( &define name lambda-list + [&optional lambda-doc] + keywordp sexp + [&rest keywordp sexp])) + (indent defun) + (doc-string 3)) + (pcase-let + ((`(,class ,slots ,_ ,docstr ,_ ,interactive-only) + (transient--expand-define-args args arglist 'transient-define-infix t))) + `(progn + (defalias ',name #'transient--default-infix-command) + (put ',name 'interactive-only ,interactive-only) + (put ',name 'completion-predicate #'transient--suffix-only) + (put ',name 'function-documentation ,docstr) + (put ',name 'transient--suffix + (,(or class 'transient-switch) :command ',name ,@slots))))) + +(defalias 'transient-define-argument #'transient-define-infix + "Define NAME as a transient infix command. + +Only use this alias to define an infix command that actually +sets an infix argument. To define a infix command that, for +example, sets a variable, use `transient-define-infix' instead. + +\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)") + +(defun transient--default-infix-command () + ;; Most infix commands are but an alias for this command. + "Cannot show any documentation for this transient infix command. + +When you request help for an infix command using `transient-help', that +usually shows the respective man-page and tries to jump to the location +where the respective argument is being described. + +If no man-page is specified for the containing transient menu, then the +docstring is displayed instead, if any. + +If the infix command doesn't have a docstring, as is the case here, then +this docstring is displayed instead, because technically infix commands +are aliases for `transient--default-infix-command'. + +`describe-function' also shows the docstring of the infix command, +falling back to that of the same aliased command." + (interactive) + (let ((obj (transient-suffix-object))) + (transient-infix-set obj (transient-infix-read obj))) + (transient--show)) +(put 'transient--default-infix-command 'interactive-only t) +(put 'transient--default-infix-command 'completion-predicate + #'transient--suffix-only) + +(define-advice find-function-advised-original + (:around (fn func) transient-default-infix) + "Return nil instead of `transient--default-infix-command'. +When using `find-function' to jump to the definition of a transient +infix command/argument, then we want to actually jump to that, not to +the definition of `transient--default-infix-command', which all infix +commands are aliases for." + (let ((val (funcall fn func))) + (and val (not (eq val 'transient--default-infix-command)) val))) + +(eval-and-compile ;transient--expand-define-args + (defun transient--expand-define-args (args &optional arglist form nobody) + ;; ARGLIST and FORM are only optional for backward compatibility. + ;; This is necessary because "emoji.el" from Emacs 29 calls this + ;; function directly, with just one argument. + (unless (listp arglist) + (error "Mandatory ARGLIST is missing")) + (let (class keys suffixes docstr declare (interactive-only t)) + (when (stringp (car args)) + (setq docstr (pop args))) + (while (keywordp (car args)) + (let ((k (pop args)) + (v (pop args))) + (if (eq k :class) + (setq class v) + (push k keys) + (push v keys)))) + (while (let ((arg (car args))) + (or (vectorp arg) + (and arg (symbolp arg)))) + (push (pop args) suffixes)) + (when (eq (car-safe (car args)) 'declare) + (setq declare (car args)) + (setq args (cdr args)) + (when-let ((int (assq 'interactive-only declare))) + (setq interactive-only (cadr int)) + (delq int declare)) + (unless (cdr declare) + (setq declare nil))) + (cond + ((not args)) + (nobody + (error "%s: No function body allowed" form)) + ((not (eq (car-safe (nth (if declare 1 0) args)) 'interactive)) + (error "%s: Interactive form missing" form))) + (list (if (eq (car-safe class) 'quote) + (cadr class) + class) + (nreverse keys) + (nreverse suffixes) + docstr + (if declare (cons declare args) args) + interactive-only)))) + +(defun transient--parse-child (prefix spec) + (cl-typecase spec + (null (error "Invalid transient--parse-child spec: %s" spec)) + (symbol (let ((value (symbol-value spec))) + (if (and (listp value) + (or (listp (car value)) + (vectorp (car value)))) + (cl-mapcan (lambda (s) (transient--parse-child prefix s)) value) + (transient--parse-child prefix value)))) + (vector (and-let* ((c (transient--parse-group prefix spec))) (list c))) + (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c))) + (string (list spec)) + (t (error "Invalid transient--parse-child spec: %s" spec)))) + +(defun transient--parse-group (prefix spec) + (setq spec (append spec nil)) + (cl-symbol-macrolet + ((car (car spec)) + (pop (pop spec))) + (let (level class args) + (when (integerp car) + (setq level pop)) + (when (stringp car) + (setq args (plist-put args :description pop))) + (while (keywordp car) + (let ((key pop) + (val pop)) + (cond ((eq key :class) + (setq class (macroexp-quote val))) + ((or (symbolp val) + (and (listp val) (not (eq (car val) 'lambda)))) + (setq args (plist-put args key (macroexp-quote val)))) + ((setq args (plist-put args key val)))))) + (unless (or spec class (not (plist-get args :setup-children))) + (message "WARNING: %s: When %s is used, %s must also be specified" + 'transient-define-prefix :setup-children :class)) + (list 'vector + (or level transient--default-child-level) + (cond (class) + ((or (vectorp car) + (and car (symbolp car))) + (quote 'transient-columns)) + ((quote 'transient-column))) + (and args (cons 'list args)) + (cons 'list + (cl-mapcan (lambda (s) (transient--parse-child prefix s)) + spec)))))) + +(defun transient--parse-suffix (prefix spec) + (let (level class args) + (cl-symbol-macrolet + ((car (car spec)) + (pop (pop spec))) + (when (integerp car) + (setq level pop)) + (when (or (stringp car) + (vectorp car)) + (setq args (plist-put args :key pop))) + (cond + ((or (stringp car) + (and (eq (car-safe car) 'lambda) + (not (commandp car)))) + (setq args (plist-put args :description pop))) + ((and (symbolp car) + (not (keywordp car)) + (not (commandp car)) + (commandp (cadr spec))) + (setq args (plist-put args :description (macroexp-quote pop))))) + (cond + ((memq car '(:info :info*))) + ((keywordp car) + (error "Need command, `:info' or `:info*', got `%s'" car)) + ((symbolp car) + (setq args (plist-put args :command (macroexp-quote pop)))) + ((and (commandp car) + (not (stringp car))) + (let ((cmd pop) + (sym (intern + (format "transient:%s:%s" + prefix + (let ((desc (plist-get args :description))) + (if (and (stringp desc) + (length< desc 16)) + desc + (plist-get args :key))))))) + (setq args (plist-put + args :command + `(prog1 ',sym + (put ',sym 'interactive-only t) + (put ',sym 'completion-predicate #'transient--suffix-only) + (defalias ',sym + ,(if (eq (car-safe cmd) 'lambda) + cmd + (macroexp-quote cmd)))))))) + ((or (stringp car) + (and car (listp car))) + (let ((arg pop) + (sym nil)) + (cl-typecase arg + (list + (setq args (plist-put args :shortarg (car arg))) + (setq args (plist-put args :argument (cadr arg))) + (setq arg (cadr arg))) + (string + (when-let ((shortarg (transient--derive-shortarg arg))) + (setq args (plist-put args :shortarg shortarg))) + (setq args (plist-put args :argument arg)))) + (setq sym (intern (format "transient:%s:%s" prefix arg))) + (setq args (plist-put + args :command + `(prog1 ',sym + (put ',sym 'interactive-only t) + (put ',sym 'completion-predicate #'transient--suffix-only) + (defalias ',sym #'transient--default-infix-command)))) + (cond ((and car (not (keywordp car))) + (setq class 'transient-option) + (setq args (plist-put args :reader (macroexp-quote pop)))) + ((not (string-suffix-p "=" arg)) + (setq class 'transient-switch)) + (t + (setq class 'transient-option))))) + (t + (error "Needed command or argument, got %S" car))) + (while (keywordp car) + (let ((key pop) + (val pop)) + (cond ((eq key :class) (setq class val)) + ((eq key :level) (setq level val)) + ((eq key :info) + (setq class 'transient-information) + (setq args (plist-put args :description val))) + ((eq key :info*) + (setq class 'transient-information*) + (setq args (plist-put args :description val))) + ((eq (car-safe val) '\,) + (setq args (plist-put args key (cadr val)))) + ((or (symbolp val) + (and (listp val) (not (eq (car val) 'lambda)))) + (setq args (plist-put args key (macroexp-quote val)))) + ((setq args (plist-put args key val))))))) + (unless (plist-get args :key) + (when-let ((shortarg (plist-get args :shortarg))) + (setq args (plist-put args :key shortarg)))) + (list 'list + (or level transient--default-child-level) + (macroexp-quote (or class 'transient-suffix)) + (cons 'list args)))) + +(defun transient--derive-shortarg (arg) + (save-match-data + (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg) + (match-string 1 arg)))) + +(defun transient-command-completion-not-suffix-only-p (symbol _buffer) + "Say whether SYMBOL should be offered as a completion. +If the value of SYMBOL's `completion-predicate' property is +`transient--suffix-only', then return nil, otherwise return t. +This is the case when a command should only ever be used as a +suffix of a transient prefix command (as opposed to bindings +in regular keymaps or by using `execute-extended-command')." + (not (eq (get symbol 'completion-predicate) 'transient--suffix-only))) + +(defalias 'transient--suffix-only #'ignore + "Ignore ARGUMENTS, do nothing, and return nil. +Also see `transient-command-completion-not-suffix-only-p'. +Only use this alias as the value of the `completion-predicate' +symbol property.") + +(when (and (boundp 'read-extended-command-predicate) ; since Emacs 28.1 + (not read-extended-command-predicate)) + (setq read-extended-command-predicate + #'transient-command-completion-not-suffix-only-p)) + +(defun transient-parse-suffix (prefix suffix) + "Parse SUFFIX, to be added to PREFIX. +PREFIX is a prefix command, a symbol. +SUFFIX is a suffix command or a group specification (of + the same forms as expected by `transient-define-prefix'). +Intended for use in a group's `:setup-children' function." + (cl-assert (and prefix (symbolp prefix))) + (eval (car (transient--parse-child prefix suffix)) t)) + +(defun transient-parse-suffixes (prefix suffixes) + "Parse SUFFIXES, to be added to PREFIX. +PREFIX is a prefix command, a symbol. +SUFFIXES is a list of suffix command or a group specification + (of the same forms as expected by `transient-define-prefix'). +Intended for use in a group's `:setup-children' function." + (cl-assert (and prefix (symbolp prefix))) + (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes)) + +;;; Edit + +(defun transient--insert-suffix (prefix loc suffix action &optional keep-other) + (let* ((suf (cl-etypecase suffix + (vector (transient--parse-group prefix suffix)) + (list (transient--parse-suffix prefix suffix)) + (string suffix))) + (mem (transient--layout-member loc prefix)) + (elt (car mem))) + (setq suf (eval suf t)) + (cond + ((not mem) + (message "Cannot insert %S into %s; %s not found" + suffix prefix loc)) + ((or (and (vectorp suffix) (not (vectorp elt))) + (and (listp suffix) (vectorp elt)) + (and (stringp suffix) (vectorp elt))) + (message "Cannot place %S into %s at %s; %s" + suffix prefix loc + "suffixes and groups cannot be siblings")) + (t + (when-let* ((bindingp (listp suf)) + (key (transient--spec-key suf)) + (conflict (car (transient--layout-member key prefix))) + (conflictp + (and (not (and (eq action 'replace) + (eq conflict elt))) + (or (not keep-other) + (eq (plist-get (nth 2 suf) :command) + (plist-get (nth 2 conflict) :command))) + (equal (transient--suffix-predicate suf) + (transient--suffix-predicate conflict))))) + (transient-remove-suffix prefix key)) + (pcase-exhaustive action + ('insert (setcdr mem (cons elt (cdr mem))) + (setcar mem suf)) + ('append (setcdr mem (cons suf (cdr mem)))) + ('replace (setcar mem suf))))))) + +;;;###autoload +(defun transient-insert-suffix (prefix loc suffix &optional keep-other) + "Insert a SUFFIX into PREFIX before LOC. +PREFIX is a prefix command, a symbol. +SUFFIX is a suffix command or a group specification (of + the same forms as expected by `transient-define-prefix'). +LOC is a command, a key vector, a key description (a string + as returned by `key-description'), or a coordination list + (whose last element may also be a command or key). +Remove a conflicting binding unless optional KEEP-OTHER is + non-nil. +See info node `(transient)Modifying Existing Transients'." + (declare (indent defun)) + (transient--insert-suffix prefix loc suffix 'insert keep-other)) + +;;;###autoload +(defun transient-append-suffix (prefix loc suffix &optional keep-other) + "Insert a SUFFIX into PREFIX after LOC. +PREFIX is a prefix command, a symbol. +SUFFIX is a suffix command or a group specification (of + the same forms as expected by `transient-define-prefix'). +LOC is a command, a key vector, a key description (a string + as returned by `key-description'), or a coordination list + (whose last element may also be a command or key). +Remove a conflicting binding unless optional KEEP-OTHER is + non-nil. +See info node `(transient)Modifying Existing Transients'." + (declare (indent defun)) + (transient--insert-suffix prefix loc suffix 'append keep-other)) + +;;;###autoload +(defun transient-replace-suffix (prefix loc suffix) + "Replace the suffix at LOC in PREFIX with SUFFIX. +PREFIX is a prefix command, a symbol. +SUFFIX is a suffix command or a group specification (of + the same forms as expected by `transient-define-prefix'). +LOC is a command, a key vector, a key description (a string + as returned by `key-description'), or a coordination list + (whose last element may also be a command or key). +See info node `(transient)Modifying Existing Transients'." + (declare (indent defun)) + (transient--insert-suffix prefix loc suffix 'replace)) + +;;;###autoload +(defun transient-remove-suffix (prefix loc) + "Remove the suffix or group at LOC in PREFIX. +PREFIX is a prefix command, a symbol. +LOC is a command, a key vector, a key description (a string + as returned by `key-description'), or a coordination list + (whose last element may also be a command or key). +See info node `(transient)Modifying Existing Transients'." + (declare (indent defun)) + (transient--layout-member loc prefix 'remove)) + +(defun transient-get-suffix (prefix loc) + "Return the suffix or group at LOC in PREFIX. +PREFIX is a prefix command, a symbol. +LOC is a command, a key vector, a key description (a string + as returned by `key-description'), or a coordination list + (whose last element may also be a command or key). +See info node `(transient)Modifying Existing Transients'." + (if-let ((mem (transient--layout-member loc prefix))) + (car mem) + (error "%s not found in %s" loc prefix))) + +(defun transient-suffix-put (prefix loc prop value) + "Edit the suffix at LOC in PREFIX, setting PROP to VALUE. +PREFIX is a prefix command, a symbol. +SUFFIX is a suffix command or a group specification (of + the same forms as expected by `transient-define-prefix'). +LOC is a command, a key vector, a key description (a string + as returned by `key-description'), or a coordination list + (whose last element may also be a command or key). +See info node `(transient)Modifying Existing Transients'." + (let ((suf (transient-get-suffix prefix loc))) + (setf (elt suf 2) + (plist-put (elt suf 2) prop value)))) + +(defun transient--layout-member (loc prefix &optional remove) + (let ((val (or (get prefix 'transient--layout) + (error "%s is not a transient command" prefix)))) + (when (listp loc) + (while (integerp (car loc)) + (let* ((children (if (vectorp val) (aref val 3) val)) + (mem (transient--nthcdr (pop loc) children))) + (if (and remove (not loc)) + (let ((rest (delq (car mem) children))) + (if (vectorp val) + (aset val 3 rest) + (put prefix 'transient--layout rest)) + (setq val nil)) + (setq val (if loc (car mem) mem))))) + (setq loc (car loc))) + (if loc + (transient--layout-member-1 (transient--kbd loc) val remove) + val))) + +(defun transient--layout-member-1 (loc layout remove) + (cond ((listp layout) + (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove)) + layout)) + ((vectorp (car (aref layout 3))) + (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove)) + (aref layout 3))) + (remove + (aset layout 3 + (delq (car (transient--group-member loc layout)) + (aref layout 3))) + nil) + ((transient--group-member loc layout)))) + +(defun transient--group-member (loc group) + (cl-member-if (lambda (suffix) + (and (listp suffix) + (let* ((def (nth 2 suffix)) + (cmd (plist-get def :command))) + (if (symbolp loc) + (eq cmd loc) + (equal (transient--kbd + (or (plist-get def :key) + (transient--command-key cmd))) + loc))))) + (aref group 3))) + +(defun transient--kbd (keys) + (when (vectorp keys) + (setq keys (key-description keys))) + (when (stringp keys) + (setq keys (kbd keys))) + keys) + +(defun transient--spec-key (spec) + (let ((plist (nth 2 spec))) + (or (plist-get plist :key) + (transient--command-key + (plist-get plist :command))))) + +(defun transient--command-key (cmd) + (and-let* ((obj (transient--suffix-prototype cmd))) + (cond ((slot-boundp obj 'key) + (oref obj key)) + ((slot-exists-p obj 'shortarg) + (if (slot-boundp obj 'shortarg) + (oref obj shortarg) + (transient--derive-shortarg (oref obj argument))))))) + +(defun transient--nthcdr (n list) + (nthcdr (if (< n 0) (- (length list) (abs n)) n) list)) + +;;; Variables + +(defvar transient-current-prefix nil + "The transient from which this suffix command was invoked. +This is an object representing that transient, use +`transient-current-command' to get the respective command.") + +(defvar transient-current-command nil + "The transient from which this suffix command was invoked. +This is a symbol representing that transient, use +`transient-current-prefix' to get the respective object.") + +(defvar transient-current-suffixes nil + "The suffixes of the transient from which this suffix command was invoked. +This is a list of objects. Usually it is sufficient to instead +use the function `transient-args', which returns a list of +values. In complex cases it might be necessary to use this +variable instead.") + +(defvar transient-exit-hook nil + "Hook run after exiting a transient.") + +(defvar transient-setup-buffer-hook nil + "Hook run when setting up the transient buffer. +That buffer is current and empty when this hook runs.") + +(defvar transient--prefix nil) +(defvar transient--layout nil) +(defvar transient--suffixes nil) + +(defconst transient--stay t "Do not exit the transient.") +(defconst transient--exit nil "Do exit the transient.") + +(defvar transient--exitp nil "Whether to exit the transient.") +(defvar transient--showp nil "Whether to show the transient popup buffer.") +(defvar transient--helpp nil "Whether help-mode is active.") +(defvar transient--editp nil "Whether edit-mode is active.") + +(defvar transient--refreshp nil + "Whether to refresh the transient completely.") + +(defvar transient--all-levels-p nil + "Whether temporary display of suffixes on all levels is active.") + +(defvar transient--timer nil) + +(defvar transient--stack nil) + +(defvar transient--minibuffer-depth 0) + +(defvar transient--buffer-name " *transient*" + "Name of the transient buffer.") + +(defvar transient--buffer nil + "The transient menu buffer.") + +(defvar transient--window nil + "The window used to display the transient popup buffer.") + +(defvar transient--original-window nil + "The window that was selected before the transient was invoked. +Usually it remains selected while the transient is active.") + +(defvar transient--original-buffer nil + "The buffer that was current before the transient was invoked. +Usually it remains current while the transient is active.") + +(defvar transient--restore-winconf nil + "Window configuration to restore after exiting help.") + +(defvar transient--shadowed-buffer nil + "The buffer that is temporarily shadowed by the transient buffer. +This is bound while the suffix predicate is being evaluated and while +drawing in the transient buffer.") + +(defvar transient--pending-suffix nil + "The suffix that is currently being processed. +This is bound while the suffix predicate is being evaluated, +and while functions that return faces are being evaluated.") + +(defvar transient--pending-group nil + "The group that is currently being processed. +This is bound while the suffixes are drawn in the transient buffer.") + +(defvar transient--debug nil + "Whether to put debug information into *Messages*.") + +(defvar transient--history nil) + +(defvar transient--scroll-commands + '(transient-scroll-up + transient-scroll-down + mwheel-scroll + scroll-bar-toolkit-scroll)) + +;;; Identities + +(defun transient-active-prefix (&optional prefixes) + "Return the active transient object. + +Return nil if there is no active transient, if the transient buffer +isn't shown, and while the active transient is suspended (e.g., while +the minibuffer is in use). + +Unlike `transient-current-prefix', which is only ever non-nil in code +that is run directly by a command that is invoked while a transient +is current, this function is also suitable for use in asynchronous +code, such as timers and callbacks (this function's main use-case). + +If optional PREFIXES is non-nil, it must be a list of prefix command +symbols, in which case the active transient object is only returned +if it matches one of the PREFIXES." + (and transient--showp + transient--prefix + (or (not prefixes) + (memq (oref transient--prefix command) prefixes)) + (or (memq 'transient--pre-command pre-command-hook) + (and (memq t pre-command-hook) + (memq 'transient--pre-command + (default-value 'pre-command-hook)))) + transient--prefix)) + +(defun transient-prefix-object () + "Return the current prefix as an object. + +While a transient is being setup or refreshed (which involves +preparing its suffixes) the variable `transient--prefix' can be +used to access the prefix object. Thus this is what has to be +used in suffix methods such as `transient-format-description', +and in object-specific functions that are stored in suffix slots +such as `description'. + +When a suffix command is invoked (i.e., in its `interactive' form +and function body) then the variable `transient-current-prefix' +has to be used instead. + +Two distinct variables are needed, because any prefix may itself +be used as a suffix of another prefix, and such sub-prefixes have +to be able to tell themselves apart from the prefix they were +invoked from. + +Regular suffix commands, which are not prefixes, do not have to +concern themselves with this distinction, so they can use this +function instead. In the context of a plain suffix, it always +returns the value of the appropriate variable." + (or transient--prefix transient-current-prefix)) + +(defun transient-suffix-object (&optional command) + "Return the object associated with the current suffix command. + +Each suffix commands is associated with an object, which holds +additional information about the suffix, such as its value (in +the case of an infix command, which is a kind of suffix command). + +This function is intended to be called by infix commands, which +are usually aliases of `transient--default-infix-command', which +is defined like this: + + (defun transient--default-infix-command () + (interactive) + (let ((obj (transient-suffix-object))) + (transient-infix-set obj (transient-infix-read obj))) + (transient--show)) + +\(User input is read outside of `interactive' to prevent the +command from being added to `command-history'. See #23.) + +Such commands need to be able to access their associated object +to guide how `transient-infix-read' reads the new value and to +store the read value. Other suffix commands (including non-infix +commands) may also need the object to guide their behavior. + +This function attempts to return the object associated with the +current suffix command even if the suffix command was not invoked +from a transient. (For some suffix command that is a valid thing +to do, for others it is not.) In that case nil may be returned, +if the command was not defined using one of the macros intended +to define such commands. + +The optional argument COMMAND is intended for internal use. If +you are contemplating using it in your own code, then you should +probably use this instead: + + (get COMMAND \\='transient--suffix)" + (when command + (cl-check-type command command)) + (cond + (transient--pending-suffix) + ((or transient--prefix + transient-current-prefix) + (let ((suffixes + (cl-remove-if-not + (lambda (obj) + (eq (oref obj command) + (or command + (if (eq this-command 'transient-set-level) + ;; This is how it can look up for which + ;; command it is setting the level. + this-original-command + this-command)))) + (or transient--suffixes + transient-current-suffixes)))) + (or (and (cdr suffixes) + (cl-find-if + (lambda (obj) + (equal (listify-key-sequence (transient--kbd (oref obj key))) + (listify-key-sequence (this-command-keys)))) + suffixes)) + (car suffixes)))) + ((and-let* ((obj (transient--suffix-prototype (or command this-command))) + (obj (clone obj))) + (progn ; work around debbugs#31840 + (transient-init-scope obj) + (transient-init-value obj) + obj))))) + +(defun transient--suffix-prototype (command) + (or (get command 'transient--suffix) + (seq-some (lambda (cmd) (get cmd 'transient--suffix)) + (function-alias-p command)))) + +;;; Keymaps + +(defvar-keymap transient-base-map + :doc "Parent of other keymaps used by Transient. + +This is the parent keymap of all the keymaps that are used in +all transients: `transient-map' (which in turn is the parent +of the transient-specific keymaps), `transient-edit-map' and +`transient-sticky-map'. + +If you change a binding here, then you might also have to edit +`transient-sticky-map' and `transient-common-commands'. While +the latter isn't a proper transient prefix command, it can be +edited using the same functions as used for transients. + +If you add a new command here, then you must also add a binding +to `transient-predicate-map'." + "ESC ESC ESC" #'transient-quit-all + "C-g" #'transient-quit-one + "C-q" #'transient-quit-all + "C-z" #'transient-suspend + "C-v" #'transient-scroll-up + "C-M-v" #'transient-scroll-down + "<next>" #'transient-scroll-up + "<prior>" #'transient-scroll-down) + +(defvar-keymap transient-map + :doc "Top-level keymap used by all transients. + +If you add a new command here, then you must also add a binding +to `transient-predicate-map'. Also see `transient-base-map'." + :parent transient-base-map + "C-u" #'universal-argument + "C--" #'negative-argument + "C-t" #'transient-show + "?" #'transient-help + "C-h" #'transient-help + ;; Also bound to "C-x p" and "C-x n" in transient-common-commands. + "C-M-p" #'transient-history-prev + "C-M-n" #'transient-history-next) + +(defvar-keymap transient-edit-map + :doc "Keymap that is active while a transient in is in \"edit mode\"." + :parent transient-base-map + "?" #'transient-help + "C-h" #'transient-help + "C-x l" #'transient-set-level) + +(defvar-keymap transient-sticky-map + :doc "Keymap that is active while an incomplete key sequence is active." + :parent transient-base-map + "C-g" #'transient-quit-seq) + +(defvar transient--common-command-prefixes '(?\C-x)) + +(put 'transient-common-commands + 'transient--layout + (list + (eval + (car (transient--parse-child + 'transient-common-commands + (vector + :hide + (lambda () + (and (not (memq + (car (bound-and-true-p transient--redisplay-key)) + transient--common-command-prefixes)) + (not transient-show-common-commands))) + (vector + "Value commands" + (list "C-x s " "Set" #'transient-set) + (list "C-x C-s" "Save" #'transient-save) + (list "C-x C-k" "Reset" #'transient-reset) + (list "C-x p " "Previous value" #'transient-history-prev) + (list "C-x n " "Next value" #'transient-history-next)) + (vector + "Sticky commands" + ;; Like `transient-sticky-map' except that + ;; "C-g" has to be bound to a different command. + (list "C-g" "Quit prefix or transient" #'transient-quit-one) + (list "C-q" "Quit transient stack" #'transient-quit-all) + (list "C-z" "Suspend transient stack" #'transient-suspend)) + (vector + "Customize" + (list "C-x t" 'transient-toggle-common :description + (lambda () + (if transient-show-common-commands + "Hide common commands" + "Show common permanently"))) + (list "C-x l" "Show/hide suffixes" #'transient-set-level) + (list "C-x a" #'transient-toggle-level-limit))))) + t))) + +(defvar-keymap transient-popup-navigation-map + :doc "One of the keymaps used when popup navigation is enabled. +See `transient-enable-popup-navigation'." + "<down-mouse-1>" #'transient-noop + "<up>" #'transient-backward-button + "<down>" #'transient-forward-button + "C-r" #'transient-isearch-backward + "C-s" #'transient-isearch-forward + "M-RET" #'transient-push-button) + +(defvar-keymap transient-button-map + :doc "One of the keymaps used when popup navigation is enabled. +See `transient-enable-popup-navigation'." + "<mouse-1>" #'transient-push-button + "<mouse-2>" #'transient-push-button) + +(defvar-keymap transient-resume-mode-map + :doc "Keymap for `transient-resume-mode'. + +This keymap remaps every command that would usually just quit the +documentation buffer to `transient-resume', which additionally +resumes the suspended transient." + "<remap> <Man-quit>" #'transient-resume + "<remap> <Info-exit>" #'transient-resume + "<remap> <quit-window>" #'transient-resume) + +(defvar-keymap transient-predicate-map + :doc "Base keymap used to map common commands to their transient behavior. + +The \"transient behavior\" of a command controls, among other +things, whether invoking the command causes the transient to be +exited or not, and whether infix arguments are exported before +doing so. + +Each \"key\" is a command that is common to all transients and +that is bound in `transient-map', `transient-edit-map', +`transient-sticky-map' and/or `transient-common-command'. + +Each binding is a \"pre-command\", a function that controls the +transient behavior of the respective command. + +For transient commands that are bound in individual transients, +the transient behavior is specified using the `:transient' slot +of the corresponding object." + "<transient-suspend>" #'transient--do-suspend + "<transient-help>" #'transient--do-stay + "<transient-set-level>" #'transient--do-stay + "<transient-history-prev>" #'transient--do-stay + "<transient-history-next>" #'transient--do-stay + "<universal-argument>" #'transient--do-stay + "<universal-argument-more>" #'transient--do-stay + "<negative-argument>" #'transient--do-minus + "<digit-argument>" #'transient--do-stay + "<top-level>" #'transient--do-quit-all + "<transient-quit-all>" #'transient--do-quit-all + "<transient-quit-one>" #'transient--do-quit-one + "<transient-quit-seq>" #'transient--do-stay + "<transient-show>" #'transient--do-stay + "<transient-update>" #'transient--do-stay + "<transient-toggle-common>" #'transient--do-stay + "<transient-set>" #'transient--do-call + "<transient-set-and-exit>" #'transient--do-exit + "<transient-save>" #'transient--do-call + "<transient-save-and-exit>" #'transient--do-exit + "<transient-reset>" #'transient--do-call + "<describe-key-briefly>" #'transient--do-stay + "<describe-key>" #'transient--do-stay + "<transient-scroll-up>" #'transient--do-stay + "<transient-scroll-down>" #'transient--do-stay + "<mwheel-scroll>" #'transient--do-stay + "<scroll-bar-toolkit-scroll>" #'transient--do-stay + "<transient-noop>" #'transient--do-noop + "<transient-mouse-push-button>" #'transient--do-move + "<transient-push-button>" #'transient--do-push-button + "<transient-backward-button>" #'transient--do-move + "<transient-forward-button>" #'transient--do-move + "<transient-isearch-backward>" #'transient--do-move + "<transient-isearch-forward>" #'transient--do-move + ;; If a valid but incomplete prefix sequence is followed by + ;; an unbound key, then Emacs calls the `undefined' command + ;; but does not set `this-command', `this-original-command' + ;; or `real-this-command' accordingly. Instead they are nil. + "<nil>" #'transient--do-warn + ;; Bound to the `mouse-movement' event, this command is similar + ;; to `ignore'. + "<ignore-preserving-kill-region>" #'transient--do-noop) + +(defvar transient--transient-map nil) +(defvar transient--predicate-map nil) +(defvar transient--redisplay-map nil) +(defvar transient--redisplay-key nil) + +(defun transient--push-keymap (var) + (let ((map (symbol-value var))) + (transient--debug " push %s%s" var (if map "" " VOID")) + (when map + (with-demoted-errors "transient--push-keymap: %S" + (internal-push-keymap map 'overriding-terminal-local-map))))) + +(defun transient--pop-keymap (var) + (let ((map (symbol-value var))) + (when map + (transient--debug " pop %s" var) + (with-demoted-errors "transient--pop-keymap: %S" + (internal-pop-keymap map 'overriding-terminal-local-map))))) + +(defun transient--make-transient-map () + (let ((map (make-sparse-keymap))) + (set-keymap-parent map (if transient--editp + transient-edit-map + transient-map)) + (dolist (obj transient--suffixes) + (let ((key (oref obj key))) + (when (vectorp key) + (setq key (key-description key)) + (oset obj key key)) + (when transient-substitute-key-function + (setq key (save-match-data + (funcall transient-substitute-key-function obj))) + (oset obj key key)) + (let* ((kbd (kbd key)) + (cmd (oref obj command)) + (alt (transient--lookup-key map kbd))) + (cond ((not alt) + (define-key map kbd cmd)) + ((eq alt cmd)) + ((transient--inapt-suffix-p obj)) + ((and-let* ((obj (transient-suffix-object alt))) + (transient--inapt-suffix-p obj)) + (define-key map kbd cmd)) + (transient-detect-key-conflicts + (error "Cannot bind %S to %s and also %s" + (string-trim key) cmd alt)) + ((define-key map kbd cmd)))))) + (when-let ((b (keymap-lookup map "-"))) (keymap-set map "<kp-subtract>" b)) + (when-let ((b (keymap-lookup map "="))) (keymap-set map "<kp-equal>" b)) + (when-let ((b (keymap-lookup map "+"))) (keymap-set map "<kp-add>" b)) + (when transient-enable-popup-navigation + ;; `transient--make-redisplay-map' maps only over bindings that are + ;; directly in the base keymap, so that cannot be a composed keymap. + (set-keymap-parent + map (make-composed-keymap + (keymap-parent map) + transient-popup-navigation-map))) + map)) + +(defun transient--make-predicate-map () + (let* ((default (transient--resolve-pre-command + (oref transient--prefix transient-suffix))) + (return (and transient--stack (eq default t))) + (map (make-sparse-keymap))) + (set-keymap-parent map transient-predicate-map) + (when (or (and (slot-boundp transient--prefix 'transient-switch-frame) + (transient--resolve-pre-command + (not (oref transient--prefix transient-switch-frame)))) + (memq (transient--resolve-pre-command + (oref transient--prefix transient-non-suffix)) + '(nil transient--do-warn transient--do-noop))) + (define-key map [handle-switch-frame] #'transient--do-suspend)) + (dolist (obj transient--suffixes) + (let* ((cmd (oref obj command)) + (kind (cond ((get cmd 'transient--prefix) 'prefix) + ((cl-typep obj 'transient-infix) 'infix) + (t 'suffix)))) + (cond + ((oref obj inapt) + (define-key map (vector cmd) #'transient--do-warn-inapt)) + ((slot-boundp obj 'transient) + (define-key map (vector cmd) + (pcase (list kind + (transient--resolve-pre-command (oref obj transient)) + return) + (`(prefix t ,_) #'transient--do-recurse) + (`(prefix nil ,_) #'transient--do-stack) + (`(infix t ,_) #'transient--do-stay) + (`(suffix t ,_) #'transient--do-call) + ('(suffix nil t) #'transient--do-return) + (`(,_ nil ,_) #'transient--do-exit) + (`(,_ ,do ,_) do)))) + ((not (lookup-key transient-predicate-map (vector cmd))) + (define-key map (vector cmd) + (pcase (list kind default return) + (`(prefix ,(or 'transient--do-stay 'transient--do-call) ,_) + #'transient--do-recurse) + (`(prefix t ,_) #'transient--do-recurse) + (`(prefix ,_ ,_) #'transient--do-stack) + (`(infix ,_ ,_) #'transient--do-stay) + (`(suffix t ,_) #'transient--do-call) + ('(suffix nil t) #'transient--do-return) + (`(suffix nil ,_) #'transient--do-exit) + (`(suffix ,do ,_) do))))))) + map)) + +(defun transient--make-redisplay-map () + (setq transient--redisplay-key + (pcase this-command + ('transient-update + (setq transient--showp t) + (setq unread-command-events + (listify-key-sequence (this-single-command-raw-keys)))) + ('transient-quit-seq + (setq unread-command-events + (butlast (listify-key-sequence + (this-single-command-raw-keys)) + 2)) + (butlast transient--redisplay-key)) + (_ nil))) + (let ((topmap (make-sparse-keymap)) + (submap (make-sparse-keymap))) + (when transient--redisplay-key + (define-key topmap (vconcat transient--redisplay-key) submap) + (set-keymap-parent submap transient-sticky-map)) + (map-keymap-internal + (lambda (key def) + (when (and (not (eq key ?\e)) + (listp def) + (keymapp def)) + (define-key topmap (vconcat transient--redisplay-key (list key)) + #'transient-update))) + (if transient--redisplay-key + (let ((key (vconcat transient--redisplay-key))) + (or (lookup-key transient--transient-map key) + (and-let* ((regular (lookup-key local-function-key-map key))) + (lookup-key transient--transient-map (vconcat regular))))) + transient--transient-map)) + topmap)) + +;;; Setup + +(defun transient-setup (&optional name layout edit &rest params) + "Setup the transient specified by NAME. + +This function is called by transient prefix commands to setup the +transient. In that case NAME is mandatory, LAYOUT and EDIT must +be nil and PARAMS may be (but usually is not) used to set, e.g., +the \"scope\" of the transient (see `transient-define-prefix'). + +This function is also called internally, in which case LAYOUT and +EDIT may be non-nil." + (transient--debug 'setup) + (transient--with-emergency-exit :setup + (cond + ((not name) + ;; Switching between regular and edit mode. + (transient--pop-keymap 'transient--transient-map) + (transient--pop-keymap 'transient--redisplay-map) + (setq name (oref transient--prefix command)) + (setq params (list :scope (oref transient--prefix scope)))) + (transient--prefix + ;; Invoked as a ":transient-non-suffix 'transient--do-{stay,call}" + ;; of an outer prefix. Unlike the usual `transient--do-stack', + ;; these predicates fail to clean up after the outer prefix. + (transient--pop-keymap 'transient--transient-map) + (transient--pop-keymap 'transient--redisplay-map)) + ((not (or layout ; resuming parent/suspended prefix + transient-current-command)) ; entering child prefix + (transient--stack-zap)) ; replace suspended prefix, if any + (edit + ;; Returning from help to edit. + (setq transient--editp t))) + (transient--init-objects name layout params) + (transient--init-keymaps) + (transient--history-init transient--prefix) + (setq transient--original-window (selected-window)) + (setq transient--original-buffer (current-buffer)) + (setq transient--minibuffer-depth (minibuffer-depth)) + (transient--redisplay) + (transient--init-transient) + (transient--suspend-which-key-mode))) + +(cl-defgeneric transient-setup-children (group children) + "Setup the CHILDREN of GROUP. +If the value of the `setup-children' slot is non-nil, then call +that function with CHILDREN as the only argument and return the +value. Otherwise return CHILDREN as is." + (if (slot-boundp group 'setup-children) + (funcall (oref group setup-children) children) + children)) + +(defun transient--init-keymaps () + (setq transient--predicate-map (transient--make-predicate-map)) + (setq transient--transient-map (transient--make-transient-map)) + (setq transient--redisplay-map (transient--make-redisplay-map))) + +(defun transient--init-objects (&optional name layout params) + (if name + (setq transient--prefix (transient--init-prefix name params)) + (setq name (oref transient--prefix command))) + (setq transient--refreshp (oref transient--prefix refresh-suffixes)) + (setq transient--layout (or layout (transient--init-suffixes name))) + (setq transient--suffixes (transient--flatten-suffixes transient--layout))) + +(defun transient--init-prefix (name &optional params) + (let ((obj (let ((proto (get name 'transient--prefix))) + (apply #'clone proto + :prototype proto + :level (or (alist-get t (alist-get name transient-levels)) + transient-default-level) + params)))) + (transient--setup-recursion obj) + (transient-init-value obj) + obj)) + +(defun transient--init-suffixes (name) + (let ((levels (alist-get name transient-levels))) + (cl-mapcan (lambda (c) (transient--init-child levels c nil)) + (append (get name 'transient--layout) + (and (not transient--editp) + (get 'transient-common-commands + 'transient--layout)))))) + +(defun transient--flatten-suffixes (layout) + (cl-labels ((s (def) + (cond + ((stringp def) nil) + ((cl-typep def 'transient-information) nil) + ((listp def) (cl-mapcan #'s def)) + ((cl-typep def 'transient-group) + (cl-mapcan #'s (oref def suffixes))) + ((cl-typep def 'transient-suffix) + (list def))))) + (cl-mapcan #'s layout))) + +(defun transient--init-child (levels spec parent) + (cl-etypecase spec + (vector (transient--init-group levels spec parent)) + (list (transient--init-suffix levels spec parent)) + (string (list spec)))) + +(defun transient--init-group (levels spec parent) + (pcase-let ((`(,level ,class ,args ,children) (append spec nil))) + (and-let* (((transient--use-level-p level)) + (obj (apply class :level level args)) + ((transient--use-suffix-p obj)) + ((prog1 t + (when (or (and parent (oref parent inapt)) + (transient--inapt-suffix-p obj)) + (oset obj inapt t)))) + (suffixes (cl-mapcan + (lambda (c) (transient--init-child levels c obj)) + (transient-setup-children obj children)))) + (progn ; work around debbugs#31840 + (oset obj suffixes suffixes) + (list obj))))) + +(defun transient--init-suffix (levels spec parent) + (pcase-let* ((`(,level ,class ,args) spec) + (cmd (plist-get args :command)) + (key (transient--kbd (plist-get args :key))) + (level (or (alist-get (cons cmd key) levels nil nil #'equal) + (alist-get cmd levels) + level))) + (let ((fn (and (symbolp cmd) + (symbol-function cmd)))) + (when (autoloadp fn) + (transient--debug " autoload %s" cmd) + (autoload-do-load fn))) + (when (transient--use-level-p level) + (let ((obj (if (child-of-class-p class 'transient-information) + (apply class :level level args) + (unless (and cmd (symbolp cmd)) + (error "BUG: Non-symbolic suffix command: %s" cmd)) + (if-let ((proto (and cmd (transient--suffix-prototype cmd)))) + (apply #'clone proto :level level args) + (apply class :command cmd :level level args))))) + (cond ((not cmd)) + ((commandp cmd)) + ((or (cl-typep obj 'transient-switch) + (cl-typep obj 'transient-option)) + ;; As a temporary special case, if the package was compiled + ;; with an older version of Transient, then we must define + ;; "anonymous" switch and option commands here. + (defalias cmd #'transient--default-infix-command)) + ((transient--use-suffix-p obj) + (error "Suffix command %s is not defined or autoloaded" cmd))) + (unless (cl-typep obj 'transient-information) + (transient--init-suffix-key obj)) + (when (transient--use-suffix-p obj) + (if (or (and parent (oref parent inapt)) + (transient--inapt-suffix-p obj)) + (oset obj inapt t) + (transient-init-scope obj) + (transient-init-value obj)) + (list obj)))))) + +(cl-defmethod transient--init-suffix-key ((obj transient-suffix)) + (unless (slot-boundp obj 'key) + (error "No key for %s" (oref obj command)))) + +(cl-defmethod transient--init-suffix-key ((obj transient-argument)) + (if (transient-switches--eieio-childp obj) + (cl-call-next-method obj) + (unless (slot-boundp obj 'shortarg) + (when-let ((shortarg (transient--derive-shortarg (oref obj argument)))) + (oset obj shortarg shortarg))) + (unless (slot-boundp obj 'key) + (if (slot-boundp obj 'shortarg) + (oset obj key (oref obj shortarg)) + (error "No key for %s" (oref obj command)))))) + +(defun transient--use-level-p (level &optional edit) + (or transient--all-levels-p + (and transient--editp (not edit)) + (and (>= level 1) + (<= level (oref transient--prefix level))))) + +(defun transient--use-suffix-p (obj) + (let ((transient--shadowed-buffer (current-buffer)) + (transient--pending-suffix obj)) + (transient--do-suffix-p + (oref obj if) + (oref obj if-not) + (oref obj if-nil) + (oref obj if-non-nil) + (oref obj if-mode) + (oref obj if-not-mode) + (oref obj if-derived) + (oref obj if-not-derived) + t))) + +(defun transient--inapt-suffix-p (obj) + (let ((transient--shadowed-buffer (current-buffer)) + (transient--pending-suffix obj)) + (transient--do-suffix-p + (oref obj inapt-if) + (oref obj inapt-if-not) + (oref obj inapt-if-nil) + (oref obj inapt-if-non-nil) + (oref obj inapt-if-mode) + (oref obj inapt-if-not-mode) + (oref obj inapt-if-derived) + (oref obj inapt-if-not-derived) + nil))) + +(defun transient--do-suffix-p + (if if-not if-nil if-non-nil if-mode if-not-mode if-derived if-not-derived + default) + (cond + (if (funcall if)) + (if-not (not (funcall if-not))) + (if-non-nil (symbol-value if-non-nil)) + (if-nil (not (symbol-value if-nil))) + (if-mode (if (atom if-mode) + (eq major-mode if-mode) + (memq major-mode if-mode))) + (if-not-mode (not (if (atom if-not-mode) + (eq major-mode if-not-mode) + (memq major-mode if-not-mode)))) + (if-derived (if (or (atom if-derived) + (>= emacs-major-version 30)) + (derived-mode-p if-derived) + (apply #'derived-mode-p if-derived))) + (if-not-derived (not (if (or (atom if-not-derived) + (>= emacs-major-version 30)) + (derived-mode-p if-not-derived) + (apply #'derived-mode-p if-not-derived)))) + (default))) + +(defun transient--suffix-predicate (spec) + (let ((plist (nth 2 spec))) + (seq-some (lambda (prop) + (and-let* ((pred (plist-get plist prop))) + (list prop pred))) + '( :if :if-not + :if-nil :if-non-nil + :if-mode :if-not-mode + :if-derived :if-not-derived + :inapt-if :inapt-if-not + :inapt-if-nil :inapt-if-non-nil + :inapt-if-mode :inapt-if-not-mode + :inapt-if-derived :inapt-if-not-derived)))) + +;;; Flow-Control + +(defun transient--init-transient () + (transient--debug 'init-transient) + (transient--push-keymap 'transient--transient-map) + (transient--push-keymap 'transient--redisplay-map) + (add-hook 'pre-command-hook #'transient--pre-command) + (add-hook 'post-command-hook #'transient--post-command) + (advice-add 'recursive-edit :around #'transient--recursive-edit) + (when transient--exitp + ;; This prefix command was invoked as the suffix of another. + ;; Prevent `transient--post-command' from removing the hooks + ;; that we just added. + (setq transient--exitp 'replace))) + +(defun transient--refresh-transient () + (transient--debug 'refresh-transient) + (transient--pop-keymap 'transient--predicate-map) + (transient--pop-keymap 'transient--transient-map) + (transient--pop-keymap 'transient--redisplay-map) + (if (eq transient--refreshp 'updated-value) + ;; Preserve the prefix value this once, because the + ;; invoked suffix indicates that it has updated that. + (setq transient--refreshp (oref transient--prefix refresh-suffixes)) + ;; Otherwise update the prefix value from suffix values. + (oset transient--prefix value (transient-get-value))) + (transient--init-objects) + (transient--init-keymaps) + (transient--push-keymap 'transient--transient-map) + (transient--push-keymap 'transient--redisplay-map) + (transient--redisplay)) + +(defun transient--pre-command () + (transient--debug 'pre-command) + (transient--with-emergency-exit :pre-command + ;; The use of `overriding-terminal-local-map' does not prevent the + ;; lookup of command remappings in the overridden maps, which can + ;; lead to a suffix being remapped to a non-suffix. We have to undo + ;; the remapping in that case. However, remapping a non-suffix to + ;; another should remain possible. + (when (and (transient--get-pre-command this-original-command 'suffix) + (not (transient--get-pre-command this-command 'suffix))) + (setq this-command this-original-command)) + (cond + ((memq this-command '(transient-update transient-quit-seq)) + (transient--pop-keymap 'transient--redisplay-map)) + ((and transient--helpp + (not (memq this-command '(transient-quit-one + transient-quit-all)))) + (cond + ((transient-help) + (transient--do-suspend) + (setq this-command 'transient-suspend) + (transient--pre-exit)) + ((not (transient--edebug-command-p)) + (setq this-command 'transient-undefined)))) + ((and transient--editp + (transient-suffix-object) + (not (memq this-command '(transient-quit-one + transient-quit-all + transient-help)))) + (setq this-command 'transient-set-level) + (transient--wrap-command)) + (t + (setq transient--exitp nil) + (let ((exitp (eq (transient--call-pre-command) transient--exit))) + (transient--wrap-command) + (when exitp + (transient--pre-exit))))))) + +(defun transient--pre-exit () + (transient--debug 'pre-exit) + (transient--delete-window) + (transient--timer-cancel) + (transient--pop-keymap 'transient--transient-map) + (transient--pop-keymap 'transient--redisplay-map) + (unless transient--showp + (let ((message-log-max nil)) + (message ""))) + (setq transient--transient-map nil) + (setq transient--predicate-map nil) + (setq transient--redisplay-map nil) + (setq transient--redisplay-key nil) + (setq transient--helpp nil) + (setq transient--editp nil) + (setq transient--prefix nil) + (setq transient--layout nil) + (setq transient--suffixes nil) + (setq transient--original-window nil) + (setq transient--original-buffer nil) + (setq transient--window nil)) + +(defun transient--delete-window () + (when (window-live-p transient--window) + (let ((remain-in-minibuffer-window + (and (minibuffer-selected-window) + (selected-window)))) + ;; Only delete the window if it has never shown another buffer. + (unless (eq (car (window-parameter transient--window 'quit-restore)) + 'other) + (with-demoted-errors "Error while exiting transient: %S" + (delete-window transient--window))) + (when (buffer-live-p transient--buffer) + (kill-buffer transient--buffer)) + (setq transient--buffer nil) + (when remain-in-minibuffer-window + (select-window remain-in-minibuffer-window))))) + +(defun transient--export () + (setq transient-current-prefix transient--prefix) + (setq transient-current-command (oref transient--prefix command)) + (setq transient-current-suffixes transient--suffixes) + (transient--history-push transient--prefix)) + +(defun transient--suspend-override (&optional nohide) + (transient--debug 'suspend-override) + (transient--timer-cancel) + (cond ((and (not nohide) transient-hide-during-minibuffer-read) + (transient--delete-window)) + ((and transient--prefix transient--redisplay-key) + (setq transient--redisplay-key nil) + (when transient--showp + (if-let ((win (minibuffer-selected-window))) + (with-selected-window win + (transient--show)) + (transient--show))))) + (transient--pop-keymap 'transient--transient-map) + (transient--pop-keymap 'transient--redisplay-map) + (remove-hook 'pre-command-hook #'transient--pre-command) + (remove-hook 'post-command-hook #'transient--post-command)) + +(defun transient--resume-override (&optional _ignore) + (transient--debug 'resume-override) + (when (and transient--showp transient-hide-during-minibuffer-read) + (transient--show)) + (transient--push-keymap 'transient--transient-map) + (transient--push-keymap 'transient--redisplay-map) + (add-hook 'pre-command-hook #'transient--pre-command) + (add-hook 'post-command-hook #'transient--post-command)) + +(defun transient--recursive-edit (fn) + (transient--debug 'recursive-edit) + (if (not transient--prefix) + (funcall fn) + (transient--suspend-override (bound-and-true-p edebug-active)) + (funcall fn) ; Already unwind protected. + (cond ((memq this-command '(top-level abort-recursive-edit)) + (setq transient--exitp t) + (transient--post-exit) + (transient--delete-window)) + (transient--prefix + (transient--resume-override))))) + +(defmacro transient--with-suspended-override (&rest body) + (let ((depth (make-symbol "depth")) + (setup (make-symbol "setup")) + (exit (make-symbol "exit"))) + `(if (and transient--transient-map + (memq transient--transient-map + overriding-terminal-local-map)) + (let ((,depth (1+ (minibuffer-depth))) ,setup ,exit) + (setq ,setup + (lambda () "@transient--with-suspended-override" + (transient--debug 'minibuffer-setup) + (remove-hook 'minibuffer-setup-hook ,setup) + (transient--suspend-override))) + (setq ,exit + (lambda () "@transient--with-suspended-override" + (transient--debug 'minibuffer-exit) + (when (= (minibuffer-depth) ,depth) + (transient--resume-override)))) + (unwind-protect + (progn + (add-hook 'minibuffer-setup-hook ,setup) + (add-hook 'minibuffer-exit-hook ,exit) + ,@body) + (remove-hook 'minibuffer-setup-hook ,setup) + (remove-hook 'minibuffer-exit-hook ,exit))) + ,@body))) + +(defun transient--wrap-command () + (static-if (>= emacs-major-version 30) + (letrec + ((prefix transient--prefix) + (suffix this-command) + (advice + (lambda (fn &rest args) + (interactive + (lambda (spec) + (let ((abort t)) + (unwind-protect + (prog1 (let ((debugger #'transient--exit-and-debug)) + (advice-eval-interactive-spec spec)) + (setq abort nil)) + (when abort + (when-let ((unwind (oref prefix unwind-suffix))) + (transient--debug 'unwind-interactive) + (funcall unwind suffix)) + (advice-remove suffix advice) + (oset prefix unwind-suffix nil)))))) + (unwind-protect + (let ((debugger #'transient--exit-and-debug)) + (apply fn args)) + (when-let ((unwind (oref prefix unwind-suffix))) + (transient--debug 'unwind-command) + (funcall unwind suffix)) + (advice-remove suffix advice) + (oset prefix unwind-suffix nil))))) + (when (symbolp this-command) + (advice-add suffix :around advice '((depth . -99)))) + (cl-assert + (>= emacs-major-version 30) nil + "Emacs was downgraded, making it necessary to recompile Transient")) + ;; (< emacs-major-version 30) + (let* ((prefix transient--prefix) + (suffix this-command) + (advice nil) + (advice-interactive + (lambda (spec) + (let ((abort t)) + (unwind-protect + (prog1 (let ((debugger #'transient--exit-and-debug)) + (advice-eval-interactive-spec spec)) + (setq abort nil)) + (when abort + (when-let ((unwind (oref prefix unwind-suffix))) + (transient--debug 'unwind-interactive) + (funcall unwind suffix)) + (advice-remove suffix advice) + (oset prefix unwind-suffix nil)))))) + (advice-body + (lambda (fn &rest args) + (unwind-protect + (let ((debugger #'transient--exit-and-debug)) + (apply fn args)) + (when-let ((unwind (oref prefix unwind-suffix))) + (transient--debug 'unwind-command) + (funcall unwind suffix)) + (advice-remove suffix advice) + (oset prefix unwind-suffix nil))))) + (setq advice `(lambda (fn &rest args) + (interactive ,advice-interactive) + (apply ',advice-body fn args))) + (when (symbolp this-command) + (advice-add suffix :around advice '((depth . -99))))))) + +(defun transient--premature-post-command () + (and (equal (this-command-keys-vector) []) + (= (minibuffer-depth) + (1+ transient--minibuffer-depth)) + (progn + (transient--debug 'premature-post-command) + (transient--suspend-override) + (oset (or transient--prefix transient-current-prefix) + unwind-suffix + (if transient--exitp + #'transient--post-exit + #'transient--resume-override)) + t))) + +(defun transient--post-command () + (unless (transient--premature-post-command) + (transient--debug 'post-command) + (transient--with-emergency-exit :post-command + (cond (transient--exitp (transient--post-exit)) + ;; If `this-command' is the current transient prefix, then we + ;; have already taken care of updating the transient buffer... + ((and (eq this-command (oref transient--prefix command)) + ;; ... but if `prefix-arg' is non-nil, then the values + ;; of `this-command' and `real-this-command' are untrue + ;; because `prefix-command-preserve-state' changes them. + ;; We cannot use `current-prefix-arg' because it is set + ;; too late (in `command-execute'), and if it were set + ;; earlier, then we likely still would not be able to + ;; rely on it, and `prefix-command-preserve-state-hook' + ;; would have to be used to record that a universal + ;; argument is in effect. + (not prefix-arg))) + (transient--refreshp + (transient--refresh-transient)) + ((let ((old transient--redisplay-map) + (new (transient--make-redisplay-map))) + (unless (equal old new) + (transient--pop-keymap 'transient--redisplay-map) + (setq transient--redisplay-map new) + (transient--push-keymap 'transient--redisplay-map)) + (transient--redisplay))))) + (setq transient-current-prefix nil) + (setq transient-current-command nil) + (setq transient-current-suffixes nil))) + +(defun transient--post-exit (&optional command) + (transient--debug 'post-exit) + (unless (and (eq transient--exitp 'replace) + (or transient--prefix + ;; The current command could act as a prefix, + ;; but decided not to call `transient-setup', + ;; or it is prevented from doing so because it + ;; uses the minibuffer and the user aborted + ;; that. + (prog1 nil + (if (let ((obj (transient-suffix-object command))) + (and (slot-boundp obj 'transient) + (oref obj transient))) + ;; This sub-prefix is a transient suffix; + ;; go back to outer prefix, by calling + ;; `transient--stack-pop' further down. + (setq transient--exitp nil) + (transient--stack-zap))))) + (remove-hook 'pre-command-hook #'transient--pre-command) + (remove-hook 'post-command-hook #'transient--post-command) + (advice-remove 'recursive-edit #'transient--recursive-edit)) + (let ((resume (and transient--stack + (not (memq transient--exitp '(replace suspend)))))) + (unless (or resume (eq transient--exitp 'replace)) + (setq transient--showp nil)) + (setq transient--exitp nil) + (setq transient--helpp nil) + (setq transient--editp nil) + (setq transient--all-levels-p nil) + (setq transient--minibuffer-depth 0) + (run-hooks 'transient-exit-hook) + (when resume + (transient--stack-pop)))) + +(defun transient--stack-push () + (transient--debug 'stack-push) + (push (list (oref transient--prefix command) + transient--layout + transient--editp + :transient-suffix (oref transient--prefix transient-suffix) + :scope (oref transient--prefix scope)) + transient--stack)) + +(defun transient--stack-pop () + (transient--debug 'stack-pop) + (and transient--stack + (prog1 t (apply #'transient-setup (pop transient--stack))))) + +(defun transient--stack-zap () + (transient--debug 'stack-zap) + (setq transient--stack nil)) + +(defun transient--redisplay () + (if (or (eq transient-show-popup t) + transient--showp) + (unless + (or (memq this-command transient--scroll-commands) + (and (or (memq this-command '(mouse-drag-region + mouse-set-region)) + (equal (key-description (this-command-keys-vector)) + "<mouse-movement>")) + (and (eq (current-buffer) transient--buffer)))) + (transient--show)) + (when (and (numberp transient-show-popup) + (not (zerop transient-show-popup)) + (not transient--timer)) + (transient--timer-start)) + (transient--show-brief))) + +(defun transient--timer-start () + (setq transient--timer + (run-at-time (abs transient-show-popup) nil + (lambda () + (transient--timer-cancel) + (transient--show) + (let ((message-log-max nil)) + (message "")))))) + +(defun transient--timer-cancel () + (when transient--timer + (cancel-timer transient--timer) + (setq transient--timer nil))) + +(defun transient--debug (arg &rest args) + (when transient--debug + (let ((inhibit-message (not (eq transient--debug 'message)))) + (if (symbolp arg) + (message "-- %-22s (cmd: %s, event: %S, exit: %s%s)" + arg + (cond ((and (symbolp this-command) this-command)) + ((fboundp 'help-fns-function-name) + (help-fns-function-name this-command)) + ((byte-code-function-p this-command) + "#[...]") + (this-command)) + (key-description (this-command-keys-vector)) + transient--exitp + (cond ((keywordp (car args)) + (format ", from: %s" + (substring (symbol-name (car args)) 1))) + ((stringp (car args)) + (concat ", " (apply #'format args))) + ((functionp (car args)) + (concat ", " (apply (car args) (cdr args)))) + (""))) + (apply #'message arg args))))) + +(defun transient--emergency-exit (&optional id) + "Exit the current transient command after an error occurred. +When no transient is active (i.e., when `transient--prefix' is +nil) then do nothing. Optional ID is a keyword identifying the +exit." + (transient--debug 'emergency-exit id) + (when transient--prefix + (setq transient--stack nil) + (setq transient--exitp t) + (transient--pre-exit) + (transient--post-exit))) + +;;; Pre-Commands + +(defun transient--call-pre-command () + (if-let ((fn (transient--get-pre-command this-command))) + (let ((action (funcall fn))) + (when (eq action transient--exit) + (setq transient--exitp (or transient--exitp t))) + action) + (if (let ((keys (this-command-keys-vector))) + (eq (aref keys (1- (length keys))) ?\C-g)) + (setq this-command 'transient-noop) + (unless (transient--edebug-command-p) + (setq this-command 'transient-undefined))) + transient--stay)) + +(defun transient--get-pre-command (&optional cmd enforce-type) + (or (and (not (eq enforce-type 'non-suffix)) + (symbolp cmd) + (lookup-key transient--predicate-map (vector cmd))) + (and (not (eq enforce-type 'suffix)) + (transient--resolve-pre-command + (oref transient--prefix transient-non-suffix) + t)))) + +(defun transient--resolve-pre-command (pre &optional resolve-boolean) + (cond ((booleanp pre) + (if resolve-boolean + (if pre #'transient--do-stay #'transient--do-warn) + pre)) + ((string-match-p "--do-" (symbol-name pre)) pre) + ((let ((sym (intern (format "transient--do-%s" pre)))) + (if (functionp sym) sym pre))))) + +(defun transient--do-stay () + "Call the command without exporting variables and stay transient." + transient--stay) + +(defun transient--do-noop () + "Call `transient-noop' and stay transient." + (setq this-command 'transient-noop) + transient--stay) + +(defun transient--do-warn () + "Call `transient-undefined' and stay transient." + (setq this-command 'transient-undefined) + transient--stay) + +(defun transient--do-warn-inapt () + "Call `transient-inapt' and stay transient." + (setq this-command 'transient-inapt) + transient--stay) + +(defun transient--do-call () + "Call the command after exporting variables and stay transient." + (transient--export) + transient--stay) + +(defun transient--do-return () + "Call the command after exporting variables and return to parent prefix. +If there is no parent prefix, then behave like `transient--do-exit'." + (if (not transient--stack) + (transient--do-exit) + (transient--export) + transient--exit)) + +(defun transient--do-exit () + "Call the command after exporting variables and exit the transient." + (transient--export) + (transient--stack-zap) + transient--exit) + +(defun transient--do-leave () + "Call the command without exporting variables and exit the transient." + (transient--stack-zap) + transient--exit) + +(defun transient--do-push-button () + "Call the command represented by the activated button. +Use that command's pre-command to determine transient behavior." + (if (and (mouse-event-p last-command-event) + (not (eq (posn-window (event-start last-command-event)) + transient--window))) + transient--stay + (setq this-command + (with-selected-window transient--window + (get-text-property (if (mouse-event-p last-command-event) + (posn-point (event-start last-command-event)) + (point)) + 'command))) + (transient--call-pre-command))) + +(defun transient--do-recurse () + "Call the transient prefix command, preparing for return to active transient. +If there is no parent prefix, then just call the command." + (transient--do-stack)) + +(defun transient--setup-recursion (prefix-obj) + (when transient--stack + (let ((command (oref prefix-obj command))) + (when-let ((suffix-obj (transient-suffix-object command))) + (when (memq (if (slot-boundp suffix-obj 'transient) + (oref suffix-obj transient) + (oref transient-current-prefix transient-suffix)) + (list t #'transient--do-recurse)) + (oset prefix-obj transient-suffix t)))))) + +(defun transient--do-stack () + "Call the transient prefix command, stacking the active transient. +Push the active transient to the transient stack." + (transient--export) + (transient--stack-push) + (setq transient--exitp 'replace) + transient--exit) + +(defun transient--do-replace () + "Call the transient prefix command, replacing the active transient. +Do not push the active transient to the transient stack." + (transient--export) + (setq transient--exitp 'replace) + transient--exit) + +(defun transient--do-suspend () + "Suspend the active transient, saving the transient stack." + (transient--stack-push) + (setq transient--exitp 'suspend) + transient--exit) + +(defun transient--do-quit-one () + "If active, quit help or edit mode, else exit the active transient." + (cond (transient--helpp + (setq transient--helpp nil) + transient--stay) + (transient--editp + (setq transient--editp nil) + (transient-setup) + transient--stay) + (prefix-arg + transient--stay) + (transient--exit))) + +(defun transient--do-quit-all () + "Exit all transients without saving the transient stack." + (transient--stack-zap) + transient--exit) + +(defun transient--do-move () + "Call the command if `transient-enable-popup-navigation' is non-nil. +In that case behave like `transient--do-stay', otherwise similar +to `transient--do-warn'." + (unless transient-enable-popup-navigation + (setq this-command 'transient-inhibit-move)) + transient--stay) + +(defun transient--do-minus () + "Call `negative-argument' or pivot to `transient-update'. +If `negative-argument' is invoked using \"-\" then preserve the +prefix argument and pivot to `transient-update'." + (when (equal (this-command-keys) "-") + (setq this-command 'transient-update)) + transient--stay) + +(put 'transient--do-stay 'transient-face 'transient-key-stay) +(put 'transient--do-noop 'transient-face 'transient-key-noop) +(put 'transient--do-warn 'transient-face 'transient-key-noop) +(put 'transient--do-warn-inapt 'transient-face 'transient-key-noop) +(put 'transient--do-call 'transient-face 'transient-key-stay) +(put 'transient--do-return 'transient-face 'transient-key-return) +(put 'transient--do-exit 'transient-face 'transient-key-exit) +(put 'transient--do-leave 'transient-face 'transient-key-exit) + +(put 'transient--do-recurse 'transient-face 'transient-key-stay) +(put 'transient--do-stack 'transient-face 'transient-key-stay) +(put 'transient--do-replace 'transient-face 'transient-key-exit) +(put 'transient--do-suspend 'transient-face 'transient-key-exit) + +(put 'transient--do-quit-one 'transient-face 'transient-key-return) +(put 'transient--do-quit-all 'transient-face 'transient-key-exit) +(put 'transient--do-move 'transient-face 'transient-key-stay) +(put 'transient--do-minus 'transient-face 'transient-key-stay) + +;;; Commands +;;;; Noop + +(defun transient-noop () + "Do nothing at all." + (interactive)) + +(defun transient-undefined () + "Warn the user that the pressed key is not bound to any suffix." + (interactive) + (transient--invalid "Unbound suffix")) + +(defun transient-inapt () + "Warn the user that the invoked command is inapt." + (interactive) + (transient--invalid "Inapt command")) + +(defun transient--invalid (msg) + (ding) + (message "%s: `%s' (Use `%s' to abort, `%s' for help)%s" + msg + (propertize (key-description (this-single-command-keys)) + 'face 'font-lock-warning-face) + (propertize "C-g" 'face 'transient-key) + (propertize "?" 'face 'transient-key) + ;; `this-command' is `transient-undefined' or `transient-inapt'. + ;; Show the command (`this-original-command') the user actually + ;; tried to invoke. + (if-let ((cmd (or (ignore-errors (symbol-name this-original-command)) + (ignore-errors (symbol-name this-command))))) + (format " [%s]" (propertize cmd 'face 'font-lock-warning-face)) + "")) + (unless (and transient--transient-map + (memq transient--transient-map overriding-terminal-local-map)) + (let ((transient--prefix (or transient--prefix 'sic))) + (transient--emergency-exit)) + (view-lossage) + (other-window 1) + (display-warning 'transient "Inconsistent transient state detected. +This should never happen. +Please open an issue and post the shown command log." :error))) + +(defun transient-inhibit-move () + "Warn the user that popup navigation is disabled." + (interactive) + (message "To enable use of `%s', please customize `%s'" + this-original-command + 'transient-enable-popup-navigation)) + +;;;; Core + +(defun transient-quit-all () + "Exit all transients without saving the transient stack." + (interactive)) + +(defun transient-quit-one () + "Exit the current transients, returning to outer transient, if any." + (interactive)) + +(defun transient-quit-seq () + "Abort the current incomplete key sequence." + (interactive)) + +(defun transient-update () + "Redraw the transient's state in the popup buffer." + (interactive) + (setq prefix-arg current-prefix-arg)) + +(defun transient-show () + "Show the transient's state in the popup buffer." + (interactive) + (setq transient--showp t)) + +(defun transient-push-button () + "Invoke the suffix command represented by this button." + (interactive)) + +;;;; Suspend + +(defun transient-suspend () + "Suspend the current transient. +It can later be resumed using `transient-resume', while no other +transient is active." + (interactive)) + +(define-minor-mode transient-resume-mode + "Auxiliary minor-mode used to resume a transient after viewing help.") + +(defun transient-resume () + "Resume a previously suspended stack of transients." + (interactive) + (cond (transient--stack + (let ((winconf transient--restore-winconf)) + (kill-local-variable 'transient--restore-winconf) + (when transient-resume-mode + (transient-resume-mode -1) + (quit-window)) + (when winconf + (set-window-configuration winconf))) + (transient--stack-pop)) + (transient-resume-mode + (kill-local-variable 'transient--restore-winconf) + (transient-resume-mode -1) + (quit-window)) + (t + (message "No suspended transient command")))) + +;;;; Help + +(defun transient-help (&optional interactive) + "Show help for the active transient or one of its suffixes.\n\n(fn)" + (interactive (list t)) + (if interactive + (setq transient--helpp t) + (with-demoted-errors "transient-help: %S" + (when (lookup-key transient--transient-map + (this-single-command-raw-keys)) + (setq transient--helpp nil) + (let ((winconf (current-window-configuration))) + (transient-show-help + (if (eq this-original-command 'transient-help) + transient--prefix + (or (transient-suffix-object) + this-original-command))) + (setq-local transient--restore-winconf winconf)) + (fit-window-to-buffer nil (frame-height) (window-height)) + (transient-resume-mode) + (message (substitute-command-keys + "Type \\`q' to resume transient command.")) + t)))) + +;;;; Level + +(defun transient-set-level (&optional command level) + "Set the level of the transient or one of its suffix commands." + (interactive + (let ((command this-original-command) + (prefix (oref transient--prefix command))) + (and (or (not (eq command 'transient-set-level)) + (and transient--editp + (setq command prefix))) + (list command + (let ((keys (this-single-command-raw-keys))) + (and (lookup-key transient--transient-map keys) + (progn + (transient--show) + (string-to-number + (transient--read-number-N + (format "Set level for `%s': " command) + nil nil (not (eq command prefix))))))))))) + (cond + ((not command) + (setq transient--editp t) + (transient-setup)) + (level + (let* ((prefix (oref transient--prefix command)) + (alist (alist-get prefix transient-levels)) + (akey command)) + (cond ((eq command prefix) + (oset transient--prefix level level) + (setq akey t)) + (t + (oset (transient-suffix-object command) level level) + (when (cdr (cl-remove-if-not (lambda (obj) + (eq (oref obj command) command)) + transient--suffixes)) + (setq akey (cons command (this-command-keys)))))) + (setf (alist-get akey alist) level) + (setf (alist-get prefix transient-levels) alist)) + (transient-save-levels) + (transient--show)) + (t + (transient-undefined)))) + +(transient-define-suffix transient-toggle-level-limit () + "Toggle whether to temporarily displayed suffixes on all levels." + :description + (lambda () + (cond + ((= transient-default-level transient--max-level) + "Always displaying all levels") + (transient--all-levels-p + (format "Hide suffix %s" + (propertize + (format "levels > %s" (oref (transient-prefix-object) level)) + 'face 'transient-higher-level))) + ("Show all suffix levels"))) + :inapt-if (lambda () (= transient-default-level transient--max-level)) + :transient t + (interactive) + (setq transient--all-levels-p (not transient--all-levels-p)) + (setq transient--refreshp t)) + +;;;; Value + +(defun transient-set () + "Set active transient's value for this Emacs session." + (interactive) + (transient-set-value (transient-prefix-object))) + +(defalias 'transient-set-and-exit #'transient-set + "Set active transient's value for this Emacs session and exit.") + +(defun transient-save () + "Save active transient's value for this and future Emacs sessions." + (interactive) + (transient-save-value (transient-prefix-object))) + +(defalias 'transient-save-and-exit #'transient-save + "Save active transient's value for this and future Emacs sessions and exit.") + +(defun transient-reset () + "Clear the set and saved values of the active transient." + (interactive) + (transient-reset-value (transient-prefix-object))) + +(defun transient-history-next () + "Switch to the next value used for the active transient." + (interactive) + (let* ((obj transient--prefix) + (pos (1- (oref obj history-pos))) + (hst (oref obj history))) + (if (< pos 0) + (user-error "End of history") + (oset obj history-pos pos) + (oset obj value (nth pos hst)) + (mapc #'transient-init-value transient--suffixes)))) + +(defun transient-history-prev () + "Switch to the previous value used for the active transient." + (interactive) + (let* ((obj transient--prefix) + (pos (1+ (oref obj history-pos))) + (hst (oref obj history)) + (len (length hst))) + (if (> pos (1- len)) + (user-error "End of history") + (oset obj history-pos pos) + (oset obj value (nth pos hst)) + (mapc #'transient-init-value transient--suffixes)))) + +(transient-define-suffix transient-preset () + "Put this preset into action." + :class transient-value-preset + (interactive) + (transient-prefix-set (oref (transient-suffix-object) set))) + +;;;; Auxiliary + +(defun transient-toggle-common () + "Toggle whether common commands are permanently shown." + (interactive) + (setq transient-show-common-commands (not transient-show-common-commands))) + +(defun transient-toggle-debug () + "Toggle debugging statements for transient commands." + (interactive) + (setq transient--debug (not transient--debug)) + (message "Debugging transient %s" + (if transient--debug "enabled" "disabled"))) + +(transient-define-suffix transient-echo-arguments (arguments) + "Show the transient's active ARGUMENTS in the echo area. +Intended for use in prefixes used for demonstration purposes, +such as when suggesting a new feature or reporting an issue." + :transient t + :description "Echo arguments" + :key "x" + (interactive (list (transient-args transient-current-command))) + (message "%s: %s" + (key-description (this-command-keys)) + (mapconcat (lambda (arg) + (propertize (if (string-match-p " " arg) + (format "%S" arg) + arg) + 'face 'transient-argument)) + arguments " "))) + +;;; Value +;;;; Init + +(cl-defgeneric transient-init-scope (obj) + "Set the scope of the suffix object OBJ. + +The scope is actually a property of the transient prefix, not of +individual suffixes. However it is possible to invoke a suffix +command directly instead of from a transient. In that case, if +the suffix expects a scope, then it has to determine that itself +and store it in its `scope' slot. + +This function is called for all suffix commands, but unless a +concrete method is implemented this falls through to the default +implementation, which is a noop.") + +(cl-defmethod transient-init-scope ((_ transient-suffix)) + "Noop." nil) + +(cl-defgeneric transient-init-value (_) + "Set the initial value of the object OBJ. + +This function is called for all prefix and suffix commands. + +For suffix commands (including infix argument commands) the +default implementation is a noop. Classes derived from the +abstract `transient-infix' class must implement this function. +Non-infix suffix commands usually don't have a value." + nil) + +(cl-defmethod transient-init-value :around ((obj transient-prefix)) + "If bound, then call OBJ's `init-value' function. +Otherwise call the primary method according to object's class." + (if (slot-boundp obj 'init-value) + (funcall (oref obj init-value) obj) + (cl-call-next-method obj))) + +(cl-defmethod transient-init-value :around ((obj transient-infix)) + "If bound, then call OBJ's `init-value' function. +Otherwise call the primary method according to object's class." + (if (slot-boundp obj 'init-value) + (funcall (oref obj init-value) obj) + (cl-call-next-method obj))) + +(cl-defmethod transient-init-value ((obj transient-prefix)) + (if (slot-boundp obj 'value) + (oref obj value) + (oset obj value + (if-let ((saved (assq (oref obj command) transient-values))) + (cdr saved) + (transient-default-value obj))))) + +(cl-defmethod transient-init-value ((obj transient-argument)) + (oset obj value + (let ((value (oref transient--prefix value)) + (argument (and (slot-boundp obj 'argument) + (oref obj argument))) + (multi-value (oref obj multi-value)) + (case-fold-search nil) + (regexp (if (slot-exists-p obj 'argument-regexp) + (oref obj argument-regexp) + (format "\\`%s\\(.*\\)" (oref obj argument))))) + (if (memq multi-value '(t rest)) + (cdr (assoc argument value)) + (let ((match (lambda (v) + (and (stringp v) + (string-match regexp v) + (match-string 1 v))))) + (if multi-value + (delq nil (mapcar match value)) + (cl-some match value))))))) + +(cl-defmethod transient-init-value ((obj transient-switch)) + (oset obj value + (car (member (oref obj argument) + (oref transient--prefix value))))) + +;;;; Default + +(cl-defgeneric transient-default-value (_) + "Return the default value." + nil) + +(cl-defmethod transient-default-value ((obj transient-prefix)) + (if-let ((default (and (slot-boundp obj 'default-value) + (oref obj default-value)))) + (if (functionp default) + (funcall default) + default) + nil)) + +;;;; Read + +(cl-defgeneric transient-infix-read (obj) + "Determine the new value of the infix object OBJ. + +This function merely determines the value; `transient-infix-set' +is used to actually store the new value in the object. + +For most infix classes this is done by reading a value from the +user using the reader specified by the `reader' slot (using the +`transient-infix' method described below). + +For some infix classes the value is changed without reading +anything in the minibuffer, i.e., the mere act of invoking the +infix command determines what the new value should be, based +on the previous value.") + +(cl-defmethod transient-infix-read :around ((obj transient-infix)) + "Refresh the transient buffer and call the next method. + +Also wrap `cl-call-next-method' with two macros: +- `transient--with-suspended-override' allows use of minibuffer. +- `transient--with-emergency-exit' arranges for the transient to + be exited in case of an error." + (transient--show) + (transient--with-emergency-exit :infix-read + (transient--with-suspended-override + (cl-call-next-method obj)))) + +(cl-defmethod transient-infix-read ((obj transient-infix)) + "Read a value while taking care of history. + +This method is suitable for a wide variety of infix commands, +including but not limited to inline arguments and variables. + +If you do not use this method for your own infix class, then +you should likely replicate a lot of the behavior of this +method. If you fail to do so, then users might not appreciate +the lack of history, for example. + +Only for very simple classes that toggle or cycle through a very +limited number of possible values should you replace this with a +simple method that does not handle history. (E.g., for a command +line switch the only possible values are \"use it\" and \"don't use +it\", in which case it is pointless to preserve history.)" + (with-slots (value multi-value always-read allow-empty choices) obj + (if (and value + (not multi-value) + (not always-read) + transient--prefix) + (oset obj value nil) + (let* ((enable-recursive-minibuffers t) + (reader (oref obj reader)) + (choices (if (functionp choices) (funcall choices) choices)) + (prompt (transient-prompt obj)) + (value (if multi-value (string-join value ",") value)) + (history-key (or (oref obj history-key) + (oref obj command))) + (transient--history (alist-get history-key transient-history)) + (transient--history (if (or (null value) + (eq value (car transient--history))) + transient--history + (cons value transient--history))) + (initial-input (and transient-read-with-initial-input + (car transient--history))) + (history (if initial-input + (cons 'transient--history 1) + 'transient--history)) + (value + (cond + (reader (funcall reader prompt initial-input history)) + (multi-value + (completing-read-multiple prompt choices nil nil + initial-input history)) + (choices + (completing-read prompt choices nil t initial-input history)) + ((read-string prompt initial-input history))))) + (cond ((and (equal value "") (not allow-empty)) + (setq value nil)) + ((and (equal value "\"\"") allow-empty) + (setq value ""))) + (when value + (when (and (bound-and-true-p ivy-mode) + (stringp (car transient--history))) + (set-text-properties 0 (length (car transient--history)) nil + (car transient--history))) + (setf (alist-get history-key transient-history) + (delete-dups transient--history))) + value)))) + +(cl-defmethod transient-infix-read ((obj transient-switch)) + "Toggle the switch on or off." + (if (oref obj value) nil (oref obj argument))) + +(cl-defmethod transient-infix-read ((obj transient-switches)) + "Cycle through the mutually exclusive switches. +The last value is \"don't use any of these switches\"." + (let ((choices (mapcar (apply-partially #'format (oref obj argument-format)) + (oref obj choices)))) + (if-let ((value (oref obj value))) + (cadr (member value choices)) + (car choices)))) + +(cl-defmethod transient-infix-read ((command symbol)) + "Elsewhere use the reader of the infix command COMMAND. +Use this if you want to share an infix's history with a regular +stand-alone command." + (if-let ((obj (transient--suffix-prototype command))) + (cl-letf (((symbol-function #'transient--show) #'ignore)) + (transient-infix-read obj)) + (error "Not a suffix command: `%s'" command))) + +;;;; Readers + +(defun transient-read-file (prompt _initial-input _history) + "Read a file." + (file-local-name (expand-file-name (read-file-name prompt)))) + +(defun transient-read-existing-file (prompt _initial-input _history) + "Read an existing file." + (file-local-name (expand-file-name (read-file-name prompt nil nil t)))) + +(defun transient-read-directory (prompt _initial-input _history) + "Read a directory." + (file-local-name (expand-file-name (read-directory-name prompt)))) + +(defun transient-read-existing-directory (prompt _initial-input _history) + "Read an existing directory." + (file-local-name (expand-file-name (read-directory-name prompt nil nil t)))) + +(defun transient-read-number-N0 (prompt initial-input history) + "Read a natural number (including zero) and return it as a string." + (transient--read-number-N prompt initial-input history t)) + +(defun transient-read-number-N+ (prompt initial-input history) + "Read a natural number (excluding zero) and return it as a string." + (transient--read-number-N prompt initial-input history nil)) + +(defun transient--read-number-N (prompt initial-input history include-zero) + (save-match-data + (cl-block nil + (while t + (let ((str (read-from-minibuffer prompt initial-input nil nil history))) + (when (or (string-equal str "") + (string-match-p (if include-zero + "\\`\\(0\\|[1-9][0-9]*\\)\\'" + "\\`[1-9][0-9]*\\'") + str)) + (cl-return str))) + (message "Please enter a natural number (%s zero)." + (if include-zero "including" "excluding")) + (sit-for 1))))) + +(defun transient-read-date (prompt default-time _history) + "Read a date using `org-read-date' (which see)." + (require 'org) + (when (fboundp 'org-read-date) + (org-read-date 'with-time nil nil prompt default-time))) + +;;;; Prompt + +(cl-defgeneric transient-prompt (obj) + "Return the prompt to be used to read infix object OBJ's value.") + +(cl-defmethod transient-prompt ((obj transient-infix)) + "Return the prompt to be used to read infix object OBJ's value. + +This implementation should be suitable for almost all infix +commands. + +If the value of OBJ's `prompt' slot is non-nil, then it must be +a string or a function. If it is a string, then use that. If +it is a function, then call that with OBJ as the only argument. +That function must return a string, which is then used as the +prompt. + +Otherwise, if the value of either the `argument' or `variable' +slot of OBJ is a string, then base the prompt on that (preferring +the former), appending either \"=\" (if it appears to be a +command-line option) or \": \". + +Finally fall through to using \"(BUG: no prompt): \" as the +prompt." + (if-let ((prompt (oref obj prompt))) + (let ((prompt (if (functionp prompt) + (funcall prompt obj) + prompt))) + (if (stringp prompt) + prompt + "(BUG: no prompt): ")) + (or (and-let* ((arg (and (slot-boundp obj 'argument) (oref obj argument)))) + (if (and (stringp arg) (string-suffix-p "=" arg)) + arg + (concat arg ": "))) + (and-let* ((var (and (slot-boundp obj 'variable) (oref obj variable)))) + (and (stringp var) + (concat var ": "))) + "(BUG: no prompt): "))) + +;;;; Set + +(cl-defgeneric transient-infix-set (obj value) + "Set the value of infix object OBJ to VALUE.") + +(cl-defmethod transient-infix-set ((obj transient-infix) value) + "Set the value of infix object OBJ to VALUE." + (oset obj value value)) + +(cl-defmethod transient-infix-set :after ((obj transient-argument) value) + "Unset incompatible infix arguments." + (when-let* ((value) + (val (transient-infix-value obj)) + (arg (if (slot-boundp obj 'argument) + (oref obj argument) + (oref obj argument-format))) + (spec (oref transient--prefix incompatible)) + (filter (lambda (x rule) + (and (member x rule) + (remove x rule)))) + (incomp (nconc + (cl-mapcan (apply-partially filter arg) spec) + (and (not (equal val arg)) + (cl-mapcan (apply-partially filter val) spec))))) + (dolist (obj transient--suffixes) + (when-let* (((cl-typep obj 'transient-argument)) + (val (transient-infix-value obj)) + (arg (if (slot-boundp obj 'argument) + (oref obj argument) + (oref obj argument-format))) + ((if (equal val arg) + (member arg incomp) + (or (member val incomp) + (member arg incomp))))) + (transient-infix-set obj nil))))) + +(defun transient-prefix-set (value) + "Set the value of the active transient prefix to VALUE. +Intended for use by transient suffix commands." + (oset transient--prefix value value) + (setq transient--refreshp 'updated-value)) + +(cl-defgeneric transient-set-value (obj) + "Persist the value of the transient prefix OBJ. +Only intended for use by `transient-set'. +Also see `transient-prefix-set'.") + +(cl-defmethod transient-set-value ((obj transient-prefix)) + (oset (oref obj prototype) value (transient-get-value)) + (transient--history-push obj)) + +;;;; Save + +(cl-defgeneric transient-save-value (obj) + "Save the value of the transient prefix OBJ.") + +(cl-defmethod transient-save-value ((obj transient-prefix)) + (let ((value (transient-get-value))) + (oset (oref obj prototype) value value) + (setf (alist-get (oref obj command) transient-values) value) + (transient-save-values)) + (transient--history-push obj)) + +;;;; Reset + +(cl-defgeneric transient-reset-value (obj) + "Clear the set and saved values of the transient prefix OBJ.") + +(cl-defmethod transient-reset-value ((obj transient-prefix)) + (let ((value (transient-default-value obj))) + (oset obj value value) + (oset (oref obj prototype) value value) + (setf (alist-get (oref obj command) transient-values nil 'remove) nil) + (transient-save-values)) + (transient--history-push obj) + (mapc #'transient-init-value transient--suffixes)) + +;;;; Get + +(defun transient-args (prefix) + "Return the value of the transient prefix command PREFIX. +If the current command was invoked from the transient prefix +command PREFIX, then return the active infix arguments. If +the current command was not invoked from PREFIX, then return +the set, saved or default value for PREFIX." + (cl-mapcan #'transient--get-wrapped-value (transient-suffixes prefix))) + +(defun transient-suffixes (prefix) + "Return the suffix objects of the transient prefix command PREFIX." + (if (eq transient-current-command prefix) + transient-current-suffixes + (let ((transient--prefix (transient--init-prefix prefix))) + (transient--flatten-suffixes + (transient--init-suffixes prefix))))) + +(defun transient-get-value () + (transient--with-emergency-exit :get-value + (cl-mapcan (lambda (obj) + (and (or (not (slot-exists-p obj 'unsavable)) + (not (oref obj unsavable))) + (transient--get-wrapped-value obj))) + (or transient--suffixes transient-current-suffixes)))) + +(defun transient--get-wrapped-value (obj) + (and-let* ((value (transient-infix-value obj))) + (pcase-exhaustive (and (slot-exists-p obj 'multi-value) + (oref obj multi-value)) + ('nil (list value)) + ((or 't 'rest) (list value)) + ('repeat value)))) + +(cl-defgeneric transient-infix-value (obj) + "Return the value of the suffix object OBJ. + +This function is called by `transient-args' (which see), meaning +this function is how the value of a transient is determined so +that the invoked suffix command can use it. + +Currently most values are strings, but that is not set in stone. +Nil is not a value, it means \"no value\". + +Usually only infixes have a value, but see the method for +`transient-suffix'.") + +(cl-defmethod transient-infix-value ((_ transient-suffix)) + "Return nil, which means \"no value\". + +Infix arguments contribute the transient's value while suffix +commands consume it. This function is called for suffixes anyway +because a command that both contributes to the transient's value +and also consumes it is not completely unconceivable. + +If you define such a command, then you must define a derived +class and implement this function because this default method +does nothing." nil) + +(cl-defmethod transient-infix-value ((obj transient-infix)) + "Return the value of OBJ's `value' slot." + (oref obj value)) + +(cl-defmethod transient-infix-value ((obj transient-option)) + "Return ARGUMENT and VALUE as a unit or nil if the latter is nil." + (and-let* ((value (oref obj value))) + (let ((arg (oref obj argument))) + (pcase-exhaustive (oref obj multi-value) + ('nil (concat arg value)) + ((or 't 'rest) (cons arg value)) + ('repeat (mapcar (lambda (v) (concat arg v)) value)))))) + +(cl-defmethod transient-infix-value ((_ transient-variable)) + "Return nil, which means \"no value\". + +Setting the value of a variable is done by, well, setting the +value of the variable. I.e., this is a side-effect and does +not contribute to the value of the transient." + nil) + +;;;; Utilities + +(defun transient-arg-value (arg args) + "Return the value of ARG as it appears in ARGS. + +For a switch return a boolean. For an option return the value as +a string, using the empty string for the empty value, or nil if +the option does not appear in ARGS." + (if (string-suffix-p "=" arg) + (save-match-data + (and-let* ((match (let ((case-fold-search nil) + (re (format "\\`%s\\(?:=\\(.+\\)\\)?\\'" + (substring arg 0 -1)))) + (cl-find-if (lambda (a) + (and (stringp a) + (string-match re a))) + args)))) + (or (match-string 1 match) ""))) + (and (member arg args) t))) + +(defun transient-scope () + "Return the value of the `scope' slot of the current prefix." + (oref (transient-prefix-object) scope)) + +;;; History + +(cl-defgeneric transient--history-key (obj) + "Return OBJ's history key. +If the value of the `history-key' slot is non-nil, then return +that. Otherwise return the value of the `command' slot." + (or (oref obj history-key) + (oref obj command))) + +(cl-defgeneric transient--history-push (obj) + "Push the current value of OBJ to its entry in `transient-history'." + (let ((key (transient--history-key obj))) + (setf (alist-get key transient-history) + (let ((args (transient-get-value))) + (cons args (delete args (alist-get key transient-history))))))) + +(cl-defgeneric transient--history-init (obj) + "Initialize OBJ's `history' slot. +This is the transient-wide history; many individual infixes also +have a history of their own.") + +(cl-defmethod transient--history-init ((obj transient-prefix)) + "Initialize OBJ's `history' slot from the variable `transient-history'." + (let ((val (oref obj value))) + (oset obj history + (cons val (delete val (alist-get (transient--history-key obj) + transient-history)))))) + +;;; Draw + +(defun transient--show-brief () + (let ((message-log-max nil)) + (if (and transient-show-popup (<= transient-show-popup 0)) + (message "%s-" (key-description (this-command-keys))) + (message + "%s- [%s] %s" + (key-description (this-command-keys)) + (oref transient--prefix command) + (mapconcat + #'identity + (sort + (cl-mapcan + (lambda (suffix) + (let ((key (kbd (oref suffix key)))) + ;; Don't list any common commands. + (and (not (memq (oref suffix command) + `(,(lookup-key transient-map key) + ,(lookup-key transient-sticky-map key) + ;; From transient-common-commands: + transient-set + transient-save + transient-history-prev + transient-history-next + transient-quit-one + transient-toggle-common + transient-set-level))) + (list (propertize (oref suffix key) 'face 'transient-key))))) + transient--suffixes) + #'string<) + (propertize "|" 'face 'transient-delimiter)))))) + +(defun transient--show () + (transient--timer-cancel) + (setq transient--showp t) + (let ((transient--shadowed-buffer (current-buffer)) + (focus nil)) + (setq transient--buffer (get-buffer-create transient--buffer-name)) + (with-current-buffer transient--buffer + (when transient-enable-popup-navigation + (setq focus (or (button-get (point) 'command) + (and (not (bobp)) + (button-get (1- (point)) 'command)) + (transient--heading-at-point)))) + (erase-buffer) + (run-hooks 'transient-setup-buffer-hook) + (when transient-force-fixed-pitch + (transient--force-fixed-pitch)) + (setq window-size-fixed t) + (when (bound-and-true-p tab-line-format) + (setq tab-line-format nil)) + (setq header-line-format nil) + (setq mode-line-format + (if (or (natnump transient-mode-line-format) + (eq transient-mode-line-format 'line)) + nil + transient-mode-line-format)) + (setq mode-line-buffer-identification + (symbol-name (oref transient--prefix command))) + (if transient-enable-popup-navigation + (setq-local cursor-in-non-selected-windows 'box) + (setq cursor-type nil)) + (setq display-line-numbers nil) + (setq show-trailing-whitespace nil) + (transient--insert-groups) + (when (or transient--helpp transient--editp) + (transient--insert-help)) + (when-let ((line (transient--separator-line))) + (insert line))) + (unless (window-live-p transient--window) + (setq transient--window + (display-buffer transient--buffer + transient-display-buffer-action))) + (when (window-live-p transient--window) + (with-selected-window transient--window + (goto-char (point-min)) + (when transient-enable-popup-navigation + (transient--goto-button focus)) + (transient--fit-window-to-buffer transient--window))))) + +(defun transient--fit-window-to-buffer (window) + (let ((window-resize-pixelwise t) + (window-size-fixed nil)) + (if (eq (car (window-parameter window 'quit-restore)) 'other) + ;; Grow but never shrink window that previously displayed + ;; another buffer and is going to display that again. + (fit-window-to-buffer window nil (window-height window)) + (fit-window-to-buffer window nil 1)))) + +(defun transient--separator-line () + (and-let* ((height (cond ((not window-system) nil) + ((natnump transient-mode-line-format) + transient-mode-line-format) + ((eq transient-mode-line-format 'line) 1))) + (face `(,@(and (>= emacs-major-version 27) '(:extend t)) + :background + ,(or (face-foreground (transient--key-face nil 'non-suffix) + nil t) + "#gray60")))) + (concat (propertize "__" 'face face 'display `(space :height (,height))) + (propertize "\n" 'face face 'line-height t)))) + +(defmacro transient-with-shadowed-buffer (&rest body) + "While in the transient buffer, temporarily make the shadowed buffer current." + (declare (indent 0) (debug t)) + `(with-current-buffer (or transient--shadowed-buffer (current-buffer)) + ,@body)) + +(defun transient--insert-groups () + (let ((groups (cl-mapcan (lambda (group) + (let ((hide (oref group hide))) + (and (not (and (functionp hide) + (transient-with-shadowed-buffer + (funcall hide)))) + (list group)))) + transient--layout))) + (while-let ((group (pop groups))) + (transient--insert-group group) + (when groups + (insert ?\n))))) + +(defvar transient--max-group-level 1) + +(cl-defgeneric transient--insert-group (group) + "Format GROUP and its elements and insert the result.") + +(cl-defmethod transient--insert-group :around ((group transient-group)) + "Insert GROUP's description, if any." + (when-let ((desc (transient-with-shadowed-buffer + (transient-format-description group)))) + (insert desc ?\n)) + (let ((transient--max-group-level + (max (oref group level) transient--max-group-level)) + (transient--pending-group group)) + (cl-call-next-method group))) + +(cl-defmethod transient--insert-group ((group transient-row)) + (transient--maybe-pad-keys group) + (dolist (suffix (oref group suffixes)) + (insert (transient-with-shadowed-buffer (transient-format suffix))) + (insert " ")) + (insert ?\n)) + +(cl-defmethod transient--insert-group ((group transient-column) + &optional skip-empty) + (transient--maybe-pad-keys group) + (dolist (suffix (oref group suffixes)) + (let ((str (transient-with-shadowed-buffer (transient-format suffix)))) + (unless (and (not skip-empty) (equal str "")) + (insert str) + (unless (string-match-p ".\n\\'" str) + (insert ?\n)))))) + +(cl-defmethod transient--insert-group ((group transient-columns)) + (if transient-force-single-column + (dolist (group (oref group suffixes)) + (transient--insert-group group t)) + (let* ((columns + (mapcar + (lambda (column) + (transient--maybe-pad-keys column group) + (transient-with-shadowed-buffer + `(,@(and-let* ((desc (transient-format-description column))) + (list desc)) + ,@(let ((transient--pending-group column)) + (mapcar #'transient-format (oref column suffixes)))))) + (oref group suffixes))) + (stops (transient--column-stops columns))) + (dolist (row (apply #'transient--mapn #'list columns)) + (let ((stops stops)) + (dolist (cell row) + (let ((stop (pop stops))) + (when cell + (transient--align-to stop) + (insert cell))))) + (insert ?\n))))) + +(cl-defmethod transient--insert-group ((group transient-subgroups)) + (let ((subgroups (oref group suffixes))) + (while-let ((subgroup (pop subgroups))) + (transient--maybe-pad-keys subgroup group) + (transient--insert-group subgroup) + (when subgroups + (insert ?\n))))) + +(cl-defgeneric transient-format (obj) + "Format and return OBJ for display. + +When this function is called, then the current buffer is some +temporary buffer. If you need the buffer from which the prefix +command was invoked to be current, then do so by temporarily +making `transient--original-buffer' current.") + +(cl-defmethod transient-format ((arg string)) + "Return the string ARG after applying the `transient-heading' face." + (propertize arg 'face 'transient-heading)) + +(cl-defmethod transient-format ((_ null)) + "Return a string containing just the newline character." + "\n") + +(cl-defmethod transient-format ((arg integer)) + "Return a string containing just the ARG character." + (char-to-string arg)) + +(cl-defmethod transient-format :around ((obj transient-suffix)) + "Add additional formatting if appropriate. +When reading user input for this infix, then highlight it. +When edit-mode is enabled, then prepend the level information. +When `transient-enable-popup-navigation' is non-nil then format +as a button." + (let ((str (cl-call-next-method obj))) + (when (and (cl-typep obj 'transient-infix) + (eq (oref obj command) this-original-command) + (active-minibuffer-window)) + (setq str (transient--add-face str 'transient-active-infix))) + (when transient--editp + (setq str (concat (let ((level (oref obj level))) + (propertize (format " %s " level) + 'face (if (transient--use-level-p level t) + 'transient-enabled-suffix + 'transient-disabled-suffix))) + str))) + (when (and transient-enable-popup-navigation + (slot-boundp obj 'command)) + (setq str (make-text-button str nil + 'type 'transient + 'command (oref obj command)))) + str)) + +(cl-defmethod transient-format ((obj transient-infix)) + "Return a string generated using OBJ's `format'. +%k is formatted using `transient-format-key'. +%d is formatted using `transient-format-description'. +%v is formatted using `transient-format-value'." + (format-spec (oref obj format) + `((?k . ,(transient-format-key obj)) + (?d . ,(transient-format-description obj)) + (?v . ,(transient-format-value obj))))) + +(cl-defmethod transient-format ((obj transient-suffix)) + "Return a string generated using OBJ's `format'. +%k is formatted using `transient-format-key'. +%d is formatted using `transient-format-description'." + (format-spec (oref obj format) + `((?k . ,(transient-format-key obj)) + (?d . ,(transient-format-description obj))))) + +(cl-defgeneric transient-format-key (obj) + "Format OBJ's `key' for display and return the result.") + +(cl-defmethod transient-format-key :around ((obj transient-suffix)) + "Add `transient-inapt-suffix' face if suffix is inapt." + (let ((str (cl-call-next-method))) + (if (oref obj inapt) + (transient--add-face str 'transient-inapt-suffix) + str))) + +(cl-defmethod transient-format-key ((obj transient-suffix)) + "Format OBJ's `key' for display and return the result." + (let ((key (if (slot-boundp obj 'key) (oref obj key) "")) + (cmd (and (slot-boundp obj 'command) (oref obj command)))) + (when-let ((width (oref transient--pending-group pad-keys))) + (setq key (truncate-string-to-width key width nil ?\s))) + (if transient--redisplay-key + (let ((len (length transient--redisplay-key)) + (seq (cl-coerce (edmacro-parse-keys key t) 'list))) + (cond + ((member (seq-take seq len) + (list transient--redisplay-key + (thread-last transient--redisplay-key + (cl-substitute ?- 'kp-subtract) + (cl-substitute ?= 'kp-equal) + (cl-substitute ?+ 'kp-add)))) + (let ((pre (key-description (vconcat (seq-take seq len)))) + (suf (key-description (vconcat (seq-drop seq len))))) + (setq pre (string-replace "RET" "C-m" pre)) + (setq pre (string-replace "TAB" "C-i" pre)) + (setq suf (string-replace "RET" "C-m" suf)) + (setq suf (string-replace "TAB" "C-i" suf)) + ;; We use e.g., "-k" instead of the more correct "- k", + ;; because the former is prettier. If we did that in + ;; the definition, then we want to drop the space that + ;; is reinserted above. False-positives are possible + ;; for silly bindings like "-C-c C-c". + (unless (string-search " " key) + (setq pre (string-replace " " "" pre)) + (setq suf (string-replace " " "" suf))) + (concat (propertize pre 'face 'transient-unreachable-key) + (and (string-prefix-p (concat pre " ") key) " ") + (propertize suf 'face (transient--key-face cmd)) + (save-excursion + (and (string-match " +\\'" key) + (propertize (match-string 0 key) + 'face 'fixed-pitch)))))) + ((transient--lookup-key transient-sticky-map (kbd key)) + (propertize key 'face (transient--key-face cmd))) + (t + (propertize key 'face 'transient-unreachable-key)))) + (propertize key 'face (transient--key-face cmd))))) + +(cl-defmethod transient-format-key :around ((obj transient-argument)) + "Handle `transient-highlight-mismatched-keys'." + (let ((key (cl-call-next-method obj))) + (cond + ((not transient-highlight-mismatched-keys) key) + ((not (slot-boundp obj 'shortarg)) + (transient--add-face key 'transient-nonstandard-key)) + ((not (string-equal key (oref obj shortarg))) + (transient--add-face key 'transient-mismatched-key)) + (key)))) + +(cl-defgeneric transient-format-description (obj) + "Format OBJ's `description' for display and return the result.") + +(cl-defmethod transient-format-description ((obj transient-suffix)) + "The `description' slot may be a function, in which case that is +called inside the correct buffer (see `transient--insert-group') +and its value is returned to the caller." + (transient--get-description obj)) + +(cl-defmethod transient-format-description ((obj transient-value-preset)) + (pcase-let* (((eieio description key set) obj) + ((eieio value) transient--prefix) + (active (seq-set-equal-p set value))) + (format + "%s %s" + (propertize (or description (format "Preset %s" key)) + 'face (and active 'transient-argument)) + (format (propertize "(%s)" 'face 'transient-delimiter) + (mapconcat (lambda (arg) + (propertize + arg 'face (cond (active 'transient-argument) + ((member arg value) + '((:weight demibold) + transient-inactive-argument)) + ('transient-inactive-argument)))) + set " "))))) + +(cl-defmethod transient-format-description ((obj transient-group)) + "Format the description by calling the next method. +If the result doesn't use the `face' property at all, then apply the +face `transient-heading' to the complete string." + (and-let* ((desc (transient--get-description obj))) + (cond ((oref obj inapt) + (propertize desc 'face 'transient-inapt-suffix)) + ((text-property-not-all 0 (length desc) 'face nil desc) + desc) + ((propertize desc 'face 'transient-heading))))) + +(cl-defmethod transient-format-description :around ((obj transient-suffix)) + "Format the description by calling the next method. +If the result is nil, then use \"(BUG: no description)\" as the +description. If the OBJ's `key' is currently unreachable, then +apply the face `transient-unreachable' to the complete string." + (let ((desc (or (cl-call-next-method obj) + (and (slot-boundp transient--prefix 'suffix-description) + (funcall (oref transient--prefix suffix-description) + obj))))) + (if desc + (when-let ((face (transient--get-face obj 'face))) + (setq desc (transient--add-face desc face t))) + (setq desc (propertize "(BUG: no description)" 'face 'error))) + (when (if transient--all-levels-p + (> (oref obj level) transient--default-prefix-level) + (and transient-highlight-higher-levels + (> (max (oref obj level) transient--max-group-level) + transient--default-prefix-level))) + (setq desc (transient--add-face desc 'transient-higher-level))) + (when-let ((inapt-face (and (oref obj inapt) + (transient--get-face obj 'inapt-face)))) + (setq desc (transient--add-face desc inapt-face))) + (when (and (slot-boundp obj 'key) + (transient--key-unreachable-p obj)) + (setq desc (transient--add-face desc 'transient-unreachable))) + desc)) + +(cl-defgeneric transient-format-value (obj) + "Format OBJ's value for display and return the result.") + +(cl-defmethod transient-format-value ((obj transient-suffix)) + (propertize (oref obj argument) + 'face (if (oref obj value) + 'transient-argument + 'transient-inactive-argument))) + +(cl-defmethod transient-format-value ((obj transient-option)) + (let ((argument (oref obj argument))) + (if-let ((value (oref obj value))) + (pcase-exhaustive (oref obj multi-value) + ('nil + (concat (propertize argument 'face 'transient-argument) + (propertize value 'face 'transient-value))) + ((or 't 'rest) + (concat (propertize (if (string-suffix-p " " argument) + argument + (concat argument " ")) + 'face 'transient-argument) + (propertize (mapconcat #'prin1-to-string value " ") + 'face 'transient-value))) + ('repeat + (mapconcat (lambda (value) + (concat (propertize argument 'face 'transient-argument) + (propertize value 'face 'transient-value))) + value " "))) + (propertize argument 'face 'transient-inactive-argument)))) + +(cl-defmethod transient-format-value ((obj transient-switches)) + (with-slots (value argument-format choices) obj + (format (propertize argument-format + 'face (if value + 'transient-argument + 'transient-inactive-argument)) + (format + (propertize "[%s]" 'face 'transient-delimiter) + (mapconcat + (lambda (choice) + (propertize choice 'face + (if (equal (format argument-format choice) value) + 'transient-value + 'transient-inactive-value))) + choices + (propertize "|" 'face 'transient-delimiter)))))) + +(cl-defmethod transient--get-description ((obj transient-child)) + (and-let* ((desc (oref obj description))) + (if (functionp desc) + (if (= (car (transient--func-arity desc)) 1) + (funcall desc obj) + (funcall desc)) + desc))) + +(cl-defmethod transient--get-face ((obj transient-suffix) slot) + (and-let* (((slot-boundp obj slot)) + (face (slot-value obj slot))) + (if (and (not (facep face)) + (functionp face)) + (let ((transient--pending-suffix obj)) + (if (= (car (transient--func-arity face)) 1) + (funcall face obj) + (funcall face))) + face))) + +(defun transient--add-face (string face &optional append beg end) + (let ((str (copy-sequence string))) + (add-face-text-property (or beg 0) (or end (length str)) face append str) + str)) + +(defun transient--key-face (&optional cmd enforce-type) + (or (and transient-semantic-coloring + (not transient--helpp) + (not transient--editp) + (or (and cmd (get cmd 'transient-face)) + (get (transient--get-pre-command cmd enforce-type) + 'transient-face))) + (if cmd 'transient-key 'transient-key-noop))) + +(defun transient--key-unreachable-p (obj) + (and transient--redisplay-key + (let ((key (oref obj key))) + (not (or (equal (seq-take (cl-coerce (edmacro-parse-keys key t) 'list) + (length transient--redisplay-key)) + transient--redisplay-key) + (transient--lookup-key transient-sticky-map (kbd key))))))) + +(defun transient--lookup-key (keymap key) + (let ((val (lookup-key keymap key))) + (and val (not (integerp val)) val))) + +(defun transient--maybe-pad-keys (group &optional parent) + (when-let ((pad (or (oref group pad-keys) + (and parent (oref parent pad-keys))))) + (oset group pad-keys + (apply #'max + (if (integerp pad) pad 0) + (seq-keep (lambda (suffix) + (and (eieio-object-p suffix) + (slot-boundp suffix 'key) + (length (oref suffix key)))) + (oref group suffixes)))))) + +(defun transient--pixel-width (string) + (save-window-excursion + (with-temp-buffer + (insert string) + (set-window-dedicated-p nil nil) + (set-window-buffer nil (current-buffer)) + (car (window-text-pixel-size + nil (line-beginning-position) (point)))))) + +(defun transient--column-stops (columns) + (let* ((var-pitch (or transient-align-variable-pitch + (oref transient--prefix variable-pitch))) + (char-width (and var-pitch (transient--pixel-width " ")))) + (transient--seq-reductions-from + (apply-partially #'+ (* 2 (if var-pitch char-width 1))) + (transient--mapn + (lambda (cells min) + (apply #'max + (if min (if var-pitch (* min char-width) min) 0) + (mapcar (if var-pitch #'transient--pixel-width #'length) cells))) + columns + (oref transient--prefix column-widths)) + 0))) + +(defun transient--align-to (stop) + (unless (zerop stop) + (insert (if (or transient-align-variable-pitch + (oref transient--prefix variable-pitch)) + (propertize " " 'display `(space :align-to (,stop))) + (make-string (max 0 (- stop (current-column))) ?\s))))) + +(defun transient-command-summary-or-name (obj) + "Return the summary or name of the command represented by OBJ. + +If the command has a doc-string, then return the first line of +that, else its name. + +Intended to be temporarily used as the `:suffix-description' of +a prefix command, while porting a regular keymap to a transient." + (let ((command (oref obj command))) + (if-let ((doc (documentation command))) + (propertize (car (split-string doc "\n")) 'face 'font-lock-doc-face) + (propertize (symbol-name command) 'face 'font-lock-function-name-face)))) + +;;; Help + +(cl-defgeneric transient-show-help (obj) + "Show documentation for the command represented by OBJ.") + +(cl-defmethod transient-show-help ((obj transient-prefix)) + "Call `show-help' if non-nil, else show `info-manual', +if non-nil, else show the `man-page' if non-nil, else use +`describe-function'." + (with-slots (show-help info-manual man-page command) obj + (cond (show-help (funcall show-help obj)) + (info-manual (transient--show-manual info-manual)) + (man-page (transient--show-manpage man-page)) + ((transient--describe-function command))))) + +(cl-defmethod transient-show-help ((obj transient-suffix)) + "Call `show-help' if non-nil, else use `describe-function'. +Also used to dispatch showing documentation for the current +prefix. If the suffix is a sub-prefix, then also call the +prefix method." + (cond + ((eq this-command 'transient-help) + (transient-show-help transient--prefix)) + ((let ((prefix (get (oref obj command) + 'transient--prefix))) + (and prefix (not (eq (oref transient--prefix command) this-command)) + (prog1 t (transient-show-help prefix))))) + ((if-let ((show-help (oref obj show-help))) + (funcall show-help obj) + (transient--describe-function this-command))))) + +(cl-defmethod transient-show-help ((obj transient-infix)) + "Call `show-help' if non-nil, else show the `man-page' +if non-nil, else use `describe-function'. When showing the +manpage, then try to jump to the correct location." + (if-let ((show-help (oref obj show-help))) + (funcall show-help obj) + (if-let ((man-page (oref transient--prefix man-page)) + (argument (and (slot-boundp obj 'argument) + (oref obj argument)))) + (transient--show-manpage man-page argument) + (transient--describe-function this-command)))) + +;; `cl-generic-generalizers' doesn't support `command' et al. +(cl-defmethod transient-show-help (cmd) + "Show the command doc-string." + (transient--describe-function cmd)) + +(defun transient--describe-function (fn) + (describe-function fn) + (unless (derived-mode-p 'help-mode) + (when-let* ((buf (get-buffer "*Help*")) + (win (or (and buf (get-buffer-window buf)) + (cl-find-if (lambda (win) + (with-current-buffer (window-buffer win) + (derived-mode-p 'help-mode))) + (window-list))))) + (select-window win)))) + +(defun transient--show-manual (manual) + (info manual)) + +(defun transient--show-manpage (manpage &optional argument) + (require 'man) + (let* ((Man-notify-method 'meek) + (buf (Man-getpage-in-background manpage)) + (proc (get-buffer-process buf))) + (while (and proc (eq (process-status proc) 'run)) + (accept-process-output proc)) + (switch-to-buffer buf) + (when argument + (transient--goto-argument-description argument)))) + +(defun transient--goto-argument-description (arg) + (goto-char (point-min)) + (let ((case-fold-search nil) + ;; This matches preceding/proceeding options. Options + ;; such as "-a", "-S[<keyid>]", and "--grep=<pattern>" + ;; are matched by this regex without the shy group. + ;; The ". " in the shy group is for options such as + ;; "-m parent-number", and the "-[^[:space:]]+ " is + ;; for options such as "--mainline parent-number" + (others "-\\(?:. \\|-[^[:space:]]+ \\)?[^[:space:]]+")) + (when (re-search-forward + (if (equal arg "--") + ;; Special case. + "^[\t\s]+\\(--\\(?: \\|$\\)\\|\\[--\\]\\)" + ;; Should start with whitespace and may have + ;; any number of options before and/or after. + (format + "^[\t\s]+\\(?:%s, \\)*?\\(?1:%s\\)%s\\(?:, %s\\)*$" + others + ;; Options don't necessarily end in an "=" + ;; (e.g., "--gpg-sign[=<keyid>]") + (string-remove-suffix "=" arg) + ;; Simple options don't end in an "=". Splitting this + ;; into 2 cases should make getting false positives + ;; less likely. + (if (string-suffix-p "=" arg) + ;; "[^[:space:]]*[^.[:space:]]" matches the option + ;; value, which is usually after the option name + ;; and either '=' or '[='. The value can't end in + ;; a period, as that means it's being used at the + ;; end of a sentence. The space is for options + ;; such as '--mainline parent-number'. + "\\(?: \\|\\[?=\\)[^[:space:]]*[^.[:space:]]" + ;; Either this doesn't match anything (e.g., "-a"), + ;; or the option is followed by a value delimited + ;; by a "[", "<", or ":". A space might appear + ;; before this value, as in "-f <file>". The + ;; space alternative is for options such as + ;; "-m parent-number". + "\\(?:\\(?: \\| ?[\\[<:]\\)[^[:space:]]*[^.[:space:]]\\)?") + others)) + nil t) + (goto-char (match-beginning 1))))) + +(defun transient--insert-help () + (unless (looking-back "\n\n" 2) + (insert "\n")) + (when transient--helpp + (insert + (format (propertize "\ +Type a %s to show help for that suffix command, or %s to show manual. +Type %s to exit help.\n" + 'face 'transient-heading) + (propertize "<KEY>" 'face 'transient-key) + (propertize "?" 'face 'transient-key) + (propertize "C-g" 'face 'transient-key)))) + (when transient--editp + (unless transient--helpp + (insert + (format (propertize "\ +Type a %s to set level for that suffix command. +Type %s to set what levels are available for this prefix command.\n" + 'face 'transient-heading) + (propertize "<KEY>" 'face 'transient-key) + (propertize "C-x l" 'face 'transient-key)))) + (with-slots (level) transient--prefix + (insert + (format (propertize " +Suffixes on levels %s are available. +Suffixes on levels %s and %s are unavailable.\n" + 'face 'transient-heading) + (propertize (format "1-%s" level) + 'face 'transient-enabled-suffix) + (propertize " 0 " + 'face 'transient-disabled-suffix) + (propertize (format ">=%s" (1+ level)) + 'face 'transient-disabled-suffix)))))) + +;;; Popup Navigation + +(defun transient-scroll-up (&optional arg) + "Scroll text of transient popup window upward ARG lines. +If ARG is nil scroll near full screen. This is a wrapper +around `scroll-up-command' (which see)." + (interactive "^P") + (with-selected-window transient--window + (scroll-up-command arg))) + +(defun transient-scroll-down (&optional arg) + "Scroll text of transient popup window down ARG lines. +If ARG is nil scroll near full screen. This is a wrapper +around `scroll-down-command' (which see)." + (interactive "^P") + (with-selected-window transient--window + (scroll-down-command arg))) + +(defun transient-backward-button (n) + "Move to the previous button in the transient popup buffer. +See `backward-button' for information about N." + (interactive "p") + (with-selected-window transient--window + (backward-button n t))) + +(defun transient-forward-button (n) + "Move to the next button in the transient popup buffer. +See `forward-button' for information about N." + (interactive "p") + (with-selected-window transient--window + (forward-button n t))) + +(define-button-type 'transient + 'face nil + 'keymap transient-button-map) + +(defun transient--goto-button (command) + (cond + ((stringp command) + (when (re-search-forward (concat "^" (regexp-quote command)) nil t) + (goto-char (match-beginning 0)))) + (command + (while (and (ignore-errors (forward-button 1)) + (not (eq (button-get (button-at (point)) 'command) command)))) + (unless (eq (button-get (button-at (point)) 'command) command) + (goto-char (point-min)) + (forward-button 1))))) + +(defun transient--heading-at-point () + (and (eq (get-text-property (point) 'face) 'transient-heading) + (let ((beg (line-beginning-position))) + (buffer-substring-no-properties + beg (next-single-property-change + beg 'face nil (line-end-position)))))) + +;;; Compatibility +;;;; Popup Isearch + +(defvar-keymap transient--isearch-mode-map + :parent isearch-mode-map + "<remap> <isearch-exit>" #'transient-isearch-exit + "<remap> <isearch-cancel>" #'transient-isearch-cancel + "<remap> <isearch-abort>" #'transient-isearch-abort) + +(defun transient-isearch-backward (&optional regexp-p) + "Do incremental search backward. +With a prefix argument, do an incremental regular expression +search instead." + (interactive "P") + (transient--isearch-setup) + (let ((isearch-mode-map transient--isearch-mode-map)) + (isearch-mode nil regexp-p))) + +(defun transient-isearch-forward (&optional regexp-p) + "Do incremental search forward. +With a prefix argument, do an incremental regular expression +search instead." + (interactive "P") + (transient--isearch-setup) + (let ((isearch-mode-map transient--isearch-mode-map)) + (isearch-mode t regexp-p))) + +(defun transient-isearch-exit () + "Like `isearch-exit' but adapted for `transient'." + (interactive) + (isearch-exit) + (transient--isearch-exit)) + +(defun transient-isearch-cancel () + "Like `isearch-cancel' but adapted for `transient'." + (interactive) + (condition-case nil (isearch-cancel) (quit)) + (transient--isearch-exit)) + +(defun transient-isearch-abort () + "Like `isearch-abort' but adapted for `transient'." + (interactive) + (let ((around (lambda (fn) + (condition-case nil (funcall fn) (quit)) + (transient--isearch-exit)))) + (advice-add 'isearch-cancel :around around) + (unwind-protect + (isearch-abort) + (advice-remove 'isearch-cancel around)))) + +(defun transient--isearch-setup () + (select-window transient--window) + (transient--suspend-override t)) + +(defun transient--isearch-exit () + (select-window transient--original-window) + (transient--resume-override)) + +;;;; Edebug + +(defun transient--edebug-command-p () + (and (bound-and-true-p edebug-active) + (or (memq this-command '(top-level abort-recursive-edit)) + (string-prefix-p "edebug" (symbol-name this-command))))) + +;;;; Miscellaneous + +(cl-pushnew (list nil (concat "^\\s-*(" + (eval-when-compile + (regexp-opt + '("transient-define-prefix" + "transient-define-suffix" + "transient-define-infix" + "transient-define-argument") + t)) + "\\s-+\\(" lisp-mode-symbol-regexp "\\)") + 2) + lisp-imenu-generic-expression :test #'equal) + +(declare-function which-key-mode "which-key" (&optional arg)) + +(defun transient--suspend-which-key-mode () + (when (bound-and-true-p which-key-mode) + (which-key-mode -1) + (add-hook 'transient-exit-hook #'transient--resume-which-key-mode))) + +(defun transient--resume-which-key-mode () + (unless transient--prefix + (which-key-mode 1) + (remove-hook 'transient-exit-hook #'transient--resume-which-key-mode))) + +(defun transient-bind-q-to-quit () + "Modify some keymaps to bind \"q\" to the appropriate quit command. + +\"C-g\" is the default binding for such commands now, but Transient's +predecessor Magit-Popup used \"q\" instead. If you would like to get +that binding back, then call this function in your init file like so: + + (with-eval-after-load \\='transient + (transient-bind-q-to-quit)) + +Individual transients may already bind \"q\" to something else +and such a binding would shadow the quit binding. If that is the +case then \"Q\" is bound to whatever \"q\" would have been bound +to by setting `transient-substitute-key-function' to a function +that does that. Of course \"Q\" may already be bound to something +else, so that function binds \"M-q\" to that command instead. +Of course \"M-q\" may already be bound to something else, but +we stop there." + (keymap-set transient-base-map "q" #'transient-quit-one) + (keymap-set transient-sticky-map "q" #'transient-quit-seq) + (setq transient-substitute-key-function + #'transient-rebind-quit-commands)) + +(defun transient-rebind-quit-commands (obj) + "See `transient-bind-q-to-quit'." + (let ((key (oref obj key))) + (cond ((string-equal key "q") "Q") + ((string-equal key "Q") "M-q") + (key)))) + +(defun transient--force-fixed-pitch () + (require 'face-remap) + (face-remap-reset-base 'default) + (face-remap-add-relative 'default 'fixed-pitch)) + +(defun transient--func-arity (fn) + (func-arity (advice--cd*r (if (symbolp fn) (symbol-function fn) fn)))) + +(defun transient--seq-reductions-from (function sequence initial-value) + (let ((acc (list initial-value))) + (seq-doseq (elt sequence) + (push (funcall function (car acc) elt) acc)) + (nreverse acc))) + +(defun transient--mapn (function &rest lists) + "Apply FUNCTION to elements of LISTS. +Like `cl-mapcar' but while that stops when the shortest list +is exhausted, continue until the longest list is, using nil +as stand-in for elements of exhausted lists." + (let (result) + (while (catch 'more (mapc (lambda (l) (and l (throw 'more t))) lists) nil) + (push (apply function (mapcar #'car-safe lists)) result) + (setq lists (mapcar #'cdr lists))) + (nreverse result))) + +;;; Font-Lock + +(defconst transient-font-lock-keywords + (eval-when-compile + `((,(concat "(" + (regexp-opt (list "transient-define-prefix" + "transient-define-infix" + "transient-define-argument" + "transient-define-suffix") + t) + "\\_>[ \t'(]*" + "\\(\\(?:\\sw\\|\\s_\\)+\\)?") + (1 'font-lock-keyword-face) + (2 'font-lock-function-name-face nil t))))) + +(font-lock-add-keywords 'emacs-lisp-mode transient-font-lock-keywords) + +;;; Auxiliary Classes +;;;; `transient-lisp-variable' + +(defclass transient-lisp-variable (transient-variable) + ((reader :initform #'transient-lisp-variable--reader) + (always-read :initform t) + (set-value :initarg :set-value :initform #'set)) + "[Experimental] Class used for Lisp variables.") + +(cl-defmethod transient-init-value ((obj transient-lisp-variable)) + (oset obj value (symbol-value (oref obj variable)))) + +(cl-defmethod transient-infix-set ((obj transient-lisp-variable) value) + (funcall (oref obj set-value) + (oref obj variable) + (oset obj value value))) + +(cl-defmethod transient-format-description ((obj transient-lisp-variable)) + (or (cl-call-next-method obj) + (symbol-name (oref obj variable)))) + +(cl-defmethod transient-format-value ((obj transient-lisp-variable)) + (propertize (prin1-to-string (oref obj value)) + 'face 'transient-value)) + +(cl-defmethod transient-prompt ((obj transient-lisp-variable)) + (if (and (slot-boundp obj 'prompt) + (oref obj prompt)) + (cl-call-next-method obj) + (format "Set %s: " (oref obj variable)))) + +(defun transient-lisp-variable--reader (prompt initial-input _history) + (read--expression prompt initial-input)) + +;;; _ +(provide 'transient) +;; Local Variables: +;; indent-tabs-mode: nil +;; checkdoc-symbol-words: ("command-line" "edit-mode" "help-mode") +;; End: +;;; transient.el ends here diff --git a/emacs/elpa/transient-20240805.1231/transient.elc b/emacs/elpa/transient-20240817.1959/transient.elc Binary files differ. diff --git a/emacs/elpa/transient-20240817.1959/transient.info b/emacs/elpa/transient-20240817.1959/transient.info @@ -0,0 +1,3318 @@ +This is transient.info, produced by makeinfo version 6.8 from +transient.texi. + + Copyright (C) 2018–2024 Free Software Foundation, Inc. + + You can redistribute this document 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 document 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. + +INFO-DIR-SECTION Emacs misc features +START-INFO-DIR-ENTRY +* Transient: (transient). Transient Commands. +END-INFO-DIR-ENTRY + + +File: transient.info, Node: Top, Next: Introduction, Up: (dir) + +Transient User and Developer Manual +*********************************** + +Transient is the library used to implement the keyboard-driven “menus” +in Magit. It is distributed as a separate package, so that it can be +used to implement similar menus in other packages. + + This manual can be bit hard to digest when getting started. A useful +resource to get over that hurdle is Psionic K’s interactive tutorial, +available at <https://github.com/positron-solutions/transient-showcase>. + +This manual is for Transient v0.7.4-6-gf4aac84. + + Copyright (C) 2018–2024 Free Software Foundation, Inc. + + You can redistribute this document 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 document 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. + +* Menu: + +* Introduction:: +* Usage:: +* Modifying Existing Transients:: +* Defining New Commands:: +* Classes and Methods:: +* FAQ:: +* Keystroke Index:: +* Command and Function Index:: +* Variable Index:: +* Concept Index:: +* GNU General Public License:: + +— The Detailed Node Listing — + +Usage + +* Invoking Transients:: +* Aborting and Resuming Transients:: +* Common Suffix Commands:: +* Saving Values:: +* Using History:: +* Getting Help for Suffix Commands:: +* Enabling and Disabling Suffixes:: +* Other Commands:: +* Configuration:: + +Defining New Commands + +* Technical Introduction:: +* Defining Transients:: +* Binding Suffix and Infix Commands:: +* Defining Suffix and Infix Commands:: +* Using Infix Arguments:: +* Transient State:: + +Binding Suffix and Infix Commands + +* Group Specifications:: +* Suffix Specifications:: + + +Classes and Methods + +* Group Classes:: +* Group Methods:: +* Prefix Classes:: +* Suffix Classes:: +* Suffix Methods:: +* Prefix Slots:: +* Suffix Slots:: +* Predicate Slots:: + +Suffix Methods + +* Suffix Value Methods:: +* Suffix Format Methods:: + + + + +File: transient.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top + +1 Introduction +************** + +Transient is the library used to implement the keyboard-driven “menus” +in Magit. It is distributed as a separate package, so that it can be +used to implement similar menus in other packages. + + This manual can be bit hard to digest when getting started. A useful +resource to get over that hurdle is Psionic K’s interactive tutorial, +available at <https://github.com/positron-solutions/transient-showcase>. + +Some things that Transient can do +================================= + + • Display current state of arguments + • Display and manage lifecycle of modal bindings + • Contextual user interface + • Flow control for wizard-like composition of interactive forms + • History & persistence + • Rendering arguments for controlling CLI programs + +Complexity in CLI programs +========================== + +Complexity tends to grow with time. How do you manage the complexity of +commands? Consider the humble shell command ‘ls’. It now has over +_fifty_ command line options. Some of these are boolean flags (‘ls +-l’). Some take arguments (‘ls --sort=s’). Some have no effect unless +paired with other flags (‘ls -lh’). Some are mutually exclusive. Some +shell commands even have so many options that they introduce +_subcommands_ (‘git branch’, ‘git commit’), each with their own rich set +of options (‘git branch -f’). + +Using Transient for composing interactive commands +================================================== + +What about Emacs commands used interactively? How do these handle +options? One solution is to make many versions of the same command, so +you don’t need to! Consider: ‘delete-other-windows’ vs. +‘delete-other-windows-vertically’ (among many similar examples). + + Some Emacs commands will simply prompt you for the next "argument" +(‘M-x switch-to-buffer’). Another common solution is to use prefix +arguments which usually start with ‘C-u’. Sometimes these are sensibly +numerical in nature (‘C-u 4 M-x forward-paragraph’ to move forward 4 +paragraphs). But sometimes they function instead as boolean "switches" +(‘C-u C-SPACE’ to jump to the last mark instead of just setting it, ‘C-u +C-u C-SPACE’ to unconditionally set the mark). Since there aren’t many +standards for the use of prefix options, you have to read the command’s +documentation to find out what the possibilities are. + + But when an Emacs command grows to have a truly large set of options +and arguments, with dependencies between them, lots of option values, +etc., these simple approaches just don’t scale. Transient is designed +to solve this issue. Think of it as the humble prefix argument ‘C-u’, +_raised to the power of 10_. Like ‘C-u’, it is key driven. Like the +shell, it supports boolean "flag" options, options that take arguments, +and even "sub-commands", with their own options. But instead of +searching through a man page or command documentation, well-designed +transients _guide_ their users to the relevant set of options (and even +their possible values!) directly, taking into account any important +pre-existing Emacs settings. And while for shell commands like ‘ls’, +there is only one way to "execute" (hit ‘Return’!), transients can +"execute" using multiple different keys tied to one of many +self-documenting _actions_ (imagine having 5 different colored return +keys on your keyboard!). Transients make navigating and setting large, +complex groups of command options and arguments easy. Fun even. Once +you’ve tried it, it’s hard to go back to the ‘C-u what can I do here +again?’ way. + + +File: transient.info, Node: Usage, Next: Modifying Existing Transients, Prev: Introduction, Up: Top + +2 Usage +******* + +* Menu: + +* Invoking Transients:: +* Aborting and Resuming Transients:: +* Common Suffix Commands:: +* Saving Values:: +* Using History:: +* Getting Help for Suffix Commands:: +* Enabling and Disabling Suffixes:: +* Other Commands:: +* Configuration:: + + +File: transient.info, Node: Invoking Transients, Next: Aborting and Resuming Transients, Up: Usage + +2.1 Invoking Transients +======================= + +A transient prefix command is invoked like any other command by pressing +the key that is bound to that command. The main difference to other +commands is that a transient prefix command activates a transient +keymap, which temporarily binds the transient’s infix and suffix +commands. Bindings from other keymaps may, or may not, be disabled +while the transient state is in effect. + + There are two kinds of commands that are available after invoking a +transient prefix command; infix and suffix commands. Infix commands set +some value (which is then shown in a popup buffer), without leaving the +transient. Suffix commands, on the other hand, usually quit the +transient and they may use the values set by the infix commands, i.e., +the infix *arguments*. + + Instead of setting arguments to be used by a suffix command, infix +commands may also set some value by side-effect, e.g., by setting the +value of some variable. + + +File: transient.info, Node: Aborting and Resuming Transients, Next: Common Suffix Commands, Prev: Invoking Transients, Up: Usage + +2.2 Aborting and Resuming Transients +==================================== + +To quit the transient without invoking a suffix command press ‘C-g’. + + Key bindings in transient keymaps may be longer than a single event. +After pressing a valid prefix key, all commands whose bindings do not +begin with that prefix key are temporarily unavailable and grayed out. +To abort the prefix key press ‘C-g’ (which in this case only quits the +prefix key, but not the complete transient). + + A transient prefix command can be bound as a suffix of another +transient. Invoking such a suffix replaces the current transient state +with a new transient state, i.e., the available bindings change and the +information displayed in the popup buffer is updated accordingly. +Pressing ‘C-g’ while a nested transient is active only quits the +innermost transient, causing a return to the previous transient. + + ‘C-q’ or ‘C-z’ on the other hand always exits all transients. If you +use the latter, then you can later resume the stack of transients using +‘M-x transient-resume’. + +‘C-g’ (‘transient-quit-seq’) +‘C-g’ (‘transient-quit-one’) + This key quits the currently active incomplete key sequence, if + any, or else the current transient. When quitting the current + transient, it returns to the previous transient, if any. + + Transient’s predecessor bound ‘q’ instead of ‘C-g’ to the quit +command. To learn how to get that binding back see +‘transient-bind-q-to-quit’’s documentation string. + +‘C-q’ (‘transient-quit-all’) + This command quits the currently active incomplete key sequence, if + any, and all transients, including the active transient and all + suspended transients, if any. + +‘C-z’ (‘transient-suspend’) + Like ‘transient-quit-all’, this command quits an incomplete key + sequence, if any, and all transients. Additionally, it saves the + stack of transients so that it can easily be resumed (which is + particularly useful if you quickly need to do “something else” and + the stack is deeper than a single transient, and/or you have + already changed the values of some infix arguments). + + Note that only a single stack of transients can be saved at a time. + If another stack is already saved, then saving a new stack discards + the previous stack. + +‘M-x transient-resume’ + This command resumes the previously suspended stack of transients, + if any. + + +File: transient.info, Node: Common Suffix Commands, Next: Saving Values, Prev: Aborting and Resuming Transients, Up: Usage + +2.3 Common Suffix Commands +========================== + +A few shared suffix commands are available in all transients. These +suffix commands are not shown in the popup buffer by default. + + This includes the aborting commands mentioned in the previous +section, as well as some other commands that are all bound to ‘C-x KEY’. +After ‘C-x’ is pressed, a section featuring all these common commands is +temporarily shown in the popup buffer. After invoking one of them, the +section disappears again. Note, however, that one of these commands is +described as “Show common permanently”; invoke that if you want the +common commands to always be shown for all transients. + +‘C-x t’ (‘transient-toggle-common’) + This command toggles whether the generic commands that are common + to all transients are always displayed or only after typing the + incomplete prefix key sequence ‘C-x’. This only affects the + current Emacs session. + + -- User Option: transient-show-common-commands + This option controls whether shared suffix commands are shown + alongside the transient-specific infix and suffix commands. By + default, the shared commands are not shown to avoid overwhelming + the user with too many options. + + While a transient is active, pressing ‘C-x’ always shows the common + commands. The value of this option can be changed for the current + Emacs session by typing ‘C-x t’ while a transient is active. + + The other common commands are described in either the previous or in +one of the following sections. + + Some of Transient’s key bindings differ from the respective bindings +of Magit-Popup; see *note FAQ:: for more information. + + +File: transient.info, Node: Saving Values, Next: Using History, Prev: Common Suffix Commands, Up: Usage + +2.4 Saving Values +================= + +After setting the infix arguments in a transient, the user can save +those arguments for future invocations. + + Most transients will start out with the saved arguments when they are +invoked. There are a few exceptions, though. Some transients are +designed so that the value that they use is stored externally as the +buffer-local value of some variable. Invoking such a transient again +uses the buffer-local value. (1) + + If the user does not save the value and just exits using a regular +suffix command, then the value is merely saved to the transient’s +history. That value won’t be used when the transient is next invoked, +but it is easily accessible (see *note Using History::). + +‘C-x s’ (‘transient-set’) + This command saves the value of the active transient for this Emacs + session. + +‘C-x C-s’ (‘transient-save’) + Save the value of the active transient persistently across Emacs + sessions. + +‘C-x C-k’ (‘transient-reset’) + Clear the set and saved values of the active transient. + + -- User Option: transient-values-file + This option names the file that is used to persist the values of + transients between Emacs sessions. + + ---------- Footnotes ---------- + + (1) ‘magit-diff’ and ‘magit-log’ are two prominent examples, and +their handling of buffer-local values is actually a bit more complicated +than outlined above and even customizable. + + +File: transient.info, Node: Using History, Next: Getting Help for Suffix Commands, Prev: Saving Values, Up: Usage + +2.5 Using History +================= + +Every time the user invokes a suffix command the transient’s current +value is saved to its history. These values can be cycled through the +same way one can cycle through the history of commands that read +user-input in the minibuffer. + +‘C-M-p’ (‘transient-history-prev’) +‘C-x p’ + This command switches to the previous value used for the active + transient. + +‘C-M-n’ (‘transient-history-next’) +‘C-x n’ + This command switches to the next value used for the active + transient. + + In addition to the transient-wide history, Transient of course +supports per-infix history. When an infix reads user-input using the +minibuffer, the user can use the regular minibuffer history commands to +cycle through previously used values. Usually the same keys as those +mentioned above are bound to those commands. + + Authors of transients should arrange for different infix commands +that read the same kind of value to also use the same history key (see +*note Suffix Slots::). + + Both kinds of history are saved to a file when Emacs is exited. + + -- User Option: transient-history-file + This option names the file that is used to persist the history of + transients and their infixes between Emacs sessions. + + -- User Option: transient-history-limit + This option controls how many history elements are kept at the time + the history is saved in ‘transient-history-file’. + + +File: transient.info, Node: Getting Help for Suffix Commands, Next: Enabling and Disabling Suffixes, Prev: Using History, Up: Usage + +2.6 Getting Help for Suffix Commands +==================================== + +Transients can have many suffixes and infixes that the user might not be +familiar with. To make it trivial to get help for these, Transient +provides access to the documentation directly from the active transient. + +‘C-h’ (‘transient-help’) + This command enters help mode. When help mode is active, typing a + key shows information about the suffix command that the key + normally is bound to (instead of invoking it). Pressing ‘C-h’ a + second time shows information about the _prefix_ command. + + After typing a key, the stack of transient states is suspended and + information about the suffix command is shown instead. Typing ‘q’ + in the help buffer buries that buffer and resumes the transient + state. + + What sort of documentation is shown depends on how the transient was +defined. For infix commands that represent command-line arguments this +ideally shows the appropriate manpage. ‘transient-help’ then tries to +jump to the correct location within that. Info manuals are also +supported. The fallback is to show the command’s documentation string, +for non-infix suffixes this is usually appropriate. + + +File: transient.info, Node: Enabling and Disabling Suffixes, Next: Other Commands, Prev: Getting Help for Suffix Commands, Up: Usage + +2.7 Enabling and Disabling Suffixes +=================================== + +The user base of a package that uses transients can be very diverse. +This is certainly the case for Magit; some users have been using it and +Git for a decade, while others are just getting started now. + + For that reason a mechanism is needed that authors can use to +classify a transient’s infixes and suffixes along the +essentials...everything spectrum. We use the term “levels” to describe +that mechanism. + + Each suffix command is placed on a level and each transient has a +level (called “transient-level”), which controls which suffix commands +are available. Integers between 1 and 7 (inclusive) are valid levels. +For suffixes, 0 is also valid; it means that the suffix is not displayed +at any level. + + The levels of individual transients and/or their individual suffixes +can be changed interactively, by invoking the transient and then +pressing ‘C-x l’ to enter the “edit” mode, see below. + + The default level for both transients and their suffixes is 4. The +‘transient-default-level’ option only controls the default for +transients. The default suffix level is always 4. The authors of +transients should place certain suffixes on a higher level, if they +expect that it won’t be of use to most users, and they should place very +important suffixes on a lower level, so that they remain available even +if the user lowers the transient level. + + -- User Option: transient-default-level + This option controls which suffix levels are made available by + default. It sets the transient-level for transients for which the + user has not set that individually. + + -- User Option: transient-levels-file + This option names the file that is used to persist the levels of + transients and their suffixes between Emacs sessions. + +‘C-x l’ (‘transient-set-level’) + This command enters edit mode. When edit mode is active, then all + infixes and suffixes that are currently usable are displayed along + with their levels. The colors of the levels indicate whether they + are enabled or not. The level of the transient is also displayed + along with some usage information. + + In edit mode, pressing the key that would usually invoke a certain + suffix instead prompts the user for the level that suffix should be + placed on. + + Help mode is available in edit mode. + + To change the transient level press ‘C-x l’ again. + + To exit edit mode press ‘C-g’. + + Note that edit mode does not display any suffixes that are not + currently usable. ‘magit-rebase’, for example, shows different + suffixes depending on whether a rebase is already in progress or + not. The predicates also apply in edit mode. + + Therefore, to control which suffixes are available given a certain + state, you have to make sure that that state is currently active. + +‘C-x a’ (‘transient-toggle-level-limit’) + This command toggle whether suffixes that are on levels higher than + the level specified by ‘transient-default-level’ are temporarily + available anyway. + + +File: transient.info, Node: Other Commands, Next: Configuration, Prev: Enabling and Disabling Suffixes, Up: Usage + +2.8 Other Commands +================== + +When invoking a transient in a small frame, the transient window may not +show the complete buffer, making it necessary to scroll, using the +following commands. These commands are never shown in the transient +window, and the key bindings are the same as for ‘scroll-up-command’ and +‘scroll-down-command’ in other buffers. + + -- Command: transient-scroll-up arg + This command scrolls text of transient popup window upward ARG + lines. If ARG is ‘nil’, then it scrolls near full screen. This is + a wrapper around ‘scroll-up-command’ (which see). + + -- Command: transient-scroll-down arg + This command scrolls text of transient popup window down ARG lines. + If ARG is ‘nil’, then it scrolls near full screen. This is a + wrapper around ‘scroll-down-command’ (which see). + + +File: transient.info, Node: Configuration, Prev: Other Commands, Up: Usage + +2.9 Configuration +================= + +More options are described in *note Common Suffix Commands::, in *note +Saving Values::, in *note Using History:: and in *note Enabling and +Disabling Suffixes::. + +Essential Options +----------------- + +Also see *note Common Suffix Commands::. + + -- User Option: transient-show-popup + This option controls whether the current transient’s infix and + suffix commands are shown in the popup buffer. + + • If ‘t’ (the default) then the popup buffer is shown as soon as + a transient prefix command is invoked. + + • If ‘nil’, then the popup buffer is not shown unless the user + explicitly requests it, by pressing an incomplete prefix key + sequence. + + • If a number, then the a brief one-line summary is shown + instead of the popup buffer. If zero or negative, then not + even that summary is shown; only the pressed key itself is + shown. + + The popup is shown when the user explicitly requests it by + pressing an incomplete prefix key sequence. Unless this is + zero, the popup is shown after that many seconds of inactivity + (using the absolute value). + + -- User Option: transient-enable-popup-navigation + This option controls whether navigation commands are enabled in the + transient popup buffer. + + While a transient is active the transient popup buffer is not the + current buffer, making it necessary to use dedicated commands to + act on that buffer itself. This is disabled by default. If this + option is non-‘nil’, then the following features are available: + + • ‘<UP>’ moves the cursor to the previous suffix. + • ‘<DOWN>’ moves the cursor to the next suffix. + • ‘<RET>’ invokes the suffix the cursor is on. + • ‘mouse-1’ invokes the clicked on suffix. + • ‘C-s’ and ‘C-r’ start isearch in the popup buffer. + + -- User Option: transient-display-buffer-action + This option specifies the action used to display the transient + popup buffer. The transient popup buffer is displayed in a window + using ‘(display-buffer BUFFER transient-display-buffer-action)’. + + The value of this option has the form ‘(FUNCTION . ALIST)’, where + FUNCTION is a function or a list of functions. Each such function + should accept two arguments: a buffer to display and an alist of + the same form as ALIST. See *note (elisp)Choosing Window::, for + details. + + The default is: + + (display-buffer-in-side-window + (side . bottom) + (inhibit-same-window . t) + (window-parameters (no-other-window . t))) + + This displays the window at the bottom of the selected frame. + Another useful FUNCTION is ‘display-buffer-below-selected’, which + is what ‘magit-popup’ used by default. For more alternatives see + *note (elisp)Buffer Display Action Functions::, and *note + (elisp)Buffer Display Action Alists::. + + Note that the buffer that was current before the transient buffer + is shown should remain the current buffer. Many suffix commands + act on the thing at point, if appropriate, and if the transient + buffer became the current buffer, then that would change what is at + point. To that effect ‘inhibit-same-window’ ensures that the + selected window is not used to show the transient buffer. + + It may be possible to display the window in another frame, but + whether that works in practice depends on the window-manager. If + the window manager selects the new window (Emacs frame), then that + unfortunately changes which buffer is current. + + If you change the value of this option, then you might also want to + change the value of ‘transient-mode-line-format’. + +Accessibility Options +--------------------- + + -- User Option: transient-force-single-column + This option controls whether the use of a single column to display + suffixes is enforced. This might be useful for users with low + vision who use large text and might otherwise have to scroll in two + dimensions. + +Auxiliary Options +----------------- + + -- User Option: transient-mode-line-format + This option controls whether the transient popup buffer has a + mode-line, separator line, or neither. + + If ‘nil’, then the buffer has no mode-line. If the buffer is not + displayed right above the echo area, then this probably is not a + good value. + + If ‘line’ (the default) or a natural number, then the buffer has no + mode-line, but a line is drawn is drawn in its place. If a number + is used, that specifies the thickness of the line. On termcap + frames we cannot draw lines, so there ‘line’ and numbers are + synonyms for ‘nil’. + + The color of the line is used to indicate if non-suffixes are + allowed and whether they exit the transient. The foreground color + of ‘transient-key-noop’ (if non-suffix are disallowed), + ‘transient-key-stay’ (if allowed and transient stays active), or + ‘transient-key-exit’ (if allowed and they exit the transient) is + used to draw the line. + + Otherwise this can be any mode-line format. See *note (elisp)Mode + Line Format::, for details. + + -- User Option: transient-semantic-coloring + This option controls whether colors are used to indicate the + transient behavior of commands. + + If non-‘nil’, then the key binding of each suffix is colorized to + indicate whether it exits the transient state or not. The color of + the prefix is indicated using the line that is drawn when the value + of ‘transient-mode-line-format’ is ‘line’. + + -- User Option: transient-highlight-mismatched-keys + This option controls whether key bindings of infix commands that do + not match the respective command-line argument should be + highlighted. For other infix commands this option has no effect. + + When this option is non-‘nil’, the key binding for an infix + argument is highlighted when only a long argument (e.g., + ‘--verbose’) is specified but no shorthand (e.g., ‘-v’). In the + rare case that a shorthand is specified but the key binding does + not match, then it is highlighted differently. + + Highlighting mismatched key bindings is useful when learning the + arguments of the underlying command-line tool; you wouldn’t want to + learn any short-hands that do not actually exist. + + The highlighting is done using one of the faces + ‘transient-mismatched-key’ and ‘transient-nonstandard-key’. + + -- User Option: transient-substitute-key-function + This function is used to modify key bindings. If the value of this + option is ‘nil’ (the default), then no substitution is performed. + + This function is called with one argument, the prefix object, and + must return a key binding description, either the existing key + description it finds in the ‘key’ slot, or the key description that + replaces the prefix key. It could be used to make other + substitutions, but that is discouraged. + + For example, ‘=’ is hard to reach using my custom keyboard layout, + so I substitute ‘(’ for that, which is easy to reach using a layout + optimized for lisp. + + (setq transient-substitute-key-function + (lambda (obj) + (let ((key (oref obj key))) + (if (string-match "\\`\\(=\\)[a-zA-Z]" key) + (replace-match "(" t t key 1) + key)))) + + -- User Option: transient-read-with-initial-input + This option controls whether the last history element is used as + the initial minibuffer input when reading the value of an infix + argument from the user. If ‘nil’, there is no initial input and + the first element has to be accessed the same way as the older + elements. + + -- User Option: transient-hide-during-minibuffer-read + This option controls whether the transient buffer is hidden while + user input is being read in the minibuffer. + + -- User Option: transient-align-variable-pitch + This option controls whether columns are aligned pixel-wise in the + popup buffer. + + If this is non-‘nil’, then columns are aligned pixel-wise to + support variable-pitch fonts. Keys are not aligned, so you should + use a fixed-pitch font for the ‘transient-key’ face. Other key + faces inherit from that face unless a theme is used that breaks + that relationship. + + This option is intended for users who use a variable-pitch font for + the ‘default’ face. + + -- User Option: transient-force-fixed-pitch + This option controls whether to force the use of a monospaced font + in popup buffer. Even if you use a proportional font for the + ‘default’ face, you might still want to use a monospaced font in + transient’s popup buffer. Setting this option to ‘t’ causes + ‘default’ to be remapped to ‘fixed-pitch’ in that buffer. + +Developer Options +----------------- + +These options are mainly intended for developers. + + -- User Option: transient-detect-key-conflicts + This option controls whether key binding conflicts should be + detected at the time the transient is invoked. If so, this results + in an error, which prevents the transient from being used. Because + of that, conflicts are ignored by default. + + Conflicts cannot be determined earlier, i.e., when the transient is + being defined and when new suffixes are being added, because at + that time there can be false-positives. It is actually valid for + multiple suffixes to share a common key binding, provided the + predicates of those suffixes prevent that more than one of them is + enabled at a time. + + -- User Option: transient-highlight-higher-levels + This option controls whether suffixes that would not be available + by default are highlighted. + + When non-‘nil’ then the descriptions of suffixes are highlighted if + their level is above 4, the default of ‘transient-default-level’. + Assuming you have set that variable to 7, this highlights all + suffixes that won’t be available to users without them making the + same customization. + + +File: transient.info, Node: Modifying Existing Transients, Next: Defining New Commands, Prev: Usage, Up: Top + +3 Modifying Existing Transients +******************************* + +To an extent, transients can be customized interactively, see *note +Enabling and Disabling Suffixes::. This section explains how existing +transients can be further modified non-interactively. Let’s begin with +an example: + + (transient-append-suffix 'magit-patch-apply "-3" + '("-R" "Apply in reverse" "--reverse")) + + This inserts a new infix argument to toggle the ‘--reverse’ argument +after the infix argument that toggles ‘-3’ in ‘magit-patch-apply’. + + The following functions share a few arguments: + + • PREFIX is a transient prefix command, a symbol. + + • SUFFIX is a transient infix or suffix specification in the same + form as expected by ‘transient-define-prefix’. Note that an infix + is a special kind of suffix. Depending on context “suffixes” means + “suffixes (including infixes)” or “non-infix suffixes”. Here it + means the former. See *note Suffix Specifications::. + + SUFFIX may also be a group in the same form as expected by + ‘transient-define-prefix’. See *note Group Specifications::. + + • LOC is a command, a key vector, a key description (a string as + returned by ‘key-description’), or a list specifying coordinates + (the last element may also be a command or key). For example ‘(1 0 + -1)’ identifies the last suffix (‘-1’) of the first subgroup (‘0’) + of the second group (‘1’). + + If LOC is a list of coordinates, then it can be used to identify a + group, not just an individual suffix command. + + The function ‘transient-get-suffix’ can be useful to determine + whether a certain coordination list identifies the suffix or group + that you expect it to identify. In hairy cases it may be necessary + to look at the definition of the transient prefix command. + + These functions operate on the information stored in the +‘transient--layout’ property of the PREFIX symbol. Suffix entries in +that tree are not objects but have the form ‘(LEVEL CLASS PLIST)’, where +PLIST should set at least ‘:key’, ‘:description’ and ‘:command’. + + -- Function: transient-insert-suffix prefix loc suffix &optional + keep-other + -- Function: transient-append-suffix prefix loc suffix &optional + keep-other + These functions insert the suffix or group SUFFIX into PREFIX + before or after LOC. + + Conceptually adding a binding to a transient prefix is similar to + adding a binding to a keymap, but this is complicated by the fact + that multiple suffix commands can be bound to the same key, + provided they are never active at the same time, see *note + Predicate Slots::. + + Unfortunately both false-positives and false-negatives are + possible. To deal with the former use non-‘nil’ KEEP-OTHER. To + deal with the latter remove the conflicting binding explicitly. + + -- Function: transient-replace-suffix prefix loc suffix + This function replaces the suffix or group at LOC in PREFIX with + suffix or group SUFFIX. + + -- Function: transient-remove-suffix prefix loc + This function removes the suffix or group at LOC in PREFIX. + + -- Function: transient-get-suffix prefix loc + This function returns the suffix or group at LOC in PREFIX. The + returned value has the form mentioned above. + + -- Function: transient-suffix-put prefix loc prop value + This function edits the suffix or group at LOC in PREFIX, by + setting the PROP of its plist to VALUE. + + Most of these functions do not signal an error if they cannot perform +the requested modification. The functions that insert new suffixes show +a warning if LOC cannot be found in PREFIX without signaling an error. +The reason for doing it like this is that establishing a key binding +(and that is what we essentially are trying to do here) should not +prevent the rest of the configuration from loading. Among these +functions only ‘transient-get-suffix’ and ‘transient-suffix-put’ may +signal an error. + + +File: transient.info, Node: Defining New Commands, Next: Classes and Methods, Prev: Modifying Existing Transients, Up: Top + +4 Defining New Commands +*********************** + +* Menu: + +* Technical Introduction:: +* Defining Transients:: +* Binding Suffix and Infix Commands:: +* Defining Suffix and Infix Commands:: +* Using Infix Arguments:: +* Transient State:: + + +File: transient.info, Node: Technical Introduction, Next: Defining Transients, Up: Defining New Commands + +4.1 Technical Introduction +========================== + +Taking inspiration from prefix keys and prefix arguments, Transient +implements a similar abstraction involving a prefix command, infix +arguments and suffix commands. + + When the user calls a transient prefix command, a transient +(temporary) keymap is activated, which binds the transient’s infix and +suffix commands, and functions that control the transient state are +added to ‘pre-command-hook’ and ‘post-command-hook’. The available +suffix and infix commands and their state are shown in a popup buffer +until the transient state is exited by invoking a suffix command. + + Calling an infix command causes its value to be changed. How that is +done depends on the type of the infix command. The simplest case is an +infix command that represents a command-line argument that does not take +a value. Invoking such an infix command causes the switch to be toggled +on or off. More complex infix commands may read a value from the user, +using the minibuffer. + + Calling a suffix command usually causes the transient to be exited; +the transient keymaps and hook functions are removed, the popup buffer +no longer shows information about the (no longer bound) suffix commands, +the values of some public global variables are set, while some internal +global variables are unset, and finally the command is actually called. +Suffix commands can also be configured to not exit the transient. + + A suffix command can, but does not have to, use the infix arguments +in much the same way any command can choose to use or ignore the prefix +arguments. For a suffix command that was invoked from a transient, the +variable ‘transient-current-suffixes’ and the function ‘transient-args’ +serve about the same purpose as the variables ‘prefix-arg’ and +‘current-prefix-arg’ do for any command that was called after the prefix +arguments have been set using a command such as ‘universal-argument’. + + Transient can be used to implement simple “command dispatchers”. The +main benefit then is that the user can see all the available commands in +a popup buffer, which can be thought of as a “menus”. That is useful by +itself because it frees the user from having to remember all the keys +that are valid after a certain prefix key or command. Magit’s +‘magit-dispatch’ (on ‘C-x M-g’) command is an example of using Transient +to merely implement a command dispatcher. + + In addition to that, Transient also allows users to interactively +pass arguments to commands. These arguments can be much more complex +than what is reasonable when using prefix arguments. There is a limit +to how many aspects of a command can be controlled using prefix +arguments. Furthermore, what a certain prefix argument means for +different commands can be completely different, and users have to read +documentation to learn and then commit to memory what a certain prefix +argument means to a certain command. + + Transient suffix commands, on the other hand, can accept dozens of +different arguments without the user having to remember anything. When +using Transient, one can call a command with arguments that are just as +complex as when calling the same function non-interactively from Lisp. + + Invoking a transient suffix command with arguments is similar to +invoking a command in a shell with command-line completion and history +enabled. One benefit of the Transient interface is that it remembers +history not only on a global level (“this command was invoked using +these arguments, and previously it was invoked using those other +arguments”), but also remembers the values of individual arguments +independently. See *note Using History::. + + After a transient prefix command is invoked, ‘C-h KEY’ can be used to +show the documentation for the infix or suffix command that ‘KEY’ is +bound to (see *note Getting Help for Suffix Commands::), and infixes and +suffixes can be removed from the transient using ‘C-x l KEY’. Infixes +and suffixes that are disabled by default can be enabled the same way. +See *note Enabling and Disabling Suffixes::. + + Transient ships with support for a few different types of specialized +infix commands. A command that sets a command line option, for example, +has different needs than a command that merely toggles a boolean flag. +Additionally, Transient provides abstractions for defining new types, +which the author of Transient did not anticipate (or didn’t get around +to implementing yet). + + Note that suffix commands also support regular prefix arguments. A +suffix command may even be called with both infix and prefix arguments +at the same time. If you invoke a command as a suffix of a transient +prefix command, but also want to pass prefix arguments to it, then first +invoke the prefix command, and only after doing that invoke the prefix +arguments, before finally invoking the suffix command. If you instead +began by providing the prefix arguments, then those would apply to the +prefix command, not the suffix command. Likewise, if you want to change +infix arguments before invoking a suffix command with prefix arguments, +then change the infix arguments before invoking the prefix arguments. +In other words, regular prefix arguments always apply to the next +command, and since transient prefix, infix and suffix commands are just +regular commands, the same applies to them. (Regular prefix keys behave +differently because they are not commands at all, instead they are just +incomplete key sequences, and those cannot be interrupted with prefix +commands.) + + +File: transient.info, Node: Defining Transients, Next: Binding Suffix and Infix Commands, Prev: Technical Introduction, Up: Defining New Commands + +4.2 Defining Transients +======================= + +A transient consists of a prefix command and at least one suffix +command, though usually a transient has several infix and suffix +commands. The below macro defines the transient prefix command *and* +binds the transient’s infix and suffix commands. In other words, it +defines the complete transient, not just the transient prefix command +that is used to invoke that transient. + + -- Macro: transient-define-prefix name arglist [docstring] [keyword + value]... group... [body...] + This macro defines NAME as a transient prefix command and binds the + transient’s infix and suffix commands. + + ARGLIST are the arguments that the prefix command takes. DOCSTRING + is the documentation string and is optional. + + These arguments can optionally be followed by keyword-value pairs. + Each key has to be a keyword symbol, either ‘:class’ or a keyword + argument supported by the constructor of that class. The + ‘transient-prefix’ class is used if the class is not specified + explicitly. + + GROUPs add key bindings for infix and suffix commands and specify + how these bindings are presented in the popup buffer. At least one + GROUP has to be specified. See *note Binding Suffix and Infix + Commands::. + + The BODY is optional. If it is omitted, then ARGLIST is ignored + and the function definition becomes: + + (lambda () + (interactive) + (transient-setup 'NAME)) + + If BODY is specified, then it must begin with an ‘interactive’ form + that matches ARGLIST, and it must call ‘transient-setup’. It may, + however, call that function only when some condition is satisfied. + + All transients have a (possibly ‘nil’) value, which is exported + when suffix commands are called, so that they can consume that + value. For some transients it might be necessary to have a sort of + secondary value, called a “scope”. Such a scope would usually be + set in the command’s ‘interactive’ form and has to be passed to the + setup function: + + (transient-setup 'NAME nil nil :scope SCOPE) + + For example, the scope of the ‘magit-branch-configure’ transient is + the branch whose variables are being configured. + + +File: transient.info, Node: Binding Suffix and Infix Commands, Next: Defining Suffix and Infix Commands, Prev: Defining Transients, Up: Defining New Commands + +4.3 Binding Suffix and Infix Commands +===================================== + +The macro ‘transient-define-prefix’ is used to define a transient. This +defines the actual transient prefix command (see *note Defining +Transients::) and adds the transient’s infix and suffix bindings, as +described below. + + Users and third-party packages can add additional bindings using +functions such as ‘transient-insert-suffix’ (see *note Modifying +Existing Transients::). These functions take a “suffix specification” +as one of their arguments, which has the same form as the specifications +used in ‘transient-define-prefix’. + +* Menu: + +* Group Specifications:: +* Suffix Specifications:: + + +File: transient.info, Node: Group Specifications, Next: Suffix Specifications, Up: Binding Suffix and Infix Commands + +4.3.1 Group Specifications +-------------------------- + +The suffix and infix commands of a transient are organized in groups. +The grouping controls how the descriptions of the suffixes are outlined +visually but also makes it possible to set certain properties for a set +of suffixes. + + Several group classes exist, some of which organize suffixes in +subgroups. In most cases the class does not have to be specified +explicitly, but see *note Group Classes::. + + Groups are specified in the call to ‘transient-define-prefix’, using +vectors. Because groups are represented using vectors, we cannot use +square brackets to indicate an optional element and instead use curly +brackets to do the latter. + + Group specifications then have this form: + + [{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...] + + The LEVEL is optional and defaults to 4. See *note Enabling and +Disabling Suffixes::. + + The DESCRIPTION is optional. If present, it is used as the heading +of the group. + + The KEYWORD-VALUE pairs are optional. Each keyword has to be a +keyword symbol, either ‘:class’ or a keyword argument supported by the +constructor of that class. + + • One of these keywords, ‘:description’, is equivalent to specifying + DESCRIPTION at the very beginning of the vector. The + recommendation is to use ‘:description’ if some other keyword is + also used, for consistency, or DESCRIPTION otherwise, because it + looks better. + + • Likewise ‘:level’ is equivalent to LEVEL. + + • Other important keywords include the ‘:if...’ keywords. These + keywords control whether the group is available in a certain + situation. + + For example, one group of the ‘magit-rebase’ transient uses ‘:if + magit-rebase-in-progress-p’, which contains the suffixes that are + useful while rebase is already in progress; and another that uses + ‘:if-not magit-rebase-in-progress-p’, which contains the suffixes + that initiate a rebase. + + These predicates can also be used on individual suffixes and are + only documented once, see *note Predicate Slots::. + + • The value of ‘:hide’, if non-‘nil’, is a predicate that controls + whether the group is hidden by default. The key bindings for + suffixes of a hidden group should all use the same prefix key. + Pressing that prefix key should temporarily show the group and its + suffixes, which assumes that a predicate like this is used: + + (lambda () + (eq (car transient--redisplay-key) + ?\C-c)) ; the prefix key shared by all bindings + + • The value of ‘:setup-children’, if non-‘nil’, is a function that + takes one argument, a potentially list of children, and must return + a list of children or an empty list. This can either be used to + somehow transform the group’s children that were defined the normal + way, or to dynamically create the children from scratch. + + The returned children must have the same form as stored in the + prefix’s ‘transient--layout’ property, but it is often more + convenient to use the same form as understood by + ‘transient-define-prefix’, described below. If you use the latter + approach, you can use the ‘transient-parse-suffixes’ and + ‘transient-parse-suffix’ functions to transform them from the + convenient to the expected form. Depending on the used group + class, ‘transient-parse-suffixes’’s SUFFIXES must be a list of + group vectors (for ‘transient-columns’) or a list of suffix lists + (for all other group classes). + + If you explicitly specify children and then transform them using + ‘:setup-children’, then the class of the group is determined as + usual, based on explicitly specified children. + + If you do not explicitly specify children and thus rely solely on + ‘:setup-children’, then you must specify the class using ‘:class’. + For backward compatibility, if you fail to do so, + ‘transient-column’ is used and a warning is displayed. This + warning will eventually be replaced with an error. + + (transient-define-prefix my-finder-by-keyword () + "Select a keyword and list matching packages." + ;; The real `finder-by-keyword' is more convenient + ;; of course, but that is not the point here. + [:class transient-columns + :setup-children + (lambda (_) + (transient-parse-suffixes + 'my-finder-by-keyword + (let ((char (1- ?A))) + (mapcar ; a list ... + (lambda (partition) + (vconcat ; of group vectors ... + (mapcar (lambda (elt) + (let ((keyword (symbol-name (car elt)))) + ; ... where each suffix is a list + (list (format "%c" (cl-incf char)) + keyword + (lambda () + (interactive) + (finder-list-matches keyword))))) + partition))) + (seq-partition finder-known-keywords 7)))))]) + + • The boolean ‘:pad-keys’ argument controls whether keys of all + suffixes contained in a group are right padded, effectively + aligning the descriptions. + + The ELEMENTs are either all subgroups, or all suffixes and strings. +(At least currently no group type exists that would allow mixing +subgroups with commands at the same level, though in principle there is +nothing that prevents that.) + + If the ELEMENTs are not subgroups, then they can be a mixture of +lists, which specify commands, and strings. Strings are inserted +verbatim into the buffer. The empty string can be used to insert gaps +between suffixes, which is particularly useful if the suffixes are +outlined as a table. + + Inside group specifications, including inside contained suffix +specifications, nothing has to be quoted and quoting anyway is invalid. +The value following a keyword, can be explicitly unquoted using ‘,’. +This feature is experimental and should be avoided. + + The form of suffix specifications is documented in the next node. + + +File: transient.info, Node: Suffix Specifications, Prev: Group Specifications, Up: Binding Suffix and Infix Commands + +4.3.2 Suffix Specifications +--------------------------- + +A transient’s suffix and infix commands are bound when the transient +prefix command is defined using ‘transient-define-prefix’, see *note +Defining Transients::. The commands are organized into groups, see +*note Group Specifications::. Here we describe the form used to bind an +individual suffix command. + + The same form is also used when later binding additional commands +using functions such as ‘transient-insert-suffix’, see *note Modifying +Existing Transients::. + + Note that an infix is a special kind of suffix. Depending on context +“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”. +Here it means the former. + + Suffix specifications have this form: + + ([LEVEL] [KEY [DESCRIPTION]] COMMAND|ARGUMENT [KEYWORD VALUE]...) + + LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs +‘:level’, ‘:key’ and ‘:description’. If the object that is associated +with COMMAND sets these properties, then they do not have to be +specified here. You can however specify them here anyway, possibly +overriding the object’s values just for the binding inside this +transient. + + • LEVEL is the suffix level, an integer between 1 and 7. See *note + Enabling and Disabling Suffixes::. + + • KEY is the key binding, either a vector or key description string. + + • DESCRIPTION is the description, either a string or a function that + takes zero or one arguments (the suffix object) and returns a + string. The function should be a lambda expression to avoid + ambiguity. In some cases a symbol that is bound as a function + would also work but to be safe you should use ‘:description’ in + that case. + + The next element is either a command or an argument. This is the +only argument that is mandatory in all cases. + + • COMMAND should be a symbol that is bound as a function, which has + to be defined or at least autoloaded as a command by the time the + containing prefix command is invoked. + + Any command will do; it does not need to have an object associated + with it (as would be the case if ‘transient-define-suffix’ or + ‘transient-define-infix’ were used to define it). + + COMMAND can also be a ‘lambda’ expression. + + As mentioned above, the object that is associated with a command + can be used to set the default for certain values that otherwise + have to be set in the suffix specification. Therefore if there is + no object, then you have to make sure to specify the KEY and the + DESCRIPTION. + + As a special case, if you want to add a command that might be + neither defined nor autoloaded, you can use a workaround like: + + (transient-insert-suffix 'some-prefix "k" + '("!" "Ceci n'est pas une commande" no-command + :if (lambda () (featurep 'no-library)))) + + Instead of ‘featurep’ you could also use ‘require’ with a non-‘nil’ + value for NOERROR. + + • The mandatory argument can also be a command-line argument, a + string. In that case an anonymous command is defined and bound. + + Instead of a string, this can also be a list of two strings, in + which case the first string is used as the short argument (which + can also be specified using ‘:shortarg’) and the second as the long + argument (which can also be specified using ‘:argument’). + + Only the long argument is displayed in the popup buffer. See + ‘transient-detect-key-conflicts’ for how the short argument may be + used. + + Unless the class is specified explicitly, the appropriate class is + guessed based on the long argument. If the argument ends with ‘=’ + (e.g., ‘--format=’) then ‘transient-option’ is used, otherwise + ‘transient-switch’. + + Finally, details can be specified using optional KEYWORD-VALUE pairs. +Each keyword has to be a keyword symbol, either ‘:class’ or a keyword +argument supported by the constructor of that class. See *note Suffix +Slots::. + + +File: transient.info, Node: Defining Suffix and Infix Commands, Next: Using Infix Arguments, Prev: Binding Suffix and Infix Commands, Up: Defining New Commands + +4.4 Defining Suffix and Infix Commands +====================================== + +Note that an infix is a special kind of suffix. Depending on context +“suffixes” means “suffixes (including infixes)” or “non-infix suffixes”. + + -- Macro: transient-define-suffix name arglist [docstring] [keyword + value]... body... + This macro defines NAME as a transient suffix command. + + ARGLIST are the arguments that the command takes. DOCSTRING is the + documentation string and is optional. + + These arguments can optionally be followed by keyword-value pairs. + Each keyword has to be a keyword symbol, either ‘:class’ or a + keyword argument supported by the constructor of that class. The + ‘transient-suffix’ class is used if the class is not specified + explicitly. + + The BODY must begin with an ‘interactive’ form that matches + ARGLIST. The infix arguments are usually accessed by using + ‘transient-args’ inside ‘interactive’. + + -- Macro: transient-define-infix name arglist [docstring] [keyword + value]... + This macro defines NAME as a transient infix command. + + ARGLIST is always ignored (but mandatory never-the-less) and + reserved for future use. DOCSTRING is the documentation string and + is optional. + + At least one key-value pair is required. All transient infix + commands are ‘equal’ to each other (but not ‘eq’). It is + meaningless to define an infix command, without providing at least + one keyword argument (usually ‘:argument’ or ‘:variable’, depending + on the class). The suffix class defaults to ‘transient-switch’ and + can be set using the ‘:class’ keyword. + + The function definition is always: + + (lambda () + (interactive) + (let ((obj (transient-suffix-object))) + (transient-infix-set obj (transient-infix-read obj))) + (transient--show)) + + ‘transient-infix-read’ and ‘transient-infix-set’ are generic + functions. Different infix commands behave differently because the + concrete methods are different for different infix command classes. + In rare cases the above command function might not be suitable, + even if you define your own infix command class. In that case you + have to use ‘transient-define-suffix’ to define the infix command + and use ‘t’ as the value of the ‘:transient’ keyword. + + -- Macro: transient-define-argument name arglist [docstring] [keyword + value]... + This macro defines NAME as a transient infix command. + + This is an alias for ‘transient-define-infix’. Only use this alias + to define an infix command that actually sets an infix argument. + To define an infix command that, for example, sets a variable, use + ‘transient-define-infix’ instead. + + +File: transient.info, Node: Using Infix Arguments, Next: Transient State, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands + +4.5 Using Infix Arguments +========================= + +The functions and the variables described below allow suffix commands to +access the value of the transient from which they were invoked; which is +the value of its infix arguments. These variables are set when the user +invokes a suffix command that exits the transient, but before actually +calling the command. + + When returning to the command-loop after calling the suffix command, +the arguments are reset to ‘nil’ (which causes the function to return +‘nil’ too). + + Like for Emacs’s prefix arguments, it is advisable, but not +mandatory, to access the infix arguments inside the command’s +‘interactive’ form. The preferred way of doing that is to call the +‘transient-args’ function, which for infix arguments serves about the +same purpose as ‘prefix-arg’ serves for prefix arguments. + + -- Function: transient-args prefix + This function returns the value of the transient prefix command + PREFIX. + + If the current command was invoked from the transient prefix + command PREFIX, then it returns the active infix arguments. If the + current command was not invoked from PREFIX, then it returns the + set, saved or default value for PREFIX. + + -- Function: transient-arg-value arg args + This function return the value of ARG as it appears in ARGS. + + For a switch a boolean is returned. For an option the value is + returned as a string, using the empty string for the empty value, + or ‘nil’ if the option does not appear in ARGS. + + -- Function: transient-suffixes prefix + This function returns the suffixes of the transient prefix command + PREFIX. This is a list of objects. This function should only be + used if you need the objects (as opposed to just their values) and + if the current command is not being invoked from PREFIX. + + -- Variable: transient-current-suffixes + The suffixes of the transient from which this suffix command was + invoked. This is a list of objects. Usually it is sufficient to + instead use the function ‘transient-args’, which returns a list of + values. In complex cases it might be necessary to use this + variable instead, i.e., if you need access to information beside + the value. + + -- Variable: transient-current-command + The transient from which this suffix command was invoked. The + returned value is a symbol, the transient prefix command. + + -- Variable: transient-current-prefix + The transient from which this suffix command was invoked. The + returned value is a ‘transient-prefix’ object, which holds + information associated with the transient prefix command. + + -- Variable: transient-active-prefix + This function returns the active transient object. Return ‘nil’ if + there is no active transient, if the transient buffer isn’t shown, + and while the active transient is suspended (e.g., while the + minibuffer is in use). + + Unlike ‘transient-current-prefix’, which is only ever non-‘nil’ in + code that is run directly by a command that is invoked while a + transient is current, this function is also suitable for use in + asynchronous code, such as timers and callbacks (this function’s + main use-case). + + If optional PREFIXES is non-‘nil’, it must be a list of prefix + command symbols, in which case the active transient object is only + returned if it matches one of the PREFIXES." + + +File: transient.info, Node: Transient State, Prev: Using Infix Arguments, Up: Defining New Commands + +4.6 Transient State +=================== + +Invoking a transient prefix command “activates” the respective +transient, i.e., it puts a transient keymap into effect, which binds the +transient’s infix and suffix commands. + + The default behavior while a transient is active is as follows: + + • Invoking an infix command does not affect the transient state; the + transient remains active. + + • Invoking a (non-infix) suffix command “deactivates” the transient + state by removing the transient keymap and performing some + additional cleanup. + + • Invoking a command that is bound in a keymap other than the + transient keymap is disallowed and trying to do so results in a + warning. This does not “deactivate” the transient. + + The behavior can be changed for all suffixes of a particular prefix +and/or for individual suffixes. The values should nearly always be +booleans, but certain functions, called “pre-commands”, can also be +used. These functions are named ‘transient--do-VERB’, and the symbol +‘VERB’ can be used as a shorthand. + + A boolean is interpreted as answering the question "does the +transient stay active, when this command is invoked?" ‘t’ means that +the transient stays active, while ‘nil’ means that invoking the command +exits the transient. + + Note that when the suffix is a “sub-prefix”, invoking that command +always activates that sub-prefix, causing the outer prefix to no longer +be active and displayed. Here ‘t’ means that when you exit the inner +prefix, then the outer prefix becomes active again, while ‘nil’ means +that all outer prefixes are exited at once. + + • The behavior for non-suffixes can be set for a particular prefix, + by the prefix’s ‘transient-non-suffix’ slot to a boolean, a + suitable pre-command function, or a shorthand for such a function. + See *note Pre-commands for Non-Suffixes::. + + • The common behavior for the suffixes of a particular prefix can be + set using the prefix’s ‘transient-suffixes’ slot. + + The value specified in this slot does *not* affect infixes. + Because it affects both regular suffixes as well as sub-prefixes, + which have different needs, it is best to avoid explicitly + specifying a function. + + • The behavior of an individual suffix can be changed using its + ‘transient’ slot. While it is usually best to use a boolean, for + this slot it can occasionally make sense to specify a function + explicitly. + + Note that this slot can be set when defining a suffix command using + ‘transient-define-suffix’ and/or in the definition of the prefix. + If set in both places, then the latter takes precedence, as usual. + + The available pre-command functions are documented in the following +sub-sections. They are called by ‘transient--pre-command’, a function +on ‘pre-command-hook’, and the value that they return determines whether +the transient is exited. To do so the value of one of the constants +‘transient--exit’ or ‘transient--stay’ is used (that way we don’t have +to remember if ‘t’ means “exit” or “stay”). + + Additionally, these functions may change the value of ‘this-command’ +(which explains why they have to be called using ‘pre-command-hook’), +call ‘transient-export’, ‘transient--stack-zap’ or +‘transient--stack-push’; and set the values of ‘transient--exitp’, +‘transient--helpp’ or ‘transient--editp’. + + For completeness sake, some notes about complications: + + • The transient-ness of certain built-in suffix commands is specified + using ‘transient-predicate-map’. This is a special keymap, which + binds commands to pre-commands (as opposed to keys to commands) and + takes precedence over the prefix’s ‘transient-suffix’ slot, but not + the suffix’s ‘transient’ slot. + + • While a sub-prefix is active we nearly always want ‘C-g’ to take + the user back to the “super-prefix”, even when the other suffixes + don’t do that. However, in rare cases this may not be desirable, + and that makes the following complication necessary: + + For ‘transient-suffix’ objects the ‘transient’ slot is unbound. We + can ignore that for the most part because ‘nil’ and the slot being + unbound are treated as equivalent, and mean “do exit”. That isn’t + actually true for suffixes that are sub-prefixes though. For such + suffixes unbound means “do exit but allow going back”, which is the + default, while ‘nil’ means “do exit permanently”, which requires + that slot to be explicitly set to that value. + +Pre-commands for Infixes +------------------------ + +The default for infixes is ‘transient--do-stay’. This is also the only +function that makes sense for infixes, which is why this predicate is +used even if the value of the prefix’s ‘transient-suffix’ slot is ‘t’. +In extremely rare cases, one might want to use something else, which can +be done by setting the infix’s ‘transient’ slot directly. + + -- Function: transient--do-stay + Call the command without exporting variables and stay transient. + +Pre-commands for Suffixes +------------------------- + +By default, invoking a suffix causes the transient to be exited. + + The behavior for an individual suffix command can be changed by +setting its ‘transient’ slot to a boolean (which is highly recommended), +or to one of the following pre-commands. + + -- Function: transient--do-exit + Call the command after exporting variables and exit the transient. + + -- Function: transient--do-return + Call the command after exporting variables and return to the parent + prefix. If there is no parent prefix, then call + ‘transient--do-exit’. + + -- Function: transient--do-call + Call the command after exporting variables and stay transient. + + The following pre-commands are only suitable for sub-prefixes. It is +not necessary to explicitly use these predicates because the correct +predicate is automatically picked based on the value of the ‘transient’ +slot for the sub-prefix itself. + + -- Function: transient--do-recurse + Call the transient prefix command, preparing for return to active + transient. + + Whether we actually return to the parent transient is ultimately + under the control of each invoked suffix. The difference between + this pre-command and ‘transient--do-stack’ is that it changes the + value of the ‘transient-suffix’ slot to ‘t’. + + If there is no parent transient, then only call this command and + skip the second step. + + -- Function: transient--do-stack + Call the transient prefix command, stacking the active transient. + Push the active transient to the transient stack. + + Unless ‘transient--do-recurse’ is explicitly used, this pre-command + is automatically used for suffixes that are prefixes themselves, + i.e., for sub-prefixes. + + -- Function: transient--do-replace + Call the transient prefix command, replacing the active transient. + Do not push the active transient to the transient stack. + + Unless ‘transient--do-recurse’ is explicitly used, this pre-command + is automatically used for suffixes that are prefixes themselves, + i.e., for sub-prefixes. + + -- Function: transient--do-suspend + Suspend the active transient, saving the transient stack. + + This is used by the command ‘transient-suspend’ and optionally also + by “external events” such as ‘handle-switch-frame’. Such bindings + should be added to ‘transient-predicate-map’. + +Pre-commands for Non-Suffixes +----------------------------- + +By default, non-suffixes (commands that are bound in other keymaps +beside the transient keymap) cannot be invoked. Trying to invoke such a +command results in a warning and the transient stays active. + + If you want a different behavior, then set the ‘transient-non-suffix’ +slot of the transient prefix command. The value should be a boolean, +answering the question, "is it allowed to invoke non-suffix commands?, a +pre-command function, or a shorthand for such a function. + + If the value is ‘t’, then non-suffixes can be invoked, when it is +‘nil’ (the default) then they cannot be invoked. + + The only other recommended value is ‘leave’. If that is used, then +non-suffixes can be invoked, but if one is invoked, then that exits the +transient. + + -- Function: transient--do-warn + Call ‘transient-undefined’ and stay transient. + + -- Function: transient--do-stay + Call the command without exporting variables and stay transient. + + -- Function: transient--do-leave + Call the command without exporting variables and exit the + transient. + +Special Pre-Commands +-------------------- + + -- Function: transient--do-quit-one + If active, quit help or edit mode, else exit the active transient. + + This is used when the user pressed ‘C-g’. + + -- Function: transient--do-quit-all + Exit all transients without saving the transient stack. + + This is used when the user pressed ‘C-q’. + + -- Function: transient--do-suspend + Suspend the active transient, saving the transient stack. + + This is used when the user pressed ‘C-z’. + + +File: transient.info, Node: Classes and Methods, Next: FAQ, Prev: Defining New Commands, Up: Top + +5 Classes and Methods +********************* + +Transient uses classes and generic functions to make it possible to +define new types of suffix commands that are similar to existing types, +but behave differently in some aspects. It does the same for groups and +prefix commands, though at least for prefix commands that *currently* +appears to be less important. + + Every prefix, infix and suffix command is associated with an object, +which holds information that controls certain aspects of its behavior. +This happens in two ways. + + • Associating a command with a certain class gives the command a + type. This makes it possible to use generic functions to do + certain things that have to be done differently depending on what + type of command it acts on. + + That in turn makes it possible for third-parties to add new types + without having to convince the maintainer of Transient that that + new type is important enough to justify adding a special case to a + dozen or so functions. + + • Associating a command with an object makes it possible to easily + store information that is specific to that particular command. + + Two commands may have the same type, but obviously their key + bindings and descriptions still have to be different, for example. + + The values of some slots are functions. The ‘reader’ slot for + example holds a function that is used to read a new value for an + infix command. The values of such slots are regular functions. + + Generic functions are used when a function should do something + different based on the type of the command, i.e., when all commands + of a certain type should behave the same way but different from the + behavior for other types. Object slots that hold a regular + function as value are used when the task that they perform is + likely to differ even between different commands of the same type. + +* Menu: + +* Group Classes:: +* Group Methods:: +* Prefix Classes:: +* Suffix Classes:: +* Suffix Methods:: +* Prefix Slots:: +* Suffix Slots:: +* Predicate Slots:: + + +File: transient.info, Node: Group Classes, Next: Group Methods, Up: Classes and Methods + +5.1 Group Classes +================= + +The type of a group can be specified using the ‘:class’ property at the +beginning of the class specification, e.g., ‘[:class transient-columns +...]’ in a call to ‘transient-define-prefix’. + + • The abstract ‘transient-child’ class is the base class of both + ‘transient-group’ (and therefore all groups) as well as of + ‘transient-suffix’ (and therefore all suffix and infix commands). + + This class exists because the elements (or “children”) of certain + groups can be other groups instead of suffix and infix commands. + + • The abstract ‘transient-group’ class is the superclass of all other + group classes. + + • The ‘transient-column’ class is the simplest group. + + This is the default “flat” group. If the class is not specified + explicitly and the first element is not a vector (i.e., not a + group), then this class is used. + + This class displays each element on a separate line. + + • The ‘transient-row’ class displays all elements on a single line. + + • The ‘transient-columns’ class displays commands organized in + columns. + + Direct elements have to be groups whose elements have to be + commands or strings. Each subgroup represents a column. This + class takes care of inserting the subgroups’ elements. + + This is the default “nested” group. If the class is not specified + explicitly and the first element is a vector (i.e., a group), then + this class is used. + + • The ‘transient-subgroups’ class wraps other groups. + + Direct elements have to be groups whose elements have to be + commands or strings. This group inserts an empty line between + subgroups. The subgroups themselves are responsible for displaying + their elements. + + +File: transient.info, Node: Group Methods, Next: Prefix Classes, Prev: Group Classes, Up: Classes and Methods + +5.2 Group Methods +================= + + -- Function: transient-setup-children group children + This generic function can be used to setup the children or a group. + + The default implementation usually just returns the children + unchanged, but if the ‘setup-children’ slot of GROUP is non-‘nil’, + then it calls that function with CHILDREN as the only argument and + returns the value. + + The children are given as a (potentially empty) list consisting of + either group or suffix specifications. These functions can make + arbitrary changes to the children including constructing new + children from scratch. + + -- Function: transient--insert-group group + This generic function formats the group and its elements and + inserts the result into the current buffer, which is a temporary + buffer. The contents of that buffer are later inserted into the + popup buffer. + + Functions that are called by this function may need to operate in + the buffer from which the transient was called. To do so they can + temporarily make the ‘transient--source-buffer’ the current buffer. + + +File: transient.info, Node: Prefix Classes, Next: Suffix Classes, Prev: Group Methods, Up: Classes and Methods + +5.3 Prefix Classes +================== + +Currently the ‘transient-prefix’ class is being used for all prefix +commands and there is only a single generic function that can be +specialized based on the class of a prefix command. + + -- Function: transient--history-init obj + This generic function is called while setting up the transient and + is responsible for initializing the ‘history’ slot. This is the + transient-wide history; many individual infixes also have a history + of their own. + + The default (and currently only) method extracts the value from the + global variable ‘transient-history’. + + A transient prefix command’s object is stored in the +‘transient--prefix’ property of the command symbol. While a transient +is active, a clone of that object is stored in the variable +‘transient--prefix’. A clone is used because some changes that are made +to the active transient’s object should not affect later invocations. + + +File: transient.info, Node: Suffix Classes, Next: Suffix Methods, Prev: Prefix Classes, Up: Classes and Methods + +5.4 Suffix Classes +================== + + • All suffix and infix classes derive from ‘transient-suffix’, which + in turn derives from ‘transient-child’, from which + ‘transient-group’ also derives (see *note Group Classes::). + + • All infix classes derive from the abstract ‘transient-infix’ class, + which in turn derives from the ‘transient-suffix’ class. + + Infixes are a special type of suffixes. The primary difference is + that infixes always use the ‘transient--do-stay’ pre-command, while + non-infix suffixes use a variety of pre-commands (see *note + Transient State::). Doing that is most easily achieved by using + this class, though theoretically it would be possible to define an + infix class that does not do so. If you do that then you get to + implement many methods. + + Also, infixes and non-infix suffixes are usually defined using + different macros (see *note Defining Suffix and Infix Commands::). + + • Classes used for infix commands that represent arguments should be + derived from the abstract ‘transient-argument’ class. + + • The ‘transient-switch’ class (or a derived class) is used for infix + arguments that represent command-line switches (arguments that do + not take a value). + + • The ‘transient-option’ class (or a derived class) is used for infix + arguments that represent command-line options (arguments that do + take a value). + + • The ‘transient-switches’ class can be used for a set of mutually + exclusive command-line switches. + + • The ‘transient-files’ class can be used for a ‘--’ argument that + indicates that all remaining arguments are files. + + • Classes used for infix commands that represent variables should + derived from the abstract ‘transient-variable’ class. + + • The ‘transient-information’ class is special in that suffixes that + use this class are not associated with a command and thus also not + with any key binding. Such suffixes are only used to display + arbitrary information, and that anywhere a suffix can appear. + Display-only suffix specifications take this form: + + ([LEVEL] :info DESCRIPTION [KEYWORD VALUE]...) + + The ‘:info’ keyword argument replaces the ‘:description’ keyword + used for other suffix classes. Other keyword arguments that you + might want to set, include ‘:face’, predicate keywords (such as + ‘:if’), and ‘:format’. By default the value of ‘:format’ includes + ‘%k’, which for this class is replaced with the empty string or + spaces, if keys are being padded in the containing group. + + Magit defines additional classes, which can serve as examples for the +fancy things you can do without modifying Transient. Some of these +classes will likely get generalized and added to Transient. For now +they are very much subject to change and not documented. + + +File: transient.info, Node: Suffix Methods, Next: Prefix Slots, Prev: Suffix Classes, Up: Classes and Methods + +5.5 Suffix Methods +================== + +To get information about the methods implementing these generic +functions use ‘describe-function’. + +* Menu: + +* Suffix Value Methods:: +* Suffix Format Methods:: + + +File: transient.info, Node: Suffix Value Methods, Next: Suffix Format Methods, Up: Suffix Methods + +5.5.1 Suffix Value Methods +-------------------------- + + -- Function: transient-init-value obj + This generic function sets the initial value of the object OBJ. + + This function is called for all suffix commands, but unless a + concrete method is implemented this falls through to the default + implementation, which is a noop. In other words this usually only + does something for infix commands, but note that this is not + implemented for the abstract class ‘transient-infix’, so if your + class derives from that directly, then you must implement a method. + + -- Function: transient-infix-read obj + This generic function determines the new value of the infix object + OBJ. + + This function merely determines the value; ‘transient-infix-set’ is + used to actually store the new value in the object. + + For most infix classes this is done by reading a value from the + user using the reader specified by the ‘reader’ slot (using the + ‘transient-infix-value’ method described below). + + For some infix classes the value is changed without reading + anything in the minibuffer, i.e., the mere act of invoking the + infix command determines what the new value should be, based on the + previous value. + + -- Function: transient-prompt obj + This generic function returns the prompt to be used to read infix + object OBJ’s value. + + -- Function: transient-infix-set obj value + This generic function sets the value of infix object OBJ to VALUE. + + -- Function: transient-infix-value obj + This generic function returns the value of the suffix object OBJ. + + This function is called by ‘transient-args’ (which see), meaning + this function is how the value of a transient is determined so that + the invoked suffix command can use it. + + Currently most values are strings, but that is not set in stone. + ‘nil’ is not a value, it means “no value”. + + Usually only infixes have a value, but see the method for + ‘transient-suffix’. + + -- Function: transient-init-scope obj + This generic function sets the scope of the suffix object OBJ. + + The scope is actually a property of the transient prefix, not of + individual suffixes. However it is possible to invoke a suffix + command directly instead of from a transient. In that case, if the + suffix expects a scope, then it has to determine that itself and + store it in its ‘scope’ slot. + + This function is called for all suffix commands, but unless a + concrete method is implemented this falls through to the default + implementation, which is a noop. + + +File: transient.info, Node: Suffix Format Methods, Prev: Suffix Value Methods, Up: Suffix Methods + +5.5.2 Suffix Format Methods +--------------------------- + + -- Function: transient-format obj + This generic function formats and returns OBJ for display. + + When this function is called, then the current buffer is some + temporary buffer. If you need the buffer from which the prefix + command was invoked to be current, then do so by temporarily making + ‘transient--source-buffer’ current. + + -- Function: transient-format-key obj + This generic function formats OBJ’s ‘key’ for display and returns + the result. + + -- Function: transient-format-description obj + This generic function formats OBJ’s ‘description’ for display and + returns the result. + + -- Function: transient-format-value obj + This generic function formats OBJ’s value for display and returns + the result. + + -- Function: transient-show-help obj + Show help for the prefix, infix or suffix command represented by + OBJ. + + For prefixes, show the info manual, if that is specified using the + ‘info-manual’ slot. Otherwise, show the manpage if that is + specified using the ‘man-page’ slot. Otherwise, show the command’s + documentation string. + + For suffixes, show the command’s documentation string. + + For infixes, show the manpage if that is specified. Otherwise show + the command’s documentation string. + + +File: transient.info, Node: Prefix Slots, Next: Suffix Slots, Prev: Suffix Methods, Up: Classes and Methods + +5.6 Prefix Slots +================ + + • ‘show-help’, ‘man-page’ or ‘info-manual’ can be used to specify the + documentation for the prefix and its suffixes. The command + ‘transient-help’ uses the method ‘transient-show-help’ (which see) + to lookup and use these values. + + • ‘history-key’ If multiple prefix commands should share a single + value, then this slot has to be set to the same value for all of + them. You probably don’t want that. + + • ‘transient-suffix’ and ‘transient-non-suffix’ play a part when + determining whether the currently active transient prefix command + remains active/transient when a suffix or arbitrary non-suffix + command is invoked. See *note Transient State::. + + • ‘refresh-suffixes’ Normally suffix objects and keymaps are only + setup once, when the prefix is invoked. Setting this to ‘t’, + causes them to be recreated after every command. This is useful + when using ‘:if...’ predicates, and those need to be rerun for some + reason. Doing this is somewhat costly, and there is a risk of + losing state, so this is disabled by default and still considered + experimental. + + • ‘incompatible’ A list of lists. Each sub-list specifies a set of + mutually exclusive arguments. Enabling one of these arguments + causes the others to be disabled. An argument may appear in + multiple sub-lists. Arguments must me given in the same form as + used in the ‘argument’ or ‘argument-format’ slot of the respective + suffix objects, usually something like ‘--switch’ or ‘--option=%s’. + For options and ‘transient-switches’ suffixes it is also possible + to match against a specific value, as returned by + ‘transient-infix-value’, for example, ‘--option=one’. + + • ‘scope’ For some transients it might be necessary to have a sort of + secondary value, called a “scope”. See ‘transient-define-prefix’. + +Internal Prefix Slots +--------------------- + +These slots are mostly intended for internal use. They should not be +set in calls to ‘transient-define-prefix’. + + • ‘prototype’ When a transient prefix command is invoked, then a + clone of that object is stored in the global variable + ‘transient--prefix’ and the prototype is stored in the clone’s + ‘prototype’ slot. + + • ‘command’ The command, a symbol. Each transient prefix command + consists of a command, which is stored in a symbol’s function slot + and an object, which is stored in the ‘transient--prefix’ property + of the same symbol. + + • ‘level’ The level of the prefix commands. The suffix commands + whose layer is equal or lower are displayed. See *note Enabling + and Disabling Suffixes::. + + • ‘value’ The likely outdated value of the prefix. Instead of + accessing this slot directly you should use the function + ‘transient-get-value’, which is guaranteed to return the up-to-date + value. + + • ‘history’ and ‘history-pos’ are used to keep track of historic + values. Unless you implement your own ‘transient-infix-read’ + method you should not have to deal with these slots. + + +File: transient.info, Node: Suffix Slots, Next: Predicate Slots, Prev: Prefix Slots, Up: Classes and Methods + +5.7 Suffix Slots +================ + +Here we document most of the slots that are only available for suffix +objects. Some slots are shared by suffix and group objects, they are +documented in *note Predicate Slots::. + + Also see *note Suffix Classes::. + +Slots of ‘transient-suffix’ +--------------------------- + + • ‘key’ The key, a key vector or a key description string. + + • ‘command’ The command, a symbol. + + • ‘transient’ Whether to stay transient. See *note Transient + State::. + + • ‘format’ The format used to display the suffix in the popup buffer. + It must contain the following %-placeholders: + + • ‘%k’ For the key. + • ‘%d’ For the description. + • ‘%v’ For the infix value. Non-infix suffixes don’t have a + value. + + • ‘description’ The description, either a string or a function, which + is called with zero or one argument (the suffix object), and + returns a string. + + • ‘face’ Face used for the description. In simple cases it is easier + to use this instead of using a function as ‘description’ and adding + the styling there. ‘face’ is appended using + ‘add-face-text-property’. + + • ‘show-help’ A function used to display help for the suffix. If + unspecified, the prefix controls how help is displayed for its + suffixes. + +Slots of ‘transient-infix’ +-------------------------- + +Some of these slots are only meaningful for some of the subclasses. +They are defined here anyway to allow sharing certain methods. + + • ‘argument’ The long argument, e.g., ‘--verbose’. + + • ‘shortarg’ The short argument, e.g., ‘-v’. + + • ‘value’ The value. Should not be accessed directly. + + • ‘init-value’ Function that is responsible for setting the object’s + value. If bound, then this is called with the object as the only + argument. Usually this is not bound, in which case the object’s + primary ‘transient-init-value’ method is called instead. + + • ‘unsavable’ Whether the value of the suffix is not saved as part of + the prefixes. + + • ‘multi-value’ For options, whether the option can have multiple + values. If this is non-‘nil’, then the values are read using + ‘completing-read-multiple’ by default and if you specify your own + reader, then it should read the values using that function or + similar. + + Supported non-‘nil’ values are: + + • Use ‘rest’ for an option that can have multiple values. This + is useful e.g., for an ‘--’ argument that indicates that all + remaining arguments are files (such as ‘git log -- file1 + file2’). + + In the list returned by ‘transient-args’ such an option and + its values are represented by a single list of the form + ‘(ARGUMENT . VALUES)’. + + • Use ‘repeat’ for an option that can be specified multiple + times. + + In the list returned by ‘transient-args’ each instance of the + option and its value appears separately in the usual from, for + example: ‘("--another-argument" "--option=first" + "--option=second")’. + + In both cases the option’s values have to be specified in the + default value of a prefix using the same format as returned by + ‘transient-args’, e.g., ‘("--other" "--o=1" "--o=2" ("--" "f1" + "f2"))’. + + • ‘always-read’ For options, whether to read a value on every + invocation. If this is ‘nil’, then options that have a value are + simply unset and have to be invoked a second time to set a new + value. + + • ‘allow-empty’ For options, whether the empty string is a valid + value. + + • ‘history-key’ The key used to store the history. This defaults to + the command name. This is useful when multiple infixes should + share the same history because their values are of the same kind. + + • ‘reader’ The function used to read the value of an infix. Not used + for switches. The function takes three arguments, PROMPT, + INITIAL-INPUT and HISTORY, and must return a string. + + • ‘prompt’ The prompt used when reading the value, either a string or + a function that takes the object as the only argument and which + returns a prompt string. + + • ‘choices’ A list of valid values, or a function that returns such a + list. The latter is not implemented for ‘transient-switches’, + because I couldn’t think of a use-case. How exactly the choices + are used varies depending on the class of the suffix. + +Slots of ‘transient-variable’ +----------------------------- + + • ‘variable’ The variable. + +Slots of ‘transient-switches’ +----------------------------- + + • ‘argument-format’ The display format. Must contain ‘%s’, one of + the ‘choices’ is substituted for that. E.g., ‘--%s-order’. + + • ‘argument-regexp’ The regexp used to match any one of the switches. + E.g., ‘\\(--\\(topo\\|author-date\\|date\\)-order\\)’. + + +File: transient.info, Node: Predicate Slots, Prev: Suffix Slots, Up: Classes and Methods + +5.8 Predicate Slots +=================== + +Suffix and group objects share some predicate slots that control whether +a group or suffix should be available depending on some state. Only one +of these slots can be used at the same time. It is undefined what +happens if you use more than one. + + • ‘if’ Enable if predicate returns non-‘nil’. + • ‘if-not’ Enable if predicate returns ‘nil’. + • ‘if-non-nil’ Enable if variable’s value is non-‘nil’. + • ‘if-nil’ Enable if variable’s value is ‘nil’. + • ‘if-mode’ Enable if major-mode matches value. + • ‘if-not-mode’ Enable if major-mode does not match value. + • ‘if-derived’ Enable if major-mode derives from value. + • ‘if-not-derived’ Enable if major-mode does not derive from value. + + By default these predicates run when the prefix command is invoked, +but this can be changes, using the ‘refresh-suffixes’ prefix slot. See +*note Prefix Slots::. + + One more slot is shared between group and suffix classes, ‘level’. +Like the slots documented above, it is a predicate, but it is used for a +different purpose. The value has to be an integer between 1 and 7. +‘level’ controls whether a suffix or a group should be available +depending on user preference. See *note Enabling and Disabling +Suffixes::. + + +File: transient.info, Node: FAQ, Next: Keystroke Index, Prev: Classes and Methods, Up: Top + +Appendix A FAQ +************** + +A.1 Can I control how the popup buffer is displayed? +==================================================== + +Yes, see ‘transient-display-buffer-action’ in *note Configuration::. + +A.2 How can I copy text from the popup buffer? +============================================== + +To be able to mark text in Transient’s popup buffer using the mouse, you +have to add the below binding. Note that for technical reasons, the +region won’t be visualized, while doing so. After you have quit the +transient popup, you will be able to yank it in another buffer. + + (keymap-set transient-predicate-map + "<mouse-set-region>" + #'transient--do-stay) + +A.3 How can I autoload prefix and suffix commands? +================================================== + +If your package only supports Emacs 30, just prefix the definition with +‘;;;###autoload’. If your package supports released versions of Emacs, +you unfortunately have to use a long form autoload comment as described +in *note (elisp)Autoload::. + + ;;;###autoload (autoload 'magit-dispatch "magit" nil t) + (transient-define-prefix magit-dispatch () + ...) + +A.4 How does Transient compare to prefix keys and universal arguments? +====================================================================== + +See +<https://github.com/magit/transient/wiki/Comparison-with-prefix-keys-and-universal-arguments>. + +A.5 How does Transient compare to Magit-Popup and Hydra? +======================================================== + +See +<https://github.com/magit/transient/wiki/Comparison-with-other-packages>. + +A.6 Why did some of the key bindings change? +============================================ + +You may have noticed that the bindings for some of the common commands +do *not* have the prefix ‘C-x’ and that furthermore some of these +commands are grayed out while others are not. That unfortunately is a +bit confusing if the section of common commands is not shown +permanently, making the following explanation necessary. + + The purpose of usually hiding that section but showing it after the +user pressed the respective prefix key is to conserve space and not +overwhelm users with too much noise, while allowing the user to quickly +list common bindings on demand. + + That however should not keep us from using the best possible key +bindings. The bindings that do use a prefix do so to avoid wasting too +many non-prefix bindings, keeping them available for use in individual +transients. The bindings that do not use a prefix and that are *not* +grayed out are very important bindings that are *always* available, even +when invoking the “common command key prefix” or *any other* +transient-specific prefix. The non-prefix keys that *are* grayed out +however, are not available when any incomplete prefix key sequence is +active. They do not use the “common command key prefix” because it is +likely that users want to invoke them several times in a row and e.g., +‘M-p M-p M-p’ is much more convenient than ‘C-x M-p C-x M-p C-x M-p’. + + You may also have noticed that the “Set” command is bound to ‘C-x s’, +while Magit-Popup used to bind ‘C-c C-c’ instead. I have seen several +users praise the latter binding (sic), so I did not change it +willy-nilly. The reason that I changed it is that using different +prefix keys for different common commands, would have made the temporary +display of the common commands even more confusing, i.e., after pressing +‘C-c’ all the bindings that begin with the ‘C-x’ prefix would be grayed +out. + + Using a single prefix for common commands key means that all other +potential prefix keys can be used for transient-specific commands +*without* the section of common commands also popping up. ‘C-c’ in +particular is a prefix that I want to (and already do) use for Magit, +and also using that for a common command would prevent me from doing so. + + (Also see the next question.) + +A.7 Why does ‘q’ not quit popups anymore? +========================================= + +I agree that ‘q’ is a good binding for commands that quit something. +This includes quitting whatever transient is currently active, but it +also includes quitting whatever it is that some specific transient is +controlling. The transient ‘magit-blame’ for example binds ‘q’ to the +command that turns ‘magit-blame-mode’ off. + + So I had to decide if ‘q’ should quit the active transient (like +Magit-Popup used to) or whether ‘C-g’ should do that instead, so that +‘q’ could be bound in individual transient to whatever commands make +sense for them. Because all other letters are already reserved for use +by individual transients, I have decided to no longer make an exception +for ‘q’. + + If you want to get ‘q’’s old binding back then you can do so. Doing +that is a bit more complicated than changing a single key binding, so I +have implemented a function, ‘transient-bind-q-to-quit’ that makes the +necessary changes. See its documentation string for more information. + + +File: transient.info, Node: Keystroke Index, Next: Command and Function Index, Prev: FAQ, Up: Top + +Appendix B Keystroke Index +************************** + + +* Menu: + +* C-g: Aborting and Resuming Transients. + (line 27) +* C-g <1>: Aborting and Resuming Transients. + (line 27) +* C-h: Getting Help for Suffix Commands. + (line 11) +* C-M-n: Using History. (line 18) +* C-M-p: Using History. (line 13) +* C-q: Aborting and Resuming Transients. + (line 36) +* C-x a: Enabling and Disabling Suffixes. + (line 68) +* C-x C-k: Saving Values. (line 29) +* C-x C-s: Saving Values. (line 25) +* C-x l: Enabling and Disabling Suffixes. + (line 43) +* C-x n: Using History. (line 18) +* C-x p: Using History. (line 13) +* C-x s: Saving Values. (line 21) +* C-x t: Common Suffix Commands. + (line 18) +* C-z: Aborting and Resuming Transients. + (line 41) + + +File: transient.info, Node: Command and Function Index, Next: Variable Index, Prev: Keystroke Index, Up: Top + +Appendix C Command and Function Index +************************************* + + +* Menu: + +* transient--do-call: Transient State. (line 125) +* transient--do-exit: Transient State. (line 117) +* transient--do-leave: Transient State. (line 193) +* transient--do-quit-all: Transient State. (line 205) +* transient--do-quit-one: Transient State. (line 200) +* transient--do-recurse: Transient State. (line 133) +* transient--do-replace: Transient State. (line 153) +* transient--do-return: Transient State. (line 120) +* transient--do-stack: Transient State. (line 145) +* transient--do-stay: Transient State. (line 105) +* transient--do-stay <1>: Transient State. (line 190) +* transient--do-suspend: Transient State. (line 161) +* transient--do-suspend <1>: Transient State. (line 210) +* transient--do-warn: Transient State. (line 187) +* transient--history-init: Prefix Classes. (line 10) +* transient--insert-group: Group Methods. (line 19) +* transient-append-suffix: Modifying Existing Transients. + (line 51) +* transient-arg-value: Using Infix Arguments. + (line 31) +* transient-args: Using Infix Arguments. + (line 22) +* transient-define-argument: Defining Suffix and Infix Commands. + (line 57) +* transient-define-infix: Defining Suffix and Infix Commands. + (line 26) +* transient-define-prefix: Defining Transients. (line 13) +* transient-define-suffix: Defining Suffix and Infix Commands. + (line 9) +* transient-format: Suffix Format Methods. + (line 6) +* transient-format-description: Suffix Format Methods. + (line 18) +* transient-format-key: Suffix Format Methods. + (line 14) +* transient-format-value: Suffix Format Methods. + (line 22) +* transient-get-suffix: Modifying Existing Transients. + (line 73) +* transient-help: Getting Help for Suffix Commands. + (line 11) +* transient-history-next: Using History. (line 18) +* transient-history-prev: Using History. (line 13) +* transient-infix-read: Suffix Value Methods. + (line 16) +* transient-infix-set: Suffix Value Methods. + (line 36) +* transient-infix-value: Suffix Value Methods. + (line 39) +* transient-init-scope: Suffix Value Methods. + (line 52) +* transient-init-value: Suffix Value Methods. + (line 6) +* transient-insert-suffix: Modifying Existing Transients. + (line 49) +* transient-prompt: Suffix Value Methods. + (line 32) +* transient-quit-all: Aborting and Resuming Transients. + (line 36) +* transient-quit-one: Aborting and Resuming Transients. + (line 27) +* transient-quit-seq: Aborting and Resuming Transients. + (line 27) +* transient-remove-suffix: Modifying Existing Transients. + (line 70) +* transient-replace-suffix: Modifying Existing Transients. + (line 66) +* transient-reset: Saving Values. (line 29) +* transient-resume: Aborting and Resuming Transients. + (line 53) +* transient-save: Saving Values. (line 25) +* transient-scroll-down: Other Commands. (line 17) +* transient-scroll-up: Other Commands. (line 12) +* transient-set: Saving Values. (line 21) +* transient-set-level: Enabling and Disabling Suffixes. + (line 43) +* transient-setup-children: Group Methods. (line 6) +* transient-show-help: Suffix Format Methods. + (line 26) +* transient-suffix-put: Modifying Existing Transients. + (line 77) +* transient-suffixes: Using Infix Arguments. + (line 38) +* transient-suspend: Aborting and Resuming Transients. + (line 41) +* transient-toggle-common: Common Suffix Commands. + (line 18) +* transient-toggle-level-limit: Enabling and Disabling Suffixes. + (line 68) + + +File: transient.info, Node: Variable Index, Next: Concept Index, Prev: Command and Function Index, Up: Top + +Appendix D Variable Index +************************* + + +* Menu: + +* transient-active-prefix: Using Infix Arguments. + (line 61) +* transient-align-variable-pitch: Configuration. (line 185) +* transient-current-command: Using Infix Arguments. + (line 52) +* transient-current-prefix: Using Infix Arguments. + (line 56) +* transient-current-suffixes: Using Infix Arguments. + (line 44) +* transient-default-level: Enabling and Disabling Suffixes. + (line 33) +* transient-detect-key-conflicts: Configuration. (line 210) +* transient-display-buffer-action: Configuration. (line 51) +* transient-enable-popup-navigation: Configuration. (line 36) +* transient-force-fixed-pitch: Configuration. (line 198) +* transient-force-single-column: Configuration. (line 93) +* transient-hide-during-minibuffer-read: Configuration. (line 181) +* transient-highlight-higher-levels: Configuration. (line 223) +* transient-highlight-mismatched-keys: Configuration. (line 135) +* transient-history-file: Using History. (line 33) +* transient-history-limit: Using History. (line 37) +* transient-levels-file: Enabling and Disabling Suffixes. + (line 38) +* transient-mode-line-format: Configuration. (line 102) +* transient-read-with-initial-input: Configuration. (line 174) +* transient-semantic-coloring: Configuration. (line 126) +* transient-show-common-commands: Common Suffix Commands. + (line 23) +* transient-show-popup: Configuration. (line 15) +* transient-substitute-key-function: Configuration. (line 153) +* transient-values-file: Saving Values. (line 31) + + +File: transient.info, Node: Concept Index, Next: GNU General Public License, Prev: Variable Index, Up: Top + +Appendix E Concept Index +************************ + + +* Menu: + +* aborting transients: Aborting and Resuming Transients. + (line 6) +* classes and methods: Classes and Methods. (line 6) +* command dispatchers: Technical Introduction. + (line 39) +* common suffix commands: Common Suffix Commands. + (line 6) +* defining infix commands: Defining Suffix and Infix Commands. + (line 6) +* defining suffix commands: Defining Suffix and Infix Commands. + (line 6) +* disabling suffixes: Enabling and Disabling Suffixes. + (line 6) +* enabling suffixes: Enabling and Disabling Suffixes. + (line 6) +* getting help: Getting Help for Suffix Commands. + (line 6) +* group specifications: Group Specifications. (line 6) +* invoking transients: Invoking Transients. (line 6) +* levels: Enabling and Disabling Suffixes. + (line 10) +* modifying existing transients: Modifying Existing Transients. + (line 6) +* quit transient: Aborting and Resuming Transients. + (line 6) +* resuming transients: Aborting and Resuming Transients. + (line 6) +* saving values of arguments: Saving Values. (line 6) +* scope of a transient: Defining Transients. (line 43) +* suffix specifications: Suffix Specifications. + (line 6) +* transient state: Transient State. (line 6) +* transient-level: Enabling and Disabling Suffixes. + (line 15) +* value history: Using History. (line 6) + + +File: transient.info, Node: GNU General Public License, Prev: Concept Index, Up: Top + +Appendix F GNU General Public License +************************************* + + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/> + + 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. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. + Copyright (C) YEAR NAME OF AUTHOR + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + + 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: + + PROGRAM Copyright (C) YEAR NAME OF AUTHOR + 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 <https://www.gnu.org/licenses/>. + + 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 <https://www.gnu.org/licenses/why-not-lgpl.html>. + + + +Tag Table: +Node: Top763 +Node: Introduction2980 +Ref: Some things that Transient can do3508 +Ref: Complexity in CLI programs3861 +Ref: Using Transient for composing interactive commands4462 +Node: Usage6704 +Node: Invoking Transients7072 +Node: Aborting and Resuming Transients8151 +Node: Common Suffix Commands10772 +Node: Saving Values12608 +Ref: Saving Values-Footnote-113979 +Node: Using History14172 +Node: Getting Help for Suffix Commands15746 +Node: Enabling and Disabling Suffixes17124 +Node: Other Commands20412 +Node: Configuration21388 +Ref: Essential Options21668 +Ref: Accessibility Options25329 +Ref: Auxiliary Options25652 +Ref: Developer Options30615 +Node: Modifying Existing Transients31863 +Node: Defining New Commands36055 +Node: Technical Introduction36418 +Node: Defining Transients42119 +Node: Binding Suffix and Infix Commands44586 +Node: Group Specifications45444 +Node: Suffix Specifications51972 +Node: Defining Suffix and Infix Commands56185 +Node: Using Infix Arguments59233 +Node: Transient State62859 +Ref: Pre-commands for Infixes67674 +Ref: Pre-commands for Suffixes68194 +Ref: Pre-commands for Non-Suffixes70648 +Ref: Special Pre-Commands71784 +Node: Classes and Methods72292 +Node: Group Classes74476 +Node: Group Methods76403 +Node: Prefix Classes77656 +Node: Suffix Classes78747 +Node: Suffix Methods81834 +Node: Suffix Value Methods82155 +Node: Suffix Format Methods84913 +Node: Prefix Slots86392 +Ref: Internal Prefix Slots88527 +Node: Suffix Slots89784 +Ref: Slots of transient-suffix90152 +Ref: Slots of transient-infix91289 +Ref: Slots of transient-variable94585 +Ref: Slots of transient-switches94687 +Node: Predicate Slots95050 +Node: FAQ96485 +Ref: Can I control how the popup buffer is displayed?96614 +Ref: How can I copy text from the popup buffer?96795 +Ref: How can I autoload prefix and suffix commands?97289 +Ref: How does Transient compare to prefix keys and universal arguments?97763 +Ref: How does Transient compare to Magit-Popup and Hydra?98006 +Ref: Why did some of the key bindings change?98200 +Ref: Why does q not quit popups anymore?100553 +Node: Keystroke Index101656 +Node: Command and Function Index103521 +Node: Variable Index110113 +Node: Concept Index112523 +Node: GNU General Public License115259 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/emacs/elpa/with-editor-20240806.1454/with-editor-pkg.el b/emacs/elpa/with-editor-20240806.1454/with-editor-pkg.el @@ -1,15 +0,0 @@ -(define-package "with-editor" "20240806.1454" "Use the Emacsclient as $EDITOR" - '((emacs "26.1") - (compat "30.0.0.0")) - :commit "78c303a0181f2132e2254f965176b549044d74f2" :authors - '(("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) - :maintainers - '(("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) - :maintainer - '("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev") - :keywords - '("processes" "terminals") - :url "https://github.com/magit/with-editor") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/emacs/elpa/with-editor-20240806.1454/with-editor.info b/emacs/elpa/with-editor-20240806.1454/with-editor.info @@ -1,384 +0,0 @@ -This is with-editor.info, produced by makeinfo version 6.8 from -with-editor.texi. - - Copyright (C) 2015-2024 Jonas Bernoulli - <emacs.with-editor@jonas.bernoulli.dev> - - You can redistribute this document 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 document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* With-Editor: (with-editor). Using the Emacsclient as $EDITOR. -END-INFO-DIR-ENTRY - - -File: with-editor.info, Node: Top, Next: Using the With-Editor package, Up: (dir) - -With-Editor User Manual -*********************** - -The library ‘with-editor’ makes it easy to use the Emacsclient as the -‘$EDITOR’ of child processes, making sure they know how to call home. -For remote processes a substitute is provided, which communicates with -Emacs on standard output instead of using a socket as the Emacsclient -does. - - This library was written because Magit has to be able to do the above -to allow the user to edit commit messages gracefully and to edit rebase -sequences, which wouldn’t be possible at all otherwise. - - Because other packages can benefit from such functionality, this -library is made available as a separate package. It also defines some -additional functionality which makes it useful even for end-users, who -don’t use Magit or another package which uses it internally. - -This manual is for With-Editor version 3.4.1. - - Copyright (C) 2015-2024 Jonas Bernoulli - <emacs.with-editor@jonas.bernoulli.dev> - - You can redistribute this document 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 document 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. - -* Menu: - -* Using the With-Editor package:: -* Using With-Editor as a library:: -* Debugging:: -* Function and Command Index:: -* Variable Index:: - -— The Detailed Node Listing — - -Using the With-Editor package - -* Configuring With-Editor:: -* Using With-Editor commands:: - - - -File: with-editor.info, Node: Using the With-Editor package, Next: Using With-Editor as a library, Prev: Top, Up: Top - -1 Using the With-Editor package -******************************* - -The ‘With-Editor’ package is used internally by Magit when editing -commit messages and rebase sequences. It also provides some commands -and features which are useful by themselves, even if you don’t use -Magit. - - For information about using this library in your own package, see -*note Using With-Editor as a library::. - -* Menu: - -* Configuring With-Editor:: -* Using With-Editor commands:: - - -File: with-editor.info, Node: Configuring With-Editor, Next: Using With-Editor commands, Up: Using the With-Editor package - -1.1 Configuring With-Editor -=========================== - -With-Editor tries very hard to locate a suitable ‘emacsclient’ -executable, so ideally you should never have to customize the option -‘with-editor-emacsclient-executable’. When it fails to do so, then the -most likely reason is that someone found yet another way to package -Emacs (most likely on macOS) without putting the executable on ‘$PATH’, -and we have to add another kludge to find it anyway. - - -- User Option: with-editor-emacsclient-executable - The ‘emacsclient’ executable used as the editor by child processes - of this Emacs instance. By using this executable, child processes - can call home to their parent process. - - This option is automatically set at startup by looking in - ‘exec-path’, and other places where the executable could be - installed, to find the ‘emacsclient’ executable most suitable for - the current Emacs instance. - - You should *not* customize this option permanently. If you have to - do it, then you should consider that a temporary kludge and inform - the Magit maintainer as described in *note Debugging::. - - If With-Editor fails to find a suitable ‘emacsclient’ on your - system, then this should be fixed for all users at once, by - teaching ‘with-editor-locate-emacsclient’ how to do so on your - system and systems like yours. Doing it this way has the - advantage, that you won’t have do it again every time you update - Emacs, and that other users who have installed Emacs the same way - as you have, won’t have to go through the same trouble. - - Note that there also is a nuclear option; setting this variable to - ‘nil’ causes the "sleeping editor" described below to be used even - for local child processes. Obviously we don’t recommend that you - use this except in "emergencies", i.e., before we had a change to - add a kludge appropriate for your setup. - - -- Function: with-editor-locate-emacsclient - The function used to set the initial value of the option - ‘with-editor-emacsclient-executable’. There’s a lot of voodoo - here. - - The ‘emacsclient’ cannot be used when using Tramp to run a process on -a remote machine. (Theoretically it could, but that would be hard to -setup, very fragile, and rather insecure). - - With-Editor provides an alternative "editor" which can be used by -remote processes in much the same way as local processes use an -‘emacsclient’ executable. This alternative is known as the "sleeping -editor" because it is implemented as a shell script which sleeps until -it receives a signal. - - -- User Option: with-editor-sleeping-editor - The sleeping editor is a shell script used as the editor of child - processes when the ‘emacsclient’ executable cannot be used. - - This fallback is used for asynchronous processes started inside the - macro ‘with-editor’, when the process runs on a remote machine or - for local processes when ‘with-editor-emacsclient-executable’ is - ‘nil’. - - Where the latter uses a socket to communicate with Emacs’ server, - this substitute prints edit requests to its standard output on - which a process filter listens for such requests. As such it is - not a complete substitute for a proper ‘emacsclient’, it can only - be used as ‘$EDITOR’ of child process of the current Emacs - instance. - - Some shells do not execute traps immediately when waiting for a - child process, but by default we do use such a blocking child - process. - - If you use such a shell (e.g., ‘csh’ on FreeBSD, but not Debian), - then you have to edit this option. You can either replace ‘sh’ - with ‘bash’ (and install that), or you can use the older, less - performant implementation: - - "sh -c '\ - echo \"WITH-EDITOR: $$ OPEN $0$1 IN $(pwd)\"; \ - trap \"exit 0\" USR1; \ - trap \"exit 1\" USR2; \ - while true; do sleep 1; done'" - - Note that the unit separator character () right after the file name - ($0) is required. - - Also note that using this alternative implementation leads to a - delay of up to a second. The delay can be shortened by replacing - ‘sleep 1’ with ‘sleep 0.01’, or if your implementation does not - support floats, then by using ‘nanosleep’ instead. - - -File: with-editor.info, Node: Using With-Editor commands, Prev: Configuring With-Editor, Up: Using the With-Editor package - -1.2 Using With-Editor commands -============================== - -This section describes how to use the ‘with-editor’ library _outside_ of -Magit. You don’t need to know any of this just to create commits using -Magit. - - The commands ‘with-editor-async-shell-command’ and -‘with-editor-shell-command’ are intended as drop in replacements for -‘async-shell-command’ and ‘shell-command’. They automatically export -‘$EDITOR’ making sure the executed command uses the current Emacs -instance as "the editor". With a prefix argument these commands prompt -for an alternative environment variable such as ‘$GIT_EDITOR’. - - -- Command: with-editor-async-shell-command - This command is like ‘async-shell-command’, but it runs the shell - command with the current Emacs instance exported as ‘$EDITOR’. - - -- Command: with-editor-shell-command - This command is like ‘shell-command’, but if the shell command ends - with ‘&’ and is therefore run asynchronously, then the current - Emacs instance is exported as ‘$EDITOR’. - - To always use these variants add this to your init file: - - (keymap-global-set "<remap> <async-shell-command>" - #'with-editor-async-shell-command) - (keymap-global-set "<remap> <shell-command>" - #'with-editor-shell-command) - - Alternatively use the global ‘shell-command-with-editor-mode’. - - -- Variable: shell-command-with-editor-mode - When this mode is active, then ‘$EDITOR’ is exported whenever - ultimately ‘shell-command’ is called to asynchronously run some - shell command. This affects most variants of that command, whether - they are defined in Emacs or in some third-party package. - - The command ‘with-editor-export-editor’ exports ‘$EDITOR’ or another -such environment variable in ‘shell-mode’, ‘eshell-mode’, ‘term-mode’ -and ‘vterm-mode’ buffers. Use this Emacs command before executing a -shell command which needs the editor set, or always arrange for the -current Emacs instance to be used as editor by adding it to the -appropriate mode hooks: - - (add-hook 'shell-mode-hook 'with-editor-export-editor) - (add-hook 'eshell-mode-hook 'with-editor-export-editor) - (add-hook 'term-exec-hook 'with-editor-export-editor) - (add-hook 'vterm-mode-hook 'with-editor-export-editor) - - Some variants of this function exist; these two forms are equivalent: - - (add-hook 'shell-mode-hook - (apply-partially 'with-editor-export-editor "GIT_EDITOR")) - (add-hook 'shell-mode-hook 'with-editor-export-git-editor) - - -- Command: with-editor-export-editor - When invoked in a ‘shell-mode’, ‘eshell-mode’, ‘term-mode’ or - ‘vterm-mode’ buffer, this command teaches shell commands to use the - current Emacs instance as the editor, by exporting ‘$EDITOR’. - - -- Command: with-editor-export-git-editor - This command is like ‘with-editor-export-editor’ but exports - ‘$GIT_EDITOR’. - - -- Command: with-editor-export-hg-editor - This command is like ‘with-editor-export-editor’ but exports - ‘$HG_EDITOR’. - - -File: with-editor.info, Node: Using With-Editor as a library, Next: Debugging, Prev: Using the With-Editor package, Up: Top - -2 Using With-Editor as a library -******************************** - -This section describes how to use the ‘with-editor’ library _outside_ of -Magit to teach another package how to have its child processes call -home, just like Magit does. You don’t need to know any of this just to -create commits using Magit. You can also ignore this if you use -‘with-editor’ outside of Magit, but only as an end-user. - - For information about interactive use and options that affect both -interactive and non-interactive use, see *note Using the With-Editor -package::. - - -- Macro: with-editor &rest body - This macro arranges for the ‘emacsclient’ or the sleeping editor to - be used as the editor of child processes, effectively teaching them - to call home to the current Emacs instance when they require that - the user edits a file. - - This is done by establishing a local binding for - ‘process-environment’ and changing the value of the ‘EDITOR’ - environment variable in that scope. This affects all - (asynchronous) processes started by forms (dynamically) inside - BODY. - - If BODY begins with a literal string, then that variable is set - instead of ‘EDITOR’. - - -- Macro: with-editor* envvar &rest body - This macro is like ‘with-editor’ instead that the ENVVAR argument - is required and that it is evaluated at run-time. - - -- Function: with-editor-set-process-filter process filter - This function is like ‘set-process-filter’ but ensures that adding - the new FILTER does not remove the ‘with-editor-process-filter’. - This is done by wrapping the two filter functions using a lambda, - which becomes the actual filter. It calls FILTER first, which may - or may not insert the text into the PROCESS’s buffer. Then it - calls ‘with-editor-process-filter’, passing ‘t’ as - NO-STANDARD-FILTER. - - -File: with-editor.info, Node: Debugging, Next: Function and Command Index, Prev: Using With-Editor as a library, Up: Top - -3 Debugging -*********** - -With-Editor tries very hard to locate a suitable ‘emacsclient’ -executable, and then sets option ‘with-editor-emacsclient-executable’ -accordingly. In very rare cases this fails. When it does fail, then -the most likely reason is that someone found yet another way to package -Emacs (most likely on macOS) without putting the executable on ‘$PATH’, -and we have to add another kludge to find it anyway. - - If you are having problems using ‘with-editor’, e.g., you cannot -commit in Magit, then please open a new issue at -<https://github.com/magit/with-editor/issues> and provide information -about your Emacs installation. Most importantly how did you install -Emacs and what is the output of ‘M-x with-editor-debug RET’. - - -File: with-editor.info, Node: Function and Command Index, Next: Variable Index, Prev: Debugging, Up: Top - -Appendix A Function and Command Index -************************************* - - -* Menu: - -* with-editor: Using With-Editor as a library. - (line 16) -* with-editor*: Using With-Editor as a library. - (line 31) -* with-editor-async-shell-command: Using With-Editor commands. - (line 17) -* with-editor-export-editor: Using With-Editor commands. - (line 59) -* with-editor-export-git-editor: Using With-Editor commands. - (line 64) -* with-editor-export-hg-editor: Using With-Editor commands. - (line 68) -* with-editor-locate-emacsclient: Configuring With-Editor. - (line 41) -* with-editor-set-process-filter: Using With-Editor as a library. - (line 35) -* with-editor-shell-command: Using With-Editor commands. - (line 21) - - -File: with-editor.info, Node: Variable Index, Prev: Function and Command Index, Up: Top - -Appendix B Variable Index -************************* - - -* Menu: - -* shell-command-with-editor-mode: Using With-Editor commands. - (line 35) -* with-editor-emacsclient-executable: Configuring With-Editor. - (line 13) -* with-editor-sleeping-editor: Configuring With-Editor. - (line 56) - - - -Tag Table: -Node: Top799 -Node: Using the With-Editor package2615 -Node: Configuring With-Editor3202 -Node: Using With-Editor commands7758 -Node: Using With-Editor as a library11060 -Node: Debugging13092 -Node: Function and Command Index13984 -Node: Variable Index15482 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/emacs/elpa/with-editor-20240806.1454/dir b/emacs/elpa/with-editor-20240817.1959/dir diff --git a/emacs/elpa/with-editor-20240806.1454/with-editor-autoloads.el b/emacs/elpa/with-editor-20240817.1959/with-editor-autoloads.el diff --git a/emacs/elpa/with-editor-20240817.1959/with-editor-pkg.el b/emacs/elpa/with-editor-20240817.1959/with-editor-pkg.el @@ -0,0 +1,15 @@ +(define-package "with-editor" "20240817.1959" "Use the Emacsclient as $EDITOR" + '((emacs "26.1") + (compat "30.0.0.0")) + :commit "8c550d9e799a0baedb2164471e7ed19fc15d9196" :authors + '(("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) + :maintainers + '(("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev")) + :maintainer + '("Jonas Bernoulli" . "emacs.with-editor@jonas.bernoulli.dev") + :keywords + '("processes" "terminals") + :url "https://github.com/magit/with-editor") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs/elpa/with-editor-20240806.1454/with-editor.el b/emacs/elpa/with-editor-20240817.1959/with-editor.el diff --git a/emacs/elpa/with-editor-20240806.1454/with-editor.elc b/emacs/elpa/with-editor-20240817.1959/with-editor.elc Binary files differ. diff --git a/emacs/elpa/with-editor-20240817.1959/with-editor.info b/emacs/elpa/with-editor-20240817.1959/with-editor.info @@ -0,0 +1,384 @@ +This is with-editor.info, produced by makeinfo version 6.8 from +with-editor.texi. + + Copyright (C) 2015-2024 Jonas Bernoulli + <emacs.with-editor@jonas.bernoulli.dev> + + You can redistribute this document 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 document 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. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* With-Editor: (with-editor). Using the Emacsclient as $EDITOR. +END-INFO-DIR-ENTRY + + +File: with-editor.info, Node: Top, Next: Using the With-Editor package, Up: (dir) + +With-Editor User Manual +*********************** + +The library ‘with-editor’ makes it easy to use the Emacsclient as the +‘$EDITOR’ of child processes, making sure they know how to call home. +For remote processes a substitute is provided, which communicates with +Emacs on standard output instead of using a socket as the Emacsclient +does. + + This library was written because Magit has to be able to do the above +to allow the user to edit commit messages gracefully and to edit rebase +sequences, which wouldn’t be possible at all otherwise. + + Because other packages can benefit from such functionality, this +library is made available as a separate package. It also defines some +additional functionality which makes it useful even for end-users, who +don’t use Magit or another package which uses it internally. + +This manual is for With-Editor v3.4.1-5-gb88e4a2. + + Copyright (C) 2015-2024 Jonas Bernoulli + <emacs.with-editor@jonas.bernoulli.dev> + + You can redistribute this document 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 document 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. + +* Menu: + +* Using the With-Editor package:: +* Using With-Editor as a library:: +* Debugging:: +* Function and Command Index:: +* Variable Index:: + +— The Detailed Node Listing — + +Using the With-Editor package + +* Configuring With-Editor:: +* Using With-Editor commands:: + + + +File: with-editor.info, Node: Using the With-Editor package, Next: Using With-Editor as a library, Prev: Top, Up: Top + +1 Using the With-Editor package +******************************* + +The ‘With-Editor’ package is used internally by Magit when editing +commit messages and rebase sequences. It also provides some commands +and features which are useful by themselves, even if you don’t use +Magit. + + For information about using this library in your own package, see +*note Using With-Editor as a library::. + +* Menu: + +* Configuring With-Editor:: +* Using With-Editor commands:: + + +File: with-editor.info, Node: Configuring With-Editor, Next: Using With-Editor commands, Up: Using the With-Editor package + +1.1 Configuring With-Editor +=========================== + +With-Editor tries very hard to locate a suitable ‘emacsclient’ +executable, so ideally you should never have to customize the option +‘with-editor-emacsclient-executable’. When it fails to do so, then the +most likely reason is that someone found yet another way to package +Emacs (most likely on macOS) without putting the executable on ‘$PATH’, +and we have to add another kludge to find it anyway. + + -- User Option: with-editor-emacsclient-executable + The ‘emacsclient’ executable used as the editor by child processes + of this Emacs instance. By using this executable, child processes + can call home to their parent process. + + This option is automatically set at startup by looking in + ‘exec-path’, and other places where the executable could be + installed, to find the ‘emacsclient’ executable most suitable for + the current Emacs instance. + + You should *not* customize this option permanently. If you have to + do it, then you should consider that a temporary kludge and inform + the Magit maintainer as described in *note Debugging::. + + If With-Editor fails to find a suitable ‘emacsclient’ on your + system, then this should be fixed for all users at once, by + teaching ‘with-editor-locate-emacsclient’ how to do so on your + system and systems like yours. Doing it this way has the + advantage, that you won’t have do it again every time you update + Emacs, and that other users who have installed Emacs the same way + as you have, won’t have to go through the same trouble. + + Note that there also is a nuclear option; setting this variable to + ‘nil’ causes the "sleeping editor" described below to be used even + for local child processes. Obviously we don’t recommend that you + use this except in "emergencies", i.e., before we had a change to + add a kludge appropriate for your setup. + + -- Function: with-editor-locate-emacsclient + The function used to set the initial value of the option + ‘with-editor-emacsclient-executable’. There’s a lot of voodoo + here. + + The ‘emacsclient’ cannot be used when using Tramp to run a process on +a remote machine. (Theoretically it could, but that would be hard to +setup, very fragile, and rather insecure). + + With-Editor provides an alternative "editor" which can be used by +remote processes in much the same way as local processes use an +‘emacsclient’ executable. This alternative is known as the "sleeping +editor" because it is implemented as a shell script which sleeps until +it receives a signal. + + -- User Option: with-editor-sleeping-editor + The sleeping editor is a shell script used as the editor of child + processes when the ‘emacsclient’ executable cannot be used. + + This fallback is used for asynchronous processes started inside the + macro ‘with-editor’, when the process runs on a remote machine or + for local processes when ‘with-editor-emacsclient-executable’ is + ‘nil’. + + Where the latter uses a socket to communicate with Emacs’ server, + this substitute prints edit requests to its standard output on + which a process filter listens for such requests. As such it is + not a complete substitute for a proper ‘emacsclient’, it can only + be used as ‘$EDITOR’ of child process of the current Emacs + instance. + + Some shells do not execute traps immediately when waiting for a + child process, but by default we do use such a blocking child + process. + + If you use such a shell (e.g., ‘csh’ on FreeBSD, but not Debian), + then you have to edit this option. You can either replace ‘sh’ + with ‘bash’ (and install that), or you can use the older, less + performant implementation: + + "sh -c '\ + echo \"WITH-EDITOR: $$ OPEN $0$1 IN $(pwd)\"; \ + trap \"exit 0\" USR1; \ + trap \"exit 1\" USR2; \ + while true; do sleep 1; done'" + + Note that the unit separator character () right after the file name + ($0) is required. + + Also note that using this alternative implementation leads to a + delay of up to a second. The delay can be shortened by replacing + ‘sleep 1’ with ‘sleep 0.01’, or if your implementation does not + support floats, then by using ‘nanosleep’ instead. + + +File: with-editor.info, Node: Using With-Editor commands, Prev: Configuring With-Editor, Up: Using the With-Editor package + +1.2 Using With-Editor commands +============================== + +This section describes how to use the ‘with-editor’ library _outside_ of +Magit. You don’t need to know any of this just to create commits using +Magit. + + The commands ‘with-editor-async-shell-command’ and +‘with-editor-shell-command’ are intended as drop in replacements for +‘async-shell-command’ and ‘shell-command’. They automatically export +‘$EDITOR’ making sure the executed command uses the current Emacs +instance as "the editor". With a prefix argument these commands prompt +for an alternative environment variable such as ‘$GIT_EDITOR’. + + -- Command: with-editor-async-shell-command + This command is like ‘async-shell-command’, but it runs the shell + command with the current Emacs instance exported as ‘$EDITOR’. + + -- Command: with-editor-shell-command + This command is like ‘shell-command’, but if the shell command ends + with ‘&’ and is therefore run asynchronously, then the current + Emacs instance is exported as ‘$EDITOR’. + + To always use these variants add this to your init file: + + (keymap-global-set "<remap> <async-shell-command>" + #'with-editor-async-shell-command) + (keymap-global-set "<remap> <shell-command>" + #'with-editor-shell-command) + + Alternatively use the global ‘shell-command-with-editor-mode’. + + -- Variable: shell-command-with-editor-mode + When this mode is active, then ‘$EDITOR’ is exported whenever + ultimately ‘shell-command’ is called to asynchronously run some + shell command. This affects most variants of that command, whether + they are defined in Emacs or in some third-party package. + + The command ‘with-editor-export-editor’ exports ‘$EDITOR’ or another +such environment variable in ‘shell-mode’, ‘eshell-mode’, ‘term-mode’ +and ‘vterm-mode’ buffers. Use this Emacs command before executing a +shell command which needs the editor set, or always arrange for the +current Emacs instance to be used as editor by adding it to the +appropriate mode hooks: + + (add-hook 'shell-mode-hook 'with-editor-export-editor) + (add-hook 'eshell-mode-hook 'with-editor-export-editor) + (add-hook 'term-exec-hook 'with-editor-export-editor) + (add-hook 'vterm-mode-hook 'with-editor-export-editor) + + Some variants of this function exist; these two forms are equivalent: + + (add-hook 'shell-mode-hook + (apply-partially 'with-editor-export-editor "GIT_EDITOR")) + (add-hook 'shell-mode-hook 'with-editor-export-git-editor) + + -- Command: with-editor-export-editor + When invoked in a ‘shell-mode’, ‘eshell-mode’, ‘term-mode’ or + ‘vterm-mode’ buffer, this command teaches shell commands to use the + current Emacs instance as the editor, by exporting ‘$EDITOR’. + + -- Command: with-editor-export-git-editor + This command is like ‘with-editor-export-editor’ but exports + ‘$GIT_EDITOR’. + + -- Command: with-editor-export-hg-editor + This command is like ‘with-editor-export-editor’ but exports + ‘$HG_EDITOR’. + + +File: with-editor.info, Node: Using With-Editor as a library, Next: Debugging, Prev: Using the With-Editor package, Up: Top + +2 Using With-Editor as a library +******************************** + +This section describes how to use the ‘with-editor’ library _outside_ of +Magit to teach another package how to have its child processes call +home, just like Magit does. You don’t need to know any of this just to +create commits using Magit. You can also ignore this if you use +‘with-editor’ outside of Magit, but only as an end-user. + + For information about interactive use and options that affect both +interactive and non-interactive use, see *note Using the With-Editor +package::. + + -- Macro: with-editor &rest body + This macro arranges for the ‘emacsclient’ or the sleeping editor to + be used as the editor of child processes, effectively teaching them + to call home to the current Emacs instance when they require that + the user edits a file. + + This is done by establishing a local binding for + ‘process-environment’ and changing the value of the ‘EDITOR’ + environment variable in that scope. This affects all + (asynchronous) processes started by forms (dynamically) inside + BODY. + + If BODY begins with a literal string, then that variable is set + instead of ‘EDITOR’. + + -- Macro: with-editor* envvar &rest body + This macro is like ‘with-editor’ instead that the ENVVAR argument + is required and that it is evaluated at run-time. + + -- Function: with-editor-set-process-filter process filter + This function is like ‘set-process-filter’ but ensures that adding + the new FILTER does not remove the ‘with-editor-process-filter’. + This is done by wrapping the two filter functions using a lambda, + which becomes the actual filter. It calls FILTER first, which may + or may not insert the text into the PROCESS’s buffer. Then it + calls ‘with-editor-process-filter’, passing ‘t’ as + NO-STANDARD-FILTER. + + +File: with-editor.info, Node: Debugging, Next: Function and Command Index, Prev: Using With-Editor as a library, Up: Top + +3 Debugging +*********** + +With-Editor tries very hard to locate a suitable ‘emacsclient’ +executable, and then sets option ‘with-editor-emacsclient-executable’ +accordingly. In very rare cases this fails. When it does fail, then +the most likely reason is that someone found yet another way to package +Emacs (most likely on macOS) without putting the executable on ‘$PATH’, +and we have to add another kludge to find it anyway. + + If you are having problems using ‘with-editor’, e.g., you cannot +commit in Magit, then please open a new issue at +<https://github.com/magit/with-editor/issues> and provide information +about your Emacs installation. Most importantly how did you install +Emacs and what is the output of ‘M-x with-editor-debug RET’. + + +File: with-editor.info, Node: Function and Command Index, Next: Variable Index, Prev: Debugging, Up: Top + +Appendix A Function and Command Index +************************************* + + +* Menu: + +* with-editor: Using With-Editor as a library. + (line 16) +* with-editor*: Using With-Editor as a library. + (line 31) +* with-editor-async-shell-command: Using With-Editor commands. + (line 17) +* with-editor-export-editor: Using With-Editor commands. + (line 59) +* with-editor-export-git-editor: Using With-Editor commands. + (line 64) +* with-editor-export-hg-editor: Using With-Editor commands. + (line 68) +* with-editor-locate-emacsclient: Configuring With-Editor. + (line 41) +* with-editor-set-process-filter: Using With-Editor as a library. + (line 35) +* with-editor-shell-command: Using With-Editor commands. + (line 21) + + +File: with-editor.info, Node: Variable Index, Prev: Function and Command Index, Up: Top + +Appendix B Variable Index +************************* + + +* Menu: + +* shell-command-with-editor-mode: Using With-Editor commands. + (line 35) +* with-editor-emacsclient-executable: Configuring With-Editor. + (line 13) +* with-editor-sleeping-editor: Configuring With-Editor. + (line 56) + + + +Tag Table: +Node: Top799 +Node: Using the With-Editor package2619 +Node: Configuring With-Editor3206 +Node: Using With-Editor commands7762 +Node: Using With-Editor as a library11064 +Node: Debugging13096 +Node: Function and Command Index13988 +Node: Variable Index15486 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: