aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Bernoulli2024-03-21 23:55:38 +0100
committerJonas Bernoulli2024-03-21 23:55:38 +0100
commitc214fc9626c8b37e4d155a6d3caebe2e09fd0ab2 (patch)
tree547e0c7bd23cd0eeea1abb8d3f3f5adf366aec95
parent2000d6e0f27f9f34f343016f4aa93e09c29c8695 (diff)
downloademacs-c214fc9626c8b37e4d155a6d3caebe2e09fd0ab2.tar.gz
emacs-c214fc9626c8b37e4d155a6d3caebe2e09fd0ab2.zip
Update to Transient v0.6.0-1-gcaef3347
-rw-r--r--doc/misc/transient.texi28
-rw-r--r--lisp/transient.el279
2 files changed, 202 insertions, 105 deletions
diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi
index f76edc6b1e4..3a6486903bf 100644
--- a/doc/misc/transient.texi
+++ b/doc/misc/transient.texi
@@ -31,7 +31,7 @@ General Public License for more details.
31@finalout 31@finalout
32@titlepage 32@titlepage
33@title Transient User and Developer Manual 33@title Transient User and Developer Manual
34@subtitle for version 0.5.2 34@subtitle for version 0.6.0
35@author Jonas Bernoulli 35@author Jonas Bernoulli
36@page 36@page
37@vskip 0pt plus 1filll 37@vskip 0pt plus 1filll
@@ -53,7 +53,7 @@ resource to get over that hurdle is Psionic K's interactive tutorial,
53available at @uref{https://github.com/positron-solutions/transient-showcase}. 53available at @uref{https://github.com/positron-solutions/transient-showcase}.
54 54
55@noindent 55@noindent
56This manual is for Transient version 0.5.2. 56This manual is for Transient version 0.6.0.
57 57
58@insertcopying 58@insertcopying
59@end ifnottex 59@end ifnottex
@@ -554,7 +554,7 @@ state, you have to make sure that that state is currently active.
554@item @kbd{C-x a} (@code{transient-toggle-level-limit}) 554@item @kbd{C-x a} (@code{transient-toggle-level-limit})
555@kindex C-x a 555@kindex C-x a
556@findex transient-toggle-level-limit 556@findex transient-toggle-level-limit
557This command toggle whether suffixes that are on levels lower than 557This command toggle whether suffixes that are on levels higher than
558the level specified by @code{transient-default-level} are temporarily 558the level specified by @code{transient-default-level} are temporarily
559available anyway. 559available anyway.
560@end table 560@end table
@@ -1206,9 +1206,19 @@ The returned children must have the same form as stored in the
1206prefix's @code{transient--layout} property, but it is often more convenient 1206prefix's @code{transient--layout} property, but it is often more convenient
1207to use the same form as understood by @code{transient-define-prefix}, 1207to use the same form as understood by @code{transient-define-prefix},
1208described below. If you use the latter approach, you can use the 1208described below. If you use the latter approach, you can use the
1209@code{transient-parse-child} and @code{transient-parse-children} functions to 1209@code{transient-parse-suffixes} and @code{transient-parse-suffix} functions to
1210transform them from the convenient to the expected form. 1210transform them from the convenient to the expected form.
1211 1211
1212If you explicitly specify children and then transform them using
1213@code{:setup-chilren}, then the class of the group is determined as usual,
1214based on explicitly specified children.
1215
1216If you do not explicitly specify children and thus rely solely on
1217@code{:setup-children}, then you must specify the class using @code{:class}.
1218For backward compatibility, if you fail to do so, @code{transient-column}
1219is used and a warning is displayed. This warning will eventually
1220be replaced with an error.
1221
1212@item 1222@item
1213The boolean @code{:pad-keys} argument controls whether keys of all suffixes 1223The boolean @code{:pad-keys} argument controls whether keys of all suffixes
1214contained in a group are right padded, effectively aligning the 1224contained in a group are right padded, effectively aligning the
@@ -1220,11 +1230,11 @@ The @var{ELEMENT}s are either all subgroups, or all suffixes and strings.
1220subgroups with commands at the same level, though in principle there 1230subgroups with commands at the same level, though in principle there
1221is nothing that prevents that.) 1231is nothing that prevents that.)
1222 1232
1223If the @var{ELEMENT}s are not subgroups, then they can be a mixture of lists 1233If the @var{ELEMENT}s are not subgroups, then they can be a mixture of
1224that specify commands and strings. Strings are inserted verbatim into 1234lists, which specify commands, and strings. Strings are inserted
1225the buffer. The empty string can be used to insert gaps between 1235verbatim into the buffer. The empty string can be used to insert gaps
1226suffixes, which is particularly useful if the suffixes are outlined as 1236between suffixes, which is particularly useful if the suffixes are
1227a table. 1237outlined as a table.
1228 1238
1229Inside group specifications, including inside contained suffix 1239Inside group specifications, including inside contained suffix
1230specifications, nothing has to be quoted and quoting anyway is 1240specifications, nothing has to be quoted and quoting anyway is
diff --git a/lisp/transient.el b/lisp/transient.el
index bb35746e186..2d8566a3ac4 100644
--- a/lisp/transient.el
+++ b/lisp/transient.el
@@ -5,7 +5,7 @@
5;; Author: Jonas Bernoulli <jonas@bernoul.li> 5;; Author: Jonas Bernoulli <jonas@bernoul.li>
6;; URL: https://github.com/magit/transient 6;; URL: https://github.com/magit/transient
7;; Keywords: extensions 7;; Keywords: extensions
8;; Version: 0.5.2 8;; Version: 0.6.0
9 9
10;; SPDX-License-Identifier: GPL-3.0-or-later 10;; SPDX-License-Identifier: GPL-3.0-or-later
11 11
@@ -93,17 +93,20 @@ enclosed in a `progn' form. ELSE-FORMS may be empty."
93 then-form 93 then-form
94 (cons 'progn else-forms))) 94 (cons 'progn else-forms)))
95 95
96(defmacro transient--with-emergency-exit (&rest body) 96(defmacro transient--with-emergency-exit (id &rest body)
97 (declare (indent defun)) 97 (declare (indent defun))
98 (unless (keywordp id)
99 (setq body (cons id body))
100 (setq id nil))
98 `(condition-case err 101 `(condition-case err
99 (let ((debugger #'transient--exit-and-debug)) 102 (let ((debugger #'transient--exit-and-debug))
100 ,(macroexp-progn body)) 103 ,(macroexp-progn body))
101 ((debug error) 104 ((debug error)
102 (transient--emergency-exit) 105 (transient--emergency-exit ,id)
103 (signal (car err) (cdr err))))) 106 (signal (car err) (cdr err)))))
104 107
105(defun transient--exit-and-debug (&rest args) 108(defun transient--exit-and-debug (&rest args)
106 (transient--emergency-exit) 109 (transient--emergency-exit :debugger)
107 (apply #'debug args)) 110 (apply #'debug args))
108 111
109;;; Options 112;;; Options
@@ -668,6 +671,7 @@ If `transient-save-history' is nil, then do nothing."
668 (incompatible :initarg :incompatible :initform nil) 671 (incompatible :initarg :incompatible :initform nil)
669 (suffix-description :initarg :suffix-description) 672 (suffix-description :initarg :suffix-description)
670 (variable-pitch :initarg :variable-pitch :initform nil) 673 (variable-pitch :initarg :variable-pitch :initform nil)
674 (column-widths :initarg :column-widths :initform nil)
671 (unwind-suffix :documentation "Internal use." :initform nil)) 675 (unwind-suffix :documentation "Internal use." :initform nil))
672 "Transient prefix command. 676 "Transient prefix command.
673 677
@@ -725,7 +729,8 @@ slot is non-nil."
725 :abstract t) 729 :abstract t)
726 730
727(defclass transient-suffix (transient-child) 731(defclass transient-suffix (transient-child)
728 ((key :initarg :key) 732 ((definition :allocation :class :initform nil)
733 (key :initarg :key)
729 (command :initarg :command) 734 (command :initarg :command)
730 (transient :initarg :transient) 735 (transient :initarg :transient)
731 (format :initarg :format :initform " %k %d") 736 (format :initarg :format :initform " %k %d")
@@ -946,7 +951,10 @@ ARGLIST. The infix arguments are usually accessed by using
946 (pcase-let ((`(,class ,slots ,_ ,docstr ,body) 951 (pcase-let ((`(,class ,slots ,_ ,docstr ,body)
947 (transient--expand-define-args args arglist))) 952 (transient--expand-define-args args arglist)))
948 `(progn 953 `(progn
949 (defalias ',name (lambda ,arglist ,@body)) 954 (defalias ',name
955 ,(if (and (not body) class (oref-default class definition))
956 `(oref-default ',class definition)
957 `(lambda ,arglist ,@body)))
950 (put ',name 'interactive-only t) 958 (put ',name 'interactive-only t)
951 (put ',name 'function-documentation ,docstr) 959 (put ',name 'function-documentation ,docstr)
952 (put ',name 'transient--suffix 960 (put ',name 'transient--suffix
@@ -997,7 +1005,7 @@ keyword.
997 `(progn 1005 `(progn
998 (defalias ',name #'transient--default-infix-command) 1006 (defalias ',name #'transient--default-infix-command)
999 (put ',name 'interactive-only t) 1007 (put ',name 'interactive-only t)
1000 (put ',name 'command-modes (list 'not-a-mode)) 1008 (put ',name 'completion-predicate #'transient--suffix-only)
1001 (put ',name 'function-documentation ,docstr) 1009 (put ',name 'function-documentation ,docstr)
1002 (put ',name 'transient--suffix 1010 (put ',name 'transient--suffix
1003 (,(or class 'transient-switch) :command ',name ,@slots))))) 1011 (,(or class 'transient-switch) :command ',name ,@slots)))))
@@ -1013,21 +1021,39 @@ example, sets a variable, use `transient-define-infix' instead.
1013 1021
1014(defun transient--default-infix-command () 1022(defun transient--default-infix-command ()
1015 ;; Most infix commands are but an alias for this command. 1023 ;; Most infix commands are but an alias for this command.
1016 "Cannot show any documentation for this anonymous infix command. 1024 "Cannot show any documentation for this transient infix command.
1025
1026When you request help for an infix command using `transient-help', that
1027usually shows the respective man-page and tries to jump to the location
1028where the respective argument is being described.
1017 1029
1018This infix command was defined anonymously, i.e., it was define 1030If no man-page is specified for the containing transient menu, then the
1019inside a call to `transient-define-prefix'. 1031docstring is displayed instead, if any.
1020 1032
1021When you request help for such an infix command, then we usually 1033If the infix command doesn't have a docstring, as is the case here, then
1022show the respective man-page and jump to the location where the 1034this docstring is displayed instead, because technically infix commands
1023respective argument is being described. This isn't possible in 1035are aliases for `transient--default-infix-command'.
1024this case, because the `man-page' slot was not set in this case." 1036
1037`describe-function' also shows the docstring of the infix command,
1038falling back to that of the same aliased command."
1025 (interactive) 1039 (interactive)
1026 (let ((obj (transient-suffix-object))) 1040 (let ((obj (transient-suffix-object)))
1027 (transient-infix-set obj (transient-infix-read obj))) 1041 (transient-infix-set obj (transient-infix-read obj)))
1028 (transient--show)) 1042 (transient--show))
1029(put 'transient--default-infix-command 'interactive-only t) 1043(put 'transient--default-infix-command 'interactive-only t)
1030(put 'transient--default-infix-command 'command-modes (list 'not-a-mode)) 1044(put 'transient--default-infix-command 'completion-predicate
1045 #'transient--suffix-only)
1046
1047(defun transient--find-function-advised-original (fn func)
1048 "Return nil instead of `transient--default-infix-command'.
1049When using `find-function' to jump to the definition of a transient
1050infix command/argument, then we want to actually jump to that, not to
1051the definition of `transient--default-infix-command', which all infix
1052commands are aliases for."
1053 (let ((val (funcall fn func)))
1054 (and val (not (eq val 'transient--default-infix-command)) val)))
1055(advice-add 'find-function-advised-original :around
1056 #'transient--find-function-advised-original)
1031 1057
1032(eval-and-compile 1058(eval-and-compile
1033 (defun transient--expand-define-args (args &optional arglist) 1059 (defun transient--expand-define-args (args &optional arglist)
@@ -1056,7 +1082,8 @@ this case, because the `man-page' slot was not set in this case."
1056 args)))) 1082 args))))
1057 1083
1058(defun transient--parse-child (prefix spec) 1084(defun transient--parse-child (prefix spec)
1059 (cl-etypecase spec 1085 (cl-typecase spec
1086 (null (error "Invalid transient--parse-child spec: %s" spec))
1060 (symbol (let ((value (symbol-value spec))) 1087 (symbol (let ((value (symbol-value spec)))
1061 (if (and (listp value) 1088 (if (and (listp value)
1062 (or (listp (car value)) 1089 (or (listp (car value))
@@ -1065,7 +1092,8 @@ this case, because the `man-page' slot was not set in this case."
1065 (transient--parse-child prefix value)))) 1092 (transient--parse-child prefix value))))
1066 (vector (and-let* ((c (transient--parse-group prefix spec))) (list c))) 1093 (vector (and-let* ((c (transient--parse-group prefix spec))) (list c)))
1067 (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c))) 1094 (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c)))
1068 (string (list spec)))) 1095 (string (list spec))
1096 (t (error "Invalid transient--parse-child spec: %s" spec))))
1069 1097
1070(defun transient--parse-group (prefix spec) 1098(defun transient--parse-group (prefix spec)
1071 (setq spec (append spec nil)) 1099 (setq spec (append spec nil))
@@ -1086,12 +1114,16 @@ this case, because the `man-page' slot was not set in this case."
1086 (and (listp val) (not (eq (car val) 'lambda)))) 1114 (and (listp val) (not (eq (car val) 'lambda))))
1087 (setq args (plist-put args key (macroexp-quote val)))) 1115 (setq args (plist-put args key (macroexp-quote val))))
1088 ((setq args (plist-put args key val)))))) 1116 ((setq args (plist-put args key val))))))
1117 (unless (or spec class (not (plist-get args :setup-children)))
1118 (message "WARNING: %s: When %s is used, %s must also be specified"
1119 'transient-define-prefix :setup-children :class))
1089 (list 'vector 1120 (list 'vector
1090 (or level transient--default-child-level) 1121 (or level transient--default-child-level)
1091 (or class 1122 (cond (class)
1092 (if (vectorp car) 1123 ((or (vectorp car)
1093 (quote 'transient-columns) 1124 (and car (symbolp car)))
1094 (quote 'transient-column))) 1125 (quote 'transient-columns))
1126 ((quote 'transient-column)))
1095 (and args (cons 'list args)) 1127 (and args (cons 'list args))
1096 (cons 'list 1128 (cons 'list
1097 (cl-mapcan (lambda (s) (transient--parse-child prefix s)) 1129 (cl-mapcan (lambda (s) (transient--parse-child prefix s))
@@ -1130,14 +1162,15 @@ this case, because the `man-page' slot was not set in this case."
1130 (format "transient:%s:%s" 1162 (format "transient:%s:%s"
1131 prefix 1163 prefix
1132 (let ((desc (plist-get args :description))) 1164 (let ((desc (plist-get args :description)))
1133 (if (and desc (or (stringp desc) (symbolp desc))) 1165 (if (and (stringp desc)
1166 (length< desc 16))
1134 desc 1167 desc
1135 (plist-get args :key))))))) 1168 (plist-get args :key)))))))
1136 (setq args (plist-put 1169 (setq args (plist-put
1137 args :command 1170 args :command
1138 `(prog1 ',sym 1171 `(prog1 ',sym
1139 (put ',sym 'interactive-only t) 1172 (put ',sym 'interactive-only t)
1140 (put ',sym 'command-modes (list 'not-a-mode)) 1173 (put ',sym 'completion-predicate #'transient--suffix-only)
1141 (defalias ',sym 1174 (defalias ',sym
1142 ,(if (eq (car-safe cmd) 'lambda) 1175 ,(if (eq (car-safe cmd) 'lambda)
1143 cmd 1176 cmd
@@ -1160,7 +1193,7 @@ this case, because the `man-page' slot was not set in this case."
1160 args :command 1193 args :command
1161 `(prog1 ',sym 1194 `(prog1 ',sym
1162 (put ',sym 'interactive-only t) 1195 (put ',sym 'interactive-only t)
1163 (put ',sym 'command-modes (list 'not-a-mode)) 1196 (put ',sym 'completion-predicate #'transient--suffix-only)
1164 (defalias ',sym #'transient--default-infix-command)))) 1197 (defalias ',sym #'transient--default-infix-command))))
1165 (cond ((and car (not (keywordp car))) 1198 (cond ((and car (not (keywordp car)))
1166 (setq class 'transient-option) 1199 (setq class 'transient-option)
@@ -1198,12 +1231,33 @@ this case, because the `man-page' slot was not set in this case."
1198 (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg) 1231 (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg)
1199 (match-string 1 arg)))) 1232 (match-string 1 arg))))
1200 1233
1234(defun transient-command-completion-not-suffix-only-p (symbol _buffer)
1235 "Say whether SYMBOL should be offered as a completion.
1236If the value of SYMBOL's `completion-predicate' property is
1237`transient--suffix-only', then return nil, otherwise return t.
1238This is the case when a command should only ever be used as a
1239suffix of a transient prefix command (as opposed to bindings
1240in regular keymaps or by using `execute-extended-command')."
1241 (not (eq (get symbol 'completion-predicate) 'transient--suffix-only)))
1242
1243(defalias 'transient--suffix-only #'ignore
1244 "Ignore ARGUMENTS, do nothing, and return nil.
1245Also see `transient-command-completion-not-suffix-only-p'.
1246Only use this alias as the value of the `completion-predicate'
1247symbol property.")
1248
1249(when (and (boundp 'read-extended-command-predicate) ; since Emacs 28.1
1250 (not read-extended-command-predicate))
1251 (setq read-extended-command-predicate
1252 'transient-command-completion-not-suffix-only-p))
1253
1201(defun transient-parse-suffix (prefix suffix) 1254(defun transient-parse-suffix (prefix suffix)
1202 "Parse SUFFIX, to be added to PREFIX. 1255 "Parse SUFFIX, to be added to PREFIX.
1203PREFIX is a prefix command, a symbol. 1256PREFIX is a prefix command, a symbol.
1204SUFFIX is a suffix command or a group specification (of 1257SUFFIX is a suffix command or a group specification (of
1205 the same forms as expected by `transient-define-prefix'). 1258 the same forms as expected by `transient-define-prefix').
1206Intended for use in a group's `:setup-children' function." 1259Intended for use in a group's `:setup-children' function."
1260 (cl-assert (and prefix (symbolp prefix)))
1207 (eval (car (transient--parse-child prefix suffix)))) 1261 (eval (car (transient--parse-child prefix suffix))))
1208 1262
1209(defun transient-parse-suffixes (prefix suffixes) 1263(defun transient-parse-suffixes (prefix suffixes)
@@ -1212,6 +1266,7 @@ PREFIX is a prefix command, a symbol.
1212SUFFIXES is a list of suffix command or a group specification 1266SUFFIXES is a list of suffix command or a group specification
1213 (of the same forms as expected by `transient-define-prefix'). 1267 (of the same forms as expected by `transient-define-prefix').
1214Intended for use in a group's `:setup-children' function." 1268Intended for use in a group's `:setup-children' function."
1269 (cl-assert (and prefix (symbolp prefix)))
1215 (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes)) 1270 (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes))
1216 1271
1217;;; Edit 1272;;; Edit
@@ -1472,7 +1527,8 @@ drawing in the transient buffer.")
1472 1527
1473(defvar transient--pending-suffix nil 1528(defvar transient--pending-suffix nil
1474 "The suffix that is currently being processed. 1529 "The suffix that is currently being processed.
1475This is bound while the suffix predicate is being evaluated.") 1530This is bound while the suffix predicate is being evaluated,
1531and while functions that return faces are being evaluated.")
1476 1532
1477(defvar transient--pending-group nil 1533(defvar transient--pending-group nil
1478 "The group that is currently being processed. 1534 "The group that is currently being processed.
@@ -1555,33 +1611,35 @@ probably use this instead:
1555 (get COMMAND \\='transient--suffix)" 1611 (get COMMAND \\='transient--suffix)"
1556 (when command 1612 (when command
1557 (cl-check-type command command)) 1613 (cl-check-type command command))
1558 (if (or transient--prefix 1614 (cond
1559 transient-current-prefix) 1615 (transient--pending-suffix)
1560 (let ((suffixes 1616 ((or transient--prefix
1561 (cl-remove-if-not 1617 transient-current-prefix)
1562 (lambda (obj) 1618 (let ((suffixes
1563 (eq (oref obj command) 1619 (cl-remove-if-not
1564 (or command 1620 (lambda (obj)
1565 (if (eq this-command 'transient-set-level) 1621 (eq (oref obj command)
1566 ;; This is how it can look up for which 1622 (or command
1567 ;; command it is setting the level. 1623 (if (eq this-command 'transient-set-level)
1568 this-original-command 1624 ;; This is how it can look up for which
1569 this-command)))) 1625 ;; command it is setting the level.
1570 (or transient--suffixes 1626 this-original-command
1571 transient-current-suffixes)))) 1627 this-command))))
1572 (or (and (cdr suffixes) 1628 (or transient--suffixes
1573 (cl-find-if 1629 transient-current-suffixes))))
1574 (lambda (obj) 1630 (or (and (cdr suffixes)
1575 (equal (listify-key-sequence (transient--kbd (oref obj key))) 1631 (cl-find-if
1576 (listify-key-sequence (this-command-keys)))) 1632 (lambda (obj)
1577 suffixes)) 1633 (equal (listify-key-sequence (transient--kbd (oref obj key)))
1578 (car suffixes))) 1634 (listify-key-sequence (this-command-keys))))
1579 (and-let* ((obj (transient--suffix-prototype (or command this-command))) 1635 suffixes))
1636 (car suffixes))))
1637 ((and-let* ((obj (transient--suffix-prototype (or command this-command)))
1580 (obj (clone obj))) 1638 (obj (clone obj)))
1581 (progn ; work around debbugs#31840 1639 (progn ; work around debbugs#31840
1582 (transient-init-scope obj) 1640 (transient-init-scope obj)
1583 (transient-init-value obj) 1641 (transient-init-value obj)
1584 obj)))) 1642 obj)))))
1585 1643
1586(defun transient--suffix-prototype (command) 1644(defun transient--suffix-prototype (command)
1587 (or (get command 'transient--suffix) 1645 (or (get command 'transient--suffix)
@@ -1762,7 +1820,10 @@ of the corresponding object."
1762 ;; an unbound key, then Emacs calls the `undefined' command 1820 ;; an unbound key, then Emacs calls the `undefined' command
1763 ;; but does not set `this-command', `this-original-command' 1821 ;; but does not set `this-command', `this-original-command'
1764 ;; or `real-this-command' accordingly. Instead they are nil. 1822 ;; or `real-this-command' accordingly. Instead they are nil.
1765 "<nil>" #'transient--do-warn) 1823 "<nil>" #'transient--do-warn
1824 ;; Bound to the `mouse-movement' event, this command is similar
1825 ;; to `ignore'.
1826 "<ignore-preserving-kill-region>" #'transient--do-noop)
1766 1827
1767(defvar transient--transient-map nil) 1828(defvar transient--transient-map nil)
1768(defvar transient--predicate-map nil) 1829(defvar transient--predicate-map nil)
@@ -1821,7 +1882,7 @@ of the corresponding object."
1821(defun transient--make-predicate-map () 1882(defun transient--make-predicate-map ()
1822 (let* ((default (transient--resolve-pre-command 1883 (let* ((default (transient--resolve-pre-command
1823 (oref transient--prefix transient-suffix))) 1884 (oref transient--prefix transient-suffix)))
1824 (return (and transient-current-prefix (eq default t))) 1885 (return (and transient--stack (eq default t)))
1825 (map (make-sparse-keymap))) 1886 (map (make-sparse-keymap)))
1826 (set-keymap-parent map transient-predicate-map) 1887 (set-keymap-parent map transient-predicate-map)
1827 (when (or (and (slot-boundp transient--prefix 'transient-switch-frame) 1888 (when (or (and (slot-boundp transient--prefix 'transient-switch-frame)
@@ -1912,7 +1973,7 @@ the \"scope\" of the transient (see `transient-define-prefix').
1912This function is also called internally in which case LAYOUT and 1973This function is also called internally in which case LAYOUT and
1913EDIT may be non-nil." 1974EDIT may be non-nil."
1914 (transient--debug 'setup) 1975 (transient--debug 'setup)
1915 (transient--with-emergency-exit 1976 (transient--with-emergency-exit :setup
1916 (cond 1977 (cond
1917 ((not name) 1978 ((not name)
1918 ;; Switching between regular and edit mode. 1979 ;; Switching between regular and edit mode.
@@ -2166,7 +2227,7 @@ value. Otherwise return CHILDREN as is."
2166 2227
2167(defun transient--pre-command () 2228(defun transient--pre-command ()
2168 (transient--debug 'pre-command) 2229 (transient--debug 'pre-command)
2169 (transient--with-emergency-exit 2230 (transient--with-emergency-exit :pre-command
2170 ;; The use of `overriding-terminal-local-map' does not prevent the 2231 ;; The use of `overriding-terminal-local-map' does not prevent the
2171 ;; lookup of command remappings in the overridden maps, which can 2232 ;; lookup of command remappings in the overridden maps, which can
2172 ;; lead to a suffix being remapped to a non-suffix. We have to undo 2233 ;; lead to a suffix being remapped to a non-suffix. We have to undo
@@ -2228,14 +2289,14 @@ value. Otherwise return CHILDREN as is."
2228 (when (window-live-p transient--window) 2289 (when (window-live-p transient--window)
2229 (let ((remain-in-minibuffer-window 2290 (let ((remain-in-minibuffer-window
2230 (and (minibuffer-selected-window) 2291 (and (minibuffer-selected-window)
2231 (selected-window))) 2292 (selected-window))))
2232 (buf (window-buffer transient--window)))
2233 ;; Only delete the window if it has never shown another buffer. 2293 ;; Only delete the window if it has never shown another buffer.
2234 (unless (eq (car (window-parameter transient--window 'quit-restore)) 2294 (unless (eq (car (window-parameter transient--window 'quit-restore))
2235 'other) 2295 'other)
2236 (with-demoted-errors "Error while exiting transient: %S" 2296 (with-demoted-errors "Error while exiting transient: %S"
2237 (delete-window transient--window))) 2297 (delete-window transient--window)))
2238 (kill-buffer buf) 2298 (when-let ((buffer (get-buffer transient--buffer-name)))
2299 (kill-buffer buffer))
2239 (when remain-in-minibuffer-window 2300 (when remain-in-minibuffer-window
2240 (select-window remain-in-minibuffer-window))))) 2301 (select-window remain-in-minibuffer-window)))))
2241 2302
@@ -2253,7 +2314,10 @@ value. Otherwise return CHILDREN as is."
2253 ((and transient--prefix transient--redisplay-key) 2314 ((and transient--prefix transient--redisplay-key)
2254 (setq transient--redisplay-key nil) 2315 (setq transient--redisplay-key nil)
2255 (when transient--showp 2316 (when transient--showp
2256 (transient--show)))) 2317 (if-let ((win (minibuffer-selected-window)))
2318 (with-selected-window win
2319 (transient--show))
2320 (transient--show)))))
2257 (transient--pop-keymap 'transient--transient-map) 2321 (transient--pop-keymap 'transient--transient-map)
2258 (transient--pop-keymap 'transient--redisplay-map) 2322 (transient--pop-keymap 'transient--redisplay-map)
2259 (remove-hook 'pre-command-hook #'transient--pre-command) 2323 (remove-hook 'pre-command-hook #'transient--pre-command)
@@ -2308,7 +2372,7 @@ value. Otherwise return CHILDREN as is."
2308 (remove-hook 'minibuffer-exit-hook ,exit))) 2372 (remove-hook 'minibuffer-exit-hook ,exit)))
2309 ,@body))) 2373 ,@body)))
2310 2374
2311(static-if (>= emacs-major-version 30) 2375(static-if (>= emacs-major-version 30) ;transient--wrap-command
2312 (defun transient--wrap-command () 2376 (defun transient--wrap-command ()
2313 (cl-assert 2377 (cl-assert
2314 (>= emacs-major-version 30) nil 2378 (>= emacs-major-version 30) nil
@@ -2316,27 +2380,31 @@ value. Otherwise return CHILDREN as is."
2316 (letrec 2380 (letrec
2317 ((prefix transient--prefix) 2381 ((prefix transient--prefix)
2318 (suffix this-command) 2382 (suffix this-command)
2319 (advice (lambda (fn &rest args) 2383 (advice
2320 (interactive 2384 (lambda (fn &rest args)
2321 (lambda (spec) 2385 (interactive
2322 (let ((abort t)) 2386 (lambda (spec)
2323 (unwind-protect 2387 (let ((abort t))
2324 (prog1 (advice-eval-interactive-spec spec) 2388 (unwind-protect
2325 (setq abort nil)) 2389 (prog1 (let ((debugger #'transient--exit-and-debug))
2326 (when abort 2390 (advice-eval-interactive-spec spec))
2327 (when-let ((unwind (oref prefix unwind-suffix))) 2391 (setq abort nil))
2328 (transient--debug 'unwind-interactive) 2392 (when abort
2329 (funcall unwind suffix))
2330 (advice-remove suffix advice)
2331 (oset prefix unwind-suffix nil))))))
2332 (unwind-protect
2333 (apply fn args)
2334 (when-let ((unwind (oref prefix unwind-suffix))) 2393 (when-let ((unwind (oref prefix unwind-suffix)))
2335 (transient--debug 'unwind-command) 2394 (transient--debug 'unwind-interactive)
2336 (funcall unwind suffix)) 2395 (funcall unwind suffix))
2337 (advice-remove suffix advice) 2396 (advice-remove suffix advice)
2338 (oset prefix unwind-suffix nil))))) 2397 (oset prefix unwind-suffix nil))))))
2339 (advice-add suffix :around advice '((depth . -99))))) 2398 (unwind-protect
2399 (let ((debugger #'transient--exit-and-debug))
2400 (apply fn args))
2401 (when-let ((unwind (oref prefix unwind-suffix)))
2402 (transient--debug 'unwind-command)
2403 (funcall unwind suffix))
2404 (advice-remove suffix advice)
2405 (oset prefix unwind-suffix nil)))))
2406 (when (symbolp this-command)
2407 (advice-add suffix :around advice '((depth . -99))))))
2340 2408
2341 (defun transient--wrap-command () 2409 (defun transient--wrap-command ()
2342 (let* ((prefix transient--prefix) 2410 (let* ((prefix transient--prefix)
@@ -2346,7 +2414,8 @@ value. Otherwise return CHILDREN as is."
2346 (lambda (spec) 2414 (lambda (spec)
2347 (let ((abort t)) 2415 (let ((abort t))
2348 (unwind-protect 2416 (unwind-protect
2349 (prog1 (advice-eval-interactive-spec spec) 2417 (prog1 (let ((debugger #'transient--exit-and-debug))
2418 (advice-eval-interactive-spec spec))
2350 (setq abort nil)) 2419 (setq abort nil))
2351 (when abort 2420 (when abort
2352 (when-let ((unwind (oref prefix unwind-suffix))) 2421 (when-let ((unwind (oref prefix unwind-suffix)))
@@ -2357,7 +2426,8 @@ value. Otherwise return CHILDREN as is."
2357 (advice-body 2426 (advice-body
2358 (lambda (fn &rest args) 2427 (lambda (fn &rest args)
2359 (unwind-protect 2428 (unwind-protect
2360 (apply fn args) 2429 (let ((debugger #'transient--exit-and-debug))
2430 (apply fn args))
2361 (when-let ((unwind (oref prefix unwind-suffix))) 2431 (when-let ((unwind (oref prefix unwind-suffix)))
2362 (transient--debug 'unwind-command) 2432 (transient--debug 'unwind-command)
2363 (funcall unwind suffix)) 2433 (funcall unwind suffix))
@@ -2366,7 +2436,8 @@ value. Otherwise return CHILDREN as is."
2366 (setq advice `(lambda (fn &rest args) 2436 (setq advice `(lambda (fn &rest args)
2367 (interactive ,advice-interactive) 2437 (interactive ,advice-interactive)
2368 (apply ',advice-body fn args))) 2438 (apply ',advice-body fn args)))
2369 (advice-add suffix :around advice '((depth . -99)))))) 2439 (when (symbolp this-command)
2440 (advice-add suffix :around advice '((depth . -99)))))))
2370 2441
2371(defun transient--premature-post-command () 2442(defun transient--premature-post-command ()
2372 (and (equal (this-command-keys-vector) []) 2443 (and (equal (this-command-keys-vector) [])
@@ -2385,7 +2456,7 @@ value. Otherwise return CHILDREN as is."
2385(defun transient--post-command () 2456(defun transient--post-command ()
2386 (unless (transient--premature-post-command) 2457 (unless (transient--premature-post-command)
2387 (transient--debug 'post-command) 2458 (transient--debug 'post-command)
2388 (transient--with-emergency-exit 2459 (transient--with-emergency-exit :post-command
2389 (cond (transient--exitp (transient--post-exit)) 2460 (cond (transient--exitp (transient--post-exit))
2390 ;; If `this-command' is the current transient prefix, then we 2461 ;; If `this-command' is the current transient prefix, then we
2391 ;; have already taken care of updating the transient buffer... 2462 ;; have already taken care of updating the transient buffer...
@@ -2509,18 +2580,22 @@ value. Otherwise return CHILDREN as is."
2509 this-command)) 2580 this-command))
2510 (key-description (this-command-keys-vector)) 2581 (key-description (this-command-keys-vector))
2511 transient--exitp 2582 transient--exitp
2512 (cond ((stringp (car args)) 2583 (cond ((keywordp (car args))
2584 (format ", from: %s"
2585 (substring (symbol-name (car args)) 1)))
2586 ((stringp (car args))
2513 (concat ", " (apply #'format args))) 2587 (concat ", " (apply #'format args)))
2514 (args 2588 ((functionp (car args))
2515 (concat ", " (apply (car args) (cdr args)))) 2589 (concat ", " (apply (car args) (cdr args))))
2516 (""))) 2590 ("")))
2517 (apply #'message arg args))))) 2591 (apply #'message arg args)))))
2518 2592
2519(defun transient--emergency-exit () 2593(defun transient--emergency-exit (&optional id)
2520 "Exit the current transient command after an error occurred. 2594 "Exit the current transient command after an error occurred.
2521When no transient is active (i.e., when `transient--prefix' is 2595When no transient is active (i.e., when `transient--prefix' is
2522nil) then do nothing." 2596nil) then do nothing. Optional ID is a keyword identifying the
2523 (transient--debug 'emergency-exit) 2597exit."
2598 (transient--debug 'emergency-exit id)
2524 (when transient--prefix 2599 (when transient--prefix
2525 (setq transient--stack nil) 2600 (setq transient--stack nil)
2526 (setq transient--exitp t) 2601 (setq transient--exitp t)
@@ -2544,6 +2619,7 @@ nil) then do nothing."
2544 2619
2545(defun transient--get-pre-command (&optional cmd enforce-type) 2620(defun transient--get-pre-command (&optional cmd enforce-type)
2546 (or (and (not (eq enforce-type 'non-suffix)) 2621 (or (and (not (eq enforce-type 'non-suffix))
2622 (symbolp cmd)
2547 (lookup-key transient--predicate-map (vector cmd))) 2623 (lookup-key transient--predicate-map (vector cmd)))
2548 (and (not (eq enforce-type 'suffix)) 2624 (and (not (eq enforce-type 'suffix))
2549 (transient--resolve-pre-command 2625 (transient--resolve-pre-command
@@ -3087,14 +3163,14 @@ infix command determines what the new value should be, based
3087on the previous value.") 3163on the previous value.")
3088 3164
3089(cl-defmethod transient-infix-read :around ((obj transient-infix)) 3165(cl-defmethod transient-infix-read :around ((obj transient-infix))
3090 "Refresh the transient buffer buffer calling the next method. 3166 "Refresh the transient buffer and call the next method.
3091 3167
3092Also wrap `cl-call-next-method' with two macros: 3168Also wrap `cl-call-next-method' with two macros:
3093- `transient--with-suspended-override' allows use of minibuffer. 3169- `transient--with-suspended-override' allows use of minibuffer.
3094- `transient--with-emergency-exit' arranges for the transient to 3170- `transient--with-emergency-exit' arranges for the transient to
3095 be exited in case of an error." 3171 be exited in case of an error."
3096 (transient--show) 3172 (transient--show)
3097 (transient--with-emergency-exit 3173 (transient--with-emergency-exit :infix-read
3098 (transient--with-suspended-override 3174 (transient--with-suspended-override
3099 (cl-call-next-method obj)))) 3175 (cl-call-next-method obj))))
3100 3176
@@ -3176,8 +3252,10 @@ The last value is \"don't use any of these switches\"."
3176 "Elsewhere use the reader of the infix command COMMAND. 3252 "Elsewhere use the reader of the infix command COMMAND.
3177Use this if you want to share an infix's history with a regular 3253Use this if you want to share an infix's history with a regular
3178stand-alone command." 3254stand-alone command."
3179 (cl-letf (((symbol-function #'transient--show) #'ignore)) 3255 (if-let ((obj (transient--suffix-prototype command)))
3180 (transient-infix-read (transient--suffix-prototype command)))) 3256 (cl-letf (((symbol-function #'transient--show) #'ignore))
3257 (transient-infix-read obj))
3258 (error "Not a suffix command: `%s'" command)))
3181 3259
3182;;;; Readers 3260;;;; Readers
3183 3261
@@ -3354,7 +3432,7 @@ the set, saved or default value for PREFIX."
3354 (transient--init-suffixes prefix))))) 3432 (transient--init-suffixes prefix)))))
3355 3433
3356(defun transient-get-value () 3434(defun transient-get-value ()
3357 (transient--with-emergency-exit 3435 (transient--with-emergency-exit :get-value
3358 (cl-mapcan (lambda (obj) 3436 (cl-mapcan (lambda (obj)
3359 (and (or (not (slot-exists-p obj 'unsavable)) 3437 (and (or (not (slot-exists-p obj 'unsavable))
3360 (not (oref obj unsavable))) 3438 (not (oref obj unsavable)))
@@ -3565,7 +3643,7 @@ have a history of their own.")
3565 (propertize "\n" 'face face 'line-height t)))) 3643 (propertize "\n" 'face face 'line-height t))))
3566 3644
3567(defmacro transient-with-shadowed-buffer (&rest body) 3645(defmacro transient-with-shadowed-buffer (&rest body)
3568 "While in the transient buffer, temporarily make the shadowed buffer current." 3646 "While in the transient buffer, temporarly make the shadowed buffer current."
3569 (declare (indent 0) (debug t)) 3647 (declare (indent 0) (debug t))
3570 `(with-current-buffer (or transient--shadowed-buffer (current-buffer)) 3648 `(with-current-buffer (or transient--shadowed-buffer (current-buffer))
3571 ,@body)) 3649 ,@body))
@@ -3620,7 +3698,8 @@ have a history of their own.")
3620 (lambda (column) 3698 (lambda (column)
3621 (transient--maybe-pad-keys column group) 3699 (transient--maybe-pad-keys column group)
3622 (transient-with-shadowed-buffer 3700 (transient-with-shadowed-buffer
3623 (let ((rows (mapcar #'transient-format (oref column suffixes)))) 3701 (let* ((transient--pending-group column)
3702 (rows (mapcar #'transient-format (oref column suffixes))))
3624 (when-let ((desc (transient-format-description column))) 3703 (when-let ((desc (transient-format-description column)))
3625 (push desc rows)) 3704 (push desc rows))
3626 (flatten-tree rows)))) 3705 (flatten-tree rows))))
@@ -3629,10 +3708,15 @@ have a history of their own.")
3629 transient-align-variable-pitch)) 3708 transient-align-variable-pitch))
3630 (rs (apply #'max (mapcar #'length columns))) 3709 (rs (apply #'max (mapcar #'length columns)))
3631 (cs (length columns)) 3710 (cs (length columns))
3632 (cw (mapcar (lambda (col) 3711 (cw (mapcar (let ((widths (oref transient--prefix column-widths)))
3633 (apply #'max 3712 (lambda (col)
3634 (mapcar (if vp #'transient--pixel-width #'length) 3713 (apply
3635 col))) 3714 #'max
3715 (if-let ((min (pop widths)))
3716 (if vp (* min (transient--pixel-width " ")) min)
3717 0)
3718 (mapcar (if vp #'transient--pixel-width #'length)
3719 col))))
3636 columns)) 3720 columns))
3637 (cc (transient--seq-reductions-from 3721 (cc (transient--seq-reductions-from
3638 (apply-partially #'+ (* 3 (if vp (transient--pixel-width " ") 1))) 3722 (apply-partially #'+ (* 3 (if vp (transient--pixel-width " ") 1)))
@@ -3908,7 +3992,10 @@ If the OBJ's `key' is currently unreachable, then apply the face
3908 (face (slot-value obj slot))) 3992 (face (slot-value obj slot)))
3909 (if (and (not (facep face)) 3993 (if (and (not (facep face))
3910 (functionp face)) 3994 (functionp face))
3911 (funcall face) 3995 (let ((transient--pending-suffix obj))
3996 (if (= (car (func-arity face)) 1)
3997 (funcall face obj)
3998 (funcall face)))
3912 face))) 3999 face)))
3913 4000
3914(defun transient--key-face (&optional cmd enforce-type) 4001(defun transient--key-face (&optional cmd enforce-type)