What
Add a <leader>T keymap that opens a floating terminal window. Unlike <leader>, (which opens a new split terminal each time), this terminal is created once and toggled — hidden when not in focus, restored to the same shell session when recalled.
Where
lua/config/options.lua — alongside the existing terminal keymaps (<leader>, on line 21, <Esc><Esc> exit on line 20).
Why it matters
The current setup has two terminal entry points: :te / tabe | te for full-tab terminals, and <leader>, for a 15-line split. Both create a new shell each time, losing working directory and shell history. The tabline timer already tracks foreground processes per-terminal PID, so a persistent float would integrate naturally. A single scratch terminal (think VS Code's integrated terminal) is the common "quick command" pattern that the current split-terminal approach partially covers but doesn't persist.
Recommended implementation
local scratch_term = { buf = nil, win = nil }
local function toggle_scratch_terminal()
-- if window is open, hide it
if scratch_term.win and vim.api.nvim_win_is_valid(scratch_term.win) then
vim.api.nvim_win_close(scratch_term.win, false)
scratch_term.win = nil
return
end
-- create buffer once
if not scratch_term.buf or not vim.api.nvim_buf_is_valid(scratch_term.buf) then
scratch_term.buf = vim.api.nvim_create_buf(false, false)
vim.api.nvim_buf_call(scratch_term.buf, function()
vim.fn.termopen(vim.o.shell, {
on_exit = function()
scratch_term.buf = nil
scratch_term.win = nil
end,
})
end)
end
local ui = vim.api.nvim_list_uis()[1] or { width = 120, height = 40 }
local width = math.floor(ui.width * 0.8)
local height = math.floor(ui.height * 0.7)
scratch_term.win = vim.api.nvim_open_win(scratch_term.buf, true, {
relative = "editor",
width = width,
height = height,
row = math.floor((ui.height - height) / 2),
col = math.floor((ui.width - width) / 2),
border = "single",
style = "minimal",
title = " scratch terminal ",
})
vim.cmd("startinsert")
end
vim.keymap.set({ "n", "t" }, "<leader>T", toggle_scratch_terminal, { desc = "Toggle scratch terminal" })
The on_exit callback clears the stale refs so the next toggle creates a fresh terminal rather than trying to reopen a dead buffer.
Trade-offs
- The terminal persists for the Neovim session lifetime; exit it explicitly (
exit or <C-d>) to free the shell process.
<leader>T in terminal mode conflicts with nothing in the current config (checked against all existing t-mode mappings: only <Esc><Esc> is set).
- The
FileTree module (lua/config/filetree.lua) already demonstrates the pattern (reusable float with toggle), so the implementation is well-understood.
What
Add a
<leader>Tkeymap that opens a floating terminal window. Unlike<leader>,(which opens a new split terminal each time), this terminal is created once and toggled — hidden when not in focus, restored to the same shell session when recalled.Where
lua/config/options.lua— alongside the existing terminal keymaps (<leader>,on line 21,<Esc><Esc>exit on line 20).Why it matters
The current setup has two terminal entry points:
:te/tabe | tefor full-tab terminals, and<leader>,for a 15-line split. Both create a new shell each time, losing working directory and shell history. The tabline timer already tracks foreground processes per-terminal PID, so a persistent float would integrate naturally. A single scratch terminal (think VS Code's integrated terminal) is the common "quick command" pattern that the current split-terminal approach partially covers but doesn't persist.Recommended implementation
The
on_exitcallback clears the stale refs so the next toggle creates a fresh terminal rather than trying to reopen a dead buffer.Trade-offs
exitor<C-d>) to free the shell process.<leader>Tin terminal mode conflicts with nothing in the current config (checked against all existingt-mode mappings: only<Esc><Esc>is set).FileTreemodule (lua/config/filetree.lua) already demonstrates the pattern (reusable float with toggle), so the implementation is well-understood.