fix(terminal): :edit should respect 'bufhidden' with exited job (#37301)

This commit is contained in:
zeertzjq
2026-01-10 08:25:49 +08:00
committed by GitHub
parent d1f7672bc9
commit 295fb3fdb2
2 changed files with 92 additions and 55 deletions

View File

@@ -2601,7 +2601,10 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
// oldwin->w_buffer to NULL.
u_sync(false);
const bool did_decrement
= close_buffer(oldwin, curbuf, (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
= close_buffer(oldwin, curbuf,
(flags & ECMD_HIDE)
|| (curbuf->terminal && terminal_running(curbuf->terminal))
? 0 : DOBUF_UNLOAD,
false, false);
// Autocommands may have closed the window.

View File

@@ -64,26 +64,6 @@ describe(':terminal buffer', function()
eq({ 0, 'line' }, eval('[&l:cursorline, &l:cursorlineopt]'))
end)
describe('when a new file is edited', function()
before_each(function()
feed('<c-\\><c-n>:set bufhidden=wipe<cr>:enew<cr>')
screen:expect([[
^ |
{100:~ }|*5
:enew |
]])
end)
it('will hide the buffer, ignoring the bufhidden option', function()
feed(':bnext:l<esc>')
screen:expect([[
^ |
{100:~ }|*5
|
]])
end)
end)
describe('swap and undo', function()
before_each(function()
feed('<c-\\><c-n>')
@@ -880,9 +860,30 @@ describe(':terminal buffer', function()
eq(false, api.nvim_buf_is_valid(term_buf))
end)
local enew_screen = [[
^ |
{1:~ }|*5
|
]]
local function test_enew_in_buf_with_running_term(env)
describe('editing a new file', function()
it('hides terminal buffer ignoring bufhidden=wipe', function()
local old_snapshot = env.screen:get_snapshot()
command('setlocal bufhidden=wipe')
command('enew')
neq(env.buf, api.nvim_get_current_buf())
env.screen:expect(enew_screen)
feed('<C-^>')
eq(env.buf, api.nvim_get_current_buf())
env.screen:expect(old_snapshot)
end)
end)
end
local function test_open_term_in_buf_with_running_term(env)
describe('does not allow', function()
it('opening another terminal with jobstart() in same buffer', function()
describe('does not allow opening another terminal', function()
it('with jobstart() in same buffer', function()
eq(
('Vim:Terminal already connected to buffer %d'):format(env.buf),
pcall_err(fn.jobstart, { testprg('tty-test') }, { term = true })
@@ -890,7 +891,7 @@ describe(':terminal buffer', function()
env.screen:expect_unchanged()
end)
it('opening another terminal with nvim_open_term() in same buffer', function()
it('with nvim_open_term() in same buffer', function()
eq(
('Terminal already connected to buffer %d'):format(env.buf),
pcall_err(api.nvim_open_term, env.buf, {})
@@ -904,16 +905,17 @@ describe(':terminal buffer', function()
local env = {}
before_each(function()
env.screen = Screen.new(60, 6)
env.screen = Screen.new(50, 7)
fn.jobstart({ testprg('tty-test') }, { term = true })
env.screen:expect([[
^tty ready |
|*5
^tty ready |
|*6
]])
env.buf = api.nvim_get_current_buf()
api.nvim_set_option_value('modified', false, { buf = env.buf })
end)
test_enew_in_buf_with_running_term(env)
test_open_term_in_buf_with_running_term(env)
end)
@@ -921,28 +923,58 @@ describe(':terminal buffer', function()
local env = {}
before_each(function()
env.screen = Screen.new(60, 6)
env.screen = Screen.new(50, 7)
local chan = api.nvim_open_term(0, {})
api.nvim_chan_send(chan, 'TEST')
env.screen:expect([[
^TEST |
|*5
^TEST |
|*6
]])
env.buf = api.nvim_get_current_buf()
api.nvim_set_option_value('modified', false, { buf = env.buf })
end)
test_enew_in_buf_with_running_term(env)
test_open_term_in_buf_with_running_term(env)
end)
local function test_open_term_in_buf_with_closed_term(env)
describe('does not leak memory when', function()
describe('opening another terminal with jobstart() in same buffer', function()
local function test_enew_in_buf_with_finished_term(env)
describe('editing a new file', function()
it('hides terminal buffer with bufhidden=hide', function()
local old_snapshot = env.screen:get_snapshot()
command('setlocal bufhidden=hide')
command('enew')
neq(env.buf, api.nvim_get_current_buf())
env.screen:expect(enew_screen)
feed('<C-^>')
eq(env.buf, api.nvim_get_current_buf())
env.screen:expect(old_snapshot)
end)
it('wipes terminal buffer with bufhidden=wipe', function()
command('setlocal bufhidden=wipe')
command('enew')
neq(env.buf, api.nvim_get_current_buf())
eq(false, api.nvim_buf_is_valid(env.buf))
env.screen:expect(enew_screen)
feed('<C-^>')
env.screen:expect([[
^ |
{1:~ }|*5
{9:E23: No alternate file} |
]])
end)
end)
end
local function test_open_term_in_buf_with_finished_term(env)
describe('does not leak memory when opening another terminal', function()
describe('with jobstart() in same buffer', function()
it('in Normal mode', function()
fn.jobstart({ testprg('tty-test') }, { term = true })
env.screen:expect([[
^tty ready |
|*5
^tty ready |
|*6
]])
end)
@@ -951,21 +983,21 @@ describe(':terminal buffer', function()
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
fn.jobstart({ testprg('tty-test') }, { term = true })
env.screen:expect([[
tty ready |
^ |
|*3
{5:-- TERMINAL --} |
tty ready |
^ |
|*4
{5:-- TERMINAL --} |
]])
end)
end)
describe('opening another terminal with nvim_open_term() in same buffer', function()
describe('with nvim_open_term() in same buffer', function()
it('in Normal mode', function()
local chan = api.nvim_open_term(env.buf, {})
api.nvim_chan_send(chan, 'OTHER')
env.screen:expect([[
^OTHER |
|*5
^OTHER |
|*6
]])
end)
@@ -975,9 +1007,9 @@ describe(':terminal buffer', function()
local chan = api.nvim_open_term(env.buf, {})
api.nvim_chan_send(chan, 'OTHER')
env.screen:expect([[
OTHER^ |
|*4
{5:-- TERMINAL --} |
OTHER^ |
|*5
{5:-- TERMINAL --} |
]])
end)
end)
@@ -988,38 +1020,40 @@ describe(':terminal buffer', function()
local env = {}
before_each(function()
env.screen = Screen.new(60, 6)
env.screen = Screen.new(50, 7)
fn.jobstart({ testprg('shell-test') }, { term = true })
env.screen:expect([[
^ready $ |
[Process exited 0] |
|*4
^ready $ |
[Process exited 0] |
|*5
]])
env.buf = api.nvim_get_current_buf()
api.nvim_set_option_value('modified', false, { buf = env.buf })
end)
test_open_term_in_buf_with_closed_term(env)
test_enew_in_buf_with_finished_term(env)
test_open_term_in_buf_with_finished_term(env)
end)
describe('with closed nvim_open_term() channel', function()
local env = {}
before_each(function()
env.screen = Screen.new(60, 6)
env.screen = Screen.new(50, 7)
local chan = api.nvim_open_term(0, {})
api.nvim_chan_send(chan, 'TEST')
fn.chanclose(chan)
env.screen:expect([[
^TEST |
[Terminal closed] |
|*4
^TEST |
[Terminal closed] |
|*5
]])
env.buf = api.nvim_get_current_buf()
api.nvim_set_option_value('modified', false, { buf = env.buf })
end)
test_open_term_in_buf_with_closed_term(env)
test_enew_in_buf_with_finished_term(env)
test_open_term_in_buf_with_finished_term(env)
end)
it('with nvim_open_term() channel and only 1 line is not reused by :enew', function()