8000 mini.nvim/doc/mini-keymap.txt at main · figofigueiroa/mini.nvim · GitHub
[go: up one dir, main page]

Skip to content
< 8000 link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/marketing-header.66fbee470ae98514.module.css" />

Latest commit

 

History

History
449 lines (371 loc) · 22 KB

mini-keymap.txt

File metadata and controls

449 lines (371 loc) · 22 KB
*mini.keymap* Special key mappings
MIT License Copyright (c) 2025 Evgeni Chasnovski
------------------------------------------------------------------------------
*MiniKeymap*
Features:
- Map keys to perform configurable multi-step actions: if condition for step
one is true - execute step one action, else check step two, and so on until
falling back to executing original keys. This is usually referred to as
"smart" keys (like "smart tab"). See |MiniKeymap.map_multistep()|.
There are many built-in steps targeted for Insert mode mappings of special
keys like <Tab>, <S-Tab>, <CR>, and <BS>:
- Navigate and accept |popupmenu-completion|. Useful for |mini.completion|.
- Navigate and expand |mini.snippets|.
- Execute <CR> and <BS> respecting |mini.pairs|.
- Jump before/after current tree-sitter node.
- Jump before opening and after closing characters (brackets and quotes).
- Increase/decrease indent when cursor is inside of it.
- Delete all whitespace to the left ("hungry backspace").
- Navigate |vim.snippet|.
- Navigate and accept in [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) completion.
- Navigate and accept in [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp) completion.
- Navigate and expand [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip) snippets.
- Execute <CR> and <BS> respecting [windwp/nvim-autopairs](https://github.com/windwp/nvim-autopairs).
- Map keys as "combo": each key acts immediately plus execute extra action if
all are typed within configurable delay between each other.
See |MiniKeymap.map_combo()|. Some of the common use cases include:
- Map insertable keys (like "jk", "kj") in Insert and Command-line mode
to exit into Normal mode.
- Fight against bad habits of pressing the same navigation key by showing
a notification if there are too many of them pressed in a row.
Sources with more details:
- |MiniKeymap-examples|
# Setup ~
This module doesn't need setup, but it can be done to improve usability.
Setup with `require('mini.keymap').setup({})` (replace `{}` with your `config`
table). It will create global Lua table `MiniKeymap` which you can use for
scripting or manually (with `:lua MiniKeymap.*`).
See |MiniKeymap.config| for `config` structure and default values.
This module doesn't have runtime options, so using `vim.b.minikeymap_config`
will have no effect here.
# Comparisons ~
- [max397574/better-escape.nvim](https://github.com/max397574/better-escape.nvim):
- Mostly similar to |MiniKeymap.map_combo()| with a different approach
to creating mappings.
- Mostly targeted for Insert mode mappings as pressed keys get removed
automatically after typed. This module allows more general cases while
requiring explicit removal of keys (usually via explicit `<BS><BS>`).
- [abecodes/tabout.nvim](https://github.com/abecodes/tabout.nvim):
- Similar general idea as in `'jump_{after,before}_tsnode'` steps
of |MiniKeymap.map_multistep()|.
- Works only with enabled tree-sitter parser. This module provides
fallback via `'jump_after_close'` and `'jump_before_open'` that work
without tree-sitter parser.
- `tabout.nvim` has finer control of how the tree-sitter node movement
is done, while this module has "jump outside of current node" behavior.
# Disabling ~
To disable acting in mappings, set `vim.g.minikeymap_disable` (globally) or
`vim.b.minikeymap_disable` (for a buffer) to `true`. Considering high number
of different scenarios and customization intentions, writing exact rules
for disabling module's functionality is left to user.
See |mini.nvim-disabling-recipes| for common recipes.
------------------------------------------------------------------------------
*MiniKeymap-examples*
# Multi-step ~
See |MiniKeymap.map_multistep()| for a general description of how multi-step
mappings work and what built-in steps are available.
Setup that works well with |mini.completion| and |mini.pairs|: >lua
local map_multistep = require('mini.keymap').map_multistep
map_multistep('i', '<Tab>', { 'pmenu_next' })
map_multistep('i', '<S-Tab>', { 'pmenu_prev' })
map_multistep('i', '<CR>', { 'pmenu_accept', 'minipairs_cr' })
map_multistep('i', '<BS>', { 'minipairs_bs' })
<
Use <Tab> / <S-Tab> to also navigate and expand |mini.snippets|: >lua
local map_multistep = require('mini.keymap').map_multistep
local tab_steps = { 'minisnippets_next','minisnippets_expand','pmenu_next' }
map_multistep('i', '<Tab>', tab_steps)
local shifttab_steps = { 'minisnippets_prev', 'pmenu_prev' }
map_multistep('i', '<S-Tab>', shifttab_steps)
<
An extra smart <Tab> and <S-Tab>: >lua
local map_multistep = require('mini.keymap').map_multistep
-- NOTE: this will never insert tab, press <C-v><Tab> for that
local tab_steps = {
'minisnippets_next', 'minisnippets_ 8000 expand', 'pmenu_next',
'jump_after_tsnode', 'jump_after_close',
}
map_multistep('i', '<Tab>', tab_steps)
local shifttab_steps = {
'minisnippets_prev', 'pmenu_prev',
'jump_before_tsnode', 'jump_before_open',
}
map_multistep('i', '<S-Tab>', shifttab_steps)
<
Navigation in active |vim.snippet| session also requires mapping in |Select-mode|: >lua
local map_multistep = require('mini.keymap').map_multistep
map_multistep({ 'i', 's' }, '<Tab>', { 'vimsnippet_next', 'pmenu_next' })
map_multistep({ 'i', 's' }, '<S-Tab>', { 'vimsnippet_prev', 'pmenu_prev' })
<
# Combos ~
See |MiniKeymap.map_combo()| for a general description of what is a combo and
more caveats about its usage.
All combos require their left hand side keys to be typed relatively quickly.
To adjust the delay between keys, add `{ delay = 500 }` (use custom value) as
fourth argument.
## "Better escape" to Normal mode ~
Leave into |Normal-mode| without having to reach for <Esc> key: >lua
-- Support most common modes. This can also contain 't', but would
-- only mean to press `<Esc>` inside terminal.
local mode = { 'i', 'c', 'x', 's' }
require('mini.keymap').map_combo(mode, 'jk', '<BS><BS><Esc>')
-- To not have to worry about the order of keys, also map "kj"
require('mini.keymap').map_combo(mode, 'kj', '<BS><BS><Esc>')
-- Escape into Normal mode from Terminal mode
require('mini.keymap').map_combo('t', 'jk', '<BS><BS><C-\\><C-n>')
require('mini.keymap').map_combo('t', 'kj', '<BS><BS><C-\\><C-n>')
<
## Show bad navigation habits ~
Show notification if there is too much movement by repeating same key: >lua
local notify_many_keys = function(key)
local lhs = string.rep(key, 5)
local action = function() vim.notify('Too many ' .. key) end
require('mini.keymap').map_combo({ 'n', 'x' }, lhs, action)
end
notify_many_keys('h')
notify_many_keys('j')
notify_many_keys('k')
notify_many_keys('l')
<
## Fix previous spelling mistake ~
Fix previous spelling mistake (see |[s| and |z=|) without manually leaving
Insert mode: >lua
local action = '<BS><BS><Esc>[s1z=gi<Right>'
require('mini.keymap').map_combo('i', 'kk', action)
<
## Hide search highlighting ~
Use double <Esc><Esc> to execute |:nohlsearch|. Although this can also be done
with `nmap <Esc> <Cmd>nohl<CR>`, the combo approach also exists and can be used
to free <Esc> mapping in Normal mode for something else. >lua
local action = function() vim.cmd('nohlsearch') end
require('mini.keymap').map_combo({ 'n','i','x','c' }, '<Esc><Esc>', action)
<
## Buffer navigation ~
Replace some movements with easier to type alternatives: >lua
local map_combo = require('mini.keymap').map_combo
map_combo({ 'n', 'x' }, 'll', 'g$')
map_combo({ 'n', 'x' }, 'hh', 'g^')
map_combo({ 'n', 'x' }, 'jj', '}')
map_combo({ 'n', 'x' }, 'kk', '{')
<
------------------------------------------------------------------------------
*MiniKeymap.setup()*
`MiniKeymap.setup`({config})
Module setup
Parameters ~
{config} `(table|nil)` Module config table. See |MiniKeymap.config|.
Usage ~
>lua
require('mini.keymap').setup({}) -- replace {} with your config table
-- needs `keymap` field present
<
------------------------------------------------------------------------------
*MiniKeymap.config*
`MiniKeymap.config`
Defaults ~
>lua
MiniKeymap.config = {}
<
------------------------------------------------------------------------------
*MiniKeymap.map_multistep()*
`MiniKeymap.map_multistep`({mode}, {lhs}, {steps}, {opts})
Map multi-step action
Mapping of a multi-step action is an expression mapping (|:map-expression|).
Executing a multi-step action is essentially:
- Check condition for step one. If `true` - execute step one action and stop.
- Check condition for step two, and so on.
- If there is no more steps, fall back to returning mapped key.
For better user experience there are many built-in steps mostly designed
to create Insert mode "smart" mappings of <Tab>, <S-Tab>, <CR>, and <BS>.
Available built-in steps ("For key" is a suggestion, any can be used):
>
┌─────────────────────┬────────────────┬──────────────────────────┬─────────┐
│ Step name │ Condition │ Action │ For key │
├─────────────────────┴────────────────┴──────────────────────────┴─────────┤
< 8000 div>
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |ins-completion-menu| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ pmenu_next │ Pmenu visible │ Select next (as <C-n>) │ <Tab> │
│ pmenu_prev │ Pmenu visible │ Select prev (as <C-p>) │ <S-Tab> │
│ pmenu_accept │ Item selected │ Accept (as <C-y>) │ <CR> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.snippets| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ minisnippets_next │ Session active │ Jump to next tabstop │ <Tab> │
│ minisnippets_prev │ Session active │ Jump to prev tabstop │ <S-Tab> │
│ minisnippets_expand │ Can expand │ Expand snippet at cursor │ <Tab> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.pairs| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ minipairs_cr │ Module set up │ <CR> respecting pairs │ <CR> │
│ minipairs_bs │ Module set up │ <BS> respecting pairs │ <BS> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Jump around in Insert mode ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ jump_after_tsnode │ TS parser │ Jump after node end │ <Tab> │
│ jump_before_tsnode │ TS parser │ Jump before node start │ <S-Tab> │
│ jump_after_close │ Insert mode │ Jump after )]}"'` │ <Tab> │
│ jump_before_open │ Insert mode │ Jump before ([{"'` │ <S-Tab> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Work with whitespace ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ increase_indent │ Is on indent │ Increase indent │ <Tab> │
│ decrease_indent │ Is on indent │ Decrease indent │ <S-Tab> │
│ hungry_bs │ Space to left │ Delete all space to left │ <BS> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |vim.snippet| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ vimsnippet_next │ Session active │ Jump to next tabstop │ <Tab> │
│ vimsnippet_prev │ Session active │ Jump to prev tabstop │ <S-Tab> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'hrsh7th/nvim-cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ cmp_next │ Menu visible │ Select next item │ <Tab> │
│ cmp_prev │ Menu visible │ Select prev item │ <S-Tab> │
│ cmp_accept │ Item selected │ Accept selected item │ <CR> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'Saghen/blink.cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ blink_next │ Menu visible │ Select next item │ <Tab> │
│ blink_prev │ Menu visible │ Select prev item │ <S-Tab> │
│ blink_accept │ Item selected │ Accept selected item │ <CR> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'L3MON4D3/LuaSnip' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ luasnip_next │ Session active │ Jump to next tabstop │ <Tab> │
│ luasnip_prev │ Session active │ Jump to prev tabstop │ <S-Tab> │
│ luasnip_expand │ Can expand │ Expand snippet at cursor │ <Tab> │
├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'windwp/nvim-autopairs' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
│ nvimautopairs_cr │ Module present │ <CR> respecting pairs │ <CR> │
│ nvimautopairs_bs │ Module present │ <BS> respecting pairs │ <BS> │
└─────────────────────┴────────────────┴──────────────────────────┴─────────┘
<
Notes:
- Executing action has limitations of |:map-expression| (like not allowed text
or buffer changes, etc.). To execute complex lua code, use |vim.schedule()|
inside action, return the code as string in |:map-cmd| format, or return
a function to be later executed. See usage examples.
- Some mapped keys (like <Tab>, <CR>) might require disabling smart presets
in plugins (like `nvim-cmp`, `blink-cmp`, `nvim-autopairs`).
Parameters ~
{mode} `(string|table)` Same as for |vim.keymap.set()|.
{lhs} `(string)` Same as for |vim.keymap.set()|.
{steps} `(table)` Array of steps. Each step can be a string with the name
of built-in step or a table with two callable methods (will be called
without arguments):
- <condition> - return `true` if the action should be executed.
- <action> - action to be executed if <condition> returns `true`.
For more flexibility, it can also return a value which can be:
- String - will be returned as expression output. Can be something like
`"<Tab>"` (treat as <Tab> key) or `"<Cmd>lua vim.notify('Hello')<CR>"`.
Should not escape keycodes (i.e. return "<Tab>" and not "\t").
To undo already done escape, use |keytrans()|.
- Function - will be executed as if `"<Cmd>lua f()<CR>"`, but does not
need to create a global function for that.
- `false` - do not stop going through steps.
{opts} `(table|nil)` Same as for |vim.keymap.set()|.
Usage ~
See |MiniKeymap-examples| for practical examples.
Some illustrative examples: >lua
_G.log = {}
local steps = {}
steps[1] = {
condition = function() table.insert(_G.log, 'C1'); return _G.cond1 end,
-- Compute and return keys. Will be emulated as pressed.
action = function() table.insert(_G.log, 'A1'); return 'hello' end,
}
steps[2] = {
condition = function() table.insert(_G.log, 'C2'); return _G.cond2 end,
-- Perform action immediately, return `false` to keep asking other steps
action = function() table.insert(_G.log, 'A2'); return false end,
}
steps[3] = {
condition = function() table.insert(_G.log, 'C3'); return _G.cond3 end,
-- Perform action later (to overcom expression mapping limitations)
action = function()
table.insert(_G.log, 'A3_1')
return function() table.insert(_G.log, 'A3_2') end
end,
}
-- Make Insert mode <Tab> mapping
require('mini.keymap').map_multistep('i', '<Tab>', steps)
-- Pressing <Tab> inserts fallback `\t`; logs C1+C2+C3
_G.cond1, _G.cond2, _G.cond3 = false, false, false
-- Pressing <Tab> inserts `hello`; logs C1+A1
_G.cond1, _G.cond2, _G.cond3 = true, false, false
-- Pressing <Tab> inserts nothing; logs C1+C2+A2+C3+A3_1+A3_2
_G.cond1, _G.cond2, _G.cond3 = false, true, true
<
------------------------------------------------------------------------------
*MiniKeymap.gen_step*
`MiniKeymap.gen_step`
Generate step for multi-step mappings
< 8000 /div>
This is a table with function elements. Call to actually get a step.
------------------------------------------------------------------------------
*MiniKeymap.gen_step.search_pattern()*
`MiniKeymap.gen_step.search_pattern`({pattern}, {flags}, {opts})
Search pattern step
Use |search()| to jump to pattern match. Possibly adjust final position to
be just to the right of the match (useful in Insert mode).
Parameters ~
{pattern} `(string)` Same as for |search()|.
{flags} `(string|nil)` Same as for |search()|.
{opts} `(table|nil)` Options. Possible fields:
- <side> `(string)` - one of `"before"` (default) or `"after"`.
- <stopline> `(number|function)` - forwarded to |search()| (as number or
as function's output after calling it before every search).
- <timeout> `(number)` - forwarded to |search()|.
- <skip> `(string|function)` - forwarded to |search()|.
Return ~
`(table)` Step which searches pattern.
Usage ~
Built-in |MiniKeymap.map_multistep()| steps "jump_after_close" and
"jump_before_open" use this, but only in Insert mode.
Steps that jump before/after all consecutive brackets in several modes: >lua
local keymap = require('mini.keymap')
local tab_step_insert = keymap.gen_step.search_pattern(
-- Need to use 'c' flag and 'after' side for robust "chaining"
[=[[)\]}]\+]=], 'ceW', { side = 'after' }
)
keymap.map_multistep('i', '<Tab>', { tab_step_insert })
local tab_step = keymap.gen_step.search_pattern([=[[)\]}]\+]=], 'eW')
keymap.map_multistep({ 'n', 'x' }, '<Tab>', { tab_step })
local stab_step = keymap.gen_step.search_pattern([=[[(\[{]\+]=], 'bW')
keymap.map_multistep({ 'i', 'n', 'x' }, '<S-Tab>', { stab_step })
<
------------------------------------------------------------------------------
*MiniKeymap.map_combo()*
`MiniKeymap.map_combo`({mode}, {lhs}, {action}, {opts})
Map combo post action
Create a combo: sequence of keys where each acts immediately plus execute
an extra action if all are typed within configurable delay between each other.
Example for Insert mode "better escape" `jk` combo with `<BS><BS><Esc>` action:
- Press `j`. It is visible immediately without any side effects.
- Quickly (no more than default 200 ms after) press `k`. This triggers the
action which is equivalent to typing <BS><BS> (delete already present `jk`)
and <Esc> to exit into Normal mode.
Notes:
- IMPORTANT! Combo is not a regular mapping but a separate key tracking
with |vim.on_key()|. This is important as combos will not be visible and
can not be managed as regular mappings. Instead each combo is associated
with a dedicated |namespace| (named for human readability). However, it is not
really expected to manage them on the fly after they are created.
- String action is executed with |nvim_input()|, i.e. emulated keys will
respect custom mappings.
- Different combos are tracked and act independent of each other. For example,
if there are combos for `jjk` and `jk` keys, fast typing `jjk` will execute both.
- Neovim>=0.11 is recommended due to |vim.on_key()| improvement to allow
watching for keys as they are typed and not as if coming from mappings.
For example, this matters when creating a `jk` combo for Visual mode while
also having `xnoremap j gj` style of remaps. On Neovim<0.11 the fix is to
use `gjgk` as combo's left hand side.
- Each combo adds very small but non-zero overhead on each keystroke.
Usually about 1-3 microseconds (i.e. 0.001-0.003 ms), which should be
fast enough for most setups. For a "normal, real world" coding session
with a total of ~20000 keystrokes it results in extra ~40ms of overhead
for a single created combo. Create many combos with caution.
Parameters ~
{mode} `(string|table)` String or array of string mode id (like "n", "i", etc.).
Array of several modes is more performant than several single mode combos.
{lhs} `(string|table)` String with tracked key sequence or an array of
tracked keys (one element - one key).
{action} `(string|function)` Action to perform after key sequence is detected.
If string, treated as keys and emulated with |nvim_input()|.
If function, executed in |vim.schedule()|. Can return string keys which will
be emulated.
{opts} `(table|nil)` Options. Possible fields:
- <delay> `(number)` - delay in milliseconds within which keys should be
pressed to detect a key sequence. Default: 200.
Usage ~
See |MiniKeymap-examples| for practical examples.
Some illustrative examples: >lua
local map_combo = require('mini.keymap').map_combo
-- In Insert mode pressing `x` followed by `x` within 1 second logs 'A'
-- and emulates extra pressing of `yy`
_G.log = {}
local action = function() table.insert(_G.log, 'A'); return 'yy' end
map_combo('i', 'xx', action, { delay = 1000 })
<
vim:tw=78:ts=8:noet:ft=help:norl:
0