fix(terminal): inconsistent mode change when switching buffer (#37215)

Problem:  When switching to another terminal buffer in Terminal mode,
          usually Nvim stays in Terminal mode, but leaves Terminal mode
          if the old terminal buffer was deleted.
Solution: Don't always leave Terminal mode when active terminal buffer
          is deleted. Instead let terminal_check_focus() decide that.
(cherry picked from commit 3621af9b97)
This commit is contained in:
zeertzjq
2026-01-03 17:55:07 +08:00
committed by github-actions[bot]
parent c124594b22
commit bb31e7b345
2 changed files with 37 additions and 3 deletions

View File

@@ -868,6 +868,11 @@ static bool terminal_check_focus(TerminalState *const s)
if (s->term != curbuf->terminal) {
// Active terminal buffer changed, flush terminal's cursor state to the UI.
terminal_focus(s->term, false);
if (s->close) {
s->term->destroy = true;
s->term->opts.close_cb(s->term->opts.data);
s->close = false;
}
s->term = curbuf->terminal;
s->term->pending.cursor = true;
@@ -886,6 +891,9 @@ static int terminal_check(VimState *state)
{
TerminalState *const s = (TerminalState *)state;
// Shouldn't reach here when pressing a key to close the terminal buffer.
assert(!s->close || (s->term->buf_handle == 0 && s->term != curbuf->terminal));
if (stop_insert_mode || !terminal_check_focus(s)) {
return 0;
}
@@ -905,7 +913,6 @@ static int terminal_check(VimState *state)
s->term->refcount--;
if (s->term->buf_handle == 0) {
s->close = true;
return 0;
}
// Autocommands above may have changed focus, scrolled, or moved the cursor.
@@ -978,7 +985,6 @@ static int terminal_execute(VimState *state, int key)
s->term->refcount--;
if (s->term->buf_handle == 0) {
s->close = true;
return 0;
}
break;

View File

@@ -4,11 +4,12 @@ local Screen = require('test.functional.ui.screen')
local assert_alive = n.assert_alive
local clear, poke_eventloop = n.clear, n.poke_eventloop
local testprg, source, eq = n.testprg, n.source, t.eq
local testprg, source, eq, neq = n.testprg, n.source, t.eq, t.neq
local feed = n.feed
local feed_command, eval = n.feed_command, n.eval
local fn = n.fn
local api = n.api
local exec_lua = n.exec_lua
local retry = t.retry
local ok = t.ok
local command = n.command
@@ -156,6 +157,33 @@ describe(':terminal', function()
feed('<Ignore>') -- Add input to separate two RPC requests
eq({ blocking = false, mode = 'nt' }, api.nvim_get_mode())
end)
it('switching to another terminal buffer in Terminal mode', function()
command('terminal')
local buf0 = api.nvim_get_current_buf()
command('terminal')
local buf1 = api.nvim_get_current_buf()
command('terminal')
local buf2 = api.nvim_get_current_buf()
neq(buf0, buf1)
neq(buf0, buf2)
neq(buf1, buf2)
feed('i')
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
api.nvim_set_current_buf(buf1)
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
api.nvim_set_current_buf(buf0)
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
exec_lua(function()
vim.api.nvim_set_current_buf(buf1)
vim.api.nvim_buf_delete(buf0, { force = true })
end)
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
api.nvim_set_current_buf(buf2)
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
api.nvim_set_current_buf(buf1)
eq({ blocking = false, mode = 't' }, api.nvim_get_mode())
end)
end)
local function test_terminal_with_fake_shell(backslash)