Skip to content

Floating TUI Tools in Neovim

Floating terminal windows for TUI tools, powered by Snacks.terminal (bundled with LazyVim).

How It Works

All TUI keymaps live in lua/plugins/floating-tui.lua. Each tool is a single Snacks.terminal.toggle(cmd, opts) call — no custom Lua module needed. Snacks handles:

  • Floating window lifecycle (create, show, hide, resize)
  • Terminal session persistence (hide with q, reopen with same keymap)
  • Double-Esc to exit terminal insert mode
  • Auto-cleanup when the process exits

This is the same mechanism behind <leader>gg (LazyGit via Snacks.lazygit()).

Default Keymaps

Keymap Tool Category
<leader>gg LazyGit Git (LazyVim built-in)
<leader>zg gh dash Git / GitHub
<leader>zs sqlit Database
<leader>fy yazi File Manager
<leader>zb btop System Monitor
<leader>zd lazydocker Container
<leader>zi ipython REPL

Inside a floating TUI window:

  • Double-Esc — exit terminal insert mode (back to normal mode)
  • q (normal mode) — hide the window, process keeps running
  • Same keymap again — reopen the hidden window

For the managed gh-dash / diffnav / lazygit setup behind <leader>zg, see Git Diff Workflow.

Adding a New TUI

Add an entry to the keys table in lua/plugins/floating-tui.lua:

{
  "<leader>zX",
  function()
    Snacks.terminal.toggle("mytool", {
      win = { title = " mytool " },
    })
  end,
  desc = "MyTool",
},

Common Options

Snacks.terminal.toggle(cmd, {
  cwd = vim.uv.cwd(),          -- working directory
  cwd = LazyVim.root.git(),    -- or use git root
  env = { FOO = "bar" },       -- environment variables
  auto_close = false,           -- keep window after process exits (for short-lived tools)
  win = {
    title = " tool name ",      -- floating window title
    width = 0.9,                -- 0-1 = ratio, >1 = columns
    height = 0.9,
    border = "rounded",         -- "rounded", "double", "single", "none"
    position = "float",         -- "float" (default for cmd), "bottom", "left", "right"
  },
})

Multi-word Commands

Pass a table for commands with arguments:

Snacks.terminal.toggle({ "gh", "dash" }, { ... })
Snacks.terminal.toggle({ "psql", "postgres://localhost/mydb" }, { ... })

Tools That Exit Quickly

Some tools (like sqlit) may exit and show [Process exited 0]. Set auto_close = false to keep the window visible so you can inspect output. The next toggle after closing will create a fresh instance.

Tools with Vim-like Keybindings

Tools that use Esc internally (like sqlit's vim mode) work fine with Snacks' double-Esc timer — a single Esc goes to the TUI, pressing Esc again within 200ms exits terminal insert mode.

Tools That Use q to Quit

By default, Snacks maps q in normal mode to hide the floating window (process keeps running). However, some TUI tools (like sqlit) use q as their own quit command, which terminates the process.

The conflict: if you Double-Esc back to Neovim normal mode and press q, Snacks hides the window — but if you press q while still in terminal insert mode, the TUI receives it and may exit the process entirely.

Solution: Remap the Snacks hide key to <C-q> for these tools, so q is never intercepted by Snacks:

Snacks.terminal.toggle("sqlit", {
  win = {
    title = " sqlit ",
    keys = {
      q = false,                              -- disable default q-to-hide
      hide = { "<C-q>", "hide", mode = "n" }, -- use Ctrl-q to hide instead
    },
  },
  auto_close = false,
})

Workflow for these tools: - Double-Esc — exit terminal insert mode - Ctrl-q (normal mode) — hide the window, process keeps running - Same keymap (e.g. <leader>zs) — reopen the hidden window

This pattern applies to any TUI tool where q has special meaning (e.g. database clients, interactive viewers).

When to Use a Dedicated Plugin Instead

For most TUI tools, Snacks.terminal.toggle is sufficient. Consider a dedicated plugin when you need:

  • Deep Neovim integration — e.g. Snacks.lazygit() auto-configures colorscheme themes and nvim-remote editing
  • File selection callbacks — e.g. yazi.nvim can open selected files in Neovim buffers
  • Output parsing / RPC — tools that need to send structured data back to Neovim
Tool Generic (Snacks) Dedicated Plugin
lazygit OK Snacks.lazygit() (built-in, recommended)
yazi OK for browsing yazi.nvim if you need file-open callbacks
gh dash OK gh-dash.nvim if used daily
btop, htop, k9s, etc. Recommended N/A