From 6657cc36712d9e7961efbf7063fec3173dfa571b Mon Sep 17 00:00:00 2001 From: Riccardo Mazzarini Date: Sat, 14 Feb 2026 00:39:05 +0100 Subject: [PATCH] fix(ui): repaint separator connectors after all window updates #37852 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: When a window is redrawn, `draw_vsep_win`/`draw_hsep_win` paint plain separator characters (`│`/`─`) along the window's entire edges, including cells that are connector corners belonging to other windows. Then `draw_sep_connectors_win` only fixes the corners of that same window, not connectors in the middle of its edges that belong to adjacent windows. If the window that "owns" the connector corner isn't part of the redraw, the connector is never repainted. Solution: Move connector drawing out of the per-window `win_update` and into a separate pass in `update_screen` that runs after all windows have been updated. --- src/nvim/drawscreen.c | 11 +++-- test/functional/ui/statusline_spec.lua | 66 ++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index d1080958af..c871d73ca7 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -678,6 +678,14 @@ int update_screen(void) } } + // Draw separator connectors for all windows after all window updates, so that + // connectors overwrite vsep/hsep characters regardless of which windows were redrawn. + if (did_one) { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + draw_sep_connectors_win(wp); + } + } + end_search_hl(); // May need to redraw the popup menu. @@ -1412,7 +1420,6 @@ static void win_update(win_T *wp) if (wp->w_view_height == 0) { // draw the horizontal separator below this window draw_hsep_win(wp); - draw_sep_connectors_win(wp); wp->w_redr_type = 0; return; } @@ -1421,7 +1428,6 @@ static void win_update(win_T *wp) if (wp->w_view_width == 0) { // draw the vertical separator right of this window draw_vsep_win(wp); - draw_sep_connectors_win(wp); wp->w_redr_type = 0; return; } @@ -2405,7 +2411,6 @@ redr_statuscol: if (wp->w_redr_type >= UPD_REDRAW_TOP) { draw_vsep_win(wp); draw_hsep_win(wp); - draw_sep_connectors_win(wp); } syn_set_timeout(NULL); diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index f637bdc8c1..5a4e20b843 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -487,6 +487,72 @@ describe('global statusline', function() ]]) end) + it('vertical separator connector is not lost when switching window', function() + screen:add_extra_attr_ids { + [101] = { background = tonumber('0x282828') }, + [102] = { bold = true, background = tonumber('0x282828'), foreground = Screen.colors.Blue1 }, + } + command('hi NormalNC guibg=#282828') + command('vsplit | wincmd l | split') + -- Cursor is in top-right. Move to bottom-right. + feed('j') + -- Verify the ├ connector is present. + screen:expect([[ + {101: }│{101: }| + {102:~ }│{102:~ }|*6 + {102:~ }├─────────────────────────────| + {102:~ }│^ | + {102:~ }│{1:~ }|*5 + {3:[No Name] 0,0-1 All}| + | + ]]) + -- Navigate from bottom-right to left. + feed('h') + -- The ├ connector must still be present. + screen:expect([[ + ^ │{101: }| + {1:~ }│{102:~ }|*6 + {1:~ }├─────────────────────────────| + {1:~ }│{101: }| + {1:~ }│{102:~ }|*5 + {3:[No Name] 0,0-1 All}| + | + ]]) + end) + + it('horizontal separator connector is not lost when switching window', function() + screen:add_extra_attr_ids { + [101] = { background = tonumber('0x282828') }, + [102] = { bold = true, background = tonumber('0x282828'), foreground = Screen.colors.Blue1 }, + } + command('hi NormalNC guibg=#282828') + command('split | wincmd j | vsplit') + -- Cursor is in bottom-left. Move to bottom-right. + feed('l') + -- Verify the ┬ connector is present. + screen:expect([[ + {101: }| + {102:~ }|*6 + ──────────────────────────────┬─────────────────────────────| + {101: }│^ | + {102:~ }│{1:~ }|*5 + {3:[No Name] 0,0-1 All}| + | + ]]) + -- Navigate from bottom-right to top. + feed('k') + -- The ┬ connector must still be present. + screen:expect([[ + ^ | + {1:~ }|*6 + ──────────────────────────────┬─────────────────────────────| + {101: }│{101: }| + {102:~ }│{102:~ }|*5 + {3:[No Name] 0,0-1 All}| + | + ]]) + end) + it('horizontal separators unchanged when failing to split-move window', function() exec([[ botright split