liangxianzhe/nap.nvim

github github
motion
stars 100
issues 1
subscribers 5
forks 5
CREATED

2023-02-06

UPDATED

last year


nap.nvim (next and previous)

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.

TLDR

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.

Operators

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
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" } }
    },

Add new operator

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

Helper functions are provided for the following plugins to save your time:

-- The provided implementation falls back to ]c [c in diff mode.
require("nap").map('c', require("nap").gitsigns())
require("nap").map('o', require("nap").aerial())
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.

Install and config

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 support C-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.

Credits