feat(api): tab-local option scope #39811

Problem:
2d795face6 added support for tab-local options ('cmdheight')
to `nvim_get_option_value`, but not to:

    nvim_get_option_info2()
    nvim_set_option_value(…, { tab = … })
    gettabwinvar()

Solution:
- Update `options.lua` to model tab-local options. Introduce `kOptScopeTab`.
- Handle tab scope in the options layer so it works for all options APIs.

Note:
- No change to `gettabvar()`. Not sure if needed/wanted.

fix https://github.com/neovim/neovim/issues/31140
This commit is contained in:
Justin M. Keyes
2026-05-17 10:24:46 -04:00
committed by GitHub
parent c55b6128f8
commit e572c9c80a
15 changed files with 297 additions and 173 deletions

View File

@@ -1516,7 +1516,7 @@ function vim.api.nvim_get_option_info(name) end
--- - last_set_linenr: line number where option was set
--- - last_set_chan: Channel where option was set (0 for local)
---
--- - scope: one of "global", "win", or "buf"
--- - scope: one of "global", "win", "buf", or "tab"
--- - global_local: whether win or buf option has a global value
---
--- - commalist: List of comma separated values
@@ -2336,6 +2336,9 @@ function vim.api.nvim_set_option(name, value) end
--- - buf: Buffer number. Used for setting buffer local option.
--- - scope: One of "global" or "local". Analogous to
--- `:setglobal` and `:setlocal`, respectively.
--- - tab: `tab-ID` for tab-local options (currently only 'cmdheight'). Tabpage 0
--- means the current tabpage. If a non-current tab is given, the value will take
--- effect when it is switched-to.
--- - win: `window-ID`. Used for setting window local option.
function vim.api.nvim_set_option_value(name, value, opts) end

View File

@@ -200,7 +200,7 @@ error('Cannot require a meta file')
--- @class vim.api.keyset.get_option_info
--- @field name string
--- @field shortname string
--- @field scope 'buf'|'win'|'global'
--- @field scope 'buf'|'win'|'global'|'tab'
--- @field global_local boolean
--- @field commalist boolean
--- @field flaglist boolean

View File

@@ -2884,22 +2884,25 @@ function vim.fn.getbufoneline(buf, lnum) end
--- Lua: Prefer |nvim_buf_get_var()| or |vim.b| after resolving {buf} to a bufnr; option names use |nvim_get_option_value()| or |vim.bo|.
---
--- The result is the value of option or local buffer variable
--- {varname} in buffer {buf}. Note that the name without "b:"
--- must be used.
--- The {varname} argument is a string.
--- When {varname} is empty returns a |Dictionary| with all the
--- buffer-local variables.
--- When {varname} is equal to "&" returns a |Dictionary| with all
--- the buffer-local options.
--- Otherwise, when {varname} starts with "&" returns the value of
--- a buffer-local option.
--- This also works for a global or buffer-local option, but it
--- doesn't work for a global variable, window-local variable or
--- window-local option.
--- For the use of {buf}, see |bufname()| above.
--- When the buffer or variable doesn't exist {def} or an empty
--- string is returned, there is no error message.
--- Gets the value of a buffer-local variable or option {varname}
--- in buffer {buf}.
---
--- {varname} is a string:
--- - Name of the variable (without "b:").
--- - If empty, gets a |Dictionary| of all buffer-local variables.
--- - If "&", gets a |Dictionary| of all buffer-local options.
--- - If it starts with "&", gets the value of a buffer-local
--- option.
---
--- {buf} has the same form as in |bufname()|.
---
--- Also works for a global or buffer-local option. But not for
--- a global variable, window-local variable or window-local
--- option.
---
--- When the buffer or variable doesn't exist, {def} or an empty
--- string is returned; there is no error.
---
--- Examples: >vim
--- let bufmodified = getbufvar(1, "&mod")
--- echo "todo myvar = " .. getbufvar("todo", "myvar")
@@ -4090,29 +4093,34 @@ function vim.fn.gettabvar(tabnr, varname, def) end
--- Lua: Prefer |nvim_win_get_var()| or |vim.w| after resolving {tabnr} and {winnr} to a winid; option names use |nvim_get_option_value()| or |vim.wo|.
---
--- Get the value of window-local variable {varname} in window
--- {winnr} in tabpage {tabnr}.
--- The {varname} argument is a string. When {varname} is empty a
--- dictionary with all window-local variables is returned.
--- When {varname} is equal to "&" get the values of all
--- window-local options in a |Dictionary|.
--- Otherwise, when {varname} starts with "&" get the value of a
--- window-local option.
--- Note that {varname} must be the name without "w:".
--- Tabs are numbered starting with one. For the current tabpage
--- use |getwinvar()|.
--- {winnr} is a |window-number| or |window-ID|.
--- Gets the value of window-local variable {varname} in {winnr}
--- (|window-number| or |window-ID|) in |tabpage-number| {tabnr}.
---
--- {varname} is a string:
--- - Name of the variable (without "w:").
--- - If empty, gets a dictionary with all window-local variables.
--- - If "&", gets the values of all window-local options in
--- a |Dictionary|.
--- - If it starts with "&", gets the value of a window-local
--- option.
---
--- To get window-local variables in the current tabpage use
--- |getwinvar()|.
---
--- When {winnr} is zero the current window is used.
--- This also works for a global option, buffer-local option and
--- window-local option, but it doesn't work for a global variable
--- or buffer-local variable.
--- When the tab, window or variable doesn't exist {def} or an
--- empty string is returned, there is no error message.
---
--- Also works for a global option, buffer-local option,
--- window-local option, and tab-local option ('cmdheight').
--- But not for a global variable or buffer-local variable.
---
--- When the tab, window or variable doesn't exist, {def} or an
--- empty string is returned; there is no error.
---
--- Examples: >vim
--- let list_is_on = gettabwinvar(1, 2, '&list')
--- echo "myvar = " .. gettabwinvar(3, 1, 'myvar')
--- <
--- To obtain all window-local variables use: >vim
--- To get all window-local variables: >vim
--- gettabwinvar({tabnr}, {winnr}, '&')
--- <
---