diff options
Diffstat (limited to 'lisp/repeat.el')
-rw-r--r-- | lisp/repeat.el | 131 |
1 files changed, 95 insertions, 36 deletions
diff --git a/lisp/repeat.el b/lisp/repeat.el index a2b04b81b03..b7118cc7f95 100644 --- a/lisp/repeat.el +++ b/lisp/repeat.el @@ -342,6 +342,34 @@ For example, you can set it to <return> like `isearch-exit'." :group 'convenience :version "28.1") +(defcustom repeat-keep-prefix t + "Keep the prefix arg of the previous command." + :type 'boolean + :group 'convenience + :version "28.1") + +(defcustom repeat-echo-function #'repeat-echo-message + "Function to display a hint about available keys. +Function is called after every repeatable command with one argument: +a repeating map, or nil after deactivating the repeat mode." + :type '(choice (const :tag "Show hints in the echo area" + repeat-echo-message) + (const :tag "Show indicator in the mode line" + repeat-echo-mode-line) + (const :tag "No visual feedback" ignore) + (function :tag "Function")) + :group 'convenience + :version "28.1") + +(defvar repeat-in-progress nil + "Non-nil when the repeating map is active.") + +;;;###autoload +(defvar repeat-map nil + "The value of the repeating map for the next command. +A command called from the map can set it again to the same map when +the map can't be set on the command symbol property `repeat-map'.") + ;;;###autoload (define-minor-mode repeat-mode "Toggle Repeat mode. @@ -363,42 +391,73 @@ When Repeat mode is enabled, and the command symbol has the property named (defun repeat-post-hook () "Function run after commands to set transient keymap for repeatable keys." - (when repeat-mode - (let ((repeat-map (and (symbolp this-command) - (get this-command 'repeat-map)))) - (when repeat-map - (when (boundp repeat-map) - (setq repeat-map (symbol-value repeat-map))) - (let ((map (copy-keymap repeat-map)) - keys mess) - (map-keymap (lambda (key _) (push key keys)) map) - - ;; Exit when the last char is not among repeatable keys, - ;; so e.g. `C-x u u' repeats undo, whereas `C-/ u' doesn't. - (when (or (memq last-command-event keys) - (memq this-original-command '(universal-argument - universal-argument-more - digit-argument - negative-argument))) - ;; Messaging - (setq mess (format-message - "Repeat with %s%s" - (mapconcat (lambda (key) - (key-description (vector key))) - keys ", ") - (if repeat-exit-key - (format ", or exit with %s" - (key-description repeat-exit-key)) - ""))) - (if (current-message) - (message "%s [%s]" (current-message) mess) - (message mess)) - - ;; Adding an exit key - (when repeat-exit-key - (define-key map repeat-exit-key 'ignore)) - - (set-transient-map map))))))) + (let ((was-in-progress repeat-in-progress)) + (setq repeat-in-progress nil) + (when repeat-mode + (let ((rep-map (or repeat-map + (and (symbolp real-this-command) + (get real-this-command 'repeat-map))))) + (when rep-map + (when (boundp rep-map) + (setq rep-map (symbol-value rep-map))) + (let ((map (copy-keymap rep-map))) + + ;; Exit when the last char is not among repeatable keys, + ;; so e.g. `C-x u u' repeats undo, whereas `C-/ u' doesn't. + (when (and (zerop (minibuffer-depth)) ; avoid remapping in prompts + (or (lookup-key map (this-command-keys-vector)) + prefix-arg)) + + ;; Messaging + (unless prefix-arg + (funcall repeat-echo-function map)) + + ;; Adding an exit key + (when repeat-exit-key + (define-key map repeat-exit-key 'ignore)) + + (when (and repeat-keep-prefix (not prefix-arg)) + (setq prefix-arg current-prefix-arg)) + + (setq repeat-in-progress t) + (set-transient-map map)))))) + + (setq repeat-map nil) + (when (and was-in-progress (not repeat-in-progress)) + (funcall repeat-echo-function nil)))) + +(defun repeat-echo-message-string (map) + "Return a string with a list of repeating keys." + (let (keys) + (map-keymap (lambda (key _) (push key keys)) map) + (format-message "Repeat with %s%s" + (mapconcat (lambda (key) + (key-description (vector key))) + keys ", ") + (if repeat-exit-key + (format ", or exit with %s" + (key-description repeat-exit-key)) + "")))) + +(defun repeat-echo-message (map) + "Display available repeating keys in the echo area." + (when map + (let ((mess (repeat-echo-message-string map))) + (if (current-message) + (message "%s [%s]" (current-message) mess) + (message mess))))) + +(defvar repeat-echo-mode-line-string + (propertize "[Repeating...] " 'face 'mode-line-emphasis) + "String displayed in the mode line in repeating mode.") + +(defun repeat-echo-mode-line (map) + "Display the repeat indicator in the mode line." + (if map + (unless (assq 'repeat-in-progress mode-line-modes) + (add-to-list 'mode-line-modes (list 'repeat-in-progress + repeat-echo-mode-line-string))) + (force-mode-line-update t))) (provide 'repeat) |