๐ฅ Which Key
WhichKey helps you remember your Neovim keymaps, by showing available keybindings
in a popup as you type.
![image](https://github.com/user-attachments/assets/e4400a1d-7e71-4439-b6ff-6cbc40647a6f)
โจ Features
- ๐ Key Binding Help: show available keybindings in a popup as you type.
- โจ๏ธ Modes: works in normal, insert, visual, operator pending, terminal and command mode.
Every mode can be enabled/disabled.
- ๐ ๏ธ Customizable Layouts: choose from
classic
, modern
, and helix
presets or customize the window.
- ๐ Flexible Sorting: sort by
local
, order
, group
, alphanum
, mod
, lower
, icase
, desc
, or manual
.
- ๐จ Formatting: customizable key labels and descriptions
- ๐ผ๏ธ Icons: integrates with mini.icons and nvim-web-devicons
- โฑ๏ธ Delay: delay is independent of
timeoutlen
- ๐ Plugins: built-in plugins for marks, registers, presets, and spelling suggestions
- ๐ Operators, Motions, Text Objects: help for operators, motions and text objects
โก๏ธ Requirements
- Neovim >= 0.9.0
- for proper icons support:
๐ฆ Installation
Install the plugin with your package manager:
{
"folke/which-key.nvim",
event = "VeryLazy",
opts = {
-- your configuration comes here
-- or leave it empty to use the default settings
-- refer to the configuration section below
},
keys = {
{
"<leader>?",
function()
require("which-key").show({ global = false })
end,
desc = "Buffer Local Keymaps (which-key)",
},
},
}
โ๏ธ Configuration
[!important]
Make sure to run :checkhealth which-key
if something isn't working properly
WhichKey is highly configurable. Expand to see the list of all the default options below.
Default Options
```lua
---@class wk.Opts
local defaults = {
---@type false | "classic" | "modern" | "helix"
preset = "classic",
-- Delay before showing the popup. Can be a number or a function that returns a number.
---@type number | fun(ctx: { keys: string, mode: string, plugin?: string }):number
delay = function(ctx)
return ctx.plugin and 0 or 200
end,
--- You can add any mappings here, or use `require('which-key').add()` later
---@type wk.Spec
spec = {},
-- show a warning when issues were detected with your mappings
notify = true,
-- Enable/disable WhichKey for certain mapping modes
modes = {
n = true, -- Normal mode
i = true, -- Insert mode
x = true, -- Visual mode
s = true, -- Select mode
o = true, -- Operator pending mode
t = true, -- Terminal mode
c = true, -- Command mode
},
plugins = {
marks = true, -- shows a list of your marks on ' and `
registers = true, -- shows your registers on " in NORMAL or in INSERT mode
-- the presets plugin, adds help for a bunch of default keybindings in Neovim
-- No actual key bindings are created
spelling = {
enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions
suggestions = 20, -- how many suggestions should be shown in the list?
},
presets = {
operators = true, -- adds help for operators like d, y, ...
motions = true, -- adds help for motions
text_objects = true, -- help for text objects triggered after entering an operator
windows = true, -- default bindings on
nav = true, -- misc bindings to work with windows
z = true, -- bindings for folds, spelling and others prefixed with z
g = true, -- bindings for prefixed with g
},
},
---@type wk.Win
win = {
-- width = 1,
-- height = { min = 4, max = 25 },
-- col = 0,
row = -1,
-- border = "none",
padding = { 1, 2 }, -- extra window padding [top/bottom, right/left]
title = true,
title_pos = "center",
zindex = 1000,
-- Additional vim.wo and vim.bo options
bo = {},
wo = {
-- winblend = 10, -- value between 0-100 0 for fully opaque and 100 for fully transparent
},
},
layout = {
width = { min = 20 }, -- min and max width of the columns
spacing = 3, -- spacing between columns
align = "left", -- align columns left, center or right
},
keys = {
scroll_down = "", -- binding to scroll down inside the popup
scroll_up = "", -- binding to scroll up inside the popup
},
---@type (string|wk.Sorter)[]
--- Add "manual" as the first element to use the order the mappings were registered
--- Other sorters: "desc"
sort = { "local", "order", "group", "alphanum", "mod", "lower", "icase" },
expand = 1, -- expand groups when <= n mappings
---@type table
replace = {
key = {
function(key)
return require("which-key.view").format(key)
end,
-- { "", "SPC" },
},
desc = {
{ "%((.*)%)", "%1" },
{ "^%+", "" },
{ "<[cC]md>", "" },
{ "<[cC][rR]>", "" },
{ "<[sS]ilent>", "" },
{ "^lua%s+", "" },
{ "^call%s+", "" },
{ "^:%s*", "" },
},
},
icons = {
breadcrumb = "ยป", -- symbol used in the command line area that shows your active key combo
separator = "โ", -- symbol used between a key and it's label
group = "+", -- symbol prepended to a group
ellipsis = "โฆ",
--- See `lua/which-key/icons.lua` for more details
--- Set to `false` to disable keymap icons
---@type wk.IconRule[]|false
rules = {},
-- use the highlights from mini.icons
-- When `false`, it will use `WhichKeyIcon` instead
colors = true,
-- used by key format
keys = {
Up = "๏ข ",
Down = "๏ฃ ",
Left = "๏ ",
Right = "๏ก ",
C = "๓ฐด ",
M = "๓ฐต ",
S = "๓ฐถ ",
CR = "๓ฐ ",
Esc = "๓ฑท ",
ScrollWheelDown = "๓ฑ ",
ScrollWheelUp = "๓ฑ ",
NL = "๓ฐ ",
BS = "โซ",
Space = "๓ฑ ",
Tab = "๓ฐ ",
},
},
show_help = true, -- show a help message in the command line for using WhichKey
show_keys = true, -- show the currently pressed key and its label as a message in the command line
-- Which-key automatically sets up triggers for your mappings.
-- But you can disable this and setup the triggers yourself.
-- Be aware, that triggers are not needed for visual and operator pending mode.
triggers = true, -- automatically setup triggers
disable = {
-- disable WhichKey for certain buf types and file types.
ft = {},
bt = {},
-- disable a trigger for a certain context by returning true
---@type fun(ctx: { keys: string, mode: string, plugin?: string }):boolean?
trigger = function(ctx)
return false
end,
},
}
```
โจ๏ธ Setup
WhichKey automatically gets the descriptions of your keymaps from the desc
attribute of the keymap. So for most use-cases, you don't need to do anything else.
However, the mapping spec is still useful to configure group descriptions and mappings that don't really exist as a regular keymap.
[!WARNING]
The mappings spec changed in v3
, so make sure to only use the new add
method if
you updated your existing mappings.
Mappings can be added as part of the config opts.spec
, or can be added later
using require("which-key").add()
.
wk.add()
can be called multiple times from anywhere in your config files.
A mapping has the following attributes:
- [1]: (
string
) lhs (required)
- [2]: (
string|fun()
) rhs (optional): when present, it will create the mapping
- desc: (
string
) description (required)
- mode: (
string|string[]
) mode (optional, defaults to "n"
)
- group: (
string
) group name (optional)
- cond: (
boolean|fun():boolean
) condition to enable the mapping (optional)
- hidden: (
boolean
) hide the mapping (optional)
- icon: (
string|wk.Icon
) icon spec (optional)
- any other option valid for
vim.keymap.set
. These are only used for creating mappings.
local wk = require("which-key")
wk.add({
{ "<leader>f", group = "file" }, -- group
{ "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find File", mode = "n" },
{ "<leader>fb", function() print("hello") end, desc = "Foobar" },
{ "<leader>fn", desc = "New File" },
{ "<leader>f1", hidden = true }, -- hide this keymap
{
-- Nested mappings are allowed and can be added in any order
-- Most attributes can be inherited or overridden on any level
-- There's no limit to the depth of nesting
mode = { "n", "v" }, -- NORMAL and VISUAL mode
{ "<leader>q", "<cmd>q<cr>", desc = "Quit" }, -- no need to specify mode since it's inherited
{ "<leader>w", "<cmd>w<cr>", desc = "Write" },
}
})
๐จ Icons
[!note]
For full support, you need to install either mini.icons or nvim-web-devicons
There's multiple ways to set icons for your keymaps:
- if you use lazy.nvim, then some icons will be autodetected for keymaps belonging to certain plugins.
- custom rules to decide what icon to use
- in your mapping spec, you can specify what icon to use at any level, so at the node for
<leader>g
for example, to apply to all git keymaps.
The icon
attribute of a mapping can be a string
, which will be used as the actual icon,
or an wk.Icon
object, which can have the following attributes:
icon
(string
): the icon to use (optional)
hl
(string
): the highlight group to use for the icon (optional)
color
(string
): the color to use for the icon (optional)
valid colors are: azure
, blue
, cyan
, green
, grey
, orange
, purple
, red
, yellow
cat
(string
): the category of the icon (optional)
valid categories are: file
, filetype
, extension
name
(string
): the name of the icon in the specified category (optional)
๐ Usage
When the WhichKey popup is open, you can use the following key bindings (they are also displayed at the bottom of the screen):
- hit one of the keys to open a group or execute a key binding
<esc>
to cancel and close the popup
<bs>
go up one level
<c-d>
scroll down
<c-u>
scroll up
๐ฅ Plugins
Four built-in plugins are included with WhichKey.
Presets
Built-in key binding help for motions
, text-objects
, operators
, windows
, nav
, z
and g
and more.
Marks
Shows a list of your buffer local and global marks when you hit ` or '
![image](https://github.com/user-attachments/assets/43fb0874-7f79-4521-aee9-03e2b0841758)
Registers
Shows a list of your buffer local and global registers when you hit " in NORMAL mode, or <c-r>
in INSERT mode.
![image](https://github.com/user-attachments/assets/d8077dcb-56fb-47b0-ad9e-1aba5db16950)
Spelling
When enabled, this plugin hooks into z=
and replaces the full-screen spelling suggestions window by a list of suggestions within WhichKey.
![image](https://github.com/user-attachments/assets/102c7963-329a-40b9-b0a8-72c8656318b7)
๐จ Colors
The table below shows all the highlight groups defined for WhichKey with their default link.
Highlight Group |
Default Group |
Description |
WhichKey |
Function |
|
WhichKeyBorder |
FloatBorder |
Border of the which-key window |
WhichKeyDesc |
Identifier |
description |
WhichKeyFloat |
NormalFloat |
Normal in th which-key window |
WhichKeyGroup |
Keyword |
group name |
WhichKeyIcon |
@markup.link |
icons |
WhichKeyIconAzure |
Function |
|
WhichKeyIconBlue |
DiagnosticInfo |
|
WhichKeyIconCyan |
DiagnosticHint |
|
WhichKeyIconGreen |
DiagnosticOk |
|
WhichKeyIconGrey |
Normal |
|
WhichKeyIconOrange |
DiagnosticWarn |
|
WhichKeyIconPurple |
Constant |
|
WhichKeyIconRed |
DiagnosticError |
|
WhichKeyIconYellow |
DiagnosticWarn |
|
WhichKeySeparator |
Comment |
the separator between the key and its description |
WhichKeyTitle |
FloatTitle |
Title of the which-key window |
WhichKeyValue |
Comment |
values by plugins (like marks, registers, etc) |