Quickly jump between next and previous NeoVim buffer, tab, file, quickfix, diagnostic, etc.
A lightweight plugin inspired by unimpaired.vim, but:
- 🌱 Focus on navigation, not editing or option toggling.
- 🚀 Jump back and forth easily with a single key, instead of two keys.
Use b
(buffer) as an example:
]b
/[b
jump to next/previous buffer. Then just pressing<c-n><c-n><c-n><c-p><c-p>...
to cycle through buffers.]B
/[B
jump to last/first buffer.
Operator | Description |
---|---|
a, A | Tab |
b, B | Buffer |
d | Diagnostic |
e | Edit (Change list) |
f, F | File |
l, L, C-l, M-l | Location list |
q, Q, C-q, M-q | Quickfix |
s | Spell |
t, T, C-t | Tag |
z | Fold |
' | Mark |
Expand to see how they are defined.
operators = {
["a"] = {
next = { rhs = "<cmd>tabnext<cr>", opts = { desc = "Next tab" } },
prev = { rhs = "<cmd>tabprevious<cr>", opts = { desc = "Prev tab" } },
},
["A"] = {
next = { rhs = "<cmd>tablast<cr>", opts = { desc = "Last tab" } },
prev = { rhs = "<cmd>tabfirst<cr>", opts = { desc = "First tab" } },
},
["b"] = {
next = { rhs = "<cmd>bnext<cr>", opts = { desc = "Next buffer" } },
prev = { rhs = "<cmd>bprevious<cr>", opts = { desc = "Prev buffer" } },
},
["B"] = {
next = { rhs = "<cmd>blast<cr>", opts = { desc = "Last buffer" } },
prev = { rhs = "<cmd>bfirst<cr>", opts = { desc = "First buffer" } },
},
["d"] = {
next = { rhs = vim.diagnostic.goto_next, opts = { desc = "Next diagnostic" } },
prev = { rhs = vim.diagnostic.goto_prev, opts = { desc = "Prev diagnostic" } },
mode = { "n", "v", "o" }
},
["e"] = {
next = { rhs = "g;", opts = { desc = "Older edit (change-list) item" } },
prev = { rhs = "g,", opts = { desc = "Newer edit (change-list) item" } }
},
["f"] = {
next = { rhs = M.next_file, opts = { desc = "Next file" } },
prev = { rhs = M.prev_file, opts = { desc = "Prev file" } },
},
["F"] = {
next = { rhs = M.last_file, opts = { desc = "Last file" } },
prev = { rhs = M.first_file, opts = { desc = "First file" } },
},
["l"] = {
next = { rhs = "<cmd>lnext<cr>", opts = { desc = "Next loclist item" } },
prev = { rhs = "<cmd>lprevious<cr>", opts = { desc = "Prev loclist item" } }
},
["L"] = {
next = { rhs = "<cmd>llast<cr>", opts = { desc = "Last loclist item" } },
prev = { rhs = "<cmd>lfirst<cr>", opts = { desc = "First loclist item" } }
},
["<C-l>"] = {
next = { rhs = "<cmd>lnfile<cr>", opts = { desc = "Next loclist item in different file" } },
prev = { rhs = "<cmd>lpfile<cr>", opts = { desc = "Prev loclist item in different file" } }
},
["<M-l>"] = {
next = { rhs = "<cmd>lnewer<cr>", opts = { desc = "Next loclist list" } },
prev = { rhs = "<cmd>lolder<cr>", opts = { desc = "Prev loclist list" } }
},
["q"] = {
next = { rhs = "<cmd>cnext<cr>", opts = { desc = "Next quickfix item" } },
prev = { rhs = "<cmd>cprevious<cr>", opts = { desc = "Prev quickfix item" } }
},
["Q"] = {
next = { rhs = "<cmd>clast<cr>", opts = { desc = "Last quickfix item" } },
prev = { rhs = "<cmd>cfirst<cr>", opts = { desc = "First quickfix item" } }
},
["<C-q>"] = {
next = { rhs = "<cmd>cnfile<cr>", opts = { desc = "Next quickfix item in different file" } },
prev = { rhs = "<cmd>cpfile<cr>", opts = { desc = "Prev quickfix item in different file" } }
},
["<M-q>"] = {
next = { rhs = "<cmd>cnewer<cr>", opts = { desc = "Next quickfix list" } },
prev = { rhs = "<cmd>colder<cr>", opts = { desc = "Prev quickfix list" } }
},
["s"] = {
next = { rhs = "]s", opts = { desc = "Next spell error" } },
prev = { rhs = "[s", opts = { desc = "Prev spell error" } },
mode = { "n", "v", "o" },
},
["t"] = {
next = { rhs = "<cmd>tnext<cr>", opts = { desc = "Next tag" } },
prev = { rhs = "<cmd>tprevious<cr>", opts = { desc = "Prev tag" } }
},
["T"] = {
next = { rhs = "<cmd>tlast<cr>", opts = { desc = "Last tag" } },
prev = { rhs = "<cmd>tfirst<cr>", opts = { desc = "First tag" } }
},
["<C-t>"] = {
next = { rhs = "<cmd>ptnext<cr>", opts = { desc = "Next tag in previous window" } },
prev = { rhs = "<cmd>ptprevious<cr>", opts = { desc = "Prev tag in previous window" } }
},
["z"] = {
next = { rhs = "zj", opts = { desc = "Next fold" } },
prev = { rhs = "zk", opts = { desc = "Prev fold" } },
mode = { "n", "v", "o" },
},
["'"] = {
next = { rhs = "]`", opts = { desc = "Next lowercase mark" } },
prev = { rhs = "[`", opts = { desc = "Prev lowercase mark" } }
},
You can add/override operators easily, for example:
require("nap").map("o", {
next = { rhs = "<cmd>AerialNext<cr>", opts = { desc = "Next outline symbol" } },
prev = { rhs = "<cmd>AerialPrev<cr>", opts = { desc = "Prev outline symbol" } },
mode = { "n", "v", "o" },
})
Under hood, this plugin calls vim.keymap.set
to define two keybindings for you, see its doc about
rhs
and opts
.
Helper functions are provided for the following plugins to save your time:
- With Gitsigns
-- The provided implementation falls back to ]c [c in diff mode.
require("nap").map('c', require("nap").gitsigns())
- With Aerial
require("nap").map('o', require("nap").aerial())
- With vim-illuminate
require("nap").map('r', require("nap").illuminate())
You can also add/remove operators inside setup call if you prefer to put them in a central place, see next section.
Add liangxianzhe/nap-nvim
to your plugin manager. Call require("nap").setup()
to use defaults:
require("nap").setup({
next_prefix = "]",
prev_prefix = "[",
next_repeat = "<c-n>",
prev_repeat = "<c-p>",
-- to exclude some keys from the default
exclude_default_operators = {"a", "A"},
-- to add custom keys
operators = {
...
},
})
We need two pairs of keys: prefix
keys to trigger the first jump, and repeat
keys to repeat with
a single press.
The best config for you depends on many factors. Here are a few examples, feel free to try it out:
]
and[
(":help ]" to check default mappings)<C-n>
and<C-p>
<Enter>
and<C-Enter>
(Some terminal doesn't supportC-Enter
)<Enter>
and\
(If you remap leader key, the original leader key is near Enter)<Space>
and<C-Space>
;
and,
(use flash.nvim, flit.nvim or similar plugins to free these two keys)>
and<
(":help >" to check default mappings)- Some
Alt
prefixed keys (Need terminal supports)
Technically you can set prefix
and repeat
to the same key (e.g. ]
). It has one issue that when
pressing ]
to repeat jump, vim will need to wait
timeoutlen to determine whether its is ]
or ]b
.