aboutsummaryrefslogtreecommitdiff
path: root/test/functional/api/vim_spec.lua
diff options
context:
space:
mode:
authorKyle <50718101+kylesower@users.noreply.github.com>2026-06-28 12:20:56 -0500
committerGitHub <noreply@github.com>2026-06-28 13:20:56 -0400
commitf34ee3da80e864ff545169bc2ced856bf5822260 (patch)
treec2df99a0bb3373efbc88cd3e0d66da26e328087f /test/functional/api/vim_spec.lua
parenta5aa62e37b82214a1d4d1e0a54d193b155fb340c (diff)
downloadrneovim-f34ee3da80e864ff545169bc2ced856bf5822260.tar.gz
rneovim-f34ee3da80e864ff545169bc2ced856bf5822260.tar.bz2
rneovim-f34ee3da80e864ff545169bc2ced856bf5822260.zip
feat(api): nvim_set_option_value(operation=...) #39849
Problem: `nvim_set_option_value` cannot "update" options similar to `:set opt=`, `:set opt+=`, etc. The Lua impls of "vim.opt" / "vim.o" have incomplete, bespoke reimplementations of those operations. ref #38420 Solution: - Add `operation` param to `nvim_set_option_value`, which may be "set", "append", "prepend", or "remove". - Use this feature to implement `vim.opt` / `vim.o`.
Diffstat (limited to 'test/functional/api/vim_spec.lua')
-rw-r--r--test/functional/api/vim_spec.lua167
1 files changed, 161 insertions, 6 deletions
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index b9f18500d0..9d6485ac0e 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1940,16 +1940,16 @@ describe('API', function()
"Invalid 'scope': expected String, got Integer",
pcall_err(api.nvim_get_option_value, 'scrolloff', { scope = 42 })
)
- eq(
- "Invalid 'value': expected valid option type, got Array",
+ matches(
+ "Invalid option type 'table' for 'scrolloff', should be number",
pcall_err(api.nvim_set_option_value, 'scrolloff', {}, {})
)
- eq(
- "Invalid value for option 'scrolloff': expected number, got boolean true",
+ matches(
+ "Invalid option type 'boolean' for 'scrolloff', should be number",
pcall_err(api.nvim_set_option_value, 'scrolloff', true, {})
)
- eq(
- 'Invalid value for option \'scrolloff\': expected number, got string "wrong"',
+ matches(
+ "Invalid option type 'string' for 'scrolloff', should be number",
pcall_err(api.nvim_set_option_value, 'scrolloff', 'wrong', {})
)
local tab1 = api.nvim_get_current_tabpage()
@@ -2243,6 +2243,161 @@ describe('API', function()
eq(0, eval('g:modeline'))
eq(1, eval('g:bufloaded'))
end)
+
+ it('expands env vars', function()
+ -- I don't know why setting vim.env.INCLUDE doesn't work here.
+ clear { env = { INCLUDE = '/dev/null' } }
+ api.nvim_set_option_value('path', '$INCLUDE', {})
+ eq('/dev/null', api.nvim_get_option_value('path', {}))
+ end)
+
+ it('expands ~', function()
+ clear { env = { HOME = '/dev/null' } }
+ api.nvim_set_option_value('rtp', '~', {})
+ eq('/dev/null', api.nvim_get_option_value('rtp', {}))
+ end)
+
+ it('allows setting, appending, prepending, and removing lists', function()
+ api.nvim_set_option_value('wildignore', { '*.o', '*.obj' }, {})
+ eq('*.o,*.obj', api.nvim_get_option_value('wildignore', {}))
+
+ api.nvim_set_option_value('wildignore', { '*.a', '*.b', '*.c' }, { operation = 'append' })
+ eq('*.o,*.obj,*.a,*.b,*.c', api.nvim_get_option_value('wildignore', {}))
+
+ api.nvim_set_option_value('wildignore', { '1', '2', '3' }, { operation = 'prepend' })
+ eq('1,2,3,*.o,*.obj,*.a,*.b,*.c', api.nvim_get_option_value('wildignore', {}))
+
+ -- NOTE: you can't remove something like { '1', '*.obj' } because lists
+ -- only support removing items in order. Behavior matches :set-=
+ api.nvim_set_option_value('wildignore', { '1', '2', '3' }, { operation = 'remove' })
+ eq('*.o,*.obj,*.a,*.b,*.c', api.nvim_get_option_value('wildignore', {}))
+ end)
+
+ it('allows setting, appending, prepending, removing tables', function()
+ -- NOTE: order is dependent on lua's hash map implementation. I don't
+ -- *think* order matters for the map style options
+ api.nvim_set_option_value('listchars', { eol = '~', space = '-' }, {})
+ eq('eol:~,space:-', api.nvim_get_option_value('listchars', {}))
+
+ api.nvim_set_option_value(
+ 'listchars',
+ { multispace = '---+', tab = '>-' },
+ { operation = 'append' }
+ )
+ eq('eol:~,space:-,multispace:---+,tab:>-', api.nvim_get_option_value('listchars', {}))
+
+ api.nvim_set_option_value('listchars', { lead = '.' }, { operation = 'prepend' })
+ eq('lead:.,eol:~,space:-,multispace:---+,tab:>-', api.nvim_get_option_value('listchars', {}))
+
+ api.nvim_set_option_value(
+ 'listchars',
+ { lead = '', multispace = '' },
+ { operation = 'remove' }
+ )
+ eq('eol:~,space:-,tab:>-', api.nvim_get_option_value('listchars', {}))
+ end)
+
+ it('returns the new option value', function()
+ eq(
+ { eol = '~', space = '-' },
+ api.nvim_set_option_value('listchars', { eol = '~', space = '-' }, {})
+ )
+ eq('eol:~,space:-', api.nvim_get_option_value('listchars', {}))
+ eq(
+ { eol = '~', space = '-', tab = '>-' },
+ api.nvim_set_option_value('listchars', { tab = '>-' }, { operation = 'append' })
+ )
+ eq('eol:~,space:-,tab:>-', api.nvim_get_option_value('listchars', {}))
+ end)
+
+ it("doesn't update option value with dry_run flag", function()
+ local listchars = api.nvim_get_option_value('listchars', {})
+ eq(
+ { eol = '~', space = '-' },
+ api.nvim_set_option_value('listchars', { eol = '~', space = '-' }, { dry_run = true })
+ )
+ eq(listchars, api.nvim_get_option_value('listchars', {}))
+ end)
+
+ it('merges options against non-current window', function()
+ api.nvim_set_option_value('listchars', {}, { operation = 'set' })
+
+ local oldwin = fn.win_getid()
+ command('split')
+ local curwin = fn.win_getid()
+ neq(oldwin, curwin)
+
+ eq(
+ { eol = '~' },
+ api.nvim_set_option_value(
+ 'listchars',
+ { eol = '~' },
+ { operation = 'append', win = oldwin }
+ )
+ )
+ eq(
+ { tab = '>-' },
+ api.nvim_set_option_value(
+ 'listchars',
+ { tab = '>-' },
+ { operation = 'append', win = curwin }
+ )
+ )
+ eq(
+ { eol = '~', space = '-' },
+ api.nvim_set_option_value(
+ 'listchars',
+ { space = '-' },
+ { operation = 'append', win = oldwin }
+ )
+ )
+ eq(
+ { lead = '.', tab = '>-' },
+ api.nvim_set_option_value(
+ 'listchars',
+ { lead = '.' },
+ { operation = 'append', win = curwin }
+ )
+ )
+ end)
+
+ it('merges options against non-current buffer', function()
+ eq({}, api.nvim_set_option_value('completeopt', {}, { operation = 'set' }))
+
+ local oldbuf = fn.bufnr()
+ command('new')
+ local curbuf = fn.bufnr()
+ neq(oldbuf, curbuf)
+
+ eq(
+ { 'fuzzy' },
+ api.nvim_set_option_value(
+ 'completeopt',
+ { 'fuzzy' },
+ { operation = 'append', buf = oldbuf }
+ )
+ )
+ eq(
+ { 'longest' },
+ api.nvim_set_option_value(
+ 'completeopt',
+ { 'longest' },
+ { operation = 'append', buf = curbuf }
+ )
+ )
+ eq(
+ { 'fuzzy', 'menu' },
+ api.nvim_set_option_value('completeopt', { 'menu' }, { operation = 'append', buf = oldbuf })
+ )
+ eq(
+ { 'longest', 'noinsert' },
+ api.nvim_set_option_value(
+ 'completeopt',
+ { 'noinsert' },
+ { operation = 'append', buf = curbuf }
+ )
+ )
+ end)
end)
describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()