commit ad1dfc92a0fc6a15915577e2d49a6b423ca81c21
parent 5e521c3b5ac3905ba4b34fead3dcd9b69e5196ed
Author: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Date: Thu, 27 Feb 2025 12:46:56 +0000
fix(terminal): add various missing redraws
Problem: missing redraws when restoring saved cursorline/column, plus missing
statusline and mode redraws when not updating the screen in terminal mode.
Solution: schedule the redraws in a similar manner to other modes and remove
some now unnecessary redrawing logic. Redraw if cursorline-related options
change from entering terminal mode. This fixes test failures in later commits.
WTF: TextChangedT triggers based on must_redraw, which is... fun...? Try to
preserve its behaviour as much as we can for now.
Diffstat:
3 files changed, 177 insertions(+), 14 deletions(-)
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
@@ -705,18 +705,19 @@ bool terminal_enter(void)
} else {
curwin->w_p_cul = false;
}
- if (curwin->w_p_cuc) {
- redraw_later(curwin, UPD_SOME_VALID);
- }
curwin->w_p_cuc = false;
curwin->w_p_so = 0;
curwin->w_p_siso = 0;
+ if (curwin->w_p_cuc != save_w_p_cuc) {
+ redraw_later(curwin, UPD_SOME_VALID);
+ } else if (curwin->w_p_cul != save_w_p_cul
+ || (curwin->w_p_cul && curwin->w_p_culopt_flags != save_w_p_culopt_flags)) {
+ redraw_later(curwin, UPD_VALID);
+ }
s->term->pending.cursor = true; // Update the cursor shape table
adjust_topline(s->term, buf, 0); // scroll to end
showmode();
- curwin->w_redr_status = true; // For mode() in statusline. #8323
- redraw_custom_title_later();
ui_cursor_shape();
apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf);
may_trigger_modechanged();
@@ -744,6 +745,12 @@ bool terminal_enter(void)
(void)parse_shape_opt(SHAPE_CURSOR);
if (save_curwin == curwin->handle) { // Else: window was closed.
+ if (save_w_p_cuc != curwin->w_p_cuc) {
+ redraw_later(curwin, UPD_SOME_VALID);
+ } else if (save_w_p_cul != curwin->w_p_cul
+ || (save_w_p_cul && save_w_p_culopt_flags != curwin->w_p_culopt_flags)) {
+ redraw_later(curwin, UPD_VALID);
+ }
curwin->w_p_cul = save_w_p_cul;
if (save_w_p_culopt) {
free_string_option(curwin->w_p_culopt);
@@ -808,10 +815,18 @@ static int terminal_check(VimState *state)
assert(s->term == curbuf->terminal);
terminal_check_cursor();
validate_cursor(curwin);
+ const bool text_changed = must_redraw != 0;
+ show_cursor_info_later(false);
if (must_redraw) {
update_screen();
-
+ } else {
+ redraw_statuslines();
+ if (clear_cmdline || redraw_cmdline || redraw_mode) {
+ showmode(); // clear cmdline and show mode
+ }
+ }
+ if (text_changed) {
// Make sure an invoked autocmd doesn't delete the buffer (and the
// terminal) under our fingers.
curbuf->b_locked++;
@@ -827,10 +842,6 @@ static int terminal_check(VimState *state)
may_trigger_win_scrolled_resized();
- if (need_maketitle) { // Update title in terminal-mode. #7248
- maketitle();
- }
-
setcursor();
refresh_cursor(s->term, &s->cursor_visible);
ui_flush();
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
@@ -189,6 +189,149 @@ describe(':terminal window', function()
]])
end)
end)
+
+ it('redrawn when restoring cursorline/column', function()
+ screen:set_default_attr_ids({
+ [1] = { bold = true },
+ [2] = { foreground = 130 },
+ [3] = { foreground = 130, underline = true },
+ [12] = { underline = true },
+ [19] = { background = 7 },
+ })
+
+ feed([[<C-\><C-N>]])
+ command('setlocal cursorline')
+ screen:expect([[
+ tty ready |
+ {12:^ }|
+ |*5
+ ]])
+ feed('i')
+ screen:expect([[
+ tty ready |
+ ^ |
+ |*4
+ {1:-- TERMINAL --} |
+ ]])
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ tty ready |
+ {12:^ }|
+ |*5
+ ]])
+
+ command('setlocal number')
+ screen:expect([[
+ {2: 1 }tty ready |
+ {3: 2 }{12:^rows: 6, cols: 46 }|
+ {2: 3 } |
+ {2: 4 } |
+ {2: 5 } |
+ {2: 6 } |
+ |
+ ]])
+ feed('i')
+ screen:expect([[
+ {2: 1 }tty ready |
+ {2: 2 }rows: 6, cols: 46 |
+ {3: 3 }^ |
+ {2: 4 } |
+ {2: 5 } |
+ {2: 6 } |
+ {1:-- TERMINAL --} |
+ ]])
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ {2: 1 }tty ready |
+ {2: 2 }rows: 6, cols: 46 |
+ {3: 3 }{12:^ }|
+ {2: 4 } |
+ {2: 5 } |
+ {2: 6 } |
+ |
+ ]])
+
+ command('setlocal nonumber nocursorline cursorcolumn')
+ screen:expect([[
+ {19:t}ty ready |
+ {19:r}ows: 6, cols: 46 |
+ ^rows: 6, cols: 50 |
+ {19: } |*3
+ |
+ ]])
+ feed('i')
+ screen:expect([[
+ tty ready |
+ rows: 6, cols: 46 |
+ rows: 6, cols: 50 |
+ ^ |
+ |*2
+ {1:-- TERMINAL --} |
+ ]])
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ {19:t}ty ready |
+ {19:r}ows: 6, cols: 46 |
+ {19:r}ows: 6, cols: 50 |
+ ^ |
+ {19: } |*2
+ |
+ ]])
+ end)
+
+ it('redraws cursor info in terminal mode', function()
+ skip(is_os('win'), '#31587')
+ command('file AMOGUS | set laststatus=2 ruler')
+ screen:expect([[
+ tty ready |
+ rows: 5, cols: 50 |
+ ^ |
+ |*2
+ {120:AMOGUS [-] 3,0-1 All}|
+ {5:-- TERMINAL --} |
+ ]])
+ feed_data('you are the imposter')
+ screen:expect([[
+ tty ready |
+ rows: 5, cols: 50 |
+ you are the imposter^ |
+ |*2
+ {120:AMOGUS [-] 3,21 All}|
+ {5:-- TERMINAL --} |
+ ]])
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ tty ready |
+ rows: 5, cols: 50 |
+ you are the imposte^r |
+ |*2
+ {120:AMOGUS [-] 3,20 All}|
+ |
+ ]])
+ end)
+
+ it('redraws stale statuslines and mode when not updating screen', function()
+ command('file foo | set ruler | vsplit')
+ screen:expect([[
+ tty ready │tty ready |
+ rows: 5, cols: 25 │rows: 5, cols: 25 |
+ ^ │ |
+ │ |*2
+ {120:<o [-] 3,0-1 All }{119:< [-] 2,0-1 Top}|
+ {5:-- TERMINAL --} |
+ ]])
+ command("call win_execute(win_getid(winnr('#')), 'call cursor(1, 1)')")
+ screen:expect([[
+ tty ready │tty ready |
+ rows: 5, cols: 25 │rows: 5, cols: 25 |
+ ^ │ |
+ │ |*2
+ {120:<o [-] 3,0-1 All }{119:< [-] 1,1 All}|
+ {5:-- TERMINAL --} |
+ ]])
+ command('echo ""')
+ screen:expect_unchanged()
+ end)
end)
describe(':terminal with multigrid', function()
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
@@ -79,18 +79,27 @@ describe('title', function()
it('is updated in Terminal mode', function()
api.nvim_set_option_value('title', true, {})
- api.nvim_set_option_value('titlestring', '(%{mode(1)}) | nvim', {})
+ api.nvim_set_option_value('titlestring', '%t (%{mode(1)}) | nvim', {})
fn.jobstart({ n.testprg('shell-test'), 'INTERACT' }, { term = true })
+ api.nvim_buf_set_name(0, 'shell-test')
screen:expect(function()
- eq('(nt) | nvim', screen.title)
+ eq('shell-test (nt) | nvim', screen.title)
end)
feed('i')
screen:expect(function()
- eq('(t) | nvim', screen.title)
+ eq('shell-test (t) | nvim', screen.title)
+ end)
+ api.nvim_set_option_value('titlelen', 1, {})
+ screen:expect(function()
+ eq('<t) | nvim', screen.title)
+ end)
+ command('set titlelen&')
+ screen:expect(function()
+ eq('shell-test (t) | nvim', screen.title)
end)
feed([[<C-\><C-N>]])
screen:expect(function()
- eq('(nt) | nvim', screen.title)
+ eq('shell-test (nt) | nvim', screen.title)
end)
end)