option_and_var_spec.lua (42539B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 local Screen = require('test.functional.ui.screen') 4 5 local NIL = vim.NIL 6 local feed = n.feed 7 local command = n.command 8 local clear = n.clear 9 local api = n.api 10 local eq = t.eq 11 local eval = n.eval 12 local exec = n.exec 13 local exec_lua = n.exec_lua 14 local fn = n.fn 15 local matches = t.matches 16 local mkdir_p = n.mkdir_p 17 local pcall_err = t.pcall_err 18 local rmdir = n.rmdir 19 local write_file = t.write_file 20 21 local function eq_exec_lua(expected, f) 22 eq(expected, exec_lua(f)) 23 end 24 25 describe('lua stdlib', function() 26 before_each(clear) 27 28 describe('variables', function() 29 it('vim.g', function() 30 exec_lua(function() 31 vim.api.nvim_set_var('testing', 'hi') 32 vim.api.nvim_set_var('other', 123) 33 vim.api.nvim_set_var('floaty', 5120.1) 34 vim.api.nvim_set_var('nullvar', vim.NIL) 35 vim.api.nvim_set_var('to_delete', { hello = 'world' }) 36 end) 37 38 eq('hi', fn.luaeval 'vim.g.testing') 39 eq(123, fn.luaeval 'vim.g.other') 40 eq(5120.1, fn.luaeval 'vim.g.floaty') 41 eq(NIL, fn.luaeval 'vim.g.nonexistent') 42 eq(NIL, fn.luaeval 'vim.g.nullvar') 43 -- lost over RPC, so test locally: 44 eq_exec_lua({ false, true }, function() 45 return { vim.g.nonexistent == vim.NIL, vim.g.nullvar == vim.NIL } 46 end) 47 48 eq({ hello = 'world' }, fn.luaeval 'vim.g.to_delete') 49 exec_lua [[ 50 vim.g.to_delete = nil 51 ]] 52 eq(NIL, fn.luaeval 'vim.g.to_delete') 53 54 matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.g[0].testing')) 55 56 exec_lua(function() 57 local counter = 0 58 local function add_counter() 59 counter = counter + 1 60 end 61 local function get_counter() 62 return counter 63 end 64 vim.g.AddCounter = add_counter 65 vim.g.GetCounter = get_counter 66 vim.g.fn = { add = add_counter, get = get_counter } 67 vim.g.AddParens = function(s) 68 return '(' .. s .. ')' 69 end 70 end) 71 72 eq(0, eval('g:GetCounter()')) 73 eval('g:AddCounter()') 74 eq(1, eval('g:GetCounter()')) 75 eval('g:AddCounter()') 76 eq(2, eval('g:GetCounter()')) 77 exec_lua([[vim.g.AddCounter()]]) 78 eq(3, exec_lua([[return vim.g.GetCounter()]])) 79 exec_lua([[vim.api.nvim_get_var('AddCounter')()]]) 80 eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]])) 81 exec_lua([[vim.g.fn.add()]]) 82 eq(5, exec_lua([[return vim.g.fn.get()]])) 83 exec_lua([[vim.api.nvim_get_var('fn').add()]]) 84 eq(6, exec_lua([[return vim.api.nvim_get_var('fn').get()]])) 85 eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) 86 87 exec_lua(function() 88 local counter = 0 89 local function add_counter() 90 counter = counter + 1 91 end 92 local function get_counter() 93 return counter 94 end 95 vim.api.nvim_set_var('AddCounter', add_counter) 96 vim.api.nvim_set_var('GetCounter', get_counter) 97 vim.api.nvim_set_var('fn', { add = add_counter, get = get_counter }) 98 vim.api.nvim_set_var('AddParens', function(s) 99 return '(' .. s .. ')' 100 end) 101 end) 102 103 eq(0, eval('g:GetCounter()')) 104 eval('g:AddCounter()') 105 eq(1, eval('g:GetCounter()')) 106 eval('g:AddCounter()') 107 eq(2, eval('g:GetCounter()')) 108 exec_lua([[vim.g.AddCounter()]]) 109 eq(3, exec_lua([[return vim.g.GetCounter()]])) 110 exec_lua([[vim.api.nvim_get_var('AddCounter')()]]) 111 eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]])) 112 exec_lua([[vim.g.fn.add()]]) 113 eq(5, exec_lua([[return vim.g.fn.get()]])) 114 exec_lua([[vim.api.nvim_get_var('fn').add()]]) 115 eq(6, exec_lua([[return vim.api.nvim_get_var('fn').get()]])) 116 eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) 117 118 exec([[ 119 function Test() 120 endfunction 121 function s:Test() 122 endfunction 123 let g:Unknown_func = function('Test') 124 let g:Unknown_script_func = function('s:Test') 125 ]]) 126 eq(NIL, exec_lua([[return vim.g.Unknown_func]])) 127 eq(NIL, exec_lua([[return vim.g.Unknown_script_func]])) 128 129 -- Check if autoload works properly 130 local pathsep = n.get_pathsep() 131 local xhome = 'Xhome_lua' 132 local xconfig = xhome .. pathsep .. 'Xconfig' 133 local xdata = xhome .. pathsep .. 'Xdata' 134 local autoload_folder = table.concat({ xconfig, 'nvim', 'autoload' }, pathsep) 135 local autoload_file = table.concat({ autoload_folder, 'testload.vim' }, pathsep) 136 mkdir_p(autoload_folder) 137 write_file(autoload_file, [[let testload#value = 2]]) 138 139 clear { args_rm = { '-u' }, env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata } } 140 141 eq(2, exec_lua("return vim.g['testload#value']")) 142 rmdir(xhome) 143 end) 144 145 it('vim.b', function() 146 exec_lua(function() 147 vim.api.nvim_buf_set_var(0, 'testing', 'hi') 148 vim.api.nvim_buf_set_var(0, 'other', 123) 149 vim.api.nvim_buf_set_var(0, 'floaty', 5120.1) 150 vim.api.nvim_buf_set_var(0, 'nullvar', vim.NIL) 151 vim.api.nvim_buf_set_var(0, 'to_delete', { hello = 'world' }) 152 _G.BUF = vim.api.nvim_create_buf(false, true) 153 vim.api.nvim_buf_set_var(_G.BUF, 'testing', 'bye') 154 end) 155 156 eq('hi', fn.luaeval 'vim.b.testing') 157 eq('bye', fn.luaeval 'vim.b[BUF].testing') 158 eq(123, fn.luaeval 'vim.b.other') 159 eq(5120.1, fn.luaeval 'vim.b.floaty') 160 eq(NIL, fn.luaeval 'vim.b.nonexistent') 161 eq(NIL, fn.luaeval 'vim.b[BUF].nonexistent') 162 eq(NIL, fn.luaeval 'vim.b.nullvar') 163 -- lost over RPC, so test locally: 164 eq_exec_lua({ false, true }, function() 165 return { vim.b.nonexistent == vim.NIL, vim.b.nullvar == vim.NIL } 166 end) 167 168 matches( 169 [[attempt to index .* nil value]], 170 pcall_err(exec_lua, 'return vim.b[BUF][0].testing') 171 ) 172 173 eq({ hello = 'world' }, fn.luaeval 'vim.b.to_delete') 174 exec_lua [[ 175 vim.b.to_delete = nil 176 ]] 177 eq(NIL, fn.luaeval 'vim.b.to_delete') 178 179 exec_lua(function() 180 local counter = 0 181 local function add_counter() 182 counter = counter + 1 183 end 184 local function get_counter() 185 return counter 186 end 187 vim.b.AddCounter = add_counter 188 vim.b.GetCounter = get_counter 189 vim.b.fn = { add = add_counter, get = get_counter } 190 vim.b.AddParens = function(s) 191 return '(' .. s .. ')' 192 end 193 end) 194 195 eq(0, eval('b:GetCounter()')) 196 eval('b:AddCounter()') 197 eq(1, eval('b:GetCounter()')) 198 eval('b:AddCounter()') 199 eq(2, eval('b:GetCounter()')) 200 exec_lua([[vim.b.AddCounter()]]) 201 eq(3, exec_lua([[return vim.b.GetCounter()]])) 202 exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]]) 203 eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]])) 204 exec_lua([[vim.b.fn.add()]]) 205 eq(5, exec_lua([[return vim.b.fn.get()]])) 206 exec_lua([[vim.api.nvim_buf_get_var(0, 'fn').add()]]) 207 eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'fn').get()]])) 208 eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) 209 210 exec_lua(function() 211 local counter = 0 212 local function add_counter() 213 counter = counter + 1 214 end 215 local function get_counter() 216 return counter 217 end 218 vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter) 219 vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter) 220 vim.api.nvim_buf_set_var(0, 'fn', { add = add_counter, get = get_counter }) 221 vim.api.nvim_buf_set_var(0, 'AddParens', function(s) 222 return '(' .. s .. ')' 223 end) 224 end) 225 226 eq(0, eval('b:GetCounter()')) 227 eval('b:AddCounter()') 228 eq(1, eval('b:GetCounter()')) 229 eval('b:AddCounter()') 230 eq(2, eval('b:GetCounter()')) 231 exec_lua([[vim.b.AddCounter()]]) 232 eq(3, exec_lua([[return vim.b.GetCounter()]])) 233 exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]]) 234 eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]])) 235 exec_lua([[vim.b.fn.add()]]) 236 eq(5, exec_lua([[return vim.b.fn.get()]])) 237 exec_lua([[vim.api.nvim_buf_get_var(0, 'fn').add()]]) 238 eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'fn').get()]])) 239 eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) 240 241 exec([[ 242 function Test() 243 endfunction 244 function s:Test() 245 endfunction 246 let b:Unknown_func = function('Test') 247 let b:Unknown_script_func = function('s:Test') 248 ]]) 249 eq(NIL, exec_lua([[return vim.b.Unknown_func]])) 250 eq(NIL, exec_lua([[return vim.b.Unknown_script_func]])) 251 252 exec_lua [[ 253 vim.cmd "vnew" 254 ]] 255 256 eq(NIL, fn.luaeval 'vim.b.testing') 257 eq(NIL, fn.luaeval 'vim.b.other') 258 eq(NIL, fn.luaeval 'vim.b.nonexistent') 259 end) 260 261 it('vim.w', function() 262 exec_lua [[ 263 vim.api.nvim_win_set_var(0, "testing", "hi") 264 vim.api.nvim_win_set_var(0, "other", 123) 265 vim.api.nvim_win_set_var(0, "to_delete", {hello="world"}) 266 BUF = vim.api.nvim_create_buf(false, true) 267 WIN = vim.api.nvim_open_win(BUF, false, { 268 width=10, height=10, 269 relative='win', row=0, col=0 270 }) 271 vim.api.nvim_win_set_var(WIN, "testing", "bye") 272 ]] 273 274 eq('hi', fn.luaeval 'vim.w.testing') 275 eq('bye', fn.luaeval 'vim.w[WIN].testing') 276 eq(123, fn.luaeval 'vim.w.other') 277 eq(NIL, fn.luaeval 'vim.w.nonexistent') 278 eq(NIL, fn.luaeval 'vim.w[WIN].nonexistent') 279 280 matches( 281 [[attempt to index .* nil value]], 282 pcall_err(exec_lua, 'return vim.w[WIN][0].testing') 283 ) 284 285 eq({ hello = 'world' }, fn.luaeval 'vim.w.to_delete') 286 exec_lua [[ 287 vim.w.to_delete = nil 288 ]] 289 eq(NIL, fn.luaeval 'vim.w.to_delete') 290 291 exec_lua [[ 292 local counter = 0 293 local function add_counter() counter = counter + 1 end 294 local function get_counter() return counter end 295 vim.w.AddCounter = add_counter 296 vim.w.GetCounter = get_counter 297 vim.w.fn = {add = add_counter, get = get_counter} 298 vim.w.AddParens = function(s) return '(' .. s .. ')' end 299 ]] 300 301 eq(0, eval('w:GetCounter()')) 302 eval('w:AddCounter()') 303 eq(1, eval('w:GetCounter()')) 304 eval('w:AddCounter()') 305 eq(2, eval('w:GetCounter()')) 306 exec_lua([[vim.w.AddCounter()]]) 307 eq(3, exec_lua([[return vim.w.GetCounter()]])) 308 exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]]) 309 eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]])) 310 exec_lua([[vim.w.fn.add()]]) 311 eq(5, exec_lua([[return vim.w.fn.get()]])) 312 exec_lua([[vim.api.nvim_win_get_var(0, 'fn').add()]]) 313 eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'fn').get()]])) 314 eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) 315 316 exec_lua [[ 317 local counter = 0 318 local function add_counter() counter = counter + 1 end 319 local function get_counter() return counter end 320 vim.api.nvim_win_set_var(0, 'AddCounter', add_counter) 321 vim.api.nvim_win_set_var(0, 'GetCounter', get_counter) 322 vim.api.nvim_win_set_var(0, 'fn', {add = add_counter, get = get_counter}) 323 vim.api.nvim_win_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) 324 ]] 325 326 eq(0, eval('w:GetCounter()')) 327 eval('w:AddCounter()') 328 eq(1, eval('w:GetCounter()')) 329 eval('w:AddCounter()') 330 eq(2, eval('w:GetCounter()')) 331 exec_lua([[vim.w.AddCounter()]]) 332 eq(3, exec_lua([[return vim.w.GetCounter()]])) 333 exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]]) 334 eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]])) 335 exec_lua([[vim.w.fn.add()]]) 336 eq(5, exec_lua([[return vim.w.fn.get()]])) 337 exec_lua([[vim.api.nvim_win_get_var(0, 'fn').add()]]) 338 eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'fn').get()]])) 339 eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) 340 341 exec([[ 342 function Test() 343 endfunction 344 function s:Test() 345 endfunction 346 let w:Unknown_func = function('Test') 347 let w:Unknown_script_func = function('s:Test') 348 ]]) 349 eq(NIL, exec_lua([[return vim.w.Unknown_func]])) 350 eq(NIL, exec_lua([[return vim.w.Unknown_script_func]])) 351 352 exec_lua [[ 353 vim.cmd "vnew" 354 ]] 355 356 eq(NIL, fn.luaeval 'vim.w.testing') 357 eq(NIL, fn.luaeval 'vim.w.other') 358 eq(NIL, fn.luaeval 'vim.w.nonexistent') 359 end) 360 361 it('vim.t', function() 362 exec_lua [[ 363 vim.api.nvim_tabpage_set_var(0, "testing", "hi") 364 vim.api.nvim_tabpage_set_var(0, "other", 123) 365 vim.api.nvim_tabpage_set_var(0, "to_delete", {hello="world"}) 366 ]] 367 368 eq('hi', fn.luaeval 'vim.t.testing') 369 eq(123, fn.luaeval 'vim.t.other') 370 eq(NIL, fn.luaeval 'vim.t.nonexistent') 371 eq('hi', fn.luaeval 'vim.t[0].testing') 372 eq(123, fn.luaeval 'vim.t[0].other') 373 eq(NIL, fn.luaeval 'vim.t[0].nonexistent') 374 375 matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.t[0][0].testing')) 376 377 eq({ hello = 'world' }, fn.luaeval 'vim.t.to_delete') 378 exec_lua [[ 379 vim.t.to_delete = nil 380 ]] 381 eq(NIL, fn.luaeval 'vim.t.to_delete') 382 383 exec_lua [[ 384 local counter = 0 385 local function add_counter() counter = counter + 1 end 386 local function get_counter() return counter end 387 vim.t.AddCounter = add_counter 388 vim.t.GetCounter = get_counter 389 vim.t.fn = {add = add_counter, get = get_counter} 390 vim.t.AddParens = function(s) return '(' .. s .. ')' end 391 ]] 392 393 eq(0, eval('t:GetCounter()')) 394 eval('t:AddCounter()') 395 eq(1, eval('t:GetCounter()')) 396 eval('t:AddCounter()') 397 eq(2, eval('t:GetCounter()')) 398 exec_lua([[vim.t.AddCounter()]]) 399 eq(3, exec_lua([[return vim.t.GetCounter()]])) 400 exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]]) 401 eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]])) 402 exec_lua([[vim.t.fn.add()]]) 403 eq(5, exec_lua([[return vim.t.fn.get()]])) 404 exec_lua([[vim.api.nvim_tabpage_get_var(0, 'fn').add()]]) 405 eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'fn').get()]])) 406 eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) 407 408 exec_lua [[ 409 local counter = 0 410 local function add_counter() counter = counter + 1 end 411 local function get_counter() return counter end 412 vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter) 413 vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter) 414 vim.api.nvim_tabpage_set_var(0, 'fn', {add = add_counter, get = get_counter}) 415 vim.api.nvim_tabpage_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) 416 ]] 417 418 eq(0, eval('t:GetCounter()')) 419 eval('t:AddCounter()') 420 eq(1, eval('t:GetCounter()')) 421 eval('t:AddCounter()') 422 eq(2, eval('t:GetCounter()')) 423 exec_lua([[vim.t.AddCounter()]]) 424 eq(3, exec_lua([[return vim.t.GetCounter()]])) 425 exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]]) 426 eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]])) 427 exec_lua([[vim.t.fn.add()]]) 428 eq(5, exec_lua([[return vim.t.fn.get()]])) 429 exec_lua([[vim.api.nvim_tabpage_get_var(0, 'fn').add()]]) 430 eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'fn').get()]])) 431 eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) 432 433 exec_lua [[ 434 vim.cmd "tabnew" 435 ]] 436 437 eq(NIL, fn.luaeval 'vim.t.testing') 438 eq(NIL, fn.luaeval 'vim.t.other') 439 eq(NIL, fn.luaeval 'vim.t.nonexistent') 440 end) 441 442 it('vim.env', function() 443 exec_lua([[vim.fn.setenv('A', 123)]]) 444 eq('123', fn.luaeval('vim.env.A')) 445 exec_lua([[vim.env.A = 456]]) 446 eq('456', fn.luaeval('vim.env.A')) 447 exec_lua([[vim.env.A = nil]]) 448 eq(NIL, fn.luaeval('vim.env.A')) 449 450 eq(true, fn.luaeval('vim.env.B == nil')) 451 452 command([[let $HOME = 'foo']]) 453 eq('foo', fn.expand('~')) 454 eq('foo', fn.luaeval('vim.env.HOME')) 455 exec_lua([[vim.env.HOME = nil]]) 456 eq('foo', fn.expand('~')) 457 exec_lua([[vim.env.HOME = 'bar']]) 458 eq('bar', fn.expand('~')) 459 eq('bar', fn.luaeval('vim.env.HOME')) 460 end) 461 462 it('vim.v', function() 463 eq(fn.luaeval "vim.api.nvim_get_vvar('progpath')", fn.luaeval 'vim.v.progpath') 464 eq(false, fn.luaeval "vim.v['false']") 465 eq(NIL, fn.luaeval 'vim.v.null') 466 matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath')) 467 matches('Key is read%-only: count$', pcall_err(exec_lua, [[vim.v.count = 42]])) 468 matches('Dict is locked$', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) 469 matches('Key is fixed: errmsg$', pcall_err(exec_lua, [[vim.v.errmsg = nil]])) 470 exec_lua([[vim.v.errmsg = 'set by Lua']]) 471 eq('set by Lua', eval('v:errmsg')) 472 exec_lua([[vim.v.errmsg = 42]]) 473 eq('42', eval('v:errmsg')) 474 exec_lua([[vim.v.oldfiles = { 'one', 'two' }]]) 475 eq({ 'one', 'two' }, eval('v:oldfiles')) 476 exec_lua([[vim.v.oldfiles = {}]]) 477 eq({}, eval('v:oldfiles')) 478 matches( 479 'Setting v:oldfiles to value with wrong type$', 480 pcall_err(exec_lua, [[vim.v.oldfiles = 'a']]) 481 ) 482 eq({}, eval('v:oldfiles')) 483 484 feed('i foo foo foo<Esc>0/foo<CR>') 485 eq({ 1, 1 }, api.nvim_win_get_cursor(0)) 486 eq(1, eval('v:searchforward')) 487 feed('n') 488 eq({ 1, 5 }, api.nvim_win_get_cursor(0)) 489 exec_lua([[vim.v.searchforward = 0]]) 490 eq(0, eval('v:searchforward')) 491 feed('n') 492 eq({ 1, 1 }, api.nvim_win_get_cursor(0)) 493 exec_lua([[vim.v.searchforward = 1]]) 494 eq(1, eval('v:searchforward')) 495 feed('n') 496 eq({ 1, 5 }, api.nvim_win_get_cursor(0)) 497 498 local screen = Screen.new(60, 3) 499 eq(1, eval('v:hlsearch')) 500 screen:expect { 501 grid = [[ 502 {10:foo} {10:^foo} {10:foo} | 503 {1:~ }| 504 | 505 ]], 506 } 507 exec_lua([[vim.v.hlsearch = 0]]) 508 eq(0, eval('v:hlsearch')) 509 screen:expect { 510 grid = [[ 511 foo ^foo foo | 512 {1:~ }| 513 | 514 ]], 515 } 516 exec_lua([[vim.v.hlsearch = 1]]) 517 eq(1, eval('v:hlsearch')) 518 screen:expect { 519 grid = [[ 520 {10:foo} {10:^foo} {10:foo} | 521 {1:~ }| 522 | 523 ]], 524 } 525 end) 526 end) 527 528 describe('options', function() 529 describe('vim.bo', function() 530 it('can get and set options', function() 531 eq('', fn.luaeval 'vim.bo.filetype') 532 exec_lua(function() 533 _G.BUF = vim.api.nvim_create_buf(false, true) 534 vim.api.nvim_set_option_value('filetype', 'markdown', {}) 535 vim.api.nvim_set_option_value('modifiable', false, { buf = _G.BUF }) 536 end) 537 eq(false, fn.luaeval 'vim.bo.modified') 538 eq('markdown', fn.luaeval 'vim.bo.filetype') 539 eq(false, fn.luaeval 'vim.bo[BUF].modifiable') 540 exec_lua(function() 541 vim.bo.filetype = '' 542 vim.bo[_G.BUF].modifiable = true 543 end) 544 eq('', fn.luaeval 'vim.bo.filetype') 545 eq(true, fn.luaeval 'vim.bo[BUF].modifiable') 546 end) 547 548 it('errors', function() 549 matches("Unknown option 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) 550 matches('Expected Lua string$', pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) 551 matches('Invalid buffer id: %-1$', pcall_err(exec_lua, 'return vim.bo[-1].filetype')) 552 end) 553 end) 554 555 describe('vim.wo', function() 556 it('can get and set options', function() 557 exec_lua(function() 558 vim.api.nvim_set_option_value('cole', 2, {}) 559 vim.cmd 'split' 560 vim.api.nvim_set_option_value('cole', 2, {}) 561 end) 562 eq(2, fn.luaeval 'vim.wo.cole') 563 exec_lua(function() 564 vim.wo.conceallevel = 0 565 end) 566 eq(0, fn.luaeval 'vim.wo.cole') 567 eq(0, fn.luaeval 'vim.wo[0].cole') 568 eq(0, fn.luaeval 'vim.wo[1001].cole') 569 matches("Unknown option 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) 570 matches('Invalid window id: %-1$', pcall_err(exec_lua, 'return vim.wo[-1].list')) 571 eq(2, fn.luaeval 'vim.wo[1000].cole') 572 exec_lua(function() 573 vim.wo[1000].cole = 0 574 end) 575 eq(0, fn.luaeval 'vim.wo[1000].cole') 576 577 -- Can handle global-local values 578 exec_lua [[vim.o.scrolloff = 100]] 579 exec_lua [[vim.wo.scrolloff = 200]] 580 eq(200, fn.luaeval 'vim.wo.scrolloff') 581 exec_lua [[vim.wo.scrolloff = -1]] 582 eq(100, fn.luaeval 'vim.wo.scrolloff') 583 exec_lua(function() 584 vim.wo[0][0].scrolloff = 200 585 vim.cmd 'enew' 586 end) 587 eq(100, fn.luaeval 'vim.wo.scrolloff') 588 end) 589 590 it('errors', function() 591 matches('only bufnr=0 is supported', pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"')) 592 matches( 593 'only bufnr=0 is supported', 594 pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn') 595 ) 596 end) 597 end) 598 599 describe('vim.opt', function() 600 -- TODO: We still need to write some tests for optlocal, opt and then getting the options 601 -- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same. 602 603 it('allows setting number values', function() 604 local scrolloff = exec_lua [[ 605 vim.opt.scrolloff = 10 606 return vim.o.scrolloff 607 ]] 608 eq(10, scrolloff) 609 end) 610 611 pending('handles STUPID window things', function() 612 eq_exec_lua({}, function() 613 return { 614 vim.api.nvim_get_option_value('scrolloff', { scope = 'global' }), 615 vim.api.nvim_get_option_value('scrolloff', { win = 0 }), 616 } 617 end) 618 end) 619 620 it('allows setting tables', function() 621 eq_exec_lua('hello,world', function() 622 vim.opt.wildignore = { 'hello', 'world' } 623 return vim.o.wildignore 624 end) 625 end) 626 627 it('allows setting tables with shortnames', function() 628 eq_exec_lua('hello,world', function() 629 vim.opt.wig = { 'hello', 'world' } 630 return vim.o.wildignore 631 end) 632 end) 633 634 it('errors when you attempt to set string values to numeric options', function() 635 eq_exec_lua(false, function() 636 return ({ 637 pcall(function() 638 vim.opt.textwidth = 'hello world' 639 end), 640 })[1] 641 end) 642 end) 643 644 it('errors when you attempt to setlocal a global value', function() 645 eq_exec_lua(false, function() 646 return pcall(function() 647 vim.opt_local.clipboard = 'hello' 648 end) 649 end) 650 end) 651 652 it('allows you to set boolean values', function() 653 eq_exec_lua({ true, false, true }, function() 654 local results = {} 655 656 vim.opt.autoindent = true 657 table.insert(results, vim.bo.autoindent) 658 659 vim.opt.autoindent = false 660 table.insert(results, vim.bo.autoindent) 661 662 vim.opt.autoindent = not vim.opt.autoindent:get() 663 table.insert(results, vim.bo.autoindent) 664 665 return results 666 end) 667 end) 668 669 it('changes current buffer values and defaults for global local values', function() 670 local result = exec_lua(function() 671 local result = {} 672 673 vim.opt.makeprg = 'global-local' 674 table.insert(result, vim.go.makeprg) 675 table.insert(result, vim.api.nvim_get_option_value('makeprg', { buf = 0 })) 676 677 vim.opt_local.mp = 'only-local' 678 table.insert(result, vim.go.makeprg) 679 table.insert(result, vim.api.nvim_get_option_value('makeprg', { buf = 0 })) 680 681 vim.opt_global.makeprg = 'only-global' 682 table.insert(result, vim.go.makeprg) 683 table.insert(result, vim.api.nvim_get_option_value('makeprg', { buf = 0 })) 684 685 vim.opt.makeprg = 'global-local' 686 table.insert(result, vim.go.makeprg) 687 table.insert(result, vim.api.nvim_get_option_value('makeprg', { buf = 0 })) 688 return result 689 end) 690 691 -- Set -> global & local 692 eq('global-local', result[1]) 693 eq('', result[2]) 694 695 -- Setlocal -> only local 696 eq('global-local', result[3]) 697 eq('only-local', result[4]) 698 699 -- Setglobal -> only global 700 eq('only-global', result[5]) 701 eq('only-local', result[6]) 702 703 -- Set -> sets global value and resets local value 704 eq('global-local', result[7]) 705 eq('', result[8]) 706 end) 707 708 it('allows you to retrieve window opts even if they have not been set', function() 709 eq_exec_lua({ false, false, true, true }, function() 710 local result = {} 711 table.insert(result, vim.opt.number:get()) 712 table.insert(result, vim.opt_local.number:get()) 713 714 vim.opt_local.number = true 715 table.insert(result, vim.opt.number:get()) 716 table.insert(result, vim.opt_local.number:get()) 717 718 return result 719 end) 720 end) 721 722 it('allows all sorts of string manipulation', function() 723 eq_exec_lua({ 'hello', 'hello world', 'start hello world' }, function() 724 local results = {} 725 726 vim.opt.makeprg = 'hello' 727 table.insert(results, vim.o.makeprg) 728 729 vim.opt.makeprg = vim.opt.makeprg + ' world' 730 table.insert(results, vim.o.makeprg) 731 732 vim.opt.makeprg = vim.opt.makeprg ^ 'start ' 733 table.insert(results, vim.o.makeprg) 734 735 return results 736 end) 737 end) 738 739 describe('option:get()', function() 740 it('works for boolean values', function() 741 eq_exec_lua(false, function() 742 vim.opt.number = false 743 return vim.opt.number:get() 744 end) 745 end) 746 747 it('works for number values', function() 748 eq_exec_lua(10, function() 749 vim.opt.tabstop = 10 750 return vim.opt.tabstop:get() 751 end) 752 end) 753 754 it('works for string values', function() 755 eq_exec_lua('hello world', function() 756 vim.opt.makeprg = 'hello world' 757 return vim.opt.makeprg:get() 758 end) 759 end) 760 761 it('works for set type flaglists', function() 762 local formatoptions = exec_lua(function() 763 vim.opt.formatoptions = 'tcro' 764 return vim.opt.formatoptions:get() 765 end) 766 767 eq(true, formatoptions.t) 768 eq(true, not formatoptions.q) 769 end) 770 771 it('works for set type flaglists', function() 772 local formatoptions = exec_lua(function() 773 vim.opt.formatoptions = { t = true, c = true, r = true, o = true } 774 return vim.opt.formatoptions:get() 775 end) 776 777 eq(true, formatoptions.t) 778 eq(true, not formatoptions.q) 779 end) 780 781 it('works for array list type options', function() 782 local wildignore = exec_lua(function() 783 vim.opt.wildignore = '*.c,*.o,__pycache__' 784 return vim.opt.wildignore:get() 785 end) 786 787 eq(3, #wildignore) 788 eq('*.c', wildignore[1]) 789 end) 790 791 it('works for options that are both commalist and flaglist', function() 792 eq_exec_lua({ b = true, s = true }, function() 793 vim.opt.whichwrap = 'b,s' 794 return vim.opt.whichwrap:get() 795 end) 796 797 eq_exec_lua({ b = true, h = true }, function() 798 vim.opt.whichwrap = { b = true, s = false, h = true } 799 return vim.opt.whichwrap:get() 800 end) 801 end) 802 803 it('works for key-value pair options', function() 804 eq_exec_lua({ tab = '> ', space = '_' }, function() 805 vim.opt.listchars = 'tab:> ,space:_' 806 return vim.opt.listchars:get() 807 end) 808 end) 809 810 it('allows you to add numeric options', function() 811 eq_exec_lua(16, function() 812 vim.opt.tabstop = 12 813 vim.opt.tabstop = vim.opt.tabstop + 4 814 return vim.bo.tabstop 815 end) 816 end) 817 818 it('allows you to subtract numeric options', function() 819 eq_exec_lua(2, function() 820 vim.opt.tabstop = 4 821 vim.opt.tabstop = vim.opt.tabstop - 2 822 return vim.bo.tabstop 823 end) 824 end) 825 end) 826 827 describe('key:value style options', function() 828 it('handles dict style', function() 829 eq_exec_lua('eol:~,space:.', function() 830 vim.opt.listchars = { eol = '~', space = '.' } 831 return vim.o.listchars 832 end) 833 end) 834 835 it('allows adding dict style', function() 836 eq_exec_lua('eol:~,space:-', function() 837 vim.opt.listchars = { eol = '~', space = '.' } 838 vim.opt.listchars = vim.opt.listchars + { space = '-' } 839 return vim.o.listchars 840 end) 841 end) 842 843 it('allows adding dict style', function() 844 eq_exec_lua('eol:~,space:_', function() 845 vim.opt.listchars = { eol = '~', space = '.' } 846 vim.opt.listchars = vim.opt.listchars + { space = '-' } + { space = '_' } 847 return vim.o.listchars 848 end) 849 end) 850 851 it('allows completely new keys', function() 852 eq_exec_lua('eol:~,space:.,tab:>>>', function() 853 vim.opt.listchars = { eol = '~', space = '.' } 854 vim.opt.listchars = vim.opt.listchars + { tab = '>>>' } 855 return vim.o.listchars 856 end) 857 end) 858 859 it('allows subtracting dict style', function() 860 eq_exec_lua('eol:~', function() 861 vim.opt.listchars = { eol = '~', space = '.' } 862 vim.opt.listchars = vim.opt.listchars - 'space' 863 return vim.o.listchars 864 end) 865 end) 866 867 it('allows subtracting dict style', function() 868 eq_exec_lua('', function() 869 vim.opt.listchars = { eol = '~', space = '.' } 870 vim.opt.listchars = vim.opt.listchars - 'space' - 'eol' 871 return vim.o.listchars 872 end) 873 end) 874 875 it('allows subtracting dict style multiple times', function() 876 eq_exec_lua('eol:~', function() 877 vim.opt.listchars = { eol = '~', space = '.' } 878 vim.opt.listchars = vim.opt.listchars - 'space' - 'space' 879 return vim.o.listchars 880 end) 881 end) 882 883 it('allows adding a key:value string to a listchars', function() 884 eq_exec_lua('eol:~,space:.,tab:>~', function() 885 vim.opt.listchars = { eol = '~', space = '.' } 886 vim.opt.listchars = vim.opt.listchars + 'tab:>~' 887 return vim.o.listchars 888 end) 889 end) 890 891 it('allows prepending a key:value string to a listchars', function() 892 eq_exec_lua('eol:~,space:.,tab:>~', function() 893 vim.opt.listchars = { eol = '~', space = '.' } 894 vim.opt.listchars = vim.opt.listchars ^ 'tab:>~' 895 return vim.o.listchars 896 end) 897 end) 898 end) 899 900 it('automatically sets when calling remove', function() 901 eq_exec_lua('foo,baz', function() 902 vim.opt.wildignore = 'foo,bar,baz' 903 vim.opt.wildignore:remove('bar') 904 return vim.o.wildignore 905 end) 906 end) 907 908 it('automatically sets when calling remove with a table', function() 909 eq_exec_lua('foo', function() 910 vim.opt.wildignore = 'foo,bar,baz' 911 vim.opt.wildignore:remove { 'bar', 'baz' } 912 return vim.o.wildignore 913 end) 914 end) 915 916 it('automatically sets when calling append', function() 917 eq_exec_lua('foo,bar,baz,bing', function() 918 vim.opt.wildignore = 'foo,bar,baz' 919 vim.opt.wildignore:append('bing') 920 return vim.o.wildignore 921 end) 922 end) 923 924 it('automatically sets when calling append with a table', function() 925 eq_exec_lua('foo,bar,baz,bing,zap', function() 926 vim.opt.wildignore = 'foo,bar,baz' 927 vim.opt.wildignore:append { 'bing', 'zap' } 928 return vim.o.wildignore 929 end) 930 end) 931 932 it('allows adding tables', function() 933 eq_exec_lua('foo', function() 934 vim.opt.wildignore = 'foo' 935 return vim.o.wildignore 936 end) 937 938 eq_exec_lua('foo,bar,baz', function() 939 vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } 940 return vim.o.wildignore 941 end) 942 end) 943 944 it('handles adding duplicates', function() 945 eq_exec_lua('foo', function() 946 vim.opt.wildignore = 'foo' 947 return vim.o.wildignore 948 end) 949 950 eq_exec_lua('foo,bar,baz', function() 951 vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } 952 return vim.o.wildignore 953 end) 954 955 eq_exec_lua('foo,bar,baz', function() 956 vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } 957 return vim.o.wildignore 958 end) 959 end) 960 961 it('allows adding multiple times', function() 962 eq_exec_lua('foo,bar,baz', function() 963 vim.opt.wildignore = 'foo' 964 vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz' 965 return vim.o.wildignore 966 end) 967 end) 968 969 it('removes values when you use minus', function() 970 eq_exec_lua('foo', function() 971 vim.opt.wildignore = 'foo' 972 return vim.o.wildignore 973 end) 974 975 eq_exec_lua('foo,bar,baz', function() 976 vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' } 977 return vim.o.wildignore 978 end) 979 980 eq_exec_lua('foo,baz', function() 981 vim.opt.wildignore = vim.opt.wildignore - 'bar' 982 return vim.o.wildignore 983 end) 984 end) 985 986 it('prepends values when using ^', function() 987 eq_exec_lua('first,foo', function() 988 vim.opt.wildignore = 'foo' 989 vim.opt.wildignore = vim.opt.wildignore ^ 'first' 990 return vim.o.wildignore 991 end) 992 993 eq_exec_lua('super_first,first,foo', function() 994 vim.opt.wildignore = vim.opt.wildignore ^ 'super_first' 995 return vim.o.wildignore 996 end) 997 end) 998 999 it('does not remove duplicates from wildmode: #14708', function() 1000 eq_exec_lua('full,list,full', function() 1001 vim.opt.wildmode = { 'full', 'list', 'full' } 1002 return vim.o.wildmode 1003 end) 1004 end) 1005 1006 describe('option types', function() 1007 it('allows to set option with numeric value', function() 1008 eq_exec_lua(4, function() 1009 vim.opt.tabstop = 4 1010 return vim.bo.tabstop 1011 end) 1012 1013 matches( 1014 "Invalid option type 'string' for 'tabstop'", 1015 pcall_err(exec_lua, [[vim.opt.tabstop = '4']]) 1016 ) 1017 matches( 1018 "Invalid option type 'boolean' for 'tabstop'", 1019 pcall_err(exec_lua, [[vim.opt.tabstop = true]]) 1020 ) 1021 matches( 1022 "Invalid option type 'table' for 'tabstop'", 1023 pcall_err(exec_lua, [[vim.opt.tabstop = {4, 2}]]) 1024 ) 1025 matches( 1026 "Invalid option type 'function' for 'tabstop'", 1027 pcall_err(exec_lua, [[vim.opt.tabstop = function() return 4 end]]) 1028 ) 1029 end) 1030 1031 it('allows to set option with boolean value', function() 1032 eq_exec_lua(true, function() 1033 vim.opt.undofile = true 1034 return vim.bo.undofile 1035 end) 1036 1037 matches( 1038 "Invalid option type 'number' for 'undofile'", 1039 pcall_err(exec_lua, [[vim.opt.undofile = 0]]) 1040 ) 1041 matches( 1042 "Invalid option type 'table' for 'undofile'", 1043 pcall_err(exec_lua, [[vim.opt.undofile = {true}]]) 1044 ) 1045 matches( 1046 "Invalid option type 'string' for 'undofile'", 1047 pcall_err(exec_lua, [[vim.opt.undofile = 'true']]) 1048 ) 1049 matches( 1050 "Invalid option type 'function' for 'undofile'", 1051 pcall_err(exec_lua, [[vim.opt.undofile = function() return true end]]) 1052 ) 1053 end) 1054 1055 it('allows to set option with array or string value', function() 1056 eq_exec_lua('indent,eol,start', function() 1057 vim.opt.backspace = { 'indent', 'eol', 'start' } 1058 return vim.go.backspace 1059 end) 1060 1061 eq_exec_lua('indent,eol,start', function() 1062 vim.opt.backspace = 'indent,eol,start' 1063 return vim.go.backspace 1064 end) 1065 1066 matches( 1067 "Invalid option type 'boolean' for 'backspace'", 1068 pcall_err(exec_lua, [[vim.opt.backspace = true]]) 1069 ) 1070 matches( 1071 "Invalid option type 'number' for 'backspace'", 1072 pcall_err(exec_lua, [[vim.opt.backspace = 2]]) 1073 ) 1074 matches( 1075 "Invalid option type 'function' for 'backspace'", 1076 pcall_err(exec_lua, [[vim.opt.backspace = function() return 'indent,eol,start' end]]) 1077 ) 1078 end) 1079 1080 it('allows set option with map or string value', function() 1081 eq_exec_lua('eol:~,space:.', function() 1082 vim.opt.listchars = { eol = '~', space = '.' } 1083 return vim.o.listchars 1084 end) 1085 1086 eq_exec_lua('eol:~,space:.,tab:>~', function() 1087 vim.opt.listchars = 'eol:~,space:.,tab:>~' 1088 return vim.o.listchars 1089 end) 1090 1091 matches( 1092 "Invalid option type 'boolean' for 'listchars'", 1093 pcall_err(exec_lua, [[vim.opt.listchars = true]]) 1094 ) 1095 matches( 1096 "Invalid option type 'number' for 'listchars'", 1097 pcall_err(exec_lua, [[vim.opt.listchars = 2]]) 1098 ) 1099 matches( 1100 "Invalid option type 'function' for 'listchars'", 1101 pcall_err( 1102 exec_lua, 1103 [[vim.opt.listchars = function() return "eol:~,space:.,tab:>~" end]] 1104 ) 1105 ) 1106 end) 1107 1108 it('allows set option with set or string value', function() 1109 eq_exec_lua('b,s', function() 1110 vim.opt.whichwrap = { b = true, s = 1 } 1111 return vim.go.whichwrap 1112 end) 1113 1114 eq_exec_lua('b,s,<,>,[,]', function() 1115 vim.opt.whichwrap = 'b,s,<,>,[,]' 1116 return vim.go.whichwrap 1117 end) 1118 1119 matches( 1120 "Invalid option type 'boolean' for 'whichwrap'", 1121 pcall_err(exec_lua, [[vim.opt.whichwrap = true]]) 1122 ) 1123 matches( 1124 "Invalid option type 'number' for 'whichwrap'", 1125 pcall_err(exec_lua, [[vim.opt.whichwrap = 2]]) 1126 ) 1127 matches( 1128 "Invalid option type 'function' for 'whichwrap'", 1129 pcall_err(exec_lua, [[vim.opt.whichwrap = function() return "b,s,<,>,[,]" end]]) 1130 ) 1131 end) 1132 end) 1133 1134 -- isfname=a,b,c,,,d,e,f 1135 it('can handle isfname ,,,', function() 1136 eq_exec_lua({ { ',', 'a', 'b', 'c' }, 'a,b,,,c' }, function() 1137 vim.opt.isfname = 'a,b,,,c' 1138 return { vim.opt.isfname:get(), vim.go.isfname } 1139 end) 1140 end) 1141 1142 -- isfname=a,b,c,^,,def 1143 it('can handle isfname ,^,,', function() 1144 eq_exec_lua({ { '^,', 'a', 'b', 'c' }, 'a,b,^,,c' }, function() 1145 vim.opt.isfname = 'a,b,^,,c' 1146 return { vim.opt.isfname:get(), vim.go.isfname } 1147 end) 1148 end) 1149 1150 describe('https://github.com/neovim/neovim/issues/14828', function() 1151 it('gives empty list when item is empty:array', function() 1152 eq_exec_lua({}, function() 1153 vim.cmd('set wildignore=') 1154 return vim.opt.wildignore:get() 1155 end) 1156 1157 eq_exec_lua({}, function() 1158 vim.opt.wildignore = {} 1159 return vim.opt.wildignore:get() 1160 end) 1161 end) 1162 1163 it('gives empty list when item is empty:set', function() 1164 eq_exec_lua({}, function() 1165 vim.cmd('set formatoptions=') 1166 return vim.opt.formatoptions:get() 1167 end) 1168 1169 eq_exec_lua({}, function() 1170 vim.opt.formatoptions = {} 1171 return vim.opt.formatoptions:get() 1172 end) 1173 end) 1174 1175 it('does not append to empty item', function() 1176 eq_exec_lua({ '*.foo', '*.bar' }, function() 1177 vim.opt.wildignore = {} 1178 vim.opt.wildignore:append { '*.foo', '*.bar' } 1179 return vim.opt.wildignore:get() 1180 end) 1181 end) 1182 1183 it('does not prepend to empty item', function() 1184 eq_exec_lua({ '*.foo', '*.bar' }, function() 1185 vim.opt.wildignore = {} 1186 vim.opt.wildignore:prepend { '*.foo', '*.bar' } 1187 return vim.opt.wildignore:get() 1188 end) 1189 end) 1190 1191 it('append to empty set', function() 1192 eq_exec_lua({ t = true }, function() 1193 vim.opt.formatoptions = {} 1194 vim.opt.formatoptions:append('t') 1195 return vim.opt.formatoptions:get() 1196 end) 1197 end) 1198 1199 it('prepend to empty set', function() 1200 eq_exec_lua({ t = true }, function() 1201 vim.opt.formatoptions = {} 1202 vim.opt.formatoptions:prepend('t') 1203 return vim.opt.formatoptions:get() 1204 end) 1205 end) 1206 end) 1207 end) -- vim.opt 1208 1209 describe('vim.opt_local', function() 1210 it('appends into global value when changing local option value', function() 1211 eq_exec_lua('foo,bar,baz,qux', function() 1212 vim.opt.tags = 'foo,bar' 1213 vim.opt_local.tags:append('baz') 1214 vim.opt_local.tags:append('qux') 1215 return vim.bo.tags 1216 end) 1217 end) 1218 end) 1219 1220 describe('vim.opt_global', function() 1221 it('gets current global option value', function() 1222 eq_exec_lua({ 'yes' }, function() 1223 vim.cmd 'setglobal signcolumn=yes' 1224 return { vim.opt_global.signcolumn:get() } 1225 end) 1226 end) 1227 end) 1228 end) 1229 end)