diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 1097eac6c9..5c11efc18e 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -737,29 +737,50 @@ static void unset_terminal_winopts(TerminalState *const s) win_T *const wp = handle_get_window(s->save_curwin_handle); if (!wp) { - free_string_option(s->save_w_p_culopt); - s->save_curwin_handle = 0; - return; + goto end; } - if (win_valid(wp)) { // No need to redraw if window not in curtab. - if (s->save_w_p_cuc != wp->w_p_cuc) { - redraw_later(wp, UPD_SOME_VALID); - } else if (s->save_w_p_cul != wp->w_p_cul - || (s->save_w_p_cul && s->save_w_p_culopt_flags != wp->w_p_culopt_flags)) { - redraw_later(wp, UPD_VALID); + winopt_T *winopts = NULL; + if (wp->w_buffer->handle != s->term->buf_handle) { // Buffer no longer in "wp". + buf_T *buf = handle_get_buffer(s->term->buf_handle); + if (buf == NULL) { + goto end; // Nothing to restore as the buffer was deleted. } + for (size_t i = 0; i < kv_size(buf->b_wininfo); i++) { + WinInfo *wip = kv_A(buf->b_wininfo, i); + if (wip->wi_win == wp && wip->wi_optset) { + winopts = &wip->wi_opt; + break; + } + } + if (winopts == NULL) { + goto end; // Nothing to restore as there is no matching WinInfo. + } + } else { + winopts = &wp->w_onebuf_opt; + if (win_valid(wp)) { // No need to redraw if window not in curtab. + if (s->save_w_p_cuc != wp->w_p_cuc) { + redraw_later(wp, UPD_SOME_VALID); + } else if (s->save_w_p_cul != wp->w_p_cul + || (s->save_w_p_cul && s->save_w_p_culopt_flags != wp->w_p_culopt_flags)) { + redraw_later(wp, UPD_VALID); + } + } + wp->w_p_culopt_flags = s->save_w_p_culopt_flags; } - wp->w_p_cul = s->save_w_p_cul; if (s->save_w_p_culopt) { - free_string_option(wp->w_p_culopt); - wp->w_p_culopt = s->save_w_p_culopt; + free_string_option(winopts->wo_culopt); + winopts->wo_culopt = s->save_w_p_culopt; + s->save_w_p_culopt = NULL; } - wp->w_p_culopt_flags = s->save_w_p_culopt_flags; - wp->w_p_cuc = s->save_w_p_cuc; - wp->w_p_so = s->save_w_p_so; - wp->w_p_siso = s->save_w_p_siso; + winopts->wo_cul = s->save_w_p_cul; + winopts->wo_cuc = s->save_w_p_cuc; + winopts->wo_so = s->save_w_p_so; + winopts->wo_siso = s->save_w_p_siso; + +end: + free_string_option(s->save_w_p_culopt); s->save_curwin_handle = 0; } diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 7c6b76c08f..586cf0020c 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -33,21 +33,35 @@ describe(':terminal buffer', function() end) it('terminal-mode forces various options', function() + local expr = + '[&l:cursorlineopt, &l:cursorline, &l:cursorcolumn, &l:scrolloff, &l:sidescrolloff]' + feed([[]]) command('setlocal cursorline cursorlineopt=both cursorcolumn scrolloff=4 sidescrolloff=7') - eq( - { 'both', 1, 1, 4, 7 }, - eval('[&l:cursorlineopt, &l:cursorline, &l:cursorcolumn, &l:scrolloff, &l:sidescrolloff]') - ) + eq({ 'both', 1, 1, 4, 7 }, eval(expr)) eq('nt', eval('mode(1)')) - -- Enter terminal-mode ("insert" mode in :terminal). + -- Enter Terminal mode ("insert" mode in :terminal). feed('i') eq('t', eval('mode(1)')) - eq( - { 'number', 1, 0, 0, 0 }, - eval('[&l:cursorlineopt, &l:cursorline, &l:cursorcolumn, &l:scrolloff, &l:sidescrolloff]') - ) + eq({ 'number', 1, 0, 0, 0 }, eval(expr)) + + -- Return to Normal mode. + feed([[]]) + eq('nt', eval('mode(1)')) + eq({ 'both', 1, 1, 4, 7 }, eval(expr)) + + -- Enter Terminal mode again. + feed('i') + eq('t', eval('mode(1)')) + eq({ 'number', 1, 0, 0, 0 }, eval(expr)) + + -- Delete the terminal buffer and return to the previous buffer. + command('bwipe!') + feed('') -- Add input to separate two RPC requests + eq('n', eval('mode(1)')) + -- Window options in the old buffer should be unchanged. #37484 + eq({ 'both', 0, 0, -1, -1 }, eval(expr)) end) it('terminal-mode does not change cursorlineopt if cursorline is disabled', function() diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua index 974bedb0fd..0f5cb76db8 100644 --- a/test/functional/terminal/window_spec.lua +++ b/test/functional/terminal/window_spec.lua @@ -436,7 +436,7 @@ describe(':terminal window', function() file foo setlocal cursorline vsplit - setlocal nocursorline cursorcolumn + setlocal nocursorline cursorcolumn cursorlineopt=number ]]) screen:expect([[ {19:t}ty ready │tty ready | @@ -580,6 +580,49 @@ describe(':terminal window', function() {7:[No Name] }{18:foo [-] }| | ]]) + + command('wincmd l | enew | setlocal cursorline nocursorcolumn') + screen:expect([[ + {1: }{5:2}{1: [No Name] }{2: foo }{4: }{2:X}| + │{12:^ }| + {6:~ }│{6:~ }|*3 + {4:[No Name] }{7:[No Name] }| + | + ]]) + command('buffer # | startinsert') + screen:expect([[ + {1: }{5:2}{1: foo }{2: foo }{4: }{2:X}| + │rows: 5, cols: 25 | + {6:~ }│rows: 5, cols: 50 | + {6:~ }│^ | + {6:~ }│ | + {4:[No Name] }{17:foo [-] }| + {1:-- TERMINAL --} | + ]]) + -- Switching to another buffer shouldn't change window options there. #37484 + command('buffer # | call setline(1, ["aaa", "bbb", "ccc"]) | normal! jl') + screen:expect([[ + {1: }{5:2}{1:+ [No Name] }{2: foo }{4: }{2:X}| + │aaa | + {6:~ }│{12:b^bb }| + {6:~ }│ccc | + {6:~ }│{6:~ }| + {4:[No Name] }{7:[No Name] [+] }| + | + ]]) + -- Window options are restored when switching back to the terminal buffer. + command('buffer #') + screen:expect([[ + {1: }{5:2}{1: foo }{2: foo }{4: }{2:X}| + │{19:r}ows: 5, cols: 25 | + {6:~ }│{19:r}ows: 5, cols: 50 | + {6:~ }│^ | + {6:~ }│{19: } | + {4:[No Name] }{17:foo [-] }| + | + ]]) + -- 'cursorlineopt' should still be "number". + eq('number', eval('&l:cursorlineopt')) end) it('not unnecessarily redrawn by events', function()