1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-05 22:20:24 -08:00

Update to Transient v0.11.0-10-g6637364e

This commit is contained in:
Jonas Bernoulli 2025-11-18 17:55:10 +01:00
parent ce5d8ddb32
commit 6415fc5e04
No known key found for this signature in database
GPG key ID: 230C2EFBB326D927
2 changed files with 227 additions and 246 deletions

View file

@ -25,13 +25,13 @@ General Public License for more details.
@dircategory Emacs misc features @dircategory Emacs misc features
@direntry @direntry
* Transient: (transient). Transient Commands. * Transient: (transient). Transient Commands.
@end direntry @end direntry
@finalout @finalout
@titlepage @titlepage
@title Transient User and Developer Manual @title Transient User and Developer Manual
@subtitle for version 0.10.1 @subtitle for version 0.11.0
@author Jonas Bernoulli @author Jonas Bernoulli
@page @page
@vskip 0pt plus 1filll @vskip 0pt plus 1filll
@ -53,7 +53,7 @@ resource to get over that hurdle is Psionic K's interactive tutorial,
available at @uref{https://github.com/positron-solutions/transient-showcase}. available at @uref{https://github.com/positron-solutions/transient-showcase}.
@noindent @noindent
This manual is for Transient version 0.10.1. This manual is for Transient version 0.11.0.
@insertcopying @insertcopying
@end ifnottex @end ifnottex
@ -385,7 +385,7 @@ than outlined above and even customizable.}
If the user does not save the value and just exits using a regular 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 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, history. That value won't be used when the transient is next invoked,
but it is easily accessible (@pxref{Using History}). but it is easily accessible (see @ref{Using History}).
Option @code{transient-common-command-prefix} controls the prefix key used Option @code{transient-common-command-prefix} controls the prefix key used
in the following bindings. For simplicity's sake the default, @kbd{C-x}, in the following bindings. For simplicity's sake the default, @kbd{C-x},
@ -454,8 +454,8 @@ previously used values. Usually the same keys as those mentioned
above are bound to those commands. above are bound to those commands.
Authors of transients should arrange for different infix commands that Authors of transients should arrange for different infix commands that
read the same kind of value to also use the same history key read the same kind of value to also use the same history key (see
(@pxref{Suffix Slots}). @ref{Suffix Slots}).
Both kinds of history are saved to a file when Emacs is exited. Both kinds of history are saved to a file when Emacs is exited.
@ -785,7 +785,7 @@ menu buffer. The menu buffer is displayed in a window using
The value of this option has the form @code{(@var{FUNCTION} . @var{ALIST})}, The value of this option has the form @code{(@var{FUNCTION} . @var{ALIST})},
where @var{FUNCTION} is a function or a list of functions. Each such where @var{FUNCTION} is a function or a list of functions. Each such
function should accept two arguments: a buffer to display and an function should accept two arguments: a buffer to display and an
alist of the same form as @var{ALIST}. @xref{Choosing Window,,,elisp,}, alist of the same form as @var{ALIST}. See @ref{Choosing Window,,,elisp,},
for details. for details.
The default is: The default is:
@ -799,7 +799,7 @@ The default is:
This displays the window at the bottom of the selected frame. This displays the window at the bottom of the selected frame.
For alternatives see @ref{Buffer Display Action Functions,,,elisp,}, For alternatives see @ref{Buffer Display Action Functions,,,elisp,},
and @xref{Buffer Display Action Alists,,,elisp,}. and @ref{Buffer Display Action Alists,,,elisp,}.
When you switch to a different ACTION, you should keep the ALIST When you switch to a different ACTION, you should keep the ALIST
entries for @code{dedicated} and @code{inhibit-same-window} in most cases. entries for @code{dedicated} and @code{inhibit-same-window} in most cases.
@ -861,7 +861,7 @@ used to draw the line.
This user option may be overridden if @code{:mode-line-format} is passed This user option may be overridden if @code{:mode-line-format} is passed
when creating a new prefix with @code{transient-define-prefix}. when creating a new prefix with @code{transient-define-prefix}.
Otherwise this can be any mode-line format. @xref{Mode Line Format,,,elisp,}, for details. Otherwise this can be any mode-line format. See @ref{Mode Line Format,,,elisp,}, for details.
@end defopt @end defopt
@defopt transient-semantic-coloring @defopt transient-semantic-coloring
@ -879,6 +879,9 @@ This option controls whether key bindings of infix commands that do
not match the respective command-line argument should be highlighted. not match the respective command-line argument should be highlighted.
For other infix commands this option has no effect. For other infix commands this option has no effect.
This is mostly indended for autors of transient menus and disabled
by default.
When this option is non-@code{nil}, the key binding for an infix argument When this option is non-@code{nil}, the key binding for an infix argument
is highlighted when only a long argument (e.g., @code{--verbose}) is is 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 specified but no shorthand (e.g., @code{-v}). In the rare case that a
@ -1026,10 +1029,10 @@ which can be included in multiple prefixes. See TODO@.
as expected by @code{transient-define-prefix}. Note that an infix is a as expected by @code{transient-define-prefix}. Note that an infix is a
special kind of suffix. Depending on context ``suffixes'' means special kind of suffix. Depending on context ``suffixes'' means
``suffixes (including infixes)'' or ``non-infix suffixes''. Here it ``suffixes (including infixes)'' or ``non-infix suffixes''. Here it
means the former. @xref{Suffix Specifications}. means the former. See @ref{Suffix Specifications}.
@var{SUFFIX} may also be a group in the same form as expected by @var{SUFFIX} may also be a group in the same form as expected by
@code{transient-define-prefix}. @xref{Group Specifications}. @code{transient-define-prefix}. See @ref{Group Specifications}.
@item @item
@var{LOC} is a key description (a string as returned by @code{key-description} @var{LOC} is a key description (a string as returned by @code{key-description}
@ -1053,11 +1056,11 @@ the function @code{transient--get-layout}.
These functions operate on the information stored in the These functions operate on the information stored in the
@code{transient--layout} property of the @var{PREFIX} symbol. Elements in that @code{transient--layout} property of the @var{PREFIX} symbol. Elements in that
tree are not objects but have the form @code{(@var{CLASS} @var{PLIST}) for suffixes} and tree are not objects but have the form @code{(@var{CLASS} @var{PLIST}) for suffixes} and
[CLASS PLIST CHILDREN] for groups. At the root of the tree is an @code{[CLASS PLIST CHILDREN]} for groups. At the root of the tree is an
element [N nil CHILDREN], where N is the version of the layout format, element @code{[N Nil CHILDREN]}, where @code{N} is the version of the layout format,
currently and hopefully for a long time 2. While that element looks currently and hopefully for a long time 2. While that element looks
like a group vector, that element does not count when identifying a like a group vector, that element does not count when identifying a
group using a coordinate vector, i.e., [0] is its first child, not the group using a coordinate vector, i.e., @code{[0]} is its first child, not the
root element itself. root element itself.
@defun transient-insert-suffix prefix loc suffix &optional keep-other @defun transient-insert-suffix prefix loc suffix &optional keep-other
@ -1202,14 +1205,14 @@ enabled. One benefit of the Transient interface is that it remembers
history not only on a global level (``this command was invoked using history not only on a global level (``this command was invoked using
these arguments, and previously it was invoked using those other these arguments, and previously it was invoked using those other
arguments''), but also remembers the values of individual arguments arguments''), but also remembers the values of individual arguments
independently. @xref{Using History}. independently. See @ref{Using History}.
After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to
show the documentation for the infix or suffix command that @kbd{@var{KEY}} is show the documentation for the infix or suffix command that @kbd{@var{KEY}} is
bound to (see @ref{Getting Help for Suffix Commands}), and infixes and bound to (see @ref{Getting Help for Suffix Commands}), and infixes and
suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}. Infixes suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}. Infixes
and suffixes that are disabled by default can be enabled the same way. and suffixes that are disabled by default can be enabled the same way.
@xref{Enabling and Disabling Suffixes}. See @ref{Enabling and Disabling Suffixes}.
Transient ships with support for a few different types of specialized Transient ships with support for a few different types of specialized
infix commands. A command that sets a command line option, for example, infix commands. A command that sets a command line option, for example,
@ -1260,7 +1263,7 @@ explicitly.
@var{GROUP}s add key bindings for infix and suffix commands and specify @var{GROUP}s add key bindings for infix and suffix commands and specify
how these bindings are presented in the menu buffer. At least one how these bindings are presented in the menu buffer. At least one
@var{GROUP} has to be specified. @xref{Binding Suffix and Infix Commands}. @var{GROUP} has to be specified. See @ref{Binding Suffix and Infix Commands}.
The @var{BODY} is optional. If it is omitted, then @var{ARGLIST} is ignored and The @var{BODY} is optional. If it is omitted, then @var{ARGLIST} is ignored and
the function definition becomes: the function definition becomes:
@ -1311,13 +1314,11 @@ GROUPs have the same form as for @code{transient-define-prefix}.
@section Binding Suffix and Infix Commands @section Binding Suffix and Infix Commands
The macro @code{transient-define-prefix} is used to define a transient. The macro @code{transient-define-prefix} is used to define a transient.
This defines the actual transient prefix command (@pxref{Defining This defines the actual transient prefix command (see @ref{Defining Transients}) and adds the transient's infix and suffix bindings, as
Transients}) and adds the transient's infix and suffix bindings, as
described below. described below.
Users and third-party packages can add additional bindings using Users and third-party packages can add additional bindings using
functions such as @code{transient-insert-suffix} (@pxref{Modifying Existing Transients}). functions such as @code{transient-insert-suffix} (see @ref{Modifying Existing Transients}). These functions take a ``suffix specification'' as one of
These functions take a ``suffix specification'' as one of
their arguments, which has the same form as the specifications used in their arguments, which has the same form as the specifications used in
@code{transient-define-prefix}. @code{transient-define-prefix}.
@ -1343,13 +1344,10 @@ brackets to do the latter.
Group specifications then have this form: Group specifications then have this form:
@lisp @lisp
[@{@var{LEVEL}@} @{@var{DESCRIPTION}@} [@{LEVEL@} @{DESCRIPTION@} @{KEYWORD VALUE@}... ELEMENT...]
@{@var{KEYWORD} @var{VALUE}@}...
@var{ELEMENT}...]
@end lisp @end lisp
The @var{LEVEL} is optional and defaults to 4. @xref{Enabling and The @var{LEVEL} is optional and defaults to 4. See @ref{Enabling and Disabling Suffixes}.
Disabling Suffixes}.
The @var{DESCRIPTION} is optional. If present, it is used as the heading of The @var{DESCRIPTION} is optional. If present, it is used as the heading of
the group. the group.
@ -1500,9 +1498,7 @@ suffixes''. Here it means the former.
Suffix specifications have this form: Suffix specifications have this form:
@lisp @lisp
([@var{LEVEL}] ([LEVEL] [KEY [DESCRIPTION]] COMMAND|ARGUMENT [KEYWORD VALUE]...)
[@var{KEY} [@var{DESCRIPTION}]]
@var{COMMAND}|@var{ARGUMENT} [@var{KEYWORD} @var{VALUE}]...)
@end lisp @end lisp
@var{LEVEL}, @var{KEY} and @var{DESCRIPTION} can also be specified using the @var{KEYWORD}s @var{LEVEL}, @var{KEY} and @var{DESCRIPTION} can also be specified using the @var{KEYWORD}s
@ -1513,8 +1509,8 @@ the object's values just for the binding inside this transient.
@itemize @itemize
@item @item
@var{LEVEL} is the suffix level, an integer between 1 and 7. @var{LEVEL} is the suffix level, an integer between 1 and 7. See
@xref{Enabling and Disabling Suffixes}. @ref{Enabling and Disabling Suffixes}.
@item @item
KEY is the key binding, a string in the format returned by KEY is the key binding, a string in the format returned by
@ -1588,7 +1584,7 @@ guessed based on the long argument. If the argument ends with @samp{=}
Finally, details can be specified using optional @var{KEYWORD}-@var{VALUE} pairs. Finally, details can be specified using optional @var{KEYWORD}-@var{VALUE} pairs.
Each keyword has to be a keyword symbol, either @code{:class} or a keyword Each keyword has to be a keyword symbol, either @code{:class} or a keyword
argument supported by the constructor of that class. @xref{Suffix Slots}. argument supported by the constructor of that class. See @ref{Suffix Slots}.
If a keyword argument accepts a function as value, you an use a @code{lambda} If a keyword argument accepts a function as value, you an use a @code{lambda}
expression. As a special case, the @code{##} macro (which returns a @code{lambda} expression. As a special case, the @code{##} macro (which returns a @code{lambda}
@ -1742,16 +1738,16 @@ its value can be accessed using @code{transient-args}.
This function returns the scope of the active or current transient This function returns the scope of the active or current transient
prefix command. prefix command.
If optional PREFIXES and CLASSES are both nil, return the scope of If optional PREFIXES and CLASSES are both @code{nil}, return the scope of
the prefix currently being setup, making this variation useful, e.g., the prefix currently being setup, making this variation useful, e.g.,
in @code{:if*} predicates. If no prefix is being setup, but the current in @code{:if*} predicates. If no prefix is being setup, but the current
command was invoked from some prefix, then return the scope of that. command was invoked from some prefix, then return the scope of that.
If PREFIXES is non-nil, it must be a prefix command or a list of such If PREFIXES is non-@code{nil}, it must be a prefix command or a list of such
commands. If CLASSES is non-nil, it must be a prefix class or a list commands. If CLASSES is non-@code{nil}, it must be a prefix class or a list
of such classes. When this function is called from the body or the of such classes. When this function is called from the body or the
@code{interactive} form of a suffix command, PREFIXES and/or CLASSES should @code{interactive} form of a suffix command, PREFIXES and/or CLASSES should
be non-nil. If either is non-nil, try the following in order: be non-@code{nil}. If either is non-@code{nil}, try the following in order:
@itemize @itemize
@item @item
@ -1777,7 +1773,7 @@ PREFIXES@. This only works if that slot is set in the respective
class definition or using its `transient-init-scope' method. class definition or using its `transient-init-scope' method.
@end itemize @end itemize
If no prefix matches, return nil. If no prefix matches, return @code{nil}.
@end defun @end defun
@node Current Suffix Command @node Current Suffix Command
@ -1938,8 +1934,8 @@ means that all outer prefixes are exited at once.
@item @item
The behavior for non-suffixes can be set for a particular prefix, The behavior for non-suffixes can be set for a particular prefix,
by the prefix's @code{transient-non-suffix} slot to a boolean, a suitable by the prefix's @code{transient-non-suffix} slot to a boolean, a suitable
pre-command function, or a shorthand for such a function. pre-command function, or a shorthand for such a function. See
@xref{Pre-commands for Non-Suffixes}. @ref{Pre-commands for Non-Suffixes}.
@item @item
The common behavior for the suffixes of a particular prefix can be The common behavior for the suffixes of a particular prefix can be
@ -2279,7 +2275,7 @@ object should not affect later invocations.
@item @item
All suffix and infix classes derive from @code{transient-suffix}, which in All suffix and infix classes derive from @code{transient-suffix}, which in
turn derives from @code{transient-child}, from which @code{transient-group} also turn derives from @code{transient-child}, from which @code{transient-group} also
derives (@pxref{Group Classes}). derives (see @ref{Group Classes}).
@item @item
All infix classes derive from the abstract @code{transient-infix} class, All infix classes derive from the abstract @code{transient-infix} class,
@ -2293,7 +2289,7 @@ that does not do so. If you do that then you get to implement many
methods. methods.
Also, infixes and non-infix suffixes are usually defined using Also, infixes and non-infix suffixes are usually defined using
different macros (@pxref{Defining Suffix and Infix Commands}). different macros (see @ref{Defining Suffix and Infix Commands}).
@item @item
Classes used for infix commands that represent arguments should Classes used for infix commands that represent arguments should
@ -2703,7 +2699,7 @@ secondary value, called a ``scope''. See @code{transient-define-prefix}.
@code{transient-suffix}, @code{transient-non-suffix} and @code{transient-switch-frame} @code{transient-suffix}, @code{transient-non-suffix} and @code{transient-switch-frame}
play a part when determining whether the currently active transient play a part when determining whether the currently active transient
prefix command remains active/transient when a suffix or arbitrary prefix command remains active/transient when a suffix or arbitrary
non-suffix command is invoked. @xref{Transient State}. non-suffix command is invoked. See @ref{Transient State}.
@item @item
@code{refresh-suffixes} Normally suffix objects and keymaps are only setup @code{refresh-suffixes} Normally suffix objects and keymaps are only setup
@ -2785,7 +2781,7 @@ of the same symbol.
@item @item
@code{level} The level of the prefix commands. The suffix commands whose @code{level} The level of the prefix commands. The suffix commands whose
layer is equal or lower are displayed. @pxref{Enabling and Disabling Suffixes}. layer is equal or lower are displayed. See @ref{Enabling and Disabling Suffixes}.
@item @item
@code{value} The likely outdated value of the prefix. Instead of accessing @code{value} The likely outdated value of the prefix. Instead of accessing
@ -2843,7 +2839,7 @@ which is useful for alignment purposes.
@code{command} The command, a symbol. @code{command} The command, a symbol.
@item @item
@code{transient} Whether to stay transient. @xref{Transient State}. @code{transient} Whether to stay transient. See @ref{Transient State}.
@item @item
@code{format} The format used to display the suffix in the menu buffer. @code{format} The format used to display the suffix in the menu buffer.
@ -2886,7 +2882,7 @@ defining a command using @code{transient-define-suffix}.
The following two slots are experimental. They can also be set for a The following two slots are experimental. They can also be set for a
group, in which case they apply to all suffixes in that group, except group, in which case they apply to all suffixes in that group, except
for suffixes that set the same slot to a non-nil value. for suffixes that set the same slot to a non-@code{nil} value.
@itemize @itemize
@item @item
@ -2897,7 +2893,7 @@ advice.
@item @item
@code{advice*} A function used to advise the command. Unlike @code{advice}, this @code{advice*} A function used to advise the command. Unlike @code{advice}, this
advises not only the command body but also its @code{interactive} spec. If advises not only the command body but also its @code{interactive} spec. If
both slots are non-nil, @code{advice} is used for the body and @code{advice*} is both slots are non-@code{nil}, @code{advice} is used for the body and @code{advice*} is
used for the @code{interactive} form. When advising the @code{interactive} spec, used for the @code{interactive} form. When advising the @code{interactive} spec,
called using @code{(funcall advice #'advice-eval-interactive-spec spec)}. called using @code{(funcall advice #'advice-eval-interactive-spec spec)}.
@end itemize @end itemize
@ -3067,14 +3063,14 @@ currently cannot be invoked.
By default these predicates run when the prefix command is invoked, By default these predicates run when the prefix command is invoked,
but this can be changes, using the @code{refresh-suffixes} prefix slot. but this can be changes, using the @code{refresh-suffixes} prefix slot.
@xref{Prefix Slots}. See @ref{Prefix Slots}.
One more slot is shared between group and suffix classes, @code{level}. Like 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 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 different purpose. The value has to be an integer between 1
and 7. @code{level} controls whether a suffix or a group should be and 7. @code{level} controls whether a suffix or a group should be
available depending on user preference. available depending on user preference.
@xref{Enabling and Disabling Suffixes}. See @ref{Enabling and Disabling Suffixes}.
@node FAQ @node FAQ
@appendix FAQ @appendix FAQ

View file

@ -5,7 +5,7 @@
;; Author: Jonas Bernoulli <jonas@bernoul.li> ;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; URL: https://github.com/magit/transient ;; URL: https://github.com/magit/transient
;; Keywords: extensions ;; Keywords: extensions
;; Version: 0.10.1 ;; Version: 0.11.0
;; SPDX-License-Identifier: GPL-3.0-or-later ;; SPDX-License-Identifier: GPL-3.0-or-later
@ -33,7 +33,7 @@
;;; Code: ;;; Code:
;;;; Frontmatter ;;;; Frontmatter
(defconst transient-version "v0.10.1-8-g188ec9a1-builtin") (defconst transient-version "v0.11.0-10-g6637364e-builtin")
(require 'cl-lib) (require 'cl-lib)
(require 'eieio) (require 'eieio)
@ -52,22 +52,6 @@
(defvar Man-notify-method) (defvar Man-notify-method)
(static-if (< emacs-major-version 30)
(progn
(defun internal--build-binding@backport-e680827e814 (fn binding prev-var)
"Backport not warning about `_' not being left unused.
Backport fix for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=69108,
from Emacs commit e680827e814e155cf79175d87ff7c6ee3a08b69a."
(let ((binding (funcall fn binding prev-var)))
(if (eq (car binding) '_)
(cons (make-symbol "s") (cdr binding))
binding)))
(advice-add 'internal--build-binding :around
#'internal--build-binding@backport-e680827e814)))
(make-obsolete-variable 'transient-hide-during-minibuffer-read
'transient-show-during-minibuffer-read "0.8.0")
(defvar transient-common-command-prefix) (defvar transient-common-command-prefix)
(defmacro transient--with-emergency-exit (id &rest body) (defmacro transient--with-emergency-exit (id &rest body)
@ -94,9 +78,10 @@ from Emacs commit e680827e814e155cf79175d87ff7c6ee3a08b69a."
(defcustom transient-show-popup t (defcustom transient-show-popup t
"Whether and when to show transient's menu in a buffer. "Whether and when to show transient's menu in a buffer.
\\<transient-map>
- If t, then show the buffer as soon as a transient prefix command \\<transient-map>\
is invoked. - If t (the default), then show the buffer as soon as a transient
prefix command is invoked.
- If nil, then do not show the buffer unless the user explicitly - If nil, then do not show the buffer unless the user explicitly
requests it, by pressing \\[transient-show] or a prefix key. requests it, by pressing \\[transient-show] or a prefix key.
@ -118,8 +103,8 @@ from Emacs commit e680827e814e155cf79175d87ff7c6ee3a08b69a."
(defcustom transient-enable-popup-navigation 'verbose (defcustom transient-enable-popup-navigation 'verbose
"Whether navigation commands are enabled in the menu buffer. "Whether navigation commands are enabled in the menu buffer.
If the value is `verbose', additionally show brief documentation If the value is `verbose' (the default), additionally show brief
about the command under point in the echo area. documentation about the command under point in the echo area.
While a transient is active transient's menu buffer is not the While a transient is active transient's menu buffer is not the
current buffer, making it necessary to use dedicated commands to current buffer, making it necessary to use dedicated commands to
@ -208,6 +193,7 @@ want to change the value of `transient-mode-line-format'."
(defcustom transient-minimal-frame-width 83 (defcustom transient-minimal-frame-width 83
"Minimal width of dedicated frame used to display transient menu. "Minimal width of dedicated frame used to display transient menu.
This is only used if the transient menu is actually displayed in a This is only used if the transient menu is actually displayed in a
dedicated frame (see `transient-display-buffer-action'). The value dedicated frame (see `transient-display-buffer-action'). The value
is in characters." is in characters."
@ -329,12 +315,15 @@ This command is not bound by default, see its docstring for instructions."
(defcustom transient-highlight-mismatched-keys nil (defcustom transient-highlight-mismatched-keys nil
"Whether to highlight keys that do not match their argument. "Whether to highlight keys that do not match their argument.
This only affects infix arguments that represent command-line This is mostly intended for authors of transient menus and disabled by
arguments. When this option is non-nil, then the key binding default.
for infix argument are highlighted when only a long argument
\(e.g., \"--verbose\") is specified but no shorthand (e.g., \"-v\"). This only affects infix arguments that represent command-line arguments.
In the rare case that a short-hand is specified but does not When this option is non-nil, then the key binding for infix argument are
match the key binding, then it is highlighted differently. highlighted when only a long argument \(e.g., \"--verbose\") is specified
but no shorthand (e.g., \"-v\"). In the rare case that a short-hand is
specified but does not match the key binding, then it is highlighted
differently.
The highlighting is done using `transient-mismatched-key' The highlighting is done using `transient-mismatched-key'
and `transient-nonstandard-key'." and `transient-nonstandard-key'."
@ -577,10 +566,9 @@ See info node `(transient)Enabling and Disabling Suffixes'."
:group 'transient-faces) :group 'transient-faces)
(defface transient-higher-level (defface transient-higher-level
`((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) (let* ((color (face-attribute 'shadow :foreground t t))
:color ,(let ((color (face-attribute 'shadow :foreground t t))) (color (if (eq color 'unspecified) "grey60" color)))
(or (and (not (eq color 'unspecified)) color) `((t :box (:line-width (-1 . -1) :color ,color))))
"grey60")))))
"Face optionally used to highlight suffixes on higher levels. "Face optionally used to highlight suffixes on higher levels.
See also option `transient-highlight-higher-levels'." See also option `transient-highlight-higher-levels'."
:group 'transient-faces) :group 'transient-faces)
@ -661,15 +649,13 @@ character used to separate possible values from each other."
:group 'transient-faces) :group 'transient-faces)
(defface transient-nonstandard-key (defface transient-nonstandard-key
`((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) `((t :box (:line-width (-1 . -1) :color "cyan")))
:color "cyan")))
"Face optionally used to highlight keys conflicting with short-argument. "Face optionally used to highlight keys conflicting with short-argument.
See also option `transient-highlight-mismatched-keys'." See also option `transient-highlight-mismatched-keys'."
:group 'transient-faces) :group 'transient-faces)
(defface transient-mismatched-key (defface transient-mismatched-key
`((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) `((t :box (:line-width (-1 . -1) :color "magenta")))
:color "magenta")))
"Face optionally used to highlight keys without a short-argument. "Face optionally used to highlight keys without a short-argument.
See also option `transient-highlight-mismatched-keys'." See also option `transient-highlight-mismatched-keys'."
:group 'transient-faces) :group 'transient-faces)
@ -1397,12 +1383,13 @@ commands are aliases for."
(_ (use key val))))) (_ (use key val)))))
(when spec (when spec
(error "Need keyword, got %S" (car spec))) (error "Need keyword, got %S" (car spec)))
(if-let* ((key (plist-get args :key))) (cond*
(when (string-match "\\`\\({p}\\)" key) ((bind-and* (key (plist-get args :key)))
(use :key (when (string-match "\\`\\({p}\\)" key)
(replace-match transient-common-command-prefix t t key 1))) (use :key
(when-let* ((shortarg (plist-get args :shortarg))) (replace-match transient-common-command-prefix t t key 1))))
(use :key shortarg)))) ((bind-and* (shortarg (plist-get args :shortarg)))
(use :key shortarg))))
(list 'cons (list 'cons
(macroexp-quote (or class 'transient-suffix)) (macroexp-quote (or class 'transient-suffix))
(cons 'list args)))) (cons 'list args))))
@ -1427,8 +1414,7 @@ See also `transient-command-completion-not-suffix-only-p'.
Only use this alias as the value of the `completion-predicate' Only use this alias as the value of the `completion-predicate'
symbol property.") symbol property.")
(when (and (boundp 'read-extended-command-predicate) ; since Emacs 28.1 (unless read-extended-command-predicate
(not read-extended-command-predicate))
(setq read-extended-command-predicate (setq read-extended-command-predicate
#'transient-command-completion-not-suffix-only-p)) #'transient-command-completion-not-suffix-only-p))
@ -1436,50 +1422,52 @@ symbol property.")
(put prefix 'transient--layout (vector 2 nil layout))) (put prefix 'transient--layout (vector 2 nil layout)))
(defun transient--get-layout (prefix) (defun transient--get-layout (prefix)
(if-let* (cond*
((layout ((bind*
(or (get prefix 'transient--layout) (layout
;; Migrate unparsed legacy group definition. (or (get prefix 'transient--layout)
(condition-case-unless-debug err ;; Migrate unparsed legacy group definition.
(and-let* ((value (symbol-value prefix))) (condition-case-unless-debug err
(transient--set-layout (and-let* ((value (symbol-value prefix)))
prefix (transient--set-layout
(if (and (listp value) prefix
(or (listp (car value)) (if (and (listp value)
(vectorp (car value)))) (or (listp (car value))
(transient-parse-suffixes prefix value) (vectorp (car value))))
(list (transient-parse-suffix prefix value))))) (transient-parse-suffixes prefix value)
(error (list (transient-parse-suffix prefix value)))))
(message "Not a legacy group definition: %s: %S" prefix err) (error
nil))))) (message "Not a legacy group definition: %s: %S" prefix err)
(if (vectorp layout) nil))))))
(let ((version (aref layout 0))) ((not layout)
(if (= version 2) (error "Not a transient prefix command or group definition: %s" prefix))
layout ((vectorp layout)
(error "Unsupported layout version %s for %s" version prefix))) (let ((version (aref layout 0)))
;; Upgrade from version 1. (if (= version 2)
(cl-labels layout
((upgrade (spec) (error "Unsupported layout version %s for %s" version prefix))))
(cond (t
((vectorp spec) ;; Upgrade from version 1.
(pcase-let ((`[,level ,class ,args ,children] spec)) (transient--set-layout
(when level prefix
(setq args (plist-put args :level level))) (named-let upgrade ((spec layout))
(vector class args (mapcar #'upgrade children)))) (cond ((vectorp spec)
((and (listp spec) (pcase-let ((`[,level ,class ,args ,children] spec))
(length= spec 3) (when level
(or (null (car spec)) (setq args (plist-put args :level level)))
(natnump (car spec))) (vector class args (mapcar #'upgrade children))))
(symbolp (cadr spec))) ((and (listp spec)
(pcase-let ((`(,level ,class ,args) spec)) (length= spec 3)
(when level (or (null (car spec))
(setq args (plist-put args :level level))) (natnump (car spec)))
(cons class args))) (symbolp (cadr spec)))
((listp spec) (pcase-let ((`(,level ,class ,args) spec))
(mapcar #'upgrade spec)) (when level
(t spec)))) (setq args (plist-put args :level level)))
(transient--set-layout prefix (upgrade layout)))) (cons class args)))
(error "Not a transient prefix command or group definition: %s" prefix))) ((listp spec)
(mapcar #'upgrade spec))
(t spec)))))))
(defun transient--get-children (prefix) (defun transient--get-children (prefix)
(aref (transient--get-layout prefix) 2)) (aref (transient--get-layout prefix) 2))
@ -1674,11 +1662,12 @@ See info node `(transient)Modifying Existing Transients'."
(defun transient--match-child (group loc child) (defun transient--match-child (group loc child)
(cl-etypecase child (cl-etypecase child
(string nil) (string nil)
(symbol (if (symbolp loc) (symbol (cond*
(and (eq child loc) ((symbolp loc)
(list child group)) (and (eq child loc)
(and-let* ((include (transient--get-layout child))) (list child group)))
(transient--locate-child include loc)))) ((bind-and* (include (transient--get-layout child)))
(transient--locate-child include loc))))
(vector (seq-some (lambda (subgroup) (vector (seq-some (lambda (subgroup)
(transient--locate-child subgroup loc)) (transient--locate-child subgroup loc))
(aref group 2))) (aref group 2)))
@ -1924,47 +1913,46 @@ probably use this instead:
(get COMMAND \\='transient--suffix)" (get COMMAND \\='transient--suffix)"
(when command (when command
(cl-check-type command command)) (cl-check-type command command))
(cond (cond*
(transient--pending-suffix) (transient--pending-suffix)
(transient--current-suffix) (transient--current-suffix)
((or transient--prefix ((or transient--prefix
transient-current-prefix) transient-current-prefix)
(let ((suffixes (let ((suffixes
(cl-remove-if-not (cl-remove-if-not
(lambda (obj) (lambda (obj)
(eq (oref obj command) (eq (oref obj command)
(or command (or command
(if (eq this-command 'transient-set-level) (if (eq this-command 'transient-set-level)
;; This is how it can look up for which ;; This is how it can look up for which
;; command it is setting the level. ;; command it is setting the level.
this-original-command this-original-command
this-command)))) this-command))))
(or transient--suffixes (or transient--suffixes
transient-current-suffixes)))) transient-current-suffixes))))
(cond (cond
((length= suffixes 1) ((length= suffixes 1)
(car suffixes)) (car suffixes))
((cl-find-if (lambda (obj) ((cl-find-if (lambda (obj)
(equal (listify-key-sequence (kbd (oref obj key))) (equal (listify-key-sequence (kbd (oref obj key)))
(listify-key-sequence (this-command-keys)))) (listify-key-sequence (this-command-keys))))
suffixes)) suffixes))
;; COMMAND is only provided if `this-command' is meaningless, in ;; COMMAND is only provided if `this-command' is meaningless, in
;; which case `this-command-keys' is also meaningless, making it ;; which case `this-command-keys' is also meaningless, making it
;; impossible to disambiguate bindings for the same command. ;; impossible to disambiguate bindings for the same command.
(command (car suffixes)) (command (car suffixes))
;; If COMMAND is nil, then failure to disambiguate likely means ;; If COMMAND is nil, then failure to disambiguate likely means
;; that there is a bug somewhere. ;; that there is a bug somewhere.
((length> suffixes 1) ((length> suffixes 1)
(error "BUG: Cannot unambiguously determine suffix object")) (error "BUG: Cannot unambiguously determine suffix object"))
;; It is legimate to use this function as a predicate of sorts. ;; It is legimate to use this function as a predicate of sorts.
;; `transient--pre-command' and `transient-help' are examples. ;; `transient--pre-command' and `transient-help' are examples.
(t nil)))) (t nil))))
((and-let* ((obj (transient--suffix-prototype (or command this-command))) ((bind-and* (obj (transient--suffix-prototype (or command this-command)))
(obj (clone obj))) (obj (clone obj)))
(progn (transient-init-scope obj)
(transient-init-scope obj) (transient-init-value obj)
(transient-init-value obj) obj)))
obj)))))
(defun transient--suffix-prototype (command) (defun transient--suffix-prototype (command)
(or (get command 'transient--suffix) (or (get command 'transient--suffix)
@ -1997,25 +1985,22 @@ to `transient-predicate-map'."
"<next>" #'transient-scroll-up "<next>" #'transient-scroll-up
"<prior>" #'transient-scroll-down) "<prior>" #'transient-scroll-down)
(defvar transient-map (defvar-keymap transient-map
(let ((map (make-sparse-keymap))) :doc "Top-level keymap used by all transients.
(set-keymap-parent map transient-base-map)
(keymap-set map "C-u" #'universal-argument)
(keymap-set map "C--" #'negative-argument)
(keymap-set map "C-t" #'transient-show)
(keymap-set map "?" #'transient-help)
(keymap-set map "C-h" #'transient-help)
;; Next two have additional bindings in transient-common-commands.
(keymap-set map "C-M-p" #'transient-history-prev)
(keymap-set map "C-M-n" #'transient-history-next)
(when (fboundp 'other-frame-prefix) ;Emacs >= 28.1
(keymap-set map "C-x 5 5" 'other-frame-prefix)
(keymap-set map "C-x 4 4" 'other-window-prefix))
map)
"Top-level keymap used by all transients.
If you add a new command here, then you must also add a binding If you add a new command here, then you must also add a binding
to `transient-predicate-map'. See also `transient-base-map'.") to `transient-predicate-map'. See also `transient-base-map'."
:parent transient-base-map
"C-u" #'universal-argument
"C--" #'negative-argument
"C-t" #'transient-show
"?" #'transient-help
"C-h" #'transient-help
"C-x 5 5" #'other-frame-prefix
"C-x 4 4" #'other-window-prefix
;; These have additional bindings in transient-common-commands.
"C-M-p" #'transient-history-prev
"C-M-n" #'transient-history-next)
(defvar-keymap transient-edit-map (defvar-keymap transient-edit-map
:doc "Keymap that is active while a transient in is in \"edit mode\"." :doc "Keymap that is active while a transient in is in \"edit mode\"."
@ -2449,16 +2434,14 @@ value. Otherwise return CHILDREN as is.")
(transient--get-children 'transient-common-commands)))))) (transient--get-children 'transient-common-commands))))))
(defun transient--flatten-suffixes (layout) (defun transient--flatten-suffixes (layout)
(cl-labels ((s (def) (named-let flatten ((def layout))
(cond (cond ((stringp def) nil)
((stringp def) nil) ((cl-typep def 'transient-information) nil)
((cl-typep def 'transient-information) nil) ((listp def) (mapcan #'flatten def))
((listp def) (mapcan #'s def)) ((cl-typep def 'transient-group)
((cl-typep def 'transient-group) (mapcan #'flatten (oref def suffixes)))
(mapcan #'s (oref def suffixes))) ((cl-typep def 'transient-suffix)
((cl-typep def 'transient-suffix) (list def)))))
(list def)))))
(mapcan #'s layout)))
(defun transient--init-child (levels spec parent) (defun transient--init-child (levels spec parent)
(cl-etypecase spec (cl-etypecase spec
@ -3825,20 +3808,22 @@ command-line option) or \": \".
Finally fall through to using \"(BUG: no prompt): \" as the Finally fall through to using \"(BUG: no prompt): \" as the
prompt." prompt."
(if-let* ((prompt (oref obj prompt))) (cond*
(let ((prompt (if (functionp prompt) ((bind-and* (prompt (oref obj prompt)))
(funcall prompt obj) (let ((prompt (if (functionp prompt)
prompt))) (funcall prompt obj)
(if (stringp prompt) prompt)))
prompt (if (stringp prompt)
"[BUG: invalid prompt]: ")) prompt
(if-let* ((name (or (and (slot-boundp obj 'argument) (oref obj argument)) "[BUG: invalid prompt]: ")))
(and (slot-boundp obj 'variable) (oref obj variable))))) ((bind-and*
(if (and (stringp name) (name (or (and (slot-boundp obj 'argument) (oref obj argument))
(string-suffix-p "=" name)) (and (slot-boundp obj 'variable) (oref obj variable)))))
name (if (and (stringp name)
(format "%s: " name)) (string-suffix-p "=" name))
"[BUG: no prompt]: "))) name
(format "%s: " name)))
("[BUG: no prompt]: ")))
;;;; Set ;;;; Set
@ -4415,8 +4400,7 @@ have a history of their own.")
(height (cond ((not window-system) nil) (height (cond ((not window-system) nil)
((natnump format) format) ((natnump format) format)
((eq format 'line) 1))) ((eq format 'line) 1)))
(face `(,@(and (>= emacs-major-version 27) '(:extend t)) (face `(:background ,(transient--prefix-color) :extend t)))
:background ,(transient--prefix-color))))
(concat (propertize "__" 'face face 'display `(space :height (,height))) (concat (propertize "__" 'face face 'display `(space :height (,height)))
(propertize "\n" 'face face 'line-height t)))) (propertize "\n" 'face face 'line-height t))))
@ -4699,9 +4683,9 @@ apply the face `transient-unreachable' to the complete string."
(when-let* ((face (transient--get-face obj 'face))) (when-let* ((face (transient--get-face obj 'face)))
(setq desc (transient--add-face desc face t))) (setq desc (transient--add-face desc face t)))
(setq desc (propertize "(BUG: no description)" 'face 'error))) (setq desc (propertize "(BUG: no description)" 'face 'error)))
(when (if transient--all-levels-p (when (cond (transient--all-levels-p
(> (oref obj level) transient--default-prefix-level) (> (oref obj level) transient--default-prefix-level))
(and transient-highlight-higher-levels (transient-highlight-higher-levels
(> (max (oref obj level) transient--max-group-level) (> (max (oref obj level) transient--max-group-level)
transient--default-prefix-level))) transient--default-prefix-level)))
(setq desc (transient--add-face desc 'transient-higher-level))) (setq desc (transient--add-face desc 'transient-higher-level)))
@ -4887,28 +4871,28 @@ if non-nil, else show the `man-page' if non-nil, else use
Also used to dispatch showing documentation for the current Also used to dispatch showing documentation for the current
prefix. If the suffix is a sub-prefix, then also call the prefix. If the suffix is a sub-prefix, then also call the
prefix method." prefix method."
(cond (cond*
((eq this-command 'transient-help) ((eq this-command 'transient-help)
(transient-show-help transient--prefix)) (transient-show-help transient--prefix))
((let ((prefix (get (oref obj command) ((bind-and* (prefix (get (oref obj command) 'transient--prefix))
'transient--prefix))) (n/a (not (eq (oref transient--prefix command) this-command))))
(and prefix (not (eq (oref transient--prefix command) this-command)) (transient-show-help prefix))
(prog1 t (transient-show-help prefix))))) ((bind-and* (show-help (oref obj show-help)))
((if-let* ((show-help (oref obj show-help))) (funcall show-help obj))
(funcall show-help obj) ((transient--describe-function this-command))))
(transient--describe-function this-command)))))
(cl-defmethod transient-show-help ((obj transient-infix)) (cl-defmethod transient-show-help ((obj transient-infix))
"Call `show-help' if non-nil, else show the `man-page' "Call `show-help' if non-nil, else show the `man-page'
if non-nil, else use `describe-function'. When showing the if non-nil, else use `describe-function'. When showing the
manpage, then try to jump to the correct location." manpage, then try to jump to the correct location."
(if-let* ((show-help (oref obj show-help))) (cond*
(funcall show-help obj) ((bind-and* (show-help (oref obj show-help)))
(if-let* ((man-page (oref transient--prefix man-page)) (funcall show-help obj))
(argument (and (slot-boundp obj 'argument) ((bind-and* (man-page (oref transient--prefix man-page))
(oref obj argument)))) (argument (and (slot-boundp obj 'argument)
(transient--show-manpage man-page argument) (oref obj argument))))
(transient--describe-function this-command)))) (transient--show-manpage man-page argument))
((transient--describe-function this-command))))
;; `cl-generic-generalizers' doesn't support `command' et al. ;; `cl-generic-generalizers' doesn't support `command' et al.
(cl-defmethod transient-show-help (cmd) (cl-defmethod transient-show-help (cmd)
@ -5159,6 +5143,7 @@ See `forward-button' for information about N."
(defvar-keymap transient--isearch-mode-map (defvar-keymap transient--isearch-mode-map
:parent isearch-mode-map :parent isearch-mode-map
"<t>" #'transient-isearch-exit
"<remap> <isearch-exit>" #'transient-isearch-exit "<remap> <isearch-exit>" #'transient-isearch-exit
"<remap> <isearch-cancel>" #'transient-isearch-cancel "<remap> <isearch-cancel>" #'transient-isearch-cancel
"<remap> <isearch-abort>" #'transient-isearch-abort) "<remap> <isearch-abort>" #'transient-isearch-abort)