leolaurindo/tunnelvision.nvim

github github
color
stars 25
issues 0
subscribers 0
forks 0
CREATED

UPDATED


tunnelvision.nvim

Neovim License: MIT

Focus on one thing at a time.

TunnelVision dims unrelated lines and keeps attention on the targeted symbol.

TunnelVision screenshot

Requirements

  • Neovim >= 0.9
  • Optional (recommended):
    • Tree-sitter for better scope detection
    • LSP with documentHighlight

Installation

{
  "leolaurindo/tunnelvision.nvim",
  opts = {},
}
vim.pack.add({ "https://github.com/leolaurindo/tunnelvision.nvim" })
require("tunnelvision").setup()

vim.pack is Neovim's built-in plugin manager in newer versions, and it is still experimental upstream.

MiniDeps.add({ source = "leolaurindo/tunnelvision.nvim" })
require("tunnelvision").setup()
use({
  "leolaurindo/tunnelvision.nvim",
  config = function()
    require("tunnelvision").setup()
  end,
})

Quick start

  1. Call require("tunnelvision").setup() so the :TunnelVision command is registered.
  2. Put the cursor on a symbol.
  3. Run :TunnelVision on.
  4. Jump with :TunnelVision next and :TunnelVision prev.
  5. Run :TunnelVision off.

Commands

:TunnelVision on|retarget|off|toggle|next|prev|refresh|status
:TunnelVision mode [static|dynamic|flow]
:TunnelVision scope [function|buffer]
:TunnelVision source [lsp_else_word|lsp|lsp_and_word|word]
:TunnelVision direction [forward|both]

Run :help tunnelvision for full command and option reference.

Modes

  • static (default): track the symbol selected on activation.
  • dynamic: retarget as the cursor moves.
  • flow: experimental mode that expands to assignment-related lines to follow value flow.

scope = "function" uses Tree-sitter when available, otherwise TunnelVision falls back to the full buffer.

source = "lsp_else_word" is the default and works well as a general setting.

Configuration

Defaults

Use setup() to define the persistent defaults used by :TunnelVision on, on(), and runtime commands such as :TunnelVision scope buffer.

require("tunnelvision").setup({
  mode = "static",
  scope = "function",
  source = "lsp_else_word",
})

The default config will essentially resolve to your colorscheme Comment color. Set dim when you want to choose the color or style used for dimmed lines yourself:

require("tunnelvision").setup({
  dim = { fg = "#565f89", italic = true },
})

One-shot activations

Use one-shot overrides when you want a specific keymap or command to activate with different behavior without changing those defaults:

require("tunnelvision").on({ scope = "buffer", source = "word" })

This makes it easy to keep a stable default, such as LSP-first matching in the current function, while adding focused alternatives like plain word matching across the full buffer.

Options

These options can be set as persistent defaults in setup(). Core behavior and appearance options such as mode, scope, source, direction, and dim can also be passed to on(opts) for one-shot activations.

Option Default Notes
mode static dynamic retargets as you move; flow is experimental.
direction forward Flow mode only. Use both to include backward influence.
scope function Uses the nearest function-like scope when Tree-sitter is available.
source lsp_else_word LSP first, then word matching when LSP data is unavailable.
fallback_warn once Controls fallback warnings for lsp_else_word.
extra_keywords {} Extra identifiers to ignore in flow analysis.
lsp_timeout_ms 150 Timeout for async LSP documentHighlight requests.
dim nil Optional color/style definition for dimmed lines. Defaults to the Comment foreground.
dim_hl TunnelVisionDim Highlight group used for dimmed lines.
max_dim_lines 6000 Skip dimming in very large buffers.
notify true Enable plugin notifications.

Run :help tunnelvision-config for the full option reference.

Suggested keymaps

local tv = require("tunnelvision")

vim.keymap.set("n", "<leader>v", "<cmd>TunnelVision on<CR>", { desc = "TunnelVision on" })
-- or vim.keymap.set("n", "<leader>v", "<cmd>TunnelVision toggle<CR>", { desc = "TunnelVision toggle" })
vim.keymap.set("n", "]v", "<cmd>TunnelVision next<CR>", { desc = "TunnelVision next" })
vim.keymap.set("n", "[v", "<cmd>TunnelVision prev<CR>", { desc = "TunnelVision prev" })
vim.keymap.set("n", "<Esc>", function()
  if tv.is_active() then
    tv.off()
    return ""
  end
  return "<Esc>"
end, { expr = true, silent = true, desc = "TunnelVision off on Esc" })

-- as an example: a different activation as one-shot
vim.keymap.set("n", "<leader>V", function()
  tv.on({ scope = "buffer", source = "word" })
end, { desc = "TunnelVision word in buffer" })

Health

  • :checkhealth tunnelvision

Contributing

Feel free to contribute.

Just make sure to:

  • include your rationale
  • update the documentation
  • update CHANGELOG.md

Other approaches