Skip to content

Comparison with prefix keys and universal arguments

Jonas Bernoulli edited this page Nov 24, 2023 · 2 revisions

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.

Sadly GitHub corrupts the below ascii diagrams. Please let me know if you find a way to work around that.

Regular Prefix Commands

Documented in the Elisp manual in Prefix-Keys.

                                  ,--> command1 --> (c)
                                  |
(c)-(+)-> prefix command or key --+--> command2 --> (c)
                                  |
                                  `--> command3 --> (c)

Regular Prefix Arguments

Documented in the Elisp manual in Prefix Command Arguments.

        ,----------------------------------,
        |                                  |
        v                                  |
(c)-(+)---> prefix argument command --(c)-(+)-> any command --> (c)
               |                                        ^        |
               |                                        |        |
               `-- sets or changes --, ,-- maybe used --'        |
                                     | |                         |
                                     v |                         |
                          prefix argument state                  |
                                      ^                          |
                                      |                          |
                                      `-------- discards --------'

Transients

This diagram ignores the infix value and external state:

(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)

This diagram takes the infix value into account to an extend, while still ignoring external state:

(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)

This diagram provides more information about the infix value and also takes external state into account.

                                       ,----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
              |    | initialized  maybe            |     |
              |    | from         used             |     |
              |    | |            |                |     |
              |    | `-- infix ---'                |     |
              |    `---> value -----------------------------> persistent
              |           ^ ^                      |     |    across
              |           | |                      |     |    invocations -,
              |       hides |                      |     |                 |
              |           | `----------------------------------------------'
              |           |                        |     |
              |           `--------------------------<---|
              |                                    |     |
              `--> any command --{2}-> {warn} -->--|     |
                                  |                |     |
                                  |--> {noop} -->--|     |
                                  |                |     |
                                  |--> {call} -->--'     ^
                                  |                      |
                                  `------------------> {exit} --> (c)
  • {1} Transients can be configured to be exited when a suffix command is invoked. The default is to do so for all suffixes except 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 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.