mirror of
https://github.com/neovim/neovim.git
synced 2026-03-31 12:52:13 +00:00
fix(terminal): possible missing refresh with buffer updates (#38388)
Problem:
Terminal refresh may be missed if buffer update callbacks poll for uv
events. Example test failure on FreeBSD:
FAILED test/functional/terminal/buffer_spec.lua @ 1049: :terminal buffer scrollback is correct if buffer update callbacks poll for uv events
test/functional/terminal/buffer_spec.lua:1004: Row 1 did not match.
Expected:
|*19995: TEST{MATCH: +}|
|*19996: TEST{MATCH: +}|
|*19997: TEST{MATCH: +}|
|*19998: TEST{MATCH: +}|
|*19999: TEST{MATCH: +}|
|^[Process exited 0] |
|{5:-- TERMINAL --} |
Actual:
|*19696: TEST |
|*19697: TEST |
|*19698: TEST |
|*19699: TEST |
|*19700: TEST |
|^[Process exited 0] |
|{5:-- TERMINAL --} |
Solution:
Call changed_lines() after resetting invalid region in refresh_screen().
Handle terminal being invalidated in the middle of refresh_timer_cb().
This commit is contained in:
@@ -2455,18 +2455,24 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
|
||||
if (exiting) { // Cannot redraw (requires event loop) during teardown/exit.
|
||||
return;
|
||||
}
|
||||
Terminal *term;
|
||||
void *stub; (void)(stub);
|
||||
// don't process autocommands while updating terminal buffers
|
||||
|
||||
// Don't process autocommands while updating terminal buffers.
|
||||
block_autocmds();
|
||||
set_foreach(&invalidated_terminals, term, {
|
||||
// Refreshing one terminal may poll for output to another, which should not
|
||||
// interfere with the set_foreach() below.
|
||||
Set(ptr_t) to_refresh = invalidated_terminals;
|
||||
invalidated_terminals = (Set(ptr_t)) SET_INIT;
|
||||
|
||||
Terminal *term;
|
||||
set_foreach(&to_refresh, term, {
|
||||
// Skip terminals in synchronized output — they will be refreshed
|
||||
// when the synchronized update ends (mode 2026 reset).
|
||||
if (!term->synchronized_output) {
|
||||
refresh_terminal(term);
|
||||
}
|
||||
});
|
||||
set_clear(ptr_t, &invalidated_terminals);
|
||||
|
||||
set_destroy(ptr_t, &to_refresh);
|
||||
unblock_autocmds();
|
||||
}
|
||||
|
||||
@@ -2612,9 +2618,11 @@ static void refresh_screen(Terminal *term, buf_T *buf)
|
||||
|
||||
int change_start = row_to_linenr(term, term->invalid_start);
|
||||
int change_end = change_start + changed;
|
||||
changed_lines(buf, change_start, 0, change_end, added, true);
|
||||
term->invalid_start = INT_MAX;
|
||||
term->invalid_end = -1;
|
||||
// Call this after resetting the invalid region, as buffer update callbacks may
|
||||
// poll for terminal output and lead to new invalidations.
|
||||
changed_lines(buf, change_start, 0, change_end, added, true);
|
||||
}
|
||||
|
||||
static void adjust_topline_cursor(Terminal *term, buf_T *buf, int added)
|
||||
|
||||
Reference in New Issue
Block a user