Commit 557b790e authored by Stefan Kangas's avatar Stefan Kangas

Add new help command describe-keymap

* lisp/help-fns.el (describe-keymap): New command to show key bindings
for a given keymap.  (Bug#30660)
* doc/emacs/help.texi (Misc Help): Document the new command.
* doc/lispref/keymaps.texi (Scanning Keymaps): Add a cross-reference
to the above documentation.
* etc/NEWS: Announce the new command.

* test/lisp/help-fns-tests.el (help-fns-test-describe-keymap/symbol)
(help-fns-test-describe-keymap/dynamically-bound-no-file): New tests.
Co-authored-by: default avatarDrew Adams <>
parent f9504ffb
......@@ -601,6 +601,11 @@ is @key{ESC}, because @kbd{@key{ESC} C-h} is actually @kbd{C-M-h},
which marks a defun. However, @w{@kbd{@key{ESC} @key{F1}}} and
@w{@kbd{@key{ESC} ?}} work fine.)
@findex describe-keymap
Finally, @kbd{M-x describe-keymap} prompts for the name of a keymap,
with completion, and displays a listing of all key bindings in that
@node Help Files
@section Help Files
......@@ -1846,8 +1846,11 @@ local map.
@cindex scanning keymaps
@cindex keymaps, scanning
This section describes functions used to scan all the current keymaps
for the sake of printing help information.
This section describes functions used to scan all the current
keymaps for the sake of printing help information. To display the
bindings in a particular keymap, you can use the
@code{describe-keymap} command (@pxref{Misc Help, , Other Help
Commands, emacs, The GNU Emacs Manual})
@defun accessible-keymaps keymap &optional prefix
This function returns a list of all the keymaps that can be reached (via
......@@ -85,6 +85,11 @@ shows equivalent key bindings for all commands that have them.
* Changes in Specialized Modes and Packages in Emacs 28.1
** Help
*** New command 'describe-keymap' describes keybindings in a keymap.
** The old non-SMIE indentation of 'sh-mode' has been removed.
......@@ -1562,6 +1562,65 @@ BUFFER should be a buffer or a buffer name."
(insert "\nThe parent category table is:")
(describe-vector table 'help-describe-category-set))))))
(defun describe-keymap (keymap)
"Describe key bindings in KEYMAP.
When called interactively, prompt for a variable that has a
keymap value."
(interactive (list
(intern (completing-read "Keymap: " obarray
(lambda (m)
(and (boundp m)
(keymapp (symbol-value m))))
t nil 'variable-name-history))))
(let (used-gentemp)
(unless (and (symbolp keymap)
(boundp keymap)
(keymapp (symbol-value keymap)))
(when (not (keymapp keymap))
(if (symbolp keymap)
(error "Not a keymap variable: %S" keymap)
(error "Not a keymap")))
(let ((sym nil))
(unless sym
(setq sym (cl-gentemp "KEYMAP OBJECT (no variable) "))
(setq used-gentemp t)
(set sym keymap))
(setq keymap sym)))
;; Follow aliasing.
(setq keymap (or (ignore-errors (indirect-variable keymap)) keymap))
(help-setup-xref (list #'describe-keymap keymap)
(called-interactively-p 'interactive))
(let* ((name (symbol-name keymap))
(doc (documentation-property keymap 'variable-documentation))
(file-name (find-lisp-object-file-name keymap 'defvar)))
(with-help-window (help-buffer)
(with-current-buffer standard-output
(unless used-gentemp
(princ (format-message "%S is a keymap variable" keymap))
(if (not file-name)
(princ ".\n\n")
(princ (format-message
" defined in `%s'.\n\n"
(if (eq file-name 'C-source)
"C source code"
(file-name-nondirectory file-name))))
(re-search-backward (substitute-command-keys
nil t)
(help-xref-button 1 'help-variable-def
keymap file-name))))
(when (and (not (equal "" doc)) doc)
(princ "Documentation:\n")
(princ (format-message "%s\n\n" doc)))
;; Use `insert' instead of `princ', so control chars (e.g. \377)
;; insert correctly.
(insert (substitute-command-keys (concat "\\{" name "}"))))))
;; Cleanup.
(when used-gentemp
(makunbound keymap))))
;;; Replacements for old lib-src/ programs. Don't seem especially useful.
......@@ -123,4 +123,32 @@ Return first line of the output of (describe-function-1 FUNC)."
(goto-char (point-min))
(should (looking-at "^font-lock-comment-face is "))))
;;; Tests for describe-keymap
(ert-deftest help-fns-test-describe-keymap/symbol ()
(describe-keymap 'minibuffer-local-must-match-map)
(with-current-buffer "*Help*"
(should (looking-at "^minibuffer-local-must-match-map is"))))
(ert-deftest help-fns-test-describe-keymap/value ()
(describe-keymap minibuffer-local-must-match-map)
(with-current-buffer "*Help*"
(should (looking-at "^key"))))
(ert-deftest help-fns-test-describe-keymap/not-keymap ()
(should-error (describe-keymap nil))
(should-error (describe-keymap emacs-version)))
(ert-deftest help-fns-test-describe-keymap/let-bound ()
(let ((foobar minibuffer-local-must-match-map))
(describe-keymap foobar)
(with-current-buffer "*Help*"
(should (looking-at "^key")))))
(ert-deftest help-fns-test-describe-keymap/dynamically-bound-no-file ()
(setq help-fns-test--describe-keymap-foo minibuffer-local-must-match-map)
(describe-keymap 'help-fns-test--describe-keymap-foo)
(with-current-buffer "*Help*"
(should (looking-at "^help-fns-test--describe-keymap-foo is"))))
;;; help-fns-tests.el ends here
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment