diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/Makefile | 96 | ||||
| -rw-r--r-- | docs/transient.org | 1862 | ||||
| -rw-r--r-- | docs/transient.texi | 2197 |
3 files changed, 4155 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..eb5084f --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,96 @@ +-include ../config.mk +include ../default.mk + +docs: info html html-dir pdf + +info: $(PKG).info dir +html: $(PKG).html +pdf: $(PKG).pdf + +ORG_ARGS = --batch -Q $(ORG_LOAD_PATH) -l ox-extra -l ox-texinfo+.el +ORG_EVAL = --eval "(ox-extras-activate '(ignore-headlines))" +ORG_EVAL += --eval "(setq indent-tabs-mode nil)" +ORG_EVAL += --eval "(setq org-src-preserve-indentation nil)" +ORG_EVAL += --funcall org-texinfo-export-to-texinfo + +# This target first bumps version strings in the Org source. The +# necessary tools might be missing so other targets do not depend +# on this target and it has to be run explicitly when appropriate. +# +# AMEND=t make texi Update manual to be amended to HEAD. +# VERSION=N make texi Update manual for release. +# +.PHONY: texi +texi: + @$(EMACS) $(ORG_ARGS) $(PKG).org $(ORG_EVAL) + @printf "\n" >> $(PKG).texi + @rm -f $(PKG).texi~ + +%.info: %.texi + @printf "Generating $@\n" + @$(MAKEINFO) --no-split $< -o $@ + +dir: $(PKG).info + @printf "Generating $@\n" + @printf "%s" $^ | xargs -n 1 $(INSTALL_INFO) --dir=$@ + +HTML_FIXUP_CSS = '/<link rel="stylesheet" type="text\/css" href="\/assets\/page.css">/a\ +<link class="s-css-s--style" rel="stylesheet" title="Default" href="/assets/themes/default.css">\ +\n<link class="s-css-s--style" rel="stylesheet alternate" title="Default high contrast" href="/assets/themes/default-high-contrast.css">\ +\n<link class="s-css-s--style" rel="stylesheet alternate" title="Solarized dark xterm" href="/assets/themes/solarized-dark-xterm.css">\ +\n<link class="s-css-s--style" rel="stylesheet alternate" title="Black on white" href="/assets/themes/black-on-white.css">\ +\n<script src="/assets/js/simple-css-switch.js"></script>' +HTML_FIXUP_ONLOAD = 's/<body lang="en">/<body lang="en" onload="simpleCssSwitch()">/' +HTML_FIXUP_MENU = '/<\/body>/i<div id="s-css-s--menu"><\/div>' + +%.html: %.texi + @printf "Generating $@\n" + @$(MAKEINFO) --html --no-split $(MANUAL_HTML_ARGS) $< + @sed -i -e $(HTML_FIXUP_CSS) -e $(HTML_FIXUP_ONLOAD) -e $(HTML_FIXUP_MENU) $@ + +html-dir: $(PKG).texi + @printf "Generating $(PKG)/*.html\n" + @$(MAKEINFO) --html $(MANUAL_HTML_ARGS) $< + @for f in $$(find $(PKG) -name '*.html') ; do \ + sed -i -e $(HTML_FIXUP_CSS) -e $(HTML_FIXUP_ONLOAD) -e $(HTML_FIXUP_MENU) $$f ; \ + done + +%.pdf: %.texi + @printf "Generating $@\n" + @texi2pdf --clean $< > /dev/null + +DOMAIN ?= magit.vc +PUBLISH_PATH ?= /manual/ +RELEASE_PATH ?= /manual/$(VERSION)/ + +S3_BUCKET ?= s3://$(DOMAIN) +PUBLISH_TARGET = $(S3_BUCKET)$(PUBLISH_PATH) +RELEASE_TARGET = $(S3_BUCKET)$(RELEASE_PATH) + +CFRONT_DIST ?= E2LUHBKU1FBV02 +CFRONT_PATHS = $(PKG).html $(PKG).pdf $(PKG)/* + +comma := , +empty := +space := $(empty) $(empty) + +publish: html html-dir pdf + @aws s3 cp $(PKG).html $(PUBLISH_TARGET) + @aws s3 cp $(PKG).pdf $(PUBLISH_TARGET) + @aws s3 sync $(PKG) $(PUBLISH_TARGET)$(PKG)/ + @printf "Generating CDN invalidation\n" + @aws cloudfront create-invalidation --distribution-id $(CFRONT_DIST) --paths \ + "$(subst $(space),$(comma),$(addprefix $(PUBLISH_PATH),$(CFRONT_PATHS)))" > /dev/null + +release: html html-dir pdf + @aws s3 cp $(PKG).html $(RELEASE_TARGET) + @aws s3 cp $(PKG).pdf $(RELEASE_TARGET) + @aws s3 sync $(PKG) $(RELEASE_TARGET)$(PKG)/ + @printf "Generating CDN invalidation\n" + @aws cloudfront create-invalidation --distribution-id $(CFRONT_DIST) --paths \ + "$(subst $(space),$(comma),$(addprefix $(RELEASE_PATH),$(CFRONT_PATHS)))" > /dev/null + +CLEAN = $(PKG).info dir $(PKG) $(PKG).html $(PKG).pdf + +clean: + @rm -rf $(CLEAN) diff --git a/docs/transient.org b/docs/transient.org new file mode 100644 index 0000000..065fc7a --- /dev/null +++ b/docs/transient.org @@ -0,0 +1,1862 @@ +#+TITLE: Transient User and Developer Manual +:PREAMBLE: +#+AUTHOR: Jonas Bernoulli +#+EMAIL: jonas@bernoul.li +#+DATE: 2018-2019 +#+LANGUAGE: en + +#+TEXINFO_DIR_CATEGORY: Emacs +#+TEXINFO_DIR_TITLE: Transient: (transient). +#+TEXINFO_DIR_DESC: Transient Commands +#+SUBTITLE: for version 0.1.0 + +#+TEXINFO_DEFFN: t +#+OPTIONS: H:4 num:4 toc:2 +#+BIND: ox-texinfo+-before-export-hook ox-texinfo+-update-version-strings + +Taking inspiration from prefix keys and prefix arguments, Transient +implements a similar abstraction involving a prefix command, infix +arguments and suffix commands. We could call this abstraction a +"transient command", but because it always involves at least two +commands (a prefix and a suffix) we prefer to call it just a +"transient". + +When the user calls a transient prefix command, then 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 the echo area +until the transient is exited by invoking a suffix command. + +Calling an infix command causes its value to be changed, possibly by +reading a new value in the minibuffer. + +Calling a suffix command usually causes the transient to be exited +but suffix commands can also be configured to not exit the transient. + +#+TEXINFO: @noindent +This manual is for Transient version 0.1.0. + +#+BEGIN_QUOTE +Copyright (C) 2018-2019 Jonas Bernoulli <jonas@bernoul.li> + +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. +#+END_QUOTE +:END: +* Introduction + +Taking inspiration from prefix keys and prefix arguments, Transient +implements a similar abstraction involving a prefix command, infix +arguments and suffix commands. We could call this abstraction a +"transient command", but because it always involves at least two +commands (a prefix and a suffix) we prefer to call it just a +"transient". + +#+BEGIN_QUOTE +Transient keymaps are a feature provided by Emacs. Transients as +implemented by this package involve the use of transient keymaps. + +Emacs provides a feature that it calls "prefix commands". When we +talk about "prefix commands" in this manual, then we mean our own kind +of "prefix commands", unless specified otherwise. To avoid ambiguity +we sometimes use the terms "transient prefix command" for our kind and +"regular prefix command" for Emacs' kind. +#+END_QUOTE + +When the user calls a transient prefix command, then 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 the echo area 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 echo area 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 it can choose to use or ignore the prefix arguments. +For a suffix command that was invoked from a transient the variable +~current-transient-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~. + +The information shown in the echo area while a transient is active +looks a bit like this: + +#+BEGIN_EXAMPLE +,----------------------------------------- +|Arguments +| -f Force (--force) +| -a Annotate (--annotate) +| +|Create +| t tag +| r telease +`----------------------------------------- +#+END_EXAMPLE + +#+BEGIN_QUOTE +This is a simplified version of ~magit-tag~. Info manuals do not +support images or colored text, so the above "screenshot" lacks some +information; in practice you would be able to tell whether the +arguments ~--force~ and ~--annotate~ are enabled or not based on their +color. +#+END_QUOTE + +Transient can be used to implement simple "command dispatchers". The +main benefit then is that the user can see all the available commands +in the echo area. 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~ 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, then one can call a command with arguments that +are just as complex as when calling the same function non-interactively +using code. + +Invoking a transient 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 [[*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 [[*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 [[*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 implement yet). + +* Usage +** 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 commands activates a +transient keymap, which temporarily binds the transients 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 the echo area), 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. + +** 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 echo area 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~ and ~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~. + +- Key: C-g, transient-quit-seq +- Key: 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, + then it returns to the previous transient, if any. + +- Key: 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. + +- Key: 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. + +- Key: M-x transient-resume, transient-resume + + This command resumes the previously suspended stack of transients, + if any. + +** Common Suffix Commands +*** _ :ignore: + +A few shared suffix commands are available in all transients. These +suffix commands are not shown in the echo area by default. + +Most of these commands are bound to ~C-x <key>~ and after pressing ~C-x~ a +section featuring all common commands is temporarily show in the echo +area. After invoking one of these commands that 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. + +- Key: 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 to many options. + + While a transient is active, pressing ~C-x~ always shows the common + command. 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 describe in either the previous node or +in one of the following nodes. + +*** Notes on Common Key Bindings +:PROPERTIES: +:NONODE: t +:END: + +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 ~C-x ...~ bindings 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 (and already do) use for Magit, and +also using that for a common command would prevent me from doing so. + +** 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. [fn: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 [[*Using History]]). + +- Key: C-x s, transient-set + + This command saves the value of the active transient for this Emacs + session. + +- Key: C-x C-s, transient-save + + Save the value of the active transient persistently across Emacs + sessions. + +- User Option: transient-values-file + + This file is used to persist the values of transients between Emacs + sessions. + +[fn: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. This is something I am +rethinking, but I don't want to rush any changes.) + +** Using History + +Every time the user invokes a suffix command the transient's current +value is saved to its history. This values can be cycled through the +same way one can cycle through the history of commands that read +user-input in the minibuffer. + +- Key: M-p, transient-history-prev + + This command switches to the previous value used for the active + transient. + +- Key: M-n, transient-history-next + + 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, then 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 +[[*Suffix Slots]]). + +Both kinds of history are saved to a file when Emacs is exited. + +- User Option: transient-history-file + + This file 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 in saved in ~transient-history-file~. + +** 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. + +- Key: C-h, transient-help + + This command enters help mode. When help mode is active, then + typing ~<key>~ shows information about the suffix command that ~<key>~ + normally is bound to (instead of invoking it). Pressing ~C-h~ a + second time shows information about the /prefix/ command. + + After typing ~<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 commands doc-string, for +non-infix suffixes this is usually appropriate. + +** 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 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 transient 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. + +(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 default level and using a higher level might not give you +as many additional suffixes as you hoped.) + +- 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 file is used to persist the levels of transients and their + suffix between Emacs sessions. + +- Key: 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 does instead prompt the user for the level that 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. + +* Other Options + +- User Option: transient-show-popup + + This option controls whether the current transient's infix and + suffix commands are shown in the echo area. + + If ~t~ (the default), then the infix and suffix commands are shown as + soon as the transient is invoked. If ~nil~, only a one line summary + is shown until the user presses a key that forms an incomplete key + sequence. If a number, behave as for ~nil~ but also show the commands + after that many seconds of inactivity. + +- 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, 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 + 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. It 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 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. + + #+BEGIN_SRC emacs-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)))) + #+END_SRC + +- 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, then 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. + +* Modifying Existing Transients + +To an extend transients can be customized interactively, see [[*Enabling +and Disabling Suffixes]]. This section explains how existing transients +can be further modified non-interactively. + +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 ~define-transient-command~. See [[*Suffix Specifications]]. +- LOC is a command, a key vector or a key description (a string as + returned by ~key-description~). + +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 + + This function inserts SUFFIX into PREFIX before LOC. + +- Function: transient-append-suffix prefix loc suffix + + This function inserts SUFFIX into PREFIX after LOC. + +- Function: transient-replace-suffix prefix loc suffix + + This function replaces the suffix at LOC in PREFIX with SUFFIX. + +- Function: transient-remove-suffix prefix loc + + This function removes the suffix at LOC in PREFIX. + +- Function: transient-get-suffix prefix loc + + This function returns the suffix 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 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 to fail also. Among these +functions only ~transient-get-suffix~ and ~transient-suffix-put~ may +signal an error. + +* Defining New Commands +** 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* it +binds the transient's infix and suffix commands. In other works, it +defines the complete transient, not just the transient prefix command +that is used to invoke that transient. + +- Macro: define-transient-command 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 echo area. At least one + GROUP has to be specified. See [[*Binding Suffix and Infix Commands]]. + + The BODY is optional. If it is omitted, then ARGLIST is ignored and + the function definition becomes: + + #+BEGIN_SRC emacs-lisp + (lambda () + (interactive) + (transient-setup 'NAME)) + #+END_SRC + + 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: + + #+BEGIN_SRC emacs-lisp + (transient-setup 'NAME nil nil :scope SCOPE) + #+END_SRC + + For example, the scope of the ~magit-branch-configure~ transient is + the branch whose variables are being configured. + +** Binding Suffix and Infix Commands +*** _ :ignore: + +The macro ~define-transient-command~ is used to define a transient. +This defines the actual transient prefix command (see [[*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 [[*Modifying Existing +Transients]]). These functions take a "suffix specification" as one of +their arguments, which has the same form as the specifications used in +~define-transient-command~. + +*** 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 [[*Group Classes]]. + +Groups are specified in the call to ~define-transient-command~, 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: + +#+BEGIN_SRC emacs-lisp + [{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...] +#+END_SRC + +The LEVEL is optional and defaults to 4. See [[*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 [[*Predicate Slots]]. + +- Finally the value of ~:hide~, if non-nil, is a predicate that control + 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: + + #+BEGIN_SRC emacs-lisp + (lambda () + (eq (car transient--redisplay-key) + ?\C-c)) ; the prefix key shared by all bindings + #+END_SRC + +The ELEMENTs are either all subgroups (vectors), or all suffixes +(lists) and strings. (At least currently no group type exists that +would allow mixing subgroups with commands at the same level, though +in principal there is nothing that prevents that.) + +If the ELEMENTs are not subgroups, then they can be a mixture of lists +that specify commands and strings. Strings are inserted verbatim. +The empty string can be used to insert gaps between suffixes, which is +particularly useful if the suffixes are outlined as a table. + +The form of suffix specifications is documented in the next node. + +*** Suffix Specifications + +A transient's suffix and infix commands are bound when the transient +prefix command is defined using ~define-transient-command~, see +[[*Defining Transients]]. The commands are organized into groups, see +[[*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 [[*Modifying +Existing Transients]]. + +Suffix specifications have this form: + +#+BEGIN_SRC emacs-lisp + ([LEVEL] [KEY] [DESCRIPTION] COMMAND|ARGUMENT [KEYWORD VALUE]...) +#+END_SRC + +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 objects value just for the binding inside this transient. + +- LEVEL is the suffix level, an integer between 1 and 7. See + [[*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 + return a string. The function should to 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 is a symbol that is bound as a function, which has to be a + command. Any command will do; it does not need to have an object + associated with it (as would be the case if ~define-suffix-command~ + or ~define-infix-command~ were used to define it). + + 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. + +- The mandatory argument can also be an 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 the long argument + (which can also be specified using ~:argument~). + + Only the long argument is displayed in the echo area. 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 [[*Suffix +Slots]]. + +** Defining Suffix and Infix Commands + +- Macro: define-suffix-command 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. + Use the function ~transient-args~ or the low-level variable + ~current-transient-suffixes~ if the former does not give you all the + required details. This should, but does not necessarily have to be, + done inside the ~interactive~ form; just like for ~prefix-arg~ and + ~current-prefix-arg~. + +- Macro: define-infix-command 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. + + The keyword-value pairs are mandatory. All transient infix commands + are ~equal~ to each other (but not ~eq~), so it is meaningless to define + an infix command without also setting at least ~:class~ and one other + keyword (which it is depends on the used class, usually ~:argument~ or + ~:variable~). + + Each keyword has to be a keyword symbol, either ~:class~ or a keyword + argument supported by the constructor of that class. The + ~transient-switch~ class is used if the class is not specified + explicitly. + + The function definitions is always: + + #+BEGIN_SRC emacs-lisp + (lambda (obj value) + (interactive + (let ((obj (transient-suffix-object))) + (list obj (transient-infix-read obj)))) + (transient-infix-set obj value) + (transient--show)) + #+END_SRC + + ~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-suffix-command~ to define the infix command and use ~t~ as + the value of the ~:transient~ keyword. + +- Macro: define-infix-argument name arglist [docstring] [keyword value]... + + This macro defines NAME as a transient infix command. + + It is an alias for ~define-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 + ~define-infix-command~ instead. + +** Using Infix Arguments + +The function 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' 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 &optional prefix separate + + This function returns the value of the transient from which the + current suffix was called. If the current suffix command was not + called from a transient, then it returns ~nil~. + + If optional PREFIX is non-~nil~, then it should be a symbol, a + transient prefix command. In that case the value of the transient + is only returned if the suffix was invoked from *that* transient. + Otherwise ~nil~ is returned. This function is also used internally, + in which PREFIX can also be a ~transient-prefix~ object. + + If optional SEPARATE is non-~nil~, then the arguments are separated + into two groups. If SEPARATE is ~t~, they are separated into atoms + and conses (~nil~ isn't a valid value, so it doesn't matter that that + is both an atom and a cons). + + SEPARATE can also be a predicate function, in which case the first + element is a list of the values for which it returns non-~nil~ and the + second element is a list of the values for which it returns ~nil~. + + For transients that are used to pass arguments to a subprocess (such + as ~git~), ~stringp~ is a useful value for SEPARATE, it separates + non-positional arguments from positional arguments. The value of + Magit's file argument (~"--"~) for example looks like this: ~("--" + file...)~." + +- Variable: current-transient-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: current-transient-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: current-transient-command + + The transient from which this suffix command was invoked. The + returned value is a symbol, the transient prefix command. + +** Transient State +*** _ :ignore: +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. + +But these are just the defaults. Whether a certain command +deactivates or "exits" the transient is configurable. There is more +than one way in which a command can be "transient" or "non-transient"; +the exact behavior is implemented by calling a so-called "pre-command" +function. Whether non-suffix commands are allowed to be called is +configurable per transient. + +- The transient-ness of suffix commands (including infix commands) is + controlled by the value of their ~transient~ slot, which can be set + either when defining the command or when adding a binding to a + transient while defining the respective transient prefix command. + + Valid values are booleans and the pre-commands described below. + + - ~t~ is equivalent to ~transient--do-stay~. + - ~nil~ is equivalent to ~transient--do-exit~. + - If ~transient~ is unbound (and that is actually the default for + non-infix suffixes) then the value of the prefix's + ~transient-suffix~ slot is used instead. The default value of that + slot is ~nil~, so the suffix's ~transient~ slot being unbound is + essentially equivalent to it being ~nil~. + +- A suffix command can be a prefix command itself, i.e. a + "sub-prefix". While a sub-prefix is active we nearly always want + ~C-g~ to take the user back to the "super-prefix". 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, as stated above, ~nil~ and the + slot being unbound are equivalent, and means "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. + +- 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 ~transient~ slot. + +The available pre-command functions are documented below. 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~. + +*** Pre-commands for Infixes +:PROPERTIES: +:NONODE: t +:END: + +The default for infixes is ~transient--do-stay~. This is also the only +function that makes sense for infixes. + +- Function: transient--do-stay + + Call the command without exporting variables and stay transient. + +*** Pre-commands for Suffixes +:PROPERTIES: +:NONODE: t +:END: + +The default for suffixes is ~transient--do-exit~. + +- Function: transient--do-exit + + Call the command after exporting variables and exit the transient. + +- Function: transient--do-call + + Call the command after exporting variables and stay transient. + +- Function: transient--do-replace + + Call the transient prefix command, replacing the active transient. + + This is used for suffix that are prefixes themselves, i.e. for + sub-prefixes. + +*** Pre-commands for Non-Suffixes +:PROPERTIES: +:NONODE: t +:END: + +The default for non-suffixes, i.e commands that are bound in other +keymaps beside the transient keymap, is ~transient--do-warn~. Silently +ignoring the user-error is also an option, though probably not a good +one. + +If you want to let the user invoke non-suffix commands, then use +~transient--do-stay~ as the value of the prefix's ~transient-non-suffix~ +slot. + +- Function: transient--do-warn + + Call ~transient-undefined~ and stay transient. + +- Function: transient--do-noop + + Call ~transient-noop~ and stay transient. + +*** Special Pre-Commands +:PROPERTIES: +:NONODE: t +:END: + +- 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~. + +* Classes and Methods +** _ :ignore: + +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. + +** 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 ~define-transient-command~. + +- 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 (aka "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. + +** Group Methods + +- 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 echo area. + + 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 + temporally make the ~transient--source-buffer~ the current buffer. + +** Prefix Classes + +Currently the ~transient-prefix~ class is being used for all prefix +command and there is only a single generic functions 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. + +** 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 [[*Group Classes]]). + +- All infix classes derived 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 [[*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 [[*Defining Suffix and Infix Commands]]). + +- Classes used for infix commands that represent arguments should + 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 + not 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-variables~ class. + +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. + +** Suffix Methods +*** _ :ignore: + +To get information about the methods implementing these generic +functions use ~describe-function~. + +*** 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. + +*** 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 doc-string. + + For suffixes show the command's doc-string. + + For infixes show the manpage if that is specified. Otherwise show + the command's doc-string. + +** TODO Prefix Slots + +** 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 [[*Predicate Slots]]. + +Also see [[*Suffix Classes]]. + +*** Slots of ~transient-suffix~ +:PROPERTIES: +:NONODE: t +:END: + +- ~key~ The key, a key vector or a key description string. + +- ~command~ The command, a symbol. + +- ~transient~ Whether to stay transient. See [[*Transient State]]. + +- ~format~ The format used to display the suffix in the echo area. Must + contain the following %-placeholders: + + - ~%k~ For the key. + - ~%d~ For the description. + - ~%v~ For the value. Non-infix suffixes don't have a value. + +- ~description~ The description, either a string or a function that is + called with no argument and returns a string. + +*** Slots of ~transient-infix~ +:PROPERTIES: +:NONODE: t +:END: + +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~. + +- ~multi-value~ For options, whether the option can have multiple + values. If non-nil, then default to use ~completing-read-multiple~. + +- ~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. How exactly that is used depends on + the class of the object. + +*** Slots of ~transient-variable~ +:PROPERTIES: +:NONODE: t +:END: + +- ~variable~ The variable. + +*** Slots of ~transient-switches~ +:PROPERTIES: +:NONODE: t +:END: + +- ~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\\)~. + +** 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. + +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 it should be available depending on +whether the user wants that or not. See [[*Enabling and Disabling +Suffixes]]. + +* Related Abstractions and Packages +** Comparison With Prefix Keys and Prefix Arguments + +While transient commands were inspired by regular prefix keys and +prefix arguments, they are also quite different and much more complex. + +The following diagrams illustrate some of the differences. + +- ~(c)~ represents a return to the command loop. +- ~(+)~ represents the user's choice to press one key or another. +- ~{WORD}~ are possible behaviors. +- ~{NUMBER}~ is a footnote. + +*** Regular Prefix Commands +:PROPERTIES: +:NONODE: t +:END: + +See [[info:elisp#Prefix Keys]]. + +#+BEGIN_EXAMPLE + ,--> command1 --> (c) + | + (c)-(+)-> prefix command or key --+--> command2 --> (c) + | + `--> command3 --> (c) +#+END_EXAMPLE + +*** Regular Prefix Arguments +:PROPERTIES: +:NONODE: t +:END: + +See [[info:elisp#Prefix Command Arguments]]. + +#+BEGIN_EXAMPLE + ,----------------------------------, + | | + v | + (c)-(+)---> prefix argument command --(c)-(+)-> any command --> (c) + | ^ | + | | | + `-- sets or changes --, ,-- maybe used --' | + | | | + v | | + prefix argument state | + ^ | + | | + `-------- discards --------' +#+END_EXAMPLE + +*** Transients +:PROPERTIES: +:NONODE: t +:END: + +(∩`-´)⊃━☆゚.*・。゚ + +This diagram ignores the infix value and external state: + +#+BEGIN_EXAMPLE + (c) + | ,- {stay} ------<-,-<------------<-,-<---, + (+) | | | | + | | | | | + | | ,--> infix1 --| | | + | | | | | | + | | |--> infix2 --| | | + v v | | | | + prefix -(c)-(+)-> infix3 --' ^ | + | | | + |---------------> suffix1 -->--| | + | | | + |---------------> suffix2 ----{1}------> {exit} --> (c) + | | + |---------------> suffix3 -------------> {exit} --> (c) + | | + `--> any command --{2}-> {warn} -->--| + | | + |--> {noop} -->--| + | | + |--> {call} -->--' + | + `------------------> {exit} --> (c) +#+END_EXAMPLE + +This diagram takes the infix value into account to an extend, while +still ignoring external state: + +#+BEGIN_EXAMPLE + (c) + | ,- {stay} ------<-,-<------------<-,-<---, + (+) | | | | + | | | | | + | | ,--> infix1 --| | | + | | | | | | | + | | ,--> infix2 --| | | + v v | | | | | + prefix -(c)-(+)-> infix3 --' | | + | | ^ | + | | | | + |---------------> suffix1 -->--| | + | | ^ | | + | | | | | + |---------------> suffix2 ----{1}------> {exit} --> (c) + | | ^ | | + | | | | v + | | | | | + |---------------> suffix3 -------------> {exit} --> (c) + | | ^ | | + | sets | | v + | | maybe | | + | | used | | + | | | | | + | | infix --' | | + | `---> value | | + | ^ | | + | | | | + | hides | | + | | | | + | `--------------------------<---| + | | | + `--> any command --{2}-> {warn} -->--| | + | | | + |--> {noop} -->--| | + | | | + |--> {call} -->--' ^ + | | + `------------------> {exit} --> (c) +#+END_EXAMPLE + +This diagram provides more information about the infix value +and also takes external state into account. + +#+BEGIN_EXAMPLE + ,----sets--- "anything" + | + v + ,---------> external + | state + | | | + | initialized | ☉‿⚆ + sets from | + | | maybe + | ,----------' used + | | | + (c) | | v + | ,- {stay} --|---<-,-<------|-----<-,-<---, + (+) | | | | | | | + | | | v | | | | + | | ,--> infix1 --| | | | + | | | | | | | | | + | | | | v | | | | + | | ,--> infix2 --| | | | + | | | | ^ | | | | + v v | | | | | | | + prefix -(c)-(+)-> infix3 --' | | | + | | ^ | ^ | + | | | v | | + |---------------> suffix1 -->--| | + | | | ^ | | | + | | | | v | | + |---------------> suffix2 ----{1}------> {exit} --> (c) + | | | ^ | | | + | | | | | | v + | | | | v | | + |---------------> suffix3 -------------> {exit} --> (c) + | | | ^ | | + | sets | | | v + | | initalized maybe | | + | | from used | | + | | | | | | + | | `-- infix --' | | + | `---> value -----------------------------> persistent + | ^ ^ | | across + | | | | | invocations -, + | hides | | | | + | | `----------------------------------------------' + | | | | + | `--------------------------<---| + | | | + `--> any command --{2}-> {warn} -->--| | + | | | + |--> {noop} -->--| | + | | | + |--> {call} -->--' ^ + | | + `------------------> {exit} --> (c) +#+END_EXAMPLE + +- ~{1}~ Transients can be configured to be exited when a suffix command + is invoked. The default is to do so for all suffixes expect for + those that are common to all transients and which are used to + perform tasks such as providing help and saving the value of the + infix arguments for future invocations. The behavior can also be + specified for individual suffix commands individually and may even + depend on state. + +- ~{2}~ Transients can be configured to allow the user to invoke + non-suffix commands. The default is to not allow that and instead + warn the user. + +Despite already being rather complex, even the last diagram leaves out +many details. Most importantly it implies that the decision whether +to remain transient is made later than it actually is made (for the +most part a function on ~pre-command-hook~ is responsible). But such +implementation details are of little relevance to users and are +covered elsewhere. + +** Comparison With Other Packages +*** Magit-Popup +:PROPERTIES: +:NONODE: t +:END: + +Transient is the successor to Magit-Popup (see [[info:magit-popup]]). + +One major difference between these two implementations of the same +ideas is that while Transient uses transient keymaps and embraces the +command-loop, Magit-Popup implemented an inferior mechanism that does +not use transient keymaps and that instead of using the command-loop +implements a naive alternative based on ~read-char~. + +Magit-Popup does not use classes and generic functions and defining a +new command type is near impossible as it involves adding hard-coded +special-cases to many functions. Because of that only a single new +type was added, which was not already part of Magit-Popup's initial +release. + +A lot of things are hard-coded in Magit-Popup. One random example is +that the key bindings for switches must begin with "-" and those for +options must begin with "=". + +*** Hydra +:PROPERTIES: +:NONODE: t +:END: + +Hydra (see https://github.com/abo-abo/hydra) is another package that +provides features similar to those of Transient. + +Both packages use transient keymaps to make a set of commands +temporarily available and the ~lv~ library to show these commands in the +echo area. (The author of Hydra is also the author of ~lv~, which is +maintained in the same repository.) + +A Hydra "body" is equivalent to a Transient "prefix" and a Hydra +"head" is equivalent to a Transient "suffix". Hydra has no equivalent +of a Transient "infix". + +Both hydras and transients can be used as simple command dispatchers. +Used like this they are similar to regular prefix commands and prefix +keys, except that the available commands are shown in the echo area. + +(Another package that does this is ~which-key~. It does so automatically +for any incomplete key sequence. The advantage of that approach is +that no additional work is necessary; the disadvantage is that the +available commands are not organized semantically.) + +Both Hydra and Transient provide features that go beyond simple +command dispatchers: + +- Invoking a command from a hydra does not necessarily exit the hydra. + That makes it possible to invoke the same command again, but using a + shorter key sequence (i.e. the key that was used to enter the hydra + does not have to be pressed again). + + Transient supports that too, but for not this feature is not a focus + and the interface is a bit more complicated. A very basic example + using the current interface: + + #+BEGIN_SRC emacs-lisp + (define-transient-command outline-navigate () + :transient-suffix 'transient--do-stay + :transient-non-suffix 'transient--do-warn + [("p" "next visible heading" outline-previous-visible-heading) + ("n" "next visible heading" outline-next-visible-heading)]) + #+END_SRC + +- Transient support infix arguments; values that are set by infix + commands and then consumed by the invoked suffix command(s). + + To my knowledge, Hydra does not support that. + +Both packages make it possible to specify how exactly the available +commands are outlined: + +- With Hydra this is often done using an explicit format string, which + gives authors a lot of flexibility and makes it possible to do fancy + things. + + The downside of this is that it becomes harder for a user to add + additional commands to an existing hydra and to change key bindings. + +- Transient allows the author of a transient to organize the commands + into groups and the use of generic functions allows authors of + transients to control exactly how a certain command type is + displayed. + + However while Transient support giving sections a heading it does + not currently support giving the displayed information more + structure by, for example, using box-drawing characters. + + That could be implemented by defining a new group class, which lets + the author specify a format string. It should be possible to + implement that without modifying any existing code, but it does not + currently exist. + +* Keystroke Index +:PROPERTIES: +:APPENDIX: t +:INDEX: ky +:COOKIE_DATA: recursive +:END: +* Command Index +:PROPERTIES: +:APPENDIX: t +:INDEX: cp +:END: +* Function Index +:PROPERTIES: +:APPENDIX: t +:INDEX: fn +:END: +* Variable Index +:PROPERTIES: +:APPENDIX: t +:INDEX: vr +:END: + +* _ Copying +:PROPERTIES: +:COPYING: t +:END: + +#+BEGIN_QUOTE +Copyright (C) 2018-2019 Jonas Bernoulli <jonas@bernoul.li> + +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. +#+END_QUOTE + +* _ :ignore: + +# LocalWords: ARGLIST ARGS DOCSTRING ELEMENTs EVAL GROUPs Infixes +# LocalWords: Infixes KEYWORDs LOC LocalWords MERCHANTABILITY Magit +# LocalWords: Magit's Magit-Popup Makefile OBJ OBJ's Pre arglist +# LocalWords: args boolean booleans customizable docstring eval +# LocalWords: featurep infixes init keymap keymaps loc magit manpage +# LocalWords: minibuffer ness nilly noop plist pre pre-command prev +# LocalWords: rebase src subclass subclasses subprocess superclass +# LocalWords: texinfo+ utils + +# IMPORTANT: Also update ORG_ARGS and ORG_EVAL in the Makefile. +# Local Variables: +# eval: (require 'magit-utils nil t) +# eval: (require 'org-man nil t) +# eval: (require 'ox-extra nil t) +# eval: (require 'ox-texinfo+ nil t) +# eval: (and (featurep 'ox-extra) (ox-extras-activate '(ignore-headlines))) +# indent-tabs-mode: nil +# org-src-preserve-indentation: nil +# End: diff --git a/docs/transient.texi b/docs/transient.texi new file mode 100644 index 0000000..a6f05c2 --- /dev/null +++ b/docs/transient.texi @@ -0,0 +1,2197 @@ +\input texinfo @c -*- texinfo -*- +@c %**start of header +@setfilename transient.info +@settitle Transient User and Developer Manual +@documentencoding UTF-8 +@documentlanguage en +@c %**end of header + +@copying +@quotation +Copyright (C) 2018-2019 Jonas Bernoulli <jonas@@bernoul.li> + +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. + +@end quotation +@end copying + +@dircategory Emacs +@direntry +* Transient: (transient). Transient Commands. +@end direntry + +@finalout +@titlepage +@title Transient User and Developer Manual +@subtitle for version 0.1.0 +@author Jonas Bernoulli +@page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@contents + +@ifnottex +@node Top +@top Transient User and Developer Manual + +Taking inspiration from prefix keys and prefix arguments, Transient +implements a similar abstraction involving a prefix command, infix +arguments and suffix commands. We could call this abstraction a +"transient command", but because it always involves at least two +commands (a prefix and a suffix) we prefer to call it just a +"transient". + +When the user calls a transient prefix command, then 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 @code{pre-command-hook} and @code{post-command-hook}. The available +suffix and infix commands and their state are shown in the echo area +until the transient is exited by invoking a suffix command. + +Calling an infix command causes its value to be changed, possibly by +reading a new value in the minibuffer. + +Calling a suffix command usually causes the transient to be exited +but suffix commands can also be configured to not exit the transient. + +@noindent +This manual is for Transient version 0.1.0. + +@quotation +Copyright (C) 2018-2019 Jonas Bernoulli <jonas@@bernoul.li> + +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. + +@end quotation +@end ifnottex + +@menu +* Introduction:: +* Usage:: +* Other Options:: +* Modifying Existing Transients:: +* Defining New Commands:: +* Classes and Methods:: +* Related Abstractions and Packages:: +* Keystroke Index:: +* Command Index:: +* Function Index:: +* Variable Index:: + +@detailmenu +--- 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:: + +Defining New Commands + +* 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:: + + +Related Abstractions and Packages + +* Comparison With Prefix Keys and Prefix Arguments:: +* Comparison With Other Packages:: + +@end detailmenu +@end menu + +@node Introduction +@chapter Introduction + +Taking inspiration from prefix keys and prefix arguments, Transient +implements a similar abstraction involving a prefix command, infix +arguments and suffix commands. We could call this abstraction a +"transient command", but because it always involves at least two +commands (a prefix and a suffix) we prefer to call it just a +"transient". + +@quotation +Transient keymaps are a feature provided by Emacs. Transients as +implemented by this package involve the use of transient keymaps. + +Emacs provides a feature that it calls "prefix commands". When we +talk about "prefix commands" in this manual, then we mean our own kind +of "prefix commands", unless specified otherwise. To avoid ambiguity +we sometimes use the terms "transient prefix command" for our kind and +"regular prefix command" for Emacs' kind. + +@end quotation + +When the user calls a transient prefix command, then 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 @code{pre-command-hook} and @code{post-command-hook}. The available suffix +and infix commands and their state are shown in the echo area 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 echo area 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 it can choose to use or ignore the prefix arguments. +For a suffix command that was invoked from a transient the variable +@code{current-transient-suffixes} and the function @code{transient-args} serve about +the same purpose as the variables @code{prefix-arg} and @code{current-prefix-arg} do +for any command that was called after the prefix arguments have been +set using a command such as @code{universal-argument}. + +The information shown in the echo area while a transient is active +looks a bit like this: + +@example +,----------------------------------------- +|Arguments +| -f Force (--force) +| -a Annotate (--annotate) +| +|Create +| t tag +| r telease +`----------------------------------------- +@end example + +@quotation +This is a simplified version of @code{magit-tag}. Info manuals do not +support images or colored text, so the above "screenshot" lacks some +information; in practice you would be able to tell whether the +arguments @code{--force} and @code{--annotate} are enabled or not based on their +color. + +@end quotation + +Transient can be used to implement simple "command dispatchers". The +main benefit then is that the user can see all the available commands +in the echo area. 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 @code{magit-dispatch} 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, then one can call a command with arguments that +are just as complex as when calling the same function non-interactively +using code. + +Invoking a transient 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 @ref{Using History}. + +After a transient prefix command is invoked @code{C-h <key>} can be used to +show the documentation for the infix or suffix command that @code{<key>} is +bound to (see @ref{Getting Help for Suffix Commands}) and infixes and +suffixes can be removed from the transient using @code{C-x l <key>}. Infixes +and suffixes that are disabled by default can be enabled the same way. +See @ref{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 implement yet). + +@node Usage +@chapter Usage + +@menu +* Invoking Transients:: +* Aborting and Resuming Transients:: +* Common Suffix Commands:: +* Saving Values:: +* Using History:: +* Getting Help for Suffix Commands:: +* Enabling and Disabling Suffixes:: +@end menu + +@node Invoking Transients +@section 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 commands activates a +transient keymap, which temporarily binds the transients 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 the echo area), 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 @strong{arguments}. + +Instead of setting arguments to be used by a suffix command, infix +commands may also set some value by side-effect. + +@node Aborting and Resuming Transients +@section Aborting and Resuming Transients + +To quit the transient without invoking a suffix command press @code{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 @code{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 echo area is updated accordingly. +Pressing @code{C-g} while a nested transient is active only quits the +innermost transient, causing a return to the previous transient. + +@code{C-q} and @code{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 +@code{M-x transient-resume}. + +@table @asis +@kindex C-g +@cindex transient-quit-seq +@item @kbd{C-g} @tie{}@tie{}@tie{}@tie{}(@code{transient-quit-seq}) +@kindex C-g +@cindex transient-quit-one +@item @kbd{C-g} @tie{}@tie{}@tie{}@tie{}(@code{transient-quit-one}) + +This key quits the currently active incomplete key sequence, if any, +or else the current transient. When quitting the current transient, +then it returns to the previous transient, if any. + +@kindex C-q +@cindex transient-quit-all +@item @kbd{C-q} @tie{}@tie{}@tie{}@tie{}(@code{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. + +@kindex C-z +@cindex transient-suspend +@item @kbd{C-z} @tie{}@tie{}@tie{}@tie{}(@code{transient-suspend}) + +Like @code{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. + +@kindex M-x transient-resume +@cindex transient-resume +@item @kbd{M-x transient-resume} @tie{}@tie{}@tie{}@tie{}(@code{transient-resume}) + +This command resumes the previously suspended stack of transients, +if any. +@end table + +@node Common Suffix Commands +@section Common Suffix Commands + +A few shared suffix commands are available in all transients. These +suffix commands are not shown in the echo area by default. + +Most of these commands are bound to @code{C-x <key>} and after pressing @code{C-x} a +section featuring all common commands is temporarily show in the echo +area. After invoking one of these commands that 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. + +@table @asis +@kindex C-x t +@cindex transient-toggle-common +@item @kbd{C-x t} @tie{}@tie{}@tie{}@tie{}(@code{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 @code{C-x}. This only affects the current +Emacs session. + +@end table + +@defopt 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 to many options. + +While a transient is active, pressing @code{C-x} always shows the common +command. The value of this option can be changed for the current +Emacs session by typing @code{C-x t} while a transient is active. +@end defopt + +The other common commands are describe in either the previous node or +in one of the following nodes. + +@subsection Notes on Common Key Bindings + +You may have noticed that the bindings for some of the common commands +do @strong{not} have the prefix @code{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 @strong{not} grayed out are very important bindings that are @strong{always} +available, even when invoking the "common command key prefix" or @strong{any +other} transient-specific prefix. The non-prefix keys that @strong{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. @code{M-p M-p M-p} is much more convenient than @code{C-x M-p C-x M-p C-x M-p}. + +You may also have noticed that the "Set" command is bound to @code{C-x s}, +while Magit-Popup used to bind @code{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 @code{C-c} all the @code{C-x ...} bindings 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 +@strong{without} the section of common commands also popping up. @code{C-c} in +particular is a prefix that I want (and already do) use for Magit, and +also using that for a common command would prevent me from doing so. + +@node Saving Values +@section 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. @footnote{@code{magit-diff} and @code{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. This is something I am +rethinking, but I don't want to rush any changes.)} + +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 @ref{Using History}). + +@table @asis +@kindex C-x s +@cindex transient-set +@item @kbd{C-x s} @tie{}@tie{}@tie{}@tie{}(@code{transient-set}) + +This command saves the value of the active transient for this Emacs +session. + +@kindex C-x C-s +@cindex transient-save +@item @kbd{C-x C-s} @tie{}@tie{}@tie{}@tie{}(@code{transient-save}) + +Save the value of the active transient persistently across Emacs +sessions. + +@end table + +@defopt transient-values-file + +This file is used to persist the values of transients between Emacs +sessions. +@end defopt + +@node Using History +@section Using History + +Every time the user invokes a suffix command the transient's current +value is saved to its history. This values can be cycled through the +same way one can cycle through the history of commands that read +user-input in the minibuffer. + +@table @asis +@kindex M-p +@cindex transient-history-prev +@item @kbd{M-p} @tie{}@tie{}@tie{}@tie{}(@code{transient-history-prev}) + +This command switches to the previous value used for the active +transient. + +@kindex M-n +@cindex transient-history-next +@item @kbd{M-n} @tie{}@tie{}@tie{}@tie{}(@code{transient-history-next}) + +This command switches to the next value used for the active +transient. +@end table + +In addition to the transient-wide history, Transient of course +supports per-infix history. When an infix reads user-input using the +minibuffer, then 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 +@ref{Suffix Slots}). + +Both kinds of history are saved to a file when Emacs is exited. + +@defopt transient-history-file + +This file is used to persist the history of transients and their +infixes between Emacs sessions. +@end defopt + +@defopt transient-history-limit + +This option controls how many history elements are kept at the time +the history in saved in @code{transient-history-file}. +@end defopt + +@node Getting Help for Suffix Commands +@section 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. + +@table @asis +@kindex C-h +@cindex transient-help +@item @kbd{C-h} @tie{}@tie{}@tie{}@tie{}(@code{transient-help}) + +This command enters help mode. When help mode is active, then +typing @code{<key>} shows information about the suffix command that @code{<key>} +normally is bound to (instead of invoking it). Pressing @code{C-h} a +second time shows information about the @emph{prefix} command. + +After typing @code{<key>} the stack of transient states is suspended and +information about the suffix command is shown instead. Typing @code{q} in +the help buffer buries that buffer and resumes the transient state. +@end table + +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. @code{transient-help} then tries +to jump to the correct location within that. Info manuals are also +supported. The fallback is to show the commands doc-string, for +non-infix suffixes this is usually appropriate. + +@node Enabling and Disabling Suffixes +@section 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 that authors can use to classify a +transient's infixes and suffixes along the essentials@dots{}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 transient and/or their individual suffixes +can be changed interactively, by invoking the transient and then +pressing @code{C-x l} to enter the "edit" mode, see below. + +The default level for both transients and their suffixes is 4. The +@code{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. + +(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 default level and using a higher level might not give you +as many additional suffixes as you hoped.) + +@defopt 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. +@end defopt + +@defopt transient-levels-file + +This file is used to persist the levels of transients and their +suffix between Emacs sessions. +@end defopt + +@table @asis +@kindex C-x l +@cindex transient-set-level +@item @kbd{C-x l} @tie{}@tie{}@tie{}@tie{}(@code{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 does instead prompt the user for the level that that suffix +should be placed on. + +Help mode is available in edit mode. + +To change the transient level press @code{C-x l} again. + +To exit edit mode press @code{C-g}. + +Note that edit mode does not display any suffixes that are not +currently usable. @code{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. +@end table + +@node Other Options +@chapter Other Options + +@defopt transient-show-popup + +This option controls whether the current transient's infix and +suffix commands are shown in the echo area. + +If @code{t} (the default), then the infix and suffix commands are shown as +soon as the transient is invoked. If @code{nil}, only a one line summary +is shown until the user presses a key that forms an incomplete key +sequence. If a number, behave as for @code{nil} but also show the commands +after that many seconds of inactivity. +@end defopt + +@defopt 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, then the key binding for infix argument +are highlighted when only a long argument (e.g. @code{--verbose}) is +specified but no shorthand (e.g @code{-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 +@code{transient-mismatched-key} and @code{transient-nonstandard-key}. +@end defopt + +@defopt transient-substitute-key-function + +This function is used to modify key bindings. It 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 @code{key} slot, or key description that +replaces the prefix key. It could be used to make other +substitutions, but that is discouraged. + +For example, @code{=} is hard to reach using my custom keyboard layout, +so I substitute @code{(} for that, which is easy to reach using a layout +optimized for lisp. + +@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)))) +@end lisp +@end defopt + +@defopt transient-detect-key-conflicts + +This option controls whether key binding conflicts should be +detected at the time the transient is invoked. If so, then 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. +@end defopt + +@node Modifying Existing Transients +@chapter Modifying Existing Transients + +To an extend transients can be customized interactively, see @ref{Enabling and Disabling Suffixes}. This section explains how existing transients +can be further modified non-interactively. + +The following functions share a few arguments: + +@itemize +@item +PREFIX is a transient prefix command, a symbol. + +@item +SUFFIX is a transient infix or suffix specification in the same form +as expected by @code{define-transient-command}. See @ref{Suffix Specifications}. + +@item +LOC is a command, a key vector or a key description (a string as +returned by @code{key-description}). +@end itemize + +These functions operate on the information stored in the +@code{transient--layout} property of the PREFIX symbol. Suffix entries in +that tree are not objects but have the form @code{(LEVEL CLASS PLIST)}, where +plist should set at least @code{:key}, @code{:description} and @code{:command}. + +@defun transient-insert-suffix prefix loc suffix + +This function inserts SUFFIX into PREFIX before LOC@. +@end defun + +@defun transient-append-suffix prefix loc suffix + +This function inserts SUFFIX into PREFIX after LOC@. +@end defun + +@defun transient-replace-suffix prefix loc suffix + +This function replaces the suffix at LOC in PREFIX with SUFFIX@. +@end defun + +@defun transient-remove-suffix prefix loc + +This function removes the suffix at LOC in PREFIX@. +@end defun + +@defun transient-get-suffix prefix loc + +This function returns the suffix at LOC in PREFIX@. The returned +value has the form mentioned above. +@end defun + +@defun transient-suffix-put prefix loc prop value + +This function edits the suffix at LOC in PREFIX, by setting the +PROP of its plist to VALUE@. +@end defun + +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 to fail also. Among these +functions only @code{transient-get-suffix} and @code{transient-suffix-put} may +signal an error. + +@node Defining New Commands +@chapter Defining New Commands + +@menu +* Defining Transients:: +* Binding Suffix and Infix Commands:: +* Defining Suffix and Infix Commands:: +* Using Infix Arguments:: +* Transient State:: +@end menu + +@node Defining Transients +@section 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 @strong{and} it +binds the transient's infix and suffix commands. In other works, it +defines the complete transient, not just the transient prefix command +that is used to invoke that transient. + +@defmac define-transient-command name arglist [docstring] [keyword value]@dots{} group@dots{} [body@dots{}] + +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 @code{:class} or a keyword +argument supported by the constructor of that class. The +@code{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 echo area. At least one +GROUP has to be specified. See @ref{Binding Suffix and Infix Commands}. + +The BODY is optional. If it is omitted, then ARGLIST is ignored and +the function definition becomes: + +@lisp +(lambda () + (interactive) + (transient-setup 'NAME)) +@end lisp + +If BODY is specified, then it must begin with an @code{interactive} form +that matches ARGLIST, and it must call @code{transient-setup}. It may +however call that function only when some condition is satisfied. + +All transients have a (possibly @code{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 @code{interactive} form and has to be passed to the +setup function: + +@lisp +(transient-setup 'NAME nil nil :scope SCOPE) +@end lisp + +For example, the scope of the @code{magit-branch-configure} transient is +the branch whose variables are being configured. +@end defmac + +@node Binding Suffix and Infix Commands +@section Binding Suffix and Infix Commands + +The macro @code{define-transient-command} is used to define a transient. +This defines the actual transient prefix command (see @ref{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 @code{transient-insert-suffix} (See @ref{Modifying Existing Transients}). These functions take a "suffix specification" as one of +their arguments, which has the same form as the specifications used in +@code{define-transient-command}. + +@menu +* Group Specifications:: +* Suffix Specifications:: +@end menu + +@node Group Specifications +@subsection 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 @ref{Group Classes}. + +Groups are specified in the call to @code{define-transient-command}, 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: + +@lisp +[@{LEVEL@} @{DESCRIPTION@} @{KEYWORD VALUE@}... ELEMENT...] +@end lisp + +The LEVEL is optional and defaults to 4. See @ref{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 @code{:class} or a keyword argument supported by the +constructor of that class. + +@itemize +@item +One of these keywords, @code{:description}, is equivalent to specifying +DESCRIPTION at the very beginning of the vector. The recommendation +is to use @code{:description} if some other keyword is also used, for +consistency, or DESCRIPTION otherwise, because it looks better. + + +@item +Likewise @code{:level} is equivalent to LEVEL@. + + +@item +Other important keywords include the @code{:if...} keywords. These +keywords control whether the group is available in a certain +situation. + +For example, one group of the @code{magit-rebase} transient uses @code{:if + magit-rebase-in-progress-p}, which contains the suffixes that are +useful while rebase is already in progress; and another that uses +@code{: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 @ref{Predicate Slots}. + + +@item +Finally the value of @code{:hide}, if non-nil, is a predicate that control +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: + +@lisp +(lambda () + (eq (car transient--redisplay-key) + ?\C-c)) ; the prefix key shared by all bindings +@end lisp +@end itemize + +The ELEMENTs are either all subgroups (vectors), or all suffixes +(lists) and strings. (At least currently no group type exists that +would allow mixing subgroups with commands at the same level, though +in principal there is nothing that prevents that.) + +If the ELEMENTs are not subgroups, then they can be a mixture of lists +that specify commands and strings. Strings are inserted verbatim. +The empty string can be used to insert gaps between suffixes, which is +particularly useful if the suffixes are outlined as a table. + +The form of suffix specifications is documented in the next node. + +@node Suffix Specifications +@subsection Suffix Specifications + +A transient's suffix and infix commands are bound when the transient +prefix command is defined using @code{define-transient-command}, see +@ref{Defining Transients}. The commands are organized into groups, see +@ref{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 @code{transient-insert-suffix}, see @ref{Modifying Existing Transients}. + +Suffix specifications have this form: + +@lisp +([LEVEL] [KEY] [DESCRIPTION] COMMAND|ARGUMENT [KEYWORD VALUE]...) +@end lisp + +LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs +@code{:level}, @code{:key} and @code{: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 objects value just for the binding inside this transient. + +@itemize +@item +LEVEL is the suffix level, an integer between 1 and 7. See +@ref{Enabling and Disabling Suffixes}. + + +@item +KEY is the key binding, either a vector or key description string. + + +@item +DESCRIPTION is the description, either a string or a function that +return a string. The function should to 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 @code{:description} in that +case. +@end itemize + +The next element is either a command or an argument. This is the only +argument that is mandatory in all cases. + +@itemize +@item +COMMAND is a symbol that is bound as a function, which has to be a +command. Any command will do; it does not need to have an object +associated with it (as would be the case if @code{define-suffix-command} +or @code{define-infix-command} were used to define it). + +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@. + + +@item +The mandatory argument can also be an 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 @code{:shortarg}) and the second the long argument +(which can also be specified using @code{:argument}). + +Only the long argument is displayed in the echo area. See +@code{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 "@samp{" + (e.g. "--format}") then @code{transient-option} is used, otherwise +@code{transient-switch}. +@end itemize + +Finally details can be specified using optional KEYWORD-VALUE pairs. +Each keyword has to be a keyword symbol, either @code{:class} or a keyword +argument supported by the constructor of that class. See @ref{Suffix Slots}. + +@node Defining Suffix and Infix Commands +@section Defining Suffix and Infix Commands + +@defmac define-suffix-command name arglist [docstring] [keyword value]@dots{} body@dots{} + +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 @code{:class} or a keyword +argument supported by the constructor of that class. The +@code{transient-suffix} class is used if the class is not specified +explicitly. + +The BODY must begin with an @code{interactive} form that matches ARGLIST@. +Use the function @code{transient-args} or the low-level variable +@code{current-transient-suffixes} if the former does not give you all the +required details. This should, but does not necessarily have to be, +done inside the @code{interactive} form; just like for @code{prefix-arg} and +@code{current-prefix-arg}. +@end defmac + +@defmac define-infix-command name arglist [docstring] [keyword value]@dots{} + +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. + +The keyword-value pairs are mandatory. All transient infix commands +are @code{equal} to each other (but not @code{eq}), so it is meaningless to define +an infix command without also setting at least @code{:class} and one other +keyword (which it is depends on the used class, usually @code{:argument} or +@code{:variable}). + +Each keyword has to be a keyword symbol, either @code{:class} or a keyword +argument supported by the constructor of that class. The +@code{transient-switch} class is used if the class is not specified +explicitly. + +The function definitions is always: + +@lisp +(lambda (obj value) + (interactive + (let ((obj (transient-suffix-object))) + (list obj (transient-infix-read obj)))) + (transient-infix-set obj value) + (transient--show)) +@end lisp + +@code{transient-infix-read} and @code{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 +@code{transient-suffix-command} to define the infix command and use @code{t} as +the value of the @code{:transient} keyword. +@end defmac + +@defmac define-infix-argument name arglist [docstring] [keyword value]@dots{} + +This macro defines NAME as a transient infix command. + +It is an alias for @code{define-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 +@code{define-infix-command} instead. +@end defmac + +@node Using Infix Arguments +@section Using Infix Arguments + +The function 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 @code{nil} (which causes the function to return +@code{nil} too). + +Like for Emacs' prefix arguments it is advisable, but not mandatory, +to access the infix arguments inside the command's @code{interactive} form. +The preferred way of doing that is to call the @code{transient-args} +function, which for infix arguments serves about the same purpose as +@code{prefix-arg} serves for prefix arguments. + +@defun transient-args &optional prefix separate + +This function returns the value of the transient from which the +current suffix was called. If the current suffix command was not +called from a transient, then it returns @code{nil}. + +If optional PREFIX is non-@code{nil}, then it should be a symbol, a +transient prefix command. In that case the value of the transient +is only returned if the suffix was invoked from @strong{that} transient. +Otherwise @code{nil} is returned. This function is also used internally, +in which PREFIX can also be a @code{transient-prefix} object. + +If optional SEPARATE is non-@code{nil}, then the arguments are separated +into two groups. If SEPARATE is @code{t}, they are separated into atoms +and conses (@code{nil} isn't a valid value, so it doesn't matter that that +is both an atom and a cons). + +SEPARATE can also be a predicate function, in which case the first +element is a list of the values for which it returns non-@code{nil} and the +second element is a list of the values for which it returns @code{nil}. + +For transients that are used to pass arguments to a subprocess (such +as @code{git}), @code{stringp} is a useful value for SEPARATE, it separates +non-positional arguments from positional arguments. The value of +Magit's file argument (@code{"--"}) for example looks like this: @code{("--" + file...)}." +@end defun + +@defvar current-transient-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 @code{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. +@end defvar + +@defvar current-transient-prefix + +The transient from which this suffix command was invoked. The +returned value is a @code{transient-prefix} object, which holds information +associated with the transient prefix command. +@end defvar + +@defvar current-transient-command + +The transient from which this suffix command was invoked. The +returned value is a symbol, the transient prefix command. +@end defvar + +@node Transient State +@section 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: + +@itemize +@item +Invoking an infix command does not affect the transient state; the +transient remains active. + + +@item +Invoking a (non-infix) suffix command "deactivates" the transient +state by removing the transient keymap and performing some +additional cleanup. + + +@item +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. +@end itemize + +But these are just the defaults. Whether a certain command +deactivates or "exits" the transient is configurable. There is more +than one way in which a command can be "transient" or "non-transient"; +the exact behavior is implemented by calling a so-called "pre-command" +function. Whether non-suffix commands are allowed to be called is +configurable per transient. + +@itemize +@item +The transient-ness of suffix commands (including infix commands) is +controlled by the value of their @code{transient} slot, which can be set +either when defining the command or when adding a binding to a +transient while defining the respective transient prefix command. + +Valid values are booleans and the pre-commands described below. + +@itemize +@item +@code{t} is equivalent to @code{transient--do-stay}. + +@item +@code{nil} is equivalent to @code{transient--do-exit}. + +@item +If @code{transient} is unbound (and that is actually the default for +non-infix suffixes) then the value of the prefix's +@code{transient-suffix} slot is used instead. The default value of that +slot is @code{nil}, so the suffix's @code{transient} slot being unbound is +essentially equivalent to it being @code{nil}. +@end itemize + + +@item +A suffix command can be a prefix command itself, i.e. a +"sub-prefix". While a sub-prefix is active we nearly always want +@code{C-g} to take the user back to the "super-prefix". However in rare +cases this may not be desirable, and that makes the following +complication necessary: + +For @code{transient-suffix} objects the @code{transient} slot is unbound. We can +ignore that for the most part because, as stated above, @code{nil} and the +slot being unbound are equivalent, and means "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 @code{nil} means "do exit permanently", which requires that +slot to be explicitly set to that value. + + +@item +The transient-ness of certain built-in suffix commands is specified +using @code{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 @code{transient} slot. +@end itemize + +The available pre-command functions are documented below. They are +called by @code{transient--pre-command}, a function on @code{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 @code{transient--exit} or +@code{transient--stay} is used (that way we don't have to remember if @code{t} means +"exit" or "stay"). + +Additionally these functions may change the value of @code{this-command} +(which explains why they have to be called using @code{pre-command-hook}), +call @code{transient-export}, @code{transient--stack-zap} or @code{transient--stack-push}; +and set the values of @code{transient--exitp}, @code{transient--helpp} or +@code{transient--editp}. + +@subsection Pre-commands for Infixes + +The default for infixes is @code{transient--do-stay}. This is also the only +function that makes sense for infixes. + +@defun transient--do-stay + +Call the command without exporting variables and stay transient. +@end defun + +@subsection Pre-commands for Suffixes + +The default for suffixes is @code{transient--do-exit}. + +@defun transient--do-exit + +Call the command after exporting variables and exit the transient. +@end defun + +@defun transient--do-call + +Call the command after exporting variables and stay transient. +@end defun + +@defun transient--do-replace + +Call the transient prefix command, replacing the active transient. + +This is used for suffix that are prefixes themselves, i.e. for +sub-prefixes. +@end defun + +@subsection Pre-commands for Non-Suffixes + +The default for non-suffixes, i.e commands that are bound in other +keymaps beside the transient keymap, is @code{transient--do-warn}. Silently +ignoring the user-error is also an option, though probably not a good +one. + +If you want to let the user invoke non-suffix commands, then use +@code{transient--do-stay} as the value of the prefix's @code{transient-non-suffix} +slot. + +@defun transient--do-warn + +Call @code{transient-undefined} and stay transient. +@end defun + +@defun transient--do-noop + +Call @code{transient-noop} and stay transient. +@end defun + +@subsection Special Pre-Commands + +@defun transient--do-quit-one + +If active, quit help or edit mode, else exit the active transient. + +This is used when the user pressed @code{C-g}. +@end defun + +@defun transient--do-quit-all + +Exit all transients without saving the transient stack. + +This is used when the user pressed @code{C-q}. +@end defun + +@defun transient--do-suspend + +Suspend the active transient, saving the transient stack. + +This is used when the user pressed @code{C-z}. +@end defun + +@node Classes and Methods +@chapter 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 +@strong{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. + +@itemize +@item +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. + + +@item +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 @code{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. +@end itemize + +@menu +* Group Classes:: +* Group Methods:: +* Prefix Classes:: +* Suffix Classes:: +* Suffix Methods:: +* Prefix Slots:: +* Suffix Slots:: +* Predicate Slots:: +@end menu + +@node Group Classes +@section Group Classes + +The type of a group can be specified using the @code{:class} property at the +beginning of the class specification, e.g. @code{[:class transient-columns +...]} in a call to @code{define-transient-command}. + +@itemize +@item +The abstract @code{transient-child} class is the base class of both +@code{transient-group} (and therefore all groups) as well as of +@code{transient-suffix} (and therefore all suffix and infix commands). + +This class exists because the elements (aka "children") of certain +groups can be other groups instead of suffix and infix commands. + + +@item +The abstract @code{transient-group} class is the superclass of all other +group classes. + + +@item +The @code{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. + + +@item +The @code{transient-row} class displays all elements on a single line. + + +@item +The @code{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. + + +@item +The @code{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. +@end itemize + +@node Group Methods +@section Group Methods + +@defun 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 echo area. + +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 +temporally make the @code{transient--source-buffer} the current buffer. +@end defun + +@node Prefix Classes +@section Prefix Classes + +Currently the @code{transient-prefix} class is being used for all prefix +command and there is only a single generic functions that can be +specialized based on the class of a prefix command. + +@defun transient--history-init obj + +This generic function is called while setting up the transient and +is responsible for initializing the @code{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 @code{transient-history}. +@end defun + +A transient prefix command's object is stored in the @code{transient--prefix} +property of the command symbol. While a transient is active, a clone +of that object is stored in the variable @code{transient--prefix}. A clone +is used because some changes that are made to the active transient's +object should not affect later invocations. + +@node Suffix Classes +@section Suffix Classes + +@itemize +@item +All suffix and infix classes derive from @code{transient-suffix}, which in +turn derives from @code{transient-child}, from which @code{transient-group} also +derives (see @ref{Group Classes}). + + +@item +All infix classes derived from the abstract @code{transient-infix} class, +which in turn derives from the @code{transient-suffix} class. + +Infixes are a special type of suffixes. The primary difference is +that infixes always use the @code{transient--do-stay} pre-command, while +non-infix suffixes use a variety of pre-commands (see @ref{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 @ref{Defining Suffix and Infix Commands}). + + +@item +Classes used for infix commands that represent arguments should +derived from the abstract @code{transient-argument} class. + + +@item +The @code{transient-switch} class (or a derived class) is used for infix +arguments that represent command-line switches (arguments that do +not take a value). + + +@item +The @code{transient-option} class (or a derived class) is used for infix +arguments that represent command-line options (arguments that do +not take a value). + + +@item +The @code{transient-switches} class can be used for a set of mutually +exclusive command-line switches. + + +@item +The @code{transient-files} class can be used for a "--" argument that +indicates that all remaining arguments are files. + + +@item +Classes used for infix commands that represent variables should +derived from the abstract @code{transient-variables} class. +@end itemize + +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. + +@node Suffix Methods +@section Suffix Methods + +To get information about the methods implementing these generic +functions use @code{describe-function}. + +@menu +* Suffix Value Methods:: +* Suffix Format Methods:: +@end menu + +@node Suffix Value Methods +@subsection Suffix Value Methods + +@defun 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 @code{transient-infix}, so if +your class derives from that directly, then you must implement +a method. +@end defun + +@defun transient-infix-read obj + +This generic function determines the new value of the infix object +OBJ@. + +This function merely determines the value; @code{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 @code{reader} slot (using the +@code{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. +@end defun + +@defun transient-prompt obj + +This generic function returns the prompt to be used to read infix +object OBJ's value. +@end defun + +@defun transient-infix-set obj value + +This generic function sets the value of infix object OBJ to value. +@end defun + +@defun transient-infix-value obj + +This generic function returns the value of the suffix object OBJ@. + +This function is called by @code{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. +@code{nil} is not a value, it means "no value". + +Usually only infixes have a value, but see the method for +@code{transient-suffix}. +@end defun + +@defun 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 @code{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. +@end defun + +@node Suffix Format Methods +@subsection Suffix Format Methods + +@defun 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 @code{transient--source-buffer} current. +@end defun + +@defun transient-format-key obj + +This generic function formats OBJ's @code{key} for display and returns the +result. +@end defun + +@defun transient-format-description obj + +This generic function formats OBJ's @code{description} for display and +returns the result. +@end defun + +@defun transient-format-value obj + +This generic function formats OBJ's value for display and returns +the result. +@end defun + +@defun 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 +@code{info-manual} slot. Otherwise show the manpage if that is specified +using the @code{man-page} slot. Otherwise show the command's doc-string. + +For suffixes show the command's doc-string. + +For infixes show the manpage if that is specified. Otherwise show +the command's doc-string. +@end defun + +@node Prefix Slots +@section @strong{TODO} Prefix Slots + +@node Suffix Slots +@section 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 @ref{Predicate Slots}. + +Also see @ref{Suffix Classes}. + +@subsection Slots of @code{transient-suffix} + +@itemize +@item +@code{key} The key, a key vector or a key description string. + + +@item +@code{command} The command, a symbol. + + +@item +@code{transient} Whether to stay transient. See @ref{Transient State}. + + +@item +@code{format} The format used to display the suffix in the echo area. Must +contain the following %-placeholders: + +@itemize +@item +@code{%k} For the key. + +@item +@code{%d} For the description. + +@item +@code{%v} For the value. Non-infix suffixes don't have a value. +@end itemize + + +@item +@code{description} The description, either a string or a function that is +called with no argument and returns a string. +@end itemize + +@subsection Slots of @code{transient-infix} + +Some of these slots are only meaningful for some of the subclasses. +They are defined here anyway to allow sharing certain methods. + +@itemize +@item +@code{argument} The long argument, e.g. @code{--verbose}. + + +@item +@code{shortarg} The short argument, e.g. @code{-v}. + + +@item +@code{multi-value} For options, whether the option can have multiple +values. If non-nil, then default to use @code{completing-read-multiple}. + + +@item +@code{allow-empty} For options, whether the empty string is a valid value. + + +@item +@code{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. + + +@item +@code{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. + + +@item +@code{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. + + +@item +@code{choices} A list of valid values. How exactly that is used depends on +the class of the object. +@end itemize + +@subsection Slots of @code{transient-variable} + +@itemize +@item +@code{variable} The variable. +@end itemize + +@subsection Slots of @code{transient-switches} + +@itemize +@item +@code{argument-format} The display format. Must contain @code{%s}, one of the +@code{choices} is substituted for that. E.g. @code{--%s-order}. + + +@item +@code{argument-regexp} The regexp used to match any one of the switches. +E.g. @code{\\(--\\(topo\\|author-date\\|date\\)-order\\)}. +@end itemize + +@node Predicate Slots +@section 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. + +@itemize +@item +@code{if} Enable if predicate returns non-nil. + +@item +@code{if-not} Enable if predicate returns nil. + +@item +@code{if-non-nil} Enable if variable's value is non-nil. + +@item +@code{if-nil} Enable if variable's value is nil. + +@item +@code{if-mode} Enable if major-mode matches value. + +@item +@code{if-not-mode} Enable if major-mode does not match value. + +@item +@code{if-derived} Enable if major-mode derives from value. + +@item +@code{if-not-derived} Enable if major-mode does not derive from value. +@end itemize + +One more slot is shared between group and suffix classes, @code{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. @code{level} controls whether it should be available depending on +whether the user wants that or not. See @ref{Enabling and Disabling Suffixes}. + +@node Related Abstractions and Packages +@chapter Related Abstractions and Packages + +@menu +* Comparison With Prefix Keys and Prefix Arguments:: +* Comparison With Other Packages:: +@end menu + +@node Comparison With Prefix Keys and Prefix Arguments +@section Comparison With Prefix Keys and Prefix Arguments + +While transient commands were inspired by regular prefix keys and +prefix arguments, they are also quite different and much more complex. + +The following diagrams illustrate some of the differences. + +@itemize +@item +@code{(c)} represents a return to the command loop. + +@item +@code{(+)} represents the user's choice to press one key or another. + +@item +@code{@{WORD@}} are possible behaviors. + +@item +@code{@{NUMBER@}} is a footnote. +@end itemize + +@subsection Regular Prefix Commands + +See @ref{Prefix Keys,,,elisp,}. + +@example + ,--> command1 --> (c) + | +(c)-(+)-> prefix command or key --+--> command2 --> (c) + | + `--> command3 --> (c) +@end example + +@subsection Regular Prefix Arguments + +See @ref{Prefix Command Arguments,,,elisp,}. + +@example + ,----------------------------------, + | | + v | +(c)-(+)---> prefix argument command --(c)-(+)-> any command --> (c) + | ^ | + | | | + `-- sets or changes --, ,-- maybe used --' | + | | | + v | | + prefix argument state | + ^ | + | | + `-------- discards --------' +@end example + +@subsection Transients + +(∩`-´)⊃━☆゚.*・。゚ + +This diagram ignores the infix value and external state: + +@example +(c) + | ,- @{stay@} ------<-,-<------------<-,-<---, +(+) | | | | + | | | | | + | | ,--> infix1 --| | | + | | | | | | + | | |--> infix2 --| | | + v v | | | | + prefix -(c)-(+)-> infix3 --' ^ | + | | | + |---------------> suffix1 -->--| | + | | | + |---------------> suffix2 ----@{1@}------> @{exit@} --> (c) + | | + |---------------> suffix3 -------------> @{exit@} --> (c) + | | + `--> any command --@{2@}-> @{warn@} -->--| + | | + |--> @{noop@} -->--| + | | + |--> @{call@} -->--' + | + `------------------> @{exit@} --> (c) +@end example + +This diagram takes the infix value into account to an extend, while +still ignoring external state: + +@example +(c) + | ,- @{stay@} ------<-,-<------------<-,-<---, +(+) | | | | + | | | | | + | | ,--> infix1 --| | | + | | | | | | | + | | ,--> infix2 --| | | + v v | | | | | + prefix -(c)-(+)-> infix3 --' | | + | | ^ | + | | | | + |---------------> suffix1 -->--| | + | | ^ | | + | | | | | + |---------------> suffix2 ----@{1@}------> @{exit@} --> (c) + | | ^ | | + | | | | v + | | | | | + |---------------> suffix3 -------------> @{exit@} --> (c) + | | ^ | | + | sets | | v + | | maybe | | + | | used | | + | | | | | + | | infix --' | | + | `---> value | | + | ^ | | + | | | | + | hides | | + | | | | + | `--------------------------<---| + | | | + `--> any command --@{2@}-> @{warn@} -->--| | + | | | + |--> @{noop@} -->--| | + | | | + |--> @{call@} -->--' ^ + | | + `------------------> @{exit@} --> (c) +@end example + +This diagram provides more information about the infix value +and also takes external state into account. + +@example + ,----sets--- "anything" + | + v + ,---------> external + | state + | | | + | initialized | ☉‿⚆ + sets from | + | | maybe + | ,----------' used + | | | +(c) | | v + | ,- @{stay@} --|---<-,-<------|-----<-,-<---, +(+) | | | | | | | + | | | v | | | | + | | ,--> infix1 --| | | | + | | | | | | | | | + | | | | v | | | | + | | ,--> infix2 --| | | | + | | | | ^ | | | | + v v | | | | | | | + prefix -(c)-(+)-> infix3 --' | | | + | | ^ | ^ | + | | | v | | + |---------------> suffix1 -->--| | + | | | ^ | | | + | | | | v | | + |---------------> suffix2 ----@{1@}------> @{exit@} --> (c) + | | | ^ | | | + | | | | | | v + | | | | v | | + |---------------> suffix3 -------------> @{exit@} --> (c) + | | | ^ | | + | sets | | | v + | | initalized maybe | | + | | from used | | + | | | | | | + | | `-- infix --' | | + | `---> value -----------------------------> persistent + | ^ ^ | | across + | | | | | invocations -, + | hides | | | | + | | `----------------------------------------------' + | | | | + | `--------------------------<---| + | | | + `--> any command --@{2@}-> @{warn@} -->--| | + | | | + |--> @{noop@} -->--| | + | | | + |--> @{call@} -->--' ^ + | | + `------------------> @{exit@} --> (c) +@end example + +@itemize +@item +@code{@{1@}} Transients can be configured to be exited when a suffix command +is invoked. The default is to do so for all suffixes expect for +those that are common to all transients and which are used to +perform tasks such as providing help and saving the value of the +infix arguments for future invocations. The behavior can also be +specified for individual suffix commands individually and may even +depend on state. + + +@item +@code{@{2@}} Transients can be configured to allow the user to invoke +non-suffix commands. The default is to not allow that and instead +warn the user. +@end itemize + +Despite already being rather complex, even the last diagram leaves out +many details. Most importantly it implies that the decision whether +to remain transient is made later than it actually is made (for the +most part a function on @code{pre-command-hook} is responsible). But such +implementation details are of little relevance to users and are +covered elsewhere. + +@node Comparison With Other Packages +@section Comparison With Other Packages + +@subsection Magit-Popup + +Transient is the successor to Magit-Popup (see @ref{Top,,,magit-popup,}). + +One major difference between these two implementations of the same +ideas is that while Transient uses transient keymaps and embraces the +command-loop, Magit-Popup implemented an inferior mechanism that does +not use transient keymaps and that instead of using the command-loop +implements a naive alternative based on @code{read-char}. + +Magit-Popup does not use classes and generic functions and defining a +new command type is near impossible as it involves adding hard-coded +special-cases to many functions. Because of that only a single new +type was added, which was not already part of Magit-Popup's initial +release. + +A lot of things are hard-coded in Magit-Popup. One random example is +that the key bindings for switches must begin with "-" and those for +options must begin with "=". + +@subsection Hydra + +Hydra (see @uref{https://github.com/abo-abo/hydra}) is another package that +provides features similar to those of Transient. + +Both packages use transient keymaps to make a set of commands +temporarily available and the @code{lv} library to show these commands in the +echo area. (The author of Hydra is also the author of @code{lv}, which is +maintained in the same repository.) + +A Hydra "body" is equivalent to a Transient "prefix" and a Hydra +"head" is equivalent to a Transient "suffix". Hydra has no equivalent +of a Transient "infix". + +Both hydras and transients can be used as simple command dispatchers. +Used like this they are similar to regular prefix commands and prefix +keys, except that the available commands are shown in the echo area. + +(Another package that does this is @code{which-key}. It does so automatically +for any incomplete key sequence. The advantage of that approach is +that no additional work is necessary; the disadvantage is that the +available commands are not organized semantically.) + +Both Hydra and Transient provide features that go beyond simple +command dispatchers: + +@itemize +@item +Invoking a command from a hydra does not necessarily exit the hydra. +That makes it possible to invoke the same command again, but using a +shorter key sequence (i.e. the key that was used to enter the hydra +does not have to be pressed again). + +Transient supports that too, but for not this feature is not a focus +and the interface is a bit more complicated. A very basic example +using the current interface: + +@lisp +(define-transient-command outline-navigate () + :transient-suffix 'transient--do-stay + :transient-non-suffix 'transient--do-warn + [("p" "next visible heading" outline-previous-visible-heading) + ("n" "next visible heading" outline-next-visible-heading)]) +@end lisp + + +@item +Transient support infix arguments; values that are set by infix +commands and then consumed by the invoked suffix command(s). + +To my knowledge, Hydra does not support that. +@end itemize + +Both packages make it possible to specify how exactly the available +commands are outlined: + +@itemize +@item +With Hydra this is often done using an explicit format string, which +gives authors a lot of flexibility and makes it possible to do fancy +things. + +The downside of this is that it becomes harder for a user to add +additional commands to an existing hydra and to change key bindings. + + +@item +Transient allows the author of a transient to organize the commands +into groups and the use of generic functions allows authors of +transients to control exactly how a certain command type is +displayed. + +However while Transient support giving sections a heading it does +not currently support giving the displayed information more +structure by, for example, using box-drawing characters. + +That could be implemented by defining a new group class, which lets +the author specify a format string. It should be possible to +implement that without modifying any existing code, but it does not +currently exist. +@end itemize + +@node Keystroke Index +@appendix Keystroke Index + +@printindex ky + +@node Command Index +@appendix Command Index + +@printindex cp + +@node Function Index +@appendix Function Index + +@printindex fn + +@node Variable Index +@appendix Variable Index + +@printindex vr + +@bye |
