mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-28 10:51:29 -08:00
365 lines
15 KiB
Org Mode
365 lines
15 KiB
Org Mode
* which-key
|
|
[[http://melpa.org/#/which-key][http://melpa.org/packages/which-key-badge.svg]]
|
|
** Introduction
|
|
=which-key= is a minor mode for Emacs that displays the keybindings following your currently
|
|
entered incomplete command (a prefix) in a popup. For example, after enabling the minor mode
|
|
if you enter =C-x= and wait for the default of 1 second the minibuffer will expand with all of
|
|
the available keybindings that follow =C-x= (or as many as space allows given your settings).
|
|
This includes prefixes like =C-x 8= which are shown in a different face. Screenshots of what
|
|
the popup will look like are included below. =which-key= started as a rewrite of
|
|
[[https://github.com/kai2nenobu/guide-key][guide-key-mode]], but the feature sets have diverged
|
|
to a certain extent.
|
|
|
|
With respect to =guide-key=, the intention is to provide the
|
|
following features:
|
|
1. A different polling mechanism to make it lighter on resources than guide-key
|
|
2. An improved display of keys with more keys being shown by default and a nicer
|
|
presentation
|
|
3. Customization options that allow for the rewriting of command names on the
|
|
fly through easily modifiable alists
|
|
4. Good default configurations that work well with most themes
|
|
5. A well configured back-end for displaying keys (removing the popwin
|
|
dependency) that can be easily customized by writing new display functions
|
|
|
|
Many of these have been implemented and are described below.
|
|
|
|
** Table of Contents :TOC@4:
|
|
- [[#which-key-][which-key ]]
|
|
- [[#introduction][Introduction]]
|
|
- [[#install][Install]]
|
|
- [[#melpa][MELPA]]
|
|
- [[#manually][Manually]]
|
|
- [[#initial-setup][Initial Setup]]
|
|
- [[#minibuffer-option][Minibuffer Option]]
|
|
- [[#side-window-right-option][Side Window Right Option]]
|
|
- [[#side-window-bottom-option][Side Window Bottom Option]]
|
|
- [[#side-window-right-then-bottom][Side Window Right then Bottom]]
|
|
- [[#special-features-and-configuration-options][Special Features and Configuration Options]]
|
|
- [[#several-popup-types][Several Popup Types]]
|
|
- [[#minibuffer][minibuffer]]
|
|
- [[#side-window][side window]]
|
|
- [[#frame][frame]]
|
|
- [[#custom][custom]]
|
|
- [[#custom-string-replacement][Custom String Replacement]]
|
|
- [[#key-based-replacement]["Key-Based" replacement]]
|
|
- [[#key-and-description-replacement][Key and Description replacement]]
|
|
- [[#sorting][Sorting]]
|
|
- [[#paging][Paging]]
|
|
- [[#other-options][Other Options]]
|
|
- [[#more-examples][More Examples]]
|
|
- [[#nice-display-with-split-frame][Nice Display with Split Frame]]
|
|
- [[#status][Status]]
|
|
- [[#thanks][Thanks]]
|
|
|
|
** Install
|
|
*** MELPA
|
|
After setting up [[http://melpa.org][MELPA]] as a repository, use =M-x package-install which-key= or
|
|
your preferred method. You will need to call =which-key-mode= to enable the
|
|
minor mode of course.
|
|
|
|
*** Manually
|
|
Add which-key.el to your =load-path= and require. Something like
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(add-to-list 'load-path "path/to/which-key.el")
|
|
(require 'which-key)
|
|
(which-key-mode)
|
|
#+END_SRC
|
|
|
|
** Initial Setup
|
|
No further setup is required if you are happy with the default setup. To try
|
|
other options, there are 3 choices of default configs that are preconfigured
|
|
(then customize to your liking). The main choice is where you want the which-key
|
|
buffer to display. Screenshots of the default options are shown in the next
|
|
sections.
|
|
|
|
In each case, we show as many key bindings as we can fit in the buffer within
|
|
the constraints. The constraints are determined by several factors, including
|
|
your emacs settings, the size of the current emacs frame, and the which-key
|
|
settings, most of which are described below.
|
|
|
|
By default which-key makes substitutions for text all with the aim of saving
|
|
space. The most noticeable are the "special keys" like SPC, TAB, RET, etc. This
|
|
can be turned off (see [[#other-options][Other Options]]), but the default is to
|
|
truncate these keys to one character and display them using =:inverse-video=
|
|
(flips foreground and background colors). You can see the effect in the
|
|
screenshots.
|
|
|
|
There are other substitution abilities included, which are quite flexible
|
|
(ability to use regexp for example). This makes which-key very customizable.
|
|
This functionality is targeting [[https://github.com/syl20bnr/spacemacs][spacemacs]].
|
|
|
|
*** Minibuffer Option
|
|
Take over the minibuffer. For the recommended configuration use
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(which-key-setup-minibuffer)
|
|
#+END_SRC
|
|
|
|
[[./img/which-key-minibuffer.png]]
|
|
|
|
Note the maximum height of the minibuffer is controlled through the built-in
|
|
variable =max-mini-window-height=.
|
|
|
|
*** Side Window Right Option
|
|
Popup side window on right. For defaults use
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(which-key-setup-side-window-right)
|
|
#+END_SRC
|
|
|
|
Note the defaults are fairly conservative and will tend to not display on
|
|
narrower frames. If you get a message saying which-key can't display the keys,
|
|
try making your frame wider or adjusting the defaults related to the maximum
|
|
width (see =M-x customize-group which-key=).
|
|
|
|
[[./img/which-key-right.png]]
|
|
|
|
*** Side Window Bottom Option
|
|
Popup side window on bottom. This is the current default. To restore this setup use
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(which-key-setup-side-window-bottom)
|
|
#+END_SRC
|
|
|
|
[[./img/which-key-bottom.png]]
|
|
|
|
*** Side Window Right then Bottom
|
|
This is a combination of the previous two choices. It will try to use the right
|
|
side, but if there is no room it will switch to using the bottom, which is
|
|
usually easier to fit keys into. This setting can be helpful if the size of
|
|
the Emacs frame changes frequently, which might be the caes if you are using
|
|
a dynamic/tiling window manager.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(which-key-setup-side-window-right-bottom)
|
|
#+END_SRC
|
|
|
|
** Special Features and Configuration Options
|
|
There are more options than the ones described here. All of the configurable
|
|
variables are available through =M-x customize-group which-key=.
|
|
*** Several Popup Types
|
|
There are three different popup types that which-key can use by default to
|
|
display the available keys. The variable =which-key-popup-type= decides which
|
|
one is used.
|
|
**** minibuffer
|
|
#+BEGIN_SRC emacs-lisp
|
|
(setq which-key-popup-type 'minibuffer)
|
|
#+END_SRC
|
|
Show keys in the minibuffer.
|
|
**** side window
|
|
#+BEGIN_SRC emacs-lisp
|
|
(setq which-key-popup-type 'side-window)
|
|
#+END_SRC
|
|
Show keys in a side window. This popup type has further options:
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; location of which-key window. valid values: top, bottom, left, right,
|
|
;; or a list of any of the two. If it's a list, which-key will always try
|
|
;; the first location first. It will go to the second location if there is
|
|
;; not enough room to display any keys in the first location
|
|
(setq which-key-side-window-location 'bottom)
|
|
|
|
;; max width of which-key window, when displayed at left or right.
|
|
;; valid values: number of columns (integer), or percentage out of current
|
|
;; frame's width (float larger than 0 and smaller than 1)
|
|
(setq which-key-side-window-max-width 0.33)
|
|
|
|
;; max height of which-key window, when displayed at top or bottom.
|
|
;; valid values: number of lines (integer), or percentage out of current
|
|
;; frame's height (float larger than 0 and smaller than 1)
|
|
(setq which-key-side-window-max-height 0.25)
|
|
#+END_SRC
|
|
**** frame
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(setq which-key-popup-type 'frame)
|
|
#+END_SRC
|
|
Show keys in a popup frame. This popup won't work very well in a terminal,
|
|
where only one frame can be shown at any given moment. This popup type has
|
|
further options:
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; max width of which-key frame: number of columns (an integer)
|
|
(setq which-key-frame-max-width 60)
|
|
|
|
;; max height of which-key frame: number of lines (an integer)
|
|
(setq which-key-frame-max-height 20)
|
|
#+END_SRC
|
|
|
|
**** custom
|
|
Write your own display functions! This requires you to write three functions,
|
|
=which-key-custom-popup-max-dimensions-function=,
|
|
=which-key-custom-show-popup-function=, and
|
|
=which-key-custom-hide-popup-function=. Refer to the documentation for those
|
|
variables for more information, but here is a working example (this is the
|
|
current implementation of side-window bottom).
|
|
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(setq which-key-popup-type 'custom)
|
|
(defun which-key-custom-popup-max-dimensions-function (ignore)
|
|
(cons
|
|
(which-key-height-or-percentage-to-height which-key-side-window-max-height)
|
|
(frame-width)))
|
|
(defun fit-horizonatally ()
|
|
(let ((fit-window-to-buffer-horizontally t))
|
|
(fit-window-to-buffer)))
|
|
(defun which-key-custom-show-popup-function (act-popup-dim)
|
|
(let* ((alist '((window-width . fit-horizontally)
|
|
(window-height . fit-window-to-buffer))))
|
|
(if (get-buffer-window which-key--buffer)
|
|
(display-buffer-reuse-window which-key--buffer alist)
|
|
(display-buffer-in-major-side-window which-key--buffer 'bottom 0 alist))))
|
|
(defun which-key-custom-hide-popup-function ()
|
|
(when (buffer-live-p which-key--buffer)
|
|
(quit-windows-on which-key--buffer)))
|
|
#+END_SRC
|
|
|
|
*** Custom String Replacement
|
|
You can customize the way the keys show in the buffer using three different
|
|
replacement methods, each of which corresponds replacement alist. The basic idea
|
|
of behind each alist is that you specify a selection string in the =car= of each
|
|
cons cell and the replacement string in the =cdr=.
|
|
|
|
**** "Key-Based" replacement
|
|
The relevant variable is the awkwardly named
|
|
=which-key-key-based-description-replacement-alist=. In this alist you can have
|
|
cons cells of two types. An example of the first type is
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
("C-x C-f" . "find files")
|
|
#+END_SRC
|
|
|
|
where the string on the left is the key combination whose description you want
|
|
to replace. For that key combination, which-key overwrites the description with
|
|
the second string, "find files". In the second type of entry you can restrict
|
|
the replacements to a major-mode. For example,
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(org-mode . (("C-c C-c" . "Org C-c C-c") ("C-c C-a" . "Org Attach"))
|
|
#+END_SRC
|
|
|
|
Here the first entry is the major-mode and the second is a list of the first
|
|
type of entries. In case the same key combination is listed under a major-mode
|
|
and by itself, the major-mode version will take precedence.
|
|
|
|
There are two helper functions to add entries to this list,
|
|
=which-key-add-key-based-replacements= and
|
|
=which-key-add-major-mode-key-based-replacements=. You can modify the alist
|
|
directly or use these.
|
|
|
|
**** Key and Description replacement
|
|
|
|
The second and third methods target the text used for the keys and the
|
|
descriptions directly. The relevant variables are
|
|
=which-key-key-replacement-alist= and =which-key-description-replacement-alist=.
|
|
Here's an example of one of the default key replacements
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
("<\\([[:alnum:]-]+\\)>" . "\\1")
|
|
#+END_SRC
|
|
|
|
The =car= takes a string which may use emacs regexp and the =cdr= takes a string
|
|
with the replacement text. As shown, you can specify a sub-expression of the
|
|
match. The replacements do not need to use regexp and can be as simple as
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
("left" . "lft")
|
|
#+END_SRC
|
|
|
|
You can add this element to the key list with (there are no helper functions for
|
|
these alists)
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(add-to-list 'which-key-key-replacement-alist '("left" . "lft"))
|
|
#+END_SRC
|
|
|
|
*** Sorting
|
|
By default the output is sorted by the key in a custom order. The default order
|
|
is to sort lexicographically within each "class" of key, where the classes and
|
|
their order are
|
|
|
|
=Special (SPC, TAB, ...) < Single Character (a, ...) < Modifier (C-, M-, ...) < Other=
|
|
|
|
You can control the order by setting this variable.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(setq which-key-sort-order 'which-key-key-order)
|
|
;; or (setq which-key-sort-order 'which-key-description-order)
|
|
#+END_SRC
|
|
|
|
The only other built-in option at the moment (besides using nil to turn off
|
|
sorting completely) is =which-key-description-order=, which orders by the key's
|
|
description based on the usual ordering of strings after applying =downcase=.
|
|
|
|
*** Paging
|
|
This is a new feature and may have bugs, so it is disabled by default. There are
|
|
at least several prefixes that have many keys bound to them, like =C-x=.
|
|
which-key displays as many keys as it can given your settings, but for these
|
|
prefixes this may not be enough. The paging feature gives you the ability to
|
|
bind a key to the function =which-key-show-next-page= which will cycle through
|
|
the pages without changing the key sequence you were in the middle of typing.
|
|
Essentially, all you need to do to enable this for a prefix like =C-x= is the
|
|
following which will bind =<f5>= to the command.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(define-key which-key-mode-map (kbd "C-x <f5>") 'which-key-show-next-page)
|
|
#+END_SRC
|
|
|
|
This is completely equivalent to
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
(setq which-key-paging-prefixes '("C-x"))
|
|
(setq which-key-paging-key "<f5>")
|
|
#+END_SRC
|
|
|
|
where the latter are provided for convenience if you have a lot of prefixes.
|
|
|
|
*** Other Options
|
|
The options below are also available through customize. Their defaults are
|
|
shown.
|
|
|
|
#+BEGIN_SRC emacs-lisp
|
|
;; Set the time delay (in seconds) for the which-key popup to appear.
|
|
(setq which-key-idle-delay 1.0)
|
|
|
|
;; Set the maximum length (in characters) for key descriptions (commands or
|
|
;; prefixes). Descriptions that are longer are truncated and have ".." added
|
|
(setq which-key-max-description-length 27)
|
|
|
|
;; Set the separator used between keys and descriptions. Change this setting to
|
|
;; an ASCII character if your font does not show the default arrow. The second
|
|
;; setting here allows for extra padding for unicode characters. which-key uses
|
|
;; characters as a means of width measurement, so wide unicode characters can
|
|
;; throw off the calculation.
|
|
(setq which-key-separator " → " )
|
|
(setq which-key-unicode-correction 3)
|
|
|
|
;; Set the special keys. These are automatically truncated to one character and
|
|
;; have which-key-special-key-face applied. Set this variable to nil to disable
|
|
;; the feature
|
|
(setq which-key-special-keys '("SPC" "TAB" "RET" "ESC" "DEL"))
|
|
|
|
;; Show the key prefix on the left or top (nil means hide the prefix). The
|
|
;; prefix consists of the keys you have typed so far. which-key also shows the
|
|
;; page information along with the prefix.
|
|
(setq which-key-show-prefix 'left)
|
|
|
|
;; Set to t to show the count of keys shown vs. total keys in the mode line.
|
|
(setq which-key-show-remaining-keys nil)
|
|
#+END_SRC
|
|
** More Examples
|
|
*** Nice Display with Split Frame
|
|
Unlike guide-key, which-key looks good even if the frame is split into several
|
|
windows.
|
|
#+CAPTION: which-key in a frame with 3 horizontal splits
|
|
[[./img/which-key-right-split.png]]
|
|
|
|
#+CAPTION: which-key in a frame with 2 vertical splits
|
|
[[./img/which-key-bottom-split.png]]
|
|
|
|
** Status
|
|
It requires testing on different platforms with different configurations, which
|
|
is beyond my capabilities. The default configuration has been reasonably stable
|
|
for me.
|
|
** Thanks
|
|
Thanks to @bmag for helping with the initial development and finding many bugs.
|