From ec8ce66d131c7fa60a8309e64554f68708a5ef29 Mon Sep 17 00:00:00 2001 From: Andreas Gerler Date: Wed, 21 May 2025 14:59:39 +0200 Subject: [PATCH] update transient --- .../dir | 0 .../gpl.info | 0 .../transient-autoloads.el | 15 +- .../transient-pkg.el | 8 +- .../transient.el | 1326 +++++++++++------ .../transient.info | 905 ++++++----- 6 files changed, 1368 insertions(+), 886 deletions(-) rename elpa/{transient-20241224.2234 => transient-20250520.1040}/dir (100%) rename elpa/{transient-20241224.2234 => transient-20250520.1040}/gpl.info (100%) rename elpa/{transient-20241224.2234 => transient-20250520.1040}/transient-autoloads.el (85%) rename elpa/{transient-20241224.2234 => transient-20250520.1040}/transient-pkg.el (69%) rename elpa/{transient-20241224.2234 => transient-20250520.1040}/transient.el (83%) rename elpa/{transient-20241224.2234 => transient-20250520.1040}/transient.info (87%) diff --git a/elpa/transient-20241224.2234/dir b/elpa/transient-20250520.1040/dir similarity index 100% rename from elpa/transient-20241224.2234/dir rename to elpa/transient-20250520.1040/dir diff --git a/elpa/transient-20241224.2234/gpl.info b/elpa/transient-20250520.1040/gpl.info similarity index 100% rename from elpa/transient-20241224.2234/gpl.info rename to elpa/transient-20250520.1040/gpl.info diff --git a/elpa/transient-20241224.2234/transient-autoloads.el b/elpa/transient-20250520.1040/transient-autoloads.el similarity index 85% rename from elpa/transient-20241224.2234/transient-autoloads.el rename to elpa/transient-20250520.1040/transient-autoloads.el index df3d3674..59a93cbb 100644 --- a/elpa/transient-20241224.2234/transient-autoloads.el +++ b/elpa/transient-20250520.1040/transient-autoloads.el @@ -20,7 +20,9 @@ LOC is a command, a key vector, a key description (a string as returned by `key-description'), or a coordination list (whose last element may also be a command or key). Remove a conflicting binding unless optional KEEP-OTHER is - non-nil. + non-nil. When the conflict appears to be a false-positive, + non-nil KEEP-OTHER may be ignored, which can be prevented + by using `always'. See info node `(transient)Modifying Existing Transients'. (fn PREFIX LOC SUFFIX &optional KEEP-OTHER)") @@ -34,7 +36,9 @@ LOC is a command, a key vector, a key description (a string as returned by `key-description'), or a coordination list (whose last element may also be a command or key). Remove a conflicting binding unless optional KEEP-OTHER is - non-nil. + non-nil. When the conflict appears to be a false-positive, + non-nil KEEP-OTHER may be ignored, which can be prevented + by using `always'. See info node `(transient)Modifying Existing Transients'. (fn PREFIX LOC SUFFIX &optional KEEP-OTHER)") @@ -51,6 +55,13 @@ See info node `(transient)Modifying Existing Transients'. (fn PREFIX LOC SUFFIX)") (function-put 'transient-replace-suffix 'lisp-indent-function 'defun) +(autoload 'transient-inline-group "transient" "\ +Inline the included GROUP into PREFIX. +Replace the symbol GROUP with its expanded layout in the +layout of PREFIX. + +(fn PREFIX GROUP)") +(function-put 'transient-inline-group 'lisp-indent-function 'defun) (autoload 'transient-remove-suffix "transient" "\ Remove the suffix or group at LOC in PREFIX. PREFIX is a prefix command, a symbol. diff --git a/elpa/transient-20241224.2234/transient-pkg.el b/elpa/transient-20250520.1040/transient-pkg.el similarity index 69% rename from elpa/transient-20241224.2234/transient-pkg.el rename to elpa/transient-20250520.1040/transient-pkg.el index 74f96170..97b5054d 100644 --- a/elpa/transient-20241224.2234/transient-pkg.el +++ b/elpa/transient-20250520.1040/transient-pkg.el @@ -1,12 +1,12 @@ ;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "transient" "20241224.2234" +(define-package "transient" "20250520.1040" "Transient commands." '((emacs "26.1") - (compat "30.0.0.0") + (compat "30.1.0.0") (seq "2.24")) :url "https://github.com/magit/transient" - :commit "280df1350bad1800501349b539d0b718ae60de65" - :revdesc "280df1350bad" + :commit "cb6550d5b111b7815feec97b236ecb051de70dbe" + :revdesc "cb6550d5b111" :keywords '("extensions") :authors '(("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev")) :maintainers '(("Jonas Bernoulli" . "emacs.transient@jonas.bernoulli.dev"))) diff --git a/elpa/transient-20241224.2234/transient.el b/elpa/transient-20250520.1040/transient.el similarity index 83% rename from elpa/transient-20241224.2234/transient.el rename to elpa/transient-20250520.1040/transient.el index 8befc835..721867ad 100644 --- a/elpa/transient-20241224.2234/transient.el +++ b/elpa/transient-20250520.1040/transient.el @@ -1,14 +1,14 @@ ;;; transient.el --- Transient commands -*- lexical-binding:t -*- -;; Copyright (C) 2018-2024 Free Software Foundation, Inc. +;; Copyright (C) 2018-2025 Free Software Foundation, Inc. ;; Author: Jonas Bernoulli ;; Homepage: https://github.com/magit/transient ;; Keywords: extensions -;; Package-Version: 20241224.2234 -;; Package-Revision: 280df1350bad -;; Package-Requires: ((emacs "26.1") (compat "30.0.0.0") (seq "2.24")) +;; Package-Version: 20250520.1040 +;; Package-Revision: cb6550d5b111 +;; Package-Requires: ((emacs "26.1") (compat "30.1.0.0") (seq "2.24")) ;; SPDX-License-Identifier: GPL-3.0-or-later @@ -35,12 +35,15 @@ ;;; Code: +(defconst transient-version "0.8.8") + (require 'cl-lib) (require 'compat) (require 'eieio) (require 'edmacro) (require 'format-spec) (require 'pcase) +(require 'pp) (eval-and-compile (when (and (featurep 'seq) @@ -101,8 +104,9 @@ TYPE is a type descriptor as accepted by `cl-typep', which see." `(pred (cl-typep _ ',type)))))) (make-obsolete-variable 'transient-hide-during-minibuffer-read - "use `transient-show-during-minibuffer-read' instead." - "0.8.0") + 'transient-show-during-minibuffer-read "0.8.0") + +(defvar transient-common-command-prefix) (defmacro transient--with-emergency-exit (id &rest body) (declare (indent defun)) @@ -127,35 +131,35 @@ TYPE is a type descriptor as accepted by `cl-typep', which see." :group 'extensions) (defcustom transient-show-popup t - "Whether to show the current transient in a popup buffer. + "Whether and when to show transient's menu in a buffer. \\ -- If t, then show the popup as soon as a transient prefix command +- If t, then show the buffer as soon as a transient prefix command is invoked. -- If nil, then do not show the popup 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. -- If a number, then delay displaying the popup and instead show +- If a number, then delay displaying the buffer and instead show a brief one-line summary. If zero or negative, then suppress even showing that summary and display the pressed key only. - Show the popup when the user explicitly requests it by pressing - \\[transient-show] or a prefix key. Unless zero, then also show the popup + Show the buffer once the user explicitly requests it by pressing + \\[transient-show] or a prefix key. Unless zero, then also show the buffer after that many seconds of inactivity (using the absolute value)." :package-version '(transient . "0.1.0") :group 'transient - :type '(choice (const :tag "instantly" t) - (const :tag "on demand" nil) - (const :tag "on demand (no summary)" 0) - (number :tag "after delay" 1))) + :type '(choice (const :tag "Instantly" t) + (const :tag "On demand" nil) + (const :tag "On demand (no summary)" 0) + (number :tag "After delay" 1))) (defcustom transient-enable-popup-navigation 'verbose - "Whether navigation commands are enabled in the transient popup. + "Whether navigation commands are enabled in the menu buffer. If the value is `verbose', additionally show brief documentation about the command under point in the echo area. -While a transient is active the transient popup 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 act on that buffer itself. If this is non-nil, then the following bindings are available: @@ -168,7 +172,7 @@ bindings are available: - \\`' and \\`' invoke the clicked on suffix. \\\ - \\[transient-isearch-backward]\ - and \\[transient-isearch-forward] start isearch in the popup buffer. + and \\[transient-isearch-forward] start isearch in the menu buffer. \\`' and \\`' are bound in `transient-push-button'. All other bindings are in `transient-popup-navigation-map'. @@ -179,18 +183,18 @@ then it is likely, that you would want \\`RET' to do what it would do if no transient were active." :package-version '(transient . "0.7.8") :group 'transient - :type '(choice (const :tag "enable navigation and echo summary" verbose) - (const :tag "enable navigation commands" t) - (const :tag "disable navigation commands" nil))) + :type '(choice (const :tag "Enable navigation and echo summary" verbose) + (const :tag "Enable navigation commands" t) + (const :tag "Disable navigation commands" nil))) (defcustom transient-display-buffer-action '(display-buffer-in-side-window (side . bottom) (dedicated . t) (inhibit-same-window . t)) - "The action used to display the transient popup buffer. + "The action used to display transient's menu buffer. -The transient popup buffer is displayed in a window using +The transient menu buffer is displayed in a window using (display-buffer BUFFER transient-display-buffer-action) @@ -211,6 +215,11 @@ This displays the window at the bottom of the selected frame. For alternatives see info node `(elisp)Display Action Functions' and info node `(elisp)Buffer Display Action Alists'. +When you switch to a different ACTION, you should keep the ALIST +entries for `dedicated' and `inhibit-same-window' in most cases. +Do not drop them because you are unsure whether they are needed; +if you are unsure, then keep them. + Note that the buffer that was current before the transient buffer is shown should remain the current buffer. Many suffix commands act on the thing at point, if appropriate, and if the transient @@ -245,7 +254,7 @@ is in characters." :type 'natnum) (defcustom transient-mode-line-format 'line - "The mode-line format for the transient popup buffer. + "The mode-line format for transient's menu buffer. If nil, then the buffer has no mode-line. If the buffer is not displayed right above the echo area, then this probably is not @@ -267,20 +276,25 @@ Otherwise this can be any mode-line format. See `mode-line-format' for details." :package-version '(transient . "0.2.0") :group 'transient - :type '(choice (const :tag "hide mode-line" nil) - (const :tag "substitute thin line" line) - (number :tag "substitute line with thickness") - (const :tag "name of prefix command" + :type '(choice (const :tag "Hide mode-line" nil) + (const :tag "Substitute thin line" line) + (number :tag "Substitute line with thickness") + (const :tag "Name of prefix command" ("%e" mode-line-front-space mode-line-buffer-identification)) - (sexp :tag "custom mode-line format"))) + (sexp :tag "Custom mode-line format"))) (defcustom transient-show-common-commands nil - "Whether to show common transient suffixes in the popup buffer. - -These commands are always shown after typing the prefix key -\"C-x\" when a transient command is active. To toggle the value -of this variable use \"C-x t\" when a transient is active." + "Whether to permanently show common suffix commands in transient menus. + +By default these commands are only temporarily shown after typing their +shared prefix key \ +\\\\[transient-common-command-prefix], \ +while a transient menu is active. When the value +of this option is non-nil, then these commands are permanently shown. +To toggle the value for the current Emacs session only type \ +\\\\[transient-toggle-common] while +any transient menu is active." :package-version '(transient . "0.1.0") :group 'transient :type 'boolean) @@ -330,6 +344,20 @@ number is positive, or hide the menu if it is negative." :format "\n %t: %v" :value -20))) +(defcustom transient-show-docstring-format "%s" + "How to display suffix docstrings. + +The command `transient-toggle-docstrings' toggles between showing suffix +descriptions as usual, and instead or additionally displaying the suffix +docstrings. The format specified here controls how that is done. %c is +the description and %s is the docstring. Use \"%-14c %s\" or similar to +display both. + +This command is not bound by default, see its docstring for instructions." + :package-version '(transient . "0.8.4") + :group 'transient + :type 'string) + (defcustom transient-read-with-initial-input nil "Whether to use the last history element as initial minibuffer input." :package-version '(transient . "0.2.0") @@ -396,7 +424,7 @@ using a layout optimized for Lisp. If non-nil, then the key binding of each suffix is colorized to indicate whether it exits the transient state or not, and the -line that is drawn below the transient popup buffer is used to +line that is drawn below transient's menu buffer is used to indicate the behavior of non-suffix commands." :package-version '(transient . "0.5.0") :group 'transient @@ -412,8 +440,18 @@ used." :group 'transient :type 'boolean) +(defcustom transient-error-on-insert-failure nil + "Whether to signal an error when failing to insert a suffix. + +When `transient-insert-suffix' and `transient-append-suffix' fail +to insert a suffix into an existing prefix, they usually just show +a warning. If this is non-nil, they signal an error instead." + :package-version '(transient . "0.8.8") + :group 'transient + :type 'boolean) + (defcustom transient-align-variable-pitch nil - "Whether to align columns pixel-wise in the popup buffer. + "Whether to align columns pixel-wise in the menu buffer. If this is non-nil, then columns are aligned pixel-wise to support variable-pitch fonts. Keys are not aligned, so you @@ -430,11 +468,11 @@ See also `transient-force-fixed-pitch'." :type 'boolean) (defcustom transient-force-fixed-pitch nil - "Whether to force use of monospaced font in the popup buffer. + "Whether to force use of monospaced font in the menu buffer. Even if you use a proportional font for the `default' face, you might still want to use a monospaced font in transient's -popup buffer. Setting this option to t causes `default' to +menu buffer. Setting this option to t causes `default' to be remapped to `fixed-pitch' in that buffer. See also `transient-align-variable-pitch'." @@ -464,7 +502,7 @@ Integers between 1 and 7 (inclusive) are valid levels. The levels of individual transients and/or their individual suffixes can be changed individually, by invoking the prefix and -then pressing \"C-x l\". +then pressing \\\\[transient-set-level]. The default level for both transients and their suffixes is 4. This option only controls the default for transients. The default @@ -551,7 +589,7 @@ give you as many additional suffixes as you hoped.)" "Face used for suffixes unreachable from the current prefix sequence." :group 'transient-faces) -(defface transient-inapt-suffix '((t :inherit shadow :italic t)) +(defface transient-inapt-suffix '((t :inherit shadow :slant italic)) "Face used for suffixes that are inapt at this time." :group 'transient-faces) @@ -573,7 +611,7 @@ See info node `(transient)Enabling and Disabling Suffixes'." (defface transient-higher-level `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1) - :color ,(let ((color (face-attribute 'shadow :foreground nil t))) + :color ,(let ((color (face-attribute 'shadow :foreground t t))) (or (and (not (eq color 'unspecified)) color) "grey60"))))) "Face optionally used to highlight suffixes on higher levels. @@ -597,7 +635,7 @@ character used to separate possible values from each other." (((class color) (background dark)) :inherit transient-key :foreground "#ddffdd")) - "Face used for keys of suffixes that don't exit transient state." + "Face used for keys of suffixes that don't exit the menu." :group 'transient-faces) (defface transient-key-noop @@ -617,7 +655,27 @@ character used to separate possible values from each other." (((class color) (background dark)) :inherit transient-key :foreground "#ffffcc")) - "Face used for keys of suffixes that return to the parent transient." + "Face used for keys of suffixes that return to the parent menu." + :group 'transient-faces) + +(defface transient-key-recurse + `((((class color) (background light)) + :inherit transient-key + :foreground "#2266ff") + (((class color) (background dark)) + :inherit transient-key + :foreground "#2299ff")) + "Face used for keys of sub-menus whose suffixes return to the parent menu." + :group 'transient-faces) + +(defface transient-key-stack + `((((class color) (background light)) + :inherit transient-key + :foreground "#dd4488") + (((class color) (background dark)) + :inherit transient-key + :foreground "#ff6699")) + "Face used for keys of sub-menus that exit the parent menu." :group 'transient-faces) (defface transient-key-exit @@ -627,7 +685,7 @@ character used to separate possible values from each other." (((class color) (background dark)) :inherit transient-key :foreground "#ffdddd")) - "Face used for keys of suffixes that exit transient state." + "Face used for keys of suffixes that exit the menu." :group 'transient-faces) (defface transient-unreachable-key @@ -706,7 +764,8 @@ should not change it manually.") "Save the value of `transient-history'. If `transient-save-history' is nil, then do nothing." (when transient-save-history - (transient-save-history))) + (with-demoted-errors "Error saving transient history: %S" + (transient-save-history)))) (unless noninteractive (add-hook 'kill-emacs-hook #'transient-maybe-save-history)) @@ -720,6 +779,7 @@ If `transient-save-history' is nil, then do nothing." (level :initarg :level) (init-value :initarg :init-value) (value) (default-value :initarg :value) + (return :initarg :return :initform nil) (scope :initarg :scope :initform nil) (history :initarg :history :initform nil) (history-pos :initarg :history-pos :initform 0) @@ -758,7 +818,7 @@ the prototype is stored in the clone's `prototype' slot.") :documentation "The parent group object.") (level :initarg :level - :initform (symbol-value 'transient--default-child-level) + :initform nil :documentation "Enable if level of prefix is equal or greater.") (if :initarg :if @@ -828,7 +888,15 @@ the prototype is stored in the clone's `prototype' slot.") (inapt-if-not-derived :initarg :inapt-if-not-derived :initform nil - :documentation "Inapt if major-mode does not derive from value.")) + :documentation "Inapt if major-mode does not derive from value.") + (advice + :initarg :advice + :initform nil + :documentation "Advise applied to the command body.") + (advice* + :initarg :advice* + :initform nil + :documentation "Advise applied to the command body and interactive spec.")) "Abstract superclass for group and suffix classes. It is undefined which predicates are used if more than one `if*' @@ -964,7 +1032,7 @@ argument supported by the constructor of that class. The explicitly. GROUPs add key bindings for infix and suffix commands and specify -how these bindings are presented in the popup buffer. At least +how these bindings are presented in the menu buffer. At least one GROUP has to be specified. See info node `(transient)Binding Suffix and Infix Commands'. @@ -999,7 +1067,7 @@ to the setup function: (indent defun) (doc-string 3)) (pcase-let - ((`(,class ,slots ,suffixes ,docstr ,body ,interactive-only) + ((`(,class ,slots ,groups ,docstr ,body ,interactive-only) (transient--expand-define-args args arglist 'transient-define-prefix))) `(progn (defalias ',name @@ -1012,9 +1080,22 @@ to the setup function: (put ',name 'function-documentation ,docstr) (put ',name 'transient--prefix (,(or class 'transient-prefix) :command ',name ,@slots)) - (put ',name 'transient--layout - (list ,@(mapcan (lambda (s) (transient--parse-child name s)) - suffixes)))))) + (transient--set-layout + ',name + (list ,@(mapcan (lambda (s) (transient--parse-child name s)) groups)))))) + +(defmacro transient-define-group (name &rest groups) + "Define one or more groups and store them in symbol NAME. + +Groups defined using this macro, can be used inside the +definition of transient prefix commands, by using the symbol +NAME where a group vector is expected. GROUPS has the same +form as for `transient-define-prefix'." + (declare (debug (&define name [&rest vectorp])) + (indent defun)) + `(transient--set-layout + ',name + (list ,@(mapcan (lambda (s) (transient--parse-child name s)) groups)))) (defmacro transient-define-suffix (name arglist &rest args) "Define NAME as a transient suffix command. @@ -1161,6 +1242,8 @@ commands are aliases for." ;; ARGLIST and FORM are only optional for backward compatibility. ;; This is necessary because "emoji.el" from Emacs 29 calls this ;; function directly, with just one argument. + (declare (advertised-calling-convention + (args arglist form &optional nobody) "0.7.1")) (unless (listp arglist) (error "Mandatory ARGLIST is missing")) (let (class keys suffixes docstr declare (interactive-only t)) @@ -1173,10 +1256,19 @@ commands are aliases for." (setq class v) (push k keys) (push v keys)))) - (while (let ((arg (car args))) - (or (vectorp arg) - (and arg (symbolp arg)))) - (push (pop args) suffixes)) + (while-let + ((arg (car args)) + (arg (cond + ;; Inline group definition. + ((vectorp arg) + (pop args)) + ;; Quoted include, as one would expect. + ((eq (car-safe arg) 'quote) + (cadr (pop args))) + ;; Unquoted include, for compatibility. + ((and arg (symbolp arg)) + (pop args))))) + (push arg suffixes)) (when (eq (car-safe (car args)) 'declare) (setq declare (car args)) (setq args (cdr args)) @@ -1203,48 +1295,33 @@ commands are aliases for." (defun transient--parse-child (prefix spec) (cl-typecase spec (null (error "Invalid transient--parse-child spec: %s" spec)) - (symbol (let ((value (symbol-value spec))) - (if (and (listp value) - (or (listp (car value)) - (vectorp (car value)))) - (mapcan (lambda (s) (transient--parse-child prefix s)) value) - (transient--parse-child prefix value)))) + (symbol (list `',spec)) (vector (and-let* ((c (transient--parse-group prefix spec))) (list c))) (list (and-let* ((c (transient--parse-suffix prefix spec))) (list c))) (string (list spec)) (t (error "Invalid transient--parse-child spec: %s" spec)))) (defun transient--parse-group (prefix spec) - (let ((spec (append spec nil)) - level class args) + (let (class args) + (setq spec (append spec nil)) (when (integerp (car spec)) - (setq level (pop spec))) + (setq args (plist-put args :level (pop spec)))) (when (stringp (car spec)) (setq args (plist-put args :description (pop spec)))) - ;; Merge value of [... GROUP-VARIABLE], if any. - (let ((spec* spec)) - (while (keywordp (car spec*)) - (setq spec* (cddr spec*))) - (when (and (length= spec* 1) (symbolp (car spec*))) - (let ((rest (append (symbol-value (car spec*)) nil)) - (args nil)) - (while (keywordp (car rest)) - (setq args (nconc (list (pop rest) (pop rest)) args))) - (setq spec (nconc args (butlast spec) rest))))) (while (keywordp (car spec)) (let* ((key (pop spec)) (val (if spec (pop spec) (error "No value for `%s'" key)))) (cond ((eq key :class) (setq class val)) ((or (symbolp val) - (and (listp val) (not (eq (car val) 'lambda)))) + (and (listp val) + (not (memq (car val) (list 'lambda (intern "")))))) (setq args (plist-put args key (macroexp-quote val)))) ((setq args (plist-put args key val)))))) (unless (or spec class (not (plist-get args :setup-children))) (message "WARNING: %s: When %s is used, %s must also be specified" 'transient-define-prefix :setup-children :class)) (list 'vector - (or level transient--default-child-level) (list 'quote (cond (class) ((cl-typep (car spec) @@ -1256,12 +1333,12 @@ commands are aliases for." (mapcan (lambda (s) (transient--parse-child prefix s)) spec))))) (defun transient--parse-suffix (prefix spec) - (let (level class args) + (let (class args) (cl-flet ((use (prop value) (setq args (plist-put args prop value)))) (pcase (car spec) ((cl-type integer) - (setq level (pop spec)))) + (use :level (pop spec)))) (pcase (car spec) ((cl-type (or string vector)) (use :key (pop spec)))) @@ -1327,7 +1404,6 @@ commands are aliases for." (val (if spec (pop spec) (error "No value for `%s'" key)))) (pcase key (:class (setq class val)) - (:level (setq level val)) (:info (setq class 'transient-information) (use :description val)) (:info* (setq class 'transient-information*) @@ -1335,16 +1411,19 @@ commands are aliases for." ((guard (eq (car-safe val) '\,)) (use key (cadr val))) ((guard (or (symbolp val) - (and (listp val) (not (eq (car val) 'lambda))))) + (and (listp val) + (not (memq (car val) (list 'lambda (intern ""))))))) (use key (macroexp-quote val))) (_ (use key val))))) (when spec (error "Need keyword, got %S" (car spec))) - (when-let* (((not (plist-get args :key))) - (shortarg (plist-get args :shortarg))) - (use :key shortarg))) - (list 'list - (or level transient--default-child-level) + (if-let ((key (plist-get args :key))) + (when (string-match "\\`\\({p}\\)" key) + (use :key + (replace-match transient-common-command-prefix t t key 1))) + (when-let ((shortarg (plist-get args :shortarg))) + (use :key shortarg)))) + (list 'cons (macroexp-quote (or class 'transient-suffix)) (cons 'list args)))) @@ -1373,62 +1452,123 @@ symbol property.") (setq read-extended-command-predicate #'transient-command-completion-not-suffix-only-p)) +(defun transient--set-layout (prefix layout) + (put prefix 'transient--layout (vector 2 nil layout))) + +(defun transient--get-layout (prefix) + (if-let* + ((layout + (or (get prefix 'transient--layout) + ;; Migrate unparsed legacy group definition. + (condition-case-unless-debug err + (and-let* ((value (symbol-value prefix))) + (transient--set-layout + prefix + (if (and (listp value) + (or (listp (car value)) + (vectorp (car value)))) + (transient-parse-suffixes prefix value) + (list (transient-parse-suffix prefix value))))) + (error + (message "Not a legacy group definition: %s: %S" prefix err) + nil))))) + (if (vectorp layout) + (let ((version (aref layout 0))) + (if (= version 2) + layout + (error "Unsupported layout version %s for %s" version prefix))) + ;; Upgrade from version 1. + (cl-labels + ((upgrade (spec) + (cond + ((vectorp spec) + (pcase-let ((`[,level ,class ,args ,children] spec)) + (when level + (setq args (plist-put args :level level))) + (vector class args (mapcar #'upgrade children)))) + ((and (listp spec) + (length= spec 3) + (or (null (car spec)) + (natnump (car spec))) + (symbolp (cadr spec))) + (pcase-let ((`(,level ,class ,args) spec)) + (when level + (setq args (plist-put args :level level))) + (cons class args))) + ((listp spec) + (mapcar #'upgrade spec)) + (t spec)))) + (transient--set-layout prefix (upgrade layout)))) + (error "Not a transient prefix command or group definition: %s" prefix))) + +(defun transient--get-children (prefix) + (aref (transient--get-layout prefix) 2)) + (defun transient-parse-suffix (prefix suffix) "Parse SUFFIX, to be added to PREFIX. -PREFIX is a prefix command, a symbol. +PREFIX is a prefix command symbol or object. SUFFIX is a suffix command or a group specification (of the same forms as expected by `transient-define-prefix'). Intended for use in a group's `:setup-children' function." - (cl-assert (and prefix (symbolp prefix))) + (if (cl-typep prefix 'transient-prefix) + (setq prefix (oref prefix command)) + (transient--get-layout prefix)) ; validate (eval (car (transient--parse-child prefix suffix)) t)) (defun transient-parse-suffixes (prefix suffixes) "Parse SUFFIXES, to be added to PREFIX. -PREFIX is a prefix command, a symbol. +PREFIX is a prefix command symbol or object. SUFFIXES is a list of suffix command or a group specification (of the same forms as expected by `transient-define-prefix'). Intended for use in a group's `:setup-children' function." - (cl-assert (and prefix (symbolp prefix))) + (if (cl-typep prefix 'transient-prefix) + (setq prefix (oref prefix command)) + (transient--get-layout prefix)) ; validate (mapcar (apply-partially #'transient-parse-suffix prefix) suffixes)) ;;; Edit (defun transient--insert-suffix (prefix loc suffix action &optional keep-other) - (let* ((suf (cl-etypecase suffix - (vector (transient--parse-group prefix suffix)) - (list (transient--parse-suffix prefix suffix)) - (string suffix))) - (mem (transient--layout-member loc prefix)) - (elt (car mem))) - (setq suf (eval suf t)) + (pcase-let* ((suf (cl-etypecase suffix + (vector (eval (transient--parse-group prefix suffix) t)) + (list (eval (transient--parse-suffix prefix suffix) t)) + (string suffix) + (symbol suffix))) + (`(,elt ,group) (transient--locate-child prefix loc))) (cond - ((not mem) - (message "Cannot insert %S into %s; %s not found" + ((not elt) + (funcall (if transient-error-on-insert-failure #'error #'message) + "Cannot insert %S into %s; %s not found" suffix prefix loc)) ((or (and (vectorp suffix) (not (vectorp elt))) (and (listp suffix) (vectorp elt)) (and (stringp suffix) (vectorp elt))) - (message "Cannot place %S into %s at %s; %s" + (funcall (if transient-error-on-insert-failure #'error #'message) + "Cannot place %S into %s at %s; %s" suffix prefix loc "suffixes and groups cannot be siblings")) (t - (when-let* ((bindingp (listp suf)) + (when-let* (((not (eq keep-other 'always))) + (bindingp (listp suf)) (key (transient--spec-key suf)) - (conflict (car (transient--layout-member key prefix))) + (conflict (car (transient--locate-child prefix key))) (conflictp (and (not (and (eq action 'replace) (eq conflict elt))) (or (not keep-other) - (eq (plist-get (nth 2 suf) :command) - (plist-get (nth 2 conflict) :command))) + (eq (plist-get (transient--suffix-props suf) + :command) + (plist-get (transient--suffix-props conflict) + :command))) (equal (transient--suffix-predicate suf) (transient--suffix-predicate conflict))))) (transient-remove-suffix prefix key)) - (pcase-exhaustive action - ('insert (setcdr mem (cons elt (cdr mem))) - (setcar mem suf)) - ('append (setcdr mem (cons suf (cdr mem)))) - ('replace (setcar mem suf))))))) + (let ((mem (memq elt (aref group 2)))) + (pcase-exhaustive action + ('insert (setcdr mem (cons elt (cdr mem))) + (setcar mem suf)) + ('append (setcdr mem (cons suf (cdr mem)))) + ('replace (setcar mem suf)))))))) ;;;###autoload (defun transient-insert-suffix (prefix loc suffix &optional keep-other) @@ -1440,7 +1580,9 @@ LOC is a command, a key vector, a key description (a string as returned by `key-description'), or a coordination list (whose last element may also be a command or key). Remove a conflicting binding unless optional KEEP-OTHER is - non-nil. + non-nil. When the conflict appears to be a false-positive, + non-nil KEEP-OTHER may be ignored, which can be prevented + by using `always'. See info node `(transient)Modifying Existing Transients'." (declare (indent defun)) (transient--insert-suffix prefix loc suffix 'insert keep-other)) @@ -1455,7 +1597,9 @@ LOC is a command, a key vector, a key description (a string as returned by `key-description'), or a coordination list (whose last element may also be a command or key). Remove a conflicting binding unless optional KEEP-OTHER is - non-nil. + non-nil. When the conflict appears to be a false-positive, + non-nil KEEP-OTHER may be ignored, which can be prevented + by using `always'. See info node `(transient)Modifying Existing Transients'." (declare (indent defun)) (transient--insert-suffix prefix loc suffix 'append keep-other)) @@ -1473,6 +1617,22 @@ See info node `(transient)Modifying Existing Transients'." (declare (indent defun)) (transient--insert-suffix prefix loc suffix 'replace)) +;;;###autoload +(defun transient-inline-group (prefix group) + "Inline the included GROUP into PREFIX. +Replace the symbol GROUP with its expanded layout in the +layout of PREFIX." + (declare (indent defun)) + (cl-assert (symbolp group)) + (pcase-let ((`(,suffix ,parent) (transient--locate-child prefix group))) + (when suffix + (let* ((siblings (aref parent 2)) + (pos (cl-position group siblings))) + (aset parent 2 + (nconc (seq-take siblings pos) + (transient--get-children group) + (seq-drop siblings (1+ pos)))))))) + ;;;###autoload (defun transient-remove-suffix (prefix loc) "Remove the suffix or group at LOC in PREFIX. @@ -1482,90 +1642,84 @@ LOC is a command, a key vector, a key description (a string (whose last element may also be a command or key). See info node `(transient)Modifying Existing Transients'." (declare (indent defun)) - (transient--layout-member loc prefix 'remove)) + (pcase-let ((`(,suffix ,group) (transient--locate-child prefix loc))) + (when suffix + (aset group 2 (delq suffix (aref group 2)))))) -(defun transient-get-suffix (prefix loc) - "Return the suffix or group at LOC in PREFIX. +(defun transient-suffix-put (prefix loc prop value) + "Edit the suffix at LOC in PREFIX, setting PROP to VALUE. PREFIX is a prefix command, a symbol. +SUFFIX is a suffix command or a group specification (of + the same forms as expected by `transient-define-prefix'). LOC is a command, a key vector, a key description (a string as returned by `key-description'), or a coordination list (whose last element may also be a command or key). See info node `(transient)Modifying Existing Transients'." - (if-let ((mem (transient--layout-member loc prefix))) - (car mem) - (error "%s not found in %s" loc prefix))) + (let ((child (transient-get-suffix prefix loc))) + (if (vectorp child) + (aset child 1 (plist-put (aref child 1) prop value)) + (setcdr child (plist-put (transient--suffix-props child) prop value))))) -(defun transient-suffix-put (prefix loc prop value) - "Edit the suffix at LOC in PREFIX, setting PROP to VALUE. +(defalias 'transient--suffix-props #'cdr) + +(defun transient-get-suffix (prefix loc) + "Return the suffix or group at LOC in PREFIX. PREFIX is a prefix command, a symbol. -SUFFIX is a suffix command or a group specification (of - the same forms as expected by `transient-define-prefix'). LOC is a command, a key vector, a key description (a string as returned by `key-description'), or a coordination list (whose last element may also be a command or key). See info node `(transient)Modifying Existing Transients'." - (let ((suf (transient-get-suffix prefix loc))) - (setf (elt suf 2) - (plist-put (elt suf 2) prop value)))) - -(defun transient--layout-member (loc prefix &optional remove) - (let ((val (or (get prefix 'transient--layout) - (error "%s is not a transient command" prefix)))) - (when (listp loc) - (while (integerp (car loc)) - (let* ((children (if (vectorp val) (aref val 3) val)) - (mem (transient--nthcdr (pop loc) children))) - (if (and remove (not loc)) - (let ((rest (delq (car mem) children))) - (if (vectorp val) - (aset val 3 rest) - (put prefix 'transient--layout rest)) - (setq val nil)) - (setq val (if loc (car mem) mem))))) - (setq loc (car loc))) - (if loc - (transient--layout-member-1 (transient--kbd loc) val remove) - val))) - -(defun transient--layout-member-1 (loc layout remove) - (cond ((listp layout) - (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove)) - layout)) - ((vectorp (car (aref layout 3))) - (seq-some (lambda (elt) (transient--layout-member-1 loc elt remove)) - (aref layout 3))) - (remove - (aset layout 3 - (delq (car (transient--group-member loc layout)) - (aref layout 3))) - nil) - ((transient--group-member loc layout)))) - -(defun transient--group-member (loc group) - (cl-member-if (lambda (suffix) - (and (listp suffix) - (let* ((def (nth 2 suffix)) - (cmd (plist-get def :command))) - (if (symbolp loc) - (eq cmd loc) - (equal (transient--kbd - (or (plist-get def :key) - (transient--command-key cmd))) - loc))))) - (aref group 3))) - -(defun transient--kbd (keys) - (when (vectorp keys) - (setq keys (key-description keys))) - (when (stringp keys) - (setq keys (kbd keys))) - keys) + (or (car (transient--locate-child prefix loc)) + (error "%s not found in %s" loc prefix))) + +(defun transient--locate-child (group loc) + (when (symbolp group) + (setq group (transient--get-layout group))) + (when (vectorp loc) + (setq loc (append loc nil))) + (if (listp loc) + (and-let* ((match (transient--nth (pop loc) (aref group 2)))) + (if loc + (transient--locate-child + match (cond ((or (stringp (car loc)) + (symbolp (car loc))) + (car loc)) + ((symbolp match) + (vconcat (cons 0 loc))) + ((vconcat loc)))) + (list match group))) + (seq-some (lambda (child) + (transient--match-child group loc child)) + (aref group 2)))) + +(defun transient--match-child (group loc child) + (cl-etypecase child + (string nil) + (symbol (if (symbolp loc) + (and (eq child loc) + (list child group)) + (and-let* ((include (transient--get-layout child))) + (transient--locate-child include loc)))) + (vector (seq-some (lambda (subgroup) + (transient--locate-child subgroup loc)) + (aref group 2))) + (list (let* ((props (transient--suffix-props child)) + (cmd (plist-get props :command))) + (and (if (symbolp loc) + (eq cmd loc) + (equal (kbd (or (plist-get props :key) + (transient--command-key cmd))) + (kbd loc))) + (list child group)))))) + +(defun transient--nth (n list) + (nth (if (< n 0) (- (length list) (abs n)) n) list)) (defun transient--spec-key (spec) - (let ((plist (nth 2 spec))) - (or (plist-get plist :key) + (let ((props (transient--suffix-props spec))) + (or (plist-get props :key) (transient--command-key - (plist-get plist :command))))) + (plist-get props :command))))) (defun transient--command-key (cmd) (and-let* ((obj (transient--suffix-prototype cmd))) @@ -1576,8 +1730,20 @@ See info node `(transient)Modifying Existing Transients'." (oref obj shortarg) (transient--derive-shortarg (oref obj argument))))))) -(defun transient--nthcdr (n list) - (nthcdr (if (< n 0) (- (length list) (abs n)) n) list)) +(defun transient-set-default-level (command level) + "Set the default level of suffix COMMAND to LEVEL. + +The default level is shadowed if the binding of the suffix in a +prefix menu specifies a level, and also if the user changes the +level of such a binding. + +The default level can only be set for commands that were defined +using `transient-define-suffix', `transient-define-infix' or +`transient-define-argument'." + (if-let ((proto (transient--suffix-prototype command))) + (oset proto level level) + (user-error "Cannot set level for `%s'; no prototype object exists" + command))) ;;; Variables @@ -1599,7 +1765,14 @@ values. In complex cases it might be necessary to use this variable instead.") (defvar transient-exit-hook nil - "Hook run after exiting a transient.") + "Hook run after exiting a transient menu. +Unlike `transient-post-exit-hook', this runs even if another transient +menu becomes active at the same time. ") + +(defvar transient-post-exit-hook nil + "Hook run after exiting all transient menus. +Unlike `transient-exit-hook', this does not run if another transient +menu becomes active at the same time.") (defvar transient-setup-buffer-hook nil "Hook run when setting up the transient buffer. @@ -1613,7 +1786,7 @@ That buffer is current and empty when this hook runs.") (defconst transient--exit nil "Do exit the transient.") (defvar transient--exitp nil "Whether to exit the transient.") -(defvar transient--showp nil "Whether to show the transient popup buffer.") +(defvar transient--showp nil "Whether to show the transient menu buffer.") (defvar transient--helpp nil "Whether help-mode is active.") (defvar transient--docsp nil "Whether docstring-mode is active.") (defvar transient--editp nil "Whether edit-mode is active.") @@ -1637,7 +1810,7 @@ That buffer is current and empty when this hook runs.") "The transient menu buffer.") (defvar transient--window nil - "The window used to display the transient popup buffer.") + "The window used to display transient's menu buffer.") (defvar transient--original-window nil "The window that was selected before the transient was invoked. @@ -1660,6 +1833,10 @@ drawing in the transient buffer.") This is bound while the suffix predicate is being evaluated, and while functions that return faces are being evaluated.") +(defvar transient--current-suffix nil + "The suffix currently being invoked using a mouse event. +Do not use this; instead use function `transient-suffix-object'.") + (defvar transient--pending-group nil "The group that is currently being processed. This is bound while the suffixes are drawn in the transient buffer.") @@ -1768,6 +1945,7 @@ probably use this instead: (cl-check-type command command)) (cond (transient--pending-suffix) + (transient--current-suffix) ((or transient--prefix transient-current-prefix) (let ((suffixes @@ -1782,22 +1960,24 @@ probably use this instead: this-command)))) (or transient--suffixes transient-current-suffixes)))) - (or (if (cdr suffixes) - (cl-find-if - (lambda (obj) - (equal (listify-key-sequence (transient--kbd (oref obj key))) - (listify-key-sequence (this-command-keys)))) - suffixes) - (car suffixes)) - ;; COMMAND is only provided if `this-command' is meaningless, in - ;; which case `this-command-keys' is also meaningless, making it - ;; impossible to disambiguate redundant bindings. - (if command - (car suffixes) - ;; TODO Decide whether it is legimate to use this function - ;; as a predicate, and also whether to return an object for - ;; suffixes common to all prefixes. See #29 and #337. - (error "BUG: Cannot determine suffix object"))))) + (cond + ((length= suffixes 1) + (car suffixes)) + ((cl-find-if (lambda (obj) + (equal (listify-key-sequence (kbd (oref obj key))) + (listify-key-sequence (this-command-keys)))) + suffixes)) + ;; COMMAND is only provided if `this-command' is meaningless, in + ;; which case `this-command-keys' is also meaningless, making it + ;; impossible to disambiguate bindings for the same command. + (command (car suffixes)) + ;; If COMMAND is nil, then failure to disambiguate likely means + ;; that there is a bug somewhere. + ((length> suffixes 1) + (error "BUG: Cannot unambiguously determine suffix object")) + ;; It is legimate to use this function as a predicate of sorts. + ;; `transient--pre-command' and `transient-help' are examples. + (t nil)))) ((and-let* ((obj (transient--suffix-prototype (or command this-command))) (obj (clone obj))) (progn @@ -1844,7 +2024,7 @@ to `transient-predicate-map'." (keymap-set map "C-t" #'transient-show) (keymap-set map "?" #'transient-help) (keymap-set map "C-h" #'transient-help) - ;; Also bound to "C-x p" and "C-x n" in transient-common-commands. + ;; 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 @@ -1859,53 +2039,84 @@ to `transient-predicate-map'. See also `transient-base-map'.") (defvar-keymap transient-edit-map :doc "Keymap that is active while a transient in is in \"edit mode\"." :parent transient-base-map - "?" #'transient-help - "C-h" #'transient-help - "C-x l" #'transient-set-level) + "?" #'transient-help + "C-h" #'transient-help) (defvar-keymap transient-sticky-map :doc "Keymap that is active while an incomplete key sequence is active." :parent transient-base-map "C-g" #'transient-quit-seq) -(defvar transient--common-command-prefixes '(?\C-x)) - -(put 'transient-common-commands - 'transient--layout - (list - (eval - (car (transient--parse-child - 'transient-common-commands - (vector - :hide - (lambda () - (and (not (memq - (car (bound-and-true-p transient--redisplay-key)) - transient--common-command-prefixes)) - (not transient-show-common-commands))) - (vector - "Value commands" - (list "C-x s " "Set" #'transient-set) - (list "C-x C-s" "Save" #'transient-save) - (list "C-x C-k" "Reset" #'transient-reset) - (list "C-x p " "Previous value" #'transient-history-prev) - (list "C-x n " "Next value" #'transient-history-next)) - (vector - "Sticky commands" - ;; Like `transient-sticky-map' except that - ;; "C-g" has to be bound to a different command. - (list "C-g" "Quit prefix or transient" #'transient-quit-one) - (list "C-q" "Quit transient stack" #'transient-quit-all) - (list "C-z" "Suspend transient stack" #'transient-suspend)) - (vector - "Customize" - (list "C-x t" #'transient-toggle-common) - (list "C-x l" "Show/hide suffixes" #'transient-set-level) - (list "C-x a" #'transient-toggle-level-limit))))) - t))) +(defvar transient-common-commands + [:hide (lambda () + (defvar transient--redisplay-key) + (and (not (equal (vconcat transient--redisplay-key) + (read-kbd-macro transient-common-command-prefix))) + (not transient-show-common-commands))) + ["Value commands" + ("{p} s " "Set" transient-set) + ("{p} C-s" "Save" transient-save) + ("{p} C-k" "Reset" transient-reset) + ("{p} p " "Previous value" transient-history-prev) + ("{p} n " "Next value" transient-history-next)] + ["Sticky commands" + ;; Like `transient-sticky-map' except that + ;; "C-g" has to be bound to a different command. + ("C-g" "Quit prefix or transient" transient-quit-one) + ("C-q" "Quit transient stack" transient-quit-all) + ("C-z" "Suspend transient stack" transient-suspend)] + ["Customize" + ("{p} t" transient-toggle-common) + ("{p} l" "Show/hide suffixes" transient-set-level) + ("{p} a" transient-toggle-level-limit)]] + "Commands available in all transient menus. + +The same functions, that are used to change bindings in transient prefix +commands and transient groups (defined using `transient-define-group'), +should be used to modify these bindings as well. The actual layout is +stored in the symbol's `transient--layout' property. The variable value +is only used when customizing `transient-common-command-prefix', which +resets the value of `transient--layout' based on the values of that +option and this variable.") + +(defun transient--init-common-commands () + (transient--set-layout + 'transient-common-commands + (list (eval (car (transient--parse-child 'transient-common-commands + transient-common-commands)) + t))) + (defvar transient-common-command-prefix) + (defvar transient--docstr-hint-1) + (defvar transient--docstr-hint-2) + (setq transient--docstr-hint-1 + (define-keymap transient-common-command-prefix + 'transient-common-command-prefix)) + (setq transient--docstr-hint-2 + (define-keymap (concat transient-common-command-prefix " t") + 'transient-toggle-common))) + +(defcustom transient-common-command-prefix "C-x" + "The prefix key used for most commands common to all menus. + +Some shared commands are available in all transient menus, most of +which share a common prefix specified by this option. By default the +bindings for these shared commands are only shown after pressing that +prefix key and before following that up with a valid key binding. + +For historic reasons \\`C-x' is used by default, but users are +encouraged to pick another key, preferably one that is not commonly used +in Emacs but is still convenient to them. See info node `(transient) +Common Suffix Commands'." + :type 'key + :initialize (lambda (symbol exp) + (custom-initialize-default symbol exp) + (transient--init-common-commands)) + :set (lambda (symbol value) + (set-default symbol value) + (transient--init-common-commands))) (defvar-keymap transient-popup-navigation-map - :doc "One of the keymaps used when popup navigation is enabled. + :doc "One of the keymaps used when menu navigation is enabled. See `transient-enable-popup-navigation'." "" #'transient-noop "" #'transient-backward-button @@ -1915,7 +2126,7 @@ See `transient-enable-popup-navigation'." "M-RET" #'transient-push-button) (defvar-keymap transient-button-map - :doc "One of the keymaps used when popup navigation is enabled. + :doc "One of the keymaps used when menu navigation is enabled. See `transient-enable-popup-navigation'." "" #'transient-push-button "" #'transient-push-button) @@ -2015,9 +2226,11 @@ of the corresponding object." (defun transient--make-transient-map () (let ((map (make-sparse-keymap))) - (set-keymap-parent map (if transient--editp - transient-edit-map - transient-map)) + (cond (transient--editp + (keymap-set map (concat transient-common-command-prefix " l") + #'transient-set-level) + (set-keymap-parent map transient-edit-map)) + ((set-keymap-parent map transient-map))) (dolist (obj transient--suffixes) (let ((key (oref obj key))) (when (vectorp key) @@ -2056,7 +2269,7 @@ of the corresponding object." (defun transient--make-predicate-map () (let* ((default (transient--resolve-pre-command (oref transient--prefix transient-suffix))) - (return (and transient--stack (eq default t))) + (return (and transient--stack (oref transient--prefix return))) (map (make-sparse-keymap))) (set-keymap-parent map transient-predicate-map) (when (or (and (slot-boundp transient--prefix 'transient-switch-frame) @@ -2077,26 +2290,26 @@ of the corresponding object." ((slot-boundp obj 'transient) (pcase (list kind (transient--resolve-pre-command - (oref obj transient)) + (oref obj transient) nil t) return) - (`(prefix t ,_) #'transient--do-recurse) - (`(prefix nil ,_) #'transient--do-stack) - (`(infix t ,_) #'transient--do-stay) - (`(suffix t ,_) #'transient--do-call) - ('(suffix nil t) #'transient--do-return) - (`(,_ nil ,_) #'transient--do-exit) - (`(,_ ,do ,_) do))) + (`(prefix t ,_) #'transient--do-recurse) + (`(prefix nil ,_) #'transient--do-stack) + (`(infix t ,_) #'transient--do-stay) + (`(suffix t ,_) #'transient--do-call) + ('(suffix nil t) #'transient--do-return) + (`(,_ nil ,_) #'transient--do-exit) + (`(,_ ,do ,_) do))) ((not (lookup-key transient-predicate-map id)) (pcase (list kind default return) (`(prefix ,(or 'transient--do-stay 'transient--do-call) ,_) #'transient--do-recurse) - (`(prefix t ,_) #'transient--do-recurse) - (`(prefix ,_ ,_) #'transient--do-stack) - (`(infix ,_ ,_) #'transient--do-stay) - (`(suffix t ,_) #'transient--do-call) - ('(suffix nil t) #'transient--do-return) - (`(suffix nil ,_) #'transient--do-exit) - (`(suffix ,do ,_) do)))))) + (`(prefix t ,_) #'transient--do-recurse) + (`(prefix ,_ ,_) #'transient--do-stack) + (`(infix ,_ ,_) #'transient--do-stay) + (`(suffix t ,_) #'transient--do-call) + ('(suffix nil t) #'transient--do-return) + (`(suffix nil nil) #'transient--do-exit) + (`(suffix ,do ,_) do)))))) (when pre (if-let ((alt (lookup-key map id))) (unless (eq alt pre) @@ -2181,6 +2394,7 @@ EDIT may be non-nil." (setq transient--minibuffer-depth (minibuffer-depth)) (transient--redisplay)) (get name 'transient--prefix)) + (transient--suspend-text-conversion-style) (transient--setup-transient) (transient--suspend-which-key-mode))) @@ -2233,18 +2447,17 @@ value. Otherwise return CHILDREN as is.") :level (or (alist-get t (alist-get name transient-levels)) transient-default-level) params)))) - (transient--setup-recursion obj) - (transient-init-scope obj) - (transient-init-value obj) + (transient-init-value obj) + (transient-init-return obj) + (transient-init-scope obj) obj)) (defun transient--init-suffixes (name) (let ((levels (alist-get name transient-levels))) (mapcan (lambda (c) (transient--init-child levels c nil)) - (append (get name 'transient--layout) + (append (transient--get-children name) (and (not transient--editp) - (get 'transient-common-commands - 'transient--layout)))))) + (transient--get-children 'transient-common-commands)))))) (defun transient--flatten-suffixes (layout) (cl-labels ((s (def) @@ -2260,12 +2473,16 @@ value. Otherwise return CHILDREN as is.") (defun transient--init-child (levels spec parent) (cl-etypecase spec + (symbol (mapcan (lambda (c) (transient--init-child levels c parent)) + (transient--get-children spec))) (vector (transient--init-group levels spec parent)) (list (transient--init-suffix levels spec parent)) (string (list spec)))) (defun transient--init-group (levels spec parent) - (pcase-let ((`(,level ,class ,args ,children) (append spec nil))) + (pcase-let* ((`[,class ,args ,children] spec) + (level (or (plist-get args :level) + transient--default-child-level))) (and-let* (((transient--use-level-p level)) (obj (apply class :parent parent :level level args)) ((transient--use-suffix-p obj)) @@ -2279,24 +2496,24 @@ value. Otherwise return CHILDREN as is.") (list obj))))) (defun transient--init-suffix (levels spec parent) - (pcase-let* ((`(,level ,class ,args) spec) + (pcase-let* ((`(,class . ,args) spec) (cmd (plist-get args :command)) - (key (transient--kbd (plist-get args :key))) + (_ (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) - level))) - (let ((fn (and (symbolp cmd) - (symbol-function cmd)))) - (when (autoloadp fn) - (transient--debug " autoload %s" cmd) - (autoload-do-load fn))) + (plist-get args :level) + (and proto (oref proto level)) + transient--default-child-level))) (when (transient--use-level-p level) (let ((obj (if (child-of-class-p class 'transient-information) (apply class :parent parent :level level args) (unless (and cmd (symbolp cmd)) (error "BUG: Non-symbolic suffix command: %s" cmd)) - (if-let ((proto (and cmd (transient--suffix-prototype cmd)))) - (apply #'clone proto :level level args) + (if proto + (apply #'clone proto :parent parent :level level args) (apply class :command cmd :parent parent :level level args))))) (cond ((not cmd)) @@ -2394,9 +2611,9 @@ value. Otherwise return CHILDREN as is.") (default))) (defun transient--suffix-predicate (spec) - (let ((plist (nth 2 spec))) + (let ((props (transient--suffix-props spec))) (seq-some (lambda (prop) - (and-let* ((pred (plist-get plist prop))) + (and-let* ((pred (plist-get props prop))) (list prop pred))) '( :if :if-not :if-nil :if-non-nil @@ -2407,13 +2624,20 @@ value. Otherwise return CHILDREN as is.") :inapt-if-mode :inapt-if-not-mode :inapt-if-derived :inapt-if-not-derived)))) +(defun transient--load-command-if-autoload (cmd) + (when-let* (((symbolp cmd)) + (fn (symbol-function cmd)) + ((autoloadp fn))) + (transient--debug " autoload %s" cmd) + (autoload-do-load fn))) + ;;; Flow-Control (defun transient--setup-transient () (transient--debug 'setup-transient) (transient--push-keymap 'transient--transient-map) (transient--push-keymap 'transient--redisplay-map) - (add-hook 'pre-command-hook #'transient--pre-command) + (add-hook 'pre-command-hook #'transient--pre-command 99) (add-hook 'post-command-hook #'transient--post-command) (advice-add 'recursive-edit :around #'transient--recursive-edit) (when transient--exitp @@ -2457,8 +2681,7 @@ value. Otherwise return CHILDREN as is.") ((not (transient--edebug-command-p)) (setq this-command 'transient-undefined)))) ((and transient--editp - ;; See TODO in that function. - (ignore-errors (transient-suffix-object)) + (transient-suffix-object) (not (memq this-command '(transient-quit-one transient-quit-all transient-help)))) @@ -2485,6 +2708,8 @@ value. Otherwise return CHILDREN as is.") (setq transient--redisplay-map nil) (setq transient--redisplay-key nil) (setq transient--helpp nil) + (unless (eq transient--docsp 'permanent) + (setq transient--docsp nil)) (setq transient--editp nil) (setq transient--prefix nil) (setq transient--layout nil) @@ -2493,28 +2718,6 @@ value. Otherwise return CHILDREN as is.") (setq transient--original-buffer nil) (setq transient--window nil)) -(defun transient--delete-window () - (when (window-live-p transient--window) - (let ((win transient--window) - (remain-in-minibuffer-window - (and (minibuffer-selected-window) - (selected-window)))) - (cond - ((eq (car (window-parameter win 'quit-restore)) 'other) - ;; Window used to display another buffer. - (set-window-parameter win 'no-other-window - (window-parameter win 'prev--no-other-window)) - (set-window-parameter win 'prev--no-other-window nil)) - ((with-demoted-errors "Error while exiting transient: %S" - (if (window-parent win) - (delete-window win) - (delete-frame (window-frame win) t))))) - (when remain-in-minibuffer-window - (select-window remain-in-minibuffer-window)))) - (when (buffer-live-p transient--buffer) - (kill-buffer transient--buffer)) - (setq transient--buffer nil)) - (defun transient--export () (setq transient-current-prefix transient--prefix) (setq transient-current-command (oref transient--prefix command)) @@ -2524,12 +2727,7 @@ value. Otherwise return CHILDREN as is.") (defun transient--suspend-override (&optional nohide) (transient--debug 'suspend-override) (transient--timer-cancel) - (let ((show (if nohide 'fixed transient-show-during-minibuffer-read))) - (when (and (integerp show) - (< (frame-height (window-frame transient--window)) - (+ (abs show) - (window-height transient--window)))) - (setq show (natnump show))) + (let ((show (transient--preserve-window-p nohide))) (cond ((not show) (transient--delete-window)) ((and transient--prefix transient--redisplay-key) @@ -2602,10 +2800,12 @@ value. Otherwise return CHILDREN as is.") ,@body))) (defun transient--wrap-command () + (transient--load-command-if-autoload this-command) (static-if (>= emacs-major-version 30) (letrec - ((prefix transient--prefix) - (suffix this-command) + ((command this-command) + (suffix (transient-suffix-object this-command)) + (prefix transient--prefix) (advice (lambda (fn &rest args) (interactive @@ -2613,59 +2813,94 @@ value. Otherwise return CHILDREN as is.") (let ((abort t)) (unwind-protect (prog1 (let ((debugger #'transient--exit-and-debug)) - (advice-eval-interactive-spec spec)) + (if-let* ((obj suffix) + (grp (oref obj parent)) + (adv (or (oref obj advice*) + (oref grp advice*)))) + (funcall + adv #'advice-eval-interactive-spec spec) + (advice-eval-interactive-spec spec))) (setq abort nil)) (when abort (when-let ((unwind (oref prefix unwind-suffix))) (transient--debug 'unwind-interactive) - (funcall unwind suffix)) - (advice-remove suffix advice) + (funcall unwind command)) + (when (symbolp command) + (remove-function (symbol-function command) advice)) (oset prefix unwind-suffix nil)))))) (unwind-protect (let ((debugger #'transient--exit-and-debug)) - (apply fn args)) + (if-let* ((obj suffix) + (grp (oref obj parent)) + (adv (or (oref obj advice) + (oref obj advice*) + (oref grp advice) + (oref grp advice*)))) + (apply adv fn args) + (apply fn args))) (when-let ((unwind (oref prefix unwind-suffix))) (transient--debug 'unwind-command) - (funcall unwind suffix)) - (advice-remove suffix advice) + (funcall unwind command)) + (when (symbolp command) + (remove-function (symbol-function command) advice)) (oset prefix unwind-suffix nil))))) - (when (symbolp this-command) - (advice-add suffix :around advice '((depth . -99)))) + (add-function :around (if (symbolp this-command) + (symbol-function this-command) + this-command) + advice '((depth . -99))) (cl-assert (>= emacs-major-version 30) nil "Emacs was downgraded, making it necessary to recompile Transient")) ;; (< emacs-major-version 30) - (let* ((prefix transient--prefix) - (suffix this-command) + (let* ((command this-command) + (suffix (transient-suffix-object this-command)) + (prefix transient--prefix) (advice nil) (advice-interactive (lambda (spec) (let ((abort t)) (unwind-protect (prog1 (let ((debugger #'transient--exit-and-debug)) - (advice-eval-interactive-spec spec)) + (if-let* ((obj suffix) + (grp (oref obj parent)) + (adv (or (oref obj advice*) + (oref grp advice*)))) + (funcall + adv #'advice-eval-interactive-spec spec) + (advice-eval-interactive-spec spec))) (setq abort nil)) (when abort (when-let ((unwind (oref prefix unwind-suffix))) (transient--debug 'unwind-interactive) - (funcall unwind suffix)) - (advice-remove suffix advice) + (funcall unwind command)) + (when (symbolp command) + (remove-function (symbol-function command) advice)) (oset prefix unwind-suffix nil)))))) (advice-body (lambda (fn &rest args) (unwind-protect (let ((debugger #'transient--exit-and-debug)) - (apply fn args)) + (if-let* ((obj suffix) + (grp (oref obj parent)) + (adv (or (oref obj advice) + (oref obj advice*) + (oref grp advice) + (oref grp advice*)))) + (apply adv fn args) + (apply fn args))) (when-let ((unwind (oref prefix unwind-suffix))) (transient--debug 'unwind-command) - (funcall unwind suffix)) - (advice-remove suffix advice) + (funcall unwind command)) + (when (symbolp command) + (remove-function (symbol-function command) advice)) (oset prefix unwind-suffix nil))))) (setq advice `(lambda (fn &rest args) (interactive ,advice-interactive) (apply ',advice-body fn args))) - (when (symbolp this-command) - (advice-add suffix :around advice '((depth . -99))))))) + (add-function :around (if (symbolp this-command) + (symbol-function this-command) + this-command) + advice '((depth . -99)))))) (defun transient--premature-post-command () (and (equal (this-command-keys-vector) []) @@ -2710,7 +2945,8 @@ value. Otherwise return CHILDREN as is.") (transient--env-apply #'transient--redisplay))))) (setq transient-current-prefix nil) (setq transient-current-command nil) - (setq transient-current-suffixes nil))) + (setq transient-current-suffixes nil) + (setq transient--current-suffix nil))) (defun transient--post-exit (&optional command) (transient--debug 'post-exit) @@ -2733,9 +2969,10 @@ value. Otherwise return CHILDREN as is.") (remove-hook 'pre-command-hook #'transient--pre-command) (remove-hook 'post-command-hook #'transient--post-command) (advice-remove 'recursive-edit #'transient--recursive-edit)) - (let ((resume (and transient--stack + (let ((replace (eq transient--exitp 'replace)) + (resume (and transient--stack (not (memq transient--exitp '(replace suspend)))))) - (unless (or resume (eq transient--exitp 'replace)) + (unless (or resume replace) (setq transient--showp nil)) (setq transient--exitp nil) (setq transient--helpp nil) @@ -2746,18 +2983,20 @@ value. Otherwise return CHILDREN as is.") (when command (setq transient-current-prefix nil) (setq transient-current-command nil) - (setq transient-current-suffixes nil)) - (when resume - (transient--stack-pop)))) + (setq transient-current-suffixes nil) + (setq transient--current-suffix nil)) + (cond (resume (transient--stack-pop)) + ((not replace) + (run-hooks 'transient-post-exit-hook))))) (defun transient--stack-push () (transient--debug 'stack-push) (push (list (oref transient--prefix command) transient--layout transient--editp - :transient-suffix (oref transient--prefix transient-suffix) - :scope (oref transient--prefix scope) - :value (transient-get-value)) + :value (transient-get-value) + :return (oref transient--prefix return) + :scope (oref transient--prefix scope)) transient--stack)) (defun transient--stack-pop () @@ -2784,7 +3023,7 @@ value. Otherwise return CHILDREN as is.") (not (zerop transient-show-popup)) (not transient--timer)) (transient--timer-start)) - (transient--show-brief))) + (transient--show-hint))) (defun transient--timer-start () (setq transient--timer @@ -2865,14 +3104,19 @@ exit." (oref transient--prefix transient-non-suffix) t)))) -(defun transient--resolve-pre-command (pre &optional resolve-boolean) - (cond ((booleanp pre) - (if resolve-boolean - (if pre #'transient--do-stay #'transient--do-warn) - pre)) - ((string-match-p "--do-" (symbol-name pre)) pre) - ((let ((sym (intern (format "transient--do-%s" pre)))) - (if (functionp sym) sym pre))))) +(defun transient--resolve-pre-command (pre &optional resolve-boolean correct) + (setq pre (cond ((booleanp pre) + (if resolve-boolean + (if pre #'transient--do-stay #'transient--do-warn) + pre)) + ((string-match-p "--do-" (symbol-name pre)) pre) + ((let ((sym (intern (format "transient--do-%s" pre)))) + (if (functionp sym) sym pre))))) + (cond ((not correct) pre) + ((and (eq pre 'transient--do-return) + (not transient--stack)) + 'transient--do-exit) + (pre))) (defun transient--do-stay () "Call the command without exporting variables and stay transient." @@ -2924,29 +3168,19 @@ Use that command's pre-command to determine transient behavior." (not (eq (posn-window (event-start last-command-event)) transient--window))) transient--stay - (setq this-command - (with-selected-window transient--window - (get-text-property (if (mouse-event-p last-command-event) - (posn-point (event-start last-command-event)) - (point)) - 'command))) + (with-selected-window transient--window + (let ((pos (if (mouse-event-p last-command-event) + (posn-point (event-start last-command-event)) + (point)))) + (setq this-command (get-text-property pos 'command)) + (setq transient--current-suffix (get-text-property pos 'suffix)))) (transient--call-pre-command))) (defun transient--do-recurse () - "Call the transient prefix command, preparing for return to active transient. + "Call the transient prefix command, preparing for return to outer transient. If there is no parent prefix, then just call the command." (transient--do-stack)) -(defun transient--setup-recursion (prefix-obj) - (when transient--stack - (let ((command (oref prefix-obj command))) - (when-let ((suffix-obj (transient-suffix-object command))) - (when (memq (if (slot-boundp suffix-obj 'transient) - (oref suffix-obj transient) - (oref transient-current-prefix transient-suffix)) - (list t #'transient--do-recurse)) - (oset prefix-obj transient-suffix t)))))) - (defun transient--do-stack () "Call the transient prefix command, stacking the active transient. Push the active transient to the transient stack." @@ -3014,8 +3248,8 @@ prefix argument and pivot to `transient-update'." (put 'transient--do-exit 'transient-face 'transient-key-exit) (put 'transient--do-leave 'transient-face 'transient-key-exit) -(put 'transient--do-recurse 'transient-face 'transient-key-stay) -(put 'transient--do-stack 'transient-face 'transient-key-stay) +(put 'transient--do-recurse 'transient-face 'transient-key-recurse) +(put 'transient--do-stack 'transient-face 'transient-key-stack) (put 'transient--do-replace 'transient-face 'transient-key-exit) (put 'transient--do-suspend 'transient-face 'transient-key-exit) @@ -3067,7 +3301,7 @@ This should never happen. Please open an issue and post the shown command log." :error))) (defun transient-inhibit-move () - "Warn the user that popup navigation is disabled." + "Warn the user that menu navigation is disabled." (interactive) (message "To enable use of `%s', please customize `%s'" this-original-command @@ -3088,12 +3322,12 @@ Please open an issue and post the shown command log." :error))) (interactive)) (defun transient-update () - "Redraw the transient's state in the popup buffer." + "Redraw the transient's state in the menu buffer." (interactive) (setq prefix-arg current-prefix-arg)) (defun transient-show () - "Show the transient's state in the popup buffer." + "Show the transient's state in the menu buffer." (interactive) (setq transient--showp t)) @@ -3134,7 +3368,8 @@ transient is active." ;;;; Help (defun transient-help (&optional interactive) - "Show help for the active transient or one of its suffixes.\n\n(fn)" + "Show help for the active transient or one of its suffixes. +\n(fn)" (interactive (list t)) (if interactive (setq transient--helpp t) @@ -3297,12 +3532,21 @@ For example: (interactive) (setq transient-show-common-commands (not transient-show-common-commands))) -(transient-define-suffix transient-toggle-docstrings () +(transient-define-suffix transient-toggle-docstrings (&optional permanent) "Toggle whether to show docstrings instead of suffix descriptions. -To make this available in all menus, bind it in `transient-map'." + +By default this is only enabled temporarily for the current transient +menu invocation. With a prefix argument, enable this until explicitly +disabled again. + +Infix arguments are not affected by this, because otherwise many menus +would likely become unreadable. To make this command available in all +menus, bind it in `transient-map'. `transient-show-docstring-format' +controls how the docstrings are displayed and whether descriptions are +also displayed." :transient t - (interactive) - (setq transient--docsp (not transient--docsp))) + (interactive (list current-prefix-arg)) + (setq transient--docsp (if permanent 'permanent (not transient--docsp)))) (defun transient-toggle-debug () "Toggle debugging statements for transient commands." @@ -3850,6 +4094,18 @@ Append \"=\ to ARG to indicate that it is an option." (or (match-string 1 match) ""))) (and (member arg args) t))) +;;; Return + +(defun transient-init-return (obj) + (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)))) + (oset obj return t))) + ;;; Scope ;;;; Init @@ -3874,37 +4130,48 @@ a default implementation, which is a noop.") ;;;; Get -(defun transient-scope (&optional prefixes) +(defun transient-scope (&optional prefixes classes) "Return the scope of the active or current transient prefix command. -If optional PREFIXES is nil, return the scope of the prefix currently -being setup, making this variant useful, e.g., in `:if*' predicates. -If no prefix is being setup, but the current command was invoked from -some prefix, then return the scope of that. - -When this function is called from the body or `interactive' form of a -suffix command, PREFIXES should be non-nil. +If optional PREFIXES and CLASSES are both nil, return the scope of +the prefix currently being setup, making this variation useful, e.g., +in `:if*' predicates. If no prefix is being setup, but the current +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 -commands. In this case try the following in order: +commands. If CLASSES is non-nil, it must be a prefix class or a list +of such classes. When this function is called from the body or the +`interactive' form of a suffix command, PREFIXES and/or CLASSES should +be non-nil. If either is non-nil, try the following in order: - If the current suffix command was invoked from a prefix, which - appears in PREFIXES, then return the scope of that prefix. + appears in PREFIXES, return the scope of that prefix. + +- If the current suffix command was invoked from a prefix, and its + class derives from one of the CLASSES, return the scope of that + prefix. + +- If a prefix is being setup and it appears in PREFIXES, return its + scope. -- If a prefix is being setup and it appears in PREFIXES, then return - its scope. +- If a prefix is being setup and its class derives from one of the + CLASSES, return its scope. -- Finally try to return the default scope of the first prefix in +- Finally try to return the default scope of the first command in PREFIXES. This only works if that slot is set in the respective class definition or using its `transient-init-scope' method. If no prefix matches, return nil." - (if prefixes - (let ((prefixes (ensure-list prefixes))) - (if-let* ((obj (or (and-let* ((obj transient-current-prefix)) - (and (memq (oref obj command) prefixes) obj)) - (and-let* ((obj transient--prefix)) - (and (memq (oref obj command) prefixes) obj))))) + (if (or prefixes classes) + (let ((prefixes (ensure-list prefixes)) + (type (if (symbolp classes) classes (cons 'or classes)))) + (if-let ((obj (cl-flet ((match (obj) + (and obj + (or (memq (oref obj command) prefixes) + (cl-typep obj type)) + obj))) + (or (match transient-current-prefix) + (match transient--prefix))))) (oref obj scope) (and (get (car prefixes) 'transient--prefix) (oref (transient--init-prefix (car prefixes)) scope)))) @@ -3943,38 +4210,11 @@ have a history of their own.") (cons val (delete val (alist-get (transient--history-key obj) transient-history)))))) -;;; Draw +;;; Display -(defun transient--show-brief () +(defun transient--show-hint () (let ((message-log-max nil)) - (if (and transient-show-popup (<= transient-show-popup 0)) - (message "%s-" (key-description (this-command-keys))) - (message - "%s- [%s] %s" - (key-description (this-command-keys)) - (oref transient--prefix command) - (mapconcat - #'identity - (sort - (mapcan - (lambda (suffix) - (let ((key (kbd (oref suffix key)))) - ;; Don't list any common commands. - (and (not (memq (oref suffix command) - `(,(lookup-key transient-map key) - ,(lookup-key transient-sticky-map key) - ;; From transient-common-commands: - transient-set - transient-save - transient-history-prev - transient-history-next - transient-quit-one - transient-toggle-common - transient-set-level))) - (list (propertize (oref suffix key) 'face 'transient-key))))) - transient--suffixes) - #'string<) - (propertize "|" 'face 'transient-delimiter)))))) + (message "%s" (transient--format-hint)))) (defun transient--show () (transient--timer-cancel) @@ -3990,28 +4230,7 @@ have a history of their own.") (button-get (1- (point)) 'command)) (transient--heading-at-point)))) (erase-buffer) - (when setup - (when transient-force-fixed-pitch - (transient--force-fixed-pitch)) - (when (bound-and-true-p tab-line-format) - (setq tab-line-format nil)) - (setq header-line-format nil) - (setq mode-line-format - (let ((format (transient--mode-line-format))) - (if (or (natnump format) (eq format 'line)) nil format))) - (setq mode-line-buffer-identification - (symbol-name (oref transient--prefix command))) - (if transient-enable-popup-navigation - (setq-local cursor-in-non-selected-windows 'box) - (setq cursor-type nil)) - (setq display-line-numbers nil) - (setq show-trailing-whitespace nil) - (run-hooks 'transient-setup-buffer-hook)) - (transient--insert-groups) - (when (or transient--helpp transient--editp) - (transient--insert-help)) - (when-let ((line (transient--separator-line))) - (insert line))) + (transient--insert-menu setup)) (unless (window-live-p transient--window) (setq transient--window (display-buffer transient--buffer @@ -4065,6 +4284,96 @@ have a history of their own.") (window-body-width window t) (window-body-height window t)))) +;;; Delete + +(defun transient--delete-window () + (when (window-live-p transient--window) + (let ((win transient--window) + (remain-in-minibuffer-window + (and (minibuffer-selected-window) + (selected-window)))) + (cond + ((eq (car (window-parameter win 'quit-restore)) 'other) + ;; Window used to display another buffer. + (set-window-parameter win 'no-other-window + (window-parameter win 'prev--no-other-window)) + (set-window-parameter win 'prev--no-other-window nil)) + ((with-demoted-errors "Error while exiting transient: %S" + (if (window-parent win) + (delete-window win) + (delete-frame (window-frame win) t))))) + (when remain-in-minibuffer-window + (select-window remain-in-minibuffer-window)))) + (when (buffer-live-p transient--buffer) + (kill-buffer transient--buffer)) + (setq transient--buffer nil)) + +(defun transient--preserve-window-p (&optional nohide) + (let ((show (if nohide 'fixed transient-show-during-minibuffer-read))) + (when (and (integerp show) + (window-live-p transient--window) + (< (frame-height (window-frame transient--window)) + (+ (abs show) + (window-height transient--window)))) + (setq show (natnump show))) + show)) + +;;; Format + +(defun transient--format-hint () + (if (and transient-show-popup (<= transient-show-popup 0)) + (format "%s-" (key-description (this-command-keys))) + (format + "%s- [%s] %s" + (key-description (this-command-keys)) + (oref transient--prefix command) + (mapconcat + #'identity + (sort + (mapcan + (lambda (suffix) + (let ((key (kbd (oref suffix key)))) + ;; Don't list any common commands. + (and (not (memq (oref suffix command) + `(,(lookup-key transient-map key) + ,(lookup-key transient-sticky-map key) + ;; From transient-common-commands: + transient-set + transient-save + transient-history-prev + transient-history-next + transient-quit-one + transient-toggle-common + transient-set-level))) + (list (propertize (oref suffix key) 'face 'transient-key))))) + transient--suffixes) + #'string<) + (propertize "|" 'face 'transient-delimiter))))) + +(defun transient--insert-menu (setup) + (when setup + (when transient-force-fixed-pitch + (transient--force-fixed-pitch)) + (when (bound-and-true-p tab-line-format) + (setq tab-line-format nil)) + (setq header-line-format nil) + (setq mode-line-format + (let ((format (transient--mode-line-format))) + (if (or (natnump format) (eq format 'line)) nil format))) + (setq mode-line-buffer-identification + (symbol-name (oref transient--prefix command))) + (if transient-enable-popup-navigation + (setq-local cursor-in-non-selected-windows 'box) + (setq cursor-type nil)) + (setq display-line-numbers nil) + (setq show-trailing-whitespace nil) + (run-hooks 'transient-setup-buffer-hook)) + (transient--insert-groups) + (when (or transient--helpp transient--editp) + (transient--insert-help)) + (when-let ((line (transient--separator-line))) + (insert line))) + (defun transient--mode-line-format () (if (slot-boundp transient--prefix 'mode-line-format) (oref transient--prefix mode-line-format) @@ -4332,16 +4641,22 @@ face `transient-heading' to the complete string." If the result is nil, then use \"(BUG: no description)\" as the description. If the OBJ's `key' is currently unreachable, then apply the face `transient-unreachable' to the complete string." - (let ((desc (if-let ((transient--docsp) - (cmd (oref obj command)) - (doc (ignore-errors (documentation cmd))) - ((not (equal doc (documentation - 'transient--default-infix-command))))) - (substring doc 0 (string-match "\\.?\n" doc)) - (or (cl-call-next-method obj) - (and (slot-boundp transient--prefix 'suffix-description) - (funcall (oref transient--prefix suffix-description) - obj)))))) + (let ((desc (or (cl-call-next-method obj) + (and (slot-boundp transient--prefix 'suffix-description) + (funcall (oref transient--prefix suffix-description) + obj))))) + (when-let* ((transient--docsp) + ((slot-boundp obj 'command)) + (cmd (oref obj command)) + ((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 "")))) + (setq desc (format-spec transient-show-docstring-format + `((?c . ,desc) + (?s . ,docstr))))) (if desc (when-let ((face (transient--get-face obj 'face))) (setq desc (transient--add-face desc face t))) @@ -4653,34 +4968,45 @@ Select the help window, and make the help buffer current and return it." (insert "\n")) (when transient--helpp (insert - (format (propertize "\ + (format + (propertize "\ Type a %s to show help for that suffix command, or %s to show manual. Type %s to exit help.\n" - 'face 'transient-heading) - (propertize "" 'face 'transient-key) - (propertize "?" 'face 'transient-key) - (propertize "C-g" 'face 'transient-key)))) + 'face 'transient-heading) + (propertize "" 'face 'transient-key) + (propertize "?" 'face 'transient-key) + (propertize "C-g" 'face 'transient-key)))) (when transient--editp (unless transient--helpp (insert - (format (propertize "\ -Type a %s to set level for that suffix command. -Type %s to set what levels are available for this prefix command.\n" - 'face 'transient-heading) - (propertize "" 'face 'transient-key) - (propertize "C-x l" 'face 'transient-key)))) + (format + (propertize "\ +Type %s and then %s to put the respective suffix command on level %s. +Type %s and then %s to display suffixes up to level %s in this menu. +Type %s and then %s to describe the respective suffix command.\n" + 'face 'transient-heading) + (propertize "" 'face 'transient-key) + (propertize "" 'face 'transient-key) + (propertize " N " 'face 'transient-enabled-suffix) + (propertize (concat transient-common-command-prefix " l") + 'face 'transient-key) + (propertize "" 'face 'transient-key) + (propertize " N " 'face 'transient-enabled-suffix) + (propertize "C-h" 'face 'transient-key) + (propertize "" 'face 'transient-key)))) (with-slots (level) transient--prefix (insert - (format (propertize " -Suffixes on levels %s are available. -Suffixes on levels %s and %s are unavailable.\n" - 'face 'transient-heading) - (propertize (format "1-%s" level) - 'face 'transient-enabled-suffix) - (propertize " 0 " - 'face 'transient-disabled-suffix) - (propertize (format ">=%s" (1+ level)) - 'face 'transient-disabled-suffix)))))) + (format + (propertize " +The current level of this menu is %s, so + commands on levels %s are displayed, and + commands on levels %s and %s are not displayed.\n" + 'face 'transient-heading) + (propertize (format " %s " level) 'face 'transient-enabled-suffix) + (propertize (format " 1..%s " level) 'face 'transient-enabled-suffix) + (propertize (format " >= %s " (1+ level)) + 'face 'transient-disabled-suffix) + (propertize " 0 " 'face 'transient-disabled-suffix)))))) (cl-defgeneric transient-show-summary (obj &optional return) "Show brief summary about the command at point in the echo area. @@ -4700,7 +5026,8 @@ This is used when a tooltip is needed.") ((doc (cond ((functionp summary) (funcall summary obj)) (summary) - ((car (split-string (documentation command) "\n"))))) + ((documentation command) + (car (split-string (documentation command) "\n"))))) ((stringp doc)) ((not (equal doc (car (split-string (documentation @@ -4713,10 +5040,10 @@ This is used when a tooltip is needed.") (let ((message-log-max nil)) (message "%s" doc)))))) -;;; Popup Navigation +;;; Menu Navigation (defun transient-scroll-up (&optional arg) - "Scroll text of transient popup window upward ARG lines. + "Scroll text of transient's menu window upward ARG lines. If ARG is nil scroll near full screen. This is a wrapper around `scroll-up-command' (which see)." (interactive "^P") @@ -4724,7 +5051,7 @@ around `scroll-up-command' (which see)." (scroll-up-command arg))) (defun transient-scroll-down (&optional arg) - "Scroll text of transient popup window down ARG lines. + "Scroll text of transient's menu window down ARG lines. If ARG is nil scroll near full screen. This is a wrapper around `scroll-down-command' (which see)." (interactive "^P") @@ -4732,7 +5059,7 @@ around `scroll-down-command' (which see)." (scroll-down-command arg))) (defun transient-backward-button (n) - "Move to the previous button in the transient popup buffer. + "Move to the previous button in transient's menu buffer. See `backward-button' for information about N." (interactive "p") (with-selected-window transient--window @@ -4741,7 +5068,7 @@ See `backward-button' for information about N." (transient-show-summary (get-text-property (point) 'suffix))))) (defun transient-forward-button (n) - "Move to the next button in the transient popup buffer. + "Move to the next button in transient's menu buffer. See `forward-button' for information about N." (interactive "p") (with-selected-window transient--window @@ -4781,7 +5108,7 @@ See `forward-button' for information about N." beg 'face nil (line-end-position)))))) ;;; Compatibility -;;;; Popup Isearch +;;;; Menu Isearch (defvar-keymap transient--isearch-mode-map :parent isearch-mode-map @@ -4859,6 +5186,16 @@ search instead." 2) lisp-imenu-generic-expression :test #'equal) +(defun transient--suspend-text-conversion-style () + (static-if (boundp 'overriding-text-conversion-style) ; since Emacs 30.1 + (when text-conversion-style + (letrec ((suspended overriding-text-conversion-style) + (fn (lambda () + (setq overriding-text-conversion-style nil) + (remove-hook 'transient-exit-hook fn)))) + (setq overriding-text-conversion-style suspended) + (add-hook 'transient-exit-hook fn))))) + (declare-function which-key-mode "ext:which-key" (&optional arg)) (defun transient--suspend-which-key-mode () @@ -4872,22 +5209,22 @@ search instead." (remove-hook 'transient-exit-hook #'transient--resume-which-key-mode))) (defun transient-bind-q-to-quit () - "Modify some keymaps to bind \"q\" to the appropriate quit command. + "Modify some keymaps to bind \\`q' to the appropriate quit command. -\"C-g\" is the default binding for such commands now, but Transient's -predecessor Magit-Popup used \"q\" instead. If you would like to get +\\`C-g' is the default binding for such commands now, but Transient's +predecessor Magit-Popup used \\`q' instead. If you would like to get that binding back, then call this function in your init file like so: (with-eval-after-load \\='transient (transient-bind-q-to-quit)) -Individual transients may already bind \"q\" to something else +Individual transients may already bind \\`q' to something else and such a binding would shadow the quit binding. If that is the -case then \"Q\" is bound to whatever \"q\" would have been bound +case then \\`Q' is bound to whatever \\`q' would have been bound to by setting `transient-substitute-key-function' to a function -that does that. Of course \"Q\" may already be bound to something -else, so that function binds \"M-q\" to that command instead. -Of course \"M-q\" may already be bound to something else, but +that does that. Of course \\`Q' may already be bound to something +else, so that function binds \\`M-q' to that command instead. +Of course \\`M-q' may already be bound to something else, but we stop there." (keymap-set transient-base-map "q" #'transient-quit-one) (keymap-set transient-sticky-map "q" #'transient-quit-seq) @@ -4932,6 +5269,7 @@ as stand-in for elements of exhausted lists." (eval-when-compile `((,(concat "(" (regexp-opt (list "transient-define-prefix" + "transient-define-group" "transient-define-infix" "transient-define-argument" "transient-define-suffix") diff --git a/elpa/transient-20241224.2234/transient.info b/elpa/transient-20250520.1040/transient.info similarity index 87% rename from elpa/transient-20241224.2234/transient.info rename to elpa/transient-20250520.1040/transient.info index da245139..3d3c4c7b 100644 --- a/elpa/transient-20241224.2234/transient.info +++ b/elpa/transient-20250520.1040/transient.info @@ -1,7 +1,7 @@ This is transient.info, produced by makeinfo version 6.8 from transient.texi. - Copyright (C) 2018–2024 Free Software Foundation, Inc. + Copyright (C) 2018–2025 Free Software Foundation, Inc. You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -32,9 +32,9 @@ used to implement similar menus in other packages. resource to get over that hurdle is Psionic K’s interactive tutorial, available at . -This manual is for Transient version 0.8.1. +This manual is for Transient version 0.8.8. - Copyright (C) 2018–2024 Free Software Foundation, Inc. + Copyright (C) 2018–2025 Free Software Foundation, Inc. You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -81,16 +81,11 @@ Defining New Commands * Binding Suffix and Infix Commands:: * Defining Suffix and Infix Commands:: * Using Infix Arguments:: +* Using Prefix Scope:: * Current Suffix Command:: * Current Prefix Command:: * Transient State:: -Binding Suffix and Infix Commands - -* Group Specifications:: -* Suffix Specifications:: - - Classes and Methods * Group Classes:: @@ -103,12 +98,6 @@ Classes and Methods * Suffix Slots:: * Predicate Slots:: -Suffix Methods - -* Suffix Value Methods:: -* Suffix Format Methods:: - -  File: transient.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top @@ -211,14 +200,15 @@ A transient prefix command is invoked like any other command by pressing the key that is bound to that command. The main difference to other commands is that a transient prefix command activates a transient keymap, which temporarily binds the transient’s infix and suffix -commands, and that those bindings are displayed in a transient menu, -displayed in a popup buffer. Bindings from other keymaps may, or may -not, be disabled while the transient state is in effect. +commands, and that those bindings are shown in menu buffer, which is +displayed in a new window, until the menu is exited. Bindings from +other keymaps may, or may not, be disabled while the transient state is +in effect. There are two kinds of commands that are available after invoking a transient prefix command; infix and suffix commands. Infix commands set -some value (which is then shown in the popup buffer), without leaving -the transient. Suffix commands, on the other hand, usually quit the +some value (which is then shown in the menu buffer), without leaving the +transient. Suffix commands, on the other hand, usually quit the transient and they may use the values set by the infix commands, i.e., the infix *arguments*. @@ -243,7 +233,7 @@ prefix key, but not the complete transient). A transient prefix command can be bound as a suffix of another transient. Invoking such a suffix replaces the current transient state with a new transient state, i.e., the available bindings change and the -information displayed in the popup buffer is updated accordingly. +information displayed in the menu buffer is updated accordingly. Pressing ‘C-g’ while a nested transient is active only quits the innermost transient, causing a return to the previous transient. @@ -289,32 +279,54 @@ File: transient.info, Node: Common Suffix Commands, Next: Saving Values, Prev ========================== A few shared suffix commands are available in all transients. These -suffix commands are not shown in the popup buffer by default. +suffix commands are not shown permanently in every menu by default. +Most of these commands share a common prefix key and pressing that key +causes the common commands to be temporarily shown in the active menu. - This includes the aborting commands mentioned in the previous -section, as well as some other commands that are all bound to ‘C-x KEY’. -After ‘C-x’ is pressed, a section featuring all these common commands is -temporarily shown in the popup buffer. After invoking one of them, the -section disappears again. Note, however, that one of these commands is -described as “Show common permanently”; invoke that if you want the -common commands to always be shown for all transients. + -- User Option: transient-show-common-commands + This option controls whether shared suffix commands are permanently + shown alongside the menu-specific infix and suffix commands. By + default, the shared commands are not permanently shown to avoid + wasting precious space and overwhelming the user with too many + choices. + + If you prefer to always see these commands, then set this option to + a non-‘nil’ value. Alternatively the value can be toggled for the + current Emacs session only, using ‘transient-toggle-common’, + described below. + + -- User Option: transient-common-command-prefix + This option specifies the prefix key used in all transient menus to + invoke most of the shared commands, which are available in all + transient menus. By default these bindings are only shown after + pressing that prefix key and before following that up with a valid + key binding (but see the previous option). + + For historic reasons ‘C-x’ is used by default, but users are + encouraged to pick another key, preferably one that is not commonly + used in Emacs but is still convenient to them. + + Usually, while a transient menu is active, the user cannot invoke + commands that are not bound in the menu itself. For those menus it + does not matter, if ‘C-x’ or another commonly used prefix key is + used for common menu commands. However, certain other, newer menus + do not suppress key bindings established outside the menu itself, + and in those cases a binding for a common menu command could shadow + an external binding. For example, ‘C-x C-s’ could not be used to + invoke ‘save-buffer’, if that binding is shadowed by the menu + binding for ‘transient-save’. + + Which key is most suitable depends on the user’s preferences, but + good choices may include function keys and ‘C-z’ (for many keyboard + layouts ‘z’ is right next to ‘x’, and invoking ‘suspend-frame’, + while a transient menu is active, would not be a good idea anyway). ‘C-x t’ (‘transient-toggle-common’) - This command toggles whether the generic commands that are common - to all transients are always displayed or only after typing the - incomplete prefix key sequence ‘C-x’. This only affects the + This command toggles whether the generic commands, that are common + to all transients, are permanently displayed or only after typing + the incomplete prefix key sequence‘’. This only affects the current Emacs session. - -- User Option: transient-show-common-commands - This option controls whether shared suffix commands are shown - alongside the transient-specific infix and suffix commands. By - default, the shared commands are not shown to avoid overwhelming - the user with too many options. - - While a transient is active, pressing ‘C-x’ always shows the common - commands. The value of this option can be changed for the current - Emacs session by typing ‘C-x t’ while a transient is active. - The other common commands are described in either the previous or in one of the following sections. @@ -338,6 +350,10 @@ 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, but it is easily accessible (see *note Using History::). + Option ‘transient-common-command-prefix’ controls the prefix key used +in the following bindings. For simplicity’s sake the default, ‘C-x’, is +shown below. + ‘C-x s’ (‘transient-set’) This command saves the value of the active transient for this Emacs session. @@ -371,6 +387,10 @@ value is saved to its history. These values can be cycled through, the same way one can cycle through the history of commands that read user-input in the minibuffer. + Option ‘transient-common-command-prefix’ controls the prefix key used +in the following bindings. For simplicity’s sake the default, ‘C-x’, is +shown below. + ‘C-M-p’ (‘transient-history-prev’) ‘C-x p’ This command switches to the previous value used for the active @@ -455,8 +475,8 @@ For suffixes, 0 is also valid; it means that the suffix is not displayed at any level. The levels of individual transients and/or their individual suffixes -can be changed interactively, by invoking the transient and then -pressing ‘C-x l’ to enter the “edit” mode, see below. +can be changed interactively, by invoking the menu and entering its +“edit” mode using the command ‘transient-set-level’, as described below. The default level for both transients and their suffixes is 4. The ‘transient-default-level’ option only controls the default for @@ -475,6 +495,10 @@ if the user lowers the transient level. This option names the file that is used to persist the levels of transients and their suffixes between Emacs sessions. + Option ‘transient-common-command-prefix’ controls the prefix key used +in the following bindings. For simplicity’s sake the default, ‘C-x’, is +shown below. + ‘C-x l’ (‘transient-set-level’) This command enters edit mode. When edit mode is active, then all infixes and suffixes that are currently usable are displayed along @@ -505,6 +529,45 @@ if the user lowers the transient level. the level specified by ‘transient-default-level’ are temporarily available anyway. + -- Function: transient-set-default-level suffix level + This function sets the default level of the suffix COMMAND to + LEVEL. + + If a suffix command appears in multiple menus, it may make sense to + consistently change its level in all those menus at once. For + example, the ‘--gpg-sign’ argument (which is implemented using the + command ‘magit:--gpg-sign’), is bound in all of Magit’s menu which + create commits. Users who sometimes sign their commits would want + that argument to be available in all of these menus, while for + users who never sign it is just unnecessary noise in any menus. + + To always make ‘--gpg-sign’ available, use: + + (transient-set-default-level 'magit:--gpg-sign 1) + + To never make ‘--gpg-sign’ available, use: + + (transient-set-default-level 'magit:--gpg-sign 0) + + This sets the level in the suffix prototype object for this + command. Commands only have a suffix prototype if they were + defined using one of ‘transient-define-argument’, + ‘transient-define-infix’ and ‘transient-define-suffix’. For all + other commands this would signal an error. (This is one of the + reasons why package authors should use one of these functions to + define shared suffix commands, and especially shared arguments.) + + If the user changes the level of a suffix in a particular menu, + using ‘C-x l’ as shown above, then that obviously shadows the + default. + + It is also possible to set the level of a suffix binding in a + particular menu, either when defining the menu using + ‘transient-define-prefix,’ or later using + ‘transient-insert-suffix’. If such bindings specify a level, then + that also overrides the default. (Per-suffix default levels is a + new feature, so you might encounter this quite often.) +  File: transient.info, Node: Other Commands, Next: Configuration, Prev: Enabling and Disabling Suffixes, Up: Usage @@ -518,14 +581,14 @@ window, and the key bindings are the same as for ‘scroll-up-command’ and ‘scroll-down-command’ in other buffers. -- Command: transient-scroll-up arg - This command scrolls text of transient popup window upward ARG + This command scrolls text of transient’s menu window upward ARG lines. If ARG is ‘nil’, then it scrolls near full screen. This is a wrapper around ‘scroll-up-command’ (which see). -- Command: transient-scroll-down arg - This command scrolls text of transient popup window down ARG lines. - If ARG is ‘nil’, then it scrolls near full screen. This is a - wrapper around ‘scroll-down-command’ (which see). + This command scrolls text of transient’s menu window down ARG + lines. If ARG is ‘nil’, then it scrolls near full screen. This is + a wrapper around ‘scroll-down-command’ (which see). The following commands are not available by default. If you would like to use them for all menus, bind them in ‘transient-map’. @@ -555,39 +618,30 @@ Disabling Suffixes::. Essential Options ----------------- -Also see *note Common Suffix Commands::. +Two more essential options are documented in *note Common Suffix +Commands::. -- User Option: transient-show-popup - This option controls whether the current transient’s infix and - suffix commands are shown in the popup buffer. + This option controls whether and when transient’s menu buffer is + shown. - • If ‘t’ (the default) then the popup buffer is shown as soon as - a transient prefix command is invoked. + • If ‘t’ (the default), then the buffer is shown as soon as a + transient prefix command is invoked. - • If ‘nil’, then the popup buffer is not shown unless the user + • If ‘nil’, then the buffer is not shown unless the user explicitly requests it, by pressing an incomplete prefix key sequence. • If a number, then the a brief one-line summary is shown - instead of the popup buffer. If zero or negative, then not + instead of the menu buffer. If zero or negative, then not even that summary is shown; only the pressed key itself is shown. - The popup is shown when the user explicitly requests it by + The buffer is shown once the user explicitly requests it by pressing an incomplete prefix key sequence. Unless this is - zero, the popup is shown after that many seconds of inactivity + zero, the menu is shown after that many seconds of inactivity (using the absolute value). - -- User Option: transient-show-common-commands - This option controls whether shared suffix commands are shown - alongside the transient-specific infix and suffix commands. By - default, the shared commands are not shown to avoid overwhelming - the user with too many options. - - While a transient is active, pressing ‘C-x’ always shows the common - commands. The value of this option can be changed for the current - Emacs session by typing ‘C-x t’ while a transient is active. - -- User Option: transient-show-during-minibuffer-read This option controls whether the transient menu continues to be displayed while the minibuffer is used to read user input. @@ -633,21 +687,21 @@ Also see *note Common Suffix Commands::. elements. -- User Option: transient-enable-popup-navigation - This option controls whether navigation commands are enabled in the - transient popup buffer. If the value is ‘verbose’ (the default), + This option controls whether navigation commands are enabled in + transient’s menu buffer. If the value is ‘verbose’ (the default), brief documentation about the command under point is additionally show in the echo area. - While a transient is active the transient popup buffer is not the - current buffer, making it necessary to use dedicated commands to - act on that buffer itself. If this option is non-‘nil’, then the + While a transient is active the menu buffer is not the current + buffer, making it necessary to use dedicated commands to act on + that buffer itself. If this option is non-‘nil’, then the following features are available: • ‘’ moves the cursor to the previous suffix. • ‘’ moves the cursor to the next suffix. • ‘M-’ invokes the suffix the cursor is on. • ‘mouse-1’ invokes the clicked on suffix. - • ‘C-s’ and ‘C-r’ start isearch in the popup buffer. + • ‘C-s’ and ‘C-r’ start isearch in the menu buffer. By default ‘M-’ is bound to ‘transient-push-button’, instead of ‘’, because if a transient allows the invocation of @@ -655,9 +709,9 @@ Also see *note Common Suffix Commands::. what it would do if no transient were active." -- User Option: transient-display-buffer-action - This option specifies the action used to display the transient - popup buffer. The transient popup buffer is displayed in a window - using ‘(display-buffer BUFFER transient-display-buffer-action)’. + This option specifies the action used to display the transient’s + menu buffer. The menu buffer is displayed in a window using + ‘(display-buffer BUFFER transient-display-buffer-action)’. The value of this option has the form ‘(FUNCTION . ALIST)’, where FUNCTION is a function or a list of functions. Each such function @@ -676,6 +730,11 @@ Also see *note Common Suffix Commands::. alternatives see *note (elisp)Buffer Display Action Functions::, and *note (elisp)Buffer Display Action Alists::. + When you switch to a different ACTION, you should keep the ALIST + entries for ‘dedicated’ and ‘inhibit-same-window’ in most cases. + Do not drop them because you are unsure whether they are needed; if + you are unsure, then keep them. + Note that the buffer that was current before the transient buffer is shown should remain the current buffer. Many suffix commands act on the thing at point, if appropriate, and if the transient @@ -707,7 +766,7 @@ Auxiliary Options ----------------- -- User Option: transient-mode-line-format - This option controls whether the transient popup buffer has a + This option controls whether transient’s menu buffer has a mode-line, separator line, or neither. If ‘nil’, then the buffer has no mode-line. If the buffer is not @@ -783,7 +842,7 @@ Auxiliary Options -- User Option: transient-align-variable-pitch This option controls whether columns are aligned pixel-wise in the - popup buffer. + menu buffer. If this is non-‘nil’, then columns are aligned pixel-wise to support variable-pitch fonts. Keys are not aligned, so you should @@ -796,10 +855,10 @@ Auxiliary Options -- User Option: transient-force-fixed-pitch This option controls whether to force the use of a monospaced font - in popup buffer. Even if you use a proportional font for the + in menu buffer. Even if you use a proportional font for the ‘default’ face, you might still want to use a monospaced font in - transient’s popup buffer. Setting this option to ‘t’ causes - ‘default’ to be remapped to ‘fixed-pitch’ in that buffer. + the menu buffer. Setting this option to ‘t’ causes ‘default’ to be + remapped to ‘fixed-pitch’ in that buffer. Developer Options ----------------- @@ -819,6 +878,12 @@ These options are mainly intended for developers. predicates of those suffixes prevent that more than one of them is enabled at a time. + -- User Option: transient-error-on-insert-failure + This option controls whether to signal an error when + ‘transient-insert-suffix’ or ‘transient-append-suffix’ failed to + insert a suffix into an existing prefix. By default a warning is + shown instead. + -- User Option: transient-highlight-higher-levels This option controls whether suffixes that would not be available by default are highlighted. @@ -833,7 +898,12 @@ Hook Variables -------------- -- Variable: transient-exit-hook - This hook is run after a transient is exited. + This hook is run after a transient menu is exited, even if another + transient menu becomes active at the same time. + + -- Variable: transient-post-exit-hook + This hook is run after a transient menu is exited, provided no + other transient menu becomes active at the same time. -- Variable: transient-setup-buffer-hook This hook is run when the transient buffer is being setup. That @@ -854,12 +924,15 @@ an example: '("-R" "Apply in reverse" "--reverse")) This inserts a new infix argument to toggle the ‘--reverse’ argument -after the infix argument that toggles ‘-3’ in ‘magit-patch-apply’. +after the infix argument that is bound to ‘-3’ in ‘magit-patch-apply’. The following functions share a few arguments: • PREFIX is a transient prefix command, a symbol. + PREFIX may also by a symbol identifying a separately defined group, + which can be included in multiple prefixes. See TODO. + • SUFFIX is a transient infix or suffix specification in the same form as expected by ‘transient-define-prefix’. Note that an infix is a special kind of suffix. Depending on context “suffixes” means @@ -869,24 +942,33 @@ after the infix argument that toggles ‘-3’ in ‘magit-patch-apply’. SUFFIX may also be a group in the same form as expected by ‘transient-define-prefix’. See *note Group Specifications::. - • LOC is a command, a key vector, a key description (a string as - returned by ‘key-description’), or a list specifying coordinates - (the last element may also be a command or key). For example ‘(1 0 - -1)’ identifies the last suffix (‘-1’) of the first subgroup (‘0’) - of the second group (‘1’). + • LOC is a key description (a string as returned by ‘key-description’ + and understood by ‘kbd’), a command, a symbol identifying an + included group, or a vector specifying coordinates. For example, + ‘[1 0 -1]’ identifies the last suffix (‘-1’) of the first subgroup + (‘0’) of the second group (‘1’). - If LOC is a list of coordinates, then it can be used to identify a - group, not just an individual suffix command. + If LOC is a vector, then it can be used to identify a group, not + just an individual suffix command. The last element in a vector + may also be a symbol or key, in which case the preceding elements + must match a group and the last element is looked up within that + group. The function ‘transient-get-suffix’ can be useful to determine - whether a certain coordination list identifies the suffix or group + whether a certain coordinate vector identifies the suffix or group that you expect it to identify. In hairy cases it may be necessary - to look at the definition of the transient prefix command. + to look at the internal layout representation, which you can access + using the function ‘transient--get-layout’. These functions operate on the information stored in the -‘transient--layout’ property of the PREFIX symbol. Suffix entries in -that tree are not objects but have the form ‘(LEVEL CLASS PLIST)’, where -PLIST should set at least ‘:key’, ‘:description’ and ‘:command’. +‘transient--layout’ property of the PREFIX symbol. Elements in that +tree are not objects but have the form ‘(CLASS PLIST) for suffixes’ and +[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, +currently and hopefully for a long time 2. While that element looks +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 +root element itself. -- Function: transient-insert-suffix prefix loc suffix &optional keep-other @@ -902,8 +984,11 @@ PLIST should set at least ‘:key’, ‘:description’ and ‘:command’. Predicate Slots::. Unfortunately both false-positives and false-negatives are - possible. To deal with the former use non-‘nil’ KEEP-OTHER. To - deal with the latter remove the conflicting binding explicitly. + possible. To deal with the former, use non-‘nil’ KEEP-OTHER. The + symbol ‘always’ prevents the removal of a false-positive, in some + cases where other non-‘nil’ values would fail. To deal with + false-negatives remove the conflicting binding separately, using + ‘transient-remove-suffix’. -- Function: transient-replace-suffix prefix loc suffix This function replaces the suffix or group at LOC in PREFIX with @@ -920,14 +1005,27 @@ PLIST should set at least ‘:key’, ‘:description’ and ‘:command’. This function edits the suffix or group at LOC in PREFIX, by setting the PROP of its plist to VALUE. + Some prefix commands share suffixes, which are separately and then +included in each prefix when it is defined. The inclusion is done by +reference, the included suffix groups are not inlined by default. So if +you change, for example, the key binding for an argument in ‘magit-diff’ +(‘d’) the same change also applies to ‘magit-diff-refresh’ (‘D’). In +the rare case that this is not desirable use ‘transient-inline-group’ +before making changes to included suffixes. + + -- Function: transient-inline-group PREFIX GROUP + This function inlines the included GROUP into PREFIX, by replacing + the symbol GROUP with its expanded layout in the layout of PREFIX. + Most of these functions do not signal an error if they cannot perform the requested modification. The functions that insert new suffixes show a warning if LOC cannot be found in PREFIX without signaling an error. The reason for doing it like this is that establishing a key binding (and that is what we essentially are trying to do here) should not prevent the rest of the configuration from loading. Among these -functions only ‘transient-get-suffix’ and ‘transient-suffix-put’ may -signal an error. +functions only ‘transient-get-suffix’ and ‘transient-suffix-put’ signal +an error by default. If you really want the insert functions to also +signal an error, set ‘transient-error-on-insert-failure’ to ‘t’.  File: transient.info, Node: Defining New Commands, Next: Classes and Methods, Prev: Modifying Existing Transients, Up: Top @@ -942,6 +1040,7 @@ File: transient.info, Node: Defining New Commands, Next: Classes and Methods, * Binding Suffix and Infix Commands:: * Defining Suffix and Infix Commands:: * Using Infix Arguments:: +* Using Prefix Scope:: * Current Suffix Command:: * Current Prefix Command:: * Transient State:: @@ -960,7 +1059,7 @@ arguments and suffix commands. (temporary) keymap is activated, which binds the transient’s infix and suffix commands, and functions that control the transient state are added to ‘pre-command-hook’ and ‘post-command-hook’. The available -suffix and infix commands and their state are shown in a popup buffer +suffix and infix commands and their state are shown in a menu buffer until the transient state is exited by invoking a suffix command. Calling an infix command causes its value to be changed. How that is @@ -971,8 +1070,8 @@ on or off. More complex infix commands may read a value from the user, using the minibuffer. Calling a suffix command usually causes the transient to be exited; -the transient keymaps and hook functions are removed, the popup buffer -no longer shows information about the (no longer bound) suffix commands, +the transient keymaps and hook functions are removed, the menu buffer no +longer shows information about the (no longer bound) suffix commands, the values of some public global variables are set, while some internal global variables are unset, and finally the command is actually called. Suffix commands can also be configured to not exit the transient. @@ -987,11 +1086,11 @@ arguments have been set using a command such as ‘universal-argument’. Transient can be used to implement simple “command dispatchers”. The main benefit then is that the user can see all the available commands in -a popup buffer, which can be thought of as a “menu”. That is useful by -itself because it frees the user from having to remember all the keys -that are valid after a certain prefix key or command. Magit’s -‘magit-dispatch’ (on ‘C-x M-g’) command is an example of using Transient -to merely implement a command dispatcher. +a temporarily shown buffer, which can be thought of as a “menu”. That +is useful by itself because it frees the user from having to remember +all the keys that are valid after a certain prefix key or command. +Magit’s ‘magit-dispatch’ (on ‘C-x M-g’) command is an example of using +Transient to merely implement a command dispatcher. In addition to that, Transient also allows users to interactively pass arguments to commands. These arguments can be much more complex @@ -1074,7 +1173,7 @@ that is used to invoke that transient. explicitly. GROUPs add key bindings for infix and suffix commands and specify - how these bindings are presented in the popup buffer. At least one + how these bindings are presented in the menu buffer. At least one GROUP has to be specified. See *note Binding Suffix and Infix Commands::. @@ -1101,6 +1200,21 @@ that is used to invoke that transient. For example, the scope of the ‘magit-branch-configure’ transient is the branch whose variables are being configured. + Sometimes multiple prefix commands share a common set of suffixes. +For example, while ‘magit-diff’ (‘d’) and ‘magit-diff-refresh’ (‘D’) +offer different suffixes to actually create or update a diff, they both +offer the same infix arguments to control how that diff is formatted. +Such shared groups should be defined using ‘transient-define-group’ and +then included in multiple prefixes, by using the symbol that identifies +the group in the prefix definition, in a location where you would +otherwise use a group vector. If an included group is placed at the +top-level of a prefix (as opposed of inside inside a vector as a child +group), then the symbol should be quoted. + + -- Macro: transient-define-group name group... + This macro define one or more groups and stores them in symbol + NAME. GROUPs have the same form as for ‘transient-define-prefix’. +  File: transient.info, Node: Binding Suffix and Infix Commands, Next: Defining Suffix and Infix Commands, Prev: Defining Transients, Up: Defining New Commands @@ -1118,14 +1232,6 @@ Existing Transients::). These functions take a “suffix specification” as one of their arguments, which has the same form as the specifications used in ‘transient-define-prefix’. -* Menu: - -* Group Specifications:: -* Suffix Specifications:: - - -File: transient.info, Node: Group Specifications, Next: Suffix Specifications, Up: Binding Suffix and Infix Commands - 4.3.1 Group Specifications -------------------------- @@ -1243,6 +1349,13 @@ constructor of that class. suffixes contained in a group are right padded, effectively aligning the descriptions. + • If a keyword argument accepts a function as value, you an use a + ‘lambda’ expression. As a special case, the ‘##’ macro (which + returns a ‘lambda’ expression and is implemented in the ‘llama’ + package) is also supported. Inside group specifications, the use + of ‘##’ is not supported anywhere but directly following a keyword + symbol. + The ELEMENTs are either all subgroups, or all suffixes and strings. (At least currently no group type exists that would allow mixing subgroups with commands at the same level, though in principle there is @@ -1261,9 +1374,6 @@ This feature is experimental and should be avoided. The form of suffix specifications is documented in the next node. - -File: transient.info, Node: Suffix Specifications, Prev: Group Specifications, Up: Binding Suffix and Infix Commands - 4.3.2 Suffix Specifications --------------------------- @@ -1295,7 +1405,16 @@ transient. • LEVEL is the suffix level, an integer between 1 and 7. See *note Enabling and Disabling Suffixes::. - • KEY is the key binding, either a vector or key description string. + • KEY is the key binding, a string in the format returned by + ‘describe-key’ and understood by ‘kbd’. + + That format is more permissive than the one accepted by + ‘key-valid-p’. Being more permissive makes it possible, for + example, to write the key binding, which toggles the ‘-a’ command + line argument, as "-a", instead of having to write "- a". Likewise + additional spaces can be added, which is not removed when + displaying the binding in the menu, which is useful for alignment + purposes. • DESCRIPTION is the description, either a string or a function that takes zero or one arguments (the suffix object) and returns a @@ -1341,7 +1460,7 @@ only argument that is mandatory in all cases. can also be specified using ‘:shortarg’) and the second as the long argument (which can also be specified using ‘:argument’). - Only the long argument is displayed in the popup buffer. See + Only the long argument is displayed in the menu buffer. See ‘transient-detect-key-conflicts’ for how the short argument may be used. @@ -1355,6 +1474,12 @@ Each keyword has to be a keyword symbol, either ‘:class’ or a keyword argument supported by the constructor of that class. See *note Suffix Slots::. + If a keyword argument accepts a function as value, you an use a +‘lambda’ expression. As a special case, the ‘##’ macro (which returns a +‘lambda’ expression and is implemented in the ‘llama’ package) is also +supported. Inside suffix bindings, the use of ‘##’ is not supported +anywhere but directly following a keyword symbol. +  File: transient.info, Node: Defining Suffix and Infix Commands, Next: Using Infix Arguments, Prev: Binding Suffix and Infix Commands, Up: Defining New Commands @@ -1422,7 +1547,7 @@ Note that an infix is a special kind of suffix. Depending on context ‘transient-define-infix’ instead.  -File: transient.info, Node: Using Infix Arguments, Next: Current Suffix Command, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands +File: transient.info, Node: Using Infix Arguments, Next: Using Prefix Scope, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands 4.5 Using Infix Arguments ========================= @@ -1474,9 +1599,56 @@ same purpose as ‘prefix-arg’ serves for prefix arguments. if the current command is not being invoked from PREFIX.  -File: transient.info, Node: Current Suffix Command, Next: Current Prefix Command, Prev: Using Infix Arguments, Up: Defining New Commands +File: transient.info, Node: Using Prefix Scope, Next: Current Suffix Command, Prev: Using Infix Arguments, Up: Defining New Commands + +4.6 Using Prefix Scope +====================== + +Some transients have a sort of secondary value, called a scope. A +prefix’s scope can be accessed using ‘transient-scope’; similar to how +its value can be accessed using ‘transient-args’. + + -- Function: transient-scope prefixes classes + This function returns the scope of the active or current transient + prefix command. + + If optional PREFIXES and CLASSES are both nil, return the scope of + the prefix currently being setup, making this variation useful, + e.g., in ‘:if*’ predicates. If no prefix is being setup, but the + current 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 commands. If CLASSES is non-nil, it must be a prefix class or + a list of such classes. When this function is called from the body + or the ‘interactive’ form of a suffix command, PREFIXES and/or + CLASSES should be non-nil. If either is non-nil, try the following + in order: + + • If the current suffix command was invoked from a prefix, which + appears in PREFIXES, return the scope of that prefix. + + • If the current suffix command was invoked from a prefix, and + its class derives from one of the CLASSES, return the scope of + that prefix. + + • If a prefix is being setup and it appears in PREFIXES, return + its scope. + + • If a prefix is being setup and its class derives from one of + the CLASSES, return its scope. + + • Finally try to return the default scope of the first command + in PREFIXES. This only works if that slot is set in the + respective class definition or using its + ‘transient-init-scope’ method. + + If no prefix matches, return nil. + + +File: transient.info, Node: Current Suffix Command, Next: Current Prefix Command, Prev: Using Prefix Scope, Up: Defining New Commands -4.6 Current Suffix Command +4.7 Current Suffix Command ========================== -- Function: transient-suffix-object command @@ -1529,7 +1701,7 @@ File: transient.info, Node: Current Suffix Command, Next: Current Prefix Comma  File: transient.info, Node: Current Prefix Command, Next: Transient State, Prev: Current Suffix Command, Up: Defining New Commands -4.7 Current Prefix Command +4.8 Current Prefix Command ========================== -- Function: transient-prefix-object @@ -1584,7 +1756,7 @@ File: transient.info, Node: Current Prefix Command, Next: Transient State, Pr  File: transient.info, Node: Transient State, Prev: Current Prefix Command, Up: Defining New Commands -4.8 Transient State +4.9 Transient State =================== Invoking a transient prefix command “activates” the respective @@ -1667,15 +1839,8 @@ call ‘transient-export’, ‘transient--stack-zap’ or • While a sub-prefix is active we nearly always want ‘C-g’ to take the user back to the “super-prefix”, even when the other suffixes don’t do that. However, in rare cases this may not be desirable, - and that makes the following complication necessary: - - For ‘transient-suffix’ objects the ‘transient’ slot is unbound. We - can ignore that for the most part because ‘nil’ and the slot being - unbound are treated as equivalent, and mean “do exit”. That isn’t - actually true for suffixes that are sub-prefixes though. For such - suffixes unbound means “do exit but allow going back”, which is the - default, while ‘nil’ means “do exit permanently”, which requires - that slot to be explicitly set to that value. + in which case ‘replace’ can be used as the value of the + sub-prefix’s ‘transient’ slot. Pre-commands for Infixes ------------------------ @@ -1715,7 +1880,7 @@ predicate is automatically picked based on the value of the ‘transient’ slot for the sub-prefix itself. -- Function: transient--do-recurse - Call the transient prefix command, preparing for return to active + Call the transient prefix command, preparing for return to outer transient. Whether we actually return to the parent transient is ultimately @@ -1920,7 +2085,7 @@ File: transient.info, Node: Group Methods, Next: Prefix Classes, Prev: Group This generic function formats the group and its elements and inserts the result into the current buffer, which is a temporary buffer. The contents of that buffer are later inserted into the - popup buffer. + menu buffer. Functions that are called by this function may need to operate in the buffer from which the transient was called. To do so they can @@ -2092,14 +2257,6 @@ File: transient.info, Node: Suffix Methods, Next: Prefix Slots, Prev: Prefix To get information about the methods implementing these generic functions use ‘describe-function’. -* Menu: - -* Suffix Value Methods:: -* Suffix Format Methods:: - - -File: transient.info, Node: Suffix Value Methods, Next: Suffix Format Methods, Up: Suffix Methods - 5.6.1 Suffix Value Methods -------------------------- @@ -2175,9 +2332,6 @@ File: transient.info, Node: Suffix Value Methods, Next: Suffix Format Methods, unless a concrete method is implemented, this falls through to the default implementation, which is a noop. - -File: transient.info, Node: Suffix Format Methods, Prev: Suffix Value Methods, Up: Suffix Methods - 5.6.2 Suffix Format Methods --------------------------- @@ -2316,8 +2470,9 @@ Appearance • ‘mode-line-format’ is this prefix’s mode line format, overriding ‘transient-mode-line-format’. It should have the same type. - • ‘column-width’ is only respected inside ‘transient-columns’ groups - and allows aligning columns across separate instances of that. + • ‘column-widths’ is only respected inside ‘transient-columns’ groups + and allows aligning columns across separate instances of that. A + list of integers. • ‘variable-pitch’ controls whether alignment is done pixel-wise to account for use of variable-pitch characters, which is useful, @@ -2386,22 +2541,32 @@ Slots of ‘transient-child’ This is the abstract superclass of ‘transient-suffix’ and ‘transient-group’. This is where the shared ‘if*’ and ‘inapt-if*’ slots -(see *note Predicate Slots::) and the ‘level’ slot (see *note Enabling -and Disabling Suffixes::) are defined. +(see *note Predicate Slots::), the ‘level’ slot (see *note Enabling and +Disabling Suffixes::), and the ‘advice’ and ‘advice*’ slots (see *note +Slots of transient-suffix::) are defined. • ‘parent’ The object for the parent group. Slots of ‘transient-suffix’ --------------------------- - • ‘key’ The key, a key vector or a key description string. + • ‘key’ is the key binding, a string in the format returned by + ‘describe-key’ and understood by ‘kbd’. + + That format is more permissive than the one accepted by + ‘key-valid-p’. Being more permissive makes it possible, for + example, to write the key binding, which toggles the ‘-a’ command + line argument, as "-a", instead of having to write "- a". Likewise + additional spaces can be added, which is not removed when + displaying the binding in the menu, which is useful for alignment + purposes. • ‘command’ The command, a symbol. • ‘transient’ Whether to stay transient. See *note Transient State::. - • ‘format’ The format used to display the suffix in the popup buffer. + • ‘format’ The format used to display the suffix in the menu buffer. It must contain the following %-placeholders: • ‘%k’ For the key. @@ -2430,6 +2595,21 @@ Slots of ‘transient-suffix’ • ‘definition’ A command, which is used if the body is omitted when defining a command using ‘transient-define-suffix’. + 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 +for suffixes that set the same slot to a non-nil value. + + • ‘advice’ A function used to advise the command. The advise is + called using ‘(apply advice command args)’, i.e., it behaves like + an "around" advice. + + • ‘advice*’ A function used to advise the command. Unlike ‘advice’, + this advises not only the command body but also its ‘interactive’ + spec. If both slots are non-nil, ‘advice’ is used for the body and + ‘advice*’ is used for the ‘interactive’ form. When advising the + ‘interactive’ spec, called using ‘(funcall advice + #'advice-eval-interactive-spec spec)’. + Slots of ‘transient-infix’ -------------------------- @@ -2574,20 +2754,20 @@ File: transient.info, Node: FAQ, Next: Keystroke Index, Prev: Classes and Met Appendix A FAQ ************** -A.1 Can I control how the popup buffer is displayed? -==================================================== +A.1 Can I control how the menu buffer is displayed? +=================================================== Yes, see ‘transient-display-buffer-action’ in *note Configuration::. -You can also control how the popup buffer is displayed on a case-by-case +You can also control how the menu buffer is displayed on a case-by-case basis by passing ‘:display-action’ to ‘transient-define-prefix’. -A.2 How can I copy text from the popup buffer? -============================================== +A.2 How can I copy text from the menu buffer? +============================================= -To be able to mark text in Transient’s popup buffer using the mouse, you +To be able to mark text in Transient’s menu buffer using the mouse, you have to add the below binding. Note that for technical reasons, the region won’t be visualized, while doing so. After you have quit the -transient popup, you will be able to yank it in another buffer. +transient menu, you will be able to yank it in another buffer. (keymap-set transient-predicate-map "" @@ -2617,50 +2797,7 @@ A.5 How does Transient compare to Magit-Popup and Hydra? See . -A.6 Why did some of the key bindings change? -============================================ - -You may have noticed that the bindings for some of the common commands -do *not* have the prefix ‘C-x’ and that furthermore some of these -commands are grayed out while others are not. That unfortunately is a -bit confusing if the section of common commands is not shown -permanently, making the following explanation necessary. - - The purpose of usually hiding that section but showing it after the -user pressed the respective prefix key is to conserve space and not -overwhelm users with too much noise, while allowing the user to quickly -list common bindings on demand. - - That however should not keep us from using the best possible key -bindings. The bindings that do use a prefix do so to avoid wasting too -many non-prefix bindings, keeping them available for use in individual -transients. The bindings that do not use a prefix and that are *not* -grayed out are very important bindings that are *always* available, even -when invoking the “common command key prefix” or *any other* -transient-specific prefix. The non-prefix keys that *are* grayed out -however, are not available when any incomplete prefix key sequence is -active. They do not use the “common command key prefix” because it is -likely that users want to invoke them several times in a row and e.g., -‘M-p M-p M-p’ is much more convenient than ‘C-x M-p C-x M-p C-x M-p’. - - You may also have noticed that the “Set” command is bound to ‘C-x s’, -while Magit-Popup used to bind ‘C-c C-c’ instead. I have seen several -users praise the latter binding (sic), so I did not change it -willy-nilly. The reason that I changed it is that using different -prefix keys for different common commands, would have made the temporary -display of the common commands even more confusing, i.e., after pressing -‘C-c’ all the bindings that begin with the ‘C-x’ prefix would be grayed -out. - - Using a single prefix for common commands key means that all other -potential prefix keys can be used for transient-specific commands -*without* the section of common commands also popping up. ‘C-c’ in -particular is a prefix that I want to (and already do) use for Magit, -and also using that for a common command would prevent me from doing so. - - (See also the next question.) - -A.7 Why does ‘q’ not quit popups anymore? +A.6 Why does ‘q’ not quit popups anymore? ========================================= I agree that ‘q’ is a good binding for commands that quit something. @@ -2696,21 +2833,21 @@ Appendix B Keystroke Index (line 27) * C-h: Getting Help for Suffix Commands. (line 11) -* C-M-n: Using History. (line 18) -* C-M-p: Using History. (line 13) +* C-M-n: Using History. (line 22) +* C-M-p: Using History. (line 17) * C-q: Aborting and Resuming Transients. (line 36) * C-x a: Enabling and Disabling Suffixes. - (line 68) -* C-x C-k: Saving Values. (line 29) -* C-x C-s: Saving Values. (line 25) + (line 72) +* C-x C-k: Saving Values. (line 33) +* C-x C-s: Saving Values. (line 29) * C-x l: Enabling and Disabling Suffixes. - (line 43) -* C-x n: Using History. (line 18) -* C-x p: Using History. (line 13) -* C-x s: Saving Values. (line 21) + (line 47) +* C-x n: Using History. (line 22) +* C-x p: Using History. (line 17) +* C-x s: Saving Values. (line 25) * C-x t: Common Suffix Commands. - (line 18) + (line 50) * C-z: Aborting and Resuming Transients. (line 41) @@ -2723,75 +2860,67 @@ Appendix C Command and Function Index [index] * Menu: -* transient--do-call: Transient State. (line 125) -* transient--do-exit: Transient State. (line 117) -* transient--do-leave: Transient State. (line 193) -* transient--do-quit-all: Transient State. (line 205) -* transient--do-quit-one: Transient State. (line 200) -* transient--do-recurse: Transient State. (line 133) -* transient--do-replace: Transient State. (line 153) -* transient--do-return: Transient State. (line 120) -* transient--do-stack: Transient State. (line 145) -* transient--do-stay: Transient State. (line 105) -* transient--do-stay <1>: Transient State. (line 190) -* transient--do-suspend: Transient State. (line 161) -* transient--do-suspend <1>: Transient State. (line 210) -* transient--do-warn: Transient State. (line 187) +* transient--do-call: Transient State. (line 118) +* transient--do-exit: Transient State. (line 110) +* transient--do-leave: Transient State. (line 186) +* transient--do-quit-all: Transient State. (line 198) +* transient--do-quit-one: Transient State. (line 193) +* transient--do-recurse: Transient State. (line 126) +* transient--do-replace: Transient State. (line 146) +* transient--do-return: Transient State. (line 113) +* transient--do-stack: Transient State. (line 138) +* transient--do-stay: Transient State. (line 98) +* transient--do-stay <1>: Transient State. (line 183) +* transient--do-suspend: Transient State. (line 154) +* transient--do-suspend <1>: Transient State. (line 203) +* transient--do-warn: Transient State. (line 180) * transient--insert-group: Group Methods. (line 19) * transient-active-prefix: Current Prefix Command. (line 39) * transient-append-suffix: Modifying Existing Transients. - (line 51) + (line 63) * transient-arg-value: Using Infix Arguments. (line 39) * transient-args: Using Infix Arguments. (line 22) * transient-copy-menu-text: Other Commands. (line 25) * transient-default-value: Prefix Methods. (line 23) -* transient-default-value <1>: Suffix Value Methods. - (line 24) +* transient-default-value <1>: Suffix Methods. (line 30) * transient-define-argument: Defining Suffix and Infix Commands. (line 57) +* transient-define-group: Defining Transients. (line 66) * transient-define-infix: Defining Suffix and Infix Commands. (line 26) * transient-define-prefix: Defining Transients. (line 13) * transient-define-suffix: Defining Suffix and Infix Commands. (line 9) -* transient-format: Suffix Format Methods. - (line 6) -* transient-format-description: Suffix Format Methods. - (line 18) -* transient-format-key: Suffix Format Methods. - (line 14) -* transient-format-value: Suffix Format Methods. - (line 22) +* transient-format: Suffix Methods. (line 87) +* transient-format-description: Suffix Methods. (line 99) +* transient-format-key: Suffix Methods. (line 95) +* transient-format-value: Suffix Methods. (line 103) * transient-get-suffix: Modifying Existing Transients. - (line 73) + (line 88) * transient-get-value: Using Infix Arguments. (line 31) * transient-help: Getting Help for Suffix Commands. (line 11) -* transient-history-next: Using History. (line 18) -* transient-history-prev: Using History. (line 13) -* transient-infix-read: Suffix Value Methods. - (line 28) -* transient-infix-set: Suffix Value Methods. - (line 48) -* transient-infix-value: Suffix Value Methods. - (line 51) +* transient-history-next: Using History. (line 22) +* transient-history-prev: Using History. (line 17) +* transient-infix-read: Suffix Methods. (line 34) +* transient-infix-set: Suffix Methods. (line 54) +* transient-infix-value: Suffix Methods. (line 57) * transient-init-scope: Prefix Methods. (line 37) -* transient-init-scope <1>: Suffix Value Methods. - (line 64) +* transient-init-scope <1>: Suffix Methods. (line 70) * transient-init-value: Prefix Methods. (line 9) -* transient-init-value <1>: Suffix Value Methods. - (line 6) +* transient-init-value <1>: Suffix Methods. (line 12) +* transient-inline-group: Modifying Existing Transients. + (line 104) * transient-insert-suffix: Modifying Existing Transients. - (line 49) + (line 61) * transient-prefix-object: Current Prefix Command. (line 6) * transient-prefix-value: Prefix Methods. (line 32) -* transient-prompt: Suffix Value Methods. - (line 44) +* transient-prompt: Suffix Methods. (line 50) * transient-quit-all: Aborting and Resuming Transients. (line 36) * transient-quit-one: Aborting and Resuming Transients. @@ -2799,38 +2928,38 @@ Appendix C Command and Function Index * transient-quit-seq: Aborting and Resuming Transients. (line 27) * transient-remove-suffix: Modifying Existing Transients. - (line 70) + (line 85) * transient-replace-suffix: Modifying Existing Transients. - (line 66) -* transient-reset: Saving Values. (line 29) + (line 81) +* transient-reset: Saving Values. (line 33) * transient-resume: Aborting and Resuming Transients. (line 53) -* transient-save: Saving Values. (line 25) +* transient-save: Saving Values. (line 29) +* transient-scope: Using Prefix Scope. (line 10) * transient-scroll-down: Other Commands. (line 17) * transient-scroll-up: Other Commands. (line 12) -* transient-set: Saving Values. (line 21) +* transient-set: Saving Values. (line 25) +* transient-set-default-level: Enabling and Disabling Suffixes. + (line 76) * transient-set-level: Enabling and Disabling Suffixes. - (line 43) + (line 47) * transient-setup-children: Group Methods. (line 6) -* transient-show-help: Suffix Format Methods. - (line 26) -* transient-show-summary: Suffix Format Methods. - (line 51) +* transient-show-help: Suffix Methods. (line 107) +* transient-show-summary: Suffix Methods. (line 132) * transient-suffix-object: Current Suffix Command. (line 6) * transient-suffix-put: Modifying Existing Transients. - (line 77) + (line 92) * transient-suffixes: Using Infix Arguments. (line 46) * transient-suspend: Aborting and Resuming Transients. (line 41) * transient-toggle-common: Common Suffix Commands. - (line 18) + (line 50) * transient-toggle-docstrings: Other Commands. (line 29) * transient-toggle-level-limit: Enabling and Disabling Suffixes. - (line 68) -* transient-with-help-window: Suffix Format Methods. - (line 46) + (line 72) +* transient-with-help-window: Suffix Methods. (line 127)  File: transient.info, Node: Variable Index, Next: Concept Index, Prev: Command and Function Index, Up: Top @@ -2841,7 +2970,9 @@ Appendix D Variable Index [index] * Menu: -* transient-align-variable-pitch: Configuration. (line 239) +* transient-align-variable-pitch: Configuration. (line 235) +* transient-common-command-prefix: Common Suffix Commands. + (line 23) * transient-current-command: Current Prefix Command. (line 35) * transient-current-prefix: Current Prefix Command. @@ -2850,30 +2981,31 @@ Appendix D Variable Index (line 45) * transient-default-level: Enabling and Disabling Suffixes. (line 33) -* transient-detect-key-conflicts: Configuration. (line 264) -* transient-display-buffer-action: Configuration. (line 112) -* transient-enable-popup-navigation: Configuration. (line 90) -* transient-exit-hook: Configuration. (line 290) -* transient-force-fixed-pitch: Configuration. (line 252) -* transient-force-single-column: Configuration. (line 155) -* transient-highlight-higher-levels: Configuration. (line 277) -* transient-highlight-mismatched-keys: Configuration. (line 200) -* transient-history-file: Using History. (line 37) -* transient-history-limit: Using History. (line 41) +* transient-detect-key-conflicts: Configuration. (line 260) +* transient-display-buffer-action: Configuration. (line 103) +* transient-enable-popup-navigation: Configuration. (line 81) +* transient-error-on-insert-failure: Configuration. (line 273) +* transient-exit-hook: Configuration. (line 292) +* transient-force-fixed-pitch: Configuration. (line 248) +* transient-force-single-column: Configuration. (line 151) +* transient-highlight-higher-levels: Configuration. (line 279) +* transient-highlight-mismatched-keys: Configuration. (line 196) +* transient-history-file: Using History. (line 41) +* transient-history-limit: Using History. (line 45) * transient-levels-file: Enabling and Disabling Suffixes. (line 38) -* transient-mode-line-format: Configuration. (line 164) -* transient-read-with-initial-input: Configuration. (line 83) -* transient-save-history: Using History. (line 33) -* transient-semantic-coloring: Configuration. (line 191) -* transient-setup-buffer-hook: Configuration. (line 293) +* transient-mode-line-format: Configuration. (line 160) +* transient-post-exit-hook: Configuration. (line 296) +* transient-read-with-initial-input: Configuration. (line 74) +* transient-save-history: Using History. (line 37) +* transient-semantic-coloring: Configuration. (line 187) +* transient-setup-buffer-hook: Configuration. (line 300) * transient-show-common-commands: Common Suffix Commands. - (line 23) -* transient-show-common-commands <1>: Configuration. (line 36) -* transient-show-during-minibuffer-read: Configuration. (line 46) -* transient-show-popup: Configuration. (line 15) -* transient-substitute-key-function: Configuration. (line 218) -* transient-values-file: Saving Values. (line 32) + (line 11) +* transient-show-during-minibuffer-read: Configuration. (line 37) +* transient-show-popup: Configuration. (line 16) +* transient-substitute-key-function: Configuration. (line 214) +* transient-values-file: Saving Values. (line 36)  File: transient.info, Node: Concept Index, Next: GNU General Public License, Prev: Variable Index, Up: Top @@ -2885,40 +3017,41 @@ Appendix E Concept Index * Menu: * aborting transients: Aborting and Resuming Transients. - (line 6) -* classes and methods: Classes and Methods. (line 6) + (line 6) +* classes and methods: Classes and Methods. (line 6) * command dispatchers: Technical Introduction. - (line 39) + (line 39) * common suffix commands: Common Suffix Commands. - (line 6) + (line 6) * defining infix commands: Defining Suffix and Infix Commands. - (line 6) + (line 6) * defining suffix commands: Defining Suffix and Infix Commands. - (line 6) + (line 6) * disabling suffixes: Enabling and Disabling Suffixes. - (line 6) + (line 6) * enabling suffixes: Enabling and Disabling Suffixes. - (line 6) + (line 6) * getting help: Getting Help for Suffix Commands. - (line 6) -* group specifications: Group Specifications. (line 6) -* invoking transients: Invoking Transients. (line 6) + (line 6) +* group specifications: Binding Suffix and Infix Commands. + (line 20) +* invoking transients: Invoking Transients. (line 6) * levels: Enabling and Disabling Suffixes. - (line 10) + (line 10) * modifying existing transients: Modifying Existing Transients. - (line 6) + (line 6) * quit transient: Aborting and Resuming Transients. - (line 6) + (line 6) * resuming transients: Aborting and Resuming Transients. - (line 6) -* saving values of arguments: Saving Values. (line 6) -* scope of a transient: Defining Transients. (line 43) -* suffix specifications: Suffix Specifications. - (line 6) -* transient state: Transient State. (line 6) + (line 6) +* saving values of arguments: Saving Values. (line 6) +* scope of a transient: Defining Transients. (line 43) +* suffix specifications: Binding Suffix and Infix Commands. + (line 162) +* transient state: Transient State. (line 6) * transient-level: Enabling and Disabling Suffixes. - (line 15) -* value history: Using History. (line 6) + (line 15) +* value history: Using History. (line 6)  File: transient.info, Node: GNU General Public License, Prev: Concept Index, Up: Top @@ -3640,77 +3773,77 @@ please read .  Tag Table: Node: Top763 -Node: Introduction3049 -Ref: Some things that Transient can do3577 -Ref: Complexity in CLI programs3930 -Ref: Using Transient for composing interactive commands4531 -Node: Usage6773 -Node: Invoking Transients7141 -Node: Aborting and Resuming Transients8310 -Node: Common Suffix Commands10931 -Node: Saving Values12638 -Ref: Saving Values-Footnote-114042 -Node: Using History14235 -Node: Getting Help for Suffix Commands15941 -Node: Enabling and Disabling Suffixes17319 -Node: Other Commands20607 -Node: Configuration22284 -Ref: Essential Options22564 -Ref: Accessibility Options29394 -Ref: Auxiliary Options29717 -Ref: Developer Options34295 -Ref: Hook Variables35543 -Node: Modifying Existing Transients35830 -Node: Defining New Commands40022 -Node: Technical Introduction40439 -Node: Defining Transients46139 -Node: Binding Suffix and Infix Commands48606 -Node: Group Specifications49464 -Node: Suffix Specifications56015 -Node: Defining Suffix and Infix Commands60228 -Node: Using Infix Arguments63276 -Node: Current Suffix Command65669 -Node: Current Prefix Command68029 -Node: Transient State70585 -Ref: Pre-commands for Infixes75401 -Ref: Pre-commands for Suffixes75921 -Ref: Pre-commands for Non-Suffixes78375 -Ref: Special Pre-Commands79511 -Node: Classes and Methods80019 -Node: Group Classes82106 -Node: Group Methods84033 -Node: Prefix Classes85293 -Node: Suffix Classes86138 -Node: Prefix Methods90118 -Node: Suffix Methods92511 -Node: Suffix Value Methods92832 -Node: Suffix Format Methods96181 -Node: Prefix Slots99183 -Ref: Value and Scope99333 -Ref: Behavior100812 -Ref: Appearance102153 -Ref: Documentation102812 -Ref: Internal103432 -Node: Suffix Slots104787 -Ref: Slots of transient-child105155 -Ref: Slots of transient-suffix105530 -Ref: Slots of transient-infix107103 -Ref: Slots of transient-variable110399 -Ref: Slots of transient-switches110501 -Node: Predicate Slots110864 -Node: FAQ113209 -Ref: Can I control how the popup buffer is displayed?113338 -Ref: How can I copy text from the popup buffer?113665 -Ref: How can I autoload prefix and suffix commands?114159 -Ref: How does Transient compare to prefix keys and universal arguments?114633 -Ref: How does Transient compare to Magit-Popup and Hydra?114876 -Ref: Why did some of the key bindings change?115070 -Ref: Why does q not quit popups anymore?117423 -Node: Keystroke Index118526 -Node: Command and Function Index120391 -Node: Variable Index128309 -Node: Concept Index130877 -Node: GNU General Public License133613 +Node: Introduction2915 +Ref: Some things that Transient can do3443 +Ref: Complexity in CLI programs3796 +Ref: Using Transient for composing interactive commands4397 +Node: Usage6639 +Node: Invoking Transients7007 +Node: Aborting and Resuming Transients8199 +Node: Common Suffix Commands10819 +Node: Saving Values13762 +Ref: Saving Values-Footnote-115336 +Node: Using History15529 +Node: Getting Help for Suffix Commands17405 +Node: Enabling and Disabling Suffixes18783 +Node: Other Commands24149 +Node: Configuration25833 +Ref: Essential Options26113 +Ref: Accessibility Options32655 +Ref: Auxiliary Options32978 +Ref: Developer Options37542 +Ref: Hook Variables39069 +Node: Modifying Existing Transients39597 +Node: Defining New Commands45454 +Node: Technical Introduction45894 +Node: Defining Transients51603 +Node: Binding Suffix and Infix Commands54956 +Ref: Group Specifications55753 +Ref: Suffix Specifications62566 +Node: Defining Suffix and Infix Commands67480 +Node: Using Infix Arguments70528 +Node: Using Prefix Scope72917 +Node: Current Suffix Command74923 +Node: Current Prefix Command77280 +Node: Transient State79836 +Ref: Pre-commands for Infixes84187 +Ref: Pre-commands for Suffixes84707 +Ref: Pre-commands for Non-Suffixes87160 +Ref: Special Pre-Commands88296 +Node: Classes and Methods88804 +Node: Group Classes90891 +Node: Group Methods92818 +Node: Prefix Classes94077 +Node: Suffix Classes94922 +Node: Prefix Methods98902 +Node: Suffix Methods101295 +Ref: Suffix Value Methods101555 +Ref: Suffix Format Methods104800 +Node: Prefix Slots107698 +Ref: Value and Scope107848 +Ref: Behavior109327 +Ref: Appearance110668 +Ref: Documentation111354 +Ref: Internal111974 +Node: Suffix Slots113329 +Ref: Slots of transient-child113697 +Ref: Slots of transient-suffix114155 +Ref: Slots of transient-infix117008 +Ref: Slots of transient-variable120304 +Ref: Slots of transient-switches120406 +Node: Predicate Slots120769 +Node: FAQ123114 +Ref: Can I control how the menu buffer is displayed?123243 +Ref: How can I copy text from the menu buffer?123567 +Ref: How can I autoload prefix and suffix commands?124057 +Ref: How does Transient compare to prefix keys and universal arguments?124531 +Ref: How does Transient compare to Magit-Popup and Hydra?124774 +Ref: Why does q not quit popups anymore?124968 +Node: Keystroke Index126071 +Node: Command and Function Index127936 +Node: Variable Index135403 +Node: Concept Index138182 +Node: GNU General Public License141006  End Tag Table -- 2.47.3