mirror of
https://github.com/neovim/neovim
synced 2025-07-16 01:01:49 +00:00
ui/terminal: make terminal state redraw like any other state
Previously, ordinary redraws were missing from terminal mode. Instead, there was an async callback that invoked update_screen() on terminal data regardless of mode (as if :redraw! was invoked by a timer). This created some issues: - async changes to an unrelated ordinary buffer were not always redrawn in terminal mode - screen cursor position was not properly updated in terminal mode (partial fix, will be properly fixed in a follow up PR) - ad-hoc logic was needed for interaction with special states such as inccommand or horizontal wildmenu. Instead redraw terminal mode just like any other state. This disables forced redraws in cmdline mode, which were inconisent which async changes to normal buffers (which are not redrawn in cmdline mode).
This commit is contained in:
@ -400,7 +400,6 @@ void terminal_enter(void)
|
||||
showmode();
|
||||
curwin->w_redr_status = true; // For mode() in statusline. #8323
|
||||
ui_busy_start();
|
||||
redraw(false);
|
||||
|
||||
s->state.execute = terminal_execute;
|
||||
s->state.check = terminal_check;
|
||||
@ -416,8 +415,10 @@ void terminal_enter(void)
|
||||
|
||||
// draw the unfocused cursor
|
||||
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
|
||||
if (curbuf->terminal == s->term && !s->close) {
|
||||
terminal_check_cursor();
|
||||
}
|
||||
unshowmode(true);
|
||||
redraw(curbuf->handle != s->term->buf_handle);
|
||||
ui_busy_stop();
|
||||
if (s->close) {
|
||||
bool wipe = s->term->buf_handle != 0;
|
||||
@ -428,6 +429,20 @@ void terminal_enter(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void terminal_check_cursor(void)
|
||||
{
|
||||
Terminal *term = curbuf->terminal;
|
||||
curwin->w_wrow = term->cursor.row;
|
||||
curwin->w_wcol = term->cursor.col + win_col_off(curwin);
|
||||
curwin->w_cursor.lnum = MIN(curbuf->b_ml.ml_line_count,
|
||||
row_to_linenr(term, term->cursor.row));
|
||||
// Nudge cursor when returning to normal-mode.
|
||||
int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1);
|
||||
curwin->w_cursor.col = MAX(0, term->cursor.col + win_col_off(curwin) + off);
|
||||
curwin->w_cursor.coladd = 0;
|
||||
mb_check_adjust_col(curwin);
|
||||
}
|
||||
|
||||
// Function executed before each iteration of terminal mode.
|
||||
// Return:
|
||||
// 1 if the iteration should continue normally
|
||||
@ -438,6 +453,19 @@ static int terminal_check(VimState *state)
|
||||
stop_insert_mode = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
terminal_check_cursor();
|
||||
|
||||
if (must_redraw) {
|
||||
update_screen(0);
|
||||
}
|
||||
|
||||
if (need_maketitle) { // Update title in terminal-mode. #7248
|
||||
maketitle();
|
||||
}
|
||||
|
||||
setcursor();
|
||||
ui_flush();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1151,11 +1179,7 @@ static void refresh_terminal(Terminal *term)
|
||||
static void refresh_timer_cb(TimeWatcher *watcher, void *data)
|
||||
{
|
||||
refresh_pending = false;
|
||||
if (exiting // Cannot redraw (requires event loop) during teardown/exit.
|
||||
|| (State & CMDPREVIEW)
|
||||
// WM_LIST (^D) is not redrawn, unlike the normal wildmenu. So we must
|
||||
// skip redraws to keep it visible.
|
||||
|| wild_menu_showing == WM_LIST) {
|
||||
if (exiting) { // Cannot redraw (requires event loop) during teardown/exit.
|
||||
return;
|
||||
}
|
||||
Terminal *term;
|
||||
@ -1165,12 +1189,8 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
|
||||
map_foreach(invalidated_terminals, term, stub, {
|
||||
refresh_terminal(term);
|
||||
});
|
||||
bool any_visible = is_term_visible();
|
||||
pmap_clear(ptr_t)(invalidated_terminals);
|
||||
unblock_autocmds();
|
||||
if (any_visible) {
|
||||
redraw(true);
|
||||
}
|
||||
}
|
||||
|
||||
static void refresh_size(Terminal *term, buf_T *buf)
|
||||
@ -1284,61 +1304,6 @@ static void refresh_screen(Terminal *term, buf_T *buf)
|
||||
term->invalid_end = -1;
|
||||
}
|
||||
|
||||
/// @return true if any invalidated terminal buffer is visible to the user
|
||||
static bool is_term_visible(void)
|
||||
{
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_buffer->terminal
|
||||
&& pmap_has(ptr_t)(invalidated_terminals, wp->w_buffer->terminal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void redraw(bool restore_cursor)
|
||||
{
|
||||
Terminal *term = curbuf->terminal;
|
||||
if (!term) {
|
||||
restore_cursor = true;
|
||||
}
|
||||
|
||||
int save_row = 0;
|
||||
int save_col = 0;
|
||||
if (restore_cursor) {
|
||||
// save the current row/col to restore after updating screen when not
|
||||
// focused
|
||||
save_row = ui_current_row();
|
||||
save_col = ui_current_col();
|
||||
}
|
||||
block_autocmds();
|
||||
|
||||
if (must_redraw) {
|
||||
update_screen(0);
|
||||
}
|
||||
|
||||
if (need_maketitle) { // Update title in terminal-mode. #7248
|
||||
maketitle();
|
||||
}
|
||||
|
||||
if (restore_cursor) {
|
||||
ui_cursor_goto(save_row, save_col);
|
||||
} else if (term) {
|
||||
curwin->w_wrow = term->cursor.row;
|
||||
curwin->w_wcol = term->cursor.col + win_col_off(curwin);
|
||||
curwin->w_cursor.lnum = MIN(curbuf->b_ml.ml_line_count,
|
||||
row_to_linenr(term, term->cursor.row));
|
||||
// Nudge cursor when returning to normal-mode.
|
||||
int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1);
|
||||
curwin->w_cursor.col = MAX(0, term->cursor.col + win_col_off(curwin) + off);
|
||||
curwin->w_cursor.coladd = 0;
|
||||
mb_check_adjust_col(curwin);
|
||||
}
|
||||
|
||||
unblock_autocmds();
|
||||
ui_flush();
|
||||
}
|
||||
|
||||
static void adjust_topline(Terminal *term, buf_T *buf, long added)
|
||||
{
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
|
@ -142,15 +142,15 @@ describe(':terminal scrollback', function()
|
||||
describe('and height decreased by 1', function()
|
||||
if helpers.pending_win32(pending) then return end
|
||||
local function will_hide_top_line()
|
||||
feed([[<C-\><C-N>:]]) -- Go to cmdline-mode, so cursor is at bottom.
|
||||
feed([[<C-\><C-N>]])
|
||||
screen:try_resize(screen._width - 2, screen._height - 1)
|
||||
screen:expect([[
|
||||
line2 |
|
||||
line3 |
|
||||
line4 |
|
||||
rows: 5, cols: 28 |
|
||||
{2: } |
|
||||
:^ |
|
||||
{2:^ } |
|
||||
|
|
||||
]])
|
||||
end
|
||||
|
||||
@ -166,11 +166,11 @@ describe(':terminal scrollback', function()
|
||||
screen:expect([[
|
||||
rows: 5, cols: 28 |
|
||||
rows: 3, cols: 26 |
|
||||
{2: } |
|
||||
:^ |
|
||||
{2:^ } |
|
||||
|
|
||||
]])
|
||||
eq(8, curbuf('line_count'))
|
||||
feed([[<C-\><C-N>3k]])
|
||||
feed([[3k]])
|
||||
screen:expect([[
|
||||
^line4 |
|
||||
rows: 5, cols: 28 |
|
||||
|
@ -69,7 +69,7 @@ describe(':terminal', function()
|
||||
end)
|
||||
|
||||
it('forwards resize request to the program', function()
|
||||
feed([[<C-\><C-N>G:]]) -- Go to cmdline-mode, so cursor is at bottom.
|
||||
feed([[<C-\><C-N>G]])
|
||||
local w1, h1 = screen._width - 3, screen._height - 2
|
||||
local w2, h2 = w1 - 6, h1 - 3
|
||||
|
||||
@ -92,16 +92,16 @@ describe(':terminal', function()
|
||||
|
|
||||
|
|
||||
|
|
||||
^ |
|
||||
|
|
||||
:^ |
|
||||
]])
|
||||
screen:try_resize(w2, h2)
|
||||
screen:expect([[
|
||||
tty ready |
|
||||
rows: 7, cols: 47 |
|
||||
rows: 4, cols: 41 |
|
||||
{2: } |
|
||||
:^ |
|
||||
{2:^ } |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
@ -163,12 +163,14 @@ describe('search highlighting', function()
|
||||
]])
|
||||
feed('/foo')
|
||||
sleep(50) -- Allow some terminal activity.
|
||||
-- NB: in earlier versions terminal output was redrawn during cmdline mode.
|
||||
-- For now just assert that the screens remain unchanged.
|
||||
screen:expect([[
|
||||
{3:foo} bar baz {3:│}xxx |
|
||||
bar baz {2:foo} {3:│}xxx |
|
||||
bar {2:foo} baz {3:│}xxx |
|
||||
{3:│}xxx |
|
||||
{1:~ }{3:│}xxx |
|
||||
{3:foo} bar baz {3:│} |
|
||||
bar baz {2:foo} {3:│} |
|
||||
bar {2:foo} baz {3:│} |
|
||||
{3:│} |
|
||||
{1:~ }{3:│} |
|
||||
{5:[No Name] [+] }{3:term }|
|
||||
/foo^ |
|
||||
]], { [1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||
|
@ -95,10 +95,12 @@ describe("'wildmenu'", function()
|
||||
|
||||
feed([[<C-\><C-N>gg]])
|
||||
feed([[:sign <Tab>]]) -- Invoke wildmenu.
|
||||
-- NB: in earlier versions terminal output was redrawn during cmdline mode.
|
||||
-- For now just assert that the screen remains unchanged.
|
||||
expect_stay_unchanged{grid=[[
|
||||
foo |
|
||||
foo |
|
||||
foo |
|
||||
|
|
||||
|
|
||||
|
|
||||
define jump list > |
|
||||
:sign define^ |
|
||||
]]}
|
||||
|
Reference in New Issue
Block a user