Stop terminal buffer from auto-closing (window)


In my NeoVim usage, I like to keep the window layout intact. Even when I close a buffer, I want the window that contained the buffer to remain open. I use bufdelete.nvim and it works perfectly for my requirements.

When I create a window and open a terminal in it, the terminal’s process may terminate. For example, because the command terminates or because I type exit<CR> in the terminal.
When that happens, there is a helpful message [Process exited 0] and any key closes the terminal buffer.


When the terminal buffer closes, because the process in the terminal terminates, it also closes the window which contains the terminal buffer. Instead, I would like the window to stay open and not mess with my layout. Is there any way to achieve that?

I want to setup terminal buffers to behave like my other buffers.

Thank you!


There are some GitHub issues for NeoVim, but I am not skilled enough in NeoVim or Lua to make use of the information in there:

This may work:

  local buf=vim.api.nvim_get_current_buf()
  local newbuf=vim.api.nvim_create_buf(false,true)
  local windows=vim.fn.getwininfo()
  for _,i in ipairs(windows) do
    if i.bufnr==buf then

oh wow this sparked an idea for me this is what i came up for my usage.

set_map("n", "<leader>x", function()
	-- don't close tab if has only one buffer in a tab
	local api = vim.api
	local tabs = api.nvim_list_tabpages()
	local is_terminal = api.nvim_buf_get_option(0, "buftype") == "terminal"
	if #tabs > 1 and not is_terminal then
		local cur_tab = api.nvim_win_get_tabpage(0)
		local cur_buf = api.nvim_get_current_buf()
		local tab_info = api.nvim_tabpage_list_wins(cur_tab)
		local valid_bufs = {}
		for _, win in ipairs(tab_info) do
			if api.nvim_buf_is_valid(win) and win ~= cur_buf then
				table.insert(valid_bufs, win)
		if #valid_bufs < 1 then
			local new_buf = api.nvim_create_buf(true, false)
			table.insert(valid_bufs, new_buf)
		pcall(api.nvim_buf_delete, cur_buf, { force = is_terminal })
		pcall(api.nvim_buf_delete, 0, { force = is_terminal })
1 Like

Thank you! That does work indeed!

However, it doesn’t keep the terminal buffer around, so I cannot read the output of the process that terminated. Instead, the auto-command immediately closes the terminal buffer.

But your proposal lead me to a solution that almost works:

vim.api.nvim_create_autocmd("TermClose", {
	callback = function()
		local buf = vim.api.nvim_get_current_buf()
		vim.api.nvim_buf_set_keymap(buf, "n", "<Esc>", ":Bdelete<CR>", { noremap = true })
		vim.api.nvim_buf_set_keymap(buf, "t", "<Esc>", ":Bdelete<CR>", { noremap = true })

The problem: it works in normal mode, but not in terminal mode. Pressing <Esc> in terminal mode still closes the window. What am I doing wrong here?

Thank you so much for you help!

I found a solution which works. I need to:

  1. Use <C-\><C-N> in the mapping to escape terminal mode first
  2. Escape terminal characters in order for the mapping to work with the lua API

With bufdelete.nvim:

-- Keep window around when terminal closes
vim.api.nvim_create_autocmd("TermClose", {
	callback = function()
		local buf = vim.api.nvim_get_current_buf()
		vim.api.nvim_buf_set_keymap(buf, "n", "<Esc>", ":Bdelete<CR>", { noremap = true, silent = true })
			vim.api.nvim_replace_termcodes("<C-\\><C-N>:Bdelete<CR>", true, true, true),
			{ noremap = true, silent = true }

Thank you all for your help! :heart: