From 5d3cda472c0c19dd33c1177349c08041052b88bc Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 14 Apr 2026 22:08:36 +0200 Subject: [PATCH] feat(api): use zindex to determine dimmed cursor shape #39054 Problem: The cursor shape is changed to indicate when it is behind an unfocused floating window (since a2b92a5e). This behavior cannot be controlled by a floating window that doesn't want to dim the cursor. Solution: Assign a zindex-offset of 50 to the zindex of the current window. To not dim the cursor when creating a floating window on top of the current window one can assign the zindex accordingly. --- runtime/doc/api.txt | 2 ++ runtime/doc/news.txt | 2 ++ runtime/lua/vim/_meta/api.gen.lua | 3 +- src/nvim/api/win_config.c | 3 +- src/nvim/ui.c | 7 +++-- test/functional/ui/float_spec.lua | 48 +++++++++++++++++++++---------- 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 3a18dfdcfb..e664d40225 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -3991,6 +3991,8 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()* wildoptions+=pum) The default value for floats are 50. In general, values below 100 are recommended, unless there is a good reason to overshadow builtin elements. + The cursor is dimmed if an unfocused float above the + cursor exceeds the zindex of the current window by 50. • _cmdline_offset: (EXPERIMENTAL) When provided, anchor the |cmdline-completion| popupmenu to this window, with an offset in screen cell width. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 084ba616b1..dac678ed3c 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -106,6 +106,8 @@ The following new features were added. API • |nvim_set_hl()| supports "font" key. +• |nvim_open_win()| `zindex` controls whether the UI will use a dimmed cursor + shape when an unfocused float is on top of the cursor. BUILD diff --git a/runtime/lua/vim/_meta/api.gen.lua b/runtime/lua/vim/_meta/api.gen.lua index 8c134d63f0..ce5c38736c 100644 --- a/runtime/lua/vim/_meta/api.gen.lua +++ b/runtime/lua/vim/_meta/api.gen.lua @@ -1887,7 +1887,8 @@ function vim.api.nvim_open_term(buffer, opts) end --- - 250: cmdline completion popupmenu (when wildoptions+=pum) --- The default value for floats are 50. In general, values below 100 are --- recommended, unless there is a good reason to overshadow builtin ---- elements. +--- elements. The cursor is dimmed if an unfocused float above the cursor +--- exceeds the zindex of the current window by 50. --- - _cmdline_offset: (EXPERIMENTAL) When provided, anchor the `cmdline-completion` --- popupmenu to this window, with an offset in screen cell width. --- @return integer # |window-ID|, or 0 on error diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index b46bb76bb6..9f44738fc0 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -194,7 +194,8 @@ /// - 250: cmdline completion popupmenu (when wildoptions+=pum) /// The default value for floats are 50. In general, values below 100 are /// recommended, unless there is a good reason to overshadow builtin -/// elements. +/// elements. The cursor is dimmed if an unfocused float above the cursor +/// exceeds the zindex of the current window by 50. /// - _cmdline_offset: (EXPERIMENTAL) When provided, anchor the |cmdline-completion| /// popupmenu to this window, with an offset in screen cell width. /// diff --git a/src/nvim/ui.c b/src/nvim/ui.c index c730631378..a3dd887a4d 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -685,7 +685,8 @@ void ui_cursor_shape(void) } /// Check if the cursor is behind a floating window (only in compositor mode). -/// @return true if cursor is obscured by a float with higher zindex +/// @return true if cursor is obscured by a float (when its zindex exceeds the +/// zindex of the current window by 50). static bool ui_cursor_is_behind_floatwin(void) { if ((State & MODE_CMDLINE) || !ui_comp_should_draw()) { @@ -697,7 +698,9 @@ static bool ui_cursor_is_behind_floatwin(void) + (curwin->w_p_rl ? curwin->w_view_width - curwin->w_wcol - 1 : curwin->w_wcol); ScreenGrid *top_grid = ui_comp_get_grid_at_coord(crow, ccol); - return top_grid != &curwin->w_grid_alloc && top_grid != &default_grid; + return top_grid != &curwin->w_grid_alloc + && top_grid != &default_grid + && top_grid->zindex >= curwin->w_grid_alloc.zindex + 50; } /// Returns true if the given UI extension is enabled. diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index e5bf766000..b517b5d613 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -11622,7 +11622,6 @@ describe('float window', function() row = 8, col = 9, border = 'single', - zindex = 1, }) local buf2 = api.nvim_create_buf(false, false) local float_win_above = api.nvim_open_win(buf2, false, { @@ -11631,7 +11630,7 @@ describe('float window', function() height = 10, row = 0, col = 0, - zindex = 2, + zindex = 100, }) if multigrid then screen:expect({ @@ -11659,8 +11658,8 @@ describe('float window', function() [2] = { height = 19, startcol = 0, startrow = 0, width = 50, win = 1000 }, }, float_pos = { - [7] = { 1004, 'NW', 1, 8, 9, true, 1, 1, 8, 9 }, - [8] = { 1005, 'NW', 1, 0, 0, true, 2, 2, 0, 0 }, + [7] = { 1004, 'NW', 1, 8, 9, true, 50, 1, 8, 9 }, + [8] = { 1005, 'NW', 1, 0, 0, true, 100, 2, 0, 0 }, }, mode = 'normal', }) @@ -11708,8 +11707,8 @@ describe('float window', function() [2] = { height = 19, startcol = 0, startrow = 0, width = 50, win = 1000 }, }, float_pos = { - [7] = { 1004, 'NW', 1, 9, 8, true, 1, 1, 9, 8 }, - [8] = { 1005, 'NW', 1, 0, 0, true, 2, 2, 0, 0 }, + [7] = { 1004, 'NW', 1, 9, 8, true, 50, 1, 9, 8 }, + [8] = { 1005, 'NW', 1, 0, 0, true, 100, 2, 0, 0 }, }, mode = 'normal', }) @@ -11759,8 +11758,8 @@ describe('float window', function() [2] = { height = 19, startcol = 0, startrow = 0, width = 50, win = 1000 }, }, float_pos = { - [7] = { 1004, 'NW', 1, 8, 8, true, 1, 1, 8, 8 }, - [8] = { 1005, 'NW', 1, 0, 0, true, 2, 2, 0, 0 }, + [7] = { 1004, 'NW', 1, 8, 8, true, 50, 1, 8, 8 }, + [8] = { 1005, 'NW', 1, 0, 0, true, 100, 2, 0, 0 }, }, mode = 'normal', }) @@ -11809,17 +11808,22 @@ describe('float window', function() [2] = { height = 19, startcol = 0, startrow = 0, width = 50, win = 1000 }, }, float_pos = { - [7] = { 1004, 'NW', 1, 8, 8, true, 1, 1, 8, 8 }, - [8] = { 1005, 'NW', 1, 0, 0, true, 2, 2, 0, 0 }, + [7] = { 1004, 'NW', 1, 8, 8, true, 50, 1, 8, 8 }, + [8] = { 1005, 'NW', 1, 0, 0, true, 100, 2, 0, 0 }, }, mode = 'normal', }) else screen:expect { mode = 'replace' } end + -- Not obscured when zindex doesn't exceed the zindex of the current grid + 50 (#37703). + api.nvim_win_set_config(float_win_above, { zindex = 99 }) + if not multigrid then + screen:expect { mode = 'normal' } + end -- Not obscured by a hidden floatwin. - api.nvim_win_set_config(float_win_above, { hide = true }) + api.nvim_win_set_config(float_win_above, { hide = true, zindex = 100 }) if multigrid then screen:expect({ grid = [[ @@ -11843,12 +11847,26 @@ describe('float window', function() {2:~ }|*9 ]], float_pos = { - [7] = { 1004, 'NW', 1, 8, 8, true, 1, 1, 8, 8 }, + [7] = { 1004, 'NW', 1, 8, 8, true, 50, 1, 8, 8 }, }, mode = 'normal', }) else - screen:expect { mode = 'normal' } + screen:expect({ + grid = [[ + one | + two | + three | + {0:~ }|*5 + {0:~ }{5:┌─────┐}{0: }| + {0:~ }{5:│}{1:^ x}{5:│}{0: }| + {0:~ }{5:│}{2: ~}{5:│}{0: }|*4 + {0:~ }{5:└─────┘}{0: }| + {0:~ }|*4 + | + ]], + mode = 'normal', + }) end -- Not obscured in the command-line if curwin's cursor is obscured. @@ -11877,8 +11895,8 @@ describe('float window', function() {2:~ }|*9 ]], float_pos = { - [7] = { 1004, 'NW', 1, 8, 8, true, 1, 1, 8, 8 }, - [8] = { 1005, 'NW', 1, 0, 0, true, 2, 2, 0, 0 }, + [7] = { 1004, 'NW', 1, 8, 8, true, 50, 1, 8, 8 }, + [8] = { 1005, 'NW', 1, 0, 0, true, 100, 2, 0, 0 }, }, mode = 'cmdline_normal', })