fix(api): fix crash after set_option_value_for() #15390

Problem:
This crashes Nvim:
    tabedit
    call nvim_win_set_option(1000, 'statusline', 'status')
    split
    wincmd J
    wincmd j

Solution:
- Change `no_display` parameter value to be the same as in matching
  `restore_win_noblock` call. In case of different values `topframe`
  isn't restored to `curtab->tp_topframe`.
- Call `restore_win_noblock` if `switch_win_noblock` returns `FAIL`
  (`switch_win` must always have matching `restore_win`)
- Change `switch_win`/`restore_win` to `_noblock` versions to allow
  autocommands.

fixes #14097
fixes #13577
This commit is contained in:
gmntroll 2021-09-26 05:48:06 +05:00 committed by GitHub
parent 2f9b9e61d7
commit 8b0e6cc05d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 9 deletions

View File

@ -1413,8 +1413,10 @@ static void set_option_value_for(char *key, int numval, char *stringval, int opt
switch (opt_type) switch (opt_type)
{ {
case SREQ_WIN: case SREQ_WIN:
if (switch_win(&save_curwin, &save_curtab, (win_T *)from, if (switch_win_noblock(&save_curwin, &save_curtab, (win_T *)from,
win_find_tabpage((win_T *)from), false) == FAIL) { win_find_tabpage((win_T *)from), true)
== FAIL) {
restore_win_noblock(save_curwin, save_curtab, true);
if (try_end(err)) { if (try_end(err)) {
return; return;
} }
@ -1424,7 +1426,7 @@ static void set_option_value_for(char *key, int numval, char *stringval, int opt
return; return;
} }
set_option_value_err(key, numval, stringval, opt_flags, err); set_option_value_err(key, numval, stringval, opt_flags, err);
restore_win(save_curwin, save_curtab, true); restore_win_noblock(save_curwin, save_curtab, true);
break; break;
case SREQ_BUF: case SREQ_BUF:
aucmd_prepbuf(&aco, (buf_T *)from); aucmd_prepbuf(&aco, (buf_T *)from);

View File

@ -1,8 +1,9 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq, local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf, ok, feed, insert, eval, tabpage = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq, helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval,
helpers.tabpage
local poke_eventloop = helpers.poke_eventloop local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths local curwinmeths = helpers.curwinmeths
local funcs = helpers.funcs local funcs = helpers.funcs
@ -11,6 +12,7 @@ local NIL = helpers.NIL
local meths = helpers.meths local meths = helpers.meths
local command = helpers.command local command = helpers.command
local pcall_err = helpers.pcall_err local pcall_err = helpers.pcall_err
local assert_alive = helpers.assert_alive
-- check if str is visible at the beginning of some line -- check if str is visible at the beginning of some line
local function is_visible(str) local function is_visible(str)
@ -206,7 +208,7 @@ describe('API/win', function()
end) end)
end) end)
describe('{get,set}_option', function() describe('nvim_win_get_option, nvim_win_set_option', function()
it('works', function() it('works', function()
curwin('set_option', 'colorcolumn', '4,3') curwin('set_option', 'colorcolumn', '4,3')
eq('4,3', curwin('get_option', 'colorcolumn')) eq('4,3', curwin('get_option', 'colorcolumn'))
@ -224,6 +226,18 @@ describe('API/win', function()
pcall_err(curwin, 'get_option', 'statusline')) pcall_err(curwin, 'get_option', 'statusline'))
eq('', eval('&l:statusline')) -- confirm local value was not copied eq('', eval('&l:statusline')) -- confirm local value was not copied
end) end)
it('after switching windows #15390', function()
nvim('command', 'tabnew')
local tab1 = unpack(nvim('list_tabpages'))
local win1 = unpack(tabpage('list_wins', tab1))
window('set_option', win1, 'statusline', 'window-status')
nvim('command', 'split')
nvim('command', 'wincmd J')
nvim('command', 'wincmd j')
eq('window-status', window('get_option', win1, 'statusline'))
assert_alive()
end)
end) end)
describe('get_position', function() describe('get_position', function()
@ -354,13 +368,13 @@ describe('API/win', function()
local win = meths.open_win(0, true, { local win = meths.open_win(0, true, {
relative='editor', row=10, col=10, width=50, height=10 relative='editor', row=10, col=10, width=50, height=10
}) })
local tabpage = eval('tabpagenr()') local tab = eval('tabpagenr()')
command('tabprevious') command('tabprevious')
eq(1, eval('tabpagenr()')) eq(1, eval('tabpagenr()'))
meths.win_close(win, false) meths.win_close(win, false)
eq(1001, meths.tabpage_get_win(tabpage).id) eq(1001, meths.tabpage_get_win(tab).id)
helpers.assert_alive() assert_alive()
end) end)
end) end)