SkillAgentSearch skills...

Detour.nvim

Use popup windows to navigate files/buffer and to contain shells/TUIs

Install / Use

/learn @carbon-steel/Detour.nvim
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

detour.nvim

It's a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there's no knowing where you might be swept off to.

<div dir="rtl"> J.R.R. Tolkien, The Lord of the Rings </div> </br></br>

detour.nvim provides commands to open floating windows that position and shape themselves.

Never lose your spot!📍🗺️

| What does detour.nvim do? | | | :--: | :--: | | :Detour/require('detour').Detour() <br />opens a floating window<br />over all current windows | detour | | :DetourCurrentWindow/<br />require('detour').DetourCurrentWindow()<br />opens a floating window over<br />only the current window | detour2 | | Works with Neovim's :split/:vsplit/<C-w>s/<C-w>v/<C-w>T commands | split | | You can nest detour popups | nest |

Neovim's floating windows are a great utility to use in plugins and functions, but they cannot be used manually. This is because creating floats is not simple like calling :split or :vsplit. vim.api.nvim_open_win(...) requires coordinates and dimensions to make a float which is too tedious to do by hand.

Detour.nvim brings a single new feature to Neovim: detour windows (aka detours). Detours are floating windows with the ease-of-use of splits.

Detours will make sure not to overlap each other unless when a detour is nested within another.

Example keymaps

detour.nvim is designed as a utility library for keymaps people can write on their own.

NOTE If you'd like to share a keymap you made, please submit it in a github issue and we'll include it in the examples directory!

Here are a few basic examples...

Open your Neovim config

vim.keymap.set("n", "<leader>e", function()
	-- Open detour
	if not require("detour").Detour() then
		return
	end
	vim.cmd.edit(vim.fn.stdpath("config")) -- open Neovim config directory
end)

Screencast from 2025-09-11 07-37-45.webm

Jump to definition in detour

vim.keymap.set("n", "<leader>gd", function()
	-- Open detour with the same buffer
	if not require("detour").Detour() then
		return
	end
	vim.lsp.buf.definition() -- jump to definition
end)

Screencast from 2025-09-13 18-57-09.webm

Wrap a TUI: top

You can wrap any TUI in a detour. Here is an example.

Run top in a detour:

vim.keymap.set("n", "<leader>p", function()
	local window_id = require("detour").Detour() -- open a detour
	if not window_id then
		return
	end

	vim.cmd.terminal("top") -- open a terminal buffer
	vim.bo.bufhidden = "delete" -- close the terminal when window closes
	vim.wo[window_id].signcolumn = "no" -- In Neovim 0.10, the signcolumn can push the TUI a bit out of window

	-- It's common for people to have `<Esc>` mapped to `<C-\><C-n>` for terminals.
	-- This can get in the way when interacting with TUIs.
	-- This maps the escape key back to itself (for this buffer) to fix this problem.
	vim.keymap.set("t", "<Esc>", "<Esc>", { buffer = true })

	vim.cmd.startinsert() -- go into insert mode

	vim.api.nvim_create_autocmd({ "TermClose" }, {
		buffer = vim.api.nvim_get_current_buf(),
		callback = function()
			-- This automated keypress skips for you the "[Process exited 0]" message
			-- that the embedded terminal shows.
			vim.api.nvim_feedkeys("i", "n", false)
		end,
	})
end)

|| | :--: | | Use keymap above -> Close window | top

Installation

Lazy.nvim

{ "carbon-steel/detour.nvim",
    config = function ()
        require("detour").setup({
            -- Put custom configuration here
        })
        vim.keymap.set('n', '<c-w><enter>', ":Detour<cr>")
        vim.keymap.set('n', '<c-w>.', ":DetourCurrentWindow<cr>")

        local detour_moves = require("detour.movements")
        -- NOTE: While using `detour_moves` is not required to use this
        -- plugin, it is strongly recommended as it makes window navigation
        -- much more intuitive.
        --
        -- The following keymaps are drop in replacements for Vim's regular
        -- window navigation commands. These replacements allows you to
        -- skip over windows covered by detours (which is a much more
        -- intuitive motion) but are otherwise the same as normal window
        -- navigation.
        --
        -- This is an example set of keymaps, but if you use other keys to
        -- navigate windows, changes these keymaps to suit your situation.
        vim.keymap.set({ "n", "t" }, "<C-j>", detour_moves.DetourWinCmdJ)
        vim.keymap.set({ "n", "t" }, "<C-w>j", detour_moves.DetourWinCmdJ)
        vim.keymap.set({ "n", "t" }, "<C-w><C-j>", detour_moves.DetourWinCmdJ)

        vim.keymap.set({ "n", "t" }, "<C-h>", detour_moves.DetourWinCmdH)
        vim.keymap.set({ "n", "t" }, "<C-w>h", detour_moves.DetourWinCmdH)
        vim.keymap.set({ "n", "t" }, "<C-w><C-h>", detour_moves.DetourWinCmdH)

        vim.keymap.set({ "n", "t" }, "<C-k>", detour_moves.DetourWinCmdK)
        vim.keymap.set({ "n", "t" }, "<C-w>k", detour_moves.DetourWinCmdK)
        vim.keymap.set({ "n", "t" }, "<C-w><C-k>", detour_moves.DetourWinCmdK)

        vim.keymap.set({ "n", "t" }, "<C-l>", detour_moves.DetourWinCmdL)
        vim.keymap.set({ "n", "t" }, "<C-w>l", detour_moves.DetourWinCmdL)
        vim.keymap.set({ "n", "t" }, "<C-w><C-l>", detour_moves.DetourWinCmdL)

        vim.keymap.set({ "n", "t" }, "<C-w>w", detour_moves.DetourWinCmdW)
        vim.keymap.set({ "n", "t" }, "<C-w><C-w>", detour_moves.DetourWinCmdW)

    end
},

Options

| Option | Description | Default value | | -- | -- | -- | | title | "path" sets the path of the current buffer as the title of the float. "none" sets no title. | "path" |

Advanced

Using detours can be simple, but they also come with features for power users:

  • require("detour.features").UncoverWindow: Update all detours to uncover a given regular window
  • require("detour.features").UncoverWindowWithMouse: Same as above but select which window to uncover with the mouse
  • require("detour.features").HideAllDetours/RevealAllDetours: Hide and reveal all detours so you can see the windows behind them
  • require("detour.features").CloseCurrentStack: Closes the current detour along with all detours it is nested within

Development

  • Build help docs: run make help from the repo root.
    • Requires lemmy-help in your PATH (repo).
    • Optional: Neovim available for generating helptags (target does not fail if absent).
  • Run test: run make test from the repo root
    • Requires docker

FAQ

I want to convert detours to splits or tabs.

<C-w>s and <C-w>v can be used from within a popup to create splits. <C-w>T creates tabs.

My LSP keeps moving my cursor to other windows.

If your LSP movements (ex: go-to-definition) are opening locations in other windows, make sure that reuse_win is set to false.

My floating windows don't look good.

Some colorschemes don't have visually clear floating window border colors. Consider customizing your colorscheme's FloatBorder to a color that makes your floating windows clearer.

My TUI is slightly wider than the floating window it's in.

This is something I noticed happening when I upgraded to Neovim 0.10. After you create your detour floating window, make sure to turn off signcolumn.

vim.opt.signcolumn = "no"
View on GitHub
GitHub Stars169
CategoryDevelopment
Updated25d ago
Forks6

Languages

Lua

Security Score

100/100

Audited on Mar 4, 2026

No findings