helpful

a fork of Wilfred's helpful
git clone https://git.trogloxene.org/helpful.git
Log | Files | Refs | README

commit b42bd5adcbf910bffec44022d1c99df7322d98f7
parent c9a3b0428dcbda6c8f3c3a0926307f2a52cdfd14
Author: Wilfred Hughes <me@wilfred.me.uk>
Date:   Fri, 16 Mar 2018 21:21:25 +0000

Fix keymap rendering with prefix keys

See projectile-mode for an example.

Diffstat:
MCHANGELOG.md | 3+++
Mhelpful.el | 50++++++++++++++++++++++++++++++++------------------
Mtest/unit-test.el | 18++++++++++++++++++
3 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -5,6 +5,9 @@ underlying symbol, show the `defalias` call in the source code, don't show duplicates in the Aliases list, and cross-reference the Elisp manual. +Fixed an issue where keymaps with prefix keys were not rendered +correctly. + Fixed an issue when looking at variable docs where we would visit the definition buffer without the user requesting it. diff --git a/helpful.el b/helpful.el @@ -669,9 +669,21 @@ Flattens nested keymaps and follows remapped commands. Returns a list of pairs (KEYCODES COMMAND), where KEYCODES is a vector suitable for `key-description', and COMMAND is a smbol." - (let (result) - (if (symbolp keymap) - (push (list (vector) keymap) result) + (cond + ;; Prefix keys. + ((and + (symbolp keymap) + (fboundp keymap) + ;; Prefix keys use a keymap in the function slot of a symbol. + (keymapp (symbol-function keymap))) + (helpful--keymap-keys (symbol-function keymap))) + ;; Other symbols mean we've reached a leaf, so this is a command + ;; we can call. + ((symbolp keymap) + `(([] ,keymap))) + ;; Otherwise, recurse on the keys at this level of the keymap. + (t + (let (result) (dolist (item (cdr keymap)) (cond ((and (consp item) @@ -693,21 +705,21 @@ vector suitable for `key-description', and COMMAND is a smbol." (-lambda ((keycodes command)) (push (list (vconcat (vector keycode) keycodes) command) result)))) - item))))) - ;; For every command `foo' mapped to a command `bar', show `foo' with - ;; the key sequence for `bar'. - (setq result - (-map-when - (-lambda ((keycodes _)) - (and (> (length keycodes) 1) - (eq (elt keycodes 0) 'remap))) - (-lambda ((keycodes command)) - (list - (where-is-internal (elt keycodes 1) global-map t) - command)) - result)) - ;; Preserve the original order of the keymap. - (nreverse result))) + item)))) + ;; For every command `new-func' mapped to a command `orig-func', show `new-func' with + ;; the key sequence for `orig-func'. + (setq result + (-map-when + (-lambda ((keycodes _)) + (and (> (length keycodes) 1) + (eq (elt keycodes 0) 'remap))) + (-lambda ((keycodes command)) + (list + (where-is-internal (elt keycodes 1) global-map t) + command)) + result)) + ;; Preserve the original order of the keymap. + (nreverse result))))) ;; TODO: unlike `substitute-command-keys', this shows keybindings ;; which are currently shadowed (e.g. a global minor mode map). @@ -830,6 +842,8 @@ This is used in `helpful--syntax-highlight' to support extra highlighting that the user may have configured in their mode hooks.") +;; TODO: crashes on `backtrace-frame' on a recent checkout. + (defun helpful--syntax-highlight (source &optional mode) "Return a propertized version of SOURCE in MODE." (unless mode diff --git a/test/unit-test.el b/test/unit-test.el @@ -357,6 +357,24 @@ associated a lambda with a keybinding." ([3 27 1] backward-char) ([97] forward-char)))))) +(defvar helpful--dummy-keymap + (let ((keymap (make-sparse-keymap))) + (define-key keymap (kbd "a") #'forward-char) + keymap)) + +;; `fset' is necessary for keymaps as prefixes. This is a quirky Emacs +;; API: https://emacs.stackexchange.com/q/28576/304 +(fset 'helpful--dummy-keymap helpful--dummy-keymap) + +(ert-deftest helpful--keymap-keys--prefix () + "Test we flatten keymaps with prefix keys." + (let* ((keymap (make-sparse-keymap))) + (define-key keymap (kbd "C-c") 'helpful--dummy-keymap) + (should + (equal + (helpful--keymap-keys keymap) + '(([3 97] forward-char)))))) + (ert-deftest helpful--keymap-keys () (let* ((parent-keymap (make-keymap)) (keymap (make-keymap)))