- It lets you keep reusable terminals around and switch between bottom layouts, right-side layouts, and dedicated terminal tabpages.
- It is designed for users who want fast terminal access without giving up their current editor split layout.
- After daily use and substantial implementation changes to fit a personal workflow, it changed enough from CRAG666/betterTerm.nvim to become its own standalone plugin.
- Neovim (>= 0.10)
- With Lazy
{
"luckpoint/termlayout.nvim",
opts = {
-- your options
},
}The repository includes a dependency-free headless Neovim E2E suite under tests/e2e/.
- Run the full suite:
./tests/e2e/run.sh - Run a single spec by basename:
./tests/e2e/run.sh ui_stubs - Run a specific file:
./tests/e2e/run.sh tests/e2e/specs/winbar_termrequest_spec.lua - Override the Neovim binary when needed:
NVIM_BIN=/path/to/nvim ./tests/e2e/run.sh
The runner starts a fresh headless Neovim process for each spec, so terminal state, layout state, and UI stubs stay isolated between cases.
open(id?, opts?): Open, focus, create, or hide a terminal.idcan be a global terminal index or buffer name. Defaults to0.opts.cwdsets the working directory for a new terminal.select(): Open a terminal picker. Includes aNewentry. Selecting a hidden terminal from a terminal window replaces the current terminal pane.rename(new_name?): Rename the current terminal. Prompts whennew_nameis omitted.toggle_termwindow(): Toggle between the current editor-only view and the previously used terminal layout. Falls back tohorizontal_single.layout(name): Switch to a preset layout.layout_select(): Open a layout picker.layout_toggle(): Show or hide the active layout.
close(id?): Close a terminal by global terminal index or buffer name. Defaults to0.send(command, index?, press?): Send a command to a terminal. Omittingindextargets terminal0.press.interruptsends<C-c>first,press.cleansends<C-l>first.send_prompt(index?, opts?): Open a 3-line floating input, then send the submitted command to terminal0by default.<C-j>and<S-CR>insert a newline. If the last line is blank, one extra<CR>is sent after 1 second.cycle(shift?): Move focus left or right among displayed terminals. Defaults to1.focus_visible(display_index): Focus a currently visible terminal by its 1-based UI index. Returnstrueon success.layout_info(): Return the current layout state as a table withname,visible,slots, andwinids.toggle_tabs(): Toggle the terminal winbar labels outside preset layouts.
| Pattern | Slots | Description |
|---|---|---|
editor |
0 | Editor only, hide the terminal preset |
horizontal_single |
1 | Keep the current editor layout and show one terminal at the bottom |
vertical_single |
1 | Keep the current editor layout and show one terminal in a right-side column |
horizontal_split |
2 | Keep the current editor layout and show two terminals side by side at the bottom |
horizontal_triple |
3 | Keep the current editor layout and show three terminals side by side at the bottom |
vertical_split |
2 | Keep the current editor layout and show two terminals stacked in a right-side column |
vertical_triple |
3 | Keep the current editor layout and show three terminals stacked in a right-side column |
quad |
4 | Open a dedicated 2x2 terminal workspace in a separate tabpage |
fullscreen |
1 | Open a dedicated fullscreen terminal in a separate tabpage |
| Layout | Layout | Layout |
|---|---|---|
editor![]() |
horizontal_single![]() |
vertical_single![]() |
horizontal_split![]() |
horizontal_triple![]() |
vertical_split![]() |
vertical_triple![]() |
quad![]() |
fullscreen![]() |
:TermLayout <name>- Switch to a layout (tab-completion supported):TermLayoutToggle- Toggle layout visibility:TermLayoutSelect- Open a layout picker
No keymaps are set by default. A minimal setup looks like this:
local tl = require("termlayout")
vim.keymap.set({ "n", "t" }, "<C-;>", tl.open, { desc = "Toggle terminal" })
vim.keymap.set("n", "<leader>tt", tl.select, { desc = "Select terminal" })
vim.keymap.set("n", "<leader>tp", tl.layout_select, { desc = "Select layout" })
vim.keymap.set("n", "<leader>tl", tl.layout_toggle, { desc = "Toggle layout" })
vim.keymap.set("n", "<leader>tw", tl.toggle_termwindow, { desc = "Toggle terminal workspace" })
for n = 1, 9 do
vim.keymap.set({ "n", "t" }, "<leader>ji" .. n, function()
tl.send_prompt(n - 1)
end, { desc = "Send command to terminal " .. n })
endAdd direct mappings for specific layouts only if you use them frequently, for example horizontal_split, vertical_split, or quad.
You can configure the plugin by passing a table to the setup function.
-- Example configuration
require('termlayout').setup {
vertical_size = 20,
horizontal_size = math.floor(vim.o.columns / 2),
}vertical_size(number, default:vim.o.lines / 2): Height used for bottom terminal layouts and bottom terminal windows.horizontal_size(number, default:vim.o.columns / 2): Width used for right-side terminal layouts and narrow terminal windows.show_tabs(boolean, default:true): Enable/Disable the tabs bar.new_tab_mapping(string, default:<C-t>): Mapping to create a new terminal from within a terminal buffer.label_hl(string, default:TabLineSel): Highlight group for the terminal label shown in the winbar.
Terminal IDs are fixed to start at 0. The winbar and picker labels remain 1-based.
sizehas been replaced byvertical_sizeandhorizontal_size.index_basehas been removed. Terminal IDs always start at0.active_tab_hlhas been renamed tolabel_hl.inactive_tab_hlhas been removed because it was unused.- Old layout names
single,horizontal-split, andtripleare still accepted, but they emit a warning and map to the new names.
require('termlayout').setup {
vertical_size = math.floor(vim.o.lines / 2),
horizontal_size = math.floor(vim.o.columns / 2),
show_tabs = true,
new_tab_mapping = "<C-t>",
label_hl = "TabLineSel",
}return {
'luckpoint/termlayout.nvim',
keys = {
{
mode = { 'n', 't' },
'<C-;>',
function()
require('termlayout').open()
end,
desc = 'Open TermLayout 0',
},
{
mode = { 'n', 't' },
'<C-/>',
function()
require('termlayout').open(1)
end,
desc = 'Open TermLayout 1',
},
{
'<leader>tt',
function()
require('termlayout').select()
end,
desc = 'Select terminal',
}
},
opts = {
vertical_size = 20,
horizontal_size = math.floor(vim.o.columns / 2),
},
}Forked from CRAG666/betterTerm.nvim.









