diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi index 4aa0ebf97d6..f2e06009771 100644 --- a/doc/misc/transient.texi +++ b/doc/misc/transient.texi @@ -31,7 +31,7 @@ General Public License for more details. @finalout @titlepage @title Transient User and Developer Manual -@subtitle for version 0.9.4 +@subtitle for version 0.10.0 @author Jonas Bernoulli @page @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}. @noindent -This manual is for Transient version 0.9.4. +This manual is for Transient version 0.10.0. @insertcopying @end ifnottex @@ -1692,15 +1692,28 @@ If the current command was invoked from the transient prefix command @var{PREFIX}, then it returns the active infix arguments. If the current command was not invoked from @var{PREFIX}, then it returns the set, saved or default value for @var{PREFIX}. + +PREFIX may also be a list of prefixes. If no prefix is active, the +fallback value of the first of these prefixes is used. + +The generic function @code{transient-prefix-value} is used to determine the +returned value. + +This function is intended to be used by suffix commands, whether they +are invoked from a menu or not. It is not intended to be used when +setting up a menu and its suffixes, in which case @code{transient-get-value} +should be used. @end defun @defun transient-get-value -This function returns the value of the current prefix. +This function returns the value of the erant prefix. -This is mostly intended for internal use, but may also be of use -in @code{transient-set-value} and @code{transient-save-value} methods. Unlike -@code{transient-args}, this does not include the values of suffixes whose -@code{unsavable} slot is non-@code{nil}. +This function is intended to be used when setting up a menu and its +suffixes. It is not intended to be used when a suffix command is +invoked, whether from a menu or not, in which case @code{transient-args} +should be used. In other words, use this, e.g., in a suffixes @code{:if*} +or @code{:inapt-if*} predicate and @code{:description} function, but never in its +@code{interactive} form or function body. @end defun @defun transient-arg-value arg args @@ -2406,6 +2419,21 @@ function, that is called to get the value. If the slot is unbound, @defun transient-prefix-value obj This generic function returns the value of the prefix object @var{OBJ}. + +OBJ is a prototype object and is only used to select the appropriate +method of this generic function. This function does not return the +value of that object. Instead it extracts the name of the respective +command from the object and uses that to collect the current values +from the suffixes of the prefix from which the current command was +invoked. If the current command was not invoked from the identified +prefix, then this method returns the set, save or default value, as +described for @code{transient-args}. + +This function is only intended to be used by @code{transient-args}. It is +not defined as an internal function because third-party packages may +define their own methods. That does not mean that it would be a good +idea to call it for any other purpose. + The respective generic function for infix and suffix objects is named @code{transient-infix-value}. @end defun @@ -2612,6 +2640,45 @@ primary @code{transient-init-value} method is called instead. then this slot has to be set to the same value for all of them. You probably don't want that. +@item +@code{remember-value} When a suffix command is invoked, which can consume +the prefix's value (which depends on the suffix slot @code{transient} and +the prefix slots @code{transient-suffix} and @code{transient-non-suffix}), then +the value is automatically pushed to the prefix's value history. + +This slot allows additionally setting or even saving the value, so +that it becomes the initial value when the menu is invoked again. + +Beside @code{nil}, the value can be one of these symbols: + +@itemize +@item +@code{export} Set the value when it is exported. That is the time when +the value would ordinarily just be pushed to the history stack. + +@item +@code{exit} Set the value when the menu is exited, except when that is +done using a command whose sole purpose is to quit the menu. + +@item +@code{quit} Set the value when the menu is quit, using a command whose +sole purpose is to do so. +@end itemize + +The value can also be a list of one or more of these symbols and +optionally also the symbol @code{save}. + +@itemize +@item +@code{save} Instead of merely setting the value, save it, so that it will +be used in future Emacs sessions. At least one other symbol has +to be used together with this. +@end itemize + +The value can also be a (quoted) variable, whose value is a list of +symbols as described above. Ideally an option should be used, since +not all users will find the automatic saving of the value desirable. + @item @code{incompatible} A list of lists. Each sub-list specifies a set of mutually exclusive arguments. Enabling one of these arguments diff --git a/lisp/transient.el b/lisp/transient.el index 44c6e6ce550..1f458be8829 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -5,7 +5,7 @@ ;; Author: Jonas Bernoulli ;; URL: https://github.com/magit/transient ;; Keywords: extensions -;; Version: 0.9.4 +;; Version: 0.10.0 ;; SPDX-License-Identifier: GPL-3.0-or-later @@ -33,7 +33,7 @@ ;;; Code: ;;;; Frontmatter -(defconst transient-version "v0.9.4-8-g6bc543d5-builtin") +(defconst transient-version "0.10.0-builtin") (require 'cl-lib) (require 'eieio) @@ -52,6 +52,19 @@ (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") @@ -526,6 +539,11 @@ give you as many additional suffixes as you hoped.)" "Face used for inactive arguments." :group 'transient-faces) +(defface transient-inapt-argument '((t :inherit shadow :weight bold)) + "Face used for inapt arguments with a (currently ignored) value. +Depending on the type this is used for the argument and/or value." + :group 'transient-faces) + (defface transient-value '((t :inherit font-lock-string-face :weight bold)) "Face used for values." :group 'transient-faces) @@ -740,6 +758,7 @@ If `transient-save-history' is nil, then do nothing." (transient-non-suffix :initarg :transient-non-suffix :initform nil) (transient-switch-frame :initarg :transient-switch-frame) (refresh-suffixes :initarg :refresh-suffixes :initform nil) + (remember-value :initarg :remember-value :initform nil) (environment :initarg :environment :initform nil) (incompatible :initarg :incompatible :initform nil) (suffix-description :initarg :suffix-description) @@ -769,6 +788,8 @@ the prototype is stored in the clone's `prototype' slot.") :initarg :level :initform nil :documentation "Enable if level of prefix is equal or greater.") + (inactive + :initform nil) (if :initarg :if :initform nil @@ -1505,7 +1526,7 @@ Intended for use in a group's `:setup-children' function." suffix prefix loc "suffixes and groups cannot be siblings")) (t - (when-let* (((not (eq keep-other 'always))) + (when-let* ((_(not (eq keep-other 'always))) (bindingp (listp suf)) (key (transient--suffix-key suf)) (conflict (car (transient--locate-child prefix key))) @@ -1808,6 +1829,10 @@ This is bound while the suffixes are drawn in the transient buffer.") mwheel-scroll scroll-bar-toolkit-scroll)) +(defvar transient--quit-commands + '(transient-quit-one + transient-quit-all)) + ;;;; Identities (defun transient-active-prefix (&optional prefixes) @@ -1936,10 +1961,9 @@ probably use this instead: (t nil)))) ((and-let* ((obj (transient--suffix-prototype (or command this-command))) (obj (clone obj))) - (progn - (transient-init-scope obj) - (transient-init-value obj) - obj))))) + (transient-init-scope obj) + (transient-init-value obj) + obj)))) (defun transient--suffix-prototype (command) (or (get command 'transient--suffix) @@ -2202,9 +2226,11 @@ of the corresponding object." (cond ((not alt) (define-key map kbd cmd)) ((eq alt cmd)) - ((transient--inapt-suffix-p obj)) - ((and-let* ((obj (transient-suffix-object alt))) - (transient--inapt-suffix-p obj)) + ((oref obj inactive)) + ((oref obj inapt)) + ((and-let* ((alt (transient-suffix-object alt))) + (or (oref alt inactive) + (oref alt inapt))) (define-key map kbd cmd)) (transient-detect-key-conflicts (error "Cannot bind %S to %s and also %s" @@ -2242,6 +2268,7 @@ of the corresponding object." ((cl-typep obj 'transient-infix) 'infix) (t 'suffix))) (pre (cond + ((oref obj inactive) nil) ((oref obj inapt) #'transient--do-warn-inapt) ((slot-boundp obj 'transient) (pcase (list kind @@ -2378,7 +2405,7 @@ value. Otherwise return CHILDREN as is.") ;; invoked suffix indicates that it has updated that. (setq transient--refreshp (oref transient--prefix refresh-suffixes)) ;; Otherwise update the prefix value from suffix values. - (oset transient--prefix value (transient-get-value)))) + (oset transient--prefix value (transient--get-extended-value)))) (transient--init-objects name layout params) (transient--init-keymaps)) @@ -2392,9 +2419,14 @@ value. Otherwise return CHILDREN as is.") (setq transient--prefix (transient--init-prefix name params)) (setq name (oref transient--prefix command))) (setq transient--refreshp (oref transient--prefix refresh-suffixes)) - (setq transient--layout (or (and (not transient--refreshp) layout) - (transient--init-suffixes name))) - (setq transient--suffixes (transient--flatten-suffixes transient--layout))) + (cond ((and (not transient--refreshp) layout) + (setq transient--layout layout) + (setq transient--suffixes (transient--flatten-suffixes layout))) + (t + (setq transient--suffixes nil) + (setq transient--layout (transient--init-suffixes name)) + (setq transient--suffixes (nreverse transient--suffixes)))) + (slot-makeunbound transient--prefix 'value)) (defun transient--init-prefix (name &optional params) (let ((obj (let ((proto (get name 'transient--prefix))) @@ -2439,57 +2471,62 @@ value. Otherwise return CHILDREN as is.") (pcase-let* ((`[,class ,args ,children] spec) (level (or (plist-get args :level) transient--default-child-level))) - (and-let* (((transient--use-level-p level)) + (and-let* ((_(transient--use-level-p level)) (obj (apply class :parent parent :level level args)) - ((transient--use-suffix-p obj)) - ((prog1 t - (when (transient--inapt-suffix-p obj) - (oset obj inapt t)))) + (_(transient--use-suffix-p obj)) + (_(prog1 t + (when (transient--inapt-suffix-p obj) + (oset obj inapt t)))) (suffixes (mapcan (lambda (c) (transient--init-child levels c obj)) (transient-setup-children obj children)))) - (progn - (oset obj suffixes suffixes) - (list obj))))) + (oset obj suffixes suffixes) + (list obj)))) (defun transient--init-suffix (levels spec parent) - (pcase-let* ((`(,class . ,args) spec) - (cmd (plist-get args :command)) - (_ (transient--load-command-if-autoload cmd)) - (key (plist-get args :key)) - (key (and key (kbd key))) - (proto (and cmd (transient--suffix-prototype cmd))) - (level (or (alist-get (cons cmd key) levels nil nil #'equal) - (alist-get cmd levels) - (plist-get args :level) - (and proto (oref proto level)) - transient--default-child-level)) - (args (plist-put (copy-sequence args) :level level))) - (when (transient--use-level-p level) - (let ((obj (if (child-of-class-p class 'transient-information) + (let* ((class (car spec)) + (args (cdr spec)) + (cmd (plist-get args :command)) + (_ (transient--load-command-if-autoload cmd)) + (key (plist-get args :key)) + (key (and key (kbd key))) + (proto (and cmd (transient--suffix-prototype cmd))) + (level (or (alist-get (cons cmd key) levels nil nil #'equal) + (alist-get cmd levels) + (plist-get args :level) + (and proto (oref proto level)) + transient--default-child-level)) + (args (plist-put (copy-sequence args) :level level)) + (obj (if (child-of-class-p class 'transient-information) (apply class :parent parent args) (unless (and cmd (symbolp cmd)) (error "BUG: Non-symbolic suffix command: %s" cmd)) (if proto (apply #'clone proto :parent parent args) - (apply class :command cmd :parent parent args))))) - (cond ((not cmd)) - ((commandp cmd)) - ((or (cl-typep obj 'transient-switch) - (cl-typep obj 'transient-option)) - ;; As a temporary special case, if the package was compiled - ;; with an older version of Transient, then we must define - ;; "anonymous" switch and option commands here. - (defalias cmd #'transient--default-infix-command)) - ((transient--use-suffix-p obj) - (error "Suffix command %s is not defined or autoloaded" cmd))) - (unless (cl-typep obj 'transient-information) - (transient--init-suffix-key obj)) - (when (transient--use-suffix-p obj) - (if (transient--inapt-suffix-p obj) - (oset obj inapt t) - (transient-init-scope obj) - (transient-init-value obj)) - (list obj)))))) + (apply class :command cmd :parent parent args)))) + (active (and (transient--use-level-p level) + (transient--use-suffix-p obj))) + (inapt (and active (transient--inapt-suffix-p obj))) + (active (and active (not inapt)))) + (cond (inapt + (oset obj inapt t)) + ((not active) + (oset obj inactive t))) + (cond ((not cmd)) + ((commandp cmd)) + ((or (cl-typep obj 'transient-switch) + (cl-typep obj 'transient-option)) + ;; As a temporary special case, if the package was compiled + ;; with an older version of Transient, then we must define + ;; "anonymous" switch and option commands here. + (defalias cmd #'transient--default-infix-command)) + (active + (error "Suffix command %s is not defined or autoloaded" cmd))) + (cond ((not (cl-typep obj 'transient-information)) + (transient--init-suffix-key obj) + (transient-init-scope obj) + (transient-init-value obj) + (push obj transient--suffixes))) + (list obj))) (cl-defmethod transient--init-suffix-key ((obj transient-suffix)) (unless (slot-boundp obj 'key) @@ -2498,9 +2535,9 @@ value. Otherwise return CHILDREN as is.") (cl-defmethod transient--init-suffix-key ((obj transient-argument)) (if (transient-switches--eieio-childp obj) (cl-call-next-method obj) - (when-let* (((not (slot-boundp obj 'shortarg))) + (when-let* ((_(not (slot-boundp obj 'shortarg))) (argument (oref obj argument)) - ((stringp argument)) + (_(stringp argument)) (shortarg (transient--derive-shortarg argument))) (oset obj shortarg shortarg)) (unless (slot-boundp obj 'key) @@ -2583,9 +2620,9 @@ value. Otherwise return CHILDREN as is.") :inapt-if-derived :inapt-if-not-derived)))) (defun transient--load-command-if-autoload (cmd) - (when-let* (((symbolp cmd)) + (when-let* ((_(symbolp cmd)) (fn (symbol-function cmd)) - ((autoloadp fn))) + (_(autoloadp fn))) (transient--debug " autoload %s" cmd) (autoload-do-load fn))) @@ -2630,8 +2667,7 @@ value. Otherwise return CHILDREN as is.") ((memq this-command '(transient-update transient-quit-seq)) (transient--pop-keymap 'transient--redisplay-map)) ((and transient--helpp - (not (memq this-command '(transient-quit-one - transient-quit-all)))) + (not (memq this-command transient--quit-commands))) (cond ((transient-help) (transient--do-suspend) @@ -2641,9 +2677,8 @@ value. Otherwise return CHILDREN as is.") (setq this-command 'transient-undefined)))) ((and transient--editp (transient-suffix-object) - (not (memq this-command '(transient-quit-one - transient-quit-all - transient-help)))) + (not (memq this-command + (cons 'transient-help transient--quit-commands)))) (setq this-command 'transient-set-level) (transient--wrap-command)) (t @@ -2651,6 +2686,7 @@ value. Otherwise return CHILDREN as is.") (let ((exitp (eq (transient--call-pre-command) transient--exit))) (transient--wrap-command) (when exitp + (transient--maybe-set-value 'exit) (transient--pre-exit))))))) (defun transient--pre-exit () @@ -2681,7 +2717,8 @@ value. Otherwise return CHILDREN as is.") (setq transient-current-prefix transient--prefix) (setq transient-current-command (oref transient--prefix command)) (setq transient-current-suffixes transient--suffixes) - (transient--history-push transient--prefix)) + (unless (transient--maybe-set-value 'export) + (transient--history-push transient--prefix))) (defun transient--suspend-override (&optional nohide) (transient--debug 'suspend-override) @@ -2898,7 +2935,7 @@ value. Otherwise return CHILDREN as is.") (push (list (oref transient--prefix command) transient--layout transient--editp - :value (transient-get-value) + :value (transient--get-extended-value) :return (oref transient--prefix return) :scope (oref transient--prefix scope)) transient--stack)) @@ -3375,19 +3412,16 @@ For example: (transient-undefined)))) (transient-define-suffix transient-toggle-level-limit () - "Toggle whether to temporarily displayed suffixes on all levels." + "Toggle whether to temporarily display suffixes on all levels." :description (lambda () (cond - ((= transient-default-level transient--max-level) - "Always displaying all levels") (transient--all-levels-p (format "Hide suffix %s" (propertize (format "levels > %s" (oref (transient-prefix-object) level)) 'face 'transient-higher-level))) ("Show all suffix levels"))) - :inapt-if (lambda () (= transient-default-level transient--max-level)) :transient t (interactive) (setq transient--all-levels-p (not transient--all-levels-p)) @@ -3815,7 +3849,7 @@ prompt." (cl-defmethod transient-infix-set :after ((obj transient-argument) value) "Unset incompatible infix arguments." - (when-let* ((value) + (when-let* ((_ value) (val (transient-infix-value obj)) (arg (if (slot-boundp obj 'argument) (oref obj argument) @@ -3829,15 +3863,15 @@ prompt." (and (not (equal val arg)) (mapcan (apply-partially filter val) spec))))) (dolist (obj transient--suffixes) - (when-let* (((cl-typep obj 'transient-argument)) + (when-let* ((_(cl-typep obj 'transient-argument)) (val (transient-infix-value obj)) (arg (if (slot-boundp obj 'argument) (oref obj argument) (oref obj argument-format))) - ((if (equal val arg) - (member arg incomp) - (or (member val incomp) - (member arg incomp))))) + (_(if (equal val arg) + (member arg incomp) + (or (member val incomp) + (member arg incomp))))) (transient-infix-set obj nil))))) (defun transient-prefix-set (value) @@ -3852,8 +3886,27 @@ Only intended for use by `transient-set'. See also `transient-prefix-set'.") (cl-defmethod transient-set-value ((obj transient-prefix)) - (oset (oref obj prototype) value (transient-get-value)) - (transient--history-push obj)) + (let ((value (transient--get-savable-value))) + (oset (oref obj prototype) value value) + (transient--history-push obj value))) + +(defun transient--maybe-set-value (event) + "Maybe set the value, subject to EVENT and the `remember-value' slot." + (let* ((event (if (and (eq event 'exit) + (memq this-command transient--quit-commands)) + 'quit + event)) + (spec (oref transient--prefix remember-value)) + (spec (cond ((listp spec) spec) + ((memq spec '(export exit quit)) + (list spec)) + ((boundp spec) + (symbol-value spec))))) + (and (memq event spec) + (prog1 t + (if (memq 'save spec) + (transient-save-value transient--prefix) + (transient-set-value transient--prefix)))))) ;;;; Save @@ -3861,11 +3914,11 @@ See also `transient-prefix-set'.") "Save the value of the transient prefix OBJ.") (cl-defmethod transient-save-value ((obj transient-prefix)) - (let ((value (transient-get-value))) + (let ((value (transient--get-savable-value))) (oset (oref obj prototype) value value) (setf (alist-get (oref obj command) transient-values) value) - (transient-save-values)) - (transient--history-push obj)) + (transient-save-values) + (transient--history-push obj value))) ;;;; Reset @@ -3877,8 +3930,8 @@ See also `transient-prefix-set'.") (oset obj value value) (oset (oref obj prototype) value value) (setf (alist-get (oref obj command) transient-values nil 'remove) nil) - (transient-save-values)) - (transient--history-push obj) + (transient-save-values) + (transient--history-push obj value)) (mapc #'transient-init-value transient--suffixes)) ;;;; Get @@ -3895,29 +3948,55 @@ PREFIX may also be a list of prefixes. If no prefix is active, the fallback value of the first of these prefixes is used. The generic function `transient-prefix-value' is used to determine the -returned value." +returned value. + +This function is intended to be used by suffix commands, whether they +are invoked from a menu or not. It is not intended to be used when +setting up a menu and its suffixes, in which case `transient-get-value' +should be used." (when (listp prefix) (setq prefix (car (or (memq transient-current-command prefix) prefix)))) (if-let* ((obj (get prefix 'transient--prefix))) + ;; This OBJ is only used for dispatch purposes; see below. (transient-prefix-value obj) (error "Not a transient prefix: %s" prefix))) (cl-defgeneric transient-prefix-value (obj) - "Return the value of the prefix object OBJ. -This function is used by `transient-args'.") + "Return a list of the values of the suffixes of the specified prefix. + +OBJ is a prototype object and is only used to select the appropriate +method of this generic function. Transient itself only provides one +such method, which should be suitable for most prefixes. + +This function is only intended to be used by `transient-args'. It is +not defined as an internal function because third-party packages may +define their own methods. That does not mean that it would be a good +idea to call it for any other purpose.") (cl-defmethod transient-prefix-value ((obj transient-prefix)) - "Return a list of the values of the suffixes the prefix object OBJ. -Use `transient-infix-value' to collect the values of individual suffix -objects." - (mapcan #'transient--get-wrapped-value + "Return a list of the values of the suffixes of the specified prefix. + +OBJ is a prototype object. This method does not return the value of +that object. Instead it extracts the name of the respective command +from the object and uses that to collect the current values from the +suffixes of the prefix from which the current command was invoked. +If the current command was not invoked from the identified prefix, +then this method returns the set, save or default value, as described +for `transient-args'. + +This method uses `transient-suffixes' (which see) to determine the +suffix objects and then extracts the value(s) from those objects." + (mapcan (lambda (obj) + (and (not (oref obj inactive)) + (not (oref obj inapt)) + (transient--get-wrapped-value obj))) (transient-suffixes (oref obj command)))) (defun transient-suffixes (prefix) "Return the suffix objects of the transient prefix command PREFIX. If PREFIX is not the current prefix, initialize the suffixes so that -they can be returned. Doing so doesn't have any side-effects." +they can be returned. That does not cause the menu to be displayed." (if (eq transient-current-command prefix) transient-current-suffixes (let ((transient--prefix (transient--init-prefix prefix))) @@ -3925,24 +4004,46 @@ they can be returned. Doing so doesn't have any side-effects." (transient--init-suffixes prefix))))) (defun transient-get-value () - "Return the value of the current prefix. + "Return the value of the extant prefix. -This is mostly intended for internal use, but may also be of use -in `transient-set-value' and `transient-save-value' methods. Unlike -`transient-args', this does not include the values of suffixes whose -`unsavable' slot is non-nil." +This function is intended to be used when setting up a menu and its +suffixes. It is not intended to be used when a suffix command is +invoked, whether from a menu or not, in which case `transient-args' +should be used." (transient--with-emergency-exit :get-value (mapcan (lambda (obj) - (and (or (not (slot-exists-p obj 'unsavable)) - (not (oref obj unsavable))) + (and (not (oref obj inactive)) + (not (oref obj inapt)) (transient--get-wrapped-value obj))) - (or transient--suffixes transient-current-suffixes)))) + transient--suffixes))) + +(defun transient--get-extended-value () + "Return the extended value of the extant prefix. + +Unlike `transient-get-value' also include the values of inactive and +inapt arguments. This function is mainly intended for internal use. +It is used to preserve the full value when a menu is being refreshed, +including the presently ineffective parts." + (transient--with-emergency-exit :get-value + (mapcan #'transient--get-wrapped-value transient--suffixes))) + +(defun transient--get-savable-value () + "Return the value of the extant prefix, excluding unsavable parts. + +This function is only intended for internal use. It is used to save +the value." + (transient--with-emergency-exit :get-savable-value + (mapcan (lambda (obj) + (and (not (and (slot-exists-p obj 'unsavable) + (oref obj unsavable))) + (transient--get-wrapped-value obj))) + transient--suffixes))) (defun transient--get-wrapped-value (obj) "Return a list of the value(s) of suffix object OBJ. Internally a suffix only ever has one value, stored in its `value' -slot, but callers of `transient-args', wish to treat the values of +slot, but callers of `transient-args' wish to treat the values of certain suffixes as multiple values. That translation is handled here. The object's `multi-value' slot specifies whether and how to interpret the `value' as multiple values." @@ -4024,13 +4125,13 @@ Append \"=\ to ARG to indicate that it is an option." ;;;; Return (defun transient-init-return (obj) - (when-let* ((transient--stack) + (when-let* ((_ transient--stack) (command (oref obj command)) (suffix-obj (transient-suffix-object command)) - ((memq (if (slot-boundp suffix-obj 'transient) - (oref suffix-obj transient) - (oref transient-current-prefix transient-suffix)) - (list t 'recurse #'transient--do-recurse)))) + (_(memq (if (slot-boundp suffix-obj 'transient) + (oref suffix-obj transient) + (oref transient-current-prefix transient-suffix)) + (list t 'recurse #'transient--do-recurse)))) (oset obj return t))) ;;;; Scope @@ -4116,14 +4217,15 @@ Otherwise return the value of the `command' slot." (or (oref obj history-key) (oref obj command))) -(cl-defgeneric transient--history-push (obj) - "Push the current value of OBJ to its entry in `transient-history'.") +(cl-defgeneric transient--history-push (obj value) + "Push VALUE to OBJ's entry in `transient-history'.") -(cl-defmethod transient--history-push ((obj transient-prefix)) +(cl-defmethod transient--history-push + ((obj transient-prefix) + &optional (value (transient--get-savable-value))) (let ((key (transient--history-key obj))) (setf (alist-get key transient-history) - (let ((args (transient-get-value))) - (cons args (delete args (alist-get key transient-history))))))) + (cons value (delete value (alist-get key transient-history)))))) (cl-defgeneric transient--history-init (obj) "Initialize OBJ's `history' slot. @@ -4132,8 +4234,8 @@ have a history of their own.") (cl-defmethod transient--history-init ((obj transient-prefix)) "Initialize OBJ's `history' slot from the variable `transient-history'." - (let ((val (oref obj value))) - (oset obj history + (oset obj history + (let ((val (transient--get-extended-value))) (cons val (delete val (alist-get (transient--history-key obj) transient-history)))))) @@ -4339,6 +4441,12 @@ have a history of their own.") (when groups (insert ?\n))))) +(defun transient--active-suffixes (group) + (seq-remove (lambda (suffix) + (and (cl-typep suffix 'transient-suffix) + (oref suffix inactive))) + (oref group suffixes))) + (defvar transient--max-group-level 1) (cl-defgeneric transient--insert-group (group) @@ -4357,7 +4465,7 @@ have a history of their own.") (cl-defmethod transient--insert-group ((group transient-row)) (transient--maybe-pad-keys group) - (dolist (suffix (oref group suffixes)) + (dolist (suffix (transient--active-suffixes group)) (insert (transient-with-shadowed-buffer (transient-format suffix))) (insert " ")) (insert ?\n)) @@ -4365,7 +4473,7 @@ have a history of their own.") (cl-defmethod transient--insert-group ((group transient-column) &optional skip-empty) (transient--maybe-pad-keys group) - (dolist (suffix (oref group suffixes)) + (dolist (suffix (transient--active-suffixes group)) (let ((str (transient-with-shadowed-buffer (transient-format suffix)))) (unless (and (not skip-empty) (equal str "")) (insert str) @@ -4384,7 +4492,8 @@ have a history of their own.") `(,@(and-let* ((desc (transient-format-description column))) (list desc)) ,@(let ((transient--pending-group column)) - (mapcar #'transient-format (oref column suffixes)))))) + (mapcar #'transient-format + (transient--active-suffixes column)))))) (oref group suffixes))) (stops (transient--column-stops columns))) (dolist (row (apply #'transient--mapn #'list columns)) @@ -4572,15 +4681,15 @@ apply the face `transient-unreachable' to the complete string." (and (slot-boundp transient--prefix 'suffix-description) (funcall (oref transient--prefix suffix-description) obj))))) - (when-let* ((transient--docsp) - ((slot-boundp obj 'command)) + (when-let* ((_ transient--docsp) + (_(slot-boundp obj 'command)) (cmd (oref obj command)) - ((not (memq 'transient--default-infix-command - (function-alias-p cmd)))) + (_(not (memq 'transient--default-infix-command + (function-alias-p cmd)))) (docstr (ignore-errors (documentation cmd))) (docstr (string-trim (substring docstr 0 (string-match "\\.?\n" docstr)))) - ((not (equal docstr "")))) + (_(not (equal docstr "")))) (setq desc (format-spec transient-show-docstring-format `((?c . ,desc) (?s . ,docstr))))) @@ -4608,28 +4717,33 @@ apply the face `transient-unreachable' to the complete string." (cl-defmethod transient-format-value ((obj transient-suffix)) (propertize (oref obj argument) 'face (if (oref obj value) - 'transient-argument + (if (oref obj inapt) + 'transient-inapt-argument + 'transient-argument) 'transient-inactive-argument))) (cl-defmethod transient-format-value ((obj transient-option)) (let ((argument (prin1-to-string (oref obj argument) t))) (if-let* ((value (oref obj value))) - (pcase-exhaustive (oref obj multi-value) - ('nil - (concat (propertize argument 'face 'transient-argument) - (propertize value 'face 'transient-value))) - ((or 't 'rest) - (concat (propertize (if (string-suffix-p " " argument) - argument - (concat argument " ")) - 'face 'transient-argument) - (propertize (mapconcat #'prin1-to-string value " ") - 'face 'transient-value))) - ('repeat - (mapconcat (lambda (value) - (concat (propertize argument 'face 'transient-argument) - (propertize value 'face 'transient-value))) - value " "))) + (let* ((inapt (oref obj inapt)) + (aface (if inapt 'transient-inapt-argument 'transient-argument)) + (vface (if inapt 'transient-inapt-argument 'transient-value))) + (pcase-exhaustive (oref obj multi-value) + ('nil + (concat (propertize argument 'face aface) + (propertize value 'face vface))) + ((or 't 'rest) + (concat (propertize (if (string-suffix-p " " argument) + argument + (concat argument " ")) + 'face aface) + (propertize (mapconcat #'prin1-to-string value " ") + 'face vface))) + ('repeat + (mapconcat (lambda (value) + (concat (propertize argument 'face aface) + (propertize value 'face vface))) + value " ")))) (propertize argument 'face 'transient-inactive-argument)))) (cl-defmethod transient-format-value ((obj transient-switches)) @@ -4644,7 +4758,9 @@ apply the face `transient-unreachable' to the complete string." (lambda (choice) (propertize choice 'face (if (equal (format argument-format choice) value) - 'transient-value + (if (oref obj inapt) + 'transient-inapt-argument + 'transient-value) 'transient-inactive-value))) choices (propertize "|" 'face 'transient-delimiter)))))) @@ -4658,7 +4774,7 @@ apply the face `transient-unreachable' to the complete string." desc))) (cl-defmethod transient--get-face ((obj transient-suffix) slot) - (and-let* (((slot-boundp obj slot)) + (and-let* ((_(slot-boundp obj slot)) (face (slot-value obj slot))) (if (and (not (facep face)) (functionp face)) @@ -4955,11 +5071,11 @@ This is used when a tooltip is needed.") (summary) ((documentation command) (car (split-string (documentation command) "\n"))))) - ((stringp doc)) - ((not (equal doc - (car (split-string (documentation - 'transient--default-infix-command) - "\n")))))) + (_(stringp doc)) + (_(not (equal doc + (car (split-string (documentation + 'transient--default-infix-command) + "\n")))))) (when (string-suffix-p "." doc) (setq doc (substring doc 0 -1))) (if return