From bcb70eeac48040fd6d6bfc20cf7fb6f41374a67c Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 4 Feb 2024 00:42:36 +0000 Subject: fix(api): win_set_config autocmds crash when moving win to other tabpage Problem: win_enter autocommands can close new_curwin, crashing if it was the last window in its tabpage after removing win, or can close parent, crashing when attempting to split it later. Solution: remove win first, check that parent is valid after win_enter. NOTE: This isn't actually quite right, as this means win is not in the window list or even has a frame when triggering enter autocommands (so it's not considered valid in the tabpage). This is addressed in later commits. --- test/functional/api/window_spec.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 097a546ef2..a812d502eb 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1663,6 +1663,27 @@ describe('API/win', function() }, }, fn.winlayout()) end) + + it('closing new curwin when moving window to other tabpage works', function() + command('split | tabnew') + local w = api.nvim_get_current_win() + local t = api.nvim_get_current_tabpage() + command('tabfirst | autocmd WinEnter * ++once quit') + api.nvim_win_set_config(0, { win = w, split = 'left' }) + -- New tabpage is now the only one, as WinEnter closed the new curwin in the original. + eq(t, api.nvim_get_current_tabpage()) + eq({ t }, api.nvim_list_tabpages()) + end) + + it('closing split parent when moving window to other tabpage aborts', function() + command('split | tabnew') + local w = api.nvim_get_current_win() + command('tabfirst | autocmd WinEnter * call nvim_win_close(' .. w .. ', 1)') + eq( + 'Window to split was closed', + pcall_err(api.nvim_win_set_config, 0, { win = w, split = 'left' }) + ) + end) end) describe('get_config', function() -- cgit From 233649bc757743f7677b2ae414779192a94aa2ae Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 4 Feb 2024 01:50:49 +0000 Subject: fix(api): win_set_config fires unnecessary autocmds Problem: win_set_config should have the observable effect of moving an existing window to another place, but instead fires autocommands as if a new window was created and entered (and does not fire autocommands reflecting a "return" to the original window). Solution: do not fire win_enter-related autocommands when splitting the window, but continue to fire them when entering the window that fills the new space when moving a window to a different tabpage, as the new curwin changes. Also, remove "++once" from the WinEnter autocmd in the other test, as omitting it also crashed Nvim before this fix. --- test/functional/api/window_spec.lua | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index a812d502eb..3914090814 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1668,7 +1668,7 @@ describe('API/win', function() command('split | tabnew') local w = api.nvim_get_current_win() local t = api.nvim_get_current_tabpage() - command('tabfirst | autocmd WinEnter * ++once quit') + command('tabfirst | autocmd WinEnter * quit') api.nvim_win_set_config(0, { win = w, split = 'left' }) -- New tabpage is now the only one, as WinEnter closed the new curwin in the original. eq(t, api.nvim_get_current_tabpage()) @@ -1684,6 +1684,38 @@ describe('API/win', function() pcall_err(api.nvim_win_set_config, 0, { win = w, split = 'left' }) ) end) + + it('expected autocmds when moving window to other tabpage', function() + local new_curwin = api.nvim_get_current_win() + command('split') + local win = api.nvim_get_current_win() + command('tabnew') + local parent = api.nvim_get_current_win() + exec([[ + tabfirst + let result = [] + autocmd WinEnter * let result += ["Enter", win_getid()] + autocmd WinLeave * let result += ["Leave", win_getid()] + autocmd WinNew * let result += ["New", win_getid()] + ]]) + api.nvim_win_set_config(0, { win = parent, split = 'left' }) + -- Shouldn't see WinNew, as we're not creating any new windows, just moving existing ones. + eq({ 'Leave', win, 'Enter', new_curwin }, eval('result')) + end) + + it('no autocmds when moving window within same 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()] + ]]) + 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')) + end) end) describe('get_config', function() -- cgit From a873f33993ef84e3f954127038e559e1ac1cac43 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 4 Feb 2024 02:59:26 +0000 Subject: fix(api): open_win fire BufWinEnter for other buffer when !enter && !noautocmd Problem: BufWinEnter is not fired when not entering a new window, even when a different buffer is specified and buffer-related autocommands are unblocked (!noautocmd). Solution: fire it in the context of the new window and buffer. Do not do it if the buffer is unchanged, like :{s}buffer. Be wary of autocommands! For example, it's possible for nvim_win_set_config to be used in an autocommand to move a window to a different tabpage (in contrast, things like wincmd T actually create a *new* window, so it may not have been possible before, meaning other parts of Nvim could assume windows can't do this... I'd be especially cautious of logic that restores curwin and curtab without checking if curwin is still valid in curtab, if any such logic exists). Also, bail early from win_set_buf if setting the temp curwin fails; this shouldn't be possible, as the callers check that wp is valid, but in case that's not true, win_set_buf will no longer continue setting a buffer for the wrong window. Note that pum_create_float_preview also uses win_set_buf, but from a glance, doesn't look like it properly checks for autocmds screwing things up (win_enter, nvim_create_buf...). I haven't addressed that here. Also adds some test coverage for nvim_open_win autocommands. Closes #27121. --- test/functional/api/window_spec.lua | 207 ++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 3914090814..8966c3b086 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1364,6 +1364,213 @@ describe('API/win', function() }, }, layout) end) + + local function setup_tabbed_autocmd_test() + local info = {} + info.orig_buf = api.nvim_get_current_buf() + info.other_buf = api.nvim_create_buf(true, true) + info.tab1_curwin = api.nvim_get_current_win() + info.tab1 = api.nvim_get_current_tabpage() + command('tab split | split') + info.tab2_curwin = api.nvim_get_current_win() + info.tab2 = api.nvim_get_current_tabpage() + exec([=[ + tabfirst + let result = [] + autocmd TabEnter * let result += [["TabEnter", nvim_get_current_tabpage()]] + autocmd TabLeave * let result += [["TabLeave", nvim_get_current_tabpage()]] + autocmd WinEnter * let result += [["WinEnter", win_getid()]] + autocmd WinLeave * let result += [["WinLeave", win_getid()]] + autocmd WinNew * let result += [["WinNew", win_getid()]] + autocmd WinClosed * let result += [["WinClosed", str2nr(expand(""))]] + autocmd BufEnter * let result += [["BufEnter", win_getid(), bufnr()]] + autocmd BufLeave * let result += [["BufLeave", win_getid(), bufnr()]] + autocmd BufWinEnter * let result += [["BufWinEnter", win_getid(), bufnr()]] + autocmd BufWinLeave * let result += [["BufWinLeave", win_getid(), bufnr()]] + ]=]) + return info + end + + it('fires expected autocmds when creating splits without entering', function() + local info = setup_tabbed_autocmd_test() + + -- For these, don't want BufWinEnter if visiting the same buffer, like :{s}buffer. + -- Same tabpage, same buffer. + local new_win = api.nvim_open_win(0, false, { split = 'left', win = info.tab1_curwin }) + eq({ + { 'WinNew', new_win }, + }, eval('result')) + eq(info.tab1_curwin, api.nvim_get_current_win()) + + -- Other tabpage, same buffer. + command('let result = []') + new_win = api.nvim_open_win(0, false, { split = 'left', win = info.tab2_curwin }) + eq({ + { 'WinNew', new_win }, + }, eval('result')) + eq(info.tab1_curwin, api.nvim_get_current_win()) + + -- Same tabpage, other buffer. + command('let result = []') + new_win = api.nvim_open_win(info.other_buf, false, { split = 'left', win = info.tab1_curwin }) + eq({ + { 'WinNew', new_win }, + { 'BufWinEnter', new_win, info.other_buf }, + }, eval('result')) + eq(info.tab1_curwin, api.nvim_get_current_win()) + + -- Other tabpage, other buffer. + command('let result = []') + new_win = api.nvim_open_win(info.other_buf, false, { split = 'left', win = info.tab2_curwin }) + eq({ + { 'WinNew', new_win }, + { 'BufWinEnter', new_win, info.other_buf }, + }, eval('result')) + eq(info.tab1_curwin, api.nvim_get_current_win()) + end) + + it('fires expected autocmds when creating and entering splits', function() + local info = setup_tabbed_autocmd_test() + + -- Same tabpage, same buffer. + local new_win = api.nvim_open_win(0, true, { split = 'left', win = info.tab1_curwin }) + eq({ + { 'WinNew', new_win }, + { 'WinLeave', info.tab1_curwin }, + { 'WinEnter', new_win }, + }, eval('result')) + + -- Same tabpage, other buffer. + api.nvim_set_current_win(info.tab1_curwin) + command('let result = []') + new_win = api.nvim_open_win(info.other_buf, true, { split = 'left', win = info.tab1_curwin }) + eq({ + { 'WinNew', new_win }, + { 'WinLeave', info.tab1_curwin }, + { 'WinEnter', new_win }, + { 'BufLeave', new_win, info.orig_buf }, + { 'BufEnter', new_win, info.other_buf }, + { 'BufWinEnter', new_win, info.other_buf }, + }, eval('result')) + + -- For these, the other tabpage's prevwin and curwin will change like we switched from its old + -- curwin to the new window, so the extra events near TabEnter reflect that. + -- Other tabpage, same buffer. + api.nvim_set_current_win(info.tab1_curwin) + command('let result = []') + new_win = api.nvim_open_win(0, true, { split = 'left', win = info.tab2_curwin }) + eq({ + { 'WinNew', new_win }, + { 'WinLeave', info.tab1_curwin }, + { 'TabLeave', info.tab1 }, + + { 'WinEnter', info.tab2_curwin }, + { 'TabEnter', info.tab2 }, + { 'WinLeave', info.tab2_curwin }, + { 'WinEnter', new_win }, + }, eval('result')) + + -- Other tabpage, other buffer. + api.nvim_set_current_win(info.tab2_curwin) + api.nvim_set_current_win(info.tab1_curwin) + command('let result = []') + new_win = api.nvim_open_win(info.other_buf, true, { split = 'left', win = info.tab2_curwin }) + eq({ + { 'WinNew', new_win }, + { 'WinLeave', info.tab1_curwin }, + { 'TabLeave', info.tab1 }, + + { 'WinEnter', info.tab2_curwin }, + { 'TabEnter', info.tab2 }, + { 'WinLeave', info.tab2_curwin }, + { 'WinEnter', new_win }, + + { 'BufLeave', new_win, info.orig_buf }, + { 'BufEnter', new_win, info.other_buf }, + { 'BufWinEnter', new_win, info.other_buf }, + }, eval('result')) + + -- Other tabpage, other buffer; but other tabpage's curwin has a new buffer active. + api.nvim_set_current_win(info.tab2_curwin) + local new_buf = api.nvim_create_buf(true, true) + api.nvim_set_current_buf(new_buf) + api.nvim_set_current_win(info.tab1_curwin) + command('let result = []') + new_win = api.nvim_open_win(info.other_buf, true, { split = 'left', win = info.tab2_curwin }) + eq({ + { 'WinNew', new_win }, + { 'BufLeave', info.tab1_curwin, info.orig_buf }, + { 'WinLeave', info.tab1_curwin }, + { 'TabLeave', info.tab1 }, + + { 'WinEnter', info.tab2_curwin }, + { 'TabEnter', info.tab2 }, + { 'BufEnter', info.tab2_curwin, new_buf }, + { 'WinLeave', info.tab2_curwin }, + { 'WinEnter', new_win }, + { 'BufLeave', new_win, new_buf }, + { 'BufEnter', new_win, info.other_buf }, + { 'BufWinEnter', new_win, info.other_buf }, + }, eval('result')) + end) + + it('OK when new window is moved to other tabpage by autocommands', function() + -- Use nvim_win_set_config in the autocommands, as other methods of moving a window to a + -- different tabpage (e.g: wincmd T) actually creates a new window. + local tab0 = api.nvim_get_current_tabpage() + local tab0_win = api.nvim_get_current_win() + command('tabnew') + local new_buf = api.nvim_create_buf(true, true) + local tab1 = api.nvim_get_current_tabpage() + local tab1_parent = api.nvim_get_current_win() + command( + 'tabfirst | autocmd WinNew * ++once call nvim_win_set_config(0, #{split: "left", win: ' + .. tab1_parent + .. '})' + ) + local new_win = api.nvim_open_win(new_buf, true, { split = 'left' }) + eq(tab1, api.nvim_get_current_tabpage()) + eq(new_win, api.nvim_get_current_win()) + eq(new_buf, api.nvim_get_current_buf()) + + -- nvim_win_set_config called after entering. It doesn't follow a curwin that is moved to a + -- different tabpage, but instead moves to the win filling the space, which is tab0_win. + command( + 'tabfirst | autocmd WinEnter * ++once call nvim_win_set_config(0, #{split: "left", win: ' + .. tab1_parent + .. '})' + ) + new_win = api.nvim_open_win(new_buf, true, { split = 'left' }) + eq(tab0, api.nvim_get_current_tabpage()) + eq(tab0_win, api.nvim_get_current_win()) + eq(tab1, api.nvim_win_get_tabpage(new_win)) + eq(new_buf, api.nvim_win_get_buf(new_win)) + + command( + 'tabfirst | autocmd BufEnter * ++once call nvim_win_set_config(0, #{split: "left", win: ' + .. tab1_parent + .. '})' + ) + new_win = api.nvim_open_win(new_buf, true, { split = 'left' }) + eq(tab0, api.nvim_get_current_tabpage()) + eq(tab0_win, api.nvim_get_current_win()) + eq(tab1, api.nvim_win_get_tabpage(new_win)) + eq(new_buf, api.nvim_win_get_buf(new_win)) + end) + + it('does not fire BufWinEnter if win_set_buf fails', function() + exec([[ + set nohidden modified + autocmd WinNew * ++once only! + let fired = v:false + autocmd BufWinEnter * ++once let fired = v:true + ]]) + eq( + 'Failed to set buffer 2', + pcall_err(api.nvim_open_win, api.nvim_create_buf(true, true), false, { split = 'left' }) + ) + eq(false, eval('fired')) + end) end) describe('set_config', function() -- cgit From e55a502ed413d2bc8954b5227acfb34c8689f979 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 11 Feb 2024 18:45:56 +0000 Subject: fix(api): open_win fire Buf* events when !enter && !noautocmd if entered early Problem: if switch_win{_noblock} fails to restore the old curwin after WinNew (e.g: it was closed), wp will become the new curwin, but win_set_buf enter events would still be blocked if !enter && !noautocmd. Solution: fire them, as we've actually entered the new window. Note: there's a problem of switch_win{_noblock} failing to restore the old curwin, leaving us in wp without triggering WinEnter/WinLeave, but this affects all callers of switch_win{_noblock} anyways. (It's also not clear how WinLeave can be called if the old curwin was closed already). --- test/functional/api/window_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 8966c3b086..e0cb66de41 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1571,6 +1571,16 @@ describe('API/win', function() ) eq(false, eval('fired')) end) + + it('fires Buf* autocommands when `!enter` if window is entered via autocommands', function() + exec([[ + autocmd WinNew * ++once only! + let fired = v:false + autocmd BufEnter * ++once let fired = v:true + ]]) + api.nvim_open_win(api.nvim_create_buf(true, true), false, { split = 'left' }) + eq(true, eval('fired')) + end) end) describe('set_config', function() -- cgit From b1e24f240baeea80dcf4a3d8453fed0230fb88fd Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 11 Feb 2024 20:15:47 +0000 Subject: fix(api): avoid open_win UAF if target buf deleted by autocmds Problem: WinNew and win_enter autocommands can delete the target buffer to switch to, causing a heap-use-after-free. Solution: store a bufref to the buffer, check it before attempting to switch. --- test/functional/api/window_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index e0cb66de41..2f6a02b5d5 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1581,6 +1581,14 @@ describe('API/win', function() api.nvim_open_win(api.nvim_create_buf(true, true), false, { split = 'left' }) eq(true, eval('fired')) end) + + it('no heap-use-after-free if target buffer deleted by autocommands', function() + local cur_buf = api.nvim_get_current_buf() + local new_buf = api.nvim_create_buf(true, true) + command('autocmd WinNew * ++once call nvim_buf_delete(' .. new_buf .. ', #{force: 1})') + api.nvim_open_win(new_buf, true, { split = 'left' }) + eq(cur_buf, api.nvim_get_current_buf()) + end) end) describe('set_config', function() -- cgit From 5d58136cccc760f6d95eb45b46f2ad60f06b103b Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Wed, 7 Feb 2024 17:17:44 +0000 Subject: fix(api): make open_win/win_set_config check if splitting allowed Problem: splitting is disallowed in some cases to prevent the window layout changes while a window is closing, but it's not checked for. Solution: check for this, and set the API error message directly. (Also sneak in a change to tui.c that got lost from #27352; it's a char* buf, and the memset is assuming one byte each anyway) --- test/functional/api/window_spec.lua | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 2f6a02b5d5..30235d6b84 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1589,6 +1589,37 @@ describe('API/win', function() api.nvim_open_win(new_buf, true, { split = 'left' }) eq(cur_buf, api.nvim_get_current_buf()) end) + + it('checks if splitting disallowed', function() + command('split | autocmd WinEnter * ++once call nvim_open_win(0, 0, #{split: "right"})') + matches("E242: Can't split a window while closing another$", pcall_err(command, 'quit')) + + command('only | autocmd BufHidden * ++once call nvim_open_win(0, 0, #{split: "left"})') + matches( + 'E1159: Cannot split a window when closing the buffer$', + pcall_err(command, 'new | quit') + ) + + local w = api.nvim_get_current_win() + command( + 'only | new | autocmd BufHidden * ++once call nvim_open_win(0, 0, #{split: "left", win: ' + .. w + .. '})' + ) + matches( + 'E1159: Cannot split a window when closing the buffer$', + pcall_err(api.nvim_win_close, w, true) + ) + + -- OK when using window to different buffer than `win`s. + w = api.nvim_get_current_win() + command( + 'only | autocmd BufHidden * ++once call nvim_open_win(0, 0, #{split: "left", win: ' + .. w + .. '})' + ) + command('new | quit') + end) end) describe('set_config', function() @@ -1941,6 +1972,22 @@ describe('API/win', function() -- Shouldn't see any of those events, as we remain in the same window. eq({}, eval('result')) end) + + it('checks if splitting disallowed', function() + command('split | autocmd WinEnter * ++once call nvim_win_set_config(0, #{split: "right"})') + matches("E242: Can't split a window while closing another$", pcall_err(command, 'quit')) + + command('autocmd BufHidden * ++once call nvim_win_set_config(0, #{split: "left"})') + matches( + 'E1159: Cannot split a window when closing the buffer$', + pcall_err(command, 'new | quit') + ) + + -- OK when using window to different buffer. + local w = api.nvim_get_current_win() + command('autocmd BufHidden * ++once call nvim_win_set_config(' .. w .. ', #{split: "left"})') + command('new | quit') + end) end) describe('get_config', function() -- cgit From b1577d371a6db43222de9e3a525def82320ebdb1 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Wed, 7 Feb 2024 21:44:42 +0000 Subject: fix(api): make win_set_config with "win" for splits need "split/vertical" Problem: currently, for splits, nvim_win_set_config accepts win without any of split or vertical set, which has little effect and seems error-prone. Solution: require at least one of split or vertical to also be set for splits. Also, update nvim_win_set_config docs, as it's no longer limited to just floating and external windows. --- test/functional/api/window_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 30235d6b84..246ff50ddc 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1727,6 +1727,15 @@ describe('API/win', function() config = api.nvim_win_get_config(win) eq('', config.relative) eq('below', config.split) + + eq( + "non-float with 'win' requires at least 'split' or 'vertical'", + pcall_err(api.nvim_win_set_config, 0, { win = 0 }) + ) + eq( + "non-float with 'win' requires at least 'split' or 'vertical'", + pcall_err(api.nvim_win_set_config, 0, { win = 0, relative = '' }) + ) end) it('creates top-level splits', function() -- cgit From a70eae57bd44208a77b5ac29839e8a39ab3c9cd8 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 11 Feb 2024 22:53:37 +0000 Subject: fix(api): make open_win block only enter/leave events if !enter && !noautocmd Problem: nvim_open_win blocking all win_set_buf autocommands when !enter && !noautocmd is too aggressive. Solution: temporarily block WinEnter/Leave and BufEnter/Leave events when setting the buffer. Delegate the firing of BufWinEnter back to win_set_buf, which also has the advantage of keeping the timing consistent (e.g: before the epilogue in enter_buffer, which also handles restoring the cursor position if autocommands didn't change it, among other things). Reword the documentation for noautocmd a bit. I pondered modifying do_buffer and callees to allow for BufEnter/Leave being conditionally disabled, but it seems too invasive (and potentially error-prone, especially if new code paths to BufEnter/Leave are added in the future). Unfortunately, doing this has the drawback of blocking ALL such events for the duration, which also means blocking unrelated such events; like if window switching occurs in a ++nested autocmd fired by win_set_buf. If this turns out to be a problem in practice, a different solution specialized for nvim_open_win could be considered. :-) --- test/functional/api/window_spec.lua | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 246ff50ddc..6e20c81fc2 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1620,6 +1620,40 @@ describe('API/win', function() ) command('new | quit') end) + + it('restores last known cursor position if BufWinEnter did not move it', function() + -- This test mostly exists to ensure BufWinEnter is executed before enter_buffer's epilogue. + local buf = api.nvim_get_current_buf() + insert([[ + foo + bar baz .etc + i love autocommand bugs! + supercalifragilisticexpialidocious + marvim is actually a human + llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch + ]]) + api.nvim_win_set_cursor(0, { 5, 2 }) + command('set nostartofline | enew') + local new_win = api.nvim_open_win(buf, false, { split = 'left' }) + eq({ 5, 2 }, api.nvim_win_get_cursor(new_win)) + + exec([[ + only! + autocmd BufWinEnter * ++once normal! j6l + ]]) + new_win = api.nvim_open_win(buf, false, { split = 'left' }) + eq({ 2, 6 }, api.nvim_win_get_cursor(new_win)) + end) + + it('does not block all win_set_buf autocommands if !enter and !noautocmd', function() + local new_buf = fn.bufadd('foobarbaz') + exec([[ + let triggered = "" + autocmd BufReadCmd * ++once let triggered = bufname() + ]]) + api.nvim_open_win(new_buf, false, { split = 'left' }) + eq('foobarbaz', eval('triggered')) + end) end) describe('set_config', function() -- cgit From d942c2b9432d81e4b509519bd48fa886e37e9ca8 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:51:31 +0000 Subject: fix(api): handle win_split_ins failure properly Problem: nvim_win_set_config does not handle failure in win_split_ins properly yet, which can cause all sorts of issues. Also nvim_open_win and nvim_win_set_config do not set the error message to the one from win_split_ins. Solution: handle failure by undoing winframe_remove, like in win_splitmove. Make sure autocommands from switching to the altwin fire within a valid window, and ensure they don't screw things up. Set the error message to that of win_split_ins, if any. Also change a few other small things, including: - adjust win_append to take a tabpage_T * argument, which is more consistent with win_remove (and also allows us to undo a call to win_remove). - allow winframe_restore to restore window positions. Useful if `wp` was in a different tabpage, as a call to win_comp_pos (which only works for the current tabpage) after winframe_restore should no longer be needed. Though enter_tabpage calls win_comp_pos anyway, this has the advantage of ensuring w_winrow/col remains accurate even before entering the tabpage (useful for stuff like win_screenpos, if used on a window in another tabpage). (This change should probably also be PR'd to Vim later, even though it doesn't use winframe_restore for a `wp` in a different tabpage yet). --- test/functional/api/window_spec.lua | 319 ++++++++++++++++++++++++++++++++++-- 1 file changed, 307 insertions(+), 12 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 6e20c81fc2..abe1ca9344 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1654,6 +1654,18 @@ describe('API/win', function() api.nvim_open_win(new_buf, false, { split = 'left' }) eq('foobarbaz', eval('triggered')) end) + + it('sets error when no room', function() + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_open_win, 0, true, { split = 'above', win = 0 }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_open_win, 0, true, { split = 'below', win = 0 }) + ) + end) end) describe('set_config', function() @@ -1965,23 +1977,89 @@ describe('API/win', function() it('closing new curwin when moving window to other tabpage works', function() command('split | tabnew') - local w = api.nvim_get_current_win() - local t = api.nvim_get_current_tabpage() - command('tabfirst | autocmd WinEnter * quit') - api.nvim_win_set_config(0, { win = w, split = 'left' }) - -- New tabpage is now the only one, as WinEnter closed the new curwin in the original. - eq(t, api.nvim_get_current_tabpage()) - eq({ t }, api.nvim_list_tabpages()) + local t2_win = api.nvim_get_current_win() + command('tabfirst | autocmd WinEnter * ++once quit') + local t1_move_win = api.nvim_get_current_win() + -- win_set_config fails to switch away from "t1_move_win" because the WinEnter autocmd that + -- closed the window we're switched to returns us to "t1_move_win", as it filled the space. + eq( + 'Failed to switch away from window ' .. t1_move_win, + pcall_err(api.nvim_win_set_config, t1_move_win, { win = t2_win, split = 'left' }) + ) + eq(t1_move_win, api.nvim_get_current_win()) + + command('split | split | autocmd WinEnter * ++once quit') + t1_move_win = api.nvim_get_current_win() + -- In this case, we closed the window that we got switched to, but doing so didn't switch us + -- back to "t1_move_win", which is fine. + api.nvim_win_set_config(t1_move_win, { win = t2_win, split = 'left' }) + neq(t1_move_win, api.nvim_get_current_win()) end) - it('closing split parent when moving window to other tabpage aborts', function() + it('messing with "win" or "parent" when moving "win" to other tabpage', function() command('split | tabnew') - local w = api.nvim_get_current_win() - command('tabfirst | autocmd WinEnter * call nvim_win_close(' .. w .. ', 1)') + 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() + command('split') + local t2_win3 = api.nvim_get_current_win() + + command('tabfirst | autocmd WinEnter * ++once call nvim_win_close(' .. t2_win1 .. ', 1)') + local cur_win = api.nvim_get_current_win() + eq( + 'Windows to split were closed', + pcall_err(api.nvim_win_set_config, 0, { win = t2_win1, split = 'left' }) + ) + eq(cur_win, api.nvim_get_current_win()) + + command('split | autocmd WinLeave * ++once quit!') + cur_win = api.nvim_get_current_win() + eq( + 'Windows to split were closed', + pcall_err(api.nvim_win_set_config, 0, { win = t2_win2, split = 'left' }) + ) + neq(cur_win, api.nvim_get_current_win()) + + exec([[ + split + autocmd WinLeave * ++once + \ call nvim_win_set_config(0, #{relative:'editor', row:0, col:0, width:5, height:5}) + ]]) + cur_win = api.nvim_get_current_win() eq( - 'Window to split was closed', - pcall_err(api.nvim_win_set_config, 0, { win = w, split = 'left' }) + 'Floating state of windows to split changed', + pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' }) ) + eq('editor', api.nvim_win_get_config(0).relative) + eq(cur_win, api.nvim_get_current_win()) + + command('autocmd WinLeave * ++once wincmd J') + cur_win = api.nvim_get_current_win() + eq( + 'Floating state of windows to split changed', + pcall_err(api.nvim_win_set_config, 0, { win = t2_win3, split = 'left' }) + ) + 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. + exec(([[ + autocmd WinLeave * ++once silent! + \ 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') + ) + -- 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)) end) it('expected autocmds when moving window to other tabpage', function() @@ -2031,6 +2109,223 @@ describe('API/win', function() command('autocmd BufHidden * ++once call nvim_win_set_config(' .. w .. ', #{split: "left"})') command('new | quit') end) + + --- Returns a function to get information about the window layout, sizes and positions of a + --- tabpage. + local function define_tp_info_function() + exec_lua([[ + function tp_info(tp) + return { + layout = vim.fn.winlayout(vim.api.nvim_tabpage_get_number(tp)), + pos_sizes = vim.tbl_map( + function(w) + local pos = vim.fn.win_screenpos(w) + return { + row = pos[1], + col = pos[2], + width = vim.fn.winwidth(w), + height = vim.fn.winheight(w) + } + end, + vim.api.nvim_tabpage_list_wins(tp) + ) + } + end + ]]) + + return function(tp) + return exec_lua('return tp_info(...)', tp) + end + end + + it('attempt to move window with no room', function() + -- Fill the 2nd tabpage full of windows until we run out of room. + -- Use &laststatus=0 to ensure restoring missing statuslines doesn't affect things. + command('set laststatus=0 | tabnew') + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + command('vsplit | wincmd | | wincmd p') + local t2 = api.nvim_get_current_tabpage() + local t2_cur_win = api.nvim_get_current_win() + local t2_top_split = fn.win_getid(1) + local t2_bot_split = fn.win_getid(fn.winnr('$')) + local t2_float = api.nvim_open_win( + 0, + false, + { relative = 'editor', row = 0, col = 0, width = 10, height = 10 } + ) + local t2_float_config = api.nvim_win_get_config(t2_float) + local tp_info = define_tp_info_function() + local t2_info = tp_info(t2) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'below' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'below' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t2_float, { win = t2_top_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t2_float, { win = t2_top_split, split = 'below' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t2_float, { win = t2_bot_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t2_float, { win = t2_bot_split, split = 'below' }) + ) + eq(t2_cur_win, api.nvim_get_current_win()) + eq(t2_info, tp_info(t2)) + eq(t2_float_config, api.nvim_win_get_config(t2_float)) + + -- Try to move windows from the 1st tabpage to the 2nd. + command('tabfirst | split | wincmd _') + local t1 = api.nvim_get_current_tabpage() + local t1_cur_win = api.nvim_get_current_win() + local t1_float = api.nvim_open_win( + 0, + false, + { relative = 'editor', row = 5, col = 3, width = 7, height = 6 } + ) + local t1_float_config = api.nvim_win_get_config(t1_float) + local t1_info = tp_info(t1) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_top_split, split = 'below' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, 0, { win = t2_bot_split, split = 'below' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t1_float, { win = t2_top_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t1_float, { win = t2_top_split, split = 'below' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t1_float, { win = t2_bot_split, split = 'above' }) + ) + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t1_float, { win = t2_bot_split, split = 'below' }) + ) + eq(t1_cur_win, api.nvim_get_current_win()) + eq(t1_info, tp_info(t1)) + eq(t1_float_config, api.nvim_win_get_config(t1_float)) + end) + + it('attempt to move window from other tabpage with no room', function() + -- Fill up the 1st tabpage with horizontal splits, then create a 2nd with only a few. Go back + -- to the 1st and try to move windows from the 2nd (while it's non-current) to it. Check that + -- window positions and sizes in the 2nd are unchanged. + command('set laststatus=0') + matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)')) + + command('tab split') + local t2 = api.nvim_get_current_tabpage() + local t2_top = api.nvim_get_current_win() + command('belowright split') + local t2_mid_left = api.nvim_get_current_win() + command('belowright vsplit') + local t2_mid_right = api.nvim_get_current_win() + command('split | wincmd J') + local t2_bot = api.nvim_get_current_win() + local tp_info = define_tp_info_function() + local t2_info = tp_info(t2) + eq({ + 'col', + { + { 'leaf', t2_top }, + { + 'row', + { + { 'leaf', t2_mid_left }, + { 'leaf', t2_mid_right }, + }, + }, + { 'leaf', t2_bot }, + }, + }, t2_info.layout) + + local function try_move_t2_wins_to_t1() + for _, w in ipairs({ t2_bot, t2_mid_left, t2_mid_right, t2_top }) do + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, w, { win = 0, split = 'below' }) + ) + eq(t2_info, tp_info(t2)) + end + end + command('tabfirst') + try_move_t2_wins_to_t1() + -- Go to the 2nd tabpage to ensure nothing changes after win_comp_pos, last_status, .etc. + -- from enter_tabpage. + command('tabnext') + eq(t2_info, tp_info(t2)) + + -- Check things are fine with the global statusline too, for good measure. + -- Set it while the 2nd tabpage is current, so last_status runs for it. + command('set laststatus=3') + t2_info = tp_info(t2) + command('tabfirst') + try_move_t2_wins_to_t1() + end) + + it('does not switch window when textlocked or in the cmdwin', function() + command('tabnew') + local t2_win = api.nvim_get_current_win() + command('tabfirst') + feed('q:') + local cur_win = api.nvim_get_current_win() + eq( + 'Failed to switch away from window ' .. cur_win, + pcall_err(api.nvim_win_set_config, 0, { split = 'left', win = t2_win }) + ) + eq( + 'E11: Invalid in command-line window; executes, CTRL-C quits', + api.nvim_get_vvar('errmsg') + ) + eq(cur_win, api.nvim_get_current_win()) + command('quit!') + + exec(([[ + new + call setline(1, 'foo') + setlocal debug=throw indentexpr=nvim_win_set_config(0,#{split:'left',win:%d}) + ]]):format(t2_win)) + cur_win = api.nvim_get_current_win() + matches( + 'E565: Not allowed to change text or change window$', + pcall_err(command, 'normal! ==') + ) + eq(cur_win, api.nvim_get_current_win()) + end) end) describe('get_config', function() -- cgit From e7c262f5553c1c6e1de95bcbdc8cfe7cc9d5e55e Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:25:44 +0000 Subject: fix(api): patch some cmdwin/textlock holes Problem: there are new ways to escape textlock or break the cmdwin in nvim_win_set_config and nvim_tabpage_set_win. Solution: fix them. Use win_goto to check it in nvim_tabpage_set_win and use the try_start/end pattern like with similar functions such as nvim_set_current_win (which uses the existing msg_list, if set). Careful not to use `wp->handle` when printing the window ID in the error message for nvim_tabpage_set_win, as win_goto autocommands may have freed the window. On a related note, I have a feeling some API functions ought to be checking curbuf_locked... --- test/functional/api/tabpage_spec.lua | 26 +++++++++++++++ test/functional/api/window_spec.lua | 65 ++++++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 6 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index 36955c4ace..f7e6eed047 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -1,5 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear, eq, ok = helpers.clear, helpers.eq, helpers.ok +local exec = helpers.exec +local feed = helpers.feed local api = helpers.api local fn = helpers.fn local request = helpers.request @@ -86,6 +88,30 @@ describe('api/tabpage', function() pcall_err(api.nvim_tabpage_set_win, tab1, win3) ) end) + + it('does not switch window when textlocked or in the cmdwin', function() + local target_win = api.nvim_get_current_win() + feed('q:') + local cur_win = api.nvim_get_current_win() + eq( + 'Vim:E11: Invalid in command-line window; executes, CTRL-C quits', + pcall_err(api.nvim_tabpage_set_win, 0, target_win) + ) + eq(cur_win, api.nvim_get_current_win()) + command('quit!') + + exec(([[ + new + call setline(1, 'foo') + setlocal debug=throw indentexpr=nvim_tabpage_set_win(0,%d) + ]]):format(target_win)) + cur_win = api.nvim_get_current_win() + eq( + 'Vim(normal):E5555: API call: Vim:E565: Not allowed to change text or change window', + pcall_err(command, 'normal! ==') + ) + eq(cur_win, api.nvim_get_current_win()) + end) end) describe('{get,set,del}_var', function() diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index abe1ca9344..ae8a519f11 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -2297,29 +2297,82 @@ describe('API/win', function() try_move_t2_wins_to_t1() end) - it('does not switch window when textlocked or in the cmdwin', function() + it('handles cmdwin and textlock restrictions', function() command('tabnew') + local t2 = api.nvim_get_current_tabpage() local t2_win = api.nvim_get_current_win() command('tabfirst') + local t1_move_win = api.nvim_get_current_win() + command('split') + + -- Can't move the cmdwin, or its old curwin to a different tabpage. + local old_curwin = api.nvim_get_current_win() feed('q:') - local cur_win = api.nvim_get_current_win() eq( - 'Failed to switch away from window ' .. cur_win, + 'E11: Invalid in command-line window; executes, CTRL-C quits', pcall_err(api.nvim_win_set_config, 0, { split = 'left', win = t2_win }) ) eq( 'E11: Invalid in command-line window; executes, CTRL-C quits', - api.nvim_get_vvar('errmsg') + pcall_err(api.nvim_win_set_config, old_curwin, { split = 'left', win = t2_win }) ) - eq(cur_win, api.nvim_get_current_win()) + -- But we can move other windows. + api.nvim_win_set_config(t1_move_win, { split = 'left', win = t2_win }) + eq(t2, api.nvim_win_get_tabpage(t1_move_win)) command('quit!') + -- Can't configure windows such that the cmdwin would become the only non-float. + command('only!') + feed('q:') + eq( + 'E11: Invalid in command-line window; executes, CTRL-C quits', + pcall_err( + api.nvim_win_set_config, + old_curwin, + { relative = 'editor', row = 0, col = 0, width = 5, height = 5 } + ) + ) + -- old_curwin is now no longer the only other non-float, so we can make it floating now. + local t1_new_win = api.nvim_open_win( + api.nvim_create_buf(true, true), + false, + { split = 'left', win = old_curwin } + ) + api.nvim_win_set_config( + old_curwin, + { relative = 'editor', row = 0, col = 0, width = 5, height = 5 } + ) + eq('editor', api.nvim_win_get_config(old_curwin).relative) + -- ...which means we shouldn't be able to also make the new window floating too! + eq( + 'E11: Invalid in command-line window; executes, CTRL-C quits', + pcall_err( + api.nvim_win_set_config, + t1_new_win, + { relative = 'editor', row = 0, col = 0, width = 5, height = 5 } + ) + ) + -- Nothing ought to stop us from making the cmdwin itself floating, though... + api.nvim_win_set_config(0, { relative = 'editor', row = 0, col = 0, width = 5, height = 5 }) + eq('editor', api.nvim_win_get_config(0).relative) + -- We can't make our new window from before floating too, as it's now the only non-float. + eq( + 'Cannot change last window into float', + pcall_err( + api.nvim_win_set_config, + t1_new_win, + { relative = 'editor', row = 0, col = 0, width = 5, height = 5 } + ) + ) + command('quit!') + + -- Can't switch away from window before moving it to a different tabpage during textlock. exec(([[ new call setline(1, 'foo') setlocal debug=throw indentexpr=nvim_win_set_config(0,#{split:'left',win:%d}) ]]):format(t2_win)) - cur_win = api.nvim_get_current_win() + local cur_win = api.nvim_get_current_win() matches( 'E565: Not allowed to change text or change window$', pcall_err(command, 'normal! ==') -- cgit From 54022a2946aca5de991e7fa1ebc2954340ec20a8 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 9 Mar 2024 01:00:33 +0000 Subject: fix(api): win_set_config update statuslines after removing splits Problem: nvim_win_set_config does not update statuslines after removing a split. Solution: call last_status. Didn't realize this was missing in the original nvim_win_set_config for splits PR. As it can only be done for the current tabpage, do it if win_tp == curtab; enter_tabpage will eventually call last_status anyway when the user enters another tabpage. --- test/functional/api/window_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index ae8a519f11..6b7c550ca8 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -2379,6 +2379,28 @@ describe('API/win', function() ) eq(cur_win, api.nvim_get_current_win()) end) + + it('updates statusline when moving bottom split', function() + local screen = Screen.new(10, 10) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText + [1] = { bold = true, reverse = true }, -- StatusLine + }) + screen:attach() + exec([[ + set laststatus=0 + belowright split + call nvim_win_set_config(0, #{split: 'above', win: win_getid(winnr('#'))}) + ]]) + screen:expect([[ + ^ | + {0:~ }|*3 + {1:[No Name] }| + | + {0:~ }|*3 + | + ]]) + end) end) describe('get_config', function() -- cgit From b52d15853e89149472c1ecd9cce3a84e4af0785a Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Sat, 9 Mar 2024 16:56:32 +0000 Subject: fix(api): win_set_config set tp_curwin of win moved from other tabpage Problem: nvim_win_set_config does not update the tp_curwin of win's original tabpage when moving it to another. Solution: update it if win was the tp_curwin. Add a test. --- test/functional/api/window_spec.lua | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 6b7c550ca8..a10c8f48ef 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -2401,6 +2401,47 @@ describe('API/win', function() | ]]) end) + + it("updates tp_curwin of moved window's original tabpage", function() + local t1 = api.nvim_get_current_tabpage() + command('tab split | split') + local t2 = api.nvim_get_current_tabpage() + local t2_alt_win = api.nvim_get_current_win() + command('vsplit') + local t2_cur_win = api.nvim_get_current_win() + command('tabprevious') + eq(t2_cur_win, api.nvim_tabpage_get_win(t2)) + + -- tp_curwin is unchanged when moved within the same tabpage. + api.nvim_win_set_config(t2_cur_win, { split = 'left', win = t2_alt_win }) + eq(t2_cur_win, api.nvim_tabpage_get_win(t2)) + + -- Also unchanged if the move failed. + command('let &winwidth = &columns | let &winminwidth = &columns') + matches( + 'E36: Not enough room$', + pcall_err(api.nvim_win_set_config, t2_cur_win, { split = 'left', win = 0 }) + ) + eq(t2_cur_win, api.nvim_tabpage_get_win(t2)) + command('set winminwidth& winwidth&') + + -- But is changed if successfully moved to a different tabpage. + 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)) + + -- Now do it for a float, which has different altwin logic. + command('tabnext') + t2_cur_win = + api.nvim_open_win(0, true, { relative = 'editor', row = 5, col = 5, width = 5, height = 5 }) + eq(t2_alt_win, fn.win_getid(fn.winnr('#'))) + command('tabprevious') + eq(t2_cur_win, api.nvim_tabpage_get_win(t2)) + + 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)) + end) end) describe('get_config', function() -- cgit From 1da0f3494eb042c84ae5f00654878f7f8cedf3b7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 11 Mar 2024 22:23:14 +0800 Subject: test: correct order of arguments to eq() (#27816) --- test/functional/api/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 9a4a457637..09a45242ec 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -707,13 +707,13 @@ describe('API', function() it('works', function() api.nvim_set_current_dir('Xtestdir') - eq(fn.getcwd(), start_dir .. helpers.get_pathsep() .. 'Xtestdir') + eq(start_dir .. helpers.get_pathsep() .. 'Xtestdir', fn.getcwd()) end) it('sets previous directory', function() api.nvim_set_current_dir('Xtestdir') command('cd -') - eq(fn.getcwd(), start_dir) + eq(start_dir, fn.getcwd()) end) end) -- cgit From 08fc1ebbaa49e3110b65bddeed28d2e61a96f5d9 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 11 Mar 2024 13:19:49 +0100 Subject: fix(api/buffer): fix handling of viewport of non-current buffer A lot of functions in move.c only worked for curwin, alternatively took a `wp` arg but still only work if that happens to be curwin. Refactor those that are needed for update_topline(wp) to work for any window. fixes #27723 fixes #27720 --- test/functional/api/buffer_spec.lua | 67 ++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 78d220ff57..f46cf7a315 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -121,6 +121,66 @@ describe('api/buf', function() eq({ 5, 2 }, api.nvim_win_get_cursor(win2)) end) + it('cursor position is maintained consistently with viewport', function() + local screen = Screen.new(20, 12) + screen:set_default_attr_ids { + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { reverse = true, bold = true }, + [3] = { reverse = true }, + } + screen:attach() + + local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' } + local buf = api.nvim_get_current_buf() + + api.nvim_buf_set_lines(buf, 0, -1, true, lines) + + command('6') + command('new') + screen:expect { + grid = [[ + ^ | + {1:~ }|*4 + {2:[No Name] }| + line5 | + line6 | + {1:~ }|*2 + {3:[No Name] [+] }| + | + ]], + } + + api.nvim_buf_set_lines(buf, 0, -1, true, lines) + screen:expect { + grid = [[ + ^ | + {1:~ }|*4 + {2:[No Name] }| + line3 | + line4 | + line5 | + line6 | + {3:[No Name] [+] }| + | + ]], + } + + command('wincmd w') + screen:expect { + grid = [[ + | + {1:~ }|*4 + {3:[No Name] }| + line3 | + line4 | + line5 | + ^line6 | + {2:[No Name] [+] }| + | + ]], + } + end) + it('line_count has defined behaviour for unloaded buffers', function() -- we'll need to know our bufnr for when it gets unloaded local bufnr = api.nvim_buf_get_number(0) @@ -323,20 +383,20 @@ describe('api/buf', function() ]], } - -- inserting just before topline scrolls up api.nvim_buf_set_lines(buf, 3, 3, true, { 'mmm' }) screen:expect { grid = [[ ^ | {1:~ }|*4 {2:[No Name] }| - mmm | wwweeee | xxx | yyy | + zzz | {3:[No Name] [+] }| | ]], + unchanged = true, } end) @@ -402,7 +462,6 @@ describe('api/buf', function() ]], } - -- inserting just before topline scrolls up api.nvim_buf_set_lines(buf, 3, 3, true, { 'mmm' }) screen:expect { grid = [[ @@ -412,10 +471,10 @@ describe('api/buf', function() mmm | wwweeee | {2:[No Name] [+] }| - mmm | wwweeee | xxx | yyy | + zzz | {3:[No Name] [+] }| | ]], -- cgit From fc2a56fe61a95b4124045039b39e20419920d2e2 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 14 Mar 2024 10:55:40 +0100 Subject: fix(api): fix set_lines viewport adjustment, but this time good fixes #27720 --- test/functional/api/buffer_spec.lua | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index f46cf7a315..a560546d2d 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -150,16 +150,16 @@ describe('api/buf', function() ]], } + lines[5] = 'boogalo 5' api.nvim_buf_set_lines(buf, 0, -1, true, lines) screen:expect { grid = [[ ^ | {1:~ }|*4 {2:[No Name] }| - line3 | - line4 | - line5 | + boogalo 5 | line6 | + {1:~ }|*2 {3:[No Name] [+] }| | ]], @@ -171,10 +171,9 @@ describe('api/buf', function() | {1:~ }|*4 {3:[No Name] }| - line3 | - line4 | - line5 | + boogalo 5 | ^line6 | + {1:~ }|*2 {2:[No Name] [+] }| | ]], -- cgit From c971f538ab87b537ae4c97bd44167661c5691a2d Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 14 Mar 2024 23:55:32 +0100 Subject: fix(api): update grid cursor in nvim_win_set_cursor() Problem: Cursor position set by nvim_win_set_cursor() is not reflected on the screen when followed by a blocking call like getchar(). Solution: Immediately update the cursor position on the grid. --- test/functional/api/window_spec.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index a10c8f48ef..721148faaa 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -219,6 +219,21 @@ describe('API/win', function() -- curwin didn't change back neq(win, curwin()) + + -- shows updated position after getchar() #20793 + feed(':call getchar()') + api.nvim_win_set_cursor(win, { 1, 5 }) + screen:expect { + grid = [[ + | + {1:~ }|*2 + {2:[No Name] }| + prolo^gue | + |*2 + {3:[No Name] [+] }| + :call getchar() | + ]], + } end) it('remembers what column it wants to be in', function() -- cgit From d5c23d72a5e4d2abb0903e58c4953fa0303d4ad6 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:55:33 +0000 Subject: fix(api): nvim_create_buf leaks memory if buffer is loaded early Problem: memory leak in nvim_create_buf if buflist_new autocommands load the new buffer early. Solution: do not open a memfile in that case. --- test/functional/api/vim_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 09a45242ec..a3f70efcea 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3135,6 +3135,15 @@ describe('API', function() -- nowadays this works because we don't execute any spurious autocmds at all #24824 assert_alive() end) + + it('no memory leak when autocommands load the buffer immediately', function() + exec([[ + autocmd BufNew * ++once call bufload(expand("")->str2nr()) + \| let loaded = bufloaded(expand("")->str2nr()) + ]]) + api.nvim_create_buf(false, true) + eq(1, eval('g:loaded')) + end) end) describe('nvim_get_runtime_file', function() -- cgit From 6091df6b7a0674a7215c5c1d2d93a1b37e9121b5 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:59:44 +0000 Subject: fix(api): nvim_create_buf assert fails if autocmds set &swapfile Problem: assertion failure in nvim_create_buf if buflist_new autocommands open a swapfile when "scratch" is set. Solution: block autocommands when setting up the buffer; fire them later instead. Note that, unlike buflist_new, I don't check if autocommands aborted script processing; the buffer is already created and configured at that point, so might as well return the handle anyway. Rather than repeat try_{start,end} and {un}block_autocmds for each relevant operation, just do it at the start and near the end. This means that, if TermResponse fires from unblock_autocmds for whatever reason, it can see the buffer in an already configured state if we didn't bail due to an error (plus it's probably a bit cleaner this way). --- test/functional/api/vim_spec.lua | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a3f70efcea..ef602b3a51 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3144,6 +3144,47 @@ describe('API', function() api.nvim_create_buf(false, true) eq(1, eval('g:loaded')) end) + + it('creating scratch buffer where autocommands set &swapfile works', function() + exec([[ + autocmd BufNew * ++once execute expand("") "buffer" + \| file foobar + \| setlocal swapfile + ]]) + local new_buf = api.nvim_create_buf(false, true) + neq('', fn.swapname(new_buf)) + end) + + it('fires expected autocommands', function() + exec([=[ + " Append the &buftype to check autocommands trigger *after* the buffer was configured to be + " scratch, if applicable. + autocmd BufNew * let fired += [["BufNew", expand("")->str2nr(), + \ getbufvar(expand("")->str2nr(), "&buftype")]] + autocmd BufAdd * let fired += [["BufAdd", expand("")->str2nr(), + \ getbufvar(expand("")->str2nr(), "&buftype")]] + + " Don't want to see OptionSet; buffer options set from passing true for "scratch", etc. + " should be configured invisibly, and before autocommands. + autocmd OptionSet * let fired += [["OptionSet", expand("")]] + + let fired = [] + ]=]) + local new_buf = api.nvim_create_buf(false, false) + eq({ { 'BufNew', new_buf, '' } }, eval('g:fired')) + + command('let fired = []') + new_buf = api.nvim_create_buf(false, true) + eq({ { 'BufNew', new_buf, 'nofile' } }, eval('g:fired')) + + command('let fired = []') + new_buf = api.nvim_create_buf(true, false) + eq({ { 'BufNew', new_buf, '' }, { 'BufAdd', new_buf, '' } }, eval('g:fired')) + + command('let fired = []') + new_buf = api.nvim_create_buf(true, true) + eq({ { 'BufNew', new_buf, 'nofile' }, { 'BufAdd', new_buf, 'nofile' } }, eval('g:fired')) + end) end) describe('nvim_get_runtime_file', function() -- cgit From 8921d56053bb3702226c03f13232b45d5f2c27a4 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 21 Mar 2024 10:08:31 +0100 Subject: fix(rpc): do not crash when no input is consumed fixes #23781 Co-authored-by: glacambre --- test/functional/api/server_requests_spec.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 298dbac217..562eeae951 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -363,6 +363,24 @@ describe('server -> client', function() server:close() client:close() end) + + it('via stdio, with many small flushes does not crash #23781', function() + source([[ + let chan = jobstart([v:progpath, '--embed', '--headless', '-n', '-u', 'NONE', '-i', 'NONE'], { 'rpc':v:false }) + call chansend(chan, 0Z94) + sleep 50m + call chansend(chan, 0Z00) + call chansend(chan, 0Z01) + call chansend(chan, 0ZAC) + call chansend(chan, 0Z6E76696D5F636F6D6D616E64) + call chansend(chan, 0Z91) + call chansend(chan, 0ZA5) + call chansend(chan, 0Z71616C6C21) + let g:statuses = jobwait([chan]) + ]]) + eq(eval('g:statuses'), { 0 }) + assert_alive() + end) end) describe('connecting to its own pipe address', function() -- cgit From 0c59771e314d6faaad69676985cd2a11c157ee37 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 22 Mar 2024 11:02:52 +0100 Subject: refactor(tests): all screen tests should use highlights This is the first installment of a multi-PR series significantly refactoring how highlights are being specified. The end goal is to have a base set of 20 ish most common highlights, and then specific files only need to add more groups to that as needed. As a complicating factor, we also want to migrate to the new default color scheme eventually. But by sharing a base set, that future PR will hopefully be a lot smaller since a lot of tests will be migrated just simply by updating the base set in place. As a first step, fix the anti-pattern than Screen defaults to ignoring highlights. Highlights are integral part of the screen state, not something "extra" which we only test "sometimes". For now, we still allow opt-out via the intentionally ugly screen._default_attr_ids = nil The end goal is to get rid of all of these eventually (which will be easier as part of the color scheme migration) --- test/functional/api/buffer_spec.lua | 11 +++++------ test/functional/api/extmark_spec.lua | 31 ++++++++++++++++--------------- test/functional/api/vim_spec.lua | 12 ++++++------ 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index a560546d2d..ea942172ab 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1744,12 +1744,11 @@ describe('api/buf', function() api.nvim_buf_set_text(0, 0, 0, 1, 3, { 'XXX', 'YYY' }) screen:expect([[ - XXX | - YYY | - ^ | - ~ | - | - + XXX | + YYY | + ^ | + {1:~ }| + | ]]) end) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 2acfbfc949..4cf96a4af6 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -460,7 +460,7 @@ describe('API/extmarks', function() -- This shouldn't seg fault screen:expect([[ 12345^ 1 | - ~ |*8 + {1:~ }|*8 | ]]) end) @@ -513,7 +513,7 @@ describe('API/extmarks', function() insert('abc') screen:expect([[ ab^c12345 | - ~ |*8 + {1:~ }|*8 | ]]) local rv = get_extmark_by_id(ns, marks[1]) @@ -1734,16 +1734,17 @@ describe('API/extmarks', function() command('d2') screen:expect([[ S2^aaa bbb ccc | - aaa bbb ccc |*3 - |*2 + {7: }aaa bbb ccc |*3 + {7: } | + | ]]) -- mark is restored with undo_restore == true command('silent undo') screen:expect([[ - S1 ^aaa bbb ccc | + S1{7: }^aaa bbb ccc | S1S2aaa bbb ccc | - S2 aaa bbb ccc | - aaa bbb ccc |*2 + S2{7: }aaa bbb ccc | + {7: }aaa bbb ccc |*2 | ]]) -- decor is not removed twice @@ -1964,7 +1965,7 @@ describe('API/win_extmark', function() grid = [[ non ui-watched line | ui-watched lin^e | - ~ | + {1:~ }| | ]], extmarks = { @@ -2052,7 +2053,7 @@ describe('API/win_extmark', function() grid = [[ ui-watched linupdat^e| e | - ~ | + {1:~ }| | ]], extmarks = { @@ -2079,9 +2080,9 @@ describe('API/win_extmark', function() grid = [[ ## grid 1 [4:--------------------]|*3 - [No Name] [+] | + {3:[No Name] [+] }| [2:--------------------]|*2 - [No Name] [+] | + {2:[No Name] [+] }| [3:--------------------]| ## grid 2 non ui-watched line | @@ -2091,7 +2092,7 @@ describe('API/win_extmark', function() ## grid 4 non ui-watched line | ui-watched lin^e | - ~ | + {1:~ }| ]], extmarks = { [2] = { @@ -2112,13 +2113,13 @@ describe('API/win_extmark', function() grid = [[ ## grid 1 [4:--------------------]|*3 - [No Name] [+] | + {3:[No Name] [+] }| [2:--------------------]|*2 - [No Name] [+] | + {2:[No Name] [+] }| [3:--------------------]| ## grid 2 non ui-watched line | - ui-watched linupd@@@| + ui-watched linupd{1:@@@}| ## grid 3 | ## grid 4 diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index ef602b3a51..d98308ee87 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1269,7 +1269,7 @@ describe('API', function() api.nvim_paste('', true, 3) screen:expect([[ | - ~ |*2 + {1:~ }|*2 :Foo^ | ]]) end) @@ -1280,8 +1280,8 @@ describe('API', function() api.nvim_paste('normal! \023\022\006\027', true, -1) screen:expect([[ | - ~ |*2 - :normal! ^W^V^F^[^ | + {1:~ }|*2 + :normal! {18:^W^V^F^[}^ | ]]) end) it('crlf=false does not break lines at CR, CRLF', function() @@ -1981,9 +1981,9 @@ describe('API', function() -- Make any RPC request (can be non-async: op-pending does not block). api.nvim_get_current_buf() screen:expect([[ - ^a$ | - b$ | - c$ | + ^a{1:$} | + b{1:$} | + c{1:$} | | ]]) end) -- cgit From 35239e977f53c25016b57729cada612aa53e11d4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 30 Mar 2024 09:29:21 +0800 Subject: test: use matches(...) instead of ok(string.find(...)) (#28111) --- test/functional/api/vim_spec.lua | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d98308ee87..d72ccf99b3 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1593,9 +1593,7 @@ describe('API', function() api.nvim_set_option_value('equalalways', false, {}) local status, rv = pcall(command_output, 'verbose set equalalways?') eq(true, status) - ok( - nil ~= string.find(rv, 'noequalalways\n' .. '\tLast set from API client %(channel id %d+%)') - ) + matches('noequalalways\n' .. '\tLast set from API client %(channel id %d+%)', rv) api.nvim_exec_lua('vim.api.nvim_set_option_value("equalalways", true, {})', {}) status, rv = pcall(command_output, 'verbose set equalalways?') @@ -2723,7 +2721,7 @@ describe('API', function() it('can throw exceptions', function() local status, err = pcall(api.nvim_get_option_value, 'invalid-option', {}) eq(false, status) - ok(err:match("Unknown option 'invalid%-option'") ~= nil) + matches("Unknown option 'invalid%-option'", err) end) it('does not truncate error message <1 MB #5984', function() @@ -2736,10 +2734,7 @@ describe('API', function() it('does not leak memory on incorrect argument types', function() local status, err = pcall(api.nvim_set_current_dir, { 'not', 'a', 'dir' }) eq(false, status) - ok( - err:match(': Wrong type for argument 1 when calling nvim_set_current_dir, expecting String') - ~= nil - ) + matches(': Wrong type for argument 1 when calling nvim_set_current_dir, expecting String', err) end) describe('nvim_parse_expression', function() @@ -3670,7 +3665,7 @@ describe('API', function() api.nvim_buf_set_name(buf, 'mybuf') local mark = api.nvim_get_mark('F', {}) -- Compare the path tail only - assert(string.find(mark[4], 'mybuf$')) + matches('mybuf$', mark[4]) eq({ 2, 2, buf, mark[4] }, mark) end) it('validation', function() -- cgit From 77d3526a3d088b16e4f07e84c79cbd4a3411d0fe Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 30 Mar 2024 00:57:22 +0100 Subject: fix: explain that user should run nvim with -V1 to see more information It's not obvious for users how to figure out where a mapping is set from only "Last set from Lua". --- test/functional/api/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d72ccf99b3..dc36926641 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1598,7 +1598,7 @@ describe('API', function() api.nvim_exec_lua('vim.api.nvim_set_option_value("equalalways", true, {})', {}) status, rv = pcall(command_output, 'verbose set equalalways?') eq(true, status) - eq(' equalalways\n\tLast set from Lua', rv) + eq(' equalalways\n\tLast set from Lua (run Nvim with -V1 for more details)', rv) end) it('updates whether the option has ever been set #25025', function() -- cgit From e016f5bee6293d126fde9e8d75a3f02f882e2c81 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 2 Apr 2024 15:45:19 +0200 Subject: test: reduce `exec_lua` calls `exec_lua` makes code slighly harder to read, so it's beneficial to remove it in cases where it's possible or convenient. Not all `exec_lua` calls should be removed even if the test passes as it changes the semantics of the test even if it happens to pass. From https://github.com/neovim/neovim/pull/28155#discussion_r1548185779: "Note for tests like this, which fundamentally are about conversion, you end up changing what conversion you are testing. Even if the result happens to be same (as they often are, as we like the rules to be consistent if possible), you are now testing the RPC conversion rules instead of the vim script to in-process lua conversion rules." From https://github.com/neovim/neovim/pull/28155#discussion_r1548190152: "A test like this specifies that the cursor is valid immediately and not after a separate cycle of normal (or an other input-processing) mode." --- test/functional/api/buffer_spec.lua | 51 +++++++------------------------------ 1 file changed, 9 insertions(+), 42 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index ea942172ab..25b0405571 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1374,12 +1374,7 @@ describe('api/buf', function() -- immediate call to nvim_win_get_cursor should have returned the same position eq({ 2, 12 }, cursor) -- coladd should be 0 - eq( - 0, - exec_lua([[ - return vim.fn.winsaveview().coladd - ]]) - ) + eq(0, fn.winsaveview().coladd) end) it('does not change cursor screen column when cursor >EOL and row got shorter', function() @@ -1393,9 +1388,7 @@ describe('api/buf', function() -- turn on virtualedit command('set virtualedit=all') -- move cursor after eol - exec_lua([[ - vim.fn.winrestview({ coladd = 5 }) - ]]) + fn.winrestview({ coladd = 5 }) local cursor = exec_lua([[ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, { @@ -1414,12 +1407,7 @@ describe('api/buf', function() -- immediate call to nvim_win_get_cursor should have returned the same position eq({ 2, 26 }, cursor) -- coladd should be increased so that cursor stays in the same screen column - eq( - 13, - exec_lua([[ - return vim.fn.winsaveview().coladd - ]]) - ) + eq(13, fn.winsaveview().coladd) end) it( @@ -1435,9 +1423,7 @@ describe('api/buf', function() -- turn on virtualedit command('set virtualedit=all') -- move cursor after eol - exec_lua([[ - vim.fn.winrestview({ coladd = 21 }) - ]]) + fn.winrestview({ coladd = 21 }) local cursor = exec_lua([[ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, { @@ -1456,12 +1442,7 @@ describe('api/buf', function() -- immediate call to nvim_win_get_cursor should have returned the same position eq({ 1, 38 }, cursor) -- coladd should be increased so that cursor stays in the same screen column - eq( - 2, - exec_lua([[ - return vim.fn.winsaveview().coladd - ]]) - ) + eq(2, fn.winsaveview().coladd) end ) @@ -1478,9 +1459,7 @@ describe('api/buf', function() -- turn on virtualedit command('set virtualedit=all') -- move cursor after eol just a bit - exec_lua([[ - vim.fn.winrestview({ coladd = 3 }) - ]]) + fn.winrestview({ coladd = 3 }) local cursor = exec_lua([[ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, { @@ -1499,12 +1478,7 @@ describe('api/buf', function() -- immediate call to nvim_win_get_cursor should have returned the same position eq({ 1, 22 }, cursor) -- coladd should become 0 - eq( - 0, - exec_lua([[ - return vim.fn.winsaveview().coladd - ]]) - ) + eq(0, fn.winsaveview().coladd) end ) @@ -1522,9 +1496,7 @@ describe('api/buf', function() -- turn on virtualedit command('set virtualedit=all') -- move cursor after eol - exec_lua([[ - vim.fn.winrestview({ coladd = 28 }) - ]]) + fn.winrestview({ coladd = 28 }) local cursor = exec_lua([[ vim.api.nvim_buf_set_text(0, 0, 15, 3, 11, { @@ -1543,12 +1515,7 @@ describe('api/buf', function() -- immediate call to nvim_win_get_cursor should have returned the same position eq({ 2, 26 }, cursor) -- coladd should be increased so that cursor stays in the same screen column - eq( - 13, - exec_lua([[ - return vim.fn.winsaveview().coladd - ]]) - ) + eq(13, fn.winsaveview().coladd) end ) end) -- cgit From 5581a90e20777a2493ca9835b11a67435287d64e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 6 Apr 2024 08:59:50 +0800 Subject: test: reduce sleep for file timestamp change (#28196) Now that Nvim always supports nanotime, sleeping for some milliseconds is enough. --- test/functional/api/keymap_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 0decd710e9..4380e76486 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -738,7 +738,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() end end - it('can set mappings containing literal keycodes', function() + it('can set mappings containing C0 control codes', function() api.nvim_set_keymap('n', '\n\r\n', 'rhs', {}) local expected = generate_mapargs('n', '', 'rhs') eq(expected, get_mapargs('n', '')) -- cgit From ae28ef327e02ac87ef26f941c401312ed0462d8c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 6 Apr 2024 11:18:43 +0800 Subject: fix: adjust error message for error in UI event callback (#28200) Also close Nvim instance before removing log file, otherwise the Nvim instance will still write to the log file. Also adjust log level in libuv_process_spawn(). Ref #27660 --- test/functional/api/server_notifications_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index d1608a951c..9b411c0c3f 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -6,6 +6,7 @@ local api = helpers.api local exec_lua = helpers.exec_lua local retry = helpers.retry local assert_alive = helpers.assert_alive +local check_close = helpers.check_close local testlog = 'Xtest-server-notify-log' @@ -18,6 +19,7 @@ describe('notify', function() end) after_each(function() + check_close() os.remove(testlog) end) -- cgit From 7035125b2b26aa68fcfb7cda39377ac79926a0f9 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 8 Apr 2024 11:03:20 +0200 Subject: test: improve test conventions Work on https://github.com/neovim/neovim/issues/27004. --- test/functional/api/autocmd_spec.lua | 22 ++-- test/functional/api/buffer_spec.lua | 32 +++--- test/functional/api/buffer_updates_spec.lua | 30 +++--- test/functional/api/command_spec.lua | 24 ++--- test/functional/api/extmark_spec.lua | 26 ++--- test/functional/api/highlight_spec.lua | 20 ++-- test/functional/api/keymap_spec.lua | 40 +++---- test/functional/api/menu_spec.lua | 8 +- test/functional/api/proc_spec.lua | 18 ++-- test/functional/api/server_notifications_spec.lua | 17 ++- test/functional/api/server_requests_spec.lua | 28 ++--- test/functional/api/tabpage_spec.lua | 18 ++-- test/functional/api/ui_spec.lua | 20 ++-- test/functional/api/version_spec.lua | 6 +- test/functional/api/vim_spec.lua | 121 +++++++++++----------- test/functional/api/window_spec.lua | 44 ++++---- 16 files changed, 235 insertions(+), 239 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index e89abf6c64..b97647850c 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -1,14 +1,14 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local command = helpers.command -local eq = helpers.eq -local neq = helpers.neq -local exec_lua = helpers.exec_lua -local matches = helpers.matches -local api = helpers.api -local source = helpers.source -local pcall_err = helpers.pcall_err +local t = require('test.functional.testutil')(after_each) + +local clear = t.clear +local command = t.command +local eq = t.eq +local neq = t.neq +local exec_lua = t.exec_lua +local matches = t.matches +local api = t.api +local source = t.source +local pcall_err = t.pcall_err before_each(clear) diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 25b0405571..de56c16bd8 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1,21 +1,21 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local Screen = require('test.functional.ui.screen') -local clear = helpers.clear -local eq = helpers.eq -local ok = helpers.ok -local describe_lua_and_rpc = helpers.describe_lua_and_rpc(describe) -local api = helpers.api -local fn = helpers.fn -local request = helpers.request -local exc_exec = helpers.exc_exec -local exec_lua = helpers.exec_lua -local feed_command = helpers.feed_command -local insert = helpers.insert +local clear = t.clear +local eq = t.eq +local ok = t.ok +local describe_lua_and_rpc = t.describe_lua_and_rpc(describe) +local api = t.api +local fn = t.fn +local request = t.request +local exc_exec = t.exc_exec +local exec_lua = t.exec_lua +local feed_command = t.feed_command +local insert = t.insert local NIL = vim.NIL -local command = helpers.command -local feed = helpers.feed -local pcall_err = helpers.pcall_err -local assert_alive = helpers.assert_alive +local command = t.command +local feed = t.feed +local pcall_err = t.pcall_err +local assert_alive = t.assert_alive describe('api/buf', function() before_each(clear) diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index 262ca40e28..715c469c76 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -1,13 +1,13 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local eq, ok = helpers.eq, helpers.ok -local fn = helpers.fn -local api = helpers.api -local command, eval, next_msg = helpers.command, helpers.eval, helpers.next_msg -local nvim_prog = helpers.nvim_prog -local pcall_err = helpers.pcall_err +local t = require('test.functional.testutil')(after_each) +local clear = t.clear +local eq, ok = t.eq, t.ok +local fn = t.fn +local api = t.api +local command, eval, next_msg = t.command, t.eval, t.next_msg +local nvim_prog = t.nvim_prog +local pcall_err = t.pcall_err local sleep = vim.uv.sleep -local write_file = helpers.write_file +local write_file = t.write_file local origlines = { 'original line 1', @@ -34,7 +34,7 @@ local function sendkeys(keys) end local function open(activate, lines) - local filename = helpers.tmpname() + local filename = t.tmpname() write_file(filename, table.concat(lines, '\n') .. '\n', true) command('edit ' .. filename) local b = api.nvim_get_current_buf() @@ -511,11 +511,11 @@ describe('API: buffer events:', function() -- create several new sessions, in addition to our main API local sessions = {} - local pipe = helpers.new_pipename() + local pipe = t.new_pipename() eval("serverstart('" .. pipe .. "')") - sessions[1] = helpers.connect(pipe) - sessions[2] = helpers.connect(pipe) - sessions[3] = helpers.connect(pipe) + sessions[1] = t.connect(pipe) + sessions[2] = t.connect(pipe) + sessions[3] = t.connect(pipe) local function request(sessionnr, method, ...) local status, rv = sessions[sessionnr]:request(method, ...) @@ -814,7 +814,7 @@ describe('API: buffer events:', function() clear() sleep(250) -- response - eq(true, helpers.request('nvim_buf_attach', 0, false, {})) + eq(true, t.request('nvim_buf_attach', 0, false, {})) -- notification eq({ [1] = 'notification', diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index f73b9c8b13..29d96a1ff5 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -1,17 +1,17 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local NIL = vim.NIL -local clear = helpers.clear -local command = helpers.command -local eq = helpers.eq -local api = helpers.api -local matches = helpers.matches -local source = helpers.source -local pcall_err = helpers.pcall_err -local exec_lua = helpers.exec_lua -local assert_alive = helpers.assert_alive -local feed = helpers.feed -local fn = helpers.fn +local clear = t.clear +local command = t.command +local eq = t.eq +local api = t.api +local matches = t.matches +local source = t.source +local pcall_err = t.pcall_err +local exec_lua = t.exec_lua +local assert_alive = t.assert_alive +local feed = t.feed +local fn = t.fn describe('nvim_get_commands', function() local cmd_dict = { diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 4cf96a4af6..1a96510d3d 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1,20 +1,20 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local Screen = require('test.functional.ui.screen') -local request = helpers.request -local eq = helpers.eq -local ok = helpers.ok -local pcall_err = helpers.pcall_err -local insert = helpers.insert -local feed = helpers.feed -local clear = helpers.clear -local command = helpers.command -local exec = helpers.exec -local api = helpers.api -local assert_alive = helpers.assert_alive +local request = t.request +local eq = t.eq +local ok = t.ok +local pcall_err = t.pcall_err +local insert = t.insert +local feed = t.feed +local clear = t.clear +local command = t.command +local exec = t.exec +local api = t.api +local assert_alive = t.assert_alive local function expect(contents) - return eq(contents, helpers.curbuf_contents()) + return eq(contents, t.curbuf_contents()) end local function set_extmark(ns_id, id, line, col, opts) diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 1973d3e1c7..4156af5901 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -1,14 +1,14 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear +local t = require('test.functional.testutil')(after_each) +local clear = t.clear local Screen = require('test.functional.ui.screen') -local eq, eval = helpers.eq, helpers.eval -local command = helpers.command -local exec_capture = helpers.exec_capture -local api = helpers.api -local fn = helpers.fn -local pcall_err = helpers.pcall_err -local ok = helpers.ok -local assert_alive = helpers.assert_alive +local eq, eval = t.eq, t.eval +local command = t.command +local exec_capture = t.exec_capture +local api = t.api +local fn = t.fn +local pcall_err = t.pcall_err +local ok = t.ok +local assert_alive = t.assert_alive describe('API: highlight', function() clear() diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 4380e76486..d6a8b592d7 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -1,17 +1,17 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local command = helpers.command -local eq, neq = helpers.eq, helpers.neq -local exec_lua = helpers.exec_lua -local exec = helpers.exec -local feed = helpers.feed -local fn = helpers.fn -local api = helpers.api -local source = helpers.source -local pcall_err = helpers.pcall_err - -local shallowcopy = helpers.shallowcopy +local t = require('test.functional.testutil')(after_each) + +local clear = t.clear +local command = t.command +local eq, neq = t.eq, t.neq +local exec_lua = t.exec_lua +local exec = t.exec +local feed = t.feed +local fn = t.fn +local api = t.api +local source = t.source +local pcall_err = t.pcall_err + +local shallowcopy = t.shallowcopy local sleep = vim.uv.sleep local sid_api_client = -9 @@ -1114,7 +1114,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() feed('asdf\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) + eq('\nNo mapping found', t.exec_capture('nmap asdf')) end) it('no double-free when unmapping simplifiable lua mappings', function() @@ -1138,13 +1138,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() feed('\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', helpers.exec_capture('nmap ')) + eq('\nNo mapping found', t.exec_capture('nmap ')) end) it('can set descriptions on mappings', function() api.nvim_set_keymap('n', 'lhs', 'rhs', { desc = 'map description' }) eq(generate_mapargs('n', 'lhs', 'rhs', { desc = 'map description' }), get_mapargs('n', 'lhs')) - eq('\nn lhs rhs\n map description', helpers.exec_capture('nmap lhs')) + eq('\nn lhs rhs\n map description', t.exec_capture('nmap lhs')) end) it('can define !-mode abbreviations with lua callbacks', function() @@ -1290,7 +1290,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('does not crash when setting mapping in a non-existing buffer #13541', function() pcall_err(api.nvim_buf_set_keymap, 100, '', 'lsh', 'irhs', {}) - helpers.assert_alive() + t.assert_alive() end) it('can make lua mappings', function() @@ -1372,7 +1372,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() feed('asdf\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) + eq('\nNo mapping found', t.exec_capture('nmap asdf')) end) it('no double-free when unmapping simplifiable lua mappings', function() @@ -1396,6 +1396,6 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() feed('\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', helpers.exec_capture('nmap ')) + eq('\nNo mapping found', t.exec_capture('nmap ')) end) end) diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 44b9039393..97d0f43d64 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -1,9 +1,9 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local Screen = require('test.functional.ui.screen') -local clear = helpers.clear -local command = helpers.command -local feed = helpers.feed +local clear = t.clear +local command = t.command +local feed = t.feed describe('update_menu notification', function() local screen diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 50c441792c..85e55d0cfb 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -1,14 +1,14 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) -local clear = helpers.clear -local eq = helpers.eq -local fn = helpers.fn -local neq = helpers.neq -local nvim_argv = helpers.nvim_argv -local request = helpers.request -local retry = helpers.retry +local clear = t.clear +local eq = t.eq +local fn = t.fn +local neq = t.neq +local nvim_argv = t.nvim_argv +local request = t.request +local retry = t.retry local NIL = vim.NIL -local is_os = helpers.is_os +local is_os = t.is_os describe('API', function() before_each(clear) diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index 9b411c0c3f..ee2e401dd5 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,12 +1,11 @@ -local helpers = require('test.functional.helpers')(after_each) -local assert_log = helpers.assert_log -local eq, clear, eval, command, next_msg = - helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.next_msg -local api = helpers.api -local exec_lua = helpers.exec_lua -local retry = helpers.retry -local assert_alive = helpers.assert_alive -local check_close = helpers.check_close +local t = require('test.functional.testutil')(after_each) +local assert_log = t.assert_log +local eq, clear, eval, command, next_msg = t.eq, t.clear, t.eval, t.command, t.next_msg +local api = t.api +local exec_lua = t.exec_lua +local retry = t.retry +local assert_alive = t.assert_alive +local check_close = t.check_close local testlog = 'Xtest-server-notify-log' diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 562eeae951..3a925dcbe2 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -1,17 +1,17 @@ -- Test server -> client RPC scenarios. Note: unlike `rpcnotify`, to evaluate -- `rpcrequest` calls we need the client event loop to be running. -local helpers = require('test.functional.helpers')(after_each) - -local clear, eval = helpers.clear, helpers.eval -local eq, neq, run, stop = helpers.eq, helpers.neq, helpers.run, helpers.stop -local nvim_prog, command, fn = helpers.nvim_prog, helpers.command, helpers.fn -local source, next_msg = helpers.source, helpers.next_msg -local ok = helpers.ok -local api = helpers.api -local spawn, merge_args = helpers.spawn, helpers.merge_args -local set_session = helpers.set_session -local pcall_err = helpers.pcall_err -local assert_alive = helpers.assert_alive +local t = require('test.functional.testutil')(after_each) + +local clear, eval = t.clear, t.eval +local eq, neq, run, stop = t.eq, t.neq, t.run, t.stop +local nvim_prog, command, fn = t.nvim_prog, t.command, t.fn +local source, next_msg = t.source, t.next_msg +local ok = t.ok +local api = t.api +local spawn, merge_args = t.spawn, t.merge_args +local set_session = t.set_session +local pcall_err = t.pcall_err +local assert_alive = t.assert_alive describe('server -> client', function() local cid @@ -259,7 +259,7 @@ describe('server -> client', function() pcall(fn.jobstop, jobid) end) - if helpers.skip(helpers.is_os('win')) then + if t.skip(t.is_os('win')) then return end @@ -280,7 +280,7 @@ describe('server -> client', function() end) describe('connecting to another (peer) nvim', function() - local nvim_argv = merge_args(helpers.nvim_argv, { '--headless' }) + local nvim_argv = merge_args(t.nvim_argv, { '--headless' }) local function connect_test(server, mode, address) local serverpid = fn.getpid() local client = spawn(nvim_argv, false, nil, true) diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index f7e6eed047..6ed5daca0f 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -1,13 +1,13 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear, eq, ok = helpers.clear, helpers.eq, helpers.ok -local exec = helpers.exec -local feed = helpers.feed -local api = helpers.api -local fn = helpers.fn -local request = helpers.request +local t = require('test.functional.testutil')(after_each) +local clear, eq, ok = t.clear, t.eq, t.ok +local exec = t.exec +local feed = t.feed +local api = t.api +local fn = t.fn +local request = t.request local NIL = vim.NIL -local pcall_err = helpers.pcall_err -local command = helpers.command +local pcall_err = t.pcall_err +local command = t.command describe('api/tabpage', function() before_each(clear) diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 3e1f1ec965..89eeeaa189 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -1,14 +1,14 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local Screen = require('test.functional.ui.screen') -local clear = helpers.clear -local command = helpers.command -local eq = helpers.eq -local eval = helpers.eval -local exec = helpers.exec -local feed = helpers.feed -local api = helpers.api -local request = helpers.request -local pcall_err = helpers.pcall_err +local clear = t.clear +local command = t.command +local eq = t.eq +local eval = t.eval +local exec = t.exec +local feed = t.feed +local api = t.api +local request = t.request +local pcall_err = t.pcall_err describe('nvim_ui_attach()', function() before_each(function() diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua index c304f1aa88..7ab27be298 100644 --- a/test/functional/api/version_spec.lua +++ b/test/functional/api/version_spec.lua @@ -1,6 +1,6 @@ -local helpers = require('test.functional.helpers')(after_each) -local clear, fn, eq = helpers.clear, helpers.fn, helpers.eq -local api = helpers.api +local t = require('test.functional.testutil')(after_each) +local clear, fn, eq = t.clear, t.fn, t.eq +local api = t.api local function read_mpack_file(fname) local fd = io.open(fname, 'rb') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index dc36926641..82d5480997 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,42 +1,42 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local Screen = require('test.functional.ui.screen') local uv = vim.uv local fmt = string.format -local dedent = helpers.dedent -local assert_alive = helpers.assert_alive +local dedent = t.dedent +local assert_alive = t.assert_alive local NIL = vim.NIL -local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq -local command = helpers.command -local command_output = helpers.api.nvim_command_output -local exec = helpers.exec -local exec_capture = helpers.exec_capture -local eval = helpers.eval -local expect = helpers.expect -local fn = helpers.fn -local api = helpers.api -local matches = helpers.matches +local clear, eq, neq = t.clear, t.eq, t.neq +local command = t.command +local command_output = t.api.nvim_command_output +local exec = t.exec +local exec_capture = t.exec_capture +local eval = t.eval +local expect = t.expect +local fn = t.fn +local api = t.api +local matches = t.matches local pesc = vim.pesc -local mkdir_p = helpers.mkdir_p -local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed -local async_meths = helpers.async_meths -local is_os = helpers.is_os -local parse_context = helpers.parse_context -local request = helpers.request -local rmdir = helpers.rmdir -local source = helpers.source -local next_msg = helpers.next_msg -local tmpname = helpers.tmpname -local write_file = helpers.write_file -local exec_lua = helpers.exec_lua -local exc_exec = helpers.exc_exec -local insert = helpers.insert -local skip = helpers.skip - -local pcall_err = helpers.pcall_err +local mkdir_p = t.mkdir_p +local ok, nvim_async, feed = t.ok, t.nvim_async, t.feed +local async_meths = t.async_meths +local is_os = t.is_os +local parse_context = t.parse_context +local request = t.request +local rmdir = t.rmdir +local source = t.source +local next_msg = t.next_msg +local tmpname = t.tmpname +local write_file = t.write_file +local exec_lua = t.exec_lua +local exc_exec = t.exc_exec +local insert = t.insert +local skip = t.skip + +local pcall_err = t.pcall_err local format_string = require('test.format_string').format_string -local intchar2lua = helpers.intchar2lua -local mergedicts_copy = helpers.mergedicts_copy +local intchar2lua = t.intchar2lua +local mergedicts_copy = t.mergedicts_copy local endswith = vim.endswith describe('API', function() @@ -702,12 +702,12 @@ describe('API', function() end) after_each(function() - helpers.rmdir('Xtestdir') + t.rmdir('Xtestdir') end) it('works', function() api.nvim_set_current_dir('Xtestdir') - eq(start_dir .. helpers.get_pathsep() .. 'Xtestdir', fn.getcwd()) + eq(start_dir .. t.get_pathsep() .. 'Xtestdir', fn.getcwd()) end) it('sets previous directory', function() @@ -1467,7 +1467,7 @@ describe('API', function() eq(NIL, api.nvim_get_var('Unknown_script_func')) -- Check if autoload works properly - local pathsep = helpers.get_pathsep() + local pathsep = t.get_pathsep() local xconfig = 'Xhome' .. pathsep .. 'Xconfig' local xdata = 'Xhome' .. pathsep .. 'Xdata' local autoload_folder = table.concat({ xconfig, 'nvim', 'autoload' }, pathsep) @@ -1951,7 +1951,7 @@ describe('API', function() describe('RPC (K_EVENT)', function() it('does not complete ("interrupt") normal-mode operator-pending #6166', function() - helpers.insert([[ + t.insert([[ FIRST LINE SECOND LINE]]) api.nvim_input('gg') @@ -1988,7 +1988,7 @@ describe('API', function() it('does not complete ("interrupt") normal-mode map-pending #6166', function() command("nnoremap dd :let g:foo='it worked...'") - helpers.insert([[ + t.insert([[ FIRST LINE SECOND LINE]]) api.nvim_input('gg') @@ -2000,13 +2000,13 @@ describe('API', function() expect([[ FIRST LINE SECOND LINE]]) - eq('it worked...', helpers.eval('g:foo')) + eq('it worked...', t.eval('g:foo')) end) it('does not complete ("interrupt") insert-mode map-pending #6166', function() command('inoremap xx foo') command('set timeoutlen=9999') - helpers.insert([[ + t.insert([[ FIRST LINE SECOND LINE]]) api.nvim_input('ix') @@ -2153,35 +2153,32 @@ describe('API', function() describe('nvim_replace_termcodes', function() it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function() - eq('\128\254X', helpers.api.nvim_replace_termcodes('\128', true, true, true)) + eq('\128\254X', t.api.nvim_replace_termcodes('\128', true, true, true)) end) it('leaves non-K_SPECIAL string unchanged', function() - eq('abc', helpers.api.nvim_replace_termcodes('abc', true, true, true)) + eq('abc', t.api.nvim_replace_termcodes('abc', true, true, true)) end) it('converts ', function() - eq('\\', helpers.api.nvim_replace_termcodes('', true, true, true)) + eq('\\', t.api.nvim_replace_termcodes('', true, true, true)) end) it('converts to K_SPECIAL KS_EXTRA KE_LEFTMOUSE', function() -- K_SPECIAL KS_EXTRA KE_LEFTMOUSE -- 0x80 0xfd 0x2c -- 128 253 44 - eq('\128\253\44', helpers.api.nvim_replace_termcodes('', true, true, true)) + eq('\128\253\44', t.api.nvim_replace_termcodes('', true, true, true)) end) it('converts keycodes', function() - eq( - '\nx\27x\rxxxxx', true, true, true) - ) + eq('\nx\27x\rxxxxx', true, true, true)) end) it('does not convert keycodes if special=false', function() eq( 'xxxx', - helpers.api.nvim_replace_termcodes('xxxx', true, true, false) + t.api.nvim_replace_termcodes('xxxx', true, true, false) ) end) @@ -2210,18 +2207,18 @@ describe('API', function() api.nvim_feedkeys(':let x1="…"\n', '', true) -- Both nvim_replace_termcodes and nvim_feedkeys escape \x80 - local inp = helpers.api.nvim_replace_termcodes(':let x2="…"', true, true, true) + local inp = t.api.nvim_replace_termcodes(':let x2="…"', true, true, true) api.nvim_feedkeys(inp, '', true) -- escape_ks=true -- nvim_feedkeys with K_SPECIAL escaping disabled - inp = helpers.api.nvim_replace_termcodes(':let x3="…"', true, true, true) + inp = t.api.nvim_replace_termcodes(':let x3="…"', true, true, true) api.nvim_feedkeys(inp, '', false) -- escape_ks=false - helpers.stop() + t.stop() end -- spin the loop a bit - helpers.run(nil, nil, on_setup) + t.run(nil, nil, on_setup) eq('…', api.nvim_get_var('x1')) -- Because of the double escaping this is neq @@ -2364,7 +2361,7 @@ describe('API', function() {0:~ }|*6 {1:very fail} | ]]) - helpers.poke_eventloop() + t.poke_eventloop() -- shows up to &cmdheight lines async_meths.nvim_err_write('more fail\ntoo fail\n') @@ -2676,7 +2673,7 @@ describe('API', function() describe('nvim_list_runtime_paths', function() setup(function() - local pathsep = helpers.get_pathsep() + local pathsep = t.get_pathsep() mkdir_p('Xtest' .. pathsep .. 'a') mkdir_p('Xtest' .. pathsep .. 'b') end) @@ -3183,7 +3180,7 @@ describe('API', function() end) describe('nvim_get_runtime_file', function() - local p = helpers.alter_slashes + local p = t.alter_slashes it('can find files', function() eq({}, api.nvim_get_runtime_file('bork.borkbork', false)) eq({}, api.nvim_get_runtime_file('bork.borkbork', true)) @@ -3410,13 +3407,13 @@ describe('API', function() {desc="(global option, fallback requested) points to global", linenr=9, sid=1, args={'completeopt', {}}}, } - for _, t in pairs(tests) do - it(t.desc, function() + for _, test in pairs(tests) do + it(test.desc, function() -- Switch to the target buffer/window so that curbuf/curwin are used. api.nvim_set_current_win(wins[2]) - local info = api.nvim_get_option_info2(unpack(t.args)) - eq(t.linenr, info.last_set_linenr) - eq(t.sid, info.last_set_sid) + local info = api.nvim_get_option_info2(unpack(test.args)) + eq(test.linenr, info.last_set_linenr) + eq(test.sid, info.last_set_sid) end) end @@ -3537,9 +3534,9 @@ describe('API', function() false, { width = 79, height = 31, row = 1, col = 1, relative = 'editor' } ) - local t = api.nvim_open_term(b, {}) + local term = api.nvim_open_term(b, {}) - api.nvim_chan_send(t, io.open('test/functional/fixtures/smile2.cat', 'r'):read('*a')) + api.nvim_chan_send(term, io.open('test/functional/fixtures/smile2.cat', 'r'):read('*a')) screen:expect { grid = [[ ^ | diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 721148faaa..43f1a05414 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1,27 +1,27 @@ -local helpers = require('test.functional.helpers')(after_each) +local t = require('test.functional.testutil')(after_each) local Screen = require('test.functional.ui.screen') local clear, curbuf, curbuf_contents, curwin, eq, neq, matches, ok, feed, insert, eval = - helpers.clear, - helpers.api.nvim_get_current_buf, - helpers.curbuf_contents, - helpers.api.nvim_get_current_win, - helpers.eq, - helpers.neq, - helpers.matches, - helpers.ok, - helpers.feed, - helpers.insert, - helpers.eval -local poke_eventloop = helpers.poke_eventloop -local exec = helpers.exec -local exec_lua = helpers.exec_lua -local fn = helpers.fn -local request = helpers.request + t.clear, + t.api.nvim_get_current_buf, + t.curbuf_contents, + t.api.nvim_get_current_win, + t.eq, + t.neq, + t.matches, + t.ok, + t.feed, + t.insert, + t.eval +local poke_eventloop = t.poke_eventloop +local exec = t.exec +local exec_lua = t.exec_lua +local fn = t.fn +local request = t.request local NIL = vim.NIL -local api = helpers.api -local command = helpers.command -local pcall_err = helpers.pcall_err -local assert_alive = helpers.assert_alive +local api = t.api +local command = t.command +local pcall_err = t.pcall_err +local assert_alive = t.assert_alive describe('API/win', function() before_each(clear) @@ -1297,7 +1297,7 @@ describe('API/win', function() local tab1 = api.nvim_get_current_tabpage() local tab1_win = api.nvim_get_current_win() - helpers.command('tabnew') + t.command('tabnew') local tab2 = api.nvim_get_current_tabpage() local tab2_win = api.nvim_get_current_win() -- cgit From 81fc27124b9e1b375e0ce9605ae69c3c2a2d9222 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 9 Apr 2024 12:26:16 +0100 Subject: refactor(test): inject after_each differently --- test/functional/api/autocmd_spec.lua | 2 +- test/functional/api/buffer_spec.lua | 2 +- test/functional/api/buffer_updates_spec.lua | 2 +- test/functional/api/command_spec.lua | 2 +- test/functional/api/extmark_spec.lua | 2 +- test/functional/api/highlight_spec.lua | 2 +- test/functional/api/keymap_spec.lua | 2 +- test/functional/api/menu_spec.lua | 2 +- test/functional/api/proc_spec.lua | 2 +- test/functional/api/server_notifications_spec.lua | 2 +- test/functional/api/server_requests_spec.lua | 2 +- test/functional/api/tabpage_spec.lua | 2 +- test/functional/api/ui_spec.lua | 2 +- test/functional/api/version_spec.lua | 2 +- test/functional/api/vim_spec.lua | 2 +- test/functional/api/window_spec.lua | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index b97647850c..31276c7566 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear = t.clear local command = t.command diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index de56c16bd8..ec5c046878 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local Screen = require('test.functional.ui.screen') local clear = t.clear local eq = t.eq diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index 715c469c76..494bc4495b 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear = t.clear local eq, ok = t.eq, t.ok local fn = t.fn diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index 29d96a1ff5..6c51fac178 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local NIL = vim.NIL local clear = t.clear diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 1a96510d3d..82e7ad3988 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local Screen = require('test.functional.ui.screen') local request = t.request diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 4156af5901..50e79f8860 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear = t.clear local Screen = require('test.functional.ui.screen') local eq, eval = t.eq, t.eval diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index d6a8b592d7..2b889fa012 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear = t.clear local command = t.command diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 97d0f43d64..2e6fdd6551 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local Screen = require('test.functional.ui.screen') local clear = t.clear diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 85e55d0cfb..1b090aa30d 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear = t.clear local eq = t.eq diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index ee2e401dd5..fd7e596016 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local assert_log = t.assert_log local eq, clear, eval, command, next_msg = t.eq, t.clear, t.eval, t.command, t.next_msg local api = t.api diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 3a925dcbe2..5385b23ec1 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -1,6 +1,6 @@ -- Test server -> client RPC scenarios. Note: unlike `rpcnotify`, to evaluate -- `rpcrequest` calls we need the client event loop to be running. -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear, eval = t.clear, t.eval local eq, neq, run, stop = t.eq, t.neq, t.run, t.stop diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index 6ed5daca0f..328e3aa653 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear, eq, ok = t.clear, t.eq, t.ok local exec = t.exec local feed = t.feed diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 89eeeaa189..36fa71f2ec 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local Screen = require('test.functional.ui.screen') local clear = t.clear local command = t.command diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua index 7ab27be298..b57f67369e 100644 --- a/test/functional/api/version_spec.lua +++ b/test/functional/api/version_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local clear, fn, eq = t.clear, t.fn, t.eq local api = t.api diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 82d5480997..4e9a42f11d 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local Screen = require('test.functional.ui.screen') local uv = vim.uv diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 43f1a05414..6a99352b3c 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1,4 +1,4 @@ -local t = require('test.functional.testutil')(after_each) +local t = require('test.functional.testutil')() local Screen = require('test.functional.ui.screen') local clear, curbuf, curbuf_contents, curwin, eq, neq, matches, ok, feed, insert, eval = t.clear, -- cgit From 7180ef690180cf92d1d49811820c46dd60e4d1c6 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Mon, 15 Apr 2024 00:10:16 +0100 Subject: feat(api)!: nvim_open_win: noautocmd blocks all autocmds #28192 Problem: noautocmd is confusing; despite its name, it doesn't block all autocommands (instead it blocks only those related to setting the buffer), and is commonly used by plugins to open windows while producing minimal side-effects. Solution: be consistent and block all autocommands when noautocmd is set. This includes WinNew (again), plus autocommands from entering the window (if enter is set) like WinEnter, WinLeave, TabEnter, .etc. See the discussion at https://github.com/neovim/neovim/pull/14659#issuecomment-2040029517 for more information. Remove win_set_buf's noautocmd argument, as it's no longer needed. NOTE: pum_create_float_preview sets noautocmd for win_set_buf, but all its callers already use block_autocmds. Despite that, pum_create_float_preview doesn't actually properly handle autocommands (it has no checks for whether those from win_enter or nvim_create_buf free the window). For now, ensure autocommands are blocked within it for correctness (in case it's ever called outside of a block_autocmds context; the function seems to have been refactored in #26739 anyway). --- test/functional/api/window_spec.lua | 39 +++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 6a99352b3c..d9d3772df2 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1162,27 +1162,6 @@ describe('API/win', function() end) describe('open_win', function() - it('noautocmd option works', function() - command('autocmd BufEnter,BufLeave,BufWinEnter * let g:fired = 1') - api.nvim_open_win(api.nvim_create_buf(true, true), true, { - relative = 'win', - row = 3, - col = 3, - width = 12, - height = 3, - noautocmd = true, - }) - eq(0, fn.exists('g:fired')) - api.nvim_open_win(api.nvim_create_buf(true, true), true, { - relative = 'win', - row = 3, - col = 3, - width = 12, - height = 3, - }) - eq(1, fn.exists('g:fired')) - end) - it('disallowed in cmdwin if enter=true or buf=cmdwin_buf', function() local new_buf = api.nvim_create_buf(true, true) feed('q:') @@ -1406,6 +1385,24 @@ describe('API/win', function() return info end + it('noautocmd option works', function() + local info = setup_tabbed_autocmd_test() + + api.nvim_open_win( + info.other_buf, + true, + { split = 'left', win = info.tab2_curwin, noautocmd = true } + ) + eq({}, eval('result')) + + api.nvim_open_win( + info.orig_buf, + true, + { relative = 'editor', row = 0, col = 0, width = 10, height = 10, noautocmd = true } + ) + eq({}, eval('result')) + end) + it('fires expected autocmds when creating splits without entering', function() local info = setup_tabbed_autocmd_test() -- cgit From 4ec8fd43bfdf1924ee03e07afc8a46dfdd3c9b12 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 15 Apr 2024 17:55:57 +0800 Subject: fix(api): make width/height for split by nvim_open_win work (#28341) --- test/functional/api/window_spec.lua | 188 +++++++++++++++++++++++++----------- 1 file changed, 129 insertions(+), 59 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index d9d3772df2..4f0da7c0f4 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1227,81 +1227,151 @@ describe('API/win', function() eq(wins_before, api.nvim_list_wins()) end) - it('creates a split window', function() - local win = api.nvim_open_win(0, true, { - vertical = false, - }) - eq('', api.nvim_win_get_config(win).relative) + describe('creates a split window above', function() + local function test_open_win_split_above(key, val) + local initial_win = api.nvim_get_current_win() + local win = api.nvim_open_win(0, true, { + [key] = val, + height = 10, + }) + eq('', api.nvim_win_get_config(win).relative) + eq(10, api.nvim_win_get_height(win)) + local layout = fn.winlayout() + eq({ + 'col', + { + { 'leaf', win }, + { 'leaf', initial_win }, + }, + }, layout) + end + + it("with split = 'above'", function() + test_open_win_split_above('split', 'above') + end) + + it("with vertical = false and 'nosplitbelow'", function() + api.nvim_set_option_value('splitbelow', false, {}) + test_open_win_split_above('vertical', false) + end) end) - it('creates split windows in the correct direction', function() - local initial_win = api.nvim_get_current_win() - local win = api.nvim_open_win(0, true, { - vertical = true, - }) - eq('', api.nvim_win_get_config(win).relative) + describe('creates a split window below', function() + local function test_open_win_split_below(key, val) + local initial_win = api.nvim_get_current_win() + local win = api.nvim_open_win(0, true, { + [key] = val, + height = 15, + }) + eq('', api.nvim_win_get_config(win).relative) + eq(15, api.nvim_win_get_height(win)) + local layout = fn.winlayout() + eq({ + 'col', + { + { 'leaf', initial_win }, + { 'leaf', win }, + }, + }, layout) + end - local layout = fn.winlayout() + it("with split = 'below'", function() + test_open_win_split_below('split', 'below') + end) - eq({ - 'row', - { - { 'leaf', win }, - { 'leaf', initial_win }, - }, - }, layout) + it("with vertical = false and 'splitbelow'", function() + api.nvim_set_option_value('splitbelow', true, {}) + test_open_win_split_below('vertical', false) + end) end) - it("respects the 'split' option", function() - local initial_win = api.nvim_get_current_win() - local win = api.nvim_open_win(0, true, { - split = 'below', - }) - eq('', api.nvim_win_get_config(win).relative) + describe('creates a split window to the left', function() + local function test_open_win_split_left(key, val) + local initial_win = api.nvim_get_current_win() + local win = api.nvim_open_win(0, true, { + [key] = val, + width = 25, + }) + eq('', api.nvim_win_get_config(win).relative) + eq(25, api.nvim_win_get_width(win)) + local layout = fn.winlayout() + eq({ + 'row', + { + { 'leaf', win }, + { 'leaf', initial_win }, + }, + }, layout) + end - local layout = fn.winlayout() + it("with split = 'left'", function() + test_open_win_split_left('split', 'left') + end) - eq({ - 'col', - { - { 'leaf', initial_win }, - { 'leaf', win }, - }, - }, layout) + it("with vertical = true and 'nosplitright'", function() + api.nvim_set_option_value('splitright', false, {}) + test_open_win_split_left('vertical', true) + end) + end) + + describe('creates a split window to the right', function() + local function test_open_win_split_right(key, val) + local initial_win = api.nvim_get_current_win() + local win = api.nvim_open_win(0, true, { + [key] = val, + width = 30, + }) + eq('', api.nvim_win_get_config(win).relative) + eq(30, api.nvim_win_get_width(win)) + local layout = fn.winlayout() + eq({ + 'row', + { + { 'leaf', initial_win }, + { 'leaf', win }, + }, + }, layout) + end + + it("with split = 'right'", function() + test_open_win_split_right('split', 'right') + end) + + it("with vertical = true and 'splitright'", function() + api.nvim_set_option_value('splitright', true, {}) + test_open_win_split_right('vertical', true) + end) end) - it( - "doesn't change tp_curwin when splitting window in non-current tab with enter=false", - function() - local tab1 = api.nvim_get_current_tabpage() - local tab1_win = api.nvim_get_current_win() + it("doesn't change tp_curwin when splitting window in another tab with enter=false", function() + local tab1 = api.nvim_get_current_tabpage() + local tab1_win = api.nvim_get_current_win() - t.command('tabnew') - local tab2 = api.nvim_get_current_tabpage() - local tab2_win = api.nvim_get_current_win() + t.command('tabnew') + local tab2 = api.nvim_get_current_tabpage() + local tab2_win = api.nvim_get_current_win() - eq({ tab1_win, tab2_win }, api.nvim_list_wins()) - eq({ tab1, tab2 }, api.nvim_list_tabpages()) + eq({ tab1_win, tab2_win }, api.nvim_list_wins()) + eq({ tab1, tab2 }, api.nvim_list_tabpages()) - api.nvim_set_current_tabpage(tab1) - eq(tab1_win, api.nvim_get_current_win()) + api.nvim_set_current_tabpage(tab1) + eq(tab1_win, api.nvim_get_current_win()) - local tab2_prevwin = fn.tabpagewinnr(tab2, '#') + local tab2_prevwin = fn.tabpagewinnr(tab2, '#') - -- split in tab2 whine in tab2, with enter = false - local tab2_win2 = api.nvim_open_win(api.nvim_create_buf(false, true), false, { - win = tab2_win, - split = 'right', - }) - eq(tab1_win, api.nvim_get_current_win()) -- we should still be in the first tp - eq(tab1_win, api.nvim_tabpage_get_win(tab1)) + -- split in tab2 whine in tab2, with enter = false + local tab2_win2 = api.nvim_open_win(api.nvim_create_buf(false, true), false, { + win = tab2_win, + split = 'right', + }) + eq(tab1_win, api.nvim_get_current_win()) -- we should still be in the first tp + eq(tab1_win, api.nvim_tabpage_get_win(tab1)) - eq(tab2_win, api.nvim_tabpage_get_win(tab2)) -- tab2's tp_curwin should not have changed - eq(tab2_prevwin, fn.tabpagewinnr(tab2, '#')) -- tab2's tp_prevwin should not have changed - eq({ tab1_win, tab2_win, tab2_win2 }, api.nvim_list_wins()) - eq({ tab2_win, tab2_win2 }, api.nvim_tabpage_list_wins(tab2)) - end - ) + eq(tab2_win, api.nvim_tabpage_get_win(tab2)) -- tab2's tp_curwin should not have changed + eq(tab2_prevwin, fn.tabpagewinnr(tab2, '#')) -- tab2's tp_prevwin should not have changed + eq({ tab1_win, tab2_win, tab2_win2 }, api.nvim_list_wins()) + eq({ tab2_win, tab2_win2 }, api.nvim_tabpage_list_wins(tab2)) + end) it('creates splits in the correct location', function() local first_win = api.nvim_get_current_win() -- cgit From 47ba96a6b3bf22097134b319ed97ec840b05eaa7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 16 Apr 2024 11:59:55 +0800 Subject: test: getting autocmd Lua callback in Vimscript (#28367) Also remove unnecessary variable in API converter. --- test/functional/api/autocmd_spec.lua | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 31276c7566..e5412a8e99 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -610,15 +610,17 @@ describe('autocmd api', function() it('can retrieve a callback from an autocmd', function() local content = 'I Am A Callback' api.nvim_set_var('content', content) - - local result = exec_lua([[ + exec_lua([[ local cb = function() return vim.g.content end vim.api.nvim_create_autocmd("User", { pattern = "TestTrigger", desc = "A test autocommand with a callback", callback = cb, }) - local aus = vim.api.nvim_get_autocmds({ event = 'User', pattern = 'TestTrigger'}) + ]]) + + local result = exec_lua([[ + local aus = vim.api.nvim_get_autocmds({ event = 'User', pattern = 'TestTrigger' }) local first = aus[1] return { cb = { @@ -627,9 +629,14 @@ describe('autocmd api', function() } } ]]) + eq({ cb = { type = 'function', can_retrieve = true } }, result) - eq('function', result.cb.type) - eq(true, result.cb.can_retrieve) + -- Also test with Vimscript + source([[ + let s:aus = nvim_get_autocmds({'event': 'User', 'pattern': 'TestTrigger'}) + let g:result = s:aus[0].callback() + ]]) + eq(content, api.nvim_get_var('result')) end) it( -- cgit From 7fa24948a936a95519f0c8c496402488b6508c14 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 16 Apr 2024 14:05:09 +0800 Subject: test: make mapping tests more consistent (#28368) - Test maparg() and maplist() in the same test. - Use matches() instead of string.match(). - Avoid overlong lines and strange spacing in exec_lua(). - Revert code change from last PR as the variable may be needed. --- test/functional/api/keymap_spec.lua | 160 ++++++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 53 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 2b889fa012..f0ed04e88e 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -8,6 +8,7 @@ local exec = t.exec local feed = t.feed local fn = t.fn local api = t.api +local matches = t.matches local source = t.source local pcall_err = t.pcall_err @@ -398,7 +399,9 @@ describe('nvim_get_keymap', function() 0, exec_lua([[ GlobalCount = 0 - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]]) ) @@ -951,7 +954,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -963,34 +968,38 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it(':map command shows lua mapping correctly', function() exec_lua [[ - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() print('jkl;') end, + }) ]] - assert.truthy( - string.match( - exec_lua [[return vim.api.nvim_exec2(':nmap asdf', { output = true }).output]], - '^\nn asdf ' - ) + matches( + '^\nn asdf ', + exec_lua [[return vim.api.nvim_exec2(':nmap asdf', { output = true }).output]] ) end) it('mapcheck() returns lua mapping correctly', function() exec_lua [[ - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() print('jkl;') end, + }) ]] - assert.truthy(string.match(fn.mapcheck('asdf', 'n'), '^')) + matches('^', fn.mapcheck('asdf', 'n')) end) - it('maparg() returns lua mapping correctly', function() + it('maparg() and maplist() return lua mapping correctly', function() eq( 0, exec_lua([[ GlobalCount = 0 - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]]) ) - assert.truthy(string.match(fn.maparg('asdf', 'n'), '^')) + matches('^', fn.maparg('asdf', 'n')) local mapargs = fn.maparg('asdf', 'n', false, true) mapargs.callback = nil @@ -1010,11 +1019,20 @@ describe('nvim_set_keymap, nvim_del_keymap', function() call maparg('asdf', 'n', v:false, v:true).callback() ]]) eq(2, exec_lua([[return GlobalCount]])) + + api.nvim_eval([[ + maplist()->filter({_, m -> m.lhs == 'asdf'})->foreach({_, m -> m.callback()}) + ]]) + eq(3, exec_lua([[return GlobalCount]])) end) it('can make lua expr mappings replacing keycodes', function() exec_lua [[ - vim.api.nvim_set_keymap('n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true }) + vim.api.nvim_set_keymap('n', 'aa', '', { + callback = function() return 'πfoo' end, + expr = true, + replace_keycodes = true, + }) ]] feed('aa') @@ -1024,7 +1042,10 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can make lua expr mappings without replacing keycodes', function() exec_lua [[ - vim.api.nvim_set_keymap('i', 'aa', '', {callback = function() return '' end, expr = true }) + vim.api.nvim_set_keymap('i', 'aa', '', { + callback = function() return '' end, + expr = true, + }) ]] feed('iaa') @@ -1034,7 +1055,10 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('lua expr mapping returning nil is equivalent to returning an empty string', function() exec_lua [[ - vim.api.nvim_set_keymap('i', 'aa', '', {callback = function() return nil end, expr = true }) + vim.api.nvim_set_keymap('i', 'aa', '', { + callback = function() return nil end, + expr = true, + }) ]] feed('iaa') @@ -1047,7 +1071,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() 0, exec_lua [[ VisibleCount = 0 - vim.api.nvim_set_keymap('i', '', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end}) + vim.api.nvim_set_keymap('i', '', '', { + callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end, + }) return VisibleCount ]] ) @@ -1060,7 +1086,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() 0, exec_lua [[ OpCount = 0 - vim.api.nvim_set_keymap('o', '', '', {callback = function() OpCount = OpCount + 1 end}) + vim.api.nvim_set_keymap('o', '', '', { + callback = function() OpCount = OpCount + 1 end, + }) return OpCount ]] ) @@ -1075,7 +1103,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1085,7 +1115,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() eq(1, exec_lua [[return GlobalCount]]) exec_lua [[ - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount - 1 end, + }) ]] feed('asdf\n') @@ -1098,7 +1130,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1107,9 +1141,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() eq(1, exec_lua [[return GlobalCount]]) - exec_lua [[ - vim.api.nvim_del_keymap('n', 'asdf' ) - ]] + exec_lua [[vim.api.nvim_del_keymap('n', 'asdf' )]] feed('asdf\n') @@ -1122,7 +1154,9 @@ describe('nvim_set_keymap, nvim_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('n', '', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_set_keymap('n', '', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1131,9 +1165,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() eq(1, exec_lua [[return GlobalCount]]) - exec_lua [[ - vim.api.nvim_del_keymap('n', '') - ]] + exec_lua [[vim.api.nvim_del_keymap('n', '')]] feed('\n') @@ -1150,10 +1182,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can define !-mode abbreviations with lua callbacks', function() exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('!a', 'foo', '', {expr = true, callback = function() - GlobalCount = GlobalCount + 1 - return tostring(GlobalCount) - end}) + vim.api.nvim_set_keymap('!a', 'foo', '', { + expr = true, + callback = function() + GlobalCount = GlobalCount + 1 + return tostring(GlobalCount) + end, + }) ]] feed 'iThe foo and the bar and the foo again' @@ -1166,10 +1201,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can define insert mode abbreviations with lua callbacks', function() exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('ia', 'foo', '', {expr = true, callback = function() - GlobalCount = GlobalCount + 1 - return tostring(GlobalCount) - end}) + vim.api.nvim_set_keymap('ia', 'foo', '', { + expr = true, + callback = function() + GlobalCount = GlobalCount + 1 + return tostring(GlobalCount) + end, + }) ]] feed 'iThe foo and the bar and the foo again' @@ -1182,10 +1220,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() it('can define cmdline mode abbreviations with lua callbacks', function() exec_lua [[ GlobalCount = 0 - vim.api.nvim_set_keymap('ca', 'foo', '', {expr = true, callback = function() - GlobalCount = GlobalCount + 1 - return tostring(GlobalCount) - end}) + vim.api.nvim_set_keymap('ca', 'foo', '', { + expr = true, + callback = function() + GlobalCount = GlobalCount + 1 + return tostring(GlobalCount) + end, + }) ]] feed 'iThe foo and the bar and the foo again' @@ -1298,7 +1339,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1310,7 +1353,11 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can make lua expr mappings replacing keycodes', function() exec_lua [[ - vim.api.nvim_buf_set_keymap(0, 'n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true }) + vim.api.nvim_buf_set_keymap(0, 'n', 'aa', '', { + callback = function() return 'πfoo' end, + expr = true, + replace_keycodes = true, + }) ]] feed('aa') @@ -1320,7 +1367,10 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('can make lua expr mappings without replacing keycodes', function() exec_lua [[ - vim.api.nvim_buf_set_keymap(0, 'i', 'aa', '', {callback = function() return '' end, expr = true }) + vim.api.nvim_buf_set_keymap(0, 'i', 'aa', '', { + callback = function() return '' end, + expr = true, + }) ]] feed('iaa') @@ -1333,7 +1383,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1343,7 +1395,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() eq(1, exec_lua [[return GlobalCount]]) exec_lua [[ - vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount - 1 end, + }) ]] feed('asdf\n') @@ -1356,7 +1410,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1365,9 +1421,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() eq(1, exec_lua [[return GlobalCount]]) - exec_lua [[ - vim.api.nvim_buf_del_keymap(0, 'n', 'asdf' ) - ]] + exec_lua [[vim.api.nvim_buf_del_keymap(0, 'n', 'asdf' )]] feed('asdf\n') @@ -1380,7 +1434,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() 0, exec_lua [[ GlobalCount = 0 - vim.api.nvim_buf_set_keymap(0, 'n', '', '', {callback = function() GlobalCount = GlobalCount + 1 end }) + vim.api.nvim_buf_set_keymap(0, 'n', '', '', { + callback = function() GlobalCount = GlobalCount + 1 end, + }) return GlobalCount ]] ) @@ -1389,9 +1445,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() eq(1, exec_lua [[return GlobalCount]]) - exec_lua [[ - vim.api.nvim_buf_del_keymap(0, 'n', '') - ]] + exec_lua [[vim.api.nvim_buf_del_keymap(0, 'n', '')]] feed('\n') -- cgit From 2fc2343728831d890a043def5d9d714947737cf6 Mon Sep 17 00:00:00 2001 From: Raphael Date: Tue, 16 Apr 2024 19:49:56 +0800 Subject: fix(api): ignore 'autochdir' when setting buf in other win (#28371) Problem: Wrong working directory when setting buffer in another window with 'autochdir' enabled. Solution: Temporarily disable 'autochdir'. --- test/functional/api/window_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 4f0da7c0f4..2ad5f0e799 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1748,6 +1748,31 @@ describe('API/win', function() pcall_err(api.nvim_open_win, 0, true, { split = 'below', win = 0 }) ) end) + + it('do not change dir when enter is false', function() + local expected = fn.getcwd() .. '/foo' + t.mkdir('foo') + exec_lua [[ + vim.opt.autochdir = true + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_name(buf, 'Foo') + vim.api.nvim_create_autocmd('CmdlineEnter', { + callback = function() + local winid = vim.api.nvim_open_win(buf, false, { + relative = 'editor', + height = 1, + width = 1, + row = 1, + col = 1, + }) + vim.api.nvim_win_close(winid, true) + end, + }) + ]] + t.feed(':edit foo/bar.txt') + eq(t.is_os('win') and expected:gsub('/', '\\') or expected, fn.getcwd()) + t.rmdir('foo') + end) end) describe('set_config', function() -- cgit From 5cfdaaaeac0f53a621696d8eb6b5a3ba90438c98 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 16 Apr 2024 20:57:01 +0800 Subject: fix(api): ignore 'autochdir' when renaming other buf (#28376) Problem: Renaming non-current buffer changes working directory when 'autochdir' is set. Solution: Temporarily disable 'autochdir'. Add more tests for the win_set_buf change. --- test/functional/api/buffer_spec.lua | 31 ++++++++++++ test/functional/api/window_spec.lua | 99 ++++++++++++++++++++++++++++--------- 2 files changed, 107 insertions(+), 23 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index ec5c046878..12b2c43158 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -2048,6 +2048,37 @@ describe('api/buf', function() eq(1, fn.filereadable(new_name)) os.remove(new_name) end) + + describe("with 'autochdir'", function() + local topdir + local oldbuf + local newbuf + + before_each(function() + command('set shellslash') + topdir = fn.getcwd() + t.mkdir(topdir .. '/Xacd') + + oldbuf = api.nvim_get_current_buf() + command('vnew') + newbuf = api.nvim_get_current_buf() + command('set autochdir') + end) + + after_each(function() + t.rmdir(topdir .. '/Xacd') + end) + + it('does not change cwd with non-current buffer', function() + api.nvim_buf_set_name(oldbuf, topdir .. '/Xacd/foo.txt') + eq(topdir, fn.getcwd()) + end) + + it('changes cwd with current buffer', function() + api.nvim_buf_set_name(newbuf, topdir .. '/Xacd/foo.txt') + eq(topdir .. '/Xacd', fn.getcwd()) + end) + end) end) describe('nvim_buf_is_loaded', function() diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 2ad5f0e799..14bb0c8697 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -111,6 +111,44 @@ describe('API/win', function() api.nvim_win_set_buf(new_win, next_buf) eq(next_buf, api.nvim_win_get_buf(new_win)) end) + + describe("with 'autochdir'", function() + local topdir + local otherbuf + local oldwin + local newwin + + before_each(function() + command('set shellslash') + topdir = fn.getcwd() + t.mkdir(topdir .. '/Xacd') + t.mkdir(topdir .. '/Xacd/foo') + otherbuf = api.nvim_create_buf(false, true) + api.nvim_buf_set_name(otherbuf, topdir .. '/Xacd/baz.txt') + + command('set autochdir') + command('edit Xacd/foo/bar.txt') + eq(topdir .. '/Xacd/foo', fn.getcwd()) + + oldwin = api.nvim_get_current_win() + command('vsplit') + newwin = api.nvim_get_current_win() + end) + + after_each(function() + t.rmdir(topdir .. '/Xacd') + end) + + it('does not change cwd with non-current window', function() + api.nvim_win_set_buf(oldwin, otherbuf) + eq(topdir .. '/Xacd/foo', fn.getcwd()) + end) + + it('changes cwd with current window', function() + api.nvim_win_set_buf(newwin, otherbuf) + eq(topdir .. '/Xacd', fn.getcwd()) + end) + end) end) describe('{get,set}_cursor', function() @@ -1749,29 +1787,44 @@ describe('API/win', function() ) end) - it('do not change dir when enter is false', function() - local expected = fn.getcwd() .. '/foo' - t.mkdir('foo') - exec_lua [[ - vim.opt.autochdir = true - local buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_name(buf, 'Foo') - vim.api.nvim_create_autocmd('CmdlineEnter', { - callback = function() - local winid = vim.api.nvim_open_win(buf, false, { - relative = 'editor', - height = 1, - width = 1, - row = 1, - col = 1, - }) - vim.api.nvim_win_close(winid, true) - end, - }) - ]] - t.feed(':edit foo/bar.txt') - eq(t.is_os('win') and expected:gsub('/', '\\') or expected, fn.getcwd()) - t.rmdir('foo') + describe("with 'autochdir'", function() + local topdir + local otherbuf + + before_each(function() + command('set shellslash') + topdir = fn.getcwd() + t.mkdir(topdir .. '/Xacd') + t.mkdir(topdir .. '/Xacd/foo') + otherbuf = api.nvim_create_buf(false, true) + api.nvim_buf_set_name(otherbuf, topdir .. '/Xacd/baz.txt') + + command('set autochdir') + command('edit Xacd/foo/bar.txt') + eq(topdir .. '/Xacd/foo', fn.getcwd()) + end) + + after_each(function() + t.rmdir(topdir .. '/Xacd') + end) + + it('does not change cwd with enter=false #15280', function() + api.nvim_open_win( + otherbuf, + false, + { relative = 'editor', height = 5, width = 5, row = 5, col = 5 } + ) + eq(topdir .. '/Xacd/foo', fn.getcwd()) + end) + + it('changes cwd with enter=true', function() + api.nvim_open_win( + otherbuf, + true, + { relative = 'editor', height = 5, width = 5, row = 5, col = 5 } + ) + eq(topdir .. '/Xacd', fn.getcwd()) + end) end) end) -- cgit From f150b62423d57b6f9fbe57330589937dfbb34f4a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 17 Apr 2024 05:44:06 +0800 Subject: fix(lua): only free luarefs when returning from API (#28373) --- test/functional/api/autocmd_spec.lua | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index e5412a8e99..d2ec3a576c 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -355,6 +355,44 @@ describe('autocmd api', function() test({ 'list' }) test({ foo = 'bar' }) end) + + it('function in arbitrary data is passed to all autocmds #28353', function() + eq( + 1303, + exec_lua([[ + local res = 1 + + local fun = function(m, x) + res = res * m + x + end + + local group = vim.api.nvim_create_augroup('MyTest', { clear = false }) + + vim.api.nvim_create_autocmd('User', { + group = group, + callback = function(payload) + payload.data.fun(10, payload.data.x) + end, + pattern = 'MyEvent', + }) + vim.api.nvim_create_autocmd('User', { + group = group, + callback = function(payload) + payload.data.fun(100, payload.data.x) + end, + pattern = 'MyEvent', + }) + + vim.api.nvim_exec_autocmds('User', { + group = group, + pattern = 'MyEvent', + data = { x = 3, fun = fun }, + }) + + return res + ]]) + ) + end) end) describe('nvim_get_autocmds', function() -- cgit From 329fc0e5b7f7777c405e4828650567a93620ba50 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 17 Apr 2024 06:34:10 +0800 Subject: test: API can return Lua function to Lua code (#28380) --- test/functional/api/vim_spec.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 4e9a42f11d..c412773482 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -559,6 +559,16 @@ describe('API', function() eq('Vim:E121: Undefined variable: bogus', pcall_err(request, 'nvim_eval', 'bogus expression')) eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) + + it('can return Lua function to Lua code', function() + eq( + [["a string with \"double quotes\" and 'single quotes'"]], + exec_lua([=[ + local fun = vim.api.nvim_eval([[luaeval('string.format')]]) + return fun('%q', [[a string with "double quotes" and 'single quotes']]) + ]=]) + ) + end) end) describe('nvim_call_function', function() @@ -624,6 +634,16 @@ describe('API', function() pcall_err(request, 'nvim_call_function', 'Foo', too_many_args) ) end) + + it('can return Lua function to Lua code', function() + eq( + [["a string with \"double quotes\" and 'single quotes'"]], + exec_lua([=[ + local fun = vim.api.nvim_call_function('luaeval', { 'string.format' }) + return fun('%q', [[a string with "double quotes" and 'single quotes']]) + ]=]) + ) + end) end) describe('nvim_call_dict_function', function() -- cgit From 344906a08f0972108eb912c87af32b275ecf318e Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 21 Apr 2024 02:15:18 +0200 Subject: fix(api): do not update grid position in nvim_win_set_cursor (#28235) Revert commit c971f538ab87b537ae4c97bd44167661c5691a2d. Forcing grid cursor position will need a new API like originally proposed in #27858. --- test/functional/api/window_spec.lua | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 14bb0c8697..36966b68f5 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -257,21 +257,6 @@ describe('API/win', function() -- curwin didn't change back neq(win, curwin()) - - -- shows updated position after getchar() #20793 - feed(':call getchar()') - api.nvim_win_set_cursor(win, { 1, 5 }) - screen:expect { - grid = [[ - | - {1:~ }|*2 - {2:[No Name] }| - prolo^gue | - |*2 - {3:[No Name] [+] }| - :call getchar() | - ]], - } end) it('remembers what column it wants to be in', function() -- cgit From 052498ed42780a76daea589d063cd8947a894673 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 20 Apr 2024 17:44:13 +0200 Subject: test: improve test conventions Specifically, functions that are run in the context of the test runner are put in module `test/testutil.lua` while the functions that are run in the context of the test session are put in `test/functional/testnvim.lua`. Closes https://github.com/neovim/neovim/issues/27004. --- test/functional/api/autocmd_spec.lua | 13 ++-- test/functional/api/buffer_spec.lua | 30 ++++---- test/functional/api/buffer_updates_spec.lua | 24 ++++--- test/functional/api/command_spec.lua | 19 ++--- test/functional/api/extmark_spec.lua | 21 +++--- test/functional/api/highlight_spec.lua | 18 ++--- test/functional/api/keymap_spec.lua | 31 +++++---- test/functional/api/menu_spec.lua | 8 +-- test/functional/api/proc_spec.lua | 11 +-- test/functional/api/server_notifications_spec.lua | 14 ++-- test/functional/api/server_requests_spec.lua | 39 ++++++----- test/functional/api/tabpage_spec.lua | 18 ++--- test/functional/api/ui_spec.lua | 18 ++--- test/functional/api/version_spec.lua | 8 ++- test/functional/api/vim_spec.lua | 85 ++++++++++++----------- test/functional/api/window_spec.lua | 40 ++++++----- 16 files changed, 210 insertions(+), 187 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index d2ec3a576c..3f9883f43f 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -1,13 +1,14 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local clear = t.clear -local command = t.command +local clear = n.clear +local command = n.command local eq = t.eq local neq = t.neq -local exec_lua = t.exec_lua +local exec_lua = n.exec_lua local matches = t.matches -local api = t.api -local source = t.source +local api = n.api +local source = n.source local pcall_err = t.pcall_err before_each(clear) diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 12b2c43158..cf69958fd8 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -1,21 +1,23 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local clear = t.clear + +local clear = n.clear local eq = t.eq local ok = t.ok -local describe_lua_and_rpc = t.describe_lua_and_rpc(describe) -local api = t.api -local fn = t.fn -local request = t.request -local exc_exec = t.exc_exec -local exec_lua = t.exec_lua -local feed_command = t.feed_command -local insert = t.insert +local describe_lua_and_rpc = n.describe_lua_and_rpc(describe) +local api = n.api +local fn = n.fn +local request = n.request +local exc_exec = n.exc_exec +local exec_lua = n.exec_lua +local feed_command = n.feed_command +local insert = n.insert local NIL = vim.NIL -local command = t.command -local feed = t.feed +local command = n.command +local feed = n.feed local pcall_err = t.pcall_err -local assert_alive = t.assert_alive +local assert_alive = n.assert_alive describe('api/buf', function() before_each(clear) @@ -2066,7 +2068,7 @@ describe('api/buf', function() end) after_each(function() - t.rmdir(topdir .. '/Xacd') + n.rmdir(topdir .. '/Xacd') end) it('does not change cwd with non-current buffer', function() diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index 494bc4495b..e030b45396 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -1,10 +1,12 @@ -local t = require('test.functional.testutil')() -local clear = t.clear +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear = n.clear local eq, ok = t.eq, t.ok -local fn = t.fn -local api = t.api -local command, eval, next_msg = t.command, t.eval, t.next_msg -local nvim_prog = t.nvim_prog +local fn = n.fn +local api = n.api +local command, eval, next_msg = n.command, n.eval, n.next_msg +local nvim_prog = n.nvim_prog local pcall_err = t.pcall_err local sleep = vim.uv.sleep local write_file = t.write_file @@ -511,11 +513,11 @@ describe('API: buffer events:', function() -- create several new sessions, in addition to our main API local sessions = {} - local pipe = t.new_pipename() + local pipe = n.new_pipename() eval("serverstart('" .. pipe .. "')") - sessions[1] = t.connect(pipe) - sessions[2] = t.connect(pipe) - sessions[3] = t.connect(pipe) + sessions[1] = n.connect(pipe) + sessions[2] = n.connect(pipe) + sessions[3] = n.connect(pipe) local function request(sessionnr, method, ...) local status, rv = sessions[sessionnr]:request(method, ...) @@ -814,7 +816,7 @@ describe('API: buffer events:', function() clear() sleep(250) -- response - eq(true, t.request('nvim_buf_attach', 0, false, {})) + eq(true, n.request('nvim_buf_attach', 0, false, {})) -- notification eq({ [1] = 'notification', diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index 6c51fac178..a16c6a88e3 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -1,17 +1,18 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local NIL = vim.NIL -local clear = t.clear -local command = t.command +local clear = n.clear +local command = n.command local eq = t.eq -local api = t.api +local api = n.api local matches = t.matches -local source = t.source +local source = n.source local pcall_err = t.pcall_err -local exec_lua = t.exec_lua -local assert_alive = t.assert_alive -local feed = t.feed -local fn = t.fn +local exec_lua = n.exec_lua +local assert_alive = n.assert_alive +local feed = n.feed +local fn = n.fn describe('nvim_get_commands', function() local cmd_dict = { diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 82e7ad3988..70bdb050e5 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1,20 +1,21 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local request = t.request +local request = n.request local eq = t.eq local ok = t.ok local pcall_err = t.pcall_err -local insert = t.insert -local feed = t.feed -local clear = t.clear -local command = t.command -local exec = t.exec -local api = t.api -local assert_alive = t.assert_alive +local insert = n.insert +local feed = n.feed +local clear = n.clear +local command = n.command +local exec = n.exec +local api = n.api +local assert_alive = n.assert_alive local function expect(contents) - return eq(contents, t.curbuf_contents()) + return eq(contents, n.curbuf_contents()) end local function set_extmark(ns_id, id, line, col, opts) diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 50e79f8860..dd0611f184 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -1,14 +1,16 @@ -local t = require('test.functional.testutil')() -local clear = t.clear +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local eq, eval = t.eq, t.eval -local command = t.command -local exec_capture = t.exec_capture -local api = t.api -local fn = t.fn + +local clear = n.clear +local eq, eval = t.eq, n.eval +local command = n.command +local exec_capture = n.exec_capture +local api = n.api +local fn = n.fn local pcall_err = t.pcall_err local ok = t.ok -local assert_alive = t.assert_alive +local assert_alive = n.assert_alive describe('API: highlight', function() clear() diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index f0ed04e88e..995711507f 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -1,15 +1,16 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local clear = t.clear -local command = t.command +local clear = n.clear +local command = n.command local eq, neq = t.eq, t.neq -local exec_lua = t.exec_lua -local exec = t.exec -local feed = t.feed -local fn = t.fn -local api = t.api +local exec_lua = n.exec_lua +local exec = n.exec +local feed = n.feed +local fn = n.fn +local api = n.api local matches = t.matches -local source = t.source +local source = n.source local pcall_err = t.pcall_err local shallowcopy = t.shallowcopy @@ -1146,7 +1147,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() feed('asdf\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', t.exec_capture('nmap asdf')) + eq('\nNo mapping found', n.exec_capture('nmap asdf')) end) it('no double-free when unmapping simplifiable lua mappings', function() @@ -1170,13 +1171,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() feed('\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', t.exec_capture('nmap ')) + eq('\nNo mapping found', n.exec_capture('nmap ')) end) it('can set descriptions on mappings', function() api.nvim_set_keymap('n', 'lhs', 'rhs', { desc = 'map description' }) eq(generate_mapargs('n', 'lhs', 'rhs', { desc = 'map description' }), get_mapargs('n', 'lhs')) - eq('\nn lhs rhs\n map description', t.exec_capture('nmap lhs')) + eq('\nn lhs rhs\n map description', n.exec_capture('nmap lhs')) end) it('can define !-mode abbreviations with lua callbacks', function() @@ -1331,7 +1332,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() it('does not crash when setting mapping in a non-existing buffer #13541', function() pcall_err(api.nvim_buf_set_keymap, 100, '', 'lsh', 'irhs', {}) - t.assert_alive() + n.assert_alive() end) it('can make lua mappings', function() @@ -1426,7 +1427,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() feed('asdf\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', t.exec_capture('nmap asdf')) + eq('\nNo mapping found', n.exec_capture('nmap asdf')) end) it('no double-free when unmapping simplifiable lua mappings', function() @@ -1450,6 +1451,6 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() feed('\n') eq(1, exec_lua [[return GlobalCount]]) - eq('\nNo mapping found', t.exec_capture('nmap ')) + eq('\nNo mapping found', n.exec_capture('nmap ')) end) end) diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 2e6fdd6551..76eef164c9 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -1,9 +1,9 @@ -local t = require('test.functional.testutil')() +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local clear = t.clear -local command = t.command -local feed = t.feed +local clear = n.clear +local command = n.command +local feed = n.feed describe('update_menu notification', function() local screen diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 1b090aa30d..d2dd655b17 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -1,11 +1,12 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local clear = t.clear +local clear = n.clear local eq = t.eq -local fn = t.fn +local fn = n.fn local neq = t.neq -local nvim_argv = t.nvim_argv -local request = t.request +local nvim_argv = n.nvim_argv +local request = n.request local retry = t.retry local NIL = vim.NIL local is_os = t.is_os diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index fd7e596016..b8efbfbd0e 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,11 +1,13 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + local assert_log = t.assert_log -local eq, clear, eval, command, next_msg = t.eq, t.clear, t.eval, t.command, t.next_msg -local api = t.api -local exec_lua = t.exec_lua +local eq, clear, eval, command, next_msg = t.eq, n.clear, n.eval, n.command, n.next_msg +local api = n.api +local exec_lua = n.exec_lua local retry = t.retry -local assert_alive = t.assert_alive -local check_close = t.check_close +local assert_alive = n.assert_alive +local check_close = n.check_close local testlog = 'Xtest-server-notify-log' diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 5385b23ec1..bdd340f6c6 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -1,17 +1,18 @@ -- Test server -> client RPC scenarios. Note: unlike `rpcnotify`, to evaluate -- `rpcrequest` calls we need the client event loop to be running. -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() -local clear, eval = t.clear, t.eval -local eq, neq, run, stop = t.eq, t.neq, t.run, t.stop -local nvim_prog, command, fn = t.nvim_prog, t.command, t.fn -local source, next_msg = t.source, t.next_msg +local clear, eval = n.clear, n.eval +local eq, neq, run, stop = t.eq, t.neq, n.run, n.stop +local nvim_prog, command, fn = n.nvim_prog, n.command, n.fn +local source, next_msg = n.source, n.next_msg local ok = t.ok -local api = t.api -local spawn, merge_args = t.spawn, t.merge_args -local set_session = t.set_session +local api = n.api +local spawn, merge_args = n.spawn, n.merge_args +local set_session = n.set_session local pcall_err = t.pcall_err -local assert_alive = t.assert_alive +local assert_alive = n.assert_alive describe('server -> client', function() local cid @@ -91,19 +92,19 @@ describe('server -> client', function() local function on_request(method, args) eq('rcall', method) - local n = unpack(args) * 2 - if n <= 16 then + local _n = unpack(args) * 2 + if _n <= 16 then local cmd - if n == 4 then - cmd = 'let g:result2 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')' - elseif n == 8 then - cmd = 'let g:result3 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')' - elseif n == 16 then - cmd = 'let g:result4 = rpcrequest(' .. cid .. ', "rcall", ' .. n .. ')' + if _n == 4 then + cmd = 'let g:result2 = rpcrequest(' .. cid .. ', "rcall", ' .. _n .. ')' + elseif _n == 8 then + cmd = 'let g:result3 = rpcrequest(' .. cid .. ', "rcall", ' .. _n .. ')' + elseif _n == 16 then + cmd = 'let g:result4 = rpcrequest(' .. cid .. ', "rcall", ' .. _n .. ')' end command(cmd) end - return n + return _n end run(on_request, nil, on_setup) end) @@ -280,7 +281,7 @@ describe('server -> client', function() end) describe('connecting to another (peer) nvim', function() - local nvim_argv = merge_args(t.nvim_argv, { '--headless' }) + local nvim_argv = merge_args(n.nvim_argv, { '--headless' }) local function connect_test(server, mode, address) local serverpid = fn.getpid() local client = spawn(nvim_argv, false, nil, true) diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index 328e3aa653..74858475c8 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -1,13 +1,15 @@ -local t = require('test.functional.testutil')() -local clear, eq, ok = t.clear, t.eq, t.ok -local exec = t.exec -local feed = t.feed -local api = t.api -local fn = t.fn -local request = t.request +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear, eq, ok = n.clear, t.eq, t.ok +local exec = n.exec +local feed = n.feed +local api = n.api +local fn = n.fn +local request = n.request local NIL = vim.NIL local pcall_err = t.pcall_err -local command = t.command +local command = n.command describe('api/tabpage', function() before_each(clear) diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 36fa71f2ec..2145db7f8a 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -1,13 +1,15 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') -local clear = t.clear -local command = t.command + +local clear = n.clear +local command = n.command local eq = t.eq -local eval = t.eval -local exec = t.exec -local feed = t.feed -local api = t.api -local request = t.request +local eval = n.eval +local exec = n.exec +local feed = n.feed +local api = n.api +local request = n.request local pcall_err = t.pcall_err describe('nvim_ui_attach()', function() diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua index b57f67369e..5dad9978b7 100644 --- a/test/functional/api/version_spec.lua +++ b/test/functional/api/version_spec.lua @@ -1,6 +1,8 @@ -local t = require('test.functional.testutil')() -local clear, fn, eq = t.clear, t.fn, t.eq -local api = t.api +local t = require('test.testutil') +local n = require('test.functional.testnvim')() + +local clear, fn, eq = n.clear, n.fn, t.eq +local api = n.api local function read_mpack_file(fname) local fd = io.open(fname, 'rb') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c412773482..2d3871a37d 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,36 +1,37 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') local uv = vim.uv local fmt = string.format local dedent = t.dedent -local assert_alive = t.assert_alive +local assert_alive = n.assert_alive local NIL = vim.NIL -local clear, eq, neq = t.clear, t.eq, t.neq -local command = t.command -local command_output = t.api.nvim_command_output -local exec = t.exec -local exec_capture = t.exec_capture -local eval = t.eval -local expect = t.expect -local fn = t.fn -local api = t.api +local clear, eq, neq = n.clear, t.eq, t.neq +local command = n.command +local command_output = n.api.nvim_command_output +local exec = n.exec +local exec_capture = n.exec_capture +local eval = n.eval +local expect = n.expect +local fn = n.fn +local api = n.api local matches = t.matches local pesc = vim.pesc -local mkdir_p = t.mkdir_p -local ok, nvim_async, feed = t.ok, t.nvim_async, t.feed -local async_meths = t.async_meths +local mkdir_p = n.mkdir_p +local ok, nvim_async, feed = t.ok, n.nvim_async, n.feed +local async_meths = n.async_meths local is_os = t.is_os -local parse_context = t.parse_context -local request = t.request -local rmdir = t.rmdir -local source = t.source -local next_msg = t.next_msg +local parse_context = n.parse_context +local request = n.request +local rmdir = n.rmdir +local source = n.source +local next_msg = n.next_msg local tmpname = t.tmpname local write_file = t.write_file -local exec_lua = t.exec_lua -local exc_exec = t.exc_exec -local insert = t.insert +local exec_lua = n.exec_lua +local exc_exec = n.exc_exec +local insert = n.insert local skip = t.skip local pcall_err = t.pcall_err @@ -722,12 +723,12 @@ describe('API', function() end) after_each(function() - t.rmdir('Xtestdir') + n.rmdir('Xtestdir') end) it('works', function() api.nvim_set_current_dir('Xtestdir') - eq(start_dir .. t.get_pathsep() .. 'Xtestdir', fn.getcwd()) + eq(start_dir .. n.get_pathsep() .. 'Xtestdir', fn.getcwd()) end) it('sets previous directory', function() @@ -1487,7 +1488,7 @@ describe('API', function() eq(NIL, api.nvim_get_var('Unknown_script_func')) -- Check if autoload works properly - local pathsep = t.get_pathsep() + local pathsep = n.get_pathsep() local xconfig = 'Xhome' .. pathsep .. 'Xconfig' local xdata = 'Xhome' .. pathsep .. 'Xdata' local autoload_folder = table.concat({ xconfig, 'nvim', 'autoload' }, pathsep) @@ -1971,7 +1972,7 @@ describe('API', function() describe('RPC (K_EVENT)', function() it('does not complete ("interrupt") normal-mode operator-pending #6166', function() - t.insert([[ + n.insert([[ FIRST LINE SECOND LINE]]) api.nvim_input('gg') @@ -2008,7 +2009,7 @@ describe('API', function() it('does not complete ("interrupt") normal-mode map-pending #6166', function() command("nnoremap dd :let g:foo='it worked...'") - t.insert([[ + n.insert([[ FIRST LINE SECOND LINE]]) api.nvim_input('gg') @@ -2020,13 +2021,13 @@ describe('API', function() expect([[ FIRST LINE SECOND LINE]]) - eq('it worked...', t.eval('g:foo')) + eq('it worked...', n.eval('g:foo')) end) it('does not complete ("interrupt") insert-mode map-pending #6166', function() command('inoremap xx foo') command('set timeoutlen=9999') - t.insert([[ + n.insert([[ FIRST LINE SECOND LINE]]) api.nvim_input('ix') @@ -2173,32 +2174,32 @@ describe('API', function() describe('nvim_replace_termcodes', function() it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function() - eq('\128\254X', t.api.nvim_replace_termcodes('\128', true, true, true)) + eq('\128\254X', n.api.nvim_replace_termcodes('\128', true, true, true)) end) it('leaves non-K_SPECIAL string unchanged', function() - eq('abc', t.api.nvim_replace_termcodes('abc', true, true, true)) + eq('abc', n.api.nvim_replace_termcodes('abc', true, true, true)) end) it('converts ', function() - eq('\\', t.api.nvim_replace_termcodes('', true, true, true)) + eq('\\', n.api.nvim_replace_termcodes('', true, true, true)) end) it('converts to K_SPECIAL KS_EXTRA KE_LEFTMOUSE', function() -- K_SPECIAL KS_EXTRA KE_LEFTMOUSE -- 0x80 0xfd 0x2c -- 128 253 44 - eq('\128\253\44', t.api.nvim_replace_termcodes('', true, true, true)) + eq('\128\253\44', n.api.nvim_replace_termcodes('', true, true, true)) end) it('converts keycodes', function() - eq('\nx\27x\rxxxxx', true, true, true)) + eq('\nx\27x\rxxxxx', true, true, true)) end) it('does not convert keycodes if special=false', function() eq( 'xxxx', - t.api.nvim_replace_termcodes('xxxx', true, true, false) + n.api.nvim_replace_termcodes('xxxx', true, true, false) ) end) @@ -2227,18 +2228,18 @@ describe('API', function() api.nvim_feedkeys(':let x1="…"\n', '', true) -- Both nvim_replace_termcodes and nvim_feedkeys escape \x80 - local inp = t.api.nvim_replace_termcodes(':let x2="…"', true, true, true) + local inp = n.api.nvim_replace_termcodes(':let x2="…"', true, true, true) api.nvim_feedkeys(inp, '', true) -- escape_ks=true -- nvim_feedkeys with K_SPECIAL escaping disabled - inp = t.api.nvim_replace_termcodes(':let x3="…"', true, true, true) + inp = n.api.nvim_replace_termcodes(':let x3="…"', true, true, true) api.nvim_feedkeys(inp, '', false) -- escape_ks=false - t.stop() + n.stop() end -- spin the loop a bit - t.run(nil, nil, on_setup) + n.run(nil, nil, on_setup) eq('…', api.nvim_get_var('x1')) -- Because of the double escaping this is neq @@ -2381,7 +2382,7 @@ describe('API', function() {0:~ }|*6 {1:very fail} | ]]) - t.poke_eventloop() + n.poke_eventloop() -- shows up to &cmdheight lines async_meths.nvim_err_write('more fail\ntoo fail\n') @@ -2693,7 +2694,7 @@ describe('API', function() describe('nvim_list_runtime_paths', function() setup(function() - local pathsep = t.get_pathsep() + local pathsep = n.get_pathsep() mkdir_p('Xtest' .. pathsep .. 'a') mkdir_p('Xtest' .. pathsep .. 'b') end) @@ -3200,7 +3201,7 @@ describe('API', function() end) describe('nvim_get_runtime_file', function() - local p = t.alter_slashes + local p = n.alter_slashes it('can find files', function() eq({}, api.nvim_get_runtime_file('bork.borkbork', false)) eq({}, api.nvim_get_runtime_file('bork.borkbork', true)) diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 36966b68f5..636338cb2e 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1,27 +1,29 @@ -local t = require('test.functional.testutil')() +local t = require('test.testutil') +local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') + local clear, curbuf, curbuf_contents, curwin, eq, neq, matches, ok, feed, insert, eval = - t.clear, - t.api.nvim_get_current_buf, - t.curbuf_contents, - t.api.nvim_get_current_win, + n.clear, + n.api.nvim_get_current_buf, + n.curbuf_contents, + n.api.nvim_get_current_win, t.eq, t.neq, t.matches, t.ok, - t.feed, - t.insert, - t.eval -local poke_eventloop = t.poke_eventloop -local exec = t.exec -local exec_lua = t.exec_lua -local fn = t.fn -local request = t.request + n.feed, + n.insert, + n.eval +local poke_eventloop = n.poke_eventloop +local exec = n.exec +local exec_lua = n.exec_lua +local fn = n.fn +local request = n.request local NIL = vim.NIL -local api = t.api -local command = t.command +local api = n.api +local command = n.command local pcall_err = t.pcall_err -local assert_alive = t.assert_alive +local assert_alive = n.assert_alive describe('API/win', function() before_each(clear) @@ -136,7 +138,7 @@ describe('API/win', function() end) after_each(function() - t.rmdir(topdir .. '/Xacd') + n.rmdir(topdir .. '/Xacd') end) it('does not change cwd with non-current window', function() @@ -1370,7 +1372,7 @@ describe('API/win', function() local tab1 = api.nvim_get_current_tabpage() local tab1_win = api.nvim_get_current_win() - t.command('tabnew') + n.command('tabnew') local tab2 = api.nvim_get_current_tabpage() local tab2_win = api.nvim_get_current_win() @@ -1790,7 +1792,7 @@ describe('API/win', function() end) after_each(function() - t.rmdir(topdir .. '/Xacd') + n.rmdir(topdir .. '/Xacd') end) it('does not change cwd with enter=false #15280', function() -- cgit From 16513b30337523dc64707309ee7fe3dd2247266d Mon Sep 17 00:00:00 2001 From: Will Hopkins Date: Wed, 24 Apr 2024 18:14:05 -0700 Subject: feat(api): allow floats to be opened in non-current tabpage (#28480) \ --- test/functional/api/window_spec.lua | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 636338cb2e..15b9b0945c 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -1454,6 +1454,40 @@ describe('API/win', function() }, layout) end) + it('opens floating windows in other tabpages', function() + local first_win = api.nvim_get_current_win() + local first_tab = api.nvim_get_current_tabpage() + + command('tabnew') + local new_tab = api.nvim_get_current_tabpage() + local win = api.nvim_open_win(0, false, { + relative = 'win', + win = first_win, + width = 5, + height = 5, + row = 1, + col = 1, + }) + eq(api.nvim_win_get_tabpage(win), first_tab) + eq(api.nvim_get_current_tabpage(), new_tab) + end) + + it('switches to new windows in non-current tabpages when enter=true', function() + local first_win = api.nvim_get_current_win() + local first_tab = api.nvim_get_current_tabpage() + command('tabnew') + local win = api.nvim_open_win(0, true, { + relative = 'win', + win = first_win, + width = 5, + height = 5, + row = 1, + col = 1, + }) + eq(api.nvim_win_get_tabpage(win), first_tab) + eq(api.nvim_get_current_tabpage(), first_tab) + end) + local function setup_tabbed_autocmd_test() local info = {} info.orig_buf = api.nvim_get_current_buf() -- cgit From 037ea6e786b5d05f4a8965e4c2ba6aa60ec7c01a Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Wed, 10 Apr 2024 11:42:46 +0200 Subject: feat(api): add nvim__redraw for more granular redrawing Experimental and subject to future changes. Add a way to redraw certain elements that are not redrawn while Nvim is waiting for input, or currently have no API to do so. This API covers all that can be done with the :redraw* commands, in addition to the following new features: - Immediately move the cursor to a (non-current) window. - Target a specific window or buffer to mark for redraw. - Mark a buffer range for redraw (replaces nvim__buf_redraw_range()). - Redraw the 'statuscolumn'. --- test/functional/api/vim_spec.lua | 212 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2d3871a37d..fbb6d42633 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -5016,4 +5016,216 @@ describe('API', function() eq(false, exec_lua('return _G.success')) end) end) + + it('nvim__redraw', function() + local screen = Screen.new(60, 5) + screen:attach() + local win = api.nvim_get_current_win() + eq('at least one action required', pcall_err(api.nvim__redraw, {})) + eq('at least one action required', pcall_err(api.nvim__redraw, { buf = 0 })) + eq('at least one action required', pcall_err(api.nvim__redraw, { win = 0 })) + eq("cannot use both 'buf' and 'win'", pcall_err(api.nvim__redraw, { buf = 0, win = 0 })) + feed(':echo getchar()') + fn.setline(1, 'foobar') + command('vnew') + fn.setline(1, 'foobaz') + -- Can flush pending screen updates + api.nvim__redraw({ flush = true }) + screen:expect({ + grid = [[ + foobaz │foobar | + {1:~ }│{1:~ }|*2 + {3:[No Name] [+] }{2:[No Name] [+] }| + ^:echo getchar() | + ]], + }) + -- Can update the grid cursor position #20793 + api.nvim__redraw({ cursor = true }) + screen:expect({ + grid = [[ + ^foobaz │foobar | + {1:~ }│{1:~ }|*2 + {3:[No Name] [+] }{2:[No Name] [+] }| + :echo getchar() | + ]], + }) + -- Also in non-current window + api.nvim__redraw({ cursor = true, win = win }) + screen:expect({ + grid = [[ + foobaz │^foobar | + {1:~ }│{1:~ }|*2 + {3:[No Name] [+] }{2:[No Name] [+] }| + :echo getchar() | + ]], + }) + -- Can update the 'statusline' in a single window + api.nvim_set_option_value('statusline', 'statusline1', { win = 0 }) + api.nvim_set_option_value('statusline', 'statusline2', { win = win }) + api.nvim__redraw({ cursor = true, win = 0, statusline = true }) + screen:expect({ + grid = [[ + ^foobaz │foobar | + {1:~ }│{1:~ }|*2 + {3:statusline1 }{2:[No Name] [+] }| + :echo getchar() | + ]], + }) + api.nvim__redraw({ win = win, statusline = true }) + screen:expect({ + grid = [[ + ^foobaz │foobar | + {1:~ }│{1:~ }|*2 + {3:statusline1 }{2:statusline2 }| + :echo getchar() | + ]], + }) + -- Can update the 'statusline' in all windows + api.nvim_set_option_value('statusline', '', { win = win }) + api.nvim_set_option_value('statusline', 'statusline3', {}) + api.nvim__redraw({ statusline = true }) + screen:expect({ + grid = [[ + ^foobaz │foobar | + {1:~ }│{1:~ }|*2 + {3:statusline3 }{2:statusline3 }| + :echo getchar() | + ]], + }) + -- Can update the 'statuscolumn' + api.nvim_set_option_value('statuscolumn', 'statuscolumn', { win = win }) + api.nvim__redraw({ statuscolumn = true }) + screen:expect({ + grid = [[ + ^foobaz │{8:statuscolumn}foobar | + {1:~ }│{1:~ }|*2 + {3:statusline3 }{2:statusline3 }| + :echo getchar() | + ]], + }) + -- Can update the 'winbar' + api.nvim_set_option_value('winbar', 'winbar', { win = 0 }) + api.nvim__redraw({ win = 0, winbar = true }) + screen:expect({ + grid = [[ + {5:^winbar }│{8:statuscolumn}foobar | + foobaz │{1:~ }| + {1:~ }│{1:~ }| + {3:statusline3 }{2:statusline3 }| + :echo getchar() | + ]], + }) + -- Can update the 'tabline' + api.nvim_set_option_value('showtabline', 2, {}) + api.nvim_set_option_value('tabline', 'tabline', {}) + api.nvim__redraw({ tabline = true }) + screen:expect({ + grid = [[ + {2:^tabline }| + {5:winbar }│{8:statuscolumn}foobar | + foobaz │{1:~ }| + {3:statusline3 }{2:statusline3 }| + :echo getchar() | + ]], + }) + -- Can update multiple status widgets + api.nvim_set_option_value('tabline', 'tabline2', {}) + api.nvim_set_option_value('statusline', 'statusline4', {}) + api.nvim__redraw({ statusline = true, tabline = true }) + screen:expect({ + grid = [[ + {2:^tabline2 }| + {5:winbar }│{8:statuscolumn}foobar | + foobaz │{1:~ }| + {3:statusline4 }{2:statusline4 }| + :echo getchar() | + ]], + }) + -- Can update all status widgets + api.nvim_set_option_value('tabline', 'tabline3', {}) + api.nvim_set_option_value('statusline', 'statusline5', {}) + api.nvim_set_option_value('statuscolumn', 'statuscolumn2', {}) + api.nvim_set_option_value('winbar', 'winbar2', {}) + api.nvim__redraw({ statuscolumn = true, statusline = true, tabline = true, winbar = true }) + screen:expect({ + grid = [[ + {2:^tabline3 }| + {5:winbar2 }│{5:winbar2 }| + {8:statuscolumn2}foobaz │{8:statuscolumn}foobar | + {3:statusline5 }{2:statusline5 }| + :echo getchar() | + ]], + }) + -- Can update status widget for a specific window + feed('') + command('let g:status=0') + api.nvim_set_option_value('statusline', '%{%g:status%}', { win = 0 }) + command('vsplit') + screen:expect({ + grid = [[ + {2:tabline3 }| + {5:winbar2 }│{5:winbar2 }│{5:winbar2 }| + {8:statuscolumn2}^foobaz │{8:statuscolumn2}foobaz│{8:statuscolumn}foobar | + {3:0 }{2:0 statusline5 }| + 13 | + ]], + }) + command('let g:status=1') + api.nvim__redraw({ win = 0, statusline = true }) + screen:expect({ + grid = [[ + {2:tabline3 }| + {5:winbar2 }│{5:winbar2 }│{5:winbar2 }| + {8:statuscolumn2}^foobaz │{8:statuscolumn2}foobaz│{8:statuscolumn}foobar | + {3:1 }{2:0 statusline5 }| + 13 | + ]], + }) + -- Can update status widget for a specific buffer + command('let g:status=2') + api.nvim__redraw({ buf = 0, statusline = true }) + screen:expect({ + grid = [[ + {2:tabline3 }| + {5:winbar2 }│{5:winbar2 }│{5:winbar2 }| + {8:statuscolumn2}^foobaz │{8:statuscolumn2}foobaz│{8:statuscolumn}foobar | + {3:2 }{2:2 statusline5 }| + 13 | + ]], + }) + -- valid = true does not draw any lines on its own + exec_lua([[ + lines = 0 + ns = vim.api.nvim_create_namespace('') + on_win = function() + if do_win then + vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'IncSearch', end_col = 6 }) + end + end + vim.api.nvim_set_decoration_provider(ns, { + on_win = on_win, + on_line = function() + lines = lines + 1 + end, + }) + ]]) + local lines = exec_lua('return lines') + api.nvim__redraw({ buf = 0, valid = true, flush = true }) + eq(lines, exec_lua('return lines')) + -- valid = false does + api.nvim__redraw({ buf = 0, valid = false, flush = true }) + neq(lines, exec_lua('return lines')) + -- valid = true does redraw lines if affected by on_win callback + exec_lua('do_win = true') + api.nvim__redraw({ buf = 0, valid = true, flush = true }) + screen:expect({ + grid = [[ + {2:tabline3 }| + {5:winbar2 }│{5:winbar2 }│{5:winbar2 }| + {8:statuscolumn2}{2:^foobaz} │{8:statuscolumn2}{2:foobaz}│{8:statuscolumn}foobar | + {3:2 }{2:2 statusline5 }| + 13 | + ]], + }) + end) end) -- cgit From cf9f002f31c8b4d9d42912a3f45f5d3db4462fd9 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Fri, 3 May 2024 04:35:32 +0200 Subject: fix(api): use correct buffer for "range" in nvim__redraw (#28614) --- test/functional/api/vim_spec.lua | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fbb6d42633..c56c8263d6 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -5195,28 +5195,27 @@ describe('API', function() }) -- valid = true does not draw any lines on its own exec_lua([[ - lines = 0 + _G.lines = 0 ns = vim.api.nvim_create_namespace('') - on_win = function() - if do_win then - vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'IncSearch', end_col = 6 }) - end - end vim.api.nvim_set_decoration_provider(ns, { - on_win = on_win, + on_win = function() + if _G.do_win then + vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { hl_group = 'IncSearch', end_col = 6 }) + end + end, on_line = function() - lines = lines + 1 + _G.lines = _G.lines + 1 end, }) ]]) local lines = exec_lua('return lines') api.nvim__redraw({ buf = 0, valid = true, flush = true }) - eq(lines, exec_lua('return lines')) + eq(lines, exec_lua('return _G.lines')) -- valid = false does api.nvim__redraw({ buf = 0, valid = false, flush = true }) - neq(lines, exec_lua('return lines')) + neq(lines, exec_lua('return _G.lines')) -- valid = true does redraw lines if affected by on_win callback - exec_lua('do_win = true') + exec_lua('_G.do_win = true') api.nvim__redraw({ buf = 0, valid = true, flush = true }) screen:expect({ grid = [[ @@ -5227,5 +5226,8 @@ describe('API', function() 13 | ]], }) + -- takes buffer line count from correct buffer with "win" and {0, -1} "range" + api.nvim__redraw({ win = 0, range = { 0, -1 } }) + n.assert_alive() end) end) -- cgit From d44ed3a885e163df33cce8180ca9f72fb5c0661a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 3 May 2024 18:02:25 +0800 Subject: perf(extmarks): better track whether namespace has extmarks (#28615) This avoids redraw when adding/removing an empty namespace for a window. This also avoids marktree traversal when clearing a namespace that has already been cleared, which is added as a benchmark. --- test/functional/api/extmark_spec.lua | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'test/functional/api') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 70bdb050e5..965a60417a 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1896,6 +1896,24 @@ describe('Extmarks buffer api with many marks', function() end eq(ns_marks[ns1], get_marks(ns1)) eq(ns_marks[ns2], get_marks(ns2)) + + api.nvim_buf_clear_namespace(0, ns1, 0, 10) + for id, mark in pairs(ns_marks[ns1]) do + if mark[1] < 10 then + ns_marks[ns1][id] = nil + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) + + api.nvim_buf_clear_namespace(0, ns1, 20, -1) + for id, mark in pairs(ns_marks[ns1]) do + if mark[1] >= 20 then + ns_marks[ns1][id] = nil + end + end + eq(ns_marks[ns1], get_marks(ns1)) + eq(ns_marks[ns2], get_marks(ns2)) end) it('can delete line', function() -- cgit From 4e5c633ed4871a948aff7338b793ac5f93484153 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 12 May 2024 05:39:33 +0800 Subject: fix(api): make getting explicit empty hl in virtual text work (#28697) --- test/functional/api/extmark_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 965a60417a..5ab3e09bf8 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1569,7 +1569,7 @@ describe('API/extmarks', function() sign_text = '>>', spell = true, virt_lines = { - { { 'lines', 'Macro' }, { '???' } }, + { { 'lines', 'Macro' }, { '???' }, { ';;;', '' } }, { { 'stack', { 'Type', 'Search' } }, { '!!!' } }, }, virt_lines_above = true, @@ -1604,7 +1604,7 @@ describe('API/extmarks', function() sign_text = '>>', spell = true, virt_lines = { - { { 'lines', 'Macro' }, { '???' } }, + { { 'lines', 'Macro' }, { '???' }, { ';;;', '' } }, { { 'stack', { 'Type', 'Search' } }, { '!!!' } }, }, virt_lines_above = true, -- cgit From aec4938a21a02d279d13a9eb64ef3b7cc592c374 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 17 May 2024 07:37:39 -0700 Subject: feat(api): broadcast events to ALL channels #28487 Problem: `vim.rpcnotify(0)` and `rpcnotify(0)` are documented as follows: If {channel} is 0, the event is broadcast to all channels. But that's not actually true. Channels must call `nvim_subscribe` to receive "broadcast" events, so it's actually "multicast". - Assuming there is a use-case for "broadcast", the current model adds an extra step for broadcasting: all channels need to "subscribe". - The presence of `nvim_subscribe` is a source of confusion for users, because its name implies something more generally useful than what it does. Presumably the use-case of `nvim_subscribe` is to avoid "noise" on RPC channels not expected a broadcast notification, and potentially an error if the channel client reports an unknown event. Solution: - Deprecate `nvim_subscribe`/`nvim_unsubscribe`. - If applications want to multicast, they can keep their own multicast list. Or they can use `nvim_list_chans()` and `nvim_get_chan_info()` to enumerate and filter the clients they want to target. - Always send "broadcast" events to ALL channels. Don't require channels to "subscribe" to receive broadcasts. This matches the documented behavior of `rpcnotify()`. --- test/functional/api/server_notifications_spec.lua | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index b8efbfbd0e..7b4c4e8312 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,7 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local assert_log = t.assert_log local eq, clear, eval, command, next_msg = t.eq, n.clear, n.eval, n.command, n.next_msg local api = n.api local exec_lua = n.exec_lua @@ -34,18 +33,18 @@ describe('notify', function() end) end) - describe('passing 0 as the channel id', function() - it('sends the notification/args to all subscribed channels', function() - api.nvim_subscribe('event2') + describe('channel id 0', function() + it('broadcasts the notification/args to all channels', function() eval('rpcnotify(0, "event1", 1, 2, 3)') eval('rpcnotify(0, "event2", 4, 5, 6)') eval('rpcnotify(0, "event2", 7, 8, 9)') + eq({ 'notification', 'event1', { 1, 2, 3 } }, next_msg()) eq({ 'notification', 'event2', { 4, 5, 6 } }, next_msg()) eq({ 'notification', 'event2', { 7, 8, 9 } }, next_msg()) - api.nvim_unsubscribe('event2') - api.nvim_subscribe('event1') + eval('rpcnotify(0, "event2", 10, 11, 12)') eval('rpcnotify(0, "event1", 13, 14, 15)') + eq({ 'notification', 'event2', { 10, 11, 12 } }, next_msg()) eq({ 'notification', 'event1', { 13, 14, 15 } }, next_msg()) end) @@ -78,17 +77,6 @@ describe('notify', function() end) end) - it('unsubscribe non-existing event #8745', function() - clear { env = { - NVIM_LOG_FILE = testlog, - } } - api.nvim_subscribe('event1') - api.nvim_unsubscribe('doesnotexist') - assert_log("tried to unsubscribe unknown event 'doesnotexist'", testlog, 10) - api.nvim_unsubscribe('event1') - assert_alive() - end) - it('cancels stale events on channel close', function() local catchan = eval("jobstart(['cat'], {'rpc': v:true})") local catpath = eval('exepath("cat")') @@ -97,7 +85,6 @@ describe('notify', function() exec_lua( [[ vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'}) - vim.rpcnotify(..., "nvim_subscribe", "daily_rant") return vim.api.nvim_get_chan_info(...) ]], catchan -- cgit From ad191be65e2b1641c181506166b1037b548d14a8 Mon Sep 17 00:00:00 2001 From: Tobias Schmitz Date: Tue, 21 May 2024 18:21:42 +0200 Subject: feat(signs)!: place higher-priority signs from the left #27781 Problem: Higher-priority signs may be hidden by lower-priority signs. Solution: Place higher-priority signs from the left. Example: nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='H', priority=1}) nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='W', priority=2}) nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='E', priority=3}) Before: | | H | W E | ^ | | Not visible After: | | | E W | H | | ^ Not visible Fixes #16632 --- test/functional/api/extmark_spec.lua | 2 +- test/functional/api/vim_spec.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'test/functional/api') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 5ab3e09bf8..7b2fe209ba 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1743,7 +1743,7 @@ describe('API/extmarks', function() command('silent undo') screen:expect([[ S1{7: }^aaa bbb ccc | - S1S2aaa bbb ccc | + S2S1aaa bbb ccc | S2{7: }aaa bbb ccc | {7: }aaa bbb ccc |*2 | diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c56c8263d6..fd0535aa51 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3918,13 +3918,13 @@ describe('API', function() norm 4G ]]) eq({ - str = '││aabb 4 ', + str = '││bbaa 4 ', width = 9, highlights = { { group = 'CursorLineFold', start = 0 }, { group = 'Normal', start = 6 }, - { group = 'IncSearch', start = 6 }, - { group = 'ErrorMsg', start = 8 }, + { group = 'ErrorMsg', start = 6 }, + { group = 'IncSearch', start = 8 }, { group = 'Normal', start = 10 }, }, }, api.nvim_eval_statusline( -- cgit