From e47650852b8aa4da6d0b0cea3b5421955795cc64 Mon Sep 17 00:00:00 2001 From: Blendoit Date: Sat, 1 Aug 2020 15:24:03 -0700 Subject: Definitely /not/ including elpa/, that would be chaos. --- elpa/transient-20200719.955/dir | 18 - elpa/transient-20200719.955/transient-autoloads.el | 80 - elpa/transient-20200719.955/transient-pkg.el | 12 - elpa/transient-20200719.955/transient.el | 3417 -------------------- elpa/transient-20200719.955/transient.info | 2442 -------------- 5 files changed, 5969 deletions(-) delete mode 100644 elpa/transient-20200719.955/dir delete mode 100644 elpa/transient-20200719.955/transient-autoloads.el delete mode 100644 elpa/transient-20200719.955/transient-pkg.el delete mode 100644 elpa/transient-20200719.955/transient.el delete mode 100644 elpa/transient-20200719.955/transient.info (limited to 'elpa/transient-20200719.955') diff --git a/elpa/transient-20200719.955/dir b/elpa/transient-20200719.955/dir deleted file mode 100644 index 4d6ad7f..0000000 --- a/elpa/transient-20200719.955/dir +++ /dev/null @@ -1,18 +0,0 @@ -This is the file .../info/dir, which contains the -topmost node of the Info hierarchy, called (dir)Top. -The first time you invoke Info you start off looking at this node. - -File: dir, Node: Top This is the top of the INFO tree - - This (the Directory node) gives a menu of major topics. - Typing "q" exits, "H" lists all Info commands, "d" returns here, - "h" gives a primer for first-timers, - "mEmacs" visits the Emacs manual, etc. - - In Emacs, you can click mouse button 2 on a menu item or cross reference - to select it. - -* Menu: - -Emacs -* Transient: (transient). Transient Commands. diff --git a/elpa/transient-20200719.955/transient-autoloads.el b/elpa/transient-20200719.955/transient-autoloads.el deleted file mode 100644 index e20a77f..0000000 --- a/elpa/transient-20200719.955/transient-autoloads.el +++ /dev/null @@ -1,80 +0,0 @@ -;;; transient-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - -(add-to-list 'load-path (directory-file-name - (or (file-name-directory #$) (car load-path)))) - - -;;;### (autoloads nil "transient" "transient.el" (0 0 0 0)) -;;; Generated autoloads from transient.el - -(autoload 'transient-insert-suffix "transient" "\ -Insert a SUFFIX into PREFIX before LOC. -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'. - -\(fn PREFIX LOC SUFFIX)" nil nil) - -(function-put 'transient-insert-suffix 'lisp-indent-function 'defun) - -(autoload 'transient-append-suffix "transient" "\ -Insert a SUFFIX into PREFIX after LOC. -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'. - -\(fn PREFIX LOC SUFFIX)" nil nil) - -(function-put 'transient-append-suffix 'lisp-indent-function 'defun) - -(autoload 'transient-replace-suffix "transient" "\ -Replace the suffix at LOC in PREFIX with SUFFIX. -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'. - -\(fn PREFIX LOC SUFFIX)" nil nil) - -(function-put 'transient-replace-suffix '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. -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'. - -\(fn PREFIX LOC)" nil nil) - -(function-put 'transient-remove-suffix 'lisp-indent-function 'defun) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "transient" '("transient-"))) - -;;;*** - -;;;### (autoloads nil nil ("transient-pkg.el") (0 0 0 0)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; transient-autoloads.el ends here diff --git a/elpa/transient-20200719.955/transient-pkg.el b/elpa/transient-20200719.955/transient-pkg.el deleted file mode 100644 index 4f00e2d..0000000 --- a/elpa/transient-20200719.955/transient-pkg.el +++ /dev/null @@ -1,12 +0,0 @@ -(define-package "transient" "20200719.955" "Transient commands" - '((emacs "25.1")) - :commit "4d44d08e90355a8ef36aaad1f9f79c95de1ce0e9" :keywords - '("bindings") - :authors - '(("Jonas Bernoulli" . "jonas@bernoul.li")) - :maintainer - '("Jonas Bernoulli" . "jonas@bernoul.li") - :url "https://github.com/magit/transient") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/transient-20200719.955/transient.el b/elpa/transient-20200719.955/transient.el deleted file mode 100644 index ae11a1d..0000000 --- a/elpa/transient-20200719.955/transient.el +++ /dev/null @@ -1,3417 +0,0 @@ -;;; transient.el --- Transient commands -*- lexical-binding: t; -*- - -;; Copyright (C) 2018-2020 Free Software Foundation, Inc. - -;; Author: Jonas Bernoulli -;; Homepage: https://github.com/magit/transient -;; Package-Requires: ((emacs "25.1")) -;; Keywords: bindings - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published -;; by the Free Software Foundation, either version 3 of the License, -;; or (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: - -;; Taking inspiration from prefix keys and prefix arguments, Transient -;; implements a similar abstraction involving a prefix command, infix -;; arguments and suffix commands. We could call this abstraction a -;; "transient command", but because it always involves at least two -;; commands (a prefix and a suffix) we prefer to call it just a -;; "transient". - -;; When the user calls a transient prefix command, then a transient -;; (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 -;; the echo area until the transient is exited by invoking a suffix -;; command. - -;; Calling an infix command causes its value to be changed, possibly -;; by reading a new value in the minibuffer. - -;; Calling a suffix command usually causes the transient to be exited -;; but suffix commands can also be configured to not exit the -;; transient state. - -;;; Code: - -(require 'cl-lib) -(require 'eieio) -(require 'format-spec) -(require 'seq) - -(eval-when-compile - (require 'subr-x)) - -(and (require 'async-bytecomp nil t) - (let ((pkgs (bound-and-true-p async-bytecomp-allowed-packages))) - (if (consp pkgs) - (cl-intersection '(all magit transient) pkgs) - (memq pkgs '(all t)))) - (fboundp 'async-bytecomp-package-mode) - (async-bytecomp-package-mode 1)) - -(declare-function info 'info) -(declare-function Man-find-section 'man) -(declare-function Man-next-section 'man) -(declare-function Man-getpage-in-background 'man) - -(defvar Man-notify-method) - -(define-obsolete-function-alias 'define-transient-command - 'transient-define-prefix "Transient 0.3.0") -(define-obsolete-function-alias 'define-suffix-command - 'transient-define-suffix "Transient 0.3.0") -(define-obsolete-function-alias 'define-infix-command - 'transient-define-infix "Transient 0.3.0") -(define-obsolete-function-alias 'define-infix-argument - 'transient-define-argument "Transient 0.3.0") - -(define-obsolete-variable-alias 'current-transient-prefix - 'transient-current-prefix "Transient 0.3.0") -(define-obsolete-variable-alias 'current-transient-command - 'transient-current-command "Transient 0.3.0") -(define-obsolete-variable-alias 'current-transient-suffixes - 'transient-current-suffixes "Transient 0.3.0") -(define-obsolete-variable-alias 'post-transient-hook - 'transient-exit-hook "Transient 0.3.0") - -;;; Options - -(defgroup transient nil - "Transient commands." - :group 'extensions) - -(defcustom transient-show-popup t - "Whether to show the current transient in a popup buffer. - -- If t, then show the popup as soon as a transient prefix command - is invoked. - -- If nil, then do not show the popup unless the user explicitly - requests it, by pressing an incomplete prefix key sequence. - -- If a number, then delay displaying the popup 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 - an incomplete prefix key sequence. Unless zero, then also show - the popup 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))) - -(defcustom transient-enable-popup-navigation nil - "Whether navigation commands are enabled in the transient popup. - -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 non-nil, then the following -features are available: - -- \"\" moves the cursor to the previous suffix. - \"\" moves the cursor to the next suffix. - \"RET\" invokes the suffix the cursor is on. -- \"\" invokes the clicked on suffix. -- \"C-s\" and \"C-r\" start isearch in the popup buffer." - :package-version '(transient . "0.2.0") - :group 'transient - :type 'boolean) - -(defcustom transient-display-buffer-action - '(display-buffer-in-side-window - (side . bottom) - (inhibit-same-window . t)) - "The action used to display the transient popup buffer. - -The transient popup buffer is displayed in a window using - - \(display-buffer buf 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 should accept two arguments: a buffer to display and -an alist of the same form as ALIST. See `display-buffer' for -details. - -The default is (display-buffer-in-side-window (side . bottom)). -This displays the window at the bottom of the selected frame. -Another useful value is (display-buffer-below-selected). This -is what `magit-popup' used by default. For more alternatives -see info node `(elisp)Display Action Functions'. - -It may be possible to display the window in another frame, but -whether that works in practice depends on the window-manager. -If the window manager selects the new window (Emacs frame), -then it doesn't work. - -If you change the value of this option, then you might also -want to change the value of `transient-mode-line-format'." - :package-version '(transient . "0.3.0") - :group 'transient - :type '(cons (choice function (repeat :tag "Functions" function)) - alist)) - -(defcustom transient-mode-line-format 'line - "The mode-line format for the transient popup 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 -a good value. - -If `line' (the default), then the buffer also has no mode-line, -but a thin line is drawn instead, using the background color of -the face `transient-separator'. Termcap frames cannot display -thin lines and therefore fallback to treating `line' like nil. - -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) - (const :tag "name of prefix command" - ("%e" mode-line-front-space - mode-line-buffer-identification)) - (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." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -(defcustom transient-read-with-initial-input nil - "Whether to use the last history element as initial minibuffer input." - :package-version '(transient . "0.2.0") - :group 'transient - :type 'boolean) - -(defcustom transient-highlight-mismatched-keys nil - "Whether to highlight keys that do not match their argument. - -This only affects infix arguments that represent command-line -arguments. When this option is non-nil, then the key binding -for infix argument are highlighted when only a long argument -\(e.g. \"--verbose\") is specified but no shor-thand (e.g \"-v\"). -In the rare case that a short-hand is specified but does not -match the key binding, then it is highlighed differently. - -The highlighting is done using using `transient-mismatched-key' -and `transient-nonstandard-key'." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -(defcustom transient-substitute-key-function nil - "Function used to modify key bindings. - -This function is called with one argument, the prefix object, -and must return a key binding description, either the existing -key description it finds in the `key' slot, or a substitution. - -This is intended to let users replace certain prefix keys. It -could also be used to make other substitutions, but that is -discouraged. - -For example, \"=\" is hard to reach using my custom keyboard -layout, so I substitute \"(\" for that, which is easy to reach -using a layout optimized for lisp. - - (setq transient-substitute-key-function - (lambda (obj) - (let ((key (oref obj key))) - (if (string-match \"\\\\`\\\\(=\\\\)[a-zA-Z]\" key) - (replace-match \"(\" t t key 1) - key)))))" - :package-version '(transient . "0.1.0") - :group 'transient - :type '(choice (const :tag "Transform no keys (nil)" nil) function)) - -(defcustom transient-semantic-coloring nil - "Whether to color prefixes and suffixes in Hydra-like fashion. -This feature is experimental. - -If non-nil, then the key binding of each suffix is colorized to -indicate whether it exits the transient state or not. The color -of the prefix is indicated using the line that is drawn when the -value of `transient-mode-line-format' is `line'. - -For more information about how Hydra uses colors see -https://github.com/abo-abo/hydra#color and -https://oremacs.com/2015/02/19/hydra-colors-reloaded." - :package-version '(transient . "0.3.0") - :group 'transient - :type 'boolean) - -(defcustom transient-detect-key-conflicts nil - "Whether to detect key binding conflicts. - -Conflicts are detected when a transient prefix command is invoked -and results in an error, which prevents the transient from being -used." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -(defcustom transient-force-fixed-pitch nil - "Whether to force used of monospaced font in popup 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." - :package-version '(transient . "0.2.0") - :group 'transient - :type 'boolean) - -(defcustom transient-default-level 4 - "Control what suffix levels are made available by default. - -Each suffix command is placed on a level and each prefix command -has a level, which controls which suffix commands are available. -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\". - -The default level for both transients and their suffixes is 4. -This option only controls the default for transients. The default -suffix level is always 4. The author of a transient should place -certain suffixes on a higher level if they expect that it won't be -of use to most users, and they should place very important suffixes -on a lower level so that they remain available even if the user -lowers the transient level. - -\(Magit currently places nearly all suffixes on level 4 and lower -levels are not used at all yet. So for the time being you should -not set a lower level here and using a higher level might not -give you as many additional suffixes as you hoped.)" - :package-version '(transient . "0.1.0") - :group 'transient - :type '(choice (const :tag "1 - fewest suffixes" 1) - (const 2) - (const 3) - (const :tag "4 - default" 4) - (const 5) - (const 6) - (const :tag "7 - most suffixes" 7))) - -(defcustom transient-levels-file - (locate-user-emacs-file (convert-standard-filename "transient/levels.el")) - "File used to save levels of transients and their suffixes." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'file) - -(defcustom transient-values-file - (locate-user-emacs-file (convert-standard-filename "transient/values.el")) - "File used to save values of transients." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'file) - -(defcustom transient-history-file - (locate-user-emacs-file (convert-standard-filename "transient/history.el")) - "File used to save history of transients and their infixes." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'file) - -(defcustom transient-history-limit 10 - "Number of history elements to keep when saving to file." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'integer) - -(defcustom transient-save-history t - "Whether to save history of transient commands when exiting Emacs." - :package-version '(transient . "0.1.0") - :group 'transient - :type 'boolean) - -;;; Faces - -(defgroup transient-faces nil - "Faces used by Transient." - :group 'transient) - -(defface transient-heading '((t :inherit font-lock-keyword-face)) - "Face used for headings." - :group 'transient-faces) - -(defface transient-key '((t :inherit font-lock-builtin-face)) - "Face used for keys." - :group 'transient-faces) - -(defface transient-argument '((t :inherit font-lock-warning-face)) - "Face used for enabled arguments." - :group 'transient-faces) - -(defface transient-value '((t :inherit font-lock-string-face)) - "Face used for values." - :group 'transient-faces) - -(defface transient-inactive-argument '((t :inherit shadow)) - "Face used for inactive arguments." - :group 'transient-faces) - -(defface transient-inactive-value '((t :inherit shadow)) - "Face used for inactive values." - :group 'transient-faces) - -(defface transient-unreachable '((t :inherit shadow)) - "Face used for suffixes unreachable from the current prefix sequence." - :group 'transient-faces) - -(defface transient-active-infix '((t :inherit secondary-selection)) - "Face used for the infix for which the value is being read." - :group 'transient-faces) - -(defface transient-unreachable-key '((t :inherit shadow)) - "Face used for keys unreachable from the current prefix sequence." - :group 'transient-faces) - -(defface transient-nonstandard-key '((t :underline t)) - "Face optionally used to highlight keys conflicting with short-argument. -Also see option `transient-highlight-mismatched-keys'." - :group 'transient-faces) - -(defface transient-mismatched-key '((t :underline t)) - "Face optionally used to highlight keys without a short-argument. -Also see option `transient-highlight-mismatched-keys'." - :group 'transient-faces) - -(defface transient-inapt-suffix '((t :inherit shadow :italic t)) - "Face used for suffixes that are inapt at this time." - :group 'transient-faces) - -(defface transient-enabled-suffix - '((t :background "green" :foreground "black" :weight bold)) - "Face used for enabled levels while editing suffix levels. -See info node `(transient)Enabling and Disabling Suffixes'." - :group 'transient-faces) - -(defface transient-disabled-suffix - '((t :background "red" :foreground "black" :weight bold)) - "Face used for disabled levels while editing suffix levels. -See info node `(transient)Enabling and Disabling Suffixes'." - :group 'transient-faces) - -(defface transient-separator - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey80") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey30")) - "Face used to draw line below transient popup window. -This is only used if `transient-mode-line-format' is `line'. -Only the background color is significant." - :group 'transient-faces) - -(defgroup transient-color-faces - '((transient-semantic-coloring custom-variable)) - "Faces used by Transient for Hydra-like command coloring. -These faces are only used if `transient-semantic-coloring' -\(which see) is non-nil." - :group 'transient-faces) - -(defface transient-red - '((t :inherit transient-key :foreground "red")) - "Face used for red prefixes and suffixes." - :group 'transient-color-faces) - -(defface transient-blue - '((t :inherit transient-key :foreground "blue")) - "Face used for blue prefixes and suffixes." - :group 'transient-color-faces) - -(defface transient-amaranth - '((t :inherit transient-key :foreground "#E52B50")) - "Face used for amaranth prefixes." - :group 'transient-color-faces) - -(defface transient-pink - '((t :inherit transient-key :foreground "#FF6EB4")) - "Face used for pink prefixes." - :group 'transient-color-faces) - -(defface transient-teal - '((t :inherit transient-key :foreground "#367588")) - "Face used for teal prefixes." - :group 'transient-color-faces) - -;;; Persistence - -(defun transient--read-file-contents (file) - (with-demoted-errors "Transient error: %S" - (and (file-exists-p file) - (with-temp-buffer - (insert-file-contents file) - (read (current-buffer)))))) - -(defun transient--pp-to-file (object file) - (make-directory (file-name-directory file) t) - (setq object (cl-sort object #'string< :key #'car)) - (with-temp-file file - (let ((print-level nil) - (print-length nil)) - (pp object (current-buffer))))) - -(defvar transient-values - (transient--read-file-contents transient-values-file) - "Values of transient commands. -The value of this variable persists between Emacs sessions -and you usually should not change it manually.") - -(defun transient-save-values () - (transient--pp-to-file transient-values transient-values-file)) - -(defvar transient-levels - (transient--read-file-contents transient-levels-file) - "Levels of transient commands. -The value of this variable persists between Emacs sessions -and you usually should not change it manually.") - -(defun transient-save-levels () - (transient--pp-to-file transient-levels transient-levels-file)) - -(defvar transient-history - (transient--read-file-contents transient-history-file) - "History of transient commands and infix arguments. -The value of this variable persists between Emacs sessions -\(unless `transient-save-history' is nil) and you usually -should not change it manually.") - -(defun transient-save-history () - (setq transient-history - (cl-sort (mapcar (pcase-lambda (`(,key . ,val)) - (cons key (seq-take (delete-dups val) - transient-history-limit))) - transient-history) - #'string< :key #'car)) - (transient--pp-to-file transient-history transient-history-file)) - -(defun transient-maybe-save-history () - "Save the value of `transient-history'. -If `transient-save-history' is nil, then do nothing." - (when transient-save-history - (transient-save-history))) - -(unless noninteractive - (add-hook 'kill-emacs-hook 'transient-maybe-save-history)) - -;;; Classes -;;;; Prefix - -(defclass transient-prefix () - ((prototype :initarg :prototype) - (command :initarg :command) - (level :initarg :level) - (variable :initarg :variable :initform nil) - (value) (default-value :initarg :value) - (scope :initarg :scope :initform nil) - (history :initarg :history :initform nil) - (history-pos :initarg :history-pos :initform 0) - (history-key :initarg :history-key :initform nil) - (man-page :initarg :man-page :initform nil) - (info-manual :initarg :info-manual :initform nil) - (transient-suffix :initarg :transient-suffix :initform nil) - (transient-non-suffix :initarg :transient-non-suffix :initform nil) - (incompatible :initarg :incompatible :initform nil)) - "Transient prefix command. - -Each transient prefix command consists of a command, which is -stored in a symbol's function slot and an object, which is -stored in the `transient--prefix' property of the same symbol. - -When a transient prefix command is invoked, then a clone of that -object is stored in the global variable `transient--prefix' and -the prototype is stored in the clone's `prototype' slot.") - -;;;; Suffix - -(defclass transient-child () - ((level - :initarg :level - :initform 1 - :documentation "Enable if level of prefix is equal or greater.") - (if - :initarg :if - :initform nil - :documentation "Enable if predicate returns non-nil.") - (if-not - :initarg :if-not - :initform nil - :documentation "Enable if predicate returns nil.") - (if-non-nil - :initarg :if-non-nil - :initform nil - :documentation "Enable if variable's value is non-nil.") - (if-nil - :initarg :if-nil - :initform nil - :documentation "Enable if variable's value is nil.") - (if-mode - :initarg :if-mode - :initform nil - :documentation "Enable if major-mode matches value.") - (if-not-mode - :initarg :if-not-mode - :initform nil - :documentation "Enable if major-mode does not match value.") - (if-derived - :initarg :if-derived - :initform nil - :documentation "Enable if major-mode derives from value.") - (if-not-derived - :initarg :if-not-derived - :initform nil - :documentation "Enable if major-mode does not derive from value.")) - "Abstract superclass for group and and suffix classes. - -It is undefined what happens if more than one `if*' predicate -slot is non-nil." - :abstract t) - -(defclass transient-suffix (transient-child) - ((key :initarg :key) - (command :initarg :command) - (transient :initarg :transient) - (format :initarg :format :initform " %k %d") - (description :initarg :description :initform nil) - (inapt :initform nil) - (inapt-if - :initarg :inapt-if - :initform nil - :documentation "Inapt if predicate returns non-nil.") - (inapt-if-not - :initarg :inapt-if-not - :initform nil - :documentation "Inapt if predicate returns nil.") - (inapt-if-non-nil - :initarg :inapt-if-non-nil - :initform nil - :documentation "Inapt if variable's value is non-nil.") - (inapt-if-nil - :initarg :inapt-if-nil - :initform nil - :documentation "Inapt if variable's value is nil.") - (inapt-if-mode - :initarg :inapt-if-mode - :initform nil - :documentation "Inapt if major-mode matches value.") - (inapt-if-not-mode - :initarg :inapt-if-not-mode - :initform nil - :documentation "Inapt if major-mode does not match value.") - (inapt-if-derived - :initarg :inapt-if-derived - :initform nil - :documentation "Inapt if major-mode derives from value.") - (inapt-if-not-derived - :initarg :inapt-if-not-derived - :initform nil - :documentation "Inapt if major-mode does not derive from value.")) - "Superclass for suffix command.") - -(defclass transient-infix (transient-suffix) - ((transient :initform t) - (argument :initarg :argument) - (shortarg :initarg :shortarg) - (value :initform nil) - (multi-value :initarg :multi-value :initform nil) - (allow-empty :initarg :allow-empty :initform nil) - (history-key :initarg :history-key :initform nil) - (reader :initarg :reader :initform nil) - (prompt :initarg :prompt :initform nil) - (choices :initarg :choices :initform nil) - (format :initform " %k %d (%v)")) - "Transient infix command." - :abstract t) - -(defclass transient-argument (transient-infix) () - "Abstract superclass for infix arguments." - :abstract t) - -(defclass transient-switch (transient-argument) () - "Class used for command-line argument that can be turned on and off.") - -(defclass transient-option (transient-argument) () - "Class used for command-line argument that can take a value.") - -(defclass transient-variable (transient-infix) - ((variable :initarg :variable) - (format :initform " %k %d %v")) - "Abstract superclass for infix commands that set a variable." - :abstract t) - -(defclass transient-switches (transient-argument) - ((argument-format :initarg :argument-format) - (argument-regexp :initarg :argument-regexp)) - "Class used for sets of mutually exclusive command-line switches.") - -(defclass transient-files (transient-infix) () - "Class used for the \"--\" argument. -All remaining arguments are treated as files. -They become the value of this this argument.") - -;;;; Group - -(defclass transient-group (transient-child) - ((suffixes :initarg :suffixes :initform nil) - (hide :initarg :hide :initform nil) - (description :initarg :description :initform nil)) - "Abstract superclass of all group classes." - :abstract t) - -(defclass transient-column (transient-group) () - "Group class that displays each element on a separate line.") - -(defclass transient-row (transient-group) () - "Group class that displays all elements on a single line.") - -(defclass transient-columns (transient-group) () - "Group class that displays elements organized in columns. -Direct elements have to be groups whose elements have to be -commands or string. Each subgroup represents a column. This -class takes care of inserting the subgroups' elements.") - -(defclass transient-subgroups (transient-group) () - "Group class that wraps other groups. - -Direct elements have to be groups whose elements have to be -commands or strings. This group inserts an empty line between -subgroups. The subgroups are responsible for displaying their -elements themselves.") - -;;; Define - -(defmacro transient-define-prefix (name arglist &rest args) - "Define NAME as a transient prefix command. - -ARGLIST are the arguments that command takes. -DOCSTRING is the documentation string and is optional. - -These arguments can optionally be followed by key-value pairs. -Each key has to be a keyword symbol, either `:class' or a keyword -argument supported by the constructor of that class. The -`transient-prefix' class is used if the class is not specified -explicitly. - -GROUPs add key bindings for infix and suffix commands and specify -how these bindings are presented in the popup buffer. At least -one GROUP has to be specified. See info node `(transient)Binding -Suffix and Infix Commands'. - -The BODY is optional. If it is omitted, then ARGLIST is also -ignored and the function definition becomes: - - (lambda () - (interactive) - (transient-setup \\='NAME)) - -If BODY is specified, then it must begin with an `interactive' -form that matches ARGLIST, and it must call `transient-setup'. -It may however call that function only when some condition is -satisfied; that is one of the reason why you might want to use -an explicit BODY. - -All transients have a (possibly nil) value, which is exported -when suffix commands are called, so that they can consume that -value. For some transients it might be necessary to have a sort -of secondary value, called a scope. Such a scope would usually -be set in the commands `interactive' form and has to be passed -to the setup function: - - (transient-setup \\='NAME nil nil :scope SCOPE) - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... GROUP... [BODY...])" - (declare (debug (&define name lambda-list - [&optional lambda-doc] - [&rest keywordp sexp] - [&rest vectorp] - [&optional ("interactive" interactive) def-body])) - (indent defun) - (doc-string 3)) - (pcase-let ((`(,class ,slots ,suffixes ,docstr ,body) - (transient--expand-define-args args))) - `(progn - (defalias ',name - ,(if body - `(lambda ,arglist ,@body) - `(lambda () - (interactive) - (transient-setup ',name)))) - (put ',name 'interactive-only t) - (put ',name 'function-documentation ,docstr) - (put ',name 'transient--prefix - (,(or class 'transient-prefix) :command ',name ,@slots)) - (put ',name 'transient--layout - ',(cl-mapcan (lambda (s) (transient--parse-child name s)) - suffixes))))) - -(defmacro transient-define-suffix (name arglist &rest args) - "Define NAME as a transient suffix command. - -ARGLIST are the arguments that the command takes. -DOCSTRING is the documentation string and is optional. - -These arguments can optionally be followed by key-value pairs. -Each key has to be a keyword symbol, either `:class' or a -keyword argument supported by the constructor of that class. -The `transient-suffix' class is used if the class is not -specified explicitly. - -The BODY must begin with an `interactive' form that matches -ARGLIST. The infix arguments are usually accessed by using -`transient-args' inside `interactive'. - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]... BODY...)" - (declare (debug (&define name lambda-list - [&optional lambda-doc] - [&rest keywordp sexp] - ("interactive" interactive) - def-body)) - (indent defun) - (doc-string 3)) - (pcase-let ((`(,class ,slots ,_ ,docstr ,body) - (transient--expand-define-args args))) - `(progn - (defalias ',name (lambda ,arglist ,@body)) - (put ',name 'interactive-only t) - (put ',name 'function-documentation ,docstr) - (put ',name 'transient--suffix - (,(or class 'transient-suffix) :command ',name ,@slots))))) - -(defmacro transient-define-infix (name _arglist &rest args) - "Define NAME as a transient infix command. - -ARGLIST is always ignored and reserved for future use. -DOCSTRING is the documentation string and is optional. - -The key-value pairs are mandatory. All transient infix commands -are equal to each other (but not eq), so it is meaningless to -define an infix command without also setting at least `:class' -and one other keyword (which it is depends on the used class, -usually `:argument' or `:variable'). - -Each key has to be a keyword symbol, either `:class' or a keyword -argument supported by the constructor of that class. The -`transient-switch' class is used if the class is not specified -explicitly. - -The function definitions is always: - - (lambda () - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) - -`transient-infix-read' and `transient-infix-set' are generic -functions. Different infix commands behave differently because -the concrete methods are different for different infix command -classes. In rare case the above command function might not be -suitable, even if you define your own infix command class. In -that case you have to use `transient-suffix-command' to define -the infix command and use t as the value of the `:transient' -keyword. - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)" - (declare (debug (&define name lambda-list - [&optional lambda-doc] - [&rest keywordp sexp])) - (indent defun) - (doc-string 3)) - (pcase-let ((`(,class ,slots ,_ ,docstr ,_) - (transient--expand-define-args args))) - `(progn - (defalias ',name ,(transient--default-infix-command)) - (put ',name 'interactive-only t) - (put ',name 'function-documentation ,docstr) - (put ',name 'transient--suffix - (,(or class 'transient-switch) :command ',name ,@slots))))) - -(defalias 'transient-define-argument 'define-infix-command - "Define NAME as a transient infix command. - -Only use this alias to define an infix command that actually -sets an infix argument. To define a infix command that, for -example, sets a variable use `transient-define-infix' instead. - -\(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)") - -(defun transient--expand-define-args (args) - (let (class keys suffixes docstr) - (when (stringp (car args)) - (setq docstr (pop args))) - (while (keywordp (car args)) - (let ((k (pop args)) - (v (pop args))) - (if (eq k :class) - (setq class v) - (push k keys) - (push v keys)))) - (while (vectorp (car args)) - (push (pop args) suffixes)) - (list (if (eq (car-safe class) 'quote) - (cadr class) - class) - (nreverse keys) - (nreverse suffixes) - docstr - args))) - -(defun transient--parse-child (prefix spec) - (cl-etypecase spec - (vector (when-let ((c (transient--parse-group prefix spec))) (list c))) - (list (when-let ((c (transient--parse-suffix prefix spec))) (list c))) - (string (list spec)))) - -(defun transient--parse-group (prefix spec) - (setq spec (append spec nil)) - (cl-symbol-macrolet - ((car (car spec)) - (pop (pop spec))) - (let (level class args) - (when (integerp car) - (setq level pop)) - (when (stringp car) - (setq args (plist-put args :description pop))) - (while (keywordp car) - (let ((k pop)) - (if (eq k :class) - (setq class pop) - (setq args (plist-put args k pop))))) - (vector (or level (oref-default 'transient-child level)) - (or class - (if (vectorp car) - 'transient-columns - 'transient-column)) - args - (cl-mapcan (lambda (s) (transient--parse-child prefix s)) spec))))) - -(defun transient--parse-suffix (prefix spec) - (let (level class args) - (cl-symbol-macrolet - ((car (car spec)) - (pop (pop spec))) - (when (integerp car) - (setq level pop)) - (when (or (stringp car) - (vectorp car)) - (setq args (plist-put args :key pop))) - (when (or (stringp car) - (eq (car-safe car) 'lambda) - (and (symbolp car) - (not (commandp car)) - (commandp (cadr spec)))) - (setq args (plist-put args :description pop))) - (cond - ((keywordp car) - (error "Need command, got %S" car)) - ((symbolp car) - (setq args (plist-put args :command pop))) - ((or (stringp car) - (and car (listp car))) - (let ((arg pop)) - (cl-typecase arg - (list - (setq args (plist-put args :shortarg (car arg))) - (setq args (plist-put args :argument (cadr arg))) - (setq arg (cadr arg))) - (string - (when-let ((shortarg (transient--derive-shortarg arg))) - (setq args (plist-put args :shortarg shortarg))) - (setq args (plist-put args :argument arg)))) - (setq args (plist-put args :command - (intern (format "transient:%s:%s" - prefix arg)))) - (cond ((and car (not (keywordp car))) - (setq class 'transient-option) - (setq args (plist-put args :reader pop))) - ((not (string-suffix-p "=" arg)) - (setq class 'transient-switch)) - (t - (setq class 'transient-option) - (setq args (plist-put args :reader 'read-string)))))) - (t - (error "Needed command or argument, got %S" car))) - (while (keywordp car) - (let ((k pop)) - (cl-case k - (:class (setq class pop)) - (:level (setq level pop)) - (t (setq args (plist-put args k pop))))))) - (unless (plist-get args :key) - (when-let ((shortarg (plist-get args :shortarg))) - (setq args (plist-put args :key shortarg)))) - (list (or level (oref-default 'transient-child level)) - (or class 'transient-suffix) - args))) - -(defun transient--default-infix-command () - (cons 'lambda - '(() - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)))) - -(defun transient--ensure-infix-command (obj) - (let ((cmd (oref obj command))) - (unless (or (commandp cmd) - (get cmd 'transient--infix-command)) - (if (or (cl-typep obj 'transient-switch) - (cl-typep obj 'transient-option)) - (put cmd 'transient--infix-command - (transient--default-infix-command)) - ;; This is not an anonymous infix argument. - (error "Suffix %s is not defined or autoloaded as a command" cmd))))) - -(defun transient--derive-shortarg (arg) - (save-match-data - (and (string-match "\\`\\(-[a-zA-Z]\\)\\(\\'\\|=\\)" arg) - (match-string 1 arg)))) - -;;; Edit - -(defun transient--insert-suffix (prefix loc suffix action) - (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))) - (cond - ((not mem) - (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" - suffix prefix loc - "suffixes and groups cannot be siblings")) - (t - (when (and (listp suffix) - (listp elt)) - (let ((key (transient--spec-key suf))) - (if (equal (transient--kbd key) - (transient--kbd (transient--spec-key elt))) - (setq action 'replace) - (transient-remove-suffix prefix key)))) - (cl-ecase 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) - "Insert a SUFFIX into PREFIX before LOC. -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'." - (declare (indent defun)) - (transient--insert-suffix prefix loc suffix 'insert)) - -;;;###autoload -(defun transient-append-suffix (prefix loc suffix) - "Insert a SUFFIX into PREFIX after LOC. -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'." - (declare (indent defun)) - (transient--insert-suffix prefix loc suffix 'append)) - -;;;###autoload -(defun transient-replace-suffix (prefix loc suffix) - "Replace the suffix at LOC in PREFIX with SUFFIX. -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'." - (declare (indent defun)) - (transient--insert-suffix prefix loc suffix 'replace)) - -;;;###autoload -(defun transient-remove-suffix (prefix loc) - "Remove the suffix or group at LOC in PREFIX. -PREFIX is a prefix command, a symbol. -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'." - (declare (indent defun)) - (transient--layout-member loc prefix 'remove)) - -(defun transient-get-suffix (prefix loc) - "Return the suffix or group at LOC in PREFIX. -PREFIX is a prefix command, a symbol. -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))) - -(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'." - (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) - (t (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) - -(defun transient--spec-key (spec) - (let ((plist (nth 2 spec))) - (or (plist-get plist :key) - (transient--command-key - (plist-get plist :command))))) - -(defun transient--command-key (cmd) - (when-let ((obj (get cmd 'transient--suffix))) - (cond ((slot-boundp obj 'key) - (oref obj key)) - ((slot-exists-p obj 'shortarg) - (if (slot-boundp obj 'shortarg) - (oref obj shortarg) - (transient--derive-shortarg (oref obj argument))))))) - -(defun transient--nthcdr (n list) - (nthcdr (if (< n 0) (- (length list) (abs n)) n) list)) - -;;; Variables - -(defvar transient-current-prefix nil - "The transient from which this suffix command was invoked. -This is an object representing that transient, use -`transient-current-command' to get the respective command.") - -(defvar transient-current-command nil - "The transient from which this suffix command was invoked. -This is a symbol representing that transient, use -`current-transient-object' to get the respective object.") - -(defvar transient-current-suffixes nil - "The suffixes of the transient from which this suffix command was invoked. -This is a list of objects. Usually it is sufficient to instead -use the function `transient-args', which returns a list of -values. In complex cases it might be necessary to use this -variable instead.") - -(defvar transient-exit-hook nil - "Hook run after exiting a transient.") - -(defvar transient--prefix nil) -(defvar transient--layout nil) -(defvar transient--suffixes nil) - -(defconst transient--stay t "Do not exit the transient.") -(defconst transient--exit nil "Do exit the transient.") - -(defvar transient--exitp nil "Whether to exit the transient.") -(defvar transient--showp nil "Whether the transient is show in a popup buffer.") -(defvar transient--helpp nil "Whether help-mode is active.") -(defvar transient--editp nil "Whether edit-mode is active.") - -(defvar transient--active-infix nil "The active infix awaiting user input.") - -(defvar transient--timer nil) - -(defvar transient--stack nil) - -(defvar transient--buffer-name " *transient*" - "Name of the transient buffer.") - -(defvar transient--window nil - "The window used to display the transient popup.") - -(defvar transient--original-window nil - "The window that was selected before the transient was invoked. -Usually it remains selected while the transient is active.") - -(define-obsolete-variable-alias 'transient--source-buffer - 'transient--original-buffer "Transient 0.2.0") - -(defvar transient--original-buffer nil - "The buffer that was current before the transient was invoked. -Usually it remains current while the transient is active.") - -(defvar transient--debug nil "Whether put debug information into *Messages*.") - -(defvar transient--history nil) - -(defvar transient--scroll-commands - '(transient-scroll-up - transient-scroll-down - mwheel-scroll - scroll-bar-toolkit-scroll)) - -;;; Identities - -(defun transient-suffix-object (&optional command) - "Return the object associated with the current suffix command. - -Each suffix commands is associated with an object, which holds -additional information about the suffix, such as its value (in -the case of an infix command, which is a kind of suffix command). - -This function is intended to be called by infix commands, whose -command definition usually (at least when defined using -`transient-define-infix') is this: - - (lambda () - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) - -\(User input is read outside of `interactive' to prevent the -command from being added to `command-history'. See #23.) - -Such commands need to be able to access their associated object -to guide how `transient-infix-read' reads the new value and to -store the read value. Other suffix commands (including non-infix -commands) may also need the object to guide their behavior. - -This function attempts to return the object associated with the -current suffix command even if the suffix command was not invoked -from a transient. (For some suffix command that is a valid thing -to do, for others it is not.) In that case nil may be returned -if the command was not defined using one of the macros intended -to define such commands. - -The optional argument COMMAND is intended for internal use. If -you are contemplating using it in your own code, then you should -probably use this instead: - - (get COMMAND 'transient--suffix)" - (when command - (cl-check-type command command)) - (if transient--prefix - (cl-find-if (lambda (obj) - (eq (transient--suffix-command obj) - (or command this-original-command))) - transient--suffixes) - (when-let ((obj (get (or command this-command) 'transient--suffix)) - (obj (clone obj))) - (transient-init-scope obj) - (transient-init-value obj) - obj))) - -(defun transient--suffix-command (object) - "Return the command represented by OBJECT. - -If the value of OBJECT's `command' slot is a command, then return -that. Otherwise it is a symbol whose `transient--infix-command' -property holds an anonymous command, which is returned instead." - (cl-check-type object transient-suffix) - (let ((sym (oref object command))) - (if (commandp sym) - sym - (get sym 'transient--infix-command)))) - -(defun transient--suffix-symbol (arg) - "Return a symbol representing ARG. - -ARG must be a command and/or a symbol. If it is a symbol, -then just return it. Otherwise return the symbol whose -`transient--infix-command' property's value is ARG." - (or (cl-typep arg 'command) - (cl-typep arg 'symbol) - (signal 'wrong-type-argument `((command symbol) ,arg))) - (if (symbolp arg) - arg - (let* ((obj (transient-suffix-object)) - (sym (oref obj command))) - (if (eq (get sym 'transient--infix-command) arg) - sym - (catch 'found - (mapatoms (lambda (sym) - (when (eq (get sym 'transient--infix-command) arg) - (throw 'found sym))))))))) - -;;; Keymaps - -(defvar transient-base-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "ESC ESC ESC") 'transient-quit-all) - (define-key map (kbd "C-g") 'transient-quit-one) - (define-key map (kbd "C-q") 'transient-quit-all) - (define-key map (kbd "C-z") 'transient-suspend) - (define-key map (kbd "C-v") 'transient-scroll-up) - (define-key map (kbd "M-v") 'transient-scroll-down) - (define-key map [next] 'transient-scroll-up) - (define-key map [prior] 'transient-scroll-down) - map) - "Parent of other keymaps used by Transient. - -This is the parent keymap of all the keymaps that are used in -all transients: `transient-map' (which in turn is the parent -of the transient-specific keymaps), `transient-edit-map' and -`transient-sticky-map'. - -If you change a binding here, then you might also have to edit -`transient-sticky-map' and `transient-common-commands'. While -the latter isn't a proper transient prefix command, it can be -edited using the same functions as used for transients.") - -(defvar transient-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map transient-base-map) - (define-key map (kbd "C-p") 'universal-argument) - (define-key map (kbd "C--") 'negative-argument) - (define-key map (kbd "C-t") 'transient-show) - (define-key map (kbd "?") 'transient-help) - (define-key map (kbd "C-h") 'transient-help) - (define-key map (kbd "M-p") 'transient-history-prev) - (define-key map (kbd "M-n") 'transient-history-next) - map) - "Top-level keymap used by all transients.") - -(defvar transient-edit-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map transient-base-map) - (define-key map (kbd "?") 'transient-help) - (define-key map (kbd "C-h") 'transient-help) - (define-key map (kbd "C-x l") 'transient-set-level) - map) - "Keymap that is active while a transient in is in \"edit mode\".") - -(defvar transient-sticky-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map transient-base-map) - (define-key map (kbd "C-g") 'transient-quit-seq) - map) - "Keymap that is active while an incomplete key sequence is active.") - -(defvar transient--common-command-prefixes '(?\C-x)) - -(put 'transient-common-commands - 'transient--layout - (cl-mapcan - (lambda (s) (transient--parse-child 'transient-common-commands s)) - '([:hide (lambda () - (and (not (memq (car transient--redisplay-key) - transient--common-command-prefixes)) - (not transient-show-common-commands))) - ["Value commands" - ("C-x s " "Set" transient-set) - ("C-x C-s" "Save" transient-save) - ("M-p " "Previous value" transient-history-prev) - ("M-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" - ("C-x t" transient-toggle-common - :description (lambda () - (if transient-show-common-commands - "Hide common commands" - "Show common permanently"))) - ("C-x l" "Show/hide suffixes" transient-set-level)]]))) - -(defvar transient-predicate-map - (let ((map (make-sparse-keymap))) - (define-key map [handle-switch-frame] 'transient--do-suspend) - (define-key map [transient-suspend] 'transient--do-suspend) - (define-key map [transient-help] 'transient--do-stay) - (define-key map [transient-set-level] 'transient--do-stay) - (define-key map [transient-history-prev] 'transient--do-stay) - (define-key map [transient-history-next] 'transient--do-stay) - (define-key map [universal-argument] 'transient--do-stay) - (define-key map [negative-argument] 'transient--do-stay) - (define-key map [digit-argument] 'transient--do-stay) - (define-key map [transient-quit-all] 'transient--do-quit-all) - (define-key map [transient-quit-one] 'transient--do-quit-one) - (define-key map [transient-quit-seq] 'transient--do-stay) - (define-key map [transient-show] 'transient--do-stay) - (define-key map [transient-update] 'transient--do-stay) - (define-key map [transient-toggle-common] 'transient--do-stay) - (define-key map [transient-set] 'transient--do-call) - (define-key map [transient-save] 'transient--do-call) - (define-key map [describe-key-briefly] 'transient--do-stay) - (define-key map [describe-key] 'transient--do-stay) - (define-key map [transient-scroll-up] 'transient--do-stay) - (define-key map [transient-scroll-down] 'transient--do-stay) - (define-key map [mwheel-scroll] 'transient--do-stay) - (define-key map [scroll-bar-toolkit-scroll] 'transient--do-stay) - (define-key map [transient-noop] 'transient--do-noop) - (define-key map [transient-mouse-push-button] 'transient--do-move) - (define-key map [transient-push-button] 'transient--do-move) - (define-key map [transient-backward-button] 'transient--do-move) - (define-key map [transient-forward-button] 'transient--do-move) - (define-key map [transient-isearch-backward] 'transient--do-move) - (define-key map [transient-isearch-forward] 'transient--do-move) - map) - "Base keymap used to map common commands to their transient behavior. - -The \"transient behavior\" of a command controls, among other -things, whether invoking the command causes the transient to be -exited or not and whether infix arguments are exported before -doing so. - -Each \"key\" is a command that is common to all transients and -that is bound in `transient-map', `transient-edit-map', -`transient-sticky-map' and/or `transient-common-command'. - -Each binding is a \"pre-command\", a function that controls the -transient behavior of the respective command. - -For transient commands that are bound in individual transients, -the transient behavior is specified using the `:transient' slot -of the corresponding object.") - -(defvar transient-popup-navigation-map) - -(defvar transient--transient-map nil) -(defvar transient--predicate-map nil) -(defvar transient--redisplay-map nil) -(defvar transient--redisplay-key nil) - -(defun transient--push-keymap (map) - (transient--debug " push %s%s" map (if (symbol-value map) "" " VOID")) - (with-demoted-errors "transient--push-keymap: %S" - (internal-push-keymap (symbol-value map) 'overriding-terminal-local-map))) - -(defun transient--pop-keymap (map) - (transient--debug " pop %s%s" map (if (symbol-value map) "" " VOID")) - (with-demoted-errors "transient--pop-keymap: %S" - (internal-pop-keymap (symbol-value map) 'overriding-terminal-local-map))) - -(defun transient--make-transient-map () - (let ((map (make-sparse-keymap))) - (set-keymap-parent map (if transient--editp - transient-edit-map - transient-map)) - (dolist (obj transient--suffixes) - (let ((key (oref obj key))) - (when (vectorp key) - (setq key (key-description key)) - (oset obj key key)) - (when transient-substitute-key-function - (setq key (save-match-data - (funcall transient-substitute-key-function obj))) - (oset obj key key)) - (let ((kbd (kbd key)) - (cmd (transient--suffix-command obj))) - (when-let ((conflict (and transient-detect-key-conflicts - (transient--lookup-key map kbd)))) - (unless (eq cmd conflict) - (transient--emergency-exit) - (error "Cannot bind %S to %s and also %s" - (string-trim key) - cmd conflict))) - (define-key map kbd cmd)))) - (when transient-enable-popup-navigation - (setq map - (make-composed-keymap (list map transient-popup-navigation-map)))) - map)) - -(defun transient--make-predicate-map () - (let ((map (make-sparse-keymap))) - (set-keymap-parent map transient-predicate-map) - (dolist (obj transient--suffixes) - (let* ((cmd (oref obj command)) - (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix))) - (sym (transient--suffix-symbol cmd))) - (cond - ((oref obj inapt) - (define-key map (vector sym) 'transient--do-warn-inapt)) - ((slot-boundp obj 'transient) - (define-key map (vector sym) - (let ((do (oref obj transient))) - (pcase do - (`t (if sub-prefix - 'transient--do-replace - 'transient--do-stay)) - (`nil 'transient--do-exit) - (_ do))))) - ((not (lookup-key transient-predicate-map (vector sym))) - (define-key map (vector sym) - (if sub-prefix - 'transient--do-replace - (or (oref transient--prefix transient-suffix) - 'transient--do-exit))))))) - map)) - -(defun transient--make-redisplay-map () - (setq transient--redisplay-key - (cl-case this-command - (transient-update - (setq transient--showp t) - (setq unread-command-events - (listify-key-sequence (this-single-command-raw-keys)))) - (transient-quit-seq - (setq unread-command-events - (butlast (listify-key-sequence - (this-single-command-raw-keys)) - 2)) - (butlast transient--redisplay-key)) - (t nil))) - (let ((topmap (make-sparse-keymap)) - (submap (make-sparse-keymap))) - (when transient--redisplay-key - (define-key topmap (vconcat transient--redisplay-key) submap) - (set-keymap-parent submap transient-sticky-map)) - (map-keymap-internal - (lambda (key def) - (when (and (not (eq key ?\e)) - (listp def) - (keymapp def)) - (define-key topmap (vconcat transient--redisplay-key (list key)) - 'transient-update))) - (if transient--redisplay-key - (lookup-key transient--transient-map (vconcat transient--redisplay-key)) - transient--transient-map)) - topmap)) - -;;; Setup - -(defun transient-setup (&optional name layout edit &rest params) - "Setup the transient specified by NAME. - -This function is called by transient prefix commands to setup the -transient. In that case NAME is mandatory, LAYOUT and EDIT must -be nil and PARAMS may be (but usually is not) used to set e.g. the -\"scope\" of the transient (see `transient-define-prefix'). - -This function is also called internally in which case LAYOUT and -EDIT may be non-nil." - (transient--debug 'setup) - (when (and (>= (minibuffer-depth) 1) transient--prefix) - (error "Cannot invoke %s while minibuffer is active %s" - this-command "on behalf of another prefix command")) - (cond - ((not name) - ;; Switching between regular and edit mode. - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (setq name (oref transient--prefix command)) - (setq params (list :scope (oref transient--prefix scope)))) - ((not (or layout ; resuming parent/suspended prefix - transient-current-command)) ; entering child prefix - (transient--stack-zap)) ; replace suspended prefix, if any - (edit - ;; Returning from help to edit. - (setq transient--editp t))) - (transient--init-objects name layout params) - (transient--history-init transient--prefix) - (setq transient--predicate-map (transient--make-predicate-map)) - (setq transient--transient-map (transient--make-transient-map)) - (setq transient--redisplay-map (transient--make-redisplay-map)) - (setq transient--original-window (selected-window)) - (setq transient--original-buffer (current-buffer)) - (transient--redisplay) - (transient--init-transient) - (transient--suspend-which-key-mode)) - -(defun transient--init-objects (name layout params) - (setq transient--prefix - (let ((proto (get name 'transient--prefix))) - (apply #'clone proto - :prototype proto - :level (or (alist-get - t (alist-get name transient-levels)) - transient-default-level) - params))) - (transient-init-value transient--prefix) - (setq transient--layout - (or layout - (let ((levels (alist-get name transient-levels))) - (cl-mapcan (lambda (c) (transient--init-child levels c)) - (append (get name 'transient--layout) - (and (not transient--editp) - (get 'transient-common-commands - 'transient--layout))))))) - (setq transient--suffixes - (cl-labels ((s (def) - (cond - ((stringp def) nil) - ((listp def) (cl-mapcan #'s def)) - ((transient-group--eieio-childp def) - (cl-mapcan #'s (oref def suffixes))) - ((transient-suffix--eieio-childp def) - (list def))))) - (cl-mapcan #'s transient--layout)))) - -(defun transient--init-child (levels spec) - (cl-etypecase spec - (vector (transient--init-group levels spec)) - (list (transient--init-suffix levels spec)) - (string (list spec)))) - -(defun transient--init-group (levels spec) - (pcase-let ((`(,level ,class ,args ,children) (append spec nil))) - (when (transient--use-level-p level) - (let ((obj (apply class :level level args))) - (when (transient--use-suffix-p obj) - (when-let ((suffixes - (cl-mapcan (lambda (c) (transient--init-child levels c)) - children))) - (oset obj suffixes suffixes) - (list obj))))))) - -(defun transient--init-suffix (levels spec) - (pcase-let* ((`(,level ,class ,args) spec) - (cmd (plist-get args :command)) - (level (or (alist-get (transient--suffix-symbol cmd) levels) - level))) - (let ((fn (and (symbolp cmd) - (symbol-function cmd)))) - (when (autoloadp fn) - (transient--debug " autoload %s" cmd) - (autoload-do-load fn))) - (when (transient--use-level-p level) - (let ((obj (if-let ((proto (and cmd - (symbolp cmd) - (get cmd 'transient--suffix)))) - (apply #'clone proto :level level args) - (apply class :level level args)))) - (transient--init-suffix-key obj) - (transient--ensure-infix-command obj) - (when (transient--use-suffix-p obj) - (if (transient--inapt-suffix-p obj) - (oset obj inapt t) - (transient-init-scope obj) - (transient-init-value obj)) - (list obj)))))) - -(cl-defmethod transient--init-suffix-key ((obj transient-suffix)) - (unless (slot-boundp obj 'key) - (error "No key for %s" (oref obj command)))) - -(cl-defmethod transient--init-suffix-key ((obj transient-argument)) - (if (transient-switches--eieio-childp obj) - (cl-call-next-method obj) - (unless (slot-boundp obj 'shortarg) - (when-let ((shortarg (transient--derive-shortarg (oref obj argument)))) - (oset obj shortarg shortarg))) - (unless (slot-boundp obj 'key) - (if (slot-boundp obj 'shortarg) - (oset obj key (oref obj shortarg)) - (error "No key for %s" (oref obj command)))))) - -(defun transient--use-level-p (level &optional edit) - (or (and transient--editp (not edit)) - (and (>= level 1) - (<= level (oref transient--prefix level))))) - -(defun transient--use-suffix-p (obj) - (transient--do-suffix-p - (oref obj if) - (oref obj if-not) - (oref obj if-nil) - (oref obj if-non-nil) - (oref obj if-mode) - (oref obj if-not-mode) - (oref obj if-derived) - (oref obj if-not-derived) - t)) - -(defun transient--inapt-suffix-p (obj) - (transient--do-suffix-p - (oref obj inapt-if) - (oref obj inapt-if-not) - (oref obj inapt-if-nil) - (oref obj inapt-if-non-nil) - (oref obj inapt-if-mode) - (oref obj inapt-if-not-mode) - (oref obj inapt-if-derived) - (oref obj inapt-if-not-derived) - nil)) - -(defun transient--do-suffix-p - (if if-not if-nil if-non-nil if-mode if-not-mode if-derived if-not-derived - default) - (cond - (if (funcall if)) - (if-not (not (funcall if-not))) - (if-non-nil (symbol-value if-non-nil)) - (if-nil (not (symbol-value if-nil))) - (if-mode (if (atom if-mode) - (eq major-mode if-mode) - (memq major-mode if-mode))) - (if-not-mode (not (if (atom if-not-mode) - (eq major-mode if-not-mode) - (memq major-mode if-not-mode)))) - (if-derived (if (atom if-derived) - (derived-mode-p if-derived) - (apply #'derived-mode-p if-derived))) - (if-not-derived (not (if (atom if-not-derived) - (derived-mode-p if-not-derived) - (apply #'derived-mode-p if-not-derived)))) - (t default))) - -;;; Flow-Control - -(defun transient--init-transient () - (transient--debug 'init-transient) - (transient--push-keymap 'transient--transient-map) - (transient--push-keymap 'transient--redisplay-map) - (add-hook 'pre-command-hook #'transient--pre-command) - (add-hook 'minibuffer-setup-hook #'transient--minibuffer-setup) - (add-hook 'minibuffer-exit-hook #'transient--minibuffer-exit) - (add-hook 'post-command-hook #'transient--post-command) - (advice-add 'abort-recursive-edit :after #'transient--minibuffer-exit) - (when transient--exitp - ;; This prefix command was invoked as the suffix of another. - ;; Prevent `transient--post-command' from removing the hooks - ;; that we just added. - (setq transient--exitp 'replace))) - -(defun transient--pre-command () - (transient--debug 'pre-command) - (cond - ((memq this-command '(transient-update transient-quit-seq)) - (transient--pop-keymap 'transient--redisplay-map)) - ((and transient--helpp - (not (memq this-command '(transient-quit-one - transient-quit-all)))) - (cond - ((transient-help) - (transient--do-suspend) - (setq this-command 'transient-suspend) - (transient--pre-exit)) - ((not (transient--edebug-command-p)) - (setq this-command 'transient-undefined)))) - ((and transient--editp - (transient-suffix-object) - (not (memq this-command '(transient-quit-one - transient-quit-all - transient-help)))) - (setq this-command 'transient-set-level)) - (t - (setq transient--exitp nil) - (when (eq (if-let ((fn (transient--get-predicate-for - this-original-command))) - (let ((action (funcall fn))) - (when (eq action transient--exit) - (setq transient--exitp (or transient--exitp t))) - action) - (if (let ((keys (this-command-keys-vector))) - (eq (aref keys (1- (length keys))) ?\C-g)) - (setq this-command 'transient-noop) - (unless (transient--edebug-command-p) - (setq this-command 'transient-undefined))) - transient--stay) - transient--exit) - (transient--pre-exit))))) - -(defun transient--get-predicate-for (cmd) - (or (lookup-key transient--predicate-map - (vector (transient--suffix-symbol cmd))) - (oref transient--prefix transient-non-suffix))) - -(defun transient--pre-exit () - (transient--debug 'pre-exit) - (transient--delete-window) - (transient--timer-cancel) - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (remove-hook 'pre-command-hook #'transient--pre-command) - (unless transient--showp - (message "")) - (setq transient--transient-map nil) - (setq transient--predicate-map nil) - (setq transient--redisplay-map nil) - (setq transient--redisplay-key nil) - (setq transient--showp nil) - (setq transient--helpp nil) - (setq transient--editp nil) - (setq transient--prefix nil) - (setq transient--layout nil) - (setq transient--suffixes nil) - (setq transient--original-window nil) - (setq transient--original-buffer nil) - (setq transient--window nil)) - -(defun transient--delete-window () - (when (window-live-p transient--window) - (let ((buf (window-buffer transient--window))) - (with-demoted-errors "Error while exiting transient: %S" - (delete-window transient--window)) - (kill-buffer buf)))) - -(defun transient--export () - (setq transient-current-prefix transient--prefix) - (setq transient-current-command (oref transient--prefix command)) - (setq transient-current-suffixes transient--suffixes) - (transient--history-push transient--prefix)) - -(defun transient--minibuffer-setup () - (transient--debug 'minibuffer-setup) - (unless (> (minibuffer-depth) 1) - (unless transient--exitp - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (remove-hook 'pre-command-hook #'transient--pre-command)) - (remove-hook 'post-command-hook #'transient--post-command))) - -(defun transient--minibuffer-exit () - (transient--debug 'minibuffer-exit) - (unless (> (minibuffer-depth) 1) - (unless transient--exitp - (transient--push-keymap 'transient--transient-map) - (transient--push-keymap 'transient--redisplay-map) - (add-hook 'pre-command-hook #'transient--pre-command)) - (add-hook 'post-command-hook #'transient--post-command))) - -(defun transient--suspend-override (&optional minibuffer-hooks) - (transient--debug 'suspend-override) - (transient--pop-keymap 'transient--transient-map) - (transient--pop-keymap 'transient--redisplay-map) - (remove-hook 'pre-command-hook #'transient--pre-command) - (remove-hook 'post-command-hook #'transient--post-command) - (when minibuffer-hooks - (remove-hook 'minibuffer-setup-hook #'transient--minibuffer-setup) - (remove-hook 'minibuffer-exit-hook #'transient--minibuffer-exit) - (advice-remove 'abort-recursive-edit #'transient--minibuffer-exit))) - -(defun transient--resume-override (&optional minibuffer-hooks) - (transient--debug 'resume-override) - (transient--push-keymap 'transient--transient-map) - (transient--push-keymap 'transient--redisplay-map) - (add-hook 'pre-command-hook #'transient--pre-command) - (add-hook 'post-command-hook #'transient--post-command) - (when minibuffer-hooks - (add-hook 'minibuffer-setup-hook #'transient--minibuffer-setup) - (add-hook 'minibuffer-exit-hook #'transient--minibuffer-exit) - (advice-add 'abort-recursive-edit :after #'transient--minibuffer-exit))) - -(defun transient--post-command () - (transient--debug 'post-command) - (if transient--exitp - (progn - (unless (and (eq transient--exitp 'replace) - (or transient--prefix - ;; The current command could act as a prefix, - ;; but decided not to call `transient-setup'. - (prog1 nil (transient--stack-zap)))) - (remove-hook 'minibuffer-setup-hook #'transient--minibuffer-setup) - (remove-hook 'minibuffer-exit-hook #'transient--minibuffer-exit) - (advice-remove 'abort-recursive-edit #'transient--minibuffer-exit) - (remove-hook 'post-command-hook #'transient--post-command)) - (setq transient-current-prefix nil) - (setq transient-current-command nil) - (setq transient-current-suffixes nil) - (let ((resume (and transient--stack - (not (memq transient--exitp '(replace suspend)))))) - (setq transient--exitp nil) - (setq transient--helpp nil) - (setq transient--editp nil) - (run-hooks 'transient-exit-hook) - (when resume - (transient--stack-pop)))) - (transient--pop-keymap 'transient--redisplay-map) - (setq transient--redisplay-map (transient--make-redisplay-map)) - (transient--push-keymap 'transient--redisplay-map) - (unless (eq this-command (oref transient--prefix command)) - (transient--redisplay)))) - -(defun transient--stack-push () - (transient--debug 'stack-push) - (push (list (oref transient--prefix command) - transient--layout - transient--editp - :scope (oref transient--prefix scope)) - transient--stack)) - -(defun transient--stack-pop () - (transient--debug 'stack-pop) - (and transient--stack - (prog1 t (apply #'transient-setup (pop transient--stack))))) - -(defun transient--stack-zap () - (transient--debug 'stack-zap) - (setq transient--stack nil)) - -(defun transient--redisplay () - (if (or (eq transient-show-popup t) - transient--showp) - (unless (memq this-command transient--scroll-commands) - (transient--show)) - (when (and (numberp transient-show-popup) - (not (zerop transient-show-popup)) - (not transient--timer)) - (transient--timer-start)) - (transient--show-brief))) - -(defun transient--timer-start () - (setq transient--timer - (run-at-time (abs transient-show-popup) nil - (lambda () - (transient--timer-cancel) - (transient--show) - (let ((message-log-max nil)) - (message "")))))) - -(defun transient--timer-cancel () - (when transient--timer - (cancel-timer transient--timer) - (setq transient--timer nil))) - -(defun transient--debug (arg &rest args) - (when transient--debug - (if (symbolp arg) - (message "-- %-16s (cmd: %s, exit: %s)" - arg this-command transient--exitp) - (apply #'message arg args)))) - -(defun transient--emergency-exit () - "Exit the current transient command after an error occurred. - -Beside being used with `condition-case', this function also has -to be a member of `debugger-mode-hook', else the debugger would -be unusable and exiting it by pressing \"q\" would fail because -the transient command would still be active and that key would -either be unbound or do something else. - -When no transient is active (i.e. when `transient--prefix') is -nil, then do nothing." - (when transient--prefix - (setq transient--stack nil) - (setq transient--exitp t) - (transient--pre-exit) - (transient--post-command))) - -(add-hook 'debugger-mode-hook 'transient--emergency-exit) - -(defmacro transient--with-emergency-exit (&rest body) - (declare (indent defun)) - `(condition-case nil - ,(macroexp-progn body) - (error (transient--emergency-exit)))) - -;;; Pre-Commands - -(defun transient--do-stay () - "Call the command without exporting variables and stay transient." - transient--stay) - -(defun transient--do-noop () - "Call `transient-noop' and stay transient." - (setq this-command 'transient-noop) - transient--stay) - -(defun transient--do-warn () - "Call `transient-undefined' and stay transient." - (setq this-command 'transient-undefined) - transient--stay) - -(defun transient--do-warn-inapt () - "Call `transient-inapt' and stay transient." - (setq this-command 'transient-inapt) - transient--stay) - -(defun transient--do-call () - "Call the command after exporting variables and stay transient." - (transient--export) - transient--stay) - -(defun transient--do-exit () - "Call the command after exporting variables and exit the transient." - (transient--export) - (transient--stack-zap) - transient--exit) - -(defun transient--do-replace () - "Call the transient prefix command, replacing the active transient." - (transient--export) - (transient--stack-push) - (setq transient--exitp 'replace) - transient--exit) - -(defun transient--do-suspend () - "Suspend the active transient, saving the transient stack." - (transient--stack-push) - (setq transient--exitp 'suspend) - transient--exit) - -(defun transient--do-quit-one () - "If active, quit help or edit mode, else exit the active transient." - (cond (transient--helpp - (setq transient--helpp nil) - transient--stay) - (transient--editp - (setq transient--editp nil) - (transient-setup) - transient--stay) - (t transient--exit))) - -(defun transient--do-quit-all () - "Exit all transients without saving the transient stack." - (transient--stack-zap) - transient--exit) - -(defun transient--do-move () - "Call the command if `transient-enable-popup-navigation' is non-nil. -In that case behave like `transient--do-stay', otherwise similar -to `transient--do-warn'." - (unless transient-enable-popup-navigation - (setq this-command 'transient-popup-navigation-help)) - transient--stay) - -(put 'transient--do-stay 'transient-color 'transient-blue) -(put 'transient--do-noop 'transient-color 'transient-blue) -(put 'transient--do-warn 'transient-color 'transient-blue) -(put 'transient--do-warn-inapt 'transient-color 'transient-blue) -(put 'transient--do-call 'transient-color 'transient-blue) -(put 'transient--do-exit 'transient-color 'transient-red) -(put 'transient--do-replace 'transient-color 'transient-red) -(put 'transient--do-suspend 'transient-color 'transient-red) -(put 'transient--do-quit-one 'transient-color 'transient-red) -(put 'transient--do-quit-all 'transient-color 'transient-red) -(put 'transient--do-move 'transient-color 'transient-blue) - -;;; Commands - -(defun transient-noop () - "Do nothing at all." - (interactive)) - -(defun transient-undefined () - "Warn the user that the pressed key is not bound to any suffix." - (interactive) - (transient--invalid "Unbound suffix")) - -(defun transient-inapt () - "Warn the user that the invoked command is inapt." - (interactive) - (transient--invalid "Inapt command")) - -(defun transient--invalid (msg) - (ding) - (message "%s: `%s' (Use `%s' to abort, `%s' for help) [%s]" - msg - (propertize (key-description (this-single-command-keys)) - 'face 'font-lock-warning-face) - (propertize "C-g" 'face 'transient-key) - (propertize "?" 'face 'transient-key) - (propertize (symbol-name (transient--suffix-symbol - this-original-command)) - 'face 'font-lock-warning-face))) - -(defun transient-toggle-common () - "Toggle whether common commands are always shown." - (interactive) - (setq transient-show-common-commands (not transient-show-common-commands))) - -(defun transient-suspend () - "Suspend the current transient. -It can later be resumed using `transient-resume' while no other -transient is active." - (interactive)) - -(defun transient-quit-all () - "Exit all transients without saving the transient stack." - (interactive)) - -(defun transient-quit-one () - "Exit the current transients, possibly returning to the previous." - (interactive)) - -(defun transient-quit-seq () - "Abort the current incomplete key sequence." - (interactive)) - -(defun transient-update () - "Redraw the transient's state in the popup buffer." - (interactive)) - -(defun transient-show () - "Show the transient's state in the popup buffer." - (interactive) - (setq transient--showp t)) - -(defvar-local transient--restore-winconf nil) - -(defvar transient-resume-mode) - -(defun transient-help () - "Show help for the active transient or one of its suffixes." - (interactive) - (if (called-interactively-p 'any) - (setq transient--helpp t) - (with-demoted-errors "transient-help: %S" - (when (lookup-key transient--transient-map - (this-single-command-raw-keys)) - (setq transient--helpp nil) - (let ((winconf (current-window-configuration))) - (transient-show-help - (if (eq this-original-command 'transient-help) - transient--prefix - (or (transient-suffix-object) - this-original-command))) - (setq transient--restore-winconf winconf)) - (fit-window-to-buffer nil (frame-height) (window-height)) - (transient-resume-mode) - (message "Type \"q\" to resume transient command.") - t)))) - -(defun transient-set-level (&optional command level) - "Set the level of the transient or one of its suffix commands." - (interactive - (let ((command this-original-command) - (prefix (oref transient--prefix command))) - (and (or (not (eq command 'transient-set-level)) - (and transient--editp - (setq command prefix))) - (list command - (let ((keys (this-single-command-raw-keys))) - (and (lookup-key transient--transient-map keys) - (string-to-number - (let ((transient--active-infix - (transient-suffix-object command))) - (transient--show) - (transient--read-number-N - (format "Set level for `%s': " - (transient--suffix-symbol command)) - nil nil (not (eq command prefix))))))))))) - (cond - ((not command) - (setq transient--editp t) - (transient-setup)) - (level - (let* ((prefix (oref transient--prefix command)) - (alist (alist-get prefix transient-levels)) - (sym (transient--suffix-symbol command))) - (if (eq command prefix) - (progn (oset transient--prefix level level) - (setq sym t)) - (oset (transient-suffix-object command) level level)) - (setf (alist-get sym alist) level) - (setf (alist-get prefix transient-levels) alist)) - (transient-save-levels)) - (t - (transient-undefined)))) - -(defun transient-set () - "Save the value of the active transient for this Emacs session." - (interactive) - (transient-set-value (or transient--prefix transient-current-prefix))) - -(defun transient-save () - "Save the value of the active transient persistenly across Emacs sessions." - (interactive) - (transient-save-value (or transient--prefix transient-current-prefix))) - -(defun transient-history-next () - "Switch to the next value used for the active transient." - (interactive) - (let* ((obj transient--prefix) - (pos (1- (oref obj history-pos))) - (hst (oref obj history))) - (if (< pos 0) - (user-error "End of history") - (oset obj history-pos pos) - (oset obj value (nth pos hst)) - (mapc #'transient-init-value transient--suffixes)))) - -(defun transient-history-prev () - "Switch to the previous value used for the active transient." - (interactive) - (let* ((obj transient--prefix) - (pos (1+ (oref obj history-pos))) - (hst (oref obj history)) - (len (length hst))) - (if (> pos (1- len)) - (user-error "End of history") - (oset obj history-pos pos) - (oset obj value (nth pos hst)) - (mapc #'transient-init-value transient--suffixes)))) - -(defun transient-scroll-up (&optional arg) - "Scroll text of transient popup window upward ARG lines. -If ARG is nil scroll near full screen. This is a wrapper -around `scroll-up-command' (which see)." - (interactive "^P") - (with-selected-window transient--window - (scroll-up-command arg))) - -(defun transient-scroll-down (&optional arg) - "Scroll text of transient popup window down ARG lines. -If ARG is nil scroll near full screen. This is a wrapper -around `scroll-down-command' (which see)." - (interactive "^P") - (with-selected-window transient--window - (scroll-down-command arg))) - -(defun transient-resume () - "Resume a previously suspended stack of transients." - (interactive) - (cond (transient--stack - (let ((winconf transient--restore-winconf)) - (kill-local-variable 'transient--restore-winconf) - (when transient-resume-mode - (transient-resume-mode -1) - (quit-window)) - (when winconf - (set-window-configuration winconf))) - (transient--stack-pop)) - (transient-resume-mode - (kill-local-variable 'transient--restore-winconf) - (transient-resume-mode -1) - (quit-window)) - (t - (message "No suspended transient command")))) - -;;; Value -;;;; Init - -(cl-defgeneric transient-init-scope (obj) - "Set the scope of the suffix object OBJ. - -The scope is actually a property of the transient prefix, not of -individual suffixes. However it is possible to invoke a suffix -command directly instead of from a transient. In that case, if -the suffix expects a scope, then it has to determine that itself -and store it in its `scope' slot. - -This function is called for all suffix commands, but unless a -concrete method is implemented this falls through to the default -implementation, which is a noop.") - -(cl-defmethod transient-init-scope ((_ transient-suffix)) - "Noop." nil) - -(cl-defgeneric transient-init-value (_) - "Set the initial value of the object OBJ. - -This function is called for all prefix and suffix commands. - -For suffix commands (including infix argument commands) the -default implementation is a noop. Classes derived from the -abstract `transient-infix' class must implement this function. -Non-infix suffix commands usually don't have a value." - nil) - -(cl-defmethod transient-init-value ((obj transient-prefix)) - (if (slot-boundp obj 'value) - (oref obj value) - (oset obj value - (if-let ((saved (assq (oref obj command) transient-values))) - (cdr saved) - (if-let ((default (and (slot-boundp obj 'default-value) - (oref obj default-value)))) - (if (functionp default) - (funcall default) - default) - nil))))) - -(cl-defmethod transient-init-value ((obj transient-switch)) - (oset obj value - (car (member (oref obj argument) - (oref transient--prefix value))))) - -(cl-defmethod transient-init-value ((obj transient-option)) - (oset obj value - (transient--value-match (format "\\`%s\\(.*\\)" (oref obj argument))))) - -(cl-defmethod transient-init-value ((obj transient-switches)) - (oset obj value - (transient--value-match (oref obj argument-regexp)))) - -(defun transient--value-match (re) - (when-let ((match (cl-find-if (lambda (v) - (and (stringp v) - (string-match re v))) - (oref transient--prefix value)))) - (match-string 1 match))) - -(cl-defmethod transient-init-value ((obj transient-files)) - (oset obj value - (cdr (assoc "--" (oref transient--prefix value))))) - -;;;; Read - -(cl-defgeneric transient-infix-read (obj) - "Determine the new value of the infix object OBJ. - -This function merely determines the value; `transient-infix-set' -is used to actually store the new value in the object. - -For most infix classes this is done by reading a value from the -user using the reader specified by the `reader' slot (using the -`transient-infix' method described below). - -For some infix classes the value is changed without reading -anything in the minibuffer, i.e. the mere act of invoking the -infix command determines what the new value should be, based -on the previous value.") - -(cl-defmethod transient-infix-read :around ((obj transient-infix)) - "Highlight the infix in the popup buffer. - -Also arrange for the transient to be exited in case of an error -because otherwise Emacs would get stuck in an inconsistent state, -which might make it necessary to kill it from the outside." - (let ((transient--active-infix obj)) - (transient--show)) - (transient--with-emergency-exit - (cl-call-next-method obj))) - -(cl-defmethod transient-infix-read ((obj transient-infix)) - "Read a value while taking care of history. - -This method is suitable for a wide variety of infix commands, -including but not limited to inline arguments and variables. - -If you do not use this method for your own infix class, then -you should likely replicate a lot of the behavior of this -method. If you fail to do so, then users might not appreciate -the lack of history, for example. - -Only for very simple classes that toggle or cycle through a very -limited number of possible values should you replace this with a -simple method that does not handle history. (E.g. for a command -line switch the only possible values are \"use it\" and \"don't use -it\", in which case it is pointless to preserve history.)" - (with-slots (value multi-value allow-empty choices) obj - (if (and value - (not multi-value) - transient--prefix) - (oset obj value nil) - (let* ((overriding-terminal-local-map nil) - (reader (oref obj reader)) - (prompt (transient-prompt obj)) - (value (if multi-value (mapconcat #'identity value ",") value)) - (history-key (or (oref obj history-key) - (oref obj command))) - (transient--history (alist-get history-key transient-history)) - (transient--history (if (or (null value) - (eq value (car transient--history))) - transient--history - (cons value transient--history))) - (initial-input (and transient-read-with-initial-input - (car transient--history))) - (history (if initial-input - (cons 'transient--history 1) - 'transient--history)) - (value - (cond - (reader (funcall reader prompt initial-input history)) - (multi-value - (completing-read-multiple prompt choices nil nil - initial-input history)) - (choices - (completing-read prompt choices nil t initial-input history)) - (t (read-string prompt initial-input history))))) - (cond ((and (equal value "") (not allow-empty)) - (setq value nil)) - ((and (equal value "\"\"") allow-empty) - (setq value ""))) - (when value - (when (bound-and-true-p ivy-mode) - (set-text-properties 0 (length (car transient--history)) nil - (car transient--history))) - (setf (alist-get history-key transient-history) - (delete-dups transient--history))) - value)))) - -(cl-defmethod transient-infix-read ((obj transient-switch)) - "Toggle the switch on or off." - (if (oref obj value) nil (oref obj argument))) - -(cl-defmethod transient-infix-read ((obj transient-switches)) - "Cycle through the mutually exclusive switches. -The last value is \"don't use any of these switches\"." - (let ((choices (mapcar (apply-partially #'format (oref obj argument-format)) - (oref obj choices)))) - (if-let ((value (oref obj value))) - (cadr (member value choices)) - (car choices)))) - -(cl-defmethod transient-infix-read ((command symbol)) - "Elsewhere use the reader of the infix command COMMAND. -Use this if you want to share an infix's history with a regular -stand-alone command." - (cl-letf (((symbol-function #'transient--show) #'ignore)) - (transient-infix-read (get command 'transient--suffix)))) - -;;;; Readers - -(defun transient-read-directory (prompt _initial-input _history) - "Read a directory." - (expand-file-name (read-directory-name prompt))) - -(defun transient-read-existing-directory (prompt _initial-input _history) - "Read an existing directory." - (expand-file-name (read-directory-name prompt nil nil t))) - -(defun transient-read-number-N0 (prompt initial-input history) - "Read a natural number (including zero) and return it as a string." - (transient--read-number-N prompt initial-input history t)) - -(defun transient-read-number-N+ (prompt initial-input history) - "Read a natural number (excluding zero) and return it as a string." - (transient--read-number-N prompt initial-input history nil)) - -(defun transient--read-number-N (prompt initial-input history include-zero) - (save-match-data - (cl-block nil - (while t - (let ((str (read-from-minibuffer prompt initial-input nil nil history))) - (cond ((string-equal str "") - (cl-return nil)) - ((string-match-p (if include-zero - "\\`\\(0\\|[1-9][0-9]*\\)\\'" - "\\`[1-9][0-9]*\\'") - str) - (cl-return str)))) - (message "Please enter a natural number (%s zero)." - (if include-zero "including" "excluding")) - (sit-for 1))))) - -(defun transient-read-date (prompt default-time _history) - "Read a date using `org-read-date' (which see)." - (require 'org) - (when (fboundp 'org-read-date) - (org-read-date 'with-time nil nil prompt default-time))) - -;;;; Prompt - -(cl-defgeneric transient-prompt (obj) - "Return the prompt to be used to read infix object OBJ's value.") - -(cl-defmethod transient-prompt ((obj transient-infix)) - "Return the prompt to be used to read infix object OBJ's value. - -This implementation should be suitable for almost all infix -commands. - -If the value of OBJ's `prompt' slot is non-nil, then it must be -a string or a function. If it is a string, then use that. If -it is a function, then call that with OBJ as the only argument. -That function must return a string, which is then used as the -prompt. - -Otherwise, if the value of either the `argument' or `variable' -slot of OBJ is a string, then base the prompt on that (preferring -the former), appending either \"=\" (if it appears to be a -command-line option) or \": \". - -Finally fall through to using \"(BUG: no prompt): \" as the -prompt." - (if-let ((prompt (oref obj prompt))) - (let ((prompt (if (functionp prompt) - (funcall prompt obj) - prompt))) - (if (stringp prompt) - prompt - "(BUG: no prompt): ")) - (or (when-let ((arg (and (slot-boundp obj 'argument) (oref obj argument)))) - (if (and (stringp arg) (string-suffix-p "=" arg)) - arg - (concat arg ": "))) - (when-let ((var (and (slot-boundp obj 'variable) (oref obj variable)))) - (and (stringp var) - (concat var ": "))) - "(BUG: no prompt): "))) - -;;;; Set - -(defvar transient--unset-incompatible t) - -(cl-defgeneric transient-infix-set (obj value) - "Set the value of infix object OBJ to value.") - -(cl-defmethod transient-infix-set ((obj transient-infix) value) - "Set the value of infix object OBJ to value. - -This implementation should be suitable for almost all infix -commands." - (oset obj value value)) - -(cl-defmethod transient-infix-set :around ((obj transient-argument) value) - "Unset incompatible infix arguments." - (let ((arg (if (slot-boundp obj 'argument) - (oref obj argument) - (oref obj argument-regexp)))) - (if-let ((sic (and value arg transient--unset-incompatible)) - (spec (oref transient--prefix incompatible)) - (incomp (remove arg (cl-find-if (lambda (elt) (member arg elt)) spec)))) - (progn - (cl-call-next-method obj value) - (dolist (arg incomp) - (when-let ((obj (cl-find-if (lambda (obj) - (and (slot-boundp obj 'argument) - (equal (oref obj argument) arg))) - transient--suffixes))) - (let ((transient--unset-incompatible nil)) - (transient-infix-set obj nil))))) - (cl-call-next-method obj value)))) - -(cl-defmethod transient-set-value ((obj transient-prefix)) - (oset (oref obj prototype) value (transient-get-value)) - (transient--history-push obj)) - -;;;; Save - -(cl-defmethod transient-save-value ((obj transient-prefix)) - (let ((value (transient-get-value))) - (oset (oref obj prototype) value value) - (setf (alist-get (oref obj command) transient-values) value) - (transient-save-values)) - (transient--history-push obj)) - -;;;; Get - -(defun transient-args (prefix) - "Return the value of the transient prefix command PREFIX. -If the current command was invoked from the transient prefix -command PREFIX, then return the active infix arguments. If -the current command was not invoked from PREFIX, then return -the set, saved or default value for PREFIX." - (if (eq transient-current-command prefix) - (delq nil (mapcar 'transient-infix-value transient-current-suffixes)) - (let ((transient--prefix nil) - (transient--layout nil) - (transient--suffixes nil)) - (transient--init-objects prefix nil nil) - (delq nil (mapcar 'transient-infix-value transient--suffixes))))) - -(defun transient-get-value () - (delq nil (mapcar 'transient-infix-value transient-current-suffixes))) - -(cl-defgeneric transient-infix-value (obj) - "Return the value of the suffix object OBJ. - -This function is called by `transient-args' (which see), meaning -this function is how the value of a transient is determined so -that the invoked suffix command can use it. - -Currently most values are strings, but that is not set in stone. -Nil is not a value, it means \"no value\". - -Usually only infixes have a value, but see the method for -`transient-suffix'.") - -(cl-defmethod transient-infix-value ((_ transient-suffix)) - "Return nil, which means \"no value\". - -Infix arguments contribute the the transient's value while suffix -commands consume it. This function is called for suffixes anyway -because a command that both contributes to the transient's value -and also consumes it is not completely unconceivable. - -If you define such a command, then you must define a derived -class and implement this function because this default method -does nothing." nil) - -(cl-defmethod transient-infix-value ((obj transient-infix)) - "Return the value of OBJ's `value' slot." - (oref obj value)) - -(cl-defmethod transient-infix-value ((obj transient-option)) - "Return (concat ARGUMENT VALUE) or nil. - -ARGUMENT and VALUE are the values of the respective slots of OBJ. -If VALUE is nil, then return nil. VALUE may be the empty string, -which is not the same as nil." - (when-let ((value (oref obj value))) - (concat (oref obj argument) value))) - -(cl-defmethod transient-infix-value ((_ transient-variable)) - "Return nil, which means \"no value\". - -Setting the value of a variable is done by, well, setting the -value of the variable. I.e. this is a side-effect and does not -contribute to the value of the transient." - nil) - -(cl-defmethod transient-infix-value ((obj transient-files)) - "Return (concat ARGUMENT VALUE) or nil. - -ARGUMENT and VALUE are the values of the respective slots of OBJ. -If VALUE is nil, then return nil. VALUE may be the empty string, -which is not the same as nil." - (when-let ((value (oref obj value))) - (cons (oref obj argument) value))) - -;;; History - -(cl-defgeneric transient--history-key (obj) - "Return OBJ's history key. -If the value of the `history-key' slot is non-nil, then return -that. Otherwise return the value of the `command' slot." - (or (oref obj history-key) - (oref obj command))) - -(cl-defgeneric transient--history-push (obj) - "Push the current value of OBJ to its entry in `transient-history'." - (let ((key (transient--history-key obj))) - (setf (alist-get key transient-history) - (let ((args (transient-get-value))) - (cons args (delete args (alist-get key transient-history))))))) - -(cl-defgeneric transient--history-init (obj) - "Initialize OBJ's `history' slot. -This is the transient-wide history; many individual infixes also -have a history of their own.") - -(cl-defmethod transient--history-init ((obj transient-prefix)) - "Initialize OBJ's `history' slot from the variable `transient-history'." - (let ((val (oref obj value))) - (oset obj history - (cons val (delete val (alist-get (transient--history-key obj) - transient-history)))))) - -;;; Draw - -(defun transient--show-brief () - (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 - (cl-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-unreachable-key)))))) - -(defun transient--show () - (transient--timer-cancel) - (setq transient--showp t) - (let ((buf (get-buffer-create transient--buffer-name)) - (focus nil)) - (unless (window-live-p transient--window) - (setq transient--window - (display-buffer buf transient-display-buffer-action))) - (with-selected-window transient--window - (when transient-enable-popup-navigation - (setq focus (button-get (point) 'command))) - (erase-buffer) - (set-window-hscroll transient--window 0) - (set-window-dedicated-p transient--window t) - (set-window-parameter transient--window 'no-other-window t) - (setq window-size-fixed t) - (when (bound-and-true-p tab-line-format) - (setq tab-line-format nil)) - (setq mode-line-format (if (eq transient-mode-line-format 'line) - nil - transient-mode-line-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) - (transient--insert-groups) - (when (or transient--helpp transient--editp) - (transient--insert-help)) - (when (and (eq transient-mode-line-format 'line) - window-system) - (let ((face - (if-let ((f (and (transient--semantic-coloring-p) - (transient--prefix-color transient--prefix)))) - `(,@(and (>= emacs-major-version 27) '(:extend t)) - :background ,(face-foreground f)) - 'transient-separator))) - (insert (propertize "__" 'face face 'display '(space :height (1)))) - (insert (propertize "\n" 'face face 'line-height t)))) - (let ((window-resize-pixelwise t) - (window-size-fixed nil)) - (fit-window-to-buffer nil nil 1)) - (goto-char (point-min)) - (when transient-force-fixed-pitch - (transient--force-fixed-pitch)) - (when transient-enable-popup-navigation - (transient--goto-button focus))))) - -(defun transient--insert-groups () - (let ((groups (cl-mapcan (lambda (group) - (let ((hide (oref group hide))) - (and (not (and (functionp hide) - (funcall hide))) - (list group)))) - transient--layout)) - group) - (while (setq group (pop groups)) - (transient--insert-group group) - (when groups - (insert ?\n))))) - -(cl-defgeneric transient--insert-group (group) - "Format GROUP and its elements and insert the result.") - -(cl-defmethod transient--insert-group :before ((group transient-group)) - "Insert GROUP's description, if any." - (when-let ((desc (transient-format-description group))) - (insert desc ?\n))) - -(cl-defmethod transient--insert-group ((group transient-row)) - (dolist (suffix (oref group suffixes)) - (insert (transient-format suffix)) - (insert " ")) - (insert ?\n)) - -(cl-defmethod transient--insert-group ((group transient-column)) - (dolist (suffix (oref group suffixes)) - (let ((str (transient-format suffix))) - (insert str) - (unless (string-match-p ".\n\\'" str) - (insert ?\n))))) - -(cl-defmethod transient--insert-group ((group transient-columns)) - (let* ((columns - (mapcar - (lambda (column) - (let ((rows (mapcar 'transient-format (oref column suffixes)))) - (when-let ((desc (transient-format-description column))) - (push desc rows)) - rows)) - (oref group suffixes))) - (rs (apply #'max (mapcar #'length columns))) - (cs (length columns)) - (cw (mapcar (lambda (col) (apply #'max (mapcar #'length col))) - columns)) - (cc (transient--seq-reductions-from (apply-partially #'+ 3) cw 0))) - (dotimes (r rs) - (dotimes (c cs) - (insert (make-string (- (nth c cc) (current-column)) ?\s)) - (when-let ((cell (nth r (nth c columns)))) - (insert cell)) - (when (= c (1- cs)) - (insert ?\n)))))) - -(cl-defmethod transient--insert-group ((group transient-subgroups)) - (let* ((subgroups (oref group suffixes)) - (n (length subgroups))) - (dotimes (s n) - (transient--insert-group (nth s subgroups)) - (when (< s (1- n)) - (insert ?\n))))) - -(cl-defgeneric transient-format (obj) - "Format and return OBJ for display. - -When this function is called, then the current buffer is some -temporary buffer. If you need the buffer from which the prefix -command was invoked to be current, then do so by temporarily -making `transient--original-buffer' current.") - -(cl-defmethod transient-format ((arg string)) - "Return the string ARG after applying the `transient-heading' face." - (propertize arg 'face 'transient-heading)) - -(cl-defmethod transient-format ((_ null)) - "Return a string containing just the newline character." - "\n") - -(cl-defmethod transient-format ((arg integer)) - "Return a string containing just the ARG character." - (char-to-string arg)) - -(cl-defmethod transient-format :around ((obj transient-infix)) - "When reading user input for this infix, then highlight it." - (let ((str (cl-call-next-method obj))) - (when (eq obj transient--active-infix) - (setq str (concat str "\n")) - (add-face-text-property - (if (eq this-command 'transient-set-level) 3 0) - (length str) - 'transient-active-infix nil str)) - str)) - -(cl-defmethod transient-format :around ((obj transient-suffix)) - "When edit-mode is enabled, then prepend the level information. -Optional support for popup buttons is also implemented here." - (let ((str (concat - (and transient--editp - (let ((level (oref obj level))) - (propertize (format " %s " level) - 'face (if (transient--use-level-p level t) - 'transient-enabled-suffix - 'transient-disabled-suffix)))) - (cl-call-next-method obj)))) - (when (oref obj inapt) - (set-text-properties 0 (length str) - (list 'face 'transient-inapt-suffix) - str)) - (if transient-enable-popup-navigation - (make-text-button str nil - 'type 'transient-button - 'command (transient--suffix-command obj)) - str))) - -(cl-defmethod transient-format ((obj transient-infix)) - "Return a string generated using OBJ's `format'. -%k is formatted using `transient-format-key'. -%d is formatted using `transient-format-description'. -%v is formatted using `transient-format-value'." - (format-spec (oref obj format) - `((?k . ,(transient-format-key obj)) - (?d . ,(transient-format-description obj)) - (?v . ,(transient-format-value obj))))) - -(cl-defmethod transient-format ((obj transient-suffix)) - "Return a string generated using OBJ's `format'. -%k is formatted using `transient-format-key'. -%d is formatted using `transient-format-description'." - (format-spec (oref obj format) - `((?k . ,(transient-format-key obj)) - (?d . ,(transient-format-description obj))))) - -(cl-defgeneric transient-format-key (obj) - "Format OBJ's `key' for display and return the result.") - -(cl-defmethod transient-format-key ((obj transient-suffix)) - "Format OBJ's `key' for display and return the result." - (let ((key (oref obj key)) - (cmd (oref obj command))) - (if transient--redisplay-key - (let ((len (length transient--redisplay-key)) - (seq (cl-coerce (edmacro-parse-keys key t) 'list))) - (cond - ((equal (seq-take seq len) transient--redisplay-key) - (let ((pre (key-description (vconcat (seq-take seq len)))) - (suf (key-description (vconcat (seq-drop seq len))))) - (setq pre (replace-regexp-in-string "RET" "C-m" pre t)) - (setq pre (replace-regexp-in-string "TAB" "C-i" pre t)) - (setq suf (replace-regexp-in-string "RET" "C-m" suf t)) - (setq suf (replace-regexp-in-string "TAB" "C-i" suf t)) - ;; We use e.g. "-k" instead of the more correct "- k", - ;; because the former is prettier. If we did that in - ;; the definition, then we want to drop the space that - ;; is reinserted above. False-positives are possible - ;; for silly bindings like "-C-c C-c". - (unless (string-match-p " " key) - (setq pre (replace-regexp-in-string " " "" pre)) - (setq suf (replace-regexp-in-string " " "" suf))) - (concat (propertize pre 'face 'default) - (and (string-prefix-p (concat pre " ") key) " ") - (transient--colorize-key suf cmd) - (save-excursion - (when (string-match " +\\'" key) - (match-string 0 key)))))) - ((transient--lookup-key transient-sticky-map (kbd key)) - (transient--colorize-key key cmd)) - (t - (propertize key 'face 'transient-unreachable-key)))) - (transient--colorize-key key cmd)))) - -(defun transient--colorize-key (key command) - (propertize key 'face - (or (and (transient--semantic-coloring-p) - (transient--suffix-color command)) - 'transient-key))) - -(cl-defmethod transient-format-key :around ((obj transient-argument)) - (let ((key (cl-call-next-method obj))) - (cond ((not transient-highlight-mismatched-keys)) - ((not (slot-boundp obj 'shortarg)) - (add-face-text-property - 0 (length key) 'transient-nonstandard-key nil key)) - ((not (string-equal key (oref obj shortarg))) - (add-face-text-property - 0 (length key) 'transient-mismatched-key nil key))) - key)) - -(cl-defgeneric transient-format-description (obj) - "Format OBJ's `description' for display and return the result.") - -(cl-defmethod transient-format-description ((obj transient-child)) - "The `description' slot may be a function, in which case that is -called inside the correct buffer (see `transient-insert-group') -and its value is returned to the caller." - (when-let ((desc (oref obj description))) - (if (functionp desc) - (with-current-buffer transient--original-buffer - (funcall desc)) - desc))) - -(cl-defmethod transient-format-description ((obj transient-group)) - "Format the description by calling the next method. If the result -doesn't use the `face' property at all, then apply the face -`transient-heading' to the complete string." - (when-let ((desc (cl-call-next-method obj))) - (if (text-property-not-all 0 (length desc) 'face nil desc) - desc - (propertize desc 'face 'transient-heading)))) - -(cl-defmethod transient-format-description :around ((obj transient-suffix)) - "Format the description by calling the next method. 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 (or (cl-call-next-method obj) - (propertize "(BUG: no description)" 'face 'error)))) - (if (transient--key-unreachable-p obj) - (propertize desc 'face 'transient-unreachable) - desc))) - -(cl-defgeneric transient-format-value (obj) - "Format OBJ's value for display and return the result.") - -(cl-defmethod transient-format-value ((obj transient-suffix)) - (propertize (oref obj argument) - 'face (if (oref obj value) - 'transient-argument - 'transient-inactive-argument))) - -(cl-defmethod transient-format-value ((obj transient-option)) - (let ((value (oref obj value))) - (propertize (concat (oref obj argument) - (if (listp value) - (mapconcat #'identity value ",") - value)) - 'face (if value - 'transient-value - 'transient-inactive-value)))) - -(cl-defmethod transient-format-value ((obj transient-switches)) - (with-slots (value argument-format choices) obj - (format (propertize argument-format - 'face (if value - 'transient-value - 'transient-inactive-value)) - (concat - (propertize "[" 'face 'transient-inactive-value) - (mapconcat - (lambda (choice) - (propertize choice 'face - (if (equal (format argument-format choice) value) - 'transient-value - 'transient-inactive-value))) - choices - (propertize "|" 'face 'transient-inactive-value)) - (propertize "]" 'face 'transient-inactive-value))))) - -(cl-defmethod transient-format-value ((obj transient-files)) - (let ((argument (oref obj argument))) - (if-let ((value (oref obj value))) - (propertize (concat argument " " - (mapconcat (lambda (f) (format "%S" f)) - (oref obj value) " ")) - 'face 'transient-argument) - (propertize argument 'face 'transient-inactive-argument)))) - -(defun transient--key-unreachable-p (obj) - (and transient--redisplay-key - (let ((key (oref obj key))) - (not (or (equal (seq-take (cl-coerce (edmacro-parse-keys key t) 'list) - (length transient--redisplay-key)) - transient--redisplay-key) - (transient--lookup-key transient-sticky-map (kbd key))))))) - -(defun transient--lookup-key (keymap key) - (let ((val (lookup-key keymap key))) - (and val (not (integerp val)) val))) - -;;; Help - -(cl-defgeneric transient-show-help (obj) - "Show help for OBJ's command.") - -(cl-defmethod transient-show-help ((obj transient-prefix)) - "Show the info manual, manpage or command doc-string. -Show the first one that is specified." - (if-let ((manual (oref obj info-manual))) - (info manual) - (if-let ((manpage (oref obj man-page))) - (transient--show-manpage manpage) - (transient--describe-function (oref obj command))))) - -(cl-defmethod transient-show-help ((_ transient-suffix)) - "Show the command doc-string." - (if (eq this-original-command 'transient-help) - (if-let ((manpage (oref transient--prefix man-page))) - (transient--show-manpage manpage) - (transient--describe-function (oref transient--prefix command))) - (transient--describe-function this-original-command))) - -(cl-defmethod transient-show-help ((obj transient-infix)) - "Show the manpage if defined or the command doc-string. -If the manpage is specified, then try to jump to the correct -location." - (if-let ((manpage (oref transient--prefix man-page))) - (transient--show-manpage manpage (ignore-errors (oref obj argument))) - (transient--describe-function this-original-command))) - -;; `cl-generic-generalizers' doesn't support `command' et al. -(cl-defmethod transient-show-help (cmd) - "Show the command doc-string." - (transient--describe-function cmd)) - -(defun transient--show-manpage (manpage &optional argument) - (require 'man) - (let* ((Man-notify-method 'meek) - (buf (Man-getpage-in-background manpage)) - (proc (get-buffer-process buf))) - (while (and proc (eq (process-status proc) 'run)) - (accept-process-output proc)) - (switch-to-buffer buf) - (when argument - (transient--goto-argument-description argument)))) - -(defun transient--describe-function (fn) - (describe-function fn) - (select-window (get-buffer-window (help-buffer)))) - -(defun transient--goto-argument-description (arg) - (goto-char (point-min)) - (let ((case-fold-search nil) - ;; This matches preceding/proceeding options. Options - ;; such as "-a", "-S[]", and "--grep=" - ;; are matched by this regex without the shy group. - ;; The ". " in the shy group is for options such as - ;; "-m parent-number", and the "-[^[:space:]]+ " is - ;; for options such as "--mainline parent-number" - (others "-\\(?:. \\|-[^[:space:]]+ \\)?[^[:space:]]+")) - (when (re-search-forward - (if (equal arg "--") - ;; Special case. - "^[\t\s]+\\(--\\(?: \\|$\\)\\|\\[--\\]\\)" - ;; Should start with whitespace and may have - ;; any number of options before and/or after. - (format - "^[\t\s]+\\(?:%s, \\)*?\\(?1:%s\\)%s\\(?:, %s\\)*$" - others - ;; Options don't necessarily end in an "=" - ;; (e.g., "--gpg-sign[=]") - (string-remove-suffix "=" arg) - ;; Simple options don't end in an "=". Splitting this - ;; into 2 cases should make getting false positives - ;; less likely. - (if (string-suffix-p "=" arg) - ;; "[^[:space:]]*[^.[:space:]]" matches the option - ;; value, which is usually after the option name - ;; and either '=' or '[='. The value can't end in - ;; a period, as that means it's being used at the - ;; end of a sentence. The space is for options - ;; such as '--mainline parent-number'. - "\\(?: \\|\\[?=\\)[^[:space:]]*[^.[:space:]]" - ;; Either this doesn't match anything (e.g., "-a"), - ;; or the option is followed by a value delimited - ;; by a "[", "<", or ":". A space might appear - ;; before this value, as in "-f ". The - ;; space alternative is for options such as - ;; "-m parent-number". - "\\(?:\\(?: \\| ?[\\[<:]\\)[^[:space:]]*[^.[:space:]]\\)?") - others)) - nil t) - (goto-char (match-beginning 1))))) - -(defun transient--insert-help () - (unless (looking-back "\n\n" 2) - (insert "\n")) - (when transient--helpp - (insert - (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)))) - (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)))) - (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)))))) - -(defvar transient-resume-mode-map - (let ((map (make-sparse-keymap))) - (define-key map [remap Man-quit] 'transient-resume) - (define-key map [remap Info-exit] 'transient-resume) - (define-key map [remap quit-window] 'transient-resume) - map) - "Keymap for `transient-resume-mode'. - -This keymap remaps every command that would usually just quit the -documentation buffer to `transient-resume', which additionally -resumes the suspended transient.") - -(define-minor-mode transient-resume-mode - "Auxiliary minor-mode used to resume a transient after viewing help.") - -;;; Compatibility -;;;; Popup Navigation - -(defun transient-popup-navigation-help () - "Inform the user how to enable popup navigation commands." - (interactive) - (message "This command is only available if `%s' is non-nil" - 'transient-enable-popup-navigation)) - -(define-button-type 'transient-button - 'face nil - 'action (lambda (button) - (let ((command (button-get button 'command))) - ;; Yes, I know that this is wrong(tm). - ;; Unfortunately it is also necessary. - (setq this-original-command command) - (call-interactively command)))) - -(defvar transient-popup-navigation-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "") 'transient-noop) - (define-key map (kbd "") 'transient-mouse-push-button) - (define-key map (kbd "RET") 'transient-push-button) - (define-key map (kbd "") 'transient-backward-button) - (define-key map (kbd "C-p") 'transient-backward-button) - (define-key map (kbd "") 'transient-forward-button) - (define-key map (kbd "C-n") 'transient-forward-button) - (define-key map (kbd "C-r") 'transient-isearch-backward) - (define-key map (kbd "C-s") 'transient-isearch-forward) - map)) - -(defun transient-mouse-push-button (&optional pos) - "Invoke the suffix the user clicks on." - (interactive (list last-command-event)) - (push-button pos)) - -(defun transient-push-button () - "Invoke the selected suffix command." - (interactive) - (with-selected-window transient--window - (push-button))) - -(defun transient-backward-button (n) - "Move to the previous button in the transient popup buffer. -See `backward-button' for information about N." - (interactive "p") - (with-selected-window transient--window - (backward-button n t))) - -(defun transient-forward-button (n) - "Move to the next button in the transient popup buffer. -See `forward-button' for information about N." - (interactive "p") - (with-selected-window transient--window - (forward-button n t))) - -(defun transient--goto-button (command) - (if (not command) - (forward-button 1) - (while (and (ignore-errors (forward-button 1)) - (not (eq (button-get (button-at (point)) 'command) command)))) - (unless (eq (button-get (button-at (point)) 'command) command) - (goto-char (point-min)) - (forward-button 1)))) - -;;;; Popup Isearch - -(defvar transient--isearch-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map isearch-mode-map) - (define-key map [remap isearch-exit] 'transient-isearch-exit) - (define-key map [remap isearch-cancel] 'transient-isearch-cancel) - (define-key map [remap isearch-abort] 'transient-isearch-abort) - map)) - -(defun transient-isearch-backward (&optional regexp-p) - "Do incremental search backward. -With a prefix argument, do an incremental regular expression -search instead." - (interactive "P") - (transient--isearch-setup) - (let ((isearch-mode-map transient--isearch-mode-map)) - (isearch-mode nil regexp-p))) - -(defun transient-isearch-forward (&optional regexp-p) - "Do incremental search forward. -With a prefix argument, do an incremental regular expression -search instead." - (interactive "P") - (transient--isearch-setup) - (let ((isearch-mode-map transient--isearch-mode-map)) - (isearch-mode t regexp-p))) - -(defun transient-isearch-exit () - "Like `isearch-exit' but adapted for `transient'." - (interactive) - (isearch-exit) - (transient--isearch-exit)) - -(defun transient-isearch-cancel () - "Like `isearch-cancel' but adapted for `transient'." - (interactive) - (condition-case nil (isearch-cancel) (quit)) - (transient--isearch-exit)) - -(defun transient-isearch-abort () - "Like `isearch-abort' but adapted for `transient'." - (interactive) - (condition-case nil (isearch-abort) (quit)) - (transient--isearch-exit)) - -(defun transient--isearch-setup () - (select-window transient--window) - (transient--suspend-override)) - -(defun transient--isearch-exit () - (select-window transient--original-window) - (transient--resume-override)) - -;;;; Hydra Color Emulation - -(defun transient--semantic-coloring-p () - (and transient-semantic-coloring - (not transient--helpp) - (not transient--editp))) - -(defun transient--suffix-color (command) - (or (get command 'transient-color) - (get (transient--get-predicate-for command) 'transient-color))) - -(defun transient--prefix-color (command) - (let* ((nonsuf (or (oref command transient-non-suffix) - 'transient--do-warn)) - (nonsuf (if (memq nonsuf '(transient--do-noop transient--do-warn)) - 'disallow - (get nonsuf 'transient-color))) - (suffix (if-let ((pred (oref command transient-suffix))) - (get pred 'transient-color) - (if (eq nonsuf 'transient-red) - 'transient-red - 'transient-blue)))) - (pcase (list suffix nonsuf) - (`(transient-red disallow) 'transient-amaranth) - (`(transient-blue disallow) 'transient-teal) - (`(transient-red transient-red) 'transient-pink) - (`(transient-red transient-blue) 'transient-red) - (`(transient-blue transient-blue) 'transient-blue)))) - -;;;; Edebug - -(defun transient--edebug--recursive-edit (fn arg-mode) - (transient--debug 'edebug--recursive-edit) - (if (not transient--prefix) - (funcall fn arg-mode) - (transient--suspend-override t) - (funcall fn arg-mode) - (transient--resume-override t))) - -(advice-add 'edebug--recursive-edit :around 'transient--edebug--recursive-edit) - -(defun transient--abort-edebug () - (when (bound-and-true-p edebug-active) - (transient--emergency-exit))) - -(advice-add 'abort-recursive-edit :before 'transient--abort-edebug) -(advice-add 'top-level :before 'transient--abort-edebug) - -(defun transient--edebug-command-p () - (and (bound-and-true-p edebug-active) - (or (memq this-command '(top-level abort-recursive-edit)) - (string-prefix-p "edebug" (symbol-name this-command))))) - -;;;; Miscellaneous - -(declare-function which-key-mode "which-key" (&optional arg)) - -(defun transient--suspend-which-key-mode () - (when (bound-and-true-p which-key-mode) - (which-key-mode -1) - (add-hook 'transient-exit-hook 'transient--resume-which-key-mode))) - -(defun transient--resume-which-key-mode () - (unless transient--prefix - (which-key-mode 1) - (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. - -\"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 -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 -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 -we stop there." - (define-key transient-base-map "q" 'transient-quit-one) - (define-key transient-sticky-map "q" 'transient-quit-seq) - (setq transient-substitute-key-function - 'transient-rebind-quit-commands)) - -(defun transient-rebind-quit-commands (obj) - "See `transient-bind-q-to-quit'." - (let ((key (oref obj key))) - (cond ((string-equal key "q") "Q") - ((string-equal key "Q") "M-q") - (t key)))) - -(defun transient--force-fixed-pitch () - (require 'face-remap) - (face-remap-reset-base 'default) - (face-remap-add-relative 'default 'fixed-pitch)) - -;;;; Missing from Emacs - -(defun transient--seq-reductions-from (function sequence initial-value) - (let ((acc (list initial-value))) - (seq-doseq (elt sequence) - (push (funcall function (car acc) elt) acc)) - (nreverse acc))) - -;;; Font-Lock - -(defconst transient-font-lock-keywords - (eval-when-compile - `((,(concat "(" - (regexp-opt (list "transient-define-prefix" - "transient-define-infix" - "transient-define-argument" - "transient-define-suffix") - t) - "\\_>[ \t'\(]*" - "\\(\\(?:\\sw\\|\\s_\\)+\\)?") - (1 'font-lock-keyword-face) - (2 'font-lock-function-name-face nil t))))) - -(font-lock-add-keywords 'emacs-lisp-mode transient-font-lock-keywords) - -;;; _ -(provide 'transient) -;; Local Variables: -;; indent-tabs-mode: nil -;; End: -;;; transient.el ends here diff --git a/elpa/transient-20200719.955/transient.info b/elpa/transient-20200719.955/transient.info deleted file mode 100644 index 1fc0d99..0000000 --- a/elpa/transient-20200719.955/transient.info +++ /dev/null @@ -1,2442 +0,0 @@ -This is transient.info, produced by makeinfo version 6.5 from -transient.texi. - - Copyright (C) 2018-2020 Jonas Bernoulli - - You can redistribute this document and/or modify it under the terms - of the GNU General Public License as published by the Free Software - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Transient: (transient). Transient Commands. -END-INFO-DIR-ENTRY - - -File: transient.info, Node: Top, Next: Introduction, Up: (dir) - -Transient User and Developer Manual -*********************************** - -Taking inspiration from prefix keys and prefix arguments, Transient -implements a similar abstraction involving a prefix command, infix -arguments and suffix commands. We could call this abstraction a -"transient command", but because it always involves at least two -commands (a prefix and a suffix) we prefer to call it just a -"transient". - - When the user calls a transient prefix command, then a transient -(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 -until the transient is exited by invoking a suffix command. - - Calling an infix command causes its value to be changed, possibly by -reading a new value in the minibuffer. - - Calling a suffix command usually causes the transient to be exited -but suffix commands can also be configured to not exit the transient. - -This manual is for Transient version 0.2.0 (v0.2.0-8-gc94cff7+1). - - Copyright (C) 2018-2020 Jonas Bernoulli - - You can redistribute this document and/or modify it under the terms - of the GNU General Public License as published by the Free Software - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - -* Menu: - -* Introduction:: -* Usage:: -* Other Options:: -* Modifying Existing Transients:: -* Defining New Commands:: -* Classes and Methods:: -* Related Abstractions and Packages:: -* FAQ:: -* Keystroke Index:: -* Command Index:: -* Function Index:: -* Variable Index:: - -— The Detailed Node Listing — - -Usage - -* Invoking Transients:: -* Aborting and Resuming Transients:: -* Common Suffix Commands:: -* Saving Values:: -* Using History:: -* Getting Help for Suffix Commands:: -* Enabling and Disabling Suffixes:: -* Other Commands:: - -Defining New Commands - -* Defining Transients:: -* Binding Suffix and Infix Commands:: -* Defining Suffix and Infix Commands:: -* Using Infix Arguments:: -* Transient State:: - -Binding Suffix and Infix Commands - -* Group Specifications:: -* Suffix Specifications:: - - -Classes and Methods - -* Group Classes:: -* Group Methods:: -* Prefix Classes:: -* Suffix Classes:: -* Suffix Methods:: -* Prefix Slots:: -* Suffix Slots:: -* Predicate Slots:: - -Suffix Methods - -* Suffix Value Methods:: -* Suffix Format Methods:: - - -Related Abstractions and Packages - -* Comparison With Prefix Keys and Prefix Arguments:: -* Comparison With Other Packages:: - - - -File: transient.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top - -1 Introduction -************** - -Taking inspiration from prefix keys and prefix arguments, Transient -implements a similar abstraction involving a prefix command, infix -arguments and suffix commands. We could call this abstraction a -"transient command", but because it always involves at least two -commands (a prefix and a suffix) we prefer to call it just a -"transient". - - Transient keymaps are a feature provided by Emacs. Transients as - implemented by this package involve the use of transient keymaps. - - Emacs provides a feature that it calls "prefix commands". When we - talk about "prefix commands" in this manual, then we mean our own - kind of "prefix commands", unless specified otherwise. To avoid - ambiguity we sometimes use the terms "transient prefix command" for - our kind and "regular prefix command" for Emacs’ kind. - - When the user calls a transient prefix command, then a transient -(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 -until the transient state is exited by invoking a suffix command. - - Calling an infix command causes its value to be changed. How that is -done depends on the type of the infix command. The simplest case is an -infix command that represents a command-line argument that does not take -a value. Invoking such an infix command causes the switch to be toggled -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 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. - - A suffix command can, but does not have to, use the infix arguments -in much the same way it can choose to use or ignore the prefix -arguments. For a suffix command that was invoked from a transient the -variable ‘transient-current-suffixes’ and the function ‘transient-args’ -serve about the same purpose as the variables ‘prefix-arg’ and -‘current-prefix-arg’ do for any command that was called after the prefix -arguments have been set using a command such as ‘universal-argument’. - - The information shown in the popup buffer while a transient is active -looks a bit like this: - - ,----------------------------------------- - |Arguments - | -f Force (--force) - | -a Annotate (--annotate) - | - |Create - | t tag - | r release - `----------------------------------------- - - This is a simplified version of ‘magit-tag’. Info manuals do not - support images or colored text, so the above "screenshot" lacks - some information; in practice you would be able to tell whether the - arguments ‘--force’ and ‘--annotate’ are enabled or not based on - their color. - - 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. 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’ 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 -than what is reasonable when using prefix arguments. There is a limit -to how many aspects of a command can be controlled using prefix -arguments. Furthermore what a certain prefix argument means for -different commands can be completely different, and users have to read -documentation to learn and then commit to memory what a certain prefix -argument means to a certain command. - - Transient suffix commands on the other hand can accept dozens of -different arguments without the user having to remember anything. When -using Transient, then one can call a command with arguments that are -just as complex as when calling the same function non-interactively -using code. - - Invoking a transient command with arguments is similar to invoking a -command in a shell with command-line completion and history enabled. -One benefit of the Transient interface is that it remembers history not -only on a global level ("this command was invoked using these arguments -and previously it was invoked using those other arguments"), but also -remembers the values of individual arguments independently. See *note -Using History::. - - After a transient prefix command is invoked ‘C-h ’ can be used -to show the documentation for the infix or suffix command that ‘’ -is bound to (see *note Getting Help for Suffix Commands::) and infixes -and suffixes can be removed from the transient using ‘C-x l ’. -Infixes and suffixes that are disabled by default can be enabled the -same way. See *note Enabling and Disabling Suffixes::. - - Transient ships with support for a few different types of specialized -infix commands. A command that sets a command line option for example -has different needs than a command that merely toggles a boolean flag. -Additionally Transient provides abstractions for defining new types, -which the author of Transient did not anticipate (or didn’t get around -to implementing yet). - - -File: transient.info, Node: Usage, Next: Other Options, Prev: Introduction, Up: Top - -2 Usage -******* - -* Menu: - -* Invoking Transients:: -* Aborting and Resuming Transients:: -* Common Suffix Commands:: -* Saving Values:: -* Using History:: -* Getting Help for Suffix Commands:: -* Enabling and Disabling Suffixes:: -* Other Commands:: - - -File: transient.info, Node: Invoking Transients, Next: Aborting and Resuming Transients, Up: Usage - -2.1 Invoking Transients -======================= - -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. 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 a popup 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*. - - Instead of setting arguments to be used by a suffix command, infix -commands may also set some value by side-effect. - - -File: transient.info, Node: Aborting and Resuming Transients, Next: Common Suffix Commands, Prev: Invoking Transients, Up: Usage - -2.2 Aborting and Resuming Transients -==================================== - -To quit the transient without invoking a suffix command press ‘C-g’. - - Key bindings in transient keymaps may be longer than a single event. -After pressing a valid prefix key, all commands whose bindings do not -begin with that prefix key are temporarily unavailable and grayed out. -To abort the prefix key press ‘C-g’ (which in this case only quits the -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. -Pressing ‘C-g’ while a nested transient is active only quits the -innermost transient, causing a return to the previous transient. - - ‘C-q’ or ‘C-z’ on the other hand always exits all transients. If you -use the latter, then you can later resume the stack of transients using -‘M-x transient-resume’. - -‘C-g’ (‘transient-quit-seq’) -‘C-g’ (‘transient-quit-one’) - - This key quits the currently active incomplete key sequence, if - any, or else the current transient. When quitting the current - transient, then it returns to the previous transient, if any. - - Transient’s predecessor bound ‘q’ instead of ‘C-g’ to the quit -command. To learn how to get that binding back see -‘transient-bind-q-to-quit’’s doc string. - -‘C-q’ (‘transient-quit-all’) - - This command quits the currently active incomplete key sequence, if - any, and all transients, including the active transient and all - suspended transients, if any. - -‘C-z’ (‘transient-suspend’) - - Like ‘transient-quit-all’, this command quits an incomplete key - sequence, if any, and all transients. Additionally it saves the - stack of transients so that it can easily be resumed (which is - particularly useful if you quickly need to do "something else" and - the stack is deeper than a single transient and/or you have already - changed the values of some infix arguments). - - Note that only a single stack of transients can be saved at a time. - If another stack is already saved, then saving a new stack discards - the previous stack. - -‘M-x transient-resume’ (‘transient-resume’) - - This command resumes the previously suspended stack of transients, - if any. - - -File: transient.info, Node: Common Suffix Commands, Next: Saving Values, Prev: Aborting and Resuming Transients, Up: Usage - -2.3 Common Suffix Commands -========================== - -A few shared suffix commands are available in all transients. These -suffix commands are not shown in the popup buffer by default. - - Most of these commands are bound to ‘C-x ’ and after pressing -‘C-x’ a section featuring all common commands is temporarily shown in -the popup buffer. After invoking one of these commands, that 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. - -‘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 - 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 to many options. - - While a transient is active, pressing ‘C-x’ always shows the common - command. 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 node -or in one of the following nodes. - - Some of Transient’s key bindings differ from the respective bindings -of Magit-Popup; see *note FAQ:: for more information. - - -File: transient.info, Node: Saving Values, Next: Using History, Prev: Common Suffix Commands, Up: Usage - -2.4 Saving Values -================= - -After setting the infix arguments in a transient, the user can save -those arguments for future invocations. - - Most transients will start out with the saved arguments when they are -invoked. There are a few exceptions though. Some transients are -designed so that the value that they use is stored externally as the -buffer-local value of some variable. Invoking such a transient again -uses the buffer-local value. (1) - - If the user does not save the value and just exits using a regular -suffix command, then the value is merely saved to the transient’s -history. That value won’t be used when the transient is next invoked -but it is easily accessible (see *note Using History::). - -‘C-x s’ (‘transient-set’) - - This command saves the value of the active transient for this Emacs - session. - -‘C-x C-s’ (‘transient-save’) - - Save the value of the active transient persistently across Emacs - sessions. - - -- User Option: transient-values-file - - This file is used to persist the values of transients between Emacs - sessions. - - ---------- Footnotes ---------- - - (1) ‘magit-diff’ and ‘magit-log’ are two prominent examples, and -their handling of buffer-local values is actually a bit more complicated -than outlined above and even customizable. This is something I am -rethinking, but I don’t want to rush any changes.) - - -File: transient.info, Node: Using History, Next: Getting Help for Suffix Commands, Prev: Saving Values, Up: Usage - -2.5 Using History -================= - -Every time the user invokes a suffix command the transient’s current -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. - -‘M-p’ (‘transient-history-prev’) - - This command switches to the previous value used for the active - transient. - -‘M-n’ (‘transient-history-next’) - - This command switches to the next value used for the active - transient. - - In addition to the transient-wide history, Transient of course -supports per-infix history. When an infix reads user-input using the -minibuffer, then the user can use the regular minibuffer history -commands to cycle through previously used values. Usually the same keys -as those mentioned above are bound to those commands. - - Authors of transients should arrange for different infix commands -that read the same kind of value to also use the same history key (see -*note Suffix Slots::). - - Both kinds of history are saved to a file when Emacs is exited. - - -- User Option: transient-history-file - - This file is used to persist the history of transients and their - infixes between Emacs sessions. - - -- User Option: transient-history-limit - - This option controls how many history elements are kept at the time - the history is saved in ‘transient-history-file’. - - -File: transient.info, Node: Getting Help for Suffix Commands, Next: Enabling and Disabling Suffixes, Prev: Using History, Up: Usage - -2.6 Getting Help for Suffix Commands -==================================== - -Transients can have many suffixes and infixes that the user might not be -familiar with. To make it trivial to get help for these, Transient -provides access to the documentation directly from the active transient. - -‘C-h’ (‘transient-help’) - - This command enters help mode. When help mode is active, then - typing ‘’ shows information about the suffix command that - ‘’ normally is bound to (instead of invoking it). Pressing - ‘C-h’ a second time shows information about the _prefix_ command. - - After typing ‘’ the stack of transient states is suspended and - information about the suffix command is shown instead. Typing ‘q’ - in the help buffer buries that buffer and resumes the transient - state. - - What sort of documentation is shown depends on how the transient was -defined. For infix commands that represent command-line arguments this -ideally shows the appropriate manpage. ‘transient-help’ then tries to -jump to the correct location within that. Info manuals are also -supported. The fallback is to show the command’s doc string, for -non-infix suffixes this is usually appropriate. - - -File: transient.info, Node: Enabling and Disabling Suffixes, Next: Other Commands, Prev: Getting Help for Suffix Commands, Up: Usage - -2.7 Enabling and Disabling Suffixes -=================================== - -The user base of a package that uses transients can be very diverse. -This is certainly the case for Magit; some users have been using it and -Git for a decade, while others are just getting started now. - - For that reason a mechanism is needed that authors can use to -classify a transient’s infixes and suffixes along the -essentials...everything spectrum. We use the term "levels" to describe -that mechanism. - - Each suffix command is placed on a level and each transient has a -level (called transient-level), which controls which suffix commands are -available. Integers between 1 and 7 (inclusive) are valid levels. 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. - - The default level for both transients and their suffixes is 4. The -‘transient-default-level’ option only controls the default for -transients. The default suffix level is always 4. The authors of -transients should place certain suffixes on a higher level, if they -expect that it won’t be of use to most users, and they should place very -important suffixes on a lower level, so that they remain available even -if the user lowers the transient level. - - (Magit currently places nearly all suffixes on level 4 and lower -levels are not used at all yet. So for the time being you should not -set a lower default level and using a higher level might not give you as -many additional suffixes as you hoped.) - - -- User Option: transient-default-level - - This option controls which suffix levels are made available by - default. It sets the transient-level for transients for which the - user has not set that individually. - - -- User Option: transient-levels-file - - This file is used to persist the levels of transients and their - suffixes between Emacs sessions. - -‘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 - with their levels. The colors of the levels indicate whether they - are enabled or not. The level of the transient is also displayed - along with some usage information. - - In edit mode, pressing the key that would usually invoke a certain - suffix instead prompts the user for the level that suffix should be - placed on. - - Help mode is available in edit mode. - - To change the transient level press ‘C-x l’ again. - - To exit edit mode press ‘C-g’. - - Note that edit mode does not display any suffixes that are not - currently usable. ‘magit-rebase’ for example shows different - suffixes depending on whether a rebase is already in progress or - not. The predicates also apply in edit mode. - - Therefore, to control which suffixes are available given a certain - state, you have to make sure that that state is currently active. - - -File: transient.info, Node: Other Commands, Prev: Enabling and Disabling Suffixes, Up: Usage - -2.8 Other Commands -================== - -When invoking a transient in a small frame, the transient window may not -show the complete buffer, making it necessary to scroll, using the -following commands. These commands are never shown in the transient -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 - 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). - - -File: transient.info, Node: Other Options, Next: Modifying Existing Transients, Prev: Usage, Up: Top - -3 Other Options -*************** - - -- User Option: transient-show-popup - - This option controls whether the current transient’s infix and - suffix commands are shown in the popup buffer. - - • If ‘t’ (the default) then the popup buffer is shown as soon as - a transient prefix command is invoked. - - • If ‘nil’, then the popup 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 - even that summary is shown; only the pressed key itself is - shown. - - The popup is shown when the user explicitly requests it by - pressing an incomplete prefix key sequence. Unless this is - zero, then the popup is shown after that many seconds of - inactivity (using the absolute value). - - -- User Option: transient-enable-popup-navigation - - This option controls whether navigation commands are enabled in the - transient popup. - - 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. This is disabled by default. 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. ‘RET’ invokes the suffix - the cursor is on. - - • ‘’ invokes the clicked on suffix. - - • ‘C-s’ and ‘C-r’ start isearch in the popup buffer. - - -- 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 buf 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 - should accept two arguments: a buffer to display and an alist of - the same form as ALIST. See *note (elisp)Choosing Window::. - - The default is ‘(display-buffer-in-side-window (side . bottom))’. - This displays the window at the bottom of the selected frame. - Another useful value is ‘(display-buffer-below-selected)’. This is - what ‘magit-popup’ used by default. For more alternatives see - *note (elisp)Display Action Functions::. - - It may be possible to display the window in another frame, but - whether that works in practice depends on the window-manager. If - the window manager selects the new window (Emacs frame), then it - doesn’t work. - - If you change the value of this option, then you might also want to - change the value of ‘transient-mode-line-format’. - - -- User Option: transient-mode-line-format - - This option controls whether the transient popup buffer has a - mode-line, separator line, or neither. - - 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 a - good value. - - If ‘line’ (the default), then the buffer also has no mode-line, but - a thin line is drawn instead, using the background color of the - face ‘transient-separator’. Termcap frames cannot display thin - lines and therefore fallback to treating ‘line’ like ‘nil’. - - Otherwise this can be any mode-line format. See *note (elisp)Mode - Line Format:: for details. - - -- User Option: transient-read-with-initial-input - - This option controls whether the last history element is used as - the initial minibuffer input when reading the value of an infix - argument from the user. If ‘nil’, then there is no initial input - and the first element has to be accessed the same way as the older - elements. - - -- User Option: transient-highlight-mismatched-keys - - This option controls whether key bindings of infix commands that do - not match the respective command-line argument should be - highlighted. For other infix commands this option has no effect. - - When this option is non-nil, then the key binding for an infix - argument is highlighted when only a long argument (e.g. - ‘--verbose’) is specified but no shorthand (e.g ‘-v’). In the rare - case that a shorthand is specified but the key binding does not - match, then it is highlighted differently. - - Highlighting mismatched key bindings is useful when learning the - arguments of the underlying command-line tool; you wouldn’t want to - learn any short-hands that do not actually exist. - - The highlighting is done using one of the faces - ‘transient-mismatched-key’ and ‘transient-nonstandard-key’. - - -- User Option: transient-substitute-key-function - - This function is used to modify key bindings. If the value of this - option is nil (the default), then no substitution is performed. - - This function is called with one argument, the prefix object, and - must return a key binding description, either the existing key - description it finds in the ‘key’ slot, or the key description that - replaces the prefix key. It could be used to make other - substitutions, but that is discouraged. - - For example, ‘=’ is hard to reach using my custom keyboard layout, - so I substitute ‘(’ for that, which is easy to reach using a layout - optimized for lisp. - - (setq transient-substitute-key-function - (lambda (obj) - (let ((key (oref obj key))) - (if (string-match "\\`\\(=\\)[a-zA-Z]" key) - (replace-match "(" t t key 1) - key)))) - - -- User Option: transient-detect-key-conflicts - - This option controls whether key binding conflicts should be - detected at the time the transient is invoked. If so, then this - results in an error, which prevents the transient from being used. - Because of that, conflicts are ignored by default. - - Conflicts cannot be determined earlier, i.e. when the transient is - being defined and when new suffixes are being added, because at - that time there can be false-positives. It is actually valid for - multiple suffixes to share a common key binding, provided the - predicates of those suffixes prevent that more than one of them is - enabled at a time. - - -- 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 - ‘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. - - -File: transient.info, Node: Modifying Existing Transients, Next: Defining New Commands, Prev: Other Options, Up: Top - -4 Modifying Existing Transients -******************************* - -To an extent transients can be customized interactively, see *note -Enabling and Disabling Suffixes::. This section explains how existing -transients can be further modified non-interactively. - - The following functions share a few arguments: - - • PREFIX is a transient prefix command, a symbol. - - • 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 - "suffixes (including infixes)" or "non-infix suffixes". Here it - means the former. See *note Suffix Specifications::. - - 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’). - - If LOC is a list of coordinates, then it can be used to identify a - group, not just an individual suffix command. - - The function ‘transient-get-suffix’ can be useful to determine - whether a certain coordination list 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. - - 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’. - - -- Function: transient-insert-suffix prefix loc suffix - - This function inserts suffix or group SUFFIX into PREFIX before - LOC. - - -- Function: transient-append-suffix prefix loc suffix - - This function inserts suffix or group SUFFIX into PREFIX after LOC. - - -- Function: transient-replace-suffix prefix loc suffix - - This function replaces the suffix or group at LOC in PREFIX with - suffix or group SUFFIX. - - -- Function: transient-remove-suffix prefix loc - - This function removes the suffix or group at LOC in PREFIX. - - -- Function: transient-get-suffix prefix loc - - This function returns the suffix or group at LOC in PREFIX. The - returned value has the form mentioned above. - - -- Function: transient-suffix-put prefix loc prop value - - This function edits the suffix or group at LOC in PREFIX, by - setting the PROP of its plist to VALUE. - - 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. - - -File: transient.info, Node: Defining New Commands, Next: Classes and Methods, Prev: Modifying Existing Transients, Up: Top - -5 Defining New Commands -*********************** - -* Menu: - -* Defining Transients:: -* Binding Suffix and Infix Commands:: -* Defining Suffix and Infix Commands:: -* Using Infix Arguments:: -* Transient State:: - - -File: transient.info, Node: Defining Transients, Next: Binding Suffix and Infix Commands, Up: Defining New Commands - -5.1 Defining Transients -======================= - -A transient consists of a prefix command and at least one suffix -command, though usually a transient has several infix and suffix -commands. The below macro defines the transient prefix command *and* -binds the transient’s infix and suffix commands. In other words, it -defines the complete transient, not just the transient prefix command -that is used to invoke that transient. - - -- Macro: transient-define-prefix name arglist [docstring] [keyword - value]... group... [body...] - - This macro defines NAME as a transient prefix command and binds the - transient’s infix and suffix commands. - - ARGLIST are the arguments that the prefix command takes. DOCSTRING - is the documentation string and is optional. - - These arguments can optionally be followed by keyword-value pairs. - Each key has to be a keyword symbol, either ‘:class’ or a keyword - argument supported by the constructor of that class. The - ‘transient-prefix’ class is used if the class is not specified - explicitly. - - GROUPs add key bindings for infix and suffix commands and specify - how these bindings are presented in the popup buffer. At least one - GROUP has to be specified. See *note Binding Suffix and Infix - Commands::. - - The BODY is optional. If it is omitted, then ARGLIST is ignored - and the function definition becomes: - - (lambda () - (interactive) - (transient-setup 'NAME)) - - If BODY is specified, then it must begin with an ‘interactive’ form - that matches ARGLIST, and it must call ‘transient-setup’. It may - however call that function only when some condition is satisfied. - - All transients have a (possibly ‘nil’) value, which is exported - when suffix commands are called, so that they can consume that - value. For some transients it might be necessary to have a sort of - secondary value, called a "scope". Such a scope would usually be - set in the command’s ‘interactive’ form and has to be passed to the - setup function: - - (transient-setup 'NAME nil nil :scope SCOPE) - - For example, the scope of the ‘magit-branch-configure’ transient is - the branch whose variables are being configured. - - -File: transient.info, Node: Binding Suffix and Infix Commands, Next: Defining Suffix and Infix Commands, Prev: Defining Transients, Up: Defining New Commands - -5.2 Binding Suffix and Infix Commands -===================================== - -The macro ‘transient-define-prefix’ is used to define a transient. This -defines the actual transient prefix command (see *note Defining -Transients::) and adds the transient’s infix and suffix bindings, as -described below. - - Users and third-party packages can add additional bindings using -functions such as ‘transient-insert-suffix’ (See *note Modifying -Existing Transients::). These functions take a "suffix specification" -as one of their arguments, which has the same form as the specifications -used in ‘transient-define-prefix’. - -* Menu: - -* Group Specifications:: -* Suffix Specifications:: - - -File: transient.info, Node: Group Specifications, Next: Suffix Specifications, Up: Binding Suffix and Infix Commands - -5.2.1 Group Specifications --------------------------- - -The suffix and infix commands of a transient are organized in groups. -The grouping controls how the descriptions of the suffixes are outlined -visually but also makes it possible to set certain properties for a set -of suffixes. - - Several group classes exist, some of which organize suffixes in -subgroups. In most cases the class does not have to be specified -explicitly, but see *note Group Classes::. - - Groups are specified in the call to ‘transient-define-prefix’, using -vectors. Because groups are represented using vectors, we cannot use -square brackets to indicate an optional element and instead use curly -brackets to do the latter. - - Group specifications then have this form: - - [{LEVEL} {DESCRIPTION} {KEYWORD VALUE}... ELEMENT...] - - The LEVEL is optional and defaults to 4. See *note Enabling and -Disabling Suffixes::. - - The DESCRIPTION is optional. If present it is used as the heading of -the group. - - The KEYWORD-VALUE pairs are optional. Each keyword has to be a -keyword symbol, either ‘:class’ or a keyword argument supported by the -constructor of that class. - - • One of these keywords, ‘:description’, is equivalent to specifying - DESCRIPTION at the very beginning of the vector. The - recommendation is to use ‘:description’ if some other keyword is - also used, for consistency, or DESCRIPTION otherwise, because it - looks better. - - • Likewise ‘:level’ is equivalent to LEVEL. - - • Other important keywords include the ‘:if...’ keywords. These - keywords control whether the group is available in a certain - situation. - - For example, one group of the ‘magit-rebase’ transient uses ‘:if - magit-rebase-in-progress-p’, which contains the suffixes that are - useful while rebase is already in progress; and another that uses - ‘:if-not magit-rebase-in-progress-p’, which contains the suffixes - that initiate a rebase. - - These predicates can also be used on individual suffixes and are - only documented once, see *note Predicate Slots::. - - • Finally the value of ‘:hide’, if non-nil, is a predicate that - controls whether the group is hidden by default. The key bindings - for suffixes of a hidden group should all use the same prefix key. - Pressing that prefix key should temporarily show the group and its - suffixes, which assumes that a predicate like this is used: - - (lambda () - (eq (car transient--redisplay-key) - ?\C-c)) ; the prefix key shared by all bindings - - The ELEMENTs are either all subgroups (vectors), or all suffixes -(lists) and strings. (At least currently no group type exists that -would allow mixing subgroups with commands at the same level, though in -principle there is nothing that prevents that.) - - If the ELEMENTs are not subgroups, then they can be a mixture of -lists that specify commands and strings. Strings are inserted verbatim. -The empty string can be used to insert gaps between suffixes, which is -particularly useful if the suffixes are outlined as a table. - - 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 - -5.2.2 Suffix Specifications ---------------------------- - -A transient’s suffix and infix commands are bound when the transient -prefix command is defined using ‘transient-define-prefix’, see *note -Defining Transients::. The commands are organized into groups, see -*note Group Specifications::. Here we describe the form used to bind an -individual suffix command. - - The same form is also used when later binding additional commands -using functions such as ‘transient-insert-suffix’, see *note Modifying -Existing Transients::. - - Note that an infix is a special kind of suffix. Depending on context -"suffixes" means "suffixes (including infixes)" or "non-infix suffixes". -Here it means the former. - - Suffix specifications have this form: - - ([LEVEL] [KEY] [DESCRIPTION] COMMAND|ARGUMENT [KEYWORD VALUE]...) - - LEVEL, KEY and DESCRIPTION can also be specified using the KEYWORDs -‘:level’, ‘:key’ and ‘:description’. If the object that is associated -with COMMAND sets these properties, then they do not have to be -specified here. You can however specify them here anyway, possibly -overriding the object’s values just for the binding inside this -transient. - - • LEVEL is the suffix level, an integer between 1 and 7. See *note - Enabling and Disabling Suffixes::. - - • KEY is the key binding, either a vector or key description string. - - • DESCRIPTION is the description, either a string or a function that - returns a string. The function should be a lambda expression to - avoid ambiguity. In some cases a symbol that is bound as a - function would also work but to be safe you should use - ‘:description’ in that case. - - The next element is either a command or an argument. This is the -only argument that is mandatory in all cases. - - • COMMAND is a symbol that is bound as a function, which has to be a - command. Any command will do; it does not need to have an object - associated with it (as would be the case if - ‘transient-define-suffix’ or ‘transient-define-infix’ were used to - define it). - - As mentioned above, the object that is associated with a command - can be used to set the default for certain values that otherwise - have to be set in the suffix specification. Therefore if there is - no object, then you have to make sure to specify the KEY and the - DESCRIPTION. - - • The mandatory argument can also be a command-line argument, a - string. In that case an anonymous command is defined and bound. - - Instead of a string, this can also be a list of two strings, in - which case the first string is used as the short argument (which - can also be specified using ‘:shortarg’) and the second as the long - argument (which can also be specified using ‘:argument’). - - Only the long argument is displayed in the popup buffer. See - ‘transient-detect-key-conflicts’ for how the short argument may be - used. - - Unless the class is specified explicitly, the appropriate class is - guessed based on the long argument. If the argument ends with "=​" - (e.g. "–format=") then ‘transient-option’ is used, otherwise - ‘transient-switch’. - - Finally, details can be specified using optional KEYWORD-VALUE pairs. -Each keyword has to be a keyword symbol, either ‘:class’ or a keyword -argument supported by the constructor of that class. See *note Suffix -Slots::. - - -File: transient.info, Node: Defining Suffix and Infix Commands, Next: Using Infix Arguments, Prev: Binding Suffix and Infix Commands, Up: Defining New Commands - -5.3 Defining Suffix and Infix Commands -====================================== - -Note that an infix is a special kind of suffix. Depending on context -"suffixes" means "suffixes (including infixes)" or "non-infix suffixes". - - -- Macro: transient-define-suffix name arglist [docstring] [keyword - value]... body... - - This macro defines NAME as a transient suffix command. - - ARGLIST are the arguments that the command takes. DOCSTRING is the - documentation string and is optional. - - These arguments can optionally be followed by keyword-value pairs. - Each keyword has to be a keyword symbol, either ‘:class’ or a - keyword argument supported by the constructor of that class. The - ‘transient-suffix’ class is used if the class is not specified - explicitly. - - The BODY must begin with an ‘interactive’ form that matches - ARGLIST. The infix arguments are usually accessed by using - ‘transient-args’ inside ‘interactive’. - - -- Macro: transient-define-infix name arglist [docstring] [keyword - value]... - - This macro defines NAME as a transient infix command. - - ARGLIST is always ignored (but mandatory never-the-less) and - reserved for future use. DOCSTRING is the documentation string and - is optional. - - The keyword-value pairs are mandatory. All transient infix - commands are ‘equal’ to each other (but not ‘eq’), so it is - meaningless to define an infix command without also setting at - least ‘:class’ and one other keyword (which it is depends on the - used class, usually ‘:argument’ or ‘:variable’). - - Each keyword has to be a keyword symbol, either ‘:class’ or a - keyword argument supported by the constructor of that class. The - ‘transient-switch’ class is used if the class is not specified - explicitly. - - The function definition is always: - - (lambda () - (interactive) - (let ((obj (transient-suffix-object))) - (transient-infix-set obj (transient-infix-read obj))) - (transient--show)) - - ‘transient-infix-read’ and ‘transient-infix-set’ are generic - functions. Different infix commands behave differently because the - concrete methods are different for different infix command classes. - In rare cases the above command function might not be suitable, - even if you define your own infix command class. In that case you - have to use ‘transient-suffix-command’ to define the infix command - and use ‘t’ as the value of the ‘:transient’ keyword. - - -- Macro: transient-define-argument name arglist [docstring] [keyword - value]... - - This macro defines NAME as a transient infix command. - - This is an alias for ‘transient-define-infix’. Only use this alias - to define an infix command that actually sets an infix argument. - To define an infix command that, for example, sets a variable, use - ‘transient-define-infix’ instead. - - -File: transient.info, Node: Using Infix Arguments, Next: Transient State, Prev: Defining Suffix and Infix Commands, Up: Defining New Commands - -5.4 Using Infix Arguments -========================= - -The function and the variables described below allow suffix commands to -access the value of the transient from which they were invoked; which is -the value of its infix arguments. These variables are set when the user -invokes a suffix command that exits the transient, but before actually -calling the command. - - When returning to the command-loop after calling the suffix command, -the arguments are reset to ‘nil’ (which causes the function to return -‘nil’ too). - - Like for Emacs’ prefix arguments it is advisable, but not mandatory, -to access the infix arguments inside the command’s ‘interactive’ form. -The preferred way of doing that is to call the ‘transient-args’ -function, which for infix arguments serves about the same purpose as -‘prefix-arg’ serves for prefix arguments. - - -- Function: transient-args &optional prefix - - This function returns the value of the transient prefix command - PREFIX. - - If the current command was invoked from the transient prefix - command PREFIX, then it returns the active infix arguments. If the - current command was not invoked from PREFIX, then it returns the - set, saved or default value for PREFIX. - - -- Variable: transient-current-suffixes - - The suffixes of the transient from which this suffix command was - invoked. This is a list of objects. Usually it is sufficient to - instead use the function ‘transient-args’, which returns a list of - values. In complex cases it might be necessary to use this - variable instead, i.e. if you need access to information beside - the value. - - -- Variable: transient-current-prefix - - The transient from which this suffix command was invoked. The - returned value is a ‘transient-prefix’ object, which holds - information associated with the transient prefix command. - - -- Variable: transient-current-command - - The transient from which this suffix command was invoked. The - returned value is a symbol, the transient prefix command. - - -File: transient.info, Node: Transient State, Prev: Using Infix Arguments, Up: Defining New Commands - -5.5 Transient State -=================== - -Invoking a transient prefix command "activates" the respective -transient, i.e. it puts a transient keymap into effect, which binds the -transient’s infix and suffix commands. - - The default behavior while a transient is active is as follows: - - • Invoking an infix command does not affect the transient state; the - transient remains active. - - • Invoking a (non-infix) suffix command "deactivates" the transient - state by removing the transient keymap and performing some - additional cleanup. - - • Invoking a command that is bound in a keymap other than the - transient keymap is disallowed and trying to do so results in a - warning. This does not "deactivate" the transient. - - But these are just the defaults. Whether a certain command -deactivates or "exits" the transient is configurable. There is more -than one way in which a command can be "transient" or "non-transient"; -the exact behavior is implemented by calling a so-called "pre-command" -function. Whether non-suffix commands are allowed to be called is -configurable per transient. - - • The transient-ness of suffix commands (including infix commands) is - controlled by the value of their ‘transient’ slot, which can be set - either when defining the command or when adding a binding to a - transient while defining the respective transient prefix command. - - Valid values are booleans and the pre-commands described below. - - • ‘t’ is equivalent to ‘transient--do-stay’. - - • ‘nil’ is equivalent to ‘transient--do-exit’. - - • If ‘transient’ is unbound (and that is actually the default - for non-infix suffixes) then the value of the prefix’s - ‘transient-suffix’ slot is used instead. The default value of - that slot is ‘nil’, so the suffix’s ‘transient’ slot being - unbound is essentially equivalent to it being ‘nil’. - - • A suffix command can be a prefix command itself, i.e. a - "sub-prefix". While a sub-prefix is active we nearly always want - ‘C-g’ to take the user back to the "super-prefix". 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, as stated above, ‘nil’ - and the slot being unbound are 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. - - • The transient-ness of certain built-in suffix commands is specified - using ‘transient-predicate-map’. This is a special keymap, which - binds commands to pre-commands (as opposed to keys to commands) and - takes precedence over the ‘transient’ slot. - - The available pre-command functions are documented below. They are -called by ‘transient--pre-command’, a function on ‘pre-command-hook’ and -the value that they return determines whether the transient is exited. -To do so the value of one of the constants ‘transient--exit’ or -‘transient--stay’ is used (that way we don’t have to remember if ‘t’ -means "exit" or "stay"). - - Additionally these functions may change the value of ‘this-command’ -(which explains why they have to be called using ‘pre-command-hook’), -call ‘transient-export’, ‘transient--stack-zap’ or -‘transient--stack-push’; and set the values of ‘transient--exitp’, -‘transient--helpp’ or ‘transient--editp’. - -5.5.1 Pre-commands for Infixes ------------------------------- - -The default for infixes is ‘transient--do-stay’. This is also the only -function that makes sense for infixes. - - -- Function: transient--do-stay - - Call the command without exporting variables and stay transient. - -5.5.2 Pre-commands for Suffixes -------------------------------- - -The default for suffixes is ‘transient--do-exit’. - - -- Function: transient--do-exit - - Call the command after exporting variables and exit the transient. - - -- Function: transient--do-call - - Call the command after exporting variables and stay transient. - - -- Function: transient--do-replace - - Call the transient prefix command, replacing the active transient. - - This is used for suffixes that are prefixes themselves, i.e. for - sub-prefixes. - -5.5.3 Pre-commands for Non-Suffixes ------------------------------------ - -The default for non-suffixes, i.e commands that are bound in other -keymaps beside the transient keymap, is ‘transient--do-warn’. Silently -ignoring the user-error is also an option, though probably not a good -one. - - If you want to let the user invoke non-suffix commands, then use -‘transient--do-stay’ as the value of the prefix’s ‘transient-non-suffix’ -slot. - - -- Function: transient--do-warn - - Call ‘transient-undefined’ and stay transient. - - -- Function: transient--do-noop - - Call ‘transient-noop’ and stay transient. - -5.5.4 Special Pre-Commands --------------------------- - - -- Function: transient--do-quit-one - - If active, quit help or edit mode, else exit the active transient. - - This is used when the user pressed ‘C-g’. - - -- Function: transient--do-quit-all - - Exit all transients without saving the transient stack. - - This is used when the user pressed ‘C-q’. - - -- Function: transient--do-suspend - - Suspend the active transient, saving the transient stack. - - This is used when the user pressed ‘C-z’. - - -File: transient.info, Node: Classes and Methods, Next: Related Abstractions and Packages, Prev: Defining New Commands, Up: Top - -6 Classes and Methods -********************* - -Transient uses classes and generic functions to make it possible to -define new types of suffix commands that are similar to existing types, -but behave differently in some aspects. It does the same for groups and -prefix commands, though at least for prefix commands that *currently* -appears to be less important. - - Every prefix, infix and suffix command is associated with an object, -which holds information that controls certain aspects of its behavior. -This happens in two ways. - - • Associating a command with a certain class gives the command a - type. This makes it possible to use generic functions to do - certain things that have to be done differently depending on what - type of command it acts on. - - That in turn makes it possible for third-parties to add new types - without having to convince the maintainer of Transient that that - new type is important enough to justify adding a special case to a - dozen or so functions. - - • Associating a command with an object makes it possible to easily - store information that is specific to that particular command. - - Two commands may have the same type, but obviously their key - bindings and descriptions still have to be different, for example. - - The values of some slots are functions. The ‘reader’ slot for - example holds a function that is used to read a new value for an - infix command. The values of such slots are regular functions. - - Generic functions are used when a function should do something - different based on the type of the command, i.e. when all commands - of a certain type should behave the same way but different from the - behavior for other types. Object slots that hold a regular - function as value are used when the task that they perform is - likely to differ even between different commands of the same type. - -* Menu: - -* Group Classes:: -* Group Methods:: -* Prefix Classes:: -* Suffix Classes:: -* Suffix Methods:: -* Prefix Slots:: -* Suffix Slots:: -* Predicate Slots:: - - -File: transient.info, Node: Group Classes, Next: Group Methods, Up: Classes and Methods - -6.1 Group Classes -================= - -The type of a group can be specified using the ‘:class’ property at the -beginning of the class specification, e.g. ‘[:class transient-columns -...]’ in a call to ‘transient-define-prefix’. - - • The abstract ‘transient-child’ class is the base class of both - ‘transient-group’ (and therefore all groups) as well as of - ‘transient-suffix’ (and therefore all suffix and infix commands). - - This class exists because the elements (aka "children") of certain - groups can be other groups instead of suffix and infix commands. - - • The abstract ‘transient-group’ class is the superclass of all other - group classes. - - • The ‘transient-column’ class is the simplest group. - - This is the default "flat" group. If the class is not specified - explicitly and the first element is not a vector (i.e. not a - group), then this class is used. - - This class displays each element on a separate line. - - • The ‘transient-row’ class displays all elements on a single line. - - • The ‘transient-columns’ class displays commands organized in - columns. - - Direct elements have to be groups whose elements have to be - commands or strings. Each subgroup represents a column. This - class takes care of inserting the subgroups’ elements. - - This is the default "nested" group. If the class is not specified - explicitly and the first element is a vector (i.e. a group), then - this class is used. - - • The ‘transient-subgroups’ class wraps other groups. - - Direct elements have to be groups whose elements have to be - commands or strings. This group inserts an empty line between - subgroups. The subgroups themselves are responsible for displaying - their elements. - - -File: transient.info, Node: Group Methods, Next: Prefix Classes, Prev: Group Classes, Up: Classes and Methods - -6.2 Group Methods -================= - - -- Function: transient--insert-group 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. - - 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 - temporarily make the ‘transient--source-buffer’ the current buffer. - - -File: transient.info, Node: Prefix Classes, Next: Suffix Classes, Prev: Group Methods, Up: Classes and Methods - -6.3 Prefix Classes -================== - -Currently the ‘transient-prefix’ class is being used for all prefix -commands and there is only a single generic function that can be -specialized based on the class of a prefix command. - - -- Function: transient--history-init obj - - This generic function is called while setting up the transient and - is responsible for initializing the ‘history’ slot. This is the - transient-wide history; many individual infixes also have a history - of their own. - - The default (and currently only) method extracts the value from the - global variable ‘transient-history’. - - A transient prefix command’s object is stored in the -‘transient--prefix’ property of the command symbol. While a transient -is active, a clone of that object is stored in the variable -‘transient--prefix’. A clone is used because some changes that are made -to the active transient’s object should not affect later invocations. - - -File: transient.info, Node: Suffix Classes, Next: Suffix Methods, Prev: Prefix Classes, Up: Classes and Methods - -6.4 Suffix Classes -================== - - • All suffix and infix classes derive from ‘transient-suffix’, which - in turn derives from ‘transient-child’, from which - ‘transient-group’ also derives (see *note Group Classes::). - - • All infix classes derive from the abstract ‘transient-infix’ class, - which in turn derives from the ‘transient-suffix’ class. - - Infixes are a special type of suffixes. The primary difference is - that infixes always use the ‘transient--do-stay’ pre-command, while - non-infix suffixes use a variety of pre-commands (see *note - Transient State::). Doing that is most easily achieved by using - this class, though theoretically it would be possible to define an - infix class that does not do so. If you do that then you get to - implement many methods. - - Also, infixes and non-infix suffixes are usually defined using - different macros (see *note Defining Suffix and Infix Commands::). - - • Classes used for infix commands that represent arguments should be - derived from the abstract ‘transient-argument’ class. - - • The ‘transient-switch’ class (or a derived class) is used for infix - arguments that represent command-line switches (arguments that do - not take a value). - - • The ‘transient-option’ class (or a derived class) is used for infix - arguments that represent command-line options (arguments that do - take a value). - - • The ‘transient-switches’ class can be used for a set of mutually - exclusive command-line switches. - - • The ‘transient-files’ class can be used for a "–" argument that - indicates that all remaining arguments are files. - - • Classes used for infix commands that represent variables should - derived from the abstract ‘transient-variables’ class. - - Magit defines additional classes, which can serve as examples for the -fancy things you can do without modifying Transient. Some of these -classes will likely get generalized and added to Transient. For now -they are very much subject to change and not documented. - - -File: transient.info, Node: Suffix Methods, Next: Prefix Slots, Prev: Suffix Classes, Up: Classes and Methods - -6.5 Suffix Methods -================== - -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 - -6.5.1 Suffix Value Methods --------------------------- - - -- Function: transient-init-value obj - - This generic function sets the initial value of the object OBJ. - - This function is called for all suffix commands, but unless a - concrete method is implemented this falls through to the default - implementation, which is a noop. In other words this usually only - does something for infix commands, but note that this is not - implemented for the abstract class ‘transient-infix’, so if your - class derives from that directly, then you must implement a method. - - -- Function: transient-infix-read obj - - This generic function determines the new value of the infix object - OBJ. - - This function merely determines the value; ‘transient-infix-set’ is - used to actually store the new value in the object. - - For most infix classes this is done by reading a value from the - user using the reader specified by the ‘reader’ slot (using the - ‘transient-infix-value’ method described below). - - For some infix classes the value is changed without reading - anything in the minibuffer, i.e. the mere act of invoking the - infix command determines what the new value should be, based on the - previous value. - - -- Function: transient-prompt obj - - This generic function returns the prompt to be used to read infix - object OBJ’s value. - - -- Function: transient-infix-set obj value - - This generic function sets the value of infix object OBJ to VALUE. - - -- Function: transient-infix-value obj - - This generic function returns the value of the suffix object OBJ. - - This function is called by ‘transient-args’ (which see), meaning - this function is how the value of a transient is determined so that - the invoked suffix command can use it. - - Currently most values are strings, but that is not set in stone. - ‘nil’ is not a value, it means "no value". - - Usually only infixes have a value, but see the method for - ‘transient-suffix’. - - -- Function: transient-init-scope obj - - This generic function sets the scope of the suffix object OBJ. - - The scope is actually a property of the transient prefix, not of - individual suffixes. However it is possible to invoke a suffix - command directly instead of from a transient. In that case, if the - suffix expects a scope, then it has to determine that itself and - store it in its ‘scope’ slot. - - This function is called for all suffix commands, but 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 - -6.5.2 Suffix Format Methods ---------------------------- - - -- Function: transient-format obj - - This generic function formats and returns OBJ for display. - - When this function is called, then the current buffer is some - temporary buffer. If you need the buffer from which the prefix - command was invoked to be current, then do so by temporarily making - ‘transient--source-buffer’ current. - - -- Function: transient-format-key obj - - This generic function formats OBJ’s ‘key’ for display and returns - the result. - - -- Function: transient-format-description obj - - This generic function formats OBJ’s ‘description’ for display and - returns the result. - - -- Function: transient-format-value obj - - This generic function formats OBJ’s value for display and returns - the result. - - -- Function: transient-show-help obj - - Show help for the prefix, infix or suffix command represented by - OBJ. - - For prefixes, show the info manual, if that is specified using the - ‘info-manual’ slot. Otherwise show the manpage if that is - specified using the ‘man-page’ slot. Otherwise show the command’s - doc string. - - For suffixes, show the command’s doc string. - - For infixes, show the manpage if that is specified. Otherwise show - the command’s doc string. - - -File: transient.info, Node: Prefix Slots, Next: Suffix Slots, Prev: Suffix Methods, Up: Classes and Methods - -6.6 Prefix Slots -================ - - • ‘man-page’ or ‘info-manual’ can be used to specify the - documentation for the prefix and its suffixes. The command - ‘transient-help’ uses the method ‘transient-show-help’ (which see) - to lookup and use these values. - - • ‘history-key’ If multiple prefix commands should share a single - value, then this slot has to be set to the same value for all of - them. You probably don’t want that. - - • ‘transient-suffix’ and ‘transient-non-suffix’ play a part when - determining whether the currently active transient prefix command - remains active/transient when a suffix or abitrary non-suffix - command is invoked. See *note Transient State::. - - • ‘incompatible’ A list of lists. Each sub-list specifies a set of - mutually exclusive arguments. Enabling one of these arguments - causes the others to be disabled. - - • ‘scope’ For some transients it might be necessary to have a sort of - secondary value, called a "scope". See ‘transient-define-prefix’. - -6.6.1 Internal Prefix Slots ---------------------------- - -These slots are mostly intended for internal use. They should not be -set in calls to ‘transient-define-prefix’. - - • ‘prototype’ When a transient prefix command is invoked, then a - clone of that object is stored in the global variable - ‘transient--prefix’ and the prototype is stored in the clone’s - ‘prototype’ slot. - - • ‘command’ The command, a symbol. Each transient prefix command - consists of a command, which is stored in a symbol’s function slot - and an object, which is stored in the ‘transient--prefix’ property - of the same symbol. - - • ‘level’ The level of the prefix commands. The suffix commands - whose layer is equal or lower are displayed. See *note Enabling - and Disabling Suffixes::. - - • ‘value’ The likely outdated value of the prefix. Instead of - accessing this slot directly you should use the function - ‘transient-get-value’, which is guaranteed to return the up-to-date - value. - - • ‘history’ and ‘history-pos’ are used to keep track of historic - values. Unless you implement your own ‘transient-infix-read’ - method you should not have to deal with these slots. - - -File: transient.info, Node: Suffix Slots, Next: Predicate Slots, Prev: Prefix Slots, Up: Classes and Methods - -6.7 Suffix Slots -================ - -Here we document most of the slots that are only available for suffix -objects. Some slots are shared by suffix and group objects, they are -documented in *note Predicate Slots::. - - Also see *note Suffix Classes::. - -6.7.1 Slots of ‘transient-suffix’ ---------------------------------- - - • ‘key’ The key, a key vector or a key description string. - - • ‘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. - It must contain the following %-placeholders: - - • ‘%k’ For the key. - - • ‘%d’ For the description. - - • ‘%v’ For the infix value. Non-infix suffixes don’t have a - value. - - • ‘description’ The description, either a string or a function that - is called with no argument and returns a string. - -6.7.2 Slots of ‘transient-infix’ --------------------------------- - -Some of these slots are only meaningful for some of the subclasses. -They are defined here anyway to allow sharing certain methods. - - • ‘argument’ The long argument, e.g. ‘--verbose’. - - • ‘shortarg’ The short argument, e.g. ‘-v’. - - • ‘multi-value’ For options, whether the option can have multiple - values. If non-nil, then default to use - ‘completing-read-multiple’. - - • ‘allow-empty’ For options, whether the empty string is a valid - value. - - • ‘history-key’ The key used to store the history. This defaults to - the command name. This is useful when multiple infixes should - share the same history because their values are of the same kind. - - • ‘reader’ The function used to read the value of an infix. Not used - for switches. The function takes three arguments, PROMPT, - INITIAL-INPUT and HISTORY, and must return a string. - - • ‘prompt’ The prompt used when reading the value, either a string or - a function that takes the object as the only argument and which - returns a prompt string. - - • ‘choices’ A list of valid values. How exactly that is used depends - on the class of the object. - -6.7.3 Slots of ‘transient-variable’ ------------------------------------ - - • ‘variable’ The variable. - -6.7.4 Slots of ‘transient-switches’ ------------------------------------ - - • ‘argument-format’ The display format. Must contain ‘%s’, one of - the ‘choices’ is substituted for that. E.g. ‘--%s-order’. - - • ‘argument-regexp’ The regexp used to match any one of the switches. - E.g. ‘\\(--\\(topo\\|author-date\\|date\\)-order\\)’. - - -File: transient.info, Node: Predicate Slots, Prev: Suffix Slots, Up: Classes and Methods - -6.8 Predicate Slots -=================== - -Suffix and group objects share some predicate slots that control whether -a group or suffix should be available depending on some state. Only one -of these slots can be used at the same time. It is undefined what -happens if you use more than one. - - • ‘if’ Enable if predicate returns non-nil. - - • ‘if-not’ Enable if predicate returns nil. - - • ‘if-non-nil’ Enable if variable’s value is non-nil. - - • ‘if-nil’ Enable if variable’s value is nil. - - • ‘if-mode’ Enable if major-mode matches value. - - • ‘if-not-mode’ Enable if major-mode does not match value. - - • ‘if-derived’ Enable if major-mode derives from value. - - • ‘if-not-derived’ Enable if major-mode does not derive from value. - - One more slot is shared between group and suffix classes, ‘level’. -Like the slots documented above, it is a predicate, but it is used for a -different purpose. The value has to be an integer between 1 and 7. -‘level’ controls whether a suffix or a group should be available -depending on user preference. See *note Enabling and Disabling -Suffixes::. - - -File: transient.info, Node: Related Abstractions and Packages, Next: FAQ, Prev: Classes and Methods, Up: Top - -7 Related Abstractions and Packages -*********************************** - -* Menu: - -* Comparison With Prefix Keys and Prefix Arguments:: -* Comparison With Other Packages:: - - -File: transient.info, Node: Comparison With Prefix Keys and Prefix Arguments, Next: Comparison With Other Packages, Up: Related Abstractions and Packages - -7.1 Comparison With Prefix Keys and Prefix Arguments -==================================================== - -While transient commands were inspired by regular prefix keys and prefix -arguments, they are also quite different and much more complex. - - The following diagrams illustrate some of the differences. - - • ‘(c)’ represents a return to the command loop. - - • ‘(+)’ represents the user’s choice to press one key or another. - - • ‘{WORD}’ are possible behaviors. - - • ‘{NUMBER}’ is a footnote. - -7.1.1 Regular Prefix Commands ------------------------------ - -See *note (elisp)Prefix Keys::. - - ,--> command1 --> (c) - | - (c)-(+)-> prefix command or key --+--> command2 --> (c) - | - `--> command3 --> (c) - -7.1.2 Regular Prefix Arguments ------------------------------- - -See *note (elisp)Prefix Command Arguments::. - - ,----------------------------------, - | | - v | - (c)-(+)---> prefix argument command --(c)-(+)-> any command --> (c) - | ^ | - | | | - `-- sets or changes --, ,-- maybe used --' | - | | | - v | | - prefix argument state | - ^ | - | | - `-------- discards --------' - -7.1.3 Transients ----------------- - -(∩`-´)⊃━☆゚.*・。゚ - - This diagram ignores the infix value and external state: - - (c) - | ,- {stay} ------<-,-<------------<-,-<---, - (+) | | | | - | | | | | - | | ,--> infix1 --| | | - | | | | | | - | | |--> infix2 --| | | - v v | | | | - prefix -(c)-(+)-> infix3 --' ^ | - | | | - |---------------> suffix1 -->--| | - | | | - |---------------> suffix2 ----{1}------> {exit} --> (c) - | | - |---------------> suffix3 -------------> {exit} --> (c) - | | - `--> any command --{2}-> {warn} -->--| - | | - |--> {noop} -->--| - | | - |--> {call} -->--' - | - `------------------> {exit} --> (c) - - This diagram takes the infix value into account to an extend, while -still ignoring external state: - - (c) - | ,- {stay} ------<-,-<------------<-,-<---, - (+) | | | | - | | | | | - | | ,--> infix1 --| | | - | | | | | | | - | | ,--> infix2 --| | | - v v | | | | | - prefix -(c)-(+)-> infix3 --' | | - | | ^ | - | | | | - |---------------> suffix1 -->--| | - | | ^ | | - | | | | | - |---------------> suffix2 ----{1}------> {exit} --> (c) - | | ^ | | - | | | | v - | | | | | - |---------------> suffix3 -------------> {exit} --> (c) - | | ^ | | - | sets | | v - | | maybe | | - | | used | | - | | | | | - | | infix --' | | - | `---> value | | - | ^ | | - | | | | - | hides | | - | | | | - | `--------------------------<---| - | | | - `--> any command --{2}-> {warn} -->--| | - | | | - |--> {noop} -->--| | - | | | - |--> {call} -->--' ^ - | | - `------------------> {exit} --> (c) - - This diagram provides more information about the infix value and also -takes external state into account. - - ,----sets--- "anything" - | - v - ,---------> external - | state - | | | - | initialized | ☉‿⚆ - sets from | - | | maybe - | ,----------' used - | | | - (c) | | v - | ,- {stay} --|---<-,-<------|-----<-,-<---, - (+) | | | | | | | - | | | v | | | | - | | ,--> infix1 --| | | | - | | | | | | | | | - | | | | v | | | | - | | ,--> infix2 --| | | | - | | | | ^ | | | | - v v | | | | | | | - prefix -(c)-(+)-> infix3 --' | | | - | | ^ | ^ | - | | | v | | - |---------------> suffix1 -->--| | - | | | ^ | | | - | | | | v | | - |---------------> suffix2 ----{1}------> {exit} --> (c) - | | | ^ | | | - | | | | | | v - | | | | v | | - |---------------> suffix3 -------------> {exit} --> (c) - | | | ^ | | - | sets | | | v - | | initialized maybe | | - | | from used | | - | | | | | | - | | `-- infix ---' | | - | `---> value -----------------------------> persistent - | ^ ^ | | across - | | | | | invocations -, - | hides | | | | - | | `----------------------------------------------' - | | | | - | `--------------------------<---| - | | | - `--> any command --{2}-> {warn} -->--| | - | | | - |--> {noop} -->--| | - | | | - |--> {call} -->--' ^ - | | - `------------------> {exit} --> (c) - - • ‘{1}’ Transients can be configured to be exited when a suffix - command is invoked. The default is to do so for all suffixes - except for those that are common to all transients and which are - used to perform tasks such as providing help and saving the value - of the infix arguments for future invocations. The behavior can - also be specified for individual suffix commands and may even - depend on state. - - • ‘{2}’ Transients can be configured to allow the user to invoke - non-suffix commands. The default is to not allow that and instead - warn the user. - - Despite already being rather complex, even the last diagram leaves -out many details. Most importantly it implies that the decision whether -to remain transient is made later than it actually is made (for the most -part a function on ‘pre-command-hook’ is responsible). But such -implementation details are of little relevance to users and are covered -elsewhere. - - -File: transient.info, Node: Comparison With Other Packages, Prev: Comparison With Prefix Keys and Prefix Arguments, Up: Related Abstractions and Packages - -7.2 Comparison With Other Packages -================================== - -7.2.1 Magit-Popup ------------------ - -Transient is the successor to Magit-Popup (see *note -(magit-popup)Top::). - - One major difference between these two implementations of the same -ideas is that while Transient uses transient keymaps and embraces the -command-loop, Magit-Popup implemented an inferior mechanism that does -not use transient keymaps and that instead of using the command-loop -implements a naive alternative based on ‘read-char’. - - Magit-Popup does not use classes and generic functions and defining a -new command type is near impossible as it involves adding hard-coded -special-cases to many functions. Because of that only a single new type -was added, which was not already part of Magit-Popup’s initial release. - - A lot of things are hard-coded in Magit-Popup. One random example is -that the key bindings for switches must begin with "-" and those for -options must begin with "=". - -7.2.2 Hydra ------------ - -Hydra (see ) is another package that -provides features similar to those of Transient. - - Both packages use transient keymaps to make a set of commands -temporarily available and show the available commands in a popup buffer. - - A Hydra "body" is equivalent to a Transient "prefix" and a Hydra -"head" is equivalent to a Transient "suffix". Hydra has no equivalent -of a Transient "infix". - - Both hydras and transients can be used as simple command dispatchers. -Used like this they are similar to regular prefix commands and prefix -keys, except that the available commands are shown in the popup buffer. - - (Another package that does this is ‘which-key’. It does so -automatically for any incomplete key sequence. The advantage of that -approach is that no additional work is necessary; the disadvantage is -that the available commands are not organized semantically.) - - Both Hydra and Transient provide features that go beyond simple -command dispatchers: - - • Invoking a command from a hydra does not necessarily exit the - hydra. That makes it possible to invoke the same command again, - but using a shorter key sequence (i.e. the key that was used to - enter the hydra does not have to be pressed again). - - Transient supports that too, but for now this feature is not a - focus and the interface is a bit more complicated. A very basic - example using the current interface: - - (transient-define-prefix outline-navigate () - :transient-suffix 'transient--do-stay - :transient-non-suffix 'transient--do-warn - [("p" "previous visible heading" outline-previous-visible-heading) - ("n" "next visible heading" outline-next-visible-heading)]) - - • Transient supports infix arguments; values that are set by infix - commands and then consumed by the invoked suffix command(s). - - To my knowledge, Hydra does not support that. - - Both packages make it possible to specify how exactly the available -commands are outlined: - - • With Hydra this is often done using an explicit format string, - which gives authors a lot of flexibility and makes it possible to - do fancy things. - - The downside of this is that it becomes harder for a user to add - additional commands to an existing hydra and to change key - bindings. - - • Transient allows the author of a transient to organize the commands - into groups and the use of generic functions allows authors of - transients to control exactly how a certain command type is - displayed. - - However while Transient supports giving sections a heading it does - not currently support giving the displayed information more - structure by, for example, using box-drawing characters. - - That could be implemented by defining a new group class, which lets - the author specify a format string. It should be possible to - implement that without modifying any existing code, but it does not - currently exist. - - -File: transient.info, Node: FAQ, Next: Keystroke Index, Prev: Related Abstractions and Packages, Up: Top - -Appendix A FAQ -************** - -A.1 Can I control how the popup buffer is displayed? -==================================================== - -Yes, see ‘transient-display-buffer-action’ in *note Other Options::. - -A.2 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 ‘C-x ...’ bindings 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. - - (Also see the next question.) - -A.3 Why does ‘q’ not quit popups anymore? -========================================= - -I agree that ‘q’ is a good binding for commands that quit something. -This includes quitting whatever transient is currently active, but it -also includes quitting whatever it is that some specific transient is -controlling. The transient ‘magit-blame’ for example binds ‘q’ to the -command that turns ‘magit-blame-mode’ off. - - So I had to decide if ‘q’ should quit the active transient (like -Magit-Popup used to) or whether ‘C-g’ should do that instead, so that -‘q’ could be bound in individual transient to whatever commands make -sense for them. Because all other letters are already reserved for use -by individual transients, I have decided to no longer make an exception -for ‘q’. - - If you want to get ‘q’’s old binding back then you can do so. Doing -that is a bit more complicated than changing a single key binding, so I -have implemented a function, ‘transient-bind-q-to-quit’ that makes the -necessary changes. See its doc string for more information. - - -File: transient.info, Node: Keystroke Index, Next: Command Index, Prev: FAQ, Up: Top - -Appendix B Keystroke Index -************************** - -[index] -* Menu: - -* C-g: Aborting and Resuming Transients. - (line 25) -* C-g <1>: Aborting and Resuming Transients. - (line 26) -* C-h: Getting Help for Suffix Commands. - (line 10) -* C-q: Aborting and Resuming Transients. - (line 36) -* C-x C-s: Saving Values. (line 25) -* C-x l: Enabling and Disabling Suffixes. - (line 49) -* C-x s: Saving Values. (line 20) -* C-x t: Common Suffix Commands. - (line 16) -* C-z: Aborting and Resuming Transients. - (line 42) -* M-n: Using History. (line 16) -* M-p: Using History. (line 11) -* M-x transient-resume: Aborting and Resuming Transients. - (line 55) - - -File: transient.info, Node: Command Index, Next: Function Index, Prev: Keystroke Index, Up: Top - -Appendix C Command Index -************************ - -[index] -* Menu: - -* transient-help: Getting Help for Suffix Commands. - (line 10) -* transient-history-next: Using History. (line 16) -* transient-history-prev: Using History. (line 11) -* transient-quit-all: Aborting and Resuming Transients. - (line 36) -* transient-quit-one: Aborting and Resuming Transients. - (line 26) -* transient-quit-seq: Aborting and Resuming Transients. - (line 25) -* transient-resume: Aborting and Resuming Transients. - (line 55) -* transient-save: Saving Values. (line 25) -* transient-scroll-down arg: Other Commands. (line 18) -* transient-scroll-up arg: Other Commands. (line 12) -* transient-set: Saving Values. (line 20) -* transient-set-level: Enabling and Disabling Suffixes. - (line 49) -* transient-suspend: Aborting and Resuming Transients. - (line 42) -* transient-toggle-common: Common Suffix Commands. - (line 16) - - -File: transient.info, Node: Function Index, Next: Variable Index, Prev: Command Index, Up: Top - -Appendix D Function Index -************************* - -[index] -* Menu: - -* transient--do-call: Transient State. (line 98) -* transient--do-exit: Transient State. (line 94) -* transient--do-noop: Transient State. (line 125) -* transient--do-quit-all: Transient State. (line 138) -* transient--do-quit-one: Transient State. (line 132) -* transient--do-replace: Transient State. (line 102) -* transient--do-stay: Transient State. (line 85) -* transient--do-suspend: Transient State. (line 144) -* transient--do-warn: Transient State. (line 121) -* transient--history-init: Prefix Classes. (line 10) -* transient--insert-group: Group Methods. (line 6) -* transient-append-suffix: Modifying Existing Transients. - (line 47) -* transient-args: Using Infix Arguments. - (line 22) -* transient-define-argument: Defining Suffix and Infix Commands. - (line 63) -* transient-define-infix: Defining Suffix and Infix Commands. - (line 27) -* 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 20) -* transient-format-key: Suffix Format Methods. - (line 15) -* transient-format-value: Suffix Format Methods. - (line 25) -* transient-get-suffix: Modifying Existing Transients. - (line 60) -* transient-infix-read: Suffix Value Methods. - (line 17) -* transient-infix-set: Suffix Value Methods. - (line 39) -* transient-infix-value: Suffix Value Methods. - (line 43) -* transient-init-scope: Suffix Value Methods. - (line 57) -* transient-init-value: Suffix Value Methods. - (line 6) -* transient-insert-suffix: Modifying Existing Transients. - (line 42) -* transient-prompt: Suffix Value Methods. - (line 34) -* transient-remove-suffix: Modifying Existing Transients. - (line 56) -* transient-replace-suffix: Modifying Existing Transients. - (line 51) -* transient-scroll-down: Other Commands. (line 18) -* transient-scroll-up: Other Commands. (line 12) -* transient-show-help: Suffix Format Methods. - (line 30) -* transient-suffix-put: Modifying Existing Transients. - (line 65) - - -File: transient.info, Node: Variable Index, Prev: Function Index, Up: Top - -Appendix E Variable Index -************************* - -[index] -* Menu: - -* transient-current-command: Using Infix Arguments. - (line 47) -* transient-current-prefix: Using Infix Arguments. - (line 41) -* transient-current-suffixes: Using Infix Arguments. - (line 32) -* transient-default-level: Enabling and Disabling Suffixes. - (line 38) -* transient-detect-key-conflicts: Other Options. (line 137) -* transient-display-buffer-action: Other Options. (line 46) -* transient-enable-popup-navigation: Other Options. (line 28) -* transient-force-fixed-pitch: Other Options. (line 151) -* transient-highlight-mismatched-keys: Other Options. (line 96) -* transient-history-file: Using History. (line 33) -* transient-history-limit: Using History. (line 38) -* transient-levels-file: Enabling and Disabling Suffixes. - (line 44) -* transient-mode-line-format: Other Options. (line 71) -* transient-read-with-initial-input: Other Options. (line 88) -* transient-show-common-commands: Common Suffix Commands. - (line 23) -* transient-show-popup: Other Options. (line 6) -* transient-substitute-key-function: Other Options. (line 115) -* transient-values-file: Saving Values. (line 30) - - - -Tag Table: -Node: Top751 -Node: Introduction3673 -Node: Usage9460 -Node: Invoking Transients9794 -Node: Aborting and Resuming Transients10826 -Node: Common Suffix Commands13485 -Node: Saving Values15239 -Ref: Saving Values-Footnote-116497 -Node: Using History16767 -Node: Getting Help for Suffix Commands18308 -Node: Enabling and Disabling Suffixes19701 -Node: Other Commands22991 -Node: Other Options23947 -Node: Modifying Existing Transients31071 -Node: Defining New Commands34473 -Node: Defining Transients34809 -Node: Binding Suffix and Infix Commands37240 -Node: Group Specifications38094 -Node: Suffix Specifications41426 -Node: Defining Suffix and Infix Commands45001 -Node: Using Infix Arguments48199 -Node: Transient State50419 -Node: Classes and Methods56292 -Node: Group Classes58506 -Node: Group Methods60422 -Node: Prefix Classes61068 -Node: Suffix Classes62160 -Node: Suffix Methods64404 -Node: Suffix Value Methods64725 -Node: Suffix Format Methods67485 -Node: Prefix Slots68937 -Node: Suffix Slots71412 -Node: Predicate Slots74263 -Node: Related Abstractions and Packages75511 -Node: Comparison With Prefix Keys and Prefix Arguments75798 -Node: Comparison With Other Packages86110 -Node: FAQ90300 -Node: Keystroke Index94034 -Node: Command Index95668 -Node: Function Index97455 -Node: Variable Index101612 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: -- cgit v1.2.3