mirror of
https://github.com/neovim/neovim.git
synced 2026-05-23 21:30:11 +00:00
fix(options): repair stale UI state after :set all& #39026
Problem: `set all&` resets option values directly and leaves UI-derived state stale for `guicursor`, `laststatus`, and `showtabline`. Solution: Repair some of the stale UI state in the bulk reset path by reparsing `guicursor`, refreshing statusline state, and recomputing tabline/window rows.
This commit is contained in:
@@ -1579,6 +1579,7 @@ int do_set(char *arg, int opt_flags)
|
||||
arg++;
|
||||
// Only for :set command set global value of local options.
|
||||
set_options_default(opt_flags);
|
||||
didset_options_all();
|
||||
didset_options();
|
||||
didset_options2();
|
||||
ui_refresh_options();
|
||||
@@ -1827,6 +1828,26 @@ static void didset_options2(void)
|
||||
tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array);
|
||||
}
|
||||
|
||||
/// Repair UI state after `:set all&`.
|
||||
///
|
||||
/// `set_options_default` resets option values via `set_option_default` and
|
||||
/// `set_option_direct` without invoking per-option `did_set` callbacks, so
|
||||
/// UI-derived state (cursor shape, statusline, tabline) can get out of sync.
|
||||
/// This function patches the known cases.
|
||||
///
|
||||
/// Note: We intentionally do not replay all `did_set` callbacks
|
||||
/// (`opt_did_set_cb`) because they have order-dependent side effects and
|
||||
/// old/new transition logic that does not hold when values are already reset.
|
||||
static void didset_options_all(void)
|
||||
{
|
||||
const char *errmsg = parse_shape_opt(SHAPE_CURSOR);
|
||||
assert(errmsg == NULL);
|
||||
(void)errmsg;
|
||||
last_status(false);
|
||||
win_float_update_statusline();
|
||||
win_new_screen_rows();
|
||||
}
|
||||
|
||||
/// Check for string options that are NULL (normally only termcap options).
|
||||
void check_options(void)
|
||||
{
|
||||
|
||||
@@ -378,6 +378,22 @@ describe('ui/cursor', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
it("'set all&' reapplies 'guicursor'", function()
|
||||
command('set guicursor=n:ver25')
|
||||
screen:expect(function()
|
||||
eq('vertical', screen._mode_info[1].cursor_shape)
|
||||
eq(25, screen._mode_info[1].cell_percentage)
|
||||
end)
|
||||
|
||||
command('set all&')
|
||||
screen:expect(function()
|
||||
eq('block', screen._mode_info[1].cursor_shape)
|
||||
eq(0, screen._mode_info[1].blinkon)
|
||||
eq(0, screen._mode_info[1].blinkoff)
|
||||
eq(true, screen._cursor_style_enabled)
|
||||
end)
|
||||
end)
|
||||
|
||||
it(':sleep does not hide cursor when sleeping', function()
|
||||
n.feed(':sleep 300m | echo 42')
|
||||
screen:expect([[
|
||||
|
||||
@@ -172,6 +172,33 @@ describe('UI receives option updates', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
it("restores statusline and tabline after 'set all&'", function()
|
||||
reset()
|
||||
command('tabnew | tabnew')
|
||||
command('set laststatus=0 showtabline=0')
|
||||
screen:expect({
|
||||
unchanged = true,
|
||||
condition = function()
|
||||
local function row_text(row)
|
||||
local chunks = {}
|
||||
for _, cell in ipairs(screen._grid.rows[row]) do
|
||||
table.insert(chunks, cell.text)
|
||||
end
|
||||
return table.concat(chunks)
|
||||
end
|
||||
|
||||
eq(nil, row_text(1):find('%[No Name%]'))
|
||||
eq(nil, row_text(screen._grid.height - 1):find('All', 1, true))
|
||||
end,
|
||||
})
|
||||
|
||||
command('set all&')
|
||||
screen:expect({
|
||||
unchanged = true,
|
||||
any = { '[No Name]', 'All' },
|
||||
})
|
||||
end)
|
||||
|
||||
it('with UI extensions', function()
|
||||
local expected = reset({ ext_cmdline = true, ext_wildmenu = true })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user