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.
This commit is contained in:
Sean Dewar
2026-03-16 13:15:33 +00:00
parent 0c1ed63c05
commit 97b064c9ac
6 changed files with 36 additions and 61 deletions

View File

@@ -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.

View File

@@ -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
---

View File

@@ -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

View File

@@ -144,7 +144,6 @@ typedef struct {
typedef struct {
OptionalKeys is_set__tabpage_config_;
Boolean enter;
Integer after;
} Dict(tabpage_config);

View File

@@ -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;

View File

@@ -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)