Function: set-transient-map
set-transient-map is a byte-compiled function defined in subr.el.gz.
Signature
(set-transient-map MAP &optional KEEP-PRED ON-EXIT MESSAGE TIMEOUT)
Documentation
Set MAP as a temporary keymap taking precedence over other keymaps.
Normally, MAP is used only once, to look up the very next key.
However, if the optional argument KEEP-PRED is t, MAP stays
active if a key from MAP is used. KEEP-PRED can also be a
function of no arguments: it is called from pre-command-hook and
if it returns non-nil, then MAP stays active.
Optional arg ON-EXIT, if non-nil, specifies a function that is called, with no arguments, after MAP is deactivated.
Optional arg MESSAGE, if non-nil, requests display of an informative message after activating the transient map. If MESSAGE is a string, it specifies the format string for the message to display, and the %k specifier in the string is replaced with the list of keys from the transient map. Any other non-nil value of MESSAGE means to use the message format string "Repeat with %k". Upon deactivating the map, the displayed message will be cleared out.
Optional arg TIMEOUT, if non-nil, should be a number specifying the
number of seconds of idle time after which the map is deactivated.
The variable set-transient-map-timeout, if non-nil, overrides the
value of TIMEOUT.
This function uses overriding-terminal-local-map, which takes precedence
over all other keymaps. As usual, if no match for a key is found in MAP,
the normal key lookup sequence then continues.
This returns an "exit function", which can be called with no argument to deactivate this transient map, regardless of KEEP-PRED.
Probably introduced at or before Emacs version 29.1.
Aliases
set-temporary-overlay-map (obsolete since 24.4)
Source Code
;; Defined in /usr/src/emacs/lisp/subr.el.gz
(defun set-transient-map (map &optional keep-pred on-exit message timeout)
"Set MAP as a temporary keymap taking precedence over other keymaps.
Normally, MAP is used only once, to look up the very next key.
However, if the optional argument KEEP-PRED is t, MAP stays
active if a key from MAP is used. KEEP-PRED can also be a
function of no arguments: it is called from `pre-command-hook' and
if it returns non-nil, then MAP stays active.
Optional arg ON-EXIT, if non-nil, specifies a function that is
called, with no arguments, after MAP is deactivated.
Optional arg MESSAGE, if non-nil, requests display of an informative
message after activating the transient map. If MESSAGE is a string,
it specifies the format string for the message to display, and the %k
specifier in the string is replaced with the list of keys from the
transient map. Any other non-nil value of MESSAGE means to use the
message format string \"Repeat with %k\". Upon deactivating the map,
the displayed message will be cleared out.
Optional arg TIMEOUT, if non-nil, should be a number specifying the
number of seconds of idle time after which the map is deactivated.
The variable `set-transient-map-timeout', if non-nil, overrides the
value of TIMEOUT.
This function uses `overriding-terminal-local-map', which takes precedence
over all other keymaps. As usual, if no match for a key is found in MAP,
the normal key lookup sequence then continues.
This returns an \"exit function\", which can be called with no argument
to deactivate this transient map, regardless of KEEP-PRED."
(let* ((timeout (or set-transient-map-timeout timeout))
(message
(when message
(let (keys)
(map-keymap (lambda (key cmd) (and cmd (push key keys))) map)
(format-spec (if (stringp message) message "Repeat with %k")
`((?k . ,(mapconcat
(lambda (key)
(substitute-command-keys
(format "\\`%s'"
(key-description (vector key)))))
keys ", ")))))))
(clearfun (make-symbol "clear-transient-map"))
(exitfun
(lambda ()
(internal-pop-keymap map 'overriding-terminal-local-map)
(remove-hook 'pre-command-hook clearfun)
;; Clear the prompt after exiting.
(when message (message ""))
(when set-transient-map-timer (cancel-timer set-transient-map-timer))
(when on-exit (funcall on-exit)))))
;; Don't use letrec, because equal (in add/remove-hook) could get trapped
;; in a cycle. (bug#46326)
(fset clearfun
(lambda ()
(with-demoted-errors "set-transient-map PCH: %S"
(if (cond
((null keep-pred) nil)
((and (not (eq map (cadr overriding-terminal-local-map)))
(memq map (cddr overriding-terminal-local-map)))
;; There's presumably some other transient-map in
;; effect. Wait for that one to terminate before we
;; remove ourselves.
;; For example, if isearch and C-u both use transient
;; maps, then the lifetime of the C-u should be nested
;; within isearch's, so the pre-command-hook of
;; isearch should be suspended during the C-u one so
;; we don't exit isearch just because we hit 1 after
;; C-u and that 1 exits isearch whereas it doesn't
;; exit C-u.
t)
((eq t keep-pred)
(let ((mc (lookup-key map (this-command-keys-vector))))
;; We may have a remapped command, so chase
;; down that.
(when (and mc (symbolp mc))
(setq mc (or (command-remapping mc) mc)))
;; If the key is unbound `this-command` is
;; nil and so is `mc`.
(and mc (eq this-command mc))))
(t (funcall keep-pred)))
;; Repeat the message for the next command.
(when message (message "%s" message))
(funcall exitfun)))))
(add-hook 'pre-command-hook clearfun)
(internal-push-keymap map 'overriding-terminal-local-map)
(when timeout
(when set-transient-map-timer (cancel-timer set-transient-map-timer))
(setq set-transient-map-timer (run-with-idle-timer timeout nil exitfun)))
(when message (message "%s" message))
exitfun))