From 17383870dd3b7f04eddd48ed929cc25c7e102277 Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 12 Dec 2024 18:45:57 +0800 Subject: [PATCH] fix(float): re-sort layers when grid zindex changed #30259 Problem: when zindex is changed in vim.schedule the zindex sort in layers not changed. Solution: resort layers when zindex changed. --- src/nvim/ui_compositor.c | 29 +++++++++ src/nvim/window.c | 6 ++ test/functional/ui/float_spec.lua | 105 ++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 4cddc3dc82..38d882462d 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -101,6 +101,35 @@ bool ui_comp_should_draw(void) return composed_uis != 0 && valid_screen; } +/// Raises or lowers the layer, syncing comp_index with zindex. +/// +/// This function adjusts the position of a layer in the layers array +/// based on its zindex, either raising or lowering it. +/// +/// @param[in] layer_idx Index of the layer to be raised or lowered. +/// @param[in] raise Raise the layer if true, else lower it. +void ui_comp_layers_adjust(size_t layer_idx, bool raise) +{ + size_t size = layers.size; + ScreenGrid *layer = layers.items[layer_idx]; + + if (raise) { + while (layer_idx < size - 1 && layer->zindex > layers.items[layer_idx + 1]->zindex) { + layers.items[layer_idx] = layers.items[layer_idx + 1]; + layers.items[layer_idx]->comp_index = layer_idx; + layer_idx++; + } + } else { + while (layer_idx > 0 && layer->zindex < layers.items[layer_idx - 1]->zindex) { + layers.items[layer_idx] = layers.items[layer_idx - 1]; + layers.items[layer_idx]->comp_index = layer_idx; + layer_idx--; + } + } + layers.items[layer_idx] = layer; + layer->comp_index = layer_idx; +} + /// Places `grid` at (col,row) position with (width * height) size. /// Adds `grid` as the top layer if it is a new layer. /// diff --git a/src/nvim/window.c b/src/nvim/window.c index 79c3ce9304..938d9d7618 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -852,7 +852,13 @@ void ui_ext_win_position(win_T *wp, bool validate) } } + bool resort = wp->w_grid_alloc.comp_index != 0 + && wp->w_grid_alloc.zindex != wp->w_config.zindex; + bool raise = resort && wp->w_grid_alloc.zindex < wp->w_config.zindex; wp->w_grid_alloc.zindex = wp->w_config.zindex; + if (resort) { + ui_comp_layers_adjust(wp->w_grid_alloc.comp_index, raise); + } if (ui_has(kUIMultigrid)) { String anchor = cstr_as_string(float_anchor_str[c.anchor]); if (!c.hide) { diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 57ef9bcff6..c676e9d5f2 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -8542,6 +8542,111 @@ describe('float window', function() | ]]} end + + -- + -- Check that floats are positioned correctly after changing the zindexes. + -- + command('fclose') + exec_lua([[ + local win1, win3 = ... + vim.api.nvim_win_set_config(win1, { zindex = 400, title = 'win_400', title_pos = 'center', border = 'double' }) + vim.api.nvim_win_set_config(win3, { zindex = 300, title = 'win_300', title_pos = 'center', border = 'single' }) + ]], win1, win3) + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*6 + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }|*5 + ## grid 3 + | + ## grid 4 + {5:╔══════}{11:win_400}{5:═══════╗}| + {5:║}{7: }{5:║}| + {5:║}{7:~ }{5:║}|*2 + {5:╚════════════════════╝}| + ## grid 6 + {5:┌──────}{11:win_300}{5:───────┐}| + {5:│}{8: }{5:│}| + {5:│}{8:~ }{5:│}|*2 + {5:└────────────────────┘}| + ]], float_pos={ + [4] = {1001, "NW", 1, 1, 5, true, 400}; + [6] = {1003, "NW", 1, 3, 7, true, 300}; + }, win_viewport={ + [2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = 1001, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = 1003, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 }, + [4] = { bottom = 1, left = 1, right = 1, top = 1, win = 1001 }, + [6] = { bottom = 1, left = 1, right = 1, top = 1, win = 1003 } + }}) + else + screen:expect({ + grid = [[ + ^ | + {0:~ }{5:╔══════}{11:win_400}{5:═══════╗}{0: }| + {0:~ }{5:║}{7: }{5:║─┐}{0: }| + {0:~ }{5:║}{7:~ }{5:║}{8: }{5:│}{0: }|*2 + {0:~ }{5:╚════════════════════╝}{8: }{5:│}{0: }| + {5:└────────────────────┘} | + ]] + }) + end + exec_lua([[ + local win1, win3 = ... + vim.api.nvim_win_set_config(win1, { zindex = 100, title='win_100' }) + vim.api.nvim_win_set_config(win3, { zindex = 150, title='win_150' }) + ]], win1, win3) + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*6 + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }|*5 + ## grid 3 + | + ## grid 4 + {5:╔}{11:win_100}{5:═════════════╗}| + {5:║}{7: }{5:║}| + {5:║}{7:~ }{5:║}|*2 + {5:╚════════════════════╝}| + ## grid 6 + {5:┌}{11:win_150}{5:─────────────┐}| + {5:│}{8: }{5:│}| + {5:│}{8:~ }{5:│}|*2 + {5:└────────────────────┘}| + ]], float_pos={ + [4] = {1001, "NW", 1, 1, 5, true, 100}; + [6] = {1003, "NW", 1, 3, 7, true, 150}; + }, win_viewport={ + [2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = 1001, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = 1003, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + }, win_viewport_margins={ + [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 }, + [4] = { bottom = 1, left = 1, right = 1, top = 1, win = 1001 }, + [6] = { bottom = 1, left = 1, right = 1, top = 1, win = 1003 } + }}) + else + screen:expect({ + grid = [[ + ^ | + {0:~ }{5:╔}{11:w}{5:┌}{11:win_150}{5:─────────────┐}{0: }| + {0:~ }{5:║}{7: }{5:│}{8: }{5:│}{0: }| + {0:~ }{5:║}{7:~}{5:│}{8:~ }{5:│}{0: }|*2 + {0:~ }{5:╚═└────────────────────┘}{0: }| + | + ]] + }) + end end) it('can use winbar', function()