fix(api): nvim_open_tabpage "after" like :[count]tab

Problem: "after" in nvim_open_tabpage is inconsistent with how a count works
with :tab, :tabnew, etc. Plus, the name "after" implies it's inserted after that
number.

Solution: internally offset by 1. Allow negative numbers to mean after current.

Hmm, should we even reserve sentinels for after current? Callers can probably
just use nil...
This commit is contained in:
Sean Dewar
2026-03-15 19:00:06 +00:00
parent cd4c98fded
commit 0c1ed63c05
4 changed files with 20 additions and 27 deletions

View File

@@ -3557,8 +3557,8 @@ nvim_open_tabpage({buffer}, {config}) *nvim_open_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: 0). 0 = after
current, 1 = first, N = before Nth.
• after: Position to insert tabpage (default: -1; after
current). 0 = first, N = after Nth.
Return: ~
(`integer`) Tabpage handle of the created tabpage

View File

@@ -1679,8 +1679,8 @@ function vim.api.nvim_notify(msg, log_level, opts) end
--- Use 0 for current buffer.
--- @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: 0).
--- 0 = after current, 1 = first, N = before Nth.
--- - 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

View File

@@ -5,7 +5,6 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/api/tabpage.h"
#include "nvim/api/vim.h"
#include "nvim/autocmd.h"
@@ -196,8 +195,8 @@ Boolean nvim_tabpage_is_valid(Tabpage tabpage)
/// Use 0 for current buffer.
/// @param config Configuration for the new tabpage. Keys:
/// - enter: Whether to enter the new tabpage (default: true)
/// - after: Position to insert tabpage (default: 0).
/// 0 = after current, 1 = first, N = before Nth.
/// - 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)
@@ -218,19 +217,15 @@ Tabpage nvim_open_tabpage(Buffer buffer, Dict(tabpage_config) *config, Error *er
return 0;
}
int after = 0; // Default to after current tabpage
int after = -1; // Default to after current tabpage
if (HAS_KEY_X(config, after)) {
after = (int)config->after;
VALIDATE_INT(after >= 0, "after", config->after, {
return 0;
});
// NOTE: win_new_tabpage will handle after > count by appending to the end.
}
tabpage_T *tp;
win_T *wp;
TRY_WRAP(err, {
tp = win_new_tabpage(after, NULL, enter, &wp);
tp = win_new_tabpage(after + 1, NULL, enter, &wp);
});
if (!tp) {
if (!ERROR_SET(err)) { // set error maybe more specific

View File

@@ -242,8 +242,8 @@ describe('api/tabpage', function()
eq(4, #newtabs2)
eq({
tab1,
new_tab,
tab2,
new_tab,
tab3,
}, newtabs2)
eq(api.nvim_get_current_tabpage(), tab3)
@@ -375,20 +375,20 @@ describe('api/tabpage', function()
eq(3, #initial_tabs)
eq({ tab1, tab2, tab3 }, initial_tabs)
-- Test after=1: should become first tab
local first_tab = api.nvim_open_tabpage(0, { enter = false, after = 1 })
-- Test after=0: should become first tab
local first_tab = api.nvim_open_tabpage(0, { enter = 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=0: should insert after current tab (tab3)
local explicit_after_current = api.nvim_open_tabpage(0, { enter = false, after = 0 })
-- Test after=-1: should insert after current tab (tab3)
local explicit_after_current = api.nvim_open_tabpage(0, { enter = 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 position 3)
local before_middle = api.nvim_open_tabpage(0, { enter = false, after = 3 })
-- 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 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)
@@ -408,8 +408,6 @@ describe('api/tabpage', function()
default_after_current,
explicit_after_current,
}, final_tabs)
eq("Invalid 'after': -1", pcall_err(api.nvim_open_tabpage, 0, { after = -1 }))
end)
it('handles position beyond last tab', function()
@@ -477,7 +475,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, after = 0 })
local new_after_current = api.nvim_open_tabpage(0, { enter = false })
local result_tabs = api.nvim_list_tabpages()
eq(6, #result_tabs)
eq({
@@ -489,8 +487,8 @@ describe('api/tabpage', function()
tabs[5],
}, result_tabs)
-- Insert at position 2 (before tab2, which becomes new position 2)
local new_at_pos2 = api.nvim_open_tabpage(0, { enter = false, after = 2 })
-- 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 final_result = api.nvim_list_tabpages()
eq(7, #final_result)
eq({
@@ -512,7 +510,7 @@ describe('api/tabpage', function()
-- Create new tab with enter=true, should insert after current (tab2)
local tab3 = api.nvim_open_tabpage(0, {
enter = true,
after = 0,
after = -1,
})
local tabs = api.nvim_list_tabpages()
@@ -524,7 +522,7 @@ describe('api/tabpage', function()
api.nvim_set_current_tabpage(tab1)
local tab4 = api.nvim_open_tabpage(0, {
enter = true,
after = 1, -- Should become first tab
after = 0, -- Should become first tab
})
local final_tabs = api.nvim_list_tabpages()