Next: , Previous: , Up: Defining New Commands [Contents][Index]


4.3 Binding Suffix and Infix Commands

The macro transient-define-prefix is used to define a transient. This defines the actual transient prefix command (see 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 transient-define-prefix.

4.3.1 Group Specifications

The suffix and infix commands of a transient are organized in groups. The grouping controls how the descriptions of the suffixes are outlined visually but also makes it possible to set certain properties for a set of suffixes.

Several group classes exist, some of which organize suffixes in subgroups. In most cases the class does not have to be specified explicitly, but see Group Classes.

Groups are specified in the call to transient-define-prefix, using vectors. Because groups are represented using vectors, we cannot use square brackets to indicate an optional element and instead use curly brackets to do the latter.

Group specifications then have this form:

[{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...]

The LEVEL is optional and defaults to 4. See 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... and :inapt-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.

  • The value of :hide, if non-nil, is a predicate that controls whether the group is hidden by default. The key bindings for suffixes of a hidden group should all use the same prefix key. Pressing that prefix key should temporarily show the group and its suffixes, which assumes that a predicate like this is used:
    (lambda ()
     (eq (car transient--redisplay-key)
     ?\C-c)) ; the prefix key shared by all bindings
    
  • The value of :setup-children, if non-nil, is a function that takes one argument, a potentially list of children, and must return a list of children or an empty list. This can either be used to somehow transform the group’s children that were defined the normal way, or to dynamically create the children from scratch.

    The returned children must have the same form as stored in the prefix’s transient--layout property, but it is often more convenient to use the same form as understood by transient-define-prefix, described below. If you use the latter approach, you can use the transient-parse-suffixes and transient-parse-suffix functions to transform them from the convenient to the expected form. Depending on the used group class, transient-parse-suffixes’s SUFFIXES must be a list of group vectors (for transient-columns) or a list of suffix lists (for all other group classes).

    If you explicitly specify children and then transform them using :setup-children, then the class of the group is determined as usual, based on explicitly specified children.

    If you do not explicitly specify children and thus rely solely on :setup-children, then you must specify the class using :class. For backward compatibility, if you fail to do so, transient-column is used and a warning is displayed. This warning will eventually be replaced with an error.

    (transient-define-prefix my-finder-by-keyword ()
     "Select a keyword and list matching packages."
     ;; The real `finder-by-keyword' is more convenient
     ;; of course, but that is not the point here.
     [:class transient-columns
     :setup-children
     (lambda (_)
     (transient-parse-suffixes
     'my-finder-by-keyword
     (let ((char (1- ?A)))
     (mapcar ; a list ...
     (lambda (partition)
     (vconcat ; of group vectors ...
     (mapcar (lambda (elt)
     (let ((keyword (symbol-name (car elt))))
     ; ... where each suffix is a list
     (list (format "%c" (cl-incf char))
     keyword
     (lambda ()
     (interactive)
     (finder-list-matches keyword)))))
     partition)))
     (seq-partition finder-known-keywords 7)))))])
    
  • The boolean :pad-keys argument controls whether keys of all suffixes contained in a group are right padded, effectively aligning the descriptions.
  • If a keyword argument accepts a function as value, you an use a lambda expression. As a special case, the ## macro (which returns a lambda expression and is implemented in the llama package) is also supported. Inside group specifications, the use of ## is not supported anywhere but directly following a keyword symbol.

The ELEMENTs are either all subgroups, or all suffixes and strings. (At least currently no group type exists that would allow mixing subgroups with commands at the same level, though in principle there is nothing that prevents that.)

If the ELEMENTs are not subgroups, then they can be a mixture of lists, which specify commands, and strings. Strings are inserted verbatim into the buffer. The empty string can be used to insert gaps between suffixes, which is particularly useful if the suffixes are outlined as a table.

Inside group specifications, including inside contained suffix specifications, nothing has to be quoted and quoting anyway is invalid. The value following a keyword, can be explicitly unquoted using ,. This feature is experimental and should be avoided.

The form of suffix specifications is documented in the next node.

4.3.2 Suffix Specifications

A transient’s suffix and infix commands are bound when the transient prefix command is defined using transient-define-prefix, see 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.

Note that an infix is a special kind of suffix. Depending on context “suffixes” means “suffixes (including infixes)” or “non-infix suffixes”. Here it means the former.

Suffix specifications have this form:

([LEVEL] [KEY [DESCRIPTION]] COMMAND|ARGUMENT [KEYWORD VALUE]...)

LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs :level, :key and :description. If the object that is associated with COMMAND sets these properties, then they do not have to be specified here. You can however specify them here anyway, possibly overriding the object’s values just for the binding inside this transient.

  • LEVEL is the suffix level, an integer between 1 and 7. See Enabling and Disabling Suffixes.
  • KEY is the key binding, a string in the format returned by describe-key and understood by kbd.

    That format is more permissive than the one accepted by key-valid-p. Being more permissive makes it possible, for example, to write the key binding, which toggles the -a command line argument, as "-a", instead of having to write "- a". Likewise additional spaces can be added, which is not removed when displaying the binding in the menu, which is useful for alignment purposes.

  • DESCRIPTION is the description, either a string or a function that takes zero or one arguments (the suffix object) and returns a string. The function should be a lambda expression to avoid ambiguity. In some cases a symbol that is bound as a function would also work but to be safe you should use :description in that case.

The next element is either a command or an argument. This is the only argument that is mandatory in all cases.

  • COMMAND should be a symbol that is bound as a function, which has to be defined or at least autoloaded as a command by the time the containing prefix command is invoked.

    Any command will do; it does not need to have an object associated with it (as would be the case if transient-define-suffix or transient-define-infix were used to define it).

    COMMAND can also be a lambda expression.

    As mentioned above, the object that is associated with a command can be used to set the default for certain values that otherwise have to be set in the suffix specification. Therefore if there is no object, then you have to make sure to specify the KEY and the DESCRIPTION.

    As a special case, if you want to add a command that might be neither defined nor autoloaded, you can use a workaround like:

    (transient-insert-suffix 'some-prefix "k"
     '("!" "Ceci n'est pas une commande" no-command
     :if (lambda () (featurep 'no-library))))
    

    Instead of featurep you could also use require with a non-nil value for NOERROR.

  • The mandatory argument can also be a command-line argument, a string. In that case an anonymous command is defined and bound.

    Instead of a string, this can also be a list of two strings, in which case the first string is used as the short argument (which can also be specified using :shortarg) and the second as the long argument (which can also be specified using :argument).

    Only the long argument is displayed in the menu buffer. See transient-detect-key-conflicts for how the short argument may be used.

    Unless the class is specified explicitly, the appropriate class is guessed based on the long argument. If the argument ends with ‘=’ (e.g., ‘--format=’) then transient-option is used, otherwise transient-switch.

Finally, details can be specified using optional KEYWORD-VALUE pairs. Each keyword has to be a keyword symbol, either :class or a keyword argument supported by the constructor of that class. See Suffix Slots.

If a keyword argument accepts a function as value, you an use a lambda expression. As a special case, the ## macro (which returns a lambda expression and is implemented in the llama package) is also supported. Inside suffix bindings, the use of ## is not supported anywhere but directly following a keyword symbol.


Next: Defining Suffix and Infix Commands, Previous: Defining Transients, Up: Defining New Commands [Contents][Index]

AltStyle によって変換されたページ (->オリジナル) /