From 97b064c9ac84bdaac65a4c4db81d11daa8f02719 Mon Sep 17 00:00:00 2001 From: Sean Dewar <6256228+seandewar@users.noreply.github.com> Date: Mon, 16 Mar 2026 13:15:33 +0000 Subject: [PATCH] fix(api): nvim_open_tabpage positional "enter" Problem: nvim_open_tabpage's "enter" argument is optional, which is inconsistent with nvim_open_win. Solution: make it a (non-optional) positional argument, like nvim_open_win. Also change "enter"'s description to be more like nvim_open_win's doc. --- runtime/doc/api.txt | 4 +- runtime/lua/vim/_meta/api.lua | 4 +- runtime/lua/vim/_meta/api_keysets.lua | 1 - src/nvim/api/keysets_defs.h | 1 - src/nvim/api/tabpage.c | 9 +--- test/functional/api/tabpage_spec.lua | 78 +++++++++++---------------- 6 files changed, 36 insertions(+), 61 deletions(-) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 7c6b0e06a0..c094ef9b45 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -3544,7 +3544,7 @@ nvim_set_option_value({name}, {value}, {opts}) ============================================================================== Tabpage Functions *api-tabpage* -nvim_open_tabpage({buffer}, {config}) *nvim_open_tabpage()* +nvim_open_tabpage({buffer}, {enter}, {config}) *nvim_open_tabpage()* Opens a new tabpage. Attributes: ~ @@ -3554,9 +3554,9 @@ nvim_open_tabpage({buffer}, {config}) *nvim_open_tabpage()* Parameters: ~ • {buffer} (`integer`) Buffer to open in the first window of the new tabpage. Use 0 for current buffer. + • {enter} (`boolean`) Enter the tabpage (make it the current tabpage). • {config} (`vim.api.keyset.tabpage_config`) Configuration for the new tabpage. Keys: - • enter: Whether to enter the new tabpage (default: true) • after: Position to insert tabpage (default: -1; after current). 0 = first, N = after Nth. diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index b96f977c96..5c2e54f3ae 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1677,12 +1677,12 @@ function vim.api.nvim_notify(msg, log_level, opts) end --- --- @param buffer integer Buffer to open in the first window of the new tabpage. --- Use 0 for current buffer. +--- @param enter boolean Enter the tabpage (make it the current tabpage). --- @param config vim.api.keyset.tabpage_config Configuration for the new tabpage. Keys: ---- - enter: Whether to enter the new tabpage (default: true) --- - after: Position to insert tabpage (default: -1; after current). --- 0 = first, N = after Nth. --- @return integer # Tabpage handle of the created tabpage -function vim.api.nvim_open_tabpage(buffer, config) end +function vim.api.nvim_open_tabpage(buffer, enter, config) end --- Open a terminal instance in a buffer --- diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua index fb7728547f..1bbd8073c2 100644 --- a/runtime/lua/vim/_meta/api_keysets.lua +++ b/runtime/lua/vim/_meta/api_keysets.lua @@ -438,7 +438,6 @@ error('Cannot require a meta file') --- @field _subpriority? integer --- @class vim.api.keyset.tabpage_config ---- @field enter? boolean --- @field after? integer --- @class vim.api.keyset.user_command diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index 419e38a973..23859049a0 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -144,7 +144,6 @@ typedef struct { typedef struct { OptionalKeys is_set__tabpage_config_; - Boolean enter; Integer after; } Dict(tabpage_config); diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 28c701f0c5..48aa743c30 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -193,13 +193,13 @@ Boolean nvim_tabpage_is_valid(Tabpage tabpage) /// /// @param buffer Buffer to open in the first window of the new tabpage. /// Use 0 for current buffer. +/// @param enter Enter the tabpage (make it the current tabpage). /// @param config Configuration for the new tabpage. Keys: -/// - enter: Whether to enter the new tabpage (default: true) /// - after: Position to insert tabpage (default: -1; after current). /// 0 = first, N = after Nth. /// @param[out] err Error details, if any /// @return Tabpage handle of the created tabpage -Tabpage nvim_open_tabpage(Buffer buffer, Dict(tabpage_config) *config, Error *err) +Tabpage nvim_open_tabpage(Buffer buffer, Boolean enter, Dict(tabpage_config) *config, Error *err) FUNC_API_SINCE(14) FUNC_API_TEXTLOCK_ALLOW_CMDWIN { #define HAS_KEY_X(d, key) HAS_KEY(d, tabpage_config, key) @@ -207,11 +207,6 @@ Tabpage nvim_open_tabpage(Buffer buffer, Dict(tabpage_config) *config, Error *er if (buf == NULL) { return 0; } - - bool enter = true; - if (HAS_KEY_X(config, enter)) { - enter = config->enter; - } if ((cmdwin_type != 0 && enter) || buf == cmdwin_buf) { api_set_error(err, kErrorTypeException, "%s", e_cmdwin); return 0; diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua index 8d364216e5..3eecfdcc86 100644 --- a/test/functional/api/tabpage_spec.lua +++ b/test/functional/api/tabpage_spec.lua @@ -94,18 +94,18 @@ describe('api/tabpage', function() end) it('checks textlock, cmdwin restrictions', function() - command('autocmd TextYankPost * ++once call nvim_open_tabpage(0, #{enter: 0})') + command('autocmd TextYankPost * ++once call nvim_open_tabpage(0, 0, {})') matches('E565:', pcall_err(command, 'yank')) eq(1, fn.tabpagenr('$')) local other_buf = api.nvim_get_current_buf() feed('q:') -- OK when not entering and not opening a tabpage with the cmdwin's buffer. - matches('E11:', pcall_err(api.nvim_open_tabpage, 0, { enter = false })) + matches('E11:', pcall_err(api.nvim_open_tabpage, 0, false, {})) eq(1, fn.tabpagenr('$')) - matches('E11:', pcall_err(api.nvim_open_tabpage, other_buf, { enter = true })) + matches('E11:', pcall_err(api.nvim_open_tabpage, other_buf, true, {})) eq(1, fn.tabpagenr('$')) - local tp = api.nvim_open_tabpage(other_buf, { enter = false }) + local tp = api.nvim_open_tabpage(other_buf, false, {}) eq(other_buf, api.nvim_win_get_buf(api.nvim_tabpage_get_win(tp))) eq('command', fn.win_gettype()) end) @@ -198,13 +198,13 @@ describe('api/tabpage', function() local tabs = api.nvim_list_tabpages() eq(1, #tabs) local curtab = api.nvim_get_current_tabpage() - local tab = api.nvim_open_tabpage(0, { enter = false }) + local tab = api.nvim_open_tabpage(0, false, {}) local newtabs = api.nvim_list_tabpages() eq(2, #newtabs) eq(tab, newtabs[2]) eq(curtab, api.nvim_get_current_tabpage()) - local tab2 = api.nvim_open_tabpage(0, { enter = true }) + local tab2 = api.nvim_open_tabpage(0, true, {}) local newtabs2 = api.nvim_list_tabpages() eq(3, #newtabs2) eq({ @@ -233,11 +233,7 @@ describe('api/tabpage', function() tab3, }) - local new_tab = api.nvim_open_tabpage(0, { - enter = false, - after = api.nvim_tabpage_get_number(tab2), - }) - + local new_tab = api.nvim_open_tabpage(0, false, { after = api.nvim_tabpage_get_number(tab2) }) local newtabs2 = api.nvim_list_tabpages() eq(4, #newtabs2) eq({ @@ -254,7 +250,7 @@ describe('api/tabpage', function() eq(1, #api.nvim_list_tabpages()) local tab1 = api.nvim_get_current_tabpage() - local new_tab = api.nvim_open_tabpage(0, { enter = false }) + local new_tab = api.nvim_open_tabpage(0, false, {}) local newtabs = api.nvim_list_tabpages() eq(2, #newtabs) eq(newtabs, { tab1, new_tab }) @@ -267,7 +263,7 @@ describe('api/tabpage', function() | ]]) - local new_tab2 = api.nvim_open_tabpage(0, { enter = true }) + local new_tab2 = api.nvim_open_tabpage(0, true, {}) local newtabs2 = api.nvim_list_tabpages() eq(3, #newtabs2) eq(newtabs2, { tab1, new_tab2, new_tab }) @@ -280,7 +276,7 @@ describe('api/tabpage', function() | ]]) - api.nvim_open_tabpage(0, { enter = false }) + api.nvim_open_tabpage(0, false, {}) -- Tabline redrawn when not entering, and when there's already one. screen:expect([[ {24: [No Name] }{5: [No Name] }{24: [No Name] [No Name] }{2: }{24:X}| @@ -302,7 +298,7 @@ describe('api/tabpage', function() autocmd BufWinEnter * let g:events += [['BufWinEnter', nvim_get_current_tabpage(), win_getid()]] ]=]) - local new_tab = api.nvim_open_tabpage(0, { enter = true }) + local new_tab = api.nvim_open_tabpage(0, true, {}) local new_win = api.nvim_tabpage_get_win(new_tab) eq({ { 'WinNew', new_tab, new_win }, @@ -313,7 +309,7 @@ describe('api/tabpage', function() eq(new_win, api.nvim_get_current_win()) api.nvim_set_var('events', {}) - new_tab = api.nvim_open_tabpage(api.nvim_create_buf(true, true), { enter = true }) + new_tab = api.nvim_open_tabpage(api.nvim_create_buf(true, true), true, {}) new_win = api.nvim_tabpage_get_win(new_tab) eq({ { 'WinNew', new_tab, new_win }, @@ -327,7 +323,7 @@ describe('api/tabpage', function() local curwin = new_win api.nvim_set_var('events', {}) - new_tab = api.nvim_open_tabpage(0, { enter = false }) + new_tab = api.nvim_open_tabpage(0, false, {}) new_win = api.nvim_tabpage_get_win(new_tab) eq( { { 'WinNew', new_tab, new_win }, { 'TabNew', new_tab, new_win } }, @@ -336,7 +332,7 @@ describe('api/tabpage', function() eq(curwin, api.nvim_get_current_win()) api.nvim_set_var('events', {}) - new_tab = api.nvim_open_tabpage(api.nvim_create_buf(true, true), { enter = false }) + new_tab = api.nvim_open_tabpage(api.nvim_create_buf(true, true), false, {}) new_win = api.nvim_tabpage_get_win(new_tab) eq({ { 'WinNew', new_tab, new_win }, @@ -347,18 +343,18 @@ describe('api/tabpage', function() end) it('handles nasty autocmds', function() - command('autocmd WinNewPre * ++once call nvim_open_tabpage(0, #{enter: 0})') + command('autocmd WinNewPre * ++once call nvim_open_tabpage(0, 0, {})') matches('E1312:', pcall_err(command, 'split')) command('autocmd TabNew * ++once quit') - eq('Tabpage was closed immediately', pcall_err(api.nvim_open_tabpage, 0, { enter = false })) + eq('Tabpage was closed immediately', pcall_err(api.nvim_open_tabpage, 0, false, {})) command('autocmd BufEnter * ++once quit') local buf = api.nvim_create_buf(true, true) - eq('Tabpage was closed immediately', pcall_err(api.nvim_open_tabpage, buf, { enter = true })) + eq('Tabpage was closed immediately', pcall_err(api.nvim_open_tabpage, buf, true, {})) -- No error if autocmds delete target buffer, if new tabpage is still valid to return. command('autocmd BufEnter * ++once buffer # | bwipeout! #') - local new_tp = api.nvim_open_tabpage(buf, { enter = true }) + local new_tp = api.nvim_open_tabpage(buf, true, {}) eq(false, api.nvim_buf_is_valid(buf)) eq(new_tp, api.nvim_get_current_tabpage()) end) @@ -376,19 +372,19 @@ describe('api/tabpage', function() eq({ tab1, tab2, tab3 }, initial_tabs) -- Test after=0: should become first tab - local first_tab = api.nvim_open_tabpage(0, { enter = false, after = 0 }) + local first_tab = api.nvim_open_tabpage(0, false, { after = 0 }) local tabs_after_first = api.nvim_list_tabpages() eq(4, #tabs_after_first) eq({ first_tab, tab1, tab2, tab3 }, tabs_after_first) -- Test after=-1: should insert after current tab (tab3) - local explicit_after_current = api.nvim_open_tabpage(0, { enter = false, after = -1 }) + local explicit_after_current = api.nvim_open_tabpage(0, false, { after = -1 }) local tabs_after_current = api.nvim_list_tabpages() eq(5, #tabs_after_current) eq({ first_tab, tab1, tab2, tab3, explicit_after_current }, tabs_after_current) -- Test inserting before a middle tab (before tab2, which is now number 3) - local before_middle = api.nvim_open_tabpage(0, { enter = false, after = 2 }) + local before_middle = api.nvim_open_tabpage(0, false, { after = 2 }) local tabs_after_middle = api.nvim_list_tabpages() eq(6, #tabs_after_middle) eq({ first_tab, tab1, before_middle, tab2, tab3, explicit_after_current }, tabs_after_middle) @@ -396,7 +392,7 @@ describe('api/tabpage', function() eq(api.nvim_get_current_tabpage(), tab3) -- Test default behavior (after current) - local default_after_current = api.nvim_open_tabpage(0, { enter = false }) + local default_after_current = api.nvim_open_tabpage(0, false, {}) local final_tabs = api.nvim_list_tabpages() eq(7, #final_tabs) eq({ @@ -423,11 +419,7 @@ describe('api/tabpage', function() -- Test that requesting position beyond last tab still works -- (should place it at the end) - local new_tab = api.nvim_open_tabpage(0, { - enter = false, - after = 10, -- Way beyond the last tab - }) - + local new_tab = api.nvim_open_tabpage(0, false, { after = 10 }) -- Way beyond the last tab local final_tabs = api.nvim_list_tabpages() eq(4, #final_tabs) -- Should append at the end @@ -436,7 +428,7 @@ describe('api/tabpage', function() it('works with specific buffer', function() local curbuf = api.nvim_get_current_buf() - local new_tab = api.nvim_open_tabpage(0, { enter = false }) + local new_tab = api.nvim_open_tabpage(0, false, {}) api.nvim_set_current_tabpage(new_tab) eq(curbuf, api.nvim_get_current_buf()) @@ -445,9 +437,7 @@ describe('api/tabpage', function() local original_tab = api.nvim_get_current_tabpage() local original_buf = api.nvim_get_current_buf() - new_tab = api.nvim_open_tabpage(buf, { - enter = true, -- Enter the tab to make testing easier - }) + new_tab = api.nvim_open_tabpage(buf, true, {}) -- Enter the tab to make testing easier -- Check that new tab has the specified buffer eq(new_tab, api.nvim_get_current_tabpage()) @@ -459,7 +449,7 @@ describe('api/tabpage', function() eq(original_buf, api.nvim_get_current_buf()) -- Test invalid buffer - eq('Invalid buffer id: 999', pcall_err(api.nvim_open_tabpage, 999, {})) + eq('Invalid buffer id: 999', pcall_err(api.nvim_open_tabpage, 999, true, {})) end) it('handles complex positioning scenarios', function() @@ -475,7 +465,7 @@ describe('api/tabpage', function() api.nvim_set_current_tabpage(tabs[3]) -- Insert after=0 (after current, which is tab 3) - local new_after_current = api.nvim_open_tabpage(0, { enter = false }) + local new_after_current = api.nvim_open_tabpage(0, false, {}) local result_tabs = api.nvim_list_tabpages() eq(6, #result_tabs) eq({ @@ -488,7 +478,7 @@ describe('api/tabpage', function() }, result_tabs) -- Insert as number 2 (before tab2, which will become number 3) - local new_at_pos2 = api.nvim_open_tabpage(0, { enter = false, after = 1 }) + local new_at_pos2 = api.nvim_open_tabpage(0, false, { after = 1 }) local final_result = api.nvim_list_tabpages() eq(7, #final_result) eq({ @@ -508,11 +498,7 @@ describe('api/tabpage', function() local tab2 = api.nvim_get_current_tabpage() -- Create new tab with enter=true, should insert after current (tab2) - local tab3 = api.nvim_open_tabpage(0, { - enter = true, - after = -1, - }) - + local tab3 = api.nvim_open_tabpage(0, true, { after = -1 }) local tabs = api.nvim_list_tabpages() eq(3, #tabs) eq({ tab1, tab2, tab3 }, tabs) @@ -520,11 +506,7 @@ describe('api/tabpage', function() -- Create another with enter=true and specific position api.nvim_set_current_tabpage(tab1) - local tab4 = api.nvim_open_tabpage(0, { - enter = true, - after = 0, -- Should become first tab - }) - + local tab4 = api.nvim_open_tabpage(0, true, { after = 0 }) -- Should become first tab local final_tabs = api.nvim_list_tabpages() eq(4, #final_tabs) eq({ tab4, tab1, tab2, tab3 }, final_tabs)