fix(terminal): avoid mismatched busy_start without busy_stop (#32458)

Problem: `showmode` in `terminal_enter` may cause `vpeekc` to process events,
which may handle pending escape sequences. If `CSI ? 25 l` is handled to hide
the cursor, it may remain hidden even after leaving terminal mode if both
`terminal_enter` and (indirectly) `showmode` call `ui_busy_start`, as there is
only one matching call to `ui_busy_stop` after leaving terminal mode.

Solution: let `terminal_enter` handle setting the initial visibility of the
cursor before calling `showmode`.

Closes #32456.

This simple solution assumes it isn't possible for e.g. `os_breakcheck` to be
called indirectly by something else before `terminal_enter` initially handles
cursor visibility and after it restores it, which I think is true.
This commit is contained in:
Sean Dewar
2025-02-15 17:25:48 +00:00
committed by GitHub
parent 8e4b77134a
commit a49f95d887
2 changed files with 27 additions and 1 deletions

View File

@ -693,7 +693,6 @@ bool terminal_enter(void)
refresh_cursor(s->term);
adjust_topline(s->term, buf, 0); // scroll to end
showmode();
curwin->w_redr_status = true; // For mode() in statusline. #8323
redraw_custom_title_later();
if (!s->term->cursor.visible) {
@ -701,6 +700,7 @@ bool terminal_enter(void)
ui_busy_start();
}
ui_cursor_shape();
showmode();
apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf);
may_trigger_modechanged();

View File

@ -357,6 +357,32 @@ describe(':terminal cursor', function()
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
end)
it('restores visibility on TermLeave #32456', function()
skip(is_os('win'), '#31587')
feed([[<C-\><C-N>]]) -- Exit terminal mode
screen:expect([[
tty ready |
^ |
|*5
]])
tt.hide_cursor()
-- :startinsert repros the issue more reliably than feed('i')
command('mode | startinsert')
screen:expect([[
tty ready |
|*5
{3:-- TERMINAL --} |
]])
feed([[<C-\><C-N>]]) -- Exit terminal mode
screen:expect([[
tty ready |
^ |
|*5
]])
end)
end)
describe('buffer cursor position is correct in terminal without number column', function()