diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2026-03-14 17:44:06 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-14 17:44:06 -0400 |
| commit | 8c2b6d6062cbfe01acd8cfc396dab56bac09253e (patch) | |
| tree | 12bf4e87e36da984a3d3168046a330aac671a860 /test/functional/api/window_spec.lua | |
| parent | 0a9d6dc9aae61374ed6ec91c68e05b27e19cb108 (diff) | |
| parent | 3115e3d0d11e0e02ba9040ac1a7bb032afa762bb (diff) | |
| download | rneovim-8c2b6d6062cbfe01acd8cfc396dab56bac09253e.tar.gz rneovim-8c2b6d6062cbfe01acd8cfc396dab56bac09253e.tar.bz2 rneovim-8c2b6d6062cbfe01acd8cfc396dab56bac09253e.zip | |
Merge #35816 nvim_win_set_config can move floatwin to another tabpage
Diffstat (limited to 'test/functional/api/window_spec.lua')
| -rw-r--r-- | test/functional/api/window_spec.lua | 312 |
1 files changed, 258 insertions, 54 deletions
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 62cc514058..bd7189e084 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -2561,60 +2561,88 @@ describe('API/win', function() eq(win, layout[2][2][2]) end) - it('moves splits to other tabpages', function() - local curtab = api.nvim_get_current_tabpage() + it('moves windows to other tabpages', function() + local first_tab = api.nvim_get_current_tabpage() + local first_win = api.nvim_get_current_win() local win = api.nvim_open_win(0, false, { split = 'left' }) command('tabnew') - local tabnr = api.nvim_get_current_tabpage() - command('tabprev') -- return to the initial tab - - api.nvim_win_set_config(win, { - split = 'right', - win = api.nvim_tabpage_get_win(tabnr), - }) - - eq(tabnr, api.nvim_win_get_tabpage(win)) + local new_tab = api.nvim_get_current_tabpage() + local tab2_win = api.nvim_get_current_win() + api.nvim_set_current_tabpage(first_tab) + -- move new win to new tabpage + api.nvim_win_set_config(win, { split = 'right', win = api.nvim_tabpage_get_win(new_tab) }) + eq(new_tab, api.nvim_win_get_tabpage(win)) -- we are changing the config, the current tabpage should not change - eq(curtab, api.nvim_get_current_tabpage()) + eq(first_tab, api.nvim_get_current_tabpage()) - command('tabnext') -- switch to the new tabpage so we can get the layout + api.nvim_set_current_tabpage(new_tab) local layout = fn.winlayout() - eq({ 'row', { - { 'leaf', api.nvim_tabpage_get_win(tabnr) }, + { 'leaf', api.nvim_tabpage_get_win(new_tab) }, { 'leaf', win }, }, }, layout) + + -- directly convert split into a float for a different tabpage + local win2 = api.nvim_open_win(0, true, { split = 'below' }) + eq('', api.nvim_win_get_config(win2).relative) + api.nvim_win_set_config( + win2, + { relative = 'editor', row = 0, col = 0, width = 1, height = 1, win = first_win } + ) + eq(first_tab, api.nvim_win_get_tabpage(win2)) + eq('editor', api.nvim_win_get_config(win2).relative) + eq({ first_win, win2 }, api.nvim_tabpage_list_wins(first_tab)) + eq({ tab2_win, win }, api.nvim_tabpage_list_wins(new_tab)) + + -- convert new win to float in new tabpage + api.nvim_win_set_config(win, { relative = 'editor', row = 2, col = 2, height = 2, width = 2 }) + api.nvim_set_current_tabpage(first_tab) + -- move to other tabpage + api.nvim_win_set_config(win, { win = first_win }) + eq(first_tab, api.nvim_win_get_tabpage(win)) + eq({ first_win, win, win2 }, api.nvim_tabpage_list_wins(first_tab)) + eq({ tab2_win }, api.nvim_tabpage_list_wins(new_tab)) + -- unlike splits, negative win is invalid + eq('Invalid window id: -1', pcall_err(api.nvim_win_set_config, win, { win = -1 })) + + -- can't convert only window in other tabpage to float + command('tabnew') + local only_win = api.nvim_get_current_win() + command('tabprevious') + eq( + 'Cannot change last window into float', + pcall_err( + api.nvim_win_set_config, + only_win, + { relative = 'editor', width = 5, height = 5, row = 0, col = 0 } + ) + ) end) it('correctly moves curwin when moving curwin to a different tabpage', function() - local curtab = api.nvim_get_current_tabpage() + local tab1 = api.nvim_get_current_tabpage() + local tab1_win = api.nvim_get_current_win() command('tabnew') local tab2 = api.nvim_get_current_tabpage() local tab2_win = api.nvim_get_current_win() - - command('tabprev') -- return to the initial tab - - local neighbor = api.nvim_get_current_win() - + api.nvim_set_current_tabpage(tab1) -- return to the initial tab -- create and enter a new split local win = api.nvim_open_win(0, true, { vertical = false, }) - eq(curtab, api.nvim_win_get_tabpage(win)) - - eq({ win, neighbor }, api.nvim_tabpage_list_wins(curtab)) + eq(tab1, api.nvim_win_get_tabpage(win)) + eq({ win, tab1_win }, api.nvim_tabpage_list_wins(tab1)) -- move the current win to a different tabpage api.nvim_win_set_config(win, { split = 'right', win = api.nvim_tabpage_get_win(tab2), }) - - eq(curtab, api.nvim_get_current_tabpage()) + eq(tab1, api.nvim_get_current_tabpage()) -- win should have moved to tab2 eq(tab2, api.nvim_win_get_tabpage(win)) @@ -2622,10 +2650,18 @@ describe('API/win', function() eq(tab2_win, api.nvim_tabpage_get_win(tab2)) -- win lists should be correct eq({ tab2_win, win }, api.nvim_tabpage_list_wins(tab2)) - eq({ neighbor }, api.nvim_tabpage_list_wins(curtab)) - + eq({ tab1_win }, api.nvim_tabpage_list_wins(tab1)) -- current win should have moved to neighboring win - eq(neighbor, api.nvim_tabpage_get_win(curtab)) + eq(tab1_win, api.nvim_tabpage_get_win(tab1)) + + api.nvim_set_current_tabpage(tab2) + -- convert new win to float + api.nvim_win_set_config(win, { relative = 'editor', row = 2, col = 2, height = 2, width = 2 }) + api.nvim_set_current_win(win) + api.nvim_win_set_config(win, { relative = 'win', win = tab1_win, row = 3, col = 3 }) + eq(tab1, api.nvim_win_get_tabpage(win)) + eq(tab2, api.nvim_get_current_tabpage()) + eq({ tab1_win, win }, api.nvim_tabpage_list_wins(tab1)) end) it('splits windows in non-current tabpage', function() @@ -2752,7 +2788,6 @@ describe('API/win', function() it('messing with "win" or "parent" when moving "win" to other tabpage', function() command('split | tabnew') - local t2 = api.nvim_get_current_tabpage() local t2_win1 = api.nvim_get_current_win() command('split') local t2_win2 = api.nvim_get_current_win() @@ -2797,23 +2832,19 @@ describe('API/win', function() eq('', api.nvim_win_get_config(0).relative) eq(cur_win, api.nvim_get_current_win()) - -- Try to make "parent" floating. This should give the same error as before, but because - -- changing a split from another tabpage into a float isn't supported yet, check for that - -- error instead for now. - -- Use ":silent!" to avoid the one second delay from printing the error message. + -- Try to make "parent" floating. This should give the same error as before. exec(([[ - autocmd WinLeave * ++once silent! + autocmd WinLeave * ++once \ call nvim_win_set_config(%d, #{relative:'editor', row:0, col:0, width:5, height:5}) ]]):format(t2_win3)) cur_win = api.nvim_get_current_win() - api.nvim_win_set_config(0, { win = t2_win3, split = 'left' }) - matches( - 'Cannot change window from different tabpage into float$', - api.nvim_get_vvar('errmsg') + eq( + 'Floating state of windows to split changed', + pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' }) ) - -- The error doesn't abort moving the window (or maybe it should, if that's wanted?) - neq(cur_win, api.nvim_get_current_win()) - eq(t2, api.nvim_win_get_tabpage(cur_win)) + eq('editor', api.nvim_win_get_config(t2_win3).relative) + eq('', api.nvim_win_get_config(0).relative) + eq(cur_win, api.nvim_get_current_win()) end) it('expected autocmds when moving window to other tabpage', function() @@ -2834,18 +2865,35 @@ describe('API/win', function() eq({ 'Leave', win, 'Enter', new_curwin }, eval('result')) end) - it('no autocmds when moving window within same tabpage', function() + it('no autocmds when moving window in same or other tabpage', function() local parent = api.nvim_get_current_win() exec([[ split - let result = [] - autocmd WinEnter * let result += ["Enter", win_getid()] - autocmd WinLeave * let result += ["Leave", win_getid()] - autocmd WinNew * let result += ["New", win_getid()] + let g:result = [] + autocmd WinEnter * let g:result += ["Enter", win_getid()] + autocmd WinLeave * let g:result += ["Leave", win_getid()] + autocmd WinNew * let g:result += ["New", win_getid()] ]]) api.nvim_win_set_config(0, { win = parent, split = 'left' }) -- Shouldn't see any of those events, as we remain in the same window. - eq({}, eval('result')) + eq({}, eval('g:result')) + + -- move float window from tab2 to tab1 + command('tabdo only') + local tab1 = api.nvim_get_current_tabpage() + local tab1_win1 = api.nvim_get_current_win() + command('tabnew') + local fwin = api.nvim_open_win(0, false, { + relative = 'editor', + row = 2, + col = 2, + height = 2, + width = 2, + }) + api.nvim_set_current_tabpage(tab1) + api.nvim_set_var('result', {}) + api.nvim_win_set_config(fwin, { win = tab1_win1 }) + eq({}, eval('g:result')) end) it('checks if splitting disallowed', function() @@ -3120,7 +3168,6 @@ describe('API/win', function() ) command('quit!') - -- Can't switch away from window before moving it to a different tabpage during textlock. exec(([[ new call setline(1, 'foo') @@ -3132,6 +3179,41 @@ describe('API/win', function() pcall_err(command, 'normal! ==') ) eq(cur_win, api.nvim_get_current_win()) + exec(([[ + wincmd p + call setline(1, 'bar') + setlocal indentexpr=nvim_win_set_config(win_getid(winnr('#')),#{split:'left',win:%d}) + ]]):format(t2_win)) + neq(cur_win, api.nvim_get_current_win()) + matches( + 'E565: Not allowed to change text or change window$', + pcall_err(command, 'normal! ==') + ) + -- expr_map_lock + exec(([[ + nnoremap <expr> @ nvim_win_set_config(win_getid(winnr('#')),#{split:'left',win:%d}) + ]]):format(t2_win)) + neq(cur_win, api.nvim_get_current_win()) + matches( + 'E565: Not allowed to change text or change window$', + pcall_err(fn.feedkeys, '@', 'x') + ) + + exec(([[ + wincmd p + autocmd WinNewPre * ++once call nvim_win_set_config(0, #{relative:'editor', win:%d, row:0, col:0, width:1, height:1}) + ]]):format(t2_win)) + matches( + 'E1312: Not allowed to change the window layout in this autocmd$', + pcall_err(command, 'split') + ) + eq(cur_win, api.nvim_get_current_win()) -- :split didn't enter new window due to error + + exec(([[ + autocmd WinLeave * ++once call nvim_win_set_config(0, #{relative:'editor', win:%d, row:0, col:0, width:1, height:1}) + ]]):format(t2_win)) + matches('Cannot move window to another tabpage whilst in use$', pcall_err(command, 'quit')) + eq(cur_win, api.nvim_get_current_win()) -- :quit didn't close window due to error end) it('updates statusline when moving bottom split', function() @@ -3190,6 +3272,35 @@ describe('API/win', function() api.nvim_win_set_config(t2_cur_win, { split = 'left', win = 0 }) eq(t2_alt_win, api.nvim_tabpage_get_win(t2)) eq(t1, api.nvim_win_get_tabpage(t2_cur_win)) + + -- Very fun: move curwin between tabpages, converting from split to float, but with an autocmd + -- that deletes altwin after we're bumped to it, re-enters curwin, then switches to a 3rd + -- tabpage. tp_curwin of the window's old tabpage shouldn't be set to the freed altwin! + command('tablast | tab split | tabprevious | split') + command('autocmd WinEnter * ++once quit | let expect_alt = win_getid() | wincmd p | tabnext') + api.nvim_win_set_config(0, { + relative = 'editor', + win = api.nvim_tabpage_get_win(t1), + row = 0, + col = 0, + width = 5, + height = 5, + }) + eq(eval('g:expect_alt'), api.nvim_tabpage_get_win(t2)) + + -- Same, but for float -> float. + command('tabprevious | split') + api.nvim_open_win(0, true, { relative = 'editor', row = 0, col = 0, width = 1, height = 1 }) + command('autocmd WinEnter * ++once quit | let expect_alt = win_getid() | wincmd p | tabnext') + api.nvim_win_set_config(0, { + relative = 'editor', + win = api.nvim_tabpage_get_win(t1), + row = 0, + col = 0, + width = 5, + height = 5, + }) + eq(eval('g:expect_alt'), api.nvim_tabpage_get_win(t2)) end) it('set_config cannot change "noautocmd" #36409', function() @@ -3203,6 +3314,64 @@ describe('API/win', function() pcall_err(api.nvim_win_set_config, win, cfg) ) end) + + it('removes last statusline if needed', function() + local screen = Screen.new(30, 9) + command('set laststatus=1 | botright split') + screen:expect([[ + | + {1:~ }|*2 + {2:[No Name] }| + ^ | + {1:~ }|*2 + {3:[No Name] }| + | + ]]) + api.nvim_win_set_config(0, { relative = 'editor', row = 0, col = 0, width = 4, height = 4 }) + screen:expect([[ + {4:^ } | + {11:~ }{1: }|*3 + {1:~ }|*4 + | + ]]) + command('quit | set laststatus=2 | botright split') + screen:expect([[ + | + {1:~ }|*2 + {2:[No Name] }| + ^ | + {1:~ }|*2 + {3:[No Name] }| + | + ]]) + api.nvim_win_set_config(0, { relative = 'editor', row = 1, col = 5, width = 4, height = 4 }) + screen:expect([[ + | + {1:~ }{4:^ }{1: }| + {1:~ }{11:~ }{1: }|*3 + {1:~ }|*2 + {2:[No Name] }| + | + ]]) + end) + + it('can convert external window to non-external', function() + Screen.new(20, 7, { ext_multigrid = true }) -- multigrid needed for external windows + api.nvim_open_win(0, true, { external = true, width = 5, height = 5 }) + eq(true, api.nvim_win_get_config(0).external) + api.nvim_win_set_config(0, { split = 'below', win = fn.win_getid(1) }) + eq(false, api.nvim_win_get_config(0).external) + + api.nvim_win_set_config(0, { external = true, width = 5, height = 5 }) + eq(true, api.nvim_win_get_config(0).external) + api.nvim_win_set_config(0, { relative = 'editor', row = 3, col = 3 }) + eq(false, api.nvim_win_get_config(0).external) + + api.nvim_win_set_config(0, { external = true, width = 5, height = 5 }) + eq(true, api.nvim_win_get_config(0).external) + api.nvim_win_set_config(0, { external = false }) + eq(false, api.nvim_win_get_config(0).external) + end) end) describe('get_config', function() @@ -3542,20 +3711,25 @@ describe('API/win', function() end) it('cannot move autocmd window between tabpages', function() - local win_type, split_ok, err = exec_lua(function() + local win_type, split_ok, split_err, float_ok, float_err = exec_lua(function() local other_tp_win = vim.api.nvim_get_current_win() vim.cmd.tabnew() - local win_type, split_ok, err + local win_type, split_ok, split_err, float_ok, float_err vim.api.nvim_buf_call(vim.api.nvim_create_buf(true, true), function() win_type = vim.fn.win_gettype() - split_ok, err = + + split_ok, split_err = pcall(vim.api.nvim_win_set_config, 0, { win = other_tp_win, split = 'right' }) + + float_ok, float_err = pcall(vim.api.nvim_win_set_config, 0, { win = other_tp_win }) end) - return win_type, split_ok, err + return win_type, split_ok, split_err, float_ok, float_err end) + eq('autocmd', win_type) - eq({ false, 'Cannot move autocmd window to another tabpage' }, { split_ok, err }) + eq({ false, 'Cannot move autocmd window to another tabpage' }, { split_ok, split_err }) + eq({ false, 'Cannot move autocmd window to another tabpage' }, { float_ok, float_err }) end) it('cannot move cmdwin between tabpages', function() @@ -3656,5 +3830,35 @@ describe('API/win', function() api.nvim_open_win(0, true, { split = 'below', style = 'minimal' }) command('quit') end) + + it('preserve current floating window when moving fails', function() + local buf = api.nvim_create_buf(false, true) + local float_win = api.nvim_open_win(buf, true, { + relative = 'editor', + row = 1, + col = 1, + width = 10, + height = 5, + }) + command('tabnew') + local tab2_win = api.nvim_get_current_win() + command('tabprev') + api.nvim_set_current_win(float_win) + command('autocmd WinLeave * ++once call nvim_win_close(' .. tab2_win .. ', v:true)') + eq( + 'Target windows were closed', + pcall_err(api.nvim_win_set_config, float_win, { win = tab2_win }) + ) + eq(float_win, api.nvim_get_current_win()) + + command('tabnew') + local tab3_win = api.nvim_get_current_win() + command('tabprev | autocmd WinEnter * ++once wincmd p') + eq( + ('Failed to switch away from window %d'):format(float_win), + pcall_err(api.nvim_win_set_config, float_win, { win = tab3_win }) + ) + eq(float_win, api.nvim_get_current_win()) + end) end) end) |