As a reader of this blog you probably know about which-key. It is a great package which helps discovering and remembering keybindings. One thing I miss, is the option to choose candidates via completion, which is the goal of this post.
When you press C-h after a prefix key, Emacs displays a buffer containing
all the bindings under that prefix. The command which gets called is determined
by the variable
Which-key makes use of this
variable, too. It uses the initial value as a fallback so the variable needs to
be set before
which-key-mode is activated:
(setq prefix-help-command #'which-key-M-x-prefix+) (which-key-mode 1)
The code of this post makes use of internal
which-key functions and is tightly
related to it, so I will keep the
which-key- prefix and add a
+ suffix. This
approach is what I’m using for all my personal package extensions. Using the
same "name space" has some nice benefits for search and completion and the
unusual suffix avoids potential name clashes.
(defun which-key-M-x-prefix+ (&optional _) "Completing read and execute command from current prefix map. This command can be used as `prefix-help-command'. The optional argument is ignored and only for compatability with `which-key-C-h-dispatch' so this command can be bound in `which-key-C-h-map', too." (interactive) (let* ((evs (if (which-key--current-prefix) (which-key--current-key-list) (butlast (append (this-command-keys-vector) nil)))) (key (apply #'vector evs)) (map (key-binding key))) (which-key--execute-binding+ map (key-description key)))) (defun which-key--execute-binding+ (map &optional prefix) "Completing read command from MAP and execute it. If PREFIX is given it should be a key description which will be included in the prompt." (let ((cmd (which-key--completing-read-cmd+ map prefix))) (when (commandp cmd) (which-key--execute-cmd+ cmd)))) (defun which-key--completing-read-cmd+ (map &optional prefix) "Completing read command from MAP. Include PREFIX in prompt if given." (which-key--hide-popup-ignore-command) (let* ((desc (completing-read (if prefix (format "Execute (%s): " prefix) "Execute: ") (mapcar #'which-key--completing-read-format+ (which-key--get-keymap-bindings map 'all))))) (intern (car (split-string desc))))) (defun which-key--execute-cmd+ (cmd) "Execute command CMD as if invoked by key sequence." (setq prefix-arg current-prefix-arg) (setq this-command cmd) (setq real-this-command cmd) (command-execute cmd 'record)) (defun which-key--completing-read-format+ (bnd) "Format binding BND for `completing-read'." (let* ((key (car bnd)) (cmd (cdr bnd)) (desc (format "%s (%s)" cmd (propertize key 'face 'which-key-key-face)))) (which-key--maybe-add-docstring (format "%-50s" desc) cmd)))
After adding the above code to your Emacs, you should be able to press a prefix key and invoke the command completion with C-h. If the which-key popup is already showing you need to press it twice, because it uses C-h for its own paging commands, too.