diff --git a/src/nvim/window.c b/src/nvim/window.c index 85673566bb..5c148ca9c7 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -1440,7 +1440,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_fl } if (toplevel) { if (flags & WSP_BOT) { - frame_add_vsep(curfrp); + frame_set_vsep(curfrp, true); } // Set width of neighbor frame frame_new_width(curfrp, curfrp->fr_width @@ -3230,6 +3230,12 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_al int row = topleft->w_winrow; int col = topleft->w_wincol; + // If this is a rightmost window, remove vertical separators to the left. + if (win->w_vsep_width == 0 && frp_close->fr_parent->fr_layout == FR_ROW + && frp_close->fr_prev != NULL) { + frame_set_vsep(frp_close->fr_prev, false); + } + // Remove this frame from the list of frames. frame_remove(frp_close); @@ -3422,7 +3428,7 @@ void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) // Vertical separators to the left may have been lost. Restore them. if (wp->w_vsep_width == 0 && frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) { - frame_add_vsep(frp->fr_prev); + frame_set_vsep(frp->fr_prev, true); } // Statuslines or horizontal separators above may have been lost. Restore them. @@ -3868,23 +3874,26 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw topfrp->fr_width = width; } -/// Add the vertical separator to windows at the right side of "frp". +/// Add or remove the vertical separator of windows to the right side of "frp". /// Note: Does not check if there is room! -static void frame_add_vsep(const frame_T *frp) +static void frame_set_vsep(const frame_T *frp, bool add) FUNC_ATTR_NONNULL_ARG(1) { if (frp->fr_layout == FR_LEAF) { win_T *wp = frp->fr_win; - if (wp->w_vsep_width == 0) { + if (add && wp->w_vsep_width == 0) { if (wp->w_width > 0) { // don't make it negative - wp->w_width--; + win_new_width(wp, wp->w_width - 1); } wp->w_vsep_width = 1; + } else if (!add && wp->w_vsep_width == 1) { + win_new_width(wp, wp->w_width + 1); + wp->w_vsep_width = 0; } } else if (frp->fr_layout == FR_COL) { // Handle all the frames in the column. FOR_ALL_FRAMES(frp, frp->fr_child) { - frame_add_vsep(frp); + frame_set_vsep(frp, add); } } else { assert(frp->fr_layout == FR_ROW); @@ -3893,7 +3902,7 @@ static void frame_add_vsep(const frame_T *frp) while (frp->fr_next != NULL) { frp = frp->fr_next; } - frame_add_vsep(frp); + frame_set_vsep(frp, add); } } diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua index 37d1101ff2..6f71e17e97 100644 --- a/test/functional/legacy/window_cmd_spec.lua +++ b/test/functional/legacy/window_cmd_spec.lua @@ -1,11 +1,14 @@ +local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') local clear = n.clear +local eq = t.eq local exec = n.exec local exec_lua = n.exec_lua local command = n.command local feed = n.feed +local fn = n.fn -- oldtest: Test_window_cmd_ls0_split_scrolling() it('scrolling with laststatus=0 and :botright split', function() @@ -354,3 +357,53 @@ describe('splitkeep', function() ]]) end) end) + +-- oldtest: Test_winfixsize_vsep_statusline() +it("'winfixwidth/height' does not leave stray vseps/statuslines", function() + clear() + local screen = Screen.new(75, 8) + exec([[ + set noequalalways splitbelow splitright + vsplit + setlocal winfixwidth + vsplit + ]]) + eq(16, fn.winwidth(1)) + eq(37, fn.winwidth(2)) + eq(20, fn.winwidth(3)) + + command('quit') + screen:expect([[ + ^ │ | + {1:~ }│{1:~ }|*5 + {3:[No Name] }{2:[No Name] }| + | + ]]) + -- Checks w_view_width in Nvim; especially important as the screen test may still pass if only + -- w_width changed to make room for the vsep. + eq(36, fn.winwidth(1)) + eq(38, fn.winwidth(2)) + + exec([[ + set laststatus=0 + only + split + set winfixheight + split + ]]) + eq(1, fn.winheight(1)) + eq(3, fn.winheight(2)) + eq(1, fn.winheight(3)) + + command('quit') + screen:expect([[ + ^ | + {1:~ }| + {3:[No Name] }| + | + {1:~ }|*3 + | + ]]) + eq(2, fn.winheight(1)) + eq(4, fn.winheight(2)) +end) diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim index ae59adbc6e..6439b9d4a3 100644 --- a/test/old/testdir/test_window_cmd.vim +++ b/test/old/testdir/test_window_cmd.vim @@ -2261,4 +2261,50 @@ func Test_winfixsize_positions() %bwipe endfunc +func Test_winfixsize_vsep_statusline() + CheckScreendump + let lines =<< trim END + set noequalalways splitbelow splitright + vsplit + setlocal winfixwidth + vsplit + func SetupWfh() + set laststatus=0 + only + split + set winfixheight + split + endfunc + END + call writefile(lines, 'XTestWinfixsizeVsepStatusline', 'D') + let buf = RunVimInTerminal('-S XTestWinfixsizeVsepStatusline', #{rows: 8}) + + call term_sendkeys(buf, ":echo winwidth(1) winwidth(2) winwidth(3)\n") + call WaitForAssert({-> assert_match('^16 37 20\>', term_getline(buf, 8))}) + + call term_sendkeys(buf, ":quit\n") + call VerifyScreenDump(buf, 'Test_winfixsize_vsep_statusline_1', {}) + + " Reported widths should be consistent with the screen dump. + call term_sendkeys(buf, ":echo winwidth(1) winwidth(2)\n") + " (May be better if 'wfw' window remains at 37 columns, but the resize is + " consistent with how things currently work for 'winfix*' windows) + call WaitForAssert({-> assert_match('^36 38\>', term_getline(buf, 8))}) + + " For good measure, also check bottom-most 'winfixheight' windows don't leave + " stray statuslines with &laststatus=0. + call term_sendkeys(buf, + \ ":call SetupWfh() | echo winheight(1) winheight(2) winheight(3)\n") + call WaitForAssert({-> assert_match('^1 3 1\>', term_getline(buf, 8))}) + + call term_sendkeys(buf, ":quit\n") + call VerifyScreenDump(buf, 'Test_winfixsize_vsep_statusline_2', {}) + + call term_sendkeys(buf, ":echo winheight(1) winheight(2)\n") + " (Likewise, may be better if 'wfh' window remains at 3 rows) + call WaitForAssert({-> assert_match('^2 4\>', term_getline(buf, 8))}) + + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab