aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/api/highlight_spec.lua95
-rw-r--r--test/functional/api/vim_spec.lua4
-rw-r--r--test/functional/api/window_spec.lua46
-rw-r--r--test/functional/core/job_spec.lua26
-rw-r--r--test/functional/core/startup_spec.lua70
-rw-r--r--test/functional/eval/null_spec.lua5
-rw-r--r--test/functional/ex_cmds/source_spec.lua46
-rw-r--r--test/functional/fixtures/streams-test.c17
-rw-r--r--test/functional/helpers.lua5
-rw-r--r--test/functional/legacy/011_autocommands_spec.lua9
-rw-r--r--test/functional/legacy/mksession_spec.lua42
-rw-r--r--test/functional/legacy/packadd_spec.lua12
-rw-r--r--test/functional/lua/buffer_updates_spec.lua73
-rw-r--r--test/functional/lua/runtime_spec.lua141
-rw-r--r--test/functional/lua/vim_spec.lua502
-rw-r--r--test/functional/plugin/health_spec.lua2
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua62
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua33
-rw-r--r--test/functional/plugin/lsp_spec.lua142
-rw-r--r--test/functional/treesitter/parser_spec.lua146
-rw-r--r--test/functional/ui/decorations_spec.lua131
-rw-r--r--test/functional/ui/float_spec.lua245
-rw-r--r--test/functional/ui/messages_spec.lua4
-rw-r--r--test/functional/ui/screen.lua29
-rw-r--r--test/functional/ui/spell_spec.lua3
25 files changed, 1734 insertions, 156 deletions
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 058706718a..21e3094f8e 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -158,3 +158,98 @@ describe('API: highlight',function()
assert_alive()
end)
end)
+
+describe("API: set highlight", function()
+ local highlight_color = {
+ fg = tonumber('0xff0000'),
+ bg = tonumber('0x0032aa'),
+ ctermfg = 8,
+ ctermbg = 15,
+ }
+ local highlight1 = {
+ background = highlight_color.bg,
+ foreground = highlight_color.fg,
+ bold = true,
+ italic = true,
+ }
+ local highlight2_config = {
+ ctermbg = highlight_color.ctermbg,
+ ctermfg = highlight_color.ctermfg,
+ underline = true,
+ reverse = true,
+ }
+ local highlight2_result = {
+ background = highlight_color.ctermbg,
+ foreground = highlight_color.ctermfg,
+ underline = true,
+ reverse = true,
+ }
+ local highlight3_config = {
+ background = highlight_color.bg,
+ foreground = highlight_color.fg,
+ ctermbg = highlight_color.ctermbg,
+ ctermfg = highlight_color.ctermfg,
+ bold = true,
+ italic = true,
+ reverse = true,
+ undercurl = true,
+ underline = true,
+ cterm = {
+ italic = true,
+ reverse = true,
+ undercurl = true,
+ }
+ }
+ local highlight3_result_gui = {
+ background = highlight_color.bg,
+ foreground = highlight_color.fg,
+ bold = true,
+ italic = true,
+ reverse = true,
+ undercurl = true,
+ underline = true,
+ }
+ local highlight3_result_cterm = {
+ background = highlight_color.ctermbg,
+ foreground = highlight_color.ctermfg,
+ italic = true,
+ reverse = true,
+ undercurl = true,
+ }
+
+ local function get_ns()
+ local ns = meths.create_namespace('Test_set_hl')
+ meths._set_hl_ns(ns)
+ return ns
+ end
+
+ before_each(clear)
+
+ it ("can set gui highlight", function()
+ local ns = get_ns()
+ meths.set_hl(ns, 'Test_hl', highlight1)
+ eq(highlight1, meths.get_hl_by_name('Test_hl', true))
+ end)
+
+ it ("can set cterm highlight", function()
+ local ns = get_ns()
+ meths.set_hl(ns, 'Test_hl', highlight2_config)
+ eq(highlight2_result, meths.get_hl_by_name('Test_hl', false))
+ end)
+
+ it ("cterm attr defaults to gui attr", function()
+ local ns = get_ns()
+ meths.set_hl(ns, 'Test_hl', highlight1)
+ eq({
+ bold = true,
+ italic = true,
+ }, meths.get_hl_by_name('Test_hl', false))
+ end)
+
+ it ("can overwrite attr for cterm", function()
+ local ns = get_ns()
+ meths.set_hl(ns, 'Test_hl', highlight3_config)
+ eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true))
+ eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false))
+ end)
+end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 6926022ee3..0c0f610401 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1986,6 +1986,10 @@ describe('API', function()
eq(meths.get_option_info'winhighlight', options_info.winhighlight)
end)
+
+ it('should not crash when echoed', function()
+ meths.exec("echo nvim_get_all_options_info()", true)
+ end)
end)
describe('nvim_get_option_info', function()
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index ceeb84cec9..bb72b63b6c 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -387,4 +387,50 @@ describe('API/win', function()
eq({oldbuf}, meths.list_bufs())
end)
end)
+
+ describe('open_win', function()
+ it('noautocmd option works', function()
+ command('autocmd BufEnter,BufLeave,BufWinEnter * let g:fired = 1')
+ meths.open_win(meths.create_buf(true, true), true, {
+ relative='win', row=3, col=3, width=12, height=3, noautocmd=true
+ })
+ eq(0, funcs.exists('g:fired'))
+ meths.open_win(meths.create_buf(true, true), true, {
+ relative='win', row=3, col=3, width=12, height=3
+ })
+ eq(1, funcs.exists('g:fired'))
+ end)
+ end)
+
+ describe('get_config', function()
+ it('includes border', function()
+ local b = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' }
+ local win = meths.open_win(0, true, {
+ relative='win', row=3, col=3, width=12, height=3,
+ border = b,
+ })
+
+ local cfg = meths.win_get_config(win)
+ eq(b, cfg.border)
+ end)
+ it('includes border with highlight group', function()
+ local b = {
+ {'a', 'Normal'},
+ {'b', 'Special'},
+ {'c', 'String'},
+ {'d', 'Comment'},
+ {'e', 'Visual'},
+ {'f', 'Error'},
+ {'g', 'Constant'},
+ {'h', 'PreProc'},
+ }
+ local win = meths.open_win(0, true, {
+ relative='win', row=3, col=3, width=12, height=3,
+ border = b,
+ })
+
+ local cfg = meths.win_get_config(win)
+ eq(b, cfg.border)
+ end)
+ end)
end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 9de0d08e79..34ab90d760 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -118,6 +118,32 @@ describe('jobs', function()
end
end)
+ it('handles case-insensitively matching #env vars', function()
+ nvim('command', "let $TOTO = 'abc'")
+ -- Since $Toto is being set in the job, it should take precedence over the
+ -- global $TOTO on Windows
+ nvim('command', "let g:job_opts = {'env': {'Toto': 'def'}, 'stdout_buffered': v:true}")
+ if iswin() then
+ nvim('command', [[let j = jobstart('set | find /I "toto="', g:job_opts)]])
+ else
+ nvim('command', [[let j = jobstart('env | grep -i toto=', g:job_opts)]])
+ end
+ nvim('command', "call jobwait([j])")
+ nvim('command', "let g:output = Normalize(g:job_opts.stdout)")
+ local actual = eval('g:output')
+ local expected
+ if iswin() then
+ -- Toto is normalized to TOTO so we can detect duplicates, and because
+ -- Windows doesn't care about case
+ expected = {'TOTO=def', ''}
+ else
+ expected = {'TOTO=abc', 'Toto=def', ''}
+ end
+ table.sort(actual)
+ table.sort(expected)
+ eq(expected, actual)
+ end)
+
it('uses &shell and &shellcmdflag if passed a string', function()
nvim('command', "let $VAR = 'abc'")
if iswin() then
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index d5f03db03a..658dfbda60 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -11,6 +11,7 @@ local exec_lua = helpers.exec_lua
local feed = helpers.feed
local funcs = helpers.funcs
local mkdir = helpers.mkdir
+local mkdir_p = helpers.mkdir_p
local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local read_file = helpers.read_file
@@ -494,6 +495,75 @@ describe('user config init', function()
end)
end)
+describe('runtime:', function()
+ local xhome = 'Xhome'
+ local pathsep = helpers.get_pathsep()
+ local xconfig = xhome .. pathsep .. 'Xconfig'
+
+ setup(function()
+ mkdir_p(xconfig .. pathsep .. 'nvim')
+ end)
+
+ teardown(function()
+ rmdir(xhome)
+ end)
+
+ it('loads plugin/*.lua from XDG config home', function()
+ local plugin_folder_path = table.concat({xconfig, 'nvim', 'plugin'}, pathsep)
+ local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'}, pathsep)
+ mkdir_p(plugin_folder_path)
+ write_file(plugin_file_path, [[ vim.g.lua_plugin = 1 ]])
+
+ clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig }}
+
+ eq(1, eval('g:lua_plugin'))
+ rmdir(plugin_folder_path)
+ end)
+
+ it('loads plugin/*.lua from start plugins', function()
+ local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'catagory',
+ 'start', 'test_plugin'}, pathsep)
+ local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep)
+ local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'},
+ pathsep)
+ local profiler_file = 'test_startuptime.log'
+
+ mkdir_p(plugin_folder_path)
+ write_file(plugin_file_path, [[vim.g.lua_plugin = 2]])
+
+ clear{ args_rm={'-u'}, args={'--startuptime', profiler_file}, env={ XDG_CONFIG_HOME=xconfig }}
+
+ eq(2, eval('g:lua_plugin'))
+ -- Check if plugin_file_path is listed in :scriptname
+ local scripts = meths.exec(':scriptnames', true)
+ assert.Truthy(scripts:find(plugin_file_path))
+
+ -- Check if plugin_file_path is listed in startup profile
+ local profile_reader = io.open(profiler_file, 'r')
+ local profile_log = profile_reader:read('*a')
+ profile_reader:close()
+ assert.Truthy(profile_log :find(plugin_file_path))
+
+ os.remove(profiler_file)
+ rmdir(plugin_path)
+ end)
+
+ it('loads ftdetect/*.lua', function()
+ local ftdetect_folder = table.concat({xconfig, 'nvim', 'ftdetect'}, pathsep)
+ local ftdetect_file = table.concat({ftdetect_folder , 'new-ft.lua'}, pathsep)
+ mkdir_p(ftdetect_folder)
+ write_file(ftdetect_file , [[vim.g.lua_ftdetect = 1]])
+
+ -- TODO(shadmansaleh): Figure out why this test fails without
+ -- setting VIMRUNTIME
+ clear{ args_rm={'-u'}, env={XDG_CONFIG_HOME=xconfig,
+ VIMRUNTIME='runtime/'}}
+
+ eq(1, eval('g:lua_ftdetect'))
+ rmdir(ftdetect_folder)
+ end)
+end)
+
describe('user session', function()
local xhome = 'Xhome'
local pathsep = helpers.get_pathsep()
diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua
index d403fbc878..b1ceff9115 100644
--- a/test/functional/eval/null_spec.lua
+++ b/test/functional/eval/null_spec.lua
@@ -73,6 +73,7 @@ describe('NULL', function()
null_expr_test('does not crash col()', 'col(L)', 0, 0)
null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
null_expr_test('does not crash line()', 'line(L)', 0, 0)
+ null_expr_test('does not crash line() with window id', 'line(L, 1000)', 0, 0)
null_expr_test('does not crash count()', 'count(L, 1)', 0, 0)
null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1)
null_expr_test('does not crash map()', 'map(L, "v:val")', 0, {})
@@ -96,7 +97,7 @@ describe('NULL', function()
null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1)
null_test('is treated by :let as empty list', ':let [l] = L', 'Vim(let):E688: More targets than List items')
null_expr_test('is accepted as an empty list by inputlist()', '[feedkeys("\\n"), inputlist(L)]',
- 'Type number and <Enter> or click with mouse (empty cancels): ', {0, 0})
+ 'Type number and <Enter> or click with the mouse (q or empty cancels): ', {0, 0})
null_expr_test('is accepted as an empty list by writefile()',
('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname),
0, {0, {}})
@@ -149,6 +150,7 @@ describe('NULL', function()
null_test('does not crash :execute', 'execute S', 0)
null_expr_test('does not crash execute()', 'execute(S)', 0, '')
null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0)
+ null_expr_test('makes timer_start() error out', 'timer_start(0, S)', 'E921: Invalid callback argument', -1)
null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0)
null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0)
null_expr_test('does not crash fnamemodify()', 'fnamemodify(S, S)', 0, '')
@@ -161,7 +163,6 @@ describe('NULL', function()
null_expr_test('does not crash mkdir()', 'mkdir(S)', 0, 0)
null_expr_test('does not crash sort()', 'sort(["b", S, "a"])', 0, {'', 'a', 'b'})
null_expr_test('does not crash split()', 'split(S)', 0, {})
-
null_test('can be used to set an option', 'let &grepprg = S', 0)
null_expr_test('is equal to non-existent variable', 'S == V', 0, 1)
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 16d0dfb6a1..a03e1ae9ce 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -6,6 +6,9 @@ local clear = helpers.clear
local meths = helpers.meths
local feed = helpers.feed
local feed_command = helpers.feed_command
+local write_file = helpers.write_file
+local exec = helpers.exec
+local eval = helpers.eval
describe(':source', function()
before_each(function()
@@ -44,4 +47,47 @@ describe(':source', function()
command('source')
eq('4', meths.exec('echo luaeval("y")', true))
end)
+
+ it('can source lua files', function()
+ local test_file = 'test.lua'
+ write_file (test_file, [[vim.g.sourced_lua = 1]])
+
+ exec('source ' .. test_file)
+
+ eq(1, eval('g:sourced_lua'))
+ os.remove(test_file)
+ end)
+
+ it('can source selected region in lua file', function()
+ local test_file = 'test.lua'
+
+ write_file (test_file, [[
+ vim.g.b = 5
+ vim.g.b = 6
+ vim.g.b = 7
+ ]])
+
+ command('edit '..test_file)
+ feed('ggjV')
+ feed_command(':source')
+
+ eq(6, eval('g:b'))
+ os.remove(test_file)
+ end)
+
+ it('can source current lua buffer without argument', function()
+ local test_file = 'test.lua'
+
+ write_file (test_file, [[
+ vim.g.c = 10
+ vim.g.c = 11
+ vim.g.c = 12
+ ]])
+
+ command('edit '..test_file)
+ feed_command(':source')
+
+ eq(12, eval('g:c'))
+ os.remove(test_file)
+ end)
end)
diff --git a/test/functional/fixtures/streams-test.c b/test/functional/fixtures/streams-test.c
index eec447153c..be40edfe7e 100644
--- a/test/functional/fixtures/streams-test.c
+++ b/test/functional/fixtures/streams-test.c
@@ -6,23 +6,22 @@
#include <uv.h>
-uv_loop_t *loop;
-uv_process_t child_req;
-uv_process_options_t options;
-
int main(int argc, char **argv)
{
- loop = uv_default_loop();
+ uv_loop_t *loop = uv_default_loop();
+ uv_process_t child_req;
char * args[3];
args[0] = "sleep";
args[1] = "10";
args[2] = NULL;
- options.exit_cb = NULL;
- options.file = "sleep";
- options.args = args;
- options.flags = UV_PROCESS_DETACHED;
+ uv_process_options_t options = {
+ .exit_cb = NULL,
+ .file = "sleep",
+ .args = args,
+ .flags = UV_PROCESS_DETACHED,
+ };
int r;
if ((r = uv_spawn(loop, &child_req, &options))) {
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 4acb1a7d8d..08ca14c3df 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -878,6 +878,11 @@ function module.os_kill(pid)
or 'kill -9 '..pid..' > /dev/null'))
end
+-- Create directories with non exsisting intermidiate directories
+function module.mkdir_p(path)
+ return module.meths.call_function('mkdir', {path, 'p'})
+end
+
module = global_helpers.tbl_extend('error', module, global_helpers)
return function(after_each)
diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua
index 7cc31dc787..7b6f2f63e9 100644
--- a/test/functional/legacy/011_autocommands_spec.lua
+++ b/test/functional/legacy/011_autocommands_spec.lua
@@ -17,6 +17,7 @@ local lfs = require('lfs')
local clear, feed_command, expect, eq, neq, dedent, write_file, feed =
helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.neq,
helpers.dedent, helpers.write_file, helpers.feed
+local command = helpers.command
local iswin = helpers.iswin
local read_file = helpers.read_file
@@ -28,7 +29,7 @@ end
local function prepare_gz_file(name, text)
write_file(name, text..'\n')
-- Compress the file with gzip.
- os.execute('gzip --force '..name)
+ command([[call system(['gzip', '--force', ']]..name..[['])]])
-- This should create the .gz file and delete the original.
neq(nil, lfs.attributes(name..'.gz'))
eq(nil, lfs.attributes(name))
@@ -54,7 +55,9 @@ describe('file reading, writing and bufnew and filter autocommands', function()
*/
]])
end)
- before_each(clear)
+ before_each(function ()
+ clear({env={GZIP=nil}})
+ end)
teardown(function()
os.remove('Xtestfile.gz')
os.remove('Xtest.c')
@@ -67,7 +70,6 @@ describe('file reading, writing and bufnew and filter autocommands', function()
it('FileReadPost (using gzip)', function()
prepare_gz_file('Xtestfile', text1)
- feed_command('let $GZIP = ""')
--execute('au FileChangedShell * echo "caught FileChangedShell"')
feed_command('set bin')
feed_command("au FileReadPost *.gz '[,']!gzip -d")
@@ -79,7 +81,6 @@ describe('file reading, writing and bufnew and filter autocommands', function()
it('BufReadPre, BufReadPost (using gzip)', function()
prepare_gz_file('Xtestfile', text1)
local gzip_data = read_file('Xtestfile.gz')
- feed_command('let $GZIP = ""')
-- Setup autocommands to decompress before reading and re-compress afterwards.
feed_command("au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand('<afile>'))")
feed_command("au BufReadPre *.gz call rename(expand('<afile>:r'), expand('<afile>'))")
diff --git a/test/functional/legacy/mksession_spec.lua b/test/functional/legacy/mksession_spec.lua
new file mode 100644
index 0000000000..a2af891107
--- /dev/null
+++ b/test/functional/legacy/mksession_spec.lua
@@ -0,0 +1,42 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local funcs = helpers.funcs
+local eq = helpers.eq
+
+describe('mksession', function()
+ before_each(clear)
+
+ after_each(function()
+ os.remove('Xtest_mks.out')
+ end)
+
+ it('supports "skiprtp" value', function()
+ command('set sessionoptions&vi')
+ command('set rtp+=$HOME')
+ command('set pp+=$HOME')
+ command('mksession! Xtest_mks.out')
+ local found_rtp = 0
+ local found_pp = 0
+ for _, line in pairs(funcs.readfile('Xtest_mks.out', 'b')) do
+ if line:find('set runtimepath') then
+ found_rtp = found_rtp + 1
+ end
+ if line:find('set packpath') then
+ found_pp = found_pp + 1
+ end
+ end
+ eq(1, found_rtp)
+ eq(1, found_pp)
+
+ command('set sessionoptions+=skiprtp')
+ command('mksession! Xtest_mks.out')
+ local found_rtp_or_pp = 0
+ for _, line in pairs(funcs.readfile('Xtest_mks.out', 'b')) do
+ if line:find('set runtimepath') or line:find('set packpath') then
+ found_rtp_or_pp = found_rtp_or_pp + 1
+ end
+ end
+ eq(0, found_rtp_or_pp)
+ end)
+end)
diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua
index 609f825177..48cd3ef9f8 100644
--- a/test/functional/legacy/packadd_spec.lua
+++ b/test/functional/legacy/packadd_spec.lua
@@ -101,9 +101,14 @@ describe('packadd', function()
call setline(1, 'let g:plugin_works = 24')
wq
+ exe 'split ' . plugdir . '/plugin/test.lua'
+ call setline(1, 'vim.g.plugin_lua_works = 24')
+ wq
+
packadd other
call assert_equal(24, g:plugin_works)
+ call assert_equal(24, g:plugin_lua_works)
call assert_true(len(&rtp) > len(rtp))
call assert_match(Escape(plugdir) . '\($\|,\)', &rtp)
endfunc
@@ -117,13 +122,18 @@ describe('packadd', function()
exe 'split ' . s:plugdir . '/plugin/test.vim'
call setline(1, 'let g:plugin_works = 42')
wq
+ exe 'split ' . s:plugdir . '/plugin/test.lua'
+ call setline(1, 'let g:plugin_lua_works = 42')
+ wq
let g:plugin_works = 0
+ let g:plugin_lua_works = 0
packadd! mytest
call assert_true(len(&rtp) > len(rtp))
call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp)
call assert_equal(0, g:plugin_works)
+ call assert_equal(0, g:plugin_lua_works)
" check the path is not added twice
let new_rtp = &rtp
@@ -267,6 +277,8 @@ describe('packadd', function()
call assert_match('look-here', tags1[0])
let tags2 = readfile(docdir2 . '/tags')
call assert_match('look-away', tags2[0])
+
+ call assert_fails('helptags abcxyz', 'E150:')
endfunc
func Test_colorscheme()
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 5da8452a51..1b2c21783e 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -401,8 +401,8 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
feed '<cr>'
check_events {
- { "test1", "bytes", 1, 4, 8, 0, 115, 0, 4, 4, 0, 0, 0 };
- { "test1", "bytes", 1, 5, 7, 4, 118, 0, 0, 0, 1, 4, 5 };
+ { "test1", "bytes", 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 7, 0, 114, 0, 0, 0, 1, 4, 5 };
}
end)
@@ -447,8 +447,8 @@ describe('lua: nvim_buf_attach on_bytes', function()
feed '<CR>'
check_events {
- { "test1", "bytes", 1, 6, 2, 2, 16, 0, 1, 1, 0, 0, 0 };
- { "test1", "bytes", 1, 7, 1, 3, 14, 0, 0, 0, 1, 3, 4 };
+ { "test1", "bytes", 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 7, 1, 2, 13, 0, 0, 0, 1, 3, 4 };
}
end)
@@ -936,6 +936,71 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+ it("virtual edit", function ()
+ local check_events = setup_eventcheck(verify, { "", " " })
+
+ meths.set_option("virtualedit", "all")
+
+ feed [[<Right><Right>iab<ESC>]]
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 };
+ { "test1", "bytes", 1, 4, 0, 2, 2, 0, 0, 0, 0, 2, 2 };
+ }
+
+ feed [[j<Right><Right>iab<ESC>]]
+
+ check_events {
+ { "test1", "bytes", 1, 5, 1, 0, 5, 0, 1, 1, 0, 8, 8 };
+ { "test1", "bytes", 1, 6, 1, 5, 10, 0, 0, 0, 0, 2, 2 };
+ }
+ end)
+
+ it("block visual paste", function()
+ local check_events = setup_eventcheck(verify, {"AAA",
+ "BBB",
+ "CCC",
+ "DDD",
+ "EEE",
+ "FFF"})
+ funcs.setreg("a", "___")
+ feed([[gg0l<c-v>3jl"ap]])
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 2, 2, 0, 0, 0 };
+ { "test1", "bytes", 1, 3, 1, 1, 3, 0, 2, 2, 0, 0, 0 };
+ { "test1", "bytes", 1, 3, 2, 1, 5, 0, 2, 2, 0, 0, 0 };
+ { "test1", "bytes", 1, 3, 3, 1, 7, 0, 2, 2, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 };
+ { "test1", "bytes", 1, 6, 1, 1, 6, 0, 0, 0, 0, 3, 3 };
+ { "test1", "bytes", 1, 7, 2, 1, 11, 0, 0, 0, 0, 3, 3 };
+ { "test1", "bytes", 1, 8, 3, 1, 16, 0, 0, 0, 0, 3, 3 };
+ }
+ end)
+
+ it("nvim_buf_set_lines", function()
+ local check_events = setup_eventcheck(verify, {"AAA", "BBB"})
+
+ -- delete
+ meths.buf_set_lines(0, 0, 1, true, {})
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 };
+ }
+
+ -- add
+ meths.buf_set_lines(0, 0, 0, true, {'asdf'})
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 };
+ }
+
+ -- replace
+ meths.buf_set_lines(0, 0, 1, true, {'asdf', 'fdsa'})
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 };
+ }
+ end)
+
teardown(function()
os.remove "Xtest-reload"
os.remove "Xtest-undofile"
diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua
new file mode 100644
index 0000000000..e9c34c9228
--- /dev/null
+++ b/test/functional/lua/runtime_spec.lua
@@ -0,0 +1,141 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local exec = helpers.exec
+local mkdir_p = helpers.mkdir_p
+local rmdir = helpers.rmdir
+local write_file = helpers.write_file
+
+describe('runtime:', function()
+ local plug_dir = 'Test_Plugin'
+ local sep = helpers.get_pathsep()
+ local init = 'dummy_init.lua'
+
+ setup(function()
+ io.open(init, 'w'):close() -- touch init file
+ clear{args = {'-u', init}}
+ exec('set rtp+=' .. plug_dir)
+ end)
+
+ teardown(function()
+ os.remove(init)
+ end)
+
+ before_each(function()
+ mkdir_p(plug_dir)
+ end)
+
+ after_each(function()
+ rmdir(plug_dir)
+ end)
+
+ describe('colors', function()
+ local colorscheme_folder = plug_dir .. sep .. 'colors'
+
+ it('loads lua colorscheme', function()
+ local colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme.lua'
+ mkdir_p(colorscheme_folder)
+ write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]])
+
+ exec('colorscheme new_colorscheme')
+
+ eq(1, eval('g:lua_colorscheme'))
+ rmdir(colorscheme_folder)
+ end)
+
+ it('loads vim colorscheme when both lua and vim version exist', function()
+ local colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme'
+ mkdir_p(colorscheme_folder)
+ write_file(colorscheme_file..'.vim', [[let g:colorscheme = 'vim']])
+ write_file(colorscheme_file..'.lua', [[vim.g.colorscheme = 'lua']])
+
+ exec('colorscheme new_colorscheme')
+
+ eq('vim', eval('g:colorscheme'))
+ rmdir(colorscheme_folder)
+ end)
+ end)
+
+ describe('compiler', function()
+ local compiler_folder = plug_dir .. sep .. 'compiler'
+
+ it('loads lua compilers', function()
+ local compiler_file = compiler_folder .. sep .. 'new_compiler.lua'
+ mkdir_p(compiler_folder)
+ write_file(compiler_file, [[vim.g.lua_compiler = 1]])
+
+ exec('compiler new_compiler')
+
+ eq(1, eval('g:lua_compiler'))
+ rmdir(compiler_folder)
+ end)
+
+ it('loads vim compilers when both lua and vim version exist', function()
+ local compiler_file = compiler_folder .. sep .. 'new_compiler'
+ mkdir_p(compiler_folder)
+ write_file(compiler_file..'.vim', [[let g:compiler = 'vim']])
+ write_file(compiler_file..'.lua', [[vim.g.compiler = 'lua']])
+
+ exec('compiler new_compiler')
+
+ eq('vim', eval('g:compiler'))
+ rmdir(compiler_folder)
+ end)
+ end)
+
+ describe('ftplugin', function()
+ local ftplugin_folder = table.concat({plug_dir, 'ftplugin'}, sep)
+
+ it('loads lua ftplugins', function()
+ local ftplugin_file = table.concat({ftplugin_folder , 'new-ft.lua'}, sep)
+ mkdir_p(ftplugin_folder)
+ write_file(ftplugin_file , [[vim.g.lua_ftplugin = 1]])
+
+ exec [[set filetype=new-ft]]
+ eq(1, eval('g:lua_ftplugin'))
+ rmdir(ftplugin_folder)
+ end)
+ end)
+
+ describe('indent', function()
+ local indent_folder = table.concat({plug_dir, 'indent'}, sep)
+
+ it('loads lua indents', function()
+ local indent_file = table.concat({indent_folder , 'new-ft.lua'}, sep)
+ mkdir_p(indent_folder)
+ write_file(indent_file , [[vim.g.lua_indent = 1]])
+
+ exec [[set filetype=new-ft]]
+ eq(1, eval('g:lua_indent'))
+ rmdir(indent_folder)
+ end)
+ end)
+
+ describe('syntax', function()
+ local syntax_folder = table.concat({plug_dir, 'syntax'}, sep)
+
+ it('loads lua syntaxes on filetype change', function()
+ local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep)
+ mkdir_p(syntax_folder)
+ write_file(syntax_file , [[vim.g.lua_syntax = 1]])
+
+ exec('set filetype=my-lang')
+ eq(1, eval('g:lua_syntax'))
+ rmdir(syntax_folder)
+ end)
+
+ it('loads lua syntaxes on syntax change', function()
+ local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep)
+ mkdir_p(syntax_folder)
+ write_file(syntax_file , [[vim.g.lua_syntax = 5]])
+
+ exec('set syntax=my-lang')
+ eq(5, eval('g:lua_syntax'))
+ rmdir(syntax_folder)
+ end)
+ end)
+
+end)
+
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 9bf00b594b..836f514433 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -945,12 +945,20 @@ describe('lua stdlib', function()
exec_lua [[
vim.api.nvim_set_var("testing", "hi")
vim.api.nvim_set_var("other", 123)
+ vim.api.nvim_set_var("floaty", 5120.1)
+ vim.api.nvim_set_var("nullvar", vim.NIL)
vim.api.nvim_set_var("to_delete", {hello="world"})
]]
eq('hi', funcs.luaeval "vim.g.testing")
eq(123, funcs.luaeval "vim.g.other")
+ eq(5120.1, funcs.luaeval "vim.g.floaty")
eq(NIL, funcs.luaeval "vim.g.nonexistant")
+ eq(NIL, funcs.luaeval "vim.g.nullvar")
+ -- lost over RPC, so test locally:
+ eq({false, true}, exec_lua [[
+ return {vim.g.nonexistant == vim.NIL, vim.g.nullvar == vim.NIL}
+ ]])
eq({hello="world"}, funcs.luaeval "vim.g.to_delete")
exec_lua [[
@@ -963,12 +971,20 @@ describe('lua stdlib', function()
exec_lua [[
vim.api.nvim_buf_set_var(0, "testing", "hi")
vim.api.nvim_buf_set_var(0, "other", 123)
+ vim.api.nvim_buf_set_var(0, "floaty", 5120.1)
+ vim.api.nvim_buf_set_var(0, "nullvar", vim.NIL)
vim.api.nvim_buf_set_var(0, "to_delete", {hello="world"})
]]
eq('hi', funcs.luaeval "vim.b.testing")
eq(123, funcs.luaeval "vim.b.other")
+ eq(5120.1, funcs.luaeval "vim.b.floaty")
eq(NIL, funcs.luaeval "vim.b.nonexistant")
+ eq(NIL, funcs.luaeval "vim.b.nullvar")
+ -- lost over RPC, so test locally:
+ eq({false, true}, exec_lua [[
+ return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL}
+ ]])
eq({hello="world"}, funcs.luaeval "vim.b.to_delete")
exec_lua [[
@@ -1097,6 +1113,464 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo[1000].cole")
end)
+ describe('vim.opt', function()
+ -- TODO: We still need to write some tests for optlocal, opt and then getting the options
+ -- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same.
+
+ it('should allow setting number values', function()
+ local scrolloff = exec_lua [[
+ vim.opt.scrolloff = 10
+ return vim.o.scrolloff
+ ]]
+ eq(scrolloff, 10)
+ end)
+
+ pending('should handle STUPID window things', function()
+ local result = exec_lua [[
+ local result = {}
+
+ table.insert(result, vim.api.nvim_get_option('scrolloff'))
+ table.insert(result, vim.api.nvim_win_get_option(0, 'scrolloff'))
+
+ return result
+ ]]
+
+ eq({}, result)
+ end)
+
+ it('should allow setting tables', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = { 'hello', 'world' }
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, "hello,world")
+ end)
+
+ it('should allow setting tables with shortnames', function()
+ local wildignore = exec_lua [[
+ vim.opt.wig = { 'hello', 'world' }
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, "hello,world")
+ end)
+
+ it('should error when you attempt to set string values to numeric options', function()
+ local result = exec_lua [[
+ return {
+ pcall(function() vim.opt.textwidth = 'hello world' end)
+ }
+ ]]
+
+ eq(false, result[1])
+ end)
+
+ it('should error when you attempt to setlocal a global value', function()
+ local result = exec_lua [[
+ return pcall(function() vim.opt_local.clipboard = "hello" end)
+ ]]
+
+ eq(false, result)
+ end)
+
+ it('should allow you to set boolean values', function()
+ eq({true, false, true}, exec_lua [[
+ local results = {}
+
+ vim.opt.autoindent = true
+ table.insert(results, vim.bo.autoindent)
+
+ vim.opt.autoindent = false
+ table.insert(results, vim.bo.autoindent)
+
+ vim.opt.autoindent = not vim.opt.autoindent:get()
+ table.insert(results, vim.bo.autoindent)
+
+ return results
+ ]])
+ end)
+
+ it('should change current buffer values and defaults for global local values', function()
+ local result = exec_lua [[
+ local result = {}
+
+ vim.opt.makeprg = "global-local"
+ table.insert(result, vim.api.nvim_get_option('makeprg'))
+ table.insert(result, (pcall(vim.api.nvim_buf_get_option, 0, 'makeprg')))
+
+ vim.opt_local.mp = "only-local"
+ table.insert(result, vim.api.nvim_get_option('makeprg'))
+ table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg'))
+
+ vim.opt_global.makeprg = "only-global"
+ table.insert(result, vim.api.nvim_get_option('makeprg'))
+ table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg'))
+
+ vim.opt.makeprg = "global-local"
+ table.insert(result, vim.api.nvim_get_option('makeprg'))
+ table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg'))
+ return result
+ ]]
+
+ -- Set -> global & local
+ eq("global-local", result[1])
+ eq(false, result[2])
+
+ -- Setlocal -> only local
+ eq("global-local", result[3])
+ eq("only-local", result[4])
+
+ -- Setglobal -> only global
+ eq("only-global", result[5])
+ eq("only-local", result[6])
+
+ -- set -> doesn't override previously set value
+ eq("global-local", result[7])
+ eq("only-local", result[8])
+ end)
+
+ it('should allow all sorts of string manipulation', function()
+ eq({'hello', 'hello world', 'start hello world'}, exec_lua [[
+ local results = {}
+
+ vim.opt.makeprg = "hello"
+ table.insert(results, vim.o.makeprg)
+
+ vim.opt.makeprg = vim.opt.makeprg + " world"
+ table.insert(results, vim.o.makeprg)
+
+ vim.opt.makeprg = vim.opt.makeprg ^ "start "
+ table.insert(results, vim.o.makeprg)
+
+ return results
+ ]])
+ end)
+
+ describe('option:get()', function()
+ it('should work for boolean values', function()
+ eq(false, exec_lua [[
+ vim.opt.number = false
+ return vim.opt.number:get()
+ ]])
+ end)
+
+ it('should work for number values', function()
+ local tabstop = exec_lua[[
+ vim.opt.tabstop = 10
+ return vim.opt.tabstop:get()
+ ]]
+
+ eq(10, tabstop)
+ end)
+
+ it('should work for string values', function()
+ eq("hello world", exec_lua [[
+ vim.opt.makeprg = "hello world"
+ return vim.opt.makeprg:get()
+ ]])
+ end)
+
+ it('should work for set type flaglists', function()
+ local formatoptions = exec_lua [[
+ vim.opt.formatoptions = 'tcro'
+ return vim.opt.formatoptions:get()
+ ]]
+
+ eq(true, formatoptions.t)
+ eq(true, not formatoptions.q)
+ end)
+
+ it('should work for set type flaglists', function()
+ local formatoptions = exec_lua [[
+ vim.opt.formatoptions = { t = true, c = true, r = true, o = true }
+ return vim.opt.formatoptions:get()
+ ]]
+
+ eq(true, formatoptions.t)
+ eq(true, not formatoptions.q)
+ end)
+
+ it('should work for array list type options', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = "*.c,*.o,__pycache__"
+ return vim.opt.wildignore:get()
+ ]]
+
+ eq(3, #wildignore)
+ eq("*.c", wildignore[1])
+ end)
+
+ it('should work for key-value pair options', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = "tab:>~,space:_"
+ return vim.opt.listchars:get()
+ ]]
+
+ eq({
+ tab = ">~",
+ space = "_",
+ }, listchars)
+ end)
+
+ it('should allow you to add numeric options', function()
+ eq(16, exec_lua [[
+ vim.opt.tabstop = 12
+ vim.opt.tabstop = vim.opt.tabstop + 4
+ return vim.bo.tabstop
+ ]])
+ end)
+
+ it('should allow you to subtract numeric options', function()
+ eq(2, exec_lua [[
+ vim.opt.tabstop = 4
+ vim.opt.tabstop = vim.opt.tabstop - 2
+ return vim.bo.tabstop
+ ]])
+ end)
+ end)
+
+ describe('key:value style options', function()
+ it('should handle dictionary style', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+
+ return vim.o.listchars
+ ]]
+ eq("eol:~,space:.", listchars)
+ end)
+
+ it('should allow adding dictionary style', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+
+ vim.opt.listchars = vim.opt.listchars + { space = "-" }
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~,space:-", listchars)
+ end)
+
+ it('should allow adding dictionary style', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars + { space = "-" } + { space = "_" }
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~,space:_", listchars)
+ end)
+
+ it('should allow completely new keys', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars + { tab = ">>>" }
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~,space:.,tab:>>>", listchars)
+ end)
+
+ it('should allow subtracting dictionary style', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars - "space"
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~", listchars)
+ end)
+
+ it('should allow subtracting dictionary style', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars - "space" - "eol"
+
+ return vim.o.listchars
+ ]]
+
+ eq("", listchars)
+ end)
+
+ it('should allow subtracting dictionary style multiple times', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars - "space" - "space"
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~", listchars)
+ end)
+
+ it('should allow adding a key:value string to a listchars', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars + "tab:>~"
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~,space:.,tab:>~", listchars)
+ end)
+
+ it('should allow prepending a key:value string to a listchars', function()
+ local listchars = exec_lua [[
+ vim.opt.listchars = {
+ eol = "~",
+ space = ".",
+ }
+ vim.opt.listchars = vim.opt.listchars ^ "tab:>~"
+
+ return vim.o.listchars
+ ]]
+
+ eq("eol:~,space:.,tab:>~", listchars)
+ end)
+ end)
+
+ it('should automatically set when calling remove', function()
+ eq("foo,baz", exec_lua [[
+ vim.opt.wildignore = "foo,bar,baz"
+ vim.opt.wildignore:remove("bar")
+
+ return vim.o.wildignore
+ ]])
+ end)
+
+ it('should automatically set when calling remove with a table', function()
+ eq("foo", exec_lua [[
+ vim.opt.wildignore = "foo,bar,baz"
+ vim.opt.wildignore:remove { "bar", "baz" }
+
+ return vim.o.wildignore
+ ]])
+ end)
+
+ it('should automatically set when calling append', function()
+ eq("foo,bar,baz,bing", exec_lua [[
+ vim.opt.wildignore = "foo,bar,baz"
+ vim.opt.wildignore:append("bing")
+
+ return vim.o.wildignore
+ ]])
+ end)
+
+ it('should automatically set when calling append with a table', function()
+ eq("foo,bar,baz,bing,zap", exec_lua [[
+ vim.opt.wildignore = "foo,bar,baz"
+ vim.opt.wildignore:append { "bing", "zap" }
+
+ return vim.o.wildignore
+ ]])
+ end)
+
+ it('should allow adding tables', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = 'foo'
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo')
+
+ wildignore = exec_lua [[
+ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo,bar,baz')
+ end)
+
+ it('should handle adding duplicates', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = 'foo'
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo')
+
+ wildignore = exec_lua [[
+ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo,bar,baz')
+
+ wildignore = exec_lua [[
+ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo,bar,baz')
+ end)
+
+ it('should allow adding multiple times', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = 'foo'
+ vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz'
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo,bar,baz')
+ end)
+
+ it('should remove values when you use minus', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = 'foo'
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo')
+
+ wildignore = exec_lua [[
+ vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo,bar,baz')
+
+ wildignore = exec_lua [[
+ vim.opt.wildignore = vim.opt.wildignore - 'bar'
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'foo,baz')
+ end)
+
+ it('should prepend values when using ^', function()
+ local wildignore = exec_lua [[
+ vim.opt.wildignore = 'foo'
+ vim.opt.wildignore = vim.opt.wildignore ^ 'first'
+ return vim.o.wildignore
+ ]]
+ eq('first,foo', wildignore)
+
+ wildignore = exec_lua [[
+ vim.opt.wildignore = vim.opt.wildignore ^ 'super_first'
+ return vim.o.wildignore
+ ]]
+ eq(wildignore, 'super_first,first,foo')
+ end)
+
+ end)
+
it('vim.cmd', function()
exec_lua [[
vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')"
@@ -1457,6 +1931,34 @@ describe('lua stdlib', function()
eq(buf2, val)
end)
end)
+
+ describe('vim.api.nvim_win_call', function()
+ it('can access window options', function()
+ command('vsplit')
+ local win1 = meths.get_current_win()
+ command('wincmd w')
+ local win2 = exec_lua [[
+ win2 = vim.api.nvim_get_current_win()
+ return win2
+ ]]
+ command('wincmd p')
+
+ eq('', meths.win_get_option(win1, 'winhighlight'))
+ eq('', meths.win_get_option(win2, 'winhighlight'))
+
+ local val = exec_lua [[
+ return vim.api.nvim_win_call(win2, function()
+ vim.cmd "setlocal winhighlight=Normal:Normal"
+ return vim.api.nvim_get_current_win()
+ end)
+ ]]
+
+ eq('', meths.win_get_option(win1, 'winhighlight'))
+ eq('Normal:Normal', meths.win_get_option(win2, 'winhighlight'))
+ eq(win1, meths.get_current_win())
+ eq(win2, val)
+ end)
+ end)
end)
describe('lua: require("mod") from packages', function()
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index a78ed07876..85c67be8f9 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -118,7 +118,7 @@ describe('health.vim', function()
Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
Heading = { bold=true, foreground=Screen.colors.Magenta },
Heading2 = { foreground = Screen.colors.SlateBlue },
- Bar = { foreground=Screen.colors.Purple },
+ Bar = { foreground = 0x6a0dad },
Bullet = { bold=true, foreground=Screen.colors.Brown },
})
command("checkhealth foo success1")
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
new file mode 100644
index 0000000000..e09d93f7cc
--- /dev/null
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -0,0 +1,62 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+
+describe('vim.lsp.codelens', function()
+ before_each(function()
+ helpers.clear()
+ exec_lua('require("vim.lsp")')
+ end)
+ after_each(helpers.clear)
+
+ it('on_codelens_stores_and_displays_lenses', function()
+ local fake_uri = "file://fake/uri"
+ local bufnr = exec_lua([[
+ fake_uri = ...
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ local lines = {'So', 'many', 'lines'}
+ vim.fn.bufload(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
+ return bufnr
+ ]], fake_uri)
+
+ exec_lua([[
+ local bufnr = ...
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 0 }
+ },
+ command = { title = 'Lens1', command = 'Dummy' }
+ },
+ }
+ vim.lsp.codelens.on_codelens(nil, 'textDocument/codeLens', lenses, 1, bufnr)
+ ]], bufnr)
+
+ local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ local expected = {
+ {
+ range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 }
+ },
+ command = {
+ title = 'Lens1',
+ command = 'Dummy',
+ },
+ },
+ }
+ eq(expected, stored_lenses)
+
+ local virtual_text_chunks = exec_lua([[
+ local bufnr = ...
+ local ns = vim.lsp.codelens.__namespaces[1]
+ local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {})
+ return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text
+ ]], bufnr)
+
+ eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks)
+ end)
+end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 8c91c4ab2c..962028e7e1 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -86,6 +86,39 @@ describe('vim.lsp.diagnostic', function()
eq(2, #result[1])
eq('Diagnostic #1', result[1][1].message)
end)
+ it('Can convert diagnostic to quickfix items format', function()
+ local bufnr = exec_lua([[
+ local fake_uri = ...
+ return vim.uri_to_bufnr(fake_uri)
+ ]], fake_uri)
+ local result = exec_lua([[
+ local bufnr = ...
+ vim.lsp.diagnostic.save(
+ {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 2, 1, 2, 1),
+ }, bufnr, 1
+ )
+ return vim.lsp.util.diagnostics_to_items(vim.lsp.diagnostic.get_all())
+ ]], bufnr)
+ local expected = {
+ {
+ bufnr = bufnr,
+ col = 2,
+ lnum = 2,
+ text = 'Diagnostic #1',
+ type = 'E'
+ },
+ {
+ bufnr = bufnr,
+ col = 2,
+ lnum = 3,
+ text = 'Diagnostic #2',
+ type = 'E'
+ },
+ }
+ eq(expected, result)
+ end)
it('should be able to save and count a single client error', function()
eq(1, exec_lua [[
vim.lsp.diagnostic.save(
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 6eda515fb6..663271deab 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -9,6 +9,7 @@ local eq = helpers.eq
local pcall_err = helpers.pcall_err
local pesc = helpers.pesc
local insert = helpers.insert
+local funcs = helpers.funcs
local retry = helpers.retry
local NIL = helpers.NIL
local read_file = require('test.helpers').read_file
@@ -1392,10 +1393,10 @@ describe('LSP', function()
{ label='foocar', sortText="e", insertText='foodar', textEdit={newText='foobar'} },
{ label='foocar', sortText="f", textEdit={newText='foobar'} },
-- real-world snippet text
- { label='foocar', sortText="g", insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} },
- { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} },
+ { label='foocar', sortText="g", insertText='foodar', insertTextFormat=2, textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} },
+ { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} },
-- nested snippet tokens
- { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} },
+ { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} },
-- plain text
{ label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
}
@@ -1407,9 +1408,9 @@ describe('LSP', function()
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="d", insertText='foobar', textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="e", insertText='foodar', textEdit={newText='foobar'} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="f", textEdit={newText='foobar'} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', insertTextFormat=2, textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
}
@@ -1820,36 +1821,20 @@ describe('LSP', function()
end)
describe('lsp.util.jump_to_location', function()
- local default_target_bufnr
- local default_target_uri = 'file://fake/uri'
-
- local create_buf = function(uri, lines)
- for i, line in ipairs(lines) do
- lines[i] = '"' .. line .. '"'
- end
- lines = table.concat(lines, ", ")
-
- -- Let's set "hidden" to true in order to avoid errors when switching
- -- between buffers in test.
- local code = string.format([[
- vim.api.nvim_set_option('hidden', true)
+ local target_bufnr
- local bufnr = vim.uri_to_bufnr("%s")
- local lines = {%s}
+ before_each(function()
+ target_bufnr = exec_lua [[
+ local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]], uri, lines)
-
- return exec_lua(code)
- end
-
- before_each(function()
- default_target_bufnr = create_buf(default_target_uri, {'1st line of text', 'å å ɧ 汉语 ↥ 🤦 🦄'})
+ ]]
end)
- local location = function(uri, start_line, start_char, end_line, end_char)
+ local location = function(start_line, start_char, end_line, end_char)
return {
- uri = uri,
+ uri = "file://fake/uri",
range = {
start = { line = start_line, character = start_char },
["end"] = { line = end_line, character = end_char },
@@ -1857,9 +1842,9 @@ describe('LSP', function()
}
end
- local jump = function(bufnr, msg)
+ local jump = function(msg)
eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg))
- eq(bufnr, exec_lua[[return vim.fn.bufnr('%')]])
+ eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]])
return {
line = exec_lua[[return vim.fn.line('.')]],
col = exec_lua[[return vim.fn.col('.')]],
@@ -1867,13 +1852,13 @@ describe('LSP', function()
end
it('jumps to a Location', function()
- local pos = jump(default_target_bufnr, location(default_target_uri, 0, 9, 0, 9))
+ local pos = jump(location(0, 9, 0, 9))
eq(1, pos.line)
eq(10, pos.col)
end)
it('jumps to a LocationLink', function()
- local pos = jump(default_target_bufnr, {
+ local pos = jump({
targetUri = "file://fake/uri",
targetSelectionRange = {
start = { line = 0, character = 4 },
@@ -1889,93 +1874,22 @@ describe('LSP', function()
end)
it('jumps to the correct multibyte column', function()
- local pos = jump(default_target_bufnr, location(default_target_uri, 1, 2, 1, 2))
+ local pos = jump(location(1, 2, 1, 2))
eq(2, pos.line)
eq(4, pos.col)
eq('å', exec_lua[[return vim.fn.expand('<cword>')]])
end)
- it('should not push item to tagstack if destination is the same as source', function()
- -- Set cursor at the 2nd line, 1st character. This is the source position
- -- for the test, and will also be the destination one, making the cursor
- -- "motionless", thus not triggering a push to the tagstack.
- exec_lua(string.format([[
- vim.api.nvim_win_set_buf(0, %d)
- vim.api.nvim_win_set_cursor(0, {2, 0})
- ]], default_target_bufnr))
-
- -- Jump to 'f' in 'foobar', at the 2nd line.
- jump(default_target_bufnr, location(default_target_uri, 1, 0, 1, 0))
-
- local stack = exec_lua[[return vim.fn.gettagstack()]]
- eq(0, stack.length)
- end)
-
- it('should not push the same item from same buffer twice to tagstack', function()
- -- Set cursor at the 2nd line, 5th character.
- exec_lua(string.format([[
- vim.api.nvim_win_set_buf(0, %d)
- vim.api.nvim_win_set_cursor(0, {2, 4})
- ]], default_target_bufnr))
-
- local stack
-
- -- Jump to 1st line, 1st column.
- jump(default_target_bufnr, location(default_target_uri, 0, 0, 0, 0))
-
- stack = exec_lua[[return vim.fn.gettagstack()]]
- eq({default_target_bufnr, 2, 5, 0}, stack.items[1].from)
-
- -- Go back to 5th character at 2nd line, which is currently at the top of
- -- the tagstack.
- exec_lua(string.format([[
- vim.api.nvim_win_set_cursor(0, {2, 4})
- ]], default_target_bufnr))
-
- -- Jump again to 1st line, 1st column. Since we're jumping from the same
- -- position we have just jumped from, this jump shouldn't be pushed to
- -- the tagstack.
- jump(default_target_bufnr, location(default_target_uri, 0, 0, 0, 0))
-
- stack = exec_lua[[return vim.fn.gettagstack()]]
- eq({default_target_bufnr, 2, 5, 0}, stack.items[1].from)
- eq(1, stack.length)
- end)
-
- it('should not push the same item from another buffer twice to tagstack', function()
- local target_uri = 'file://foo/bar'
- local target_bufnr = create_buf(target_uri, {'this is a line', 'foobar'})
-
- -- Set cursor at the 1st line, 3rd character of the default test buffer.
- exec_lua(string.format([[
- vim.api.nvim_win_set_buf(0, %d)
- vim.api.nvim_win_set_cursor(0, {1, 2})
- ]], default_target_bufnr))
-
- local stack
+ it('adds current position to jumplist before jumping', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+ local mark = funcs.nvim_buf_get_mark(target_bufnr, "'")
+ eq({ 1, 0 }, mark)
- -- Jump to 1st line, 1st column of a different buffer from the source
- -- position.
- jump(target_bufnr, location(target_uri, 0, 0, 0, 0))
+ funcs.nvim_win_set_cursor(0, {2, 3})
+ jump(location(0, 9, 0, 9))
- stack = exec_lua[[return vim.fn.gettagstack()]]
- eq({default_target_bufnr, 1, 3, 0}, stack.items[1].from)
-
- -- Go back to 3rd character at 1st line of the default test buffer, which
- -- is currently at the top of the tagstack.
- exec_lua(string.format([[
- vim.api.nvim_win_set_buf(0, %d)
- vim.api.nvim_win_set_cursor(0, {1, 2})
- ]], default_target_bufnr))
-
- -- Jump again to 1st line, 1st column of the different buffer. Since
- -- we're jumping from the same position we have just jumped from, this
- -- jump shouldn't be pushed to the tagstack.
- jump(target_bufnr, location(target_uri, 0, 0, 0, 0))
-
- stack = exec_lua[[return vim.fn.gettagstack()]]
- eq({default_target_bufnr, 1, 3, 0}, stack.items[1].from)
- eq(1, stack.length)
+ mark = funcs.nvim_buf_get_mark(target_bufnr, "'")
+ eq({ 2, 3 }, mark)
end)
end)
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 72ff6f2fb6..d2f9148e8f 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -235,6 +235,100 @@ void ui_refresh(void)
}, res)
end)
+ it('can match special regex characters like \\ * + ( with `vim-match?`', function()
+ if pending_c_parser(pending) then return end
+
+ insert('char* astring = "\\n"; (1 + 1) * 2 != 2;')
+
+ local res = exec_lua([[
+ cquery = vim.treesitter.parse_query("c", '((_) @plus (vim-match? @plus "^\\\\+$"))'..
+ '((_) @times (vim-match? @times "^\\\\*$"))'..
+ '((_) @paren (vim-match? @paren "^\\\\($"))'..
+ '((_) @escape (vim-match? @escape "^\\\\\\\\n$"))'..
+ '((_) @string (vim-match? @string "^\\"\\\\\\\\n\\"$"))')
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0) do
+ -- can't transmit node over RPC. just check the name and range
+ local mrepr = {}
+ for cid,node in pairs(match) do
+ table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()})
+ end
+ table.insert(res, {pattern, mrepr})
+ end
+ return res
+ ]])
+
+ eq({
+ { 2, { { "times", '*', 0, 4, 0, 5 } } },
+ { 5, { { "string", 'string_literal', 0, 16, 0, 20 } } },
+ { 4, { { "escape", 'escape_sequence', 0, 17, 0, 19 } } },
+ { 3, { { "paren", '(', 0, 22, 0, 23 } } },
+ { 1, { { "plus", '+', 0, 25, 0, 26 } } },
+ { 2, { { "times", '*', 0, 30, 0, 31 } } },
+ }, res)
+ end)
+
+ it('supports builtin query predicate any-of?', function()
+ if pending_c_parser(pending) then return end
+
+ insert([[
+ #include <stdio.h>
+
+ int main(void) {
+ int i;
+ for(i=1; i<=100; i++) {
+ if(((i%3)||(i%5))== 0)
+ printf("number= %d FizzBuzz\n", i);
+ else if((i%3)==0)
+ printf("number= %d Fizz\n", i);
+ else if((i%5)==0)
+ printf("number= %d Buzz\n", i);
+ else
+ printf("number= %d\n",i);
+ }
+ return 0;
+ }
+ ]])
+ exec_lua([[
+ function get_query_result(query_text)
+ cquery = vim.treesitter.parse_query("c", query_text)
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ res = {}
+ for cid, node in cquery:iter_captures(tree:root(), 0) do
+ -- can't transmit node over RPC. just check the name, range, and text
+ local text = vim.treesitter.get_node_text(node, 0)
+ local range = {node:range()}
+ table.insert(res, {cquery.captures[cid], node:type(), range, text})
+ end
+ return res
+ end
+ ]])
+
+ local res0 = exec_lua([[return get_query_result(...)]],
+ [[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]])
+ eq({
+ { "c-keyword", "primitive_type", { 2, 2, 2, 5 }, "int" },
+ { "c-keyword", "primitive_type", { 3, 4, 3, 7 }, "int" },
+ }, res0)
+
+ local res1 = exec_lua([[return get_query_result(...)]],
+ [[
+ ((string_literal) @fizzbuzz-strings (#any-of? @fizzbuzz-strings
+ "\"number= %d FizzBuzz\\n\""
+ "\"number= %d Fizz\\n\""
+ "\"number= %d Buzz\\n\""
+ ))
+ ]])
+ eq({
+ { "fizzbuzz-strings", "string_literal", { 6, 15, 6, 38 }, "\"number= %d FizzBuzz\\n\""},
+ { "fizzbuzz-strings", "string_literal", { 8, 15, 8, 34 }, "\"number= %d Fizz\\n\""},
+ { "fizzbuzz-strings", "string_literal", { 10, 15, 10, 34 }, "\"number= %d Buzz\\n\""},
+ }, res1)
+ end)
+
it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function()
if pending_c_parser(pending) then return end
@@ -308,7 +402,7 @@ void ui_refresh(void)
return list
]]
- eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
+ eq({ 'any-of?', 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
end)
@@ -599,6 +693,56 @@ int x = INT_MAX;
eq(result, "value")
end)
+
+ describe("when setting a key on a capture", function()
+ it("it should create the nested table", function()
+ insert([[
+ int x = 3;
+ ]])
+
+ local result = exec_lua([[
+ local query = require("vim.treesitter.query")
+ local value
+
+ query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))')
+ parser = vim.treesitter.get_parser(0, "c")
+
+ for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do
+ for _, nested_tbl in pairs(metadata) do
+ return nested_tbl.key
+ end
+ end
+ ]])
+
+ eq(result, "value")
+ end)
+
+ it("it should not overwrite the nested table", function()
+ insert([[
+ int x = 3;
+ ]])
+
+ local result = exec_lua([[
+ local query = require("vim.treesitter.query")
+ local result
+
+ query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))')
+ parser = vim.treesitter.get_parser(0, "c")
+
+ for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do
+ for _, nested_tbl in pairs(metadata) do
+ return nested_tbl
+ end
+ end
+ ]])
+ local expected = {
+ ["key"] = "value",
+ ["key2"] = "value2",
+ }
+
+ eq(expected, result)
+ end)
+ end)
end)
end)
end)
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 82d3075be2..98aafd8757 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -66,6 +66,18 @@ describe('decorations providers', function()
expect_events(expected, actual, "beam trace")
end
+ it('does not OOM when inserting, rather than appending, to the decoration provider vector', function()
+ -- Add a dummy decoration provider with a larger ns id than what setup_provider() creates.
+ -- This forces get_decor_provider() to insert into the providers vector,
+ -- rather than append, which used to spin in an infinite loop allocating
+ -- memory until nvim crashed/was killed.
+ setup_provider([[
+ local ns2 = a.nvim_create_namespace "ns2"
+ a.nvim_set_decoration_provider(ns2, {})
+ ]])
+ helpers.assert_alive()
+ end)
+
it('leave a trace', function()
insert(mulholland)
@@ -333,6 +345,35 @@ describe('decorations providers', function()
]]}
end)
+ it('can have virtual text of the style: right_align', function()
+ insert(mulholland)
+ setup_provider [[
+ local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
+ local test_ns = a.nvim_create_namespace "mulholland"
+ function on_do(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
+ virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}};
+ virt_text_pos='right_align';
+ ephemeral = true;
+ })
+ end
+ end
+ ]]
+
+ screen:expect{grid=[[
+ // just to see if there was an acciden+{2: }|
+ // on Mulholland Drive +{2: }|
+ try_start(); +{2: }|
+ bufref_T save_buf; +{2: }|
+ switch_buffer(&save_buf, buf); +{2: }|
+ posp = getmark(mark, false); +{2: }|
+ restore_buffer(&save_buf);^ +{2: }|
+ |
+ ]]}
+ end)
+
it('can highlight beyond EOL', function()
insert(mulholland)
setup_provider [[
@@ -366,7 +407,7 @@ describe('decorations providers', function()
end)
describe('extmark decorations', function()
- local screen
+ local screen, ns
before_each( function()
clear()
screen = Screen.new(50, 15)
@@ -397,6 +438,8 @@ describe('extmark decorations', function()
[23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey};
[24] = {bold = true};
}
+
+ ns = meths.create_namespace 'test'
end)
local example_text = [[
@@ -417,7 +460,6 @@ end]]
insert(example_text)
feed 'gg'
- local ns = meths.create_namespace 'test'
for i = 1,9 do
meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'})
if i == 3 or (i >= 6 and i <= 9) then
@@ -484,7 +526,6 @@ end]]
it('can have virtual text of overlay position and styling', function()
insert(example_text)
feed 'gg'
- local ns = meths.create_namespace 'test'
command 'set ft=lua'
command 'syntax on'
@@ -572,4 +613,88 @@ end]]
{24:-- VISUAL LINE --} |
]]}
end)
+
+ it('can have virtual text of fixed win_col position', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
+
+ screen:expect{grid=[[
+ ^for _,item in ipairs(items) do |
+ local text, hl_id_cell, cou{4:Very} unpack(item) |
+ if hl_id_cell ~= nil then {4:Much} |
+ hl_id = hl_id_cell {4:Error} |
+ end |
+ for _ = 1, (count or 1) do |
+ local cell = line[colpos] |
+ {1:-} cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '3G12|i<cr><esc>'
+ screen:expect{grid=[[
+ for _,item in ipairs(items) do |
+ local text, hl_id_cell, cou{4:Very} unpack(item) |
+ if hl_i {4:Much} |
+ ^d_cell ~= nil then |
+ hl_id = hl_id_cell {4:Error} |
+ end |
+ for _ = 1, (count or 1) do |
+ local cell = line[colpos] |
+ {1:-} cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ |
+ ]]}
+
+ feed 'u:<cr>'
+ screen:expect{grid=[[
+ for _,item in ipairs(items) do |
+ local text, hl_id_cell, cou{4:Very} unpack(item) |
+ if hl_i^d_cell ~= nil then {4:Much} |
+ hl_id = hl_id_cell {4:Error} |
+ end |
+ for _ = 1, (count or 1) do |
+ local cell = line[colpos] |
+ {1:-} cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ : |
+ ]]}
+
+ feed '8|i<cr><esc>'
+ screen:expect{grid=[[
+ for _,item in ipairs(items) do |
+ local text, hl_id_cell, cou{4:Very} unpack(item) |
+ if |
+ ^hl_id_cell ~= nil then {4:Much} |
+ hl_id = hl_id_cell {4:Error} |
+ end |
+ for _ = 1, (count or 1) do |
+ local cell = line[colpos] |
+ {1:-} cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+1 |
+ end |
+ end |
+ {1:~ }|
+ |
+ ]]}
+ end)
end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index ccb13a69d2..9fa0ad08f1 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -62,6 +62,27 @@ describe('float window', function()
eq(1000, funcs.win_getid())
end)
+ it('win_execute() should work' , function()
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {'the floatwin', 'abc', 'def'})
+ local win = meths.open_win(buf, false, {relative='win', width=16, height=1, row=0, col=10})
+ local line = funcs.win_execute(win, 'echo getline(1)')
+ eq('\nthe floatwin', line)
+ eq('\n1', funcs.win_execute(win, 'echo line(".",'..win.id..')'))
+ eq('\n3', funcs.win_execute(win, 'echo line("$",'..win.id..')'))
+ eq('\n0', funcs.win_execute(win, 'echo line("$", 123456)'))
+ funcs.win_execute(win, 'bwipe!')
+ end)
+
+ it('win_execute() call commands that not allowed' , function()
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'})
+ local win = meths.open_win(buf, true, {relative='win', width=16, height=1, row=0, col=10})
+ eq(pcall_err(funcs.win_execute, win, 'close'), 'Vim(close):E37: No write since last change (add ! to override)')
+ eq(pcall_err(funcs.win_execute, win, 'bdelete'), 'Vim(bdelete):E89: No write since last change for buffer 2 (add ! to override)')
+ funcs.win_execute(win, 'bwipe!')
+ end)
+
it('closed immediately by autocmd #11383', function()
eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
pcall_err(exec_lua, [[
@@ -690,6 +711,49 @@ describe('float window', function()
]]}
end
+ meths.win_set_config(win, {border="rounded"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╭─────────╮}|
+ {5:│}{1: halloj! }{5:│}|
+ {5:│}{1: BORDAA }{5:│}|
+ {5:╰─────────╯}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╭─────────╮}{0: }|
+ {0:~ }{5:│}{1: halloj! }{5:│}{0: }|
+ {0:~ }{5:│}{1: BORDAA }{5:│}{0: }|
+ {0:~ }{5:╰─────────╯}{0: }|
+ |
+ ]]}
+ end
+
meths.win_set_config(win, {border="solid"})
if multigrid then
screen:expect{grid=[[
@@ -910,6 +974,57 @@ describe('float window', function()
end
end)
+ it('terminates border on edge of viewport when window extends past viewport', function()
+ local buf = meths.create_buf(false, false)
+ meths.open_win(buf, false, {relative='editor', width=40, height=7, row=0, col=0, border="single"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {5:┌────────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:└────────────────────────────────────────┘}|
+ ]], float_pos={
+ [4] = { { id = 1001 }, "NW", 1, 0, 0, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ {5:^┌──────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:└──────────────────────────────────────┘}|
+ |
+ ]]}
+ end
+ end)
+
it('with border show popupmenu', function()
screen:try_resize(40,10)
local buf = meths.create_buf(false, false)
@@ -1008,8 +1123,8 @@ describe('float window', function()
{1: abb }|
{13: acc }|
]], float_pos={
- [5] = { { id = 1002 }, "NW", 1, 0, 5, true },
- [6] = { { id = -1 }, "NW", 5, 4, 0, false }
+ [5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 },
+ [6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 }
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
[5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3};
@@ -2686,8 +2801,8 @@ describe('float window', function()
{1: word }|
{1: longtext }|
]], float_pos={
- [4] = {{ id = 1001 }, "NW", 1, 2, 5, true},
- [5] = {{ id = -1 }, "NW", 4, 1, 1, false}
+ [4] = {{ id = 1001 }, "NW", 1, 2, 5, true, 50},
+ [5] = {{ id = -1 }, "NW", 4, 1, 1, false, 100}
}}
else
screen:expect([[
@@ -2773,8 +2888,8 @@ describe('float window', function()
{1:yy }|
{1:zz }|
]], float_pos={
- [4] = {{ id = 1001 }, "NW", 1, 2, 5, true},
- [5] = {{ id = -1 }, "NW", 2, 1, 0, false}
+ [4] = {{ id = 1001 }, "NW", 1, 2, 5, true, 50},
+ [5] = {{ id = -1 }, "NW", 2, 1, 0, false, 100}
}}
else
screen:expect([[
@@ -2829,6 +2944,53 @@ describe('float window', function()
end
end)
+ it('command menu rendered above cursor (pum_above)', function()
+ command('set wildmenu wildmode=longest:full wildoptions=pum')
+ feed(':sign u<tab>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ :sign un^ |
+ ## grid 4
+ {7: }|
+ {12:~ }|
+ {12:~ }|
+ {12:~ }|
+ ## grid 5
+ {1: undefine }|
+ {1: unplace }|
+ ]], float_pos={
+ [5] = {{id = -1}, "SW", 1, 6, 5, false, 250};
+ [4] = {{id = 1001}, "NW", 1, 2, 5, true, 50};
+ }}
+ else
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {0:~ }{7: }{0: }|
+ {0:~ }{12:~ }{0: }|
+ {0:~ }{1: undefine }{0: }|
+ {0:~ }{1: unplace }{0: }|
+ :sign un^ |
+ ]]}
+ end
+ end)
+
it('with ext_popupmenu', function()
screen:set_option('ext_popupmenu', true)
feed('ix ')
@@ -3035,7 +3197,7 @@ describe('float window', function()
{1:word }|
{1:longtext }|
]], float_pos={
- [4] = {{id = -1}, "NW", 2, 1, 0, false}}
+ [4] = {{id = -1}, "NW", 2, 1, 0, false, 100}}
}
else
screen:expect([[
@@ -3079,8 +3241,8 @@ describe('float window', function()
{15:some info }|
{15:about item }|
]], float_pos={
- [4] = {{id = -1}, "NW", 2, 1, 0, false},
- [6] = {{id = 1002}, "NW", 2, 1, 12, true},
+ [4] = {{id = -1}, "NW", 2, 1, 0, false, 100},
+ [6] = {{id = 1002}, "NW", 2, 1, 12, true, 50},
}}
else
screen:expect([[
@@ -3194,7 +3356,7 @@ describe('float window', function()
{1:word }|
{1:longtext }|
]], float_pos={
- [4] = {{id = -1}, "NW", 2, 1, 0, false},
+ [4] = {{id = -1}, "NW", 2, 1, 0, false, 100},
}}
else
screen:expect([[
@@ -6227,6 +6389,69 @@ describe('float window', function()
]]}
end
end)
+
+ it('can use z-index', function()
+ local buf = meths.create_buf(false,false)
+ local win1 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=1, col=5, zindex=30})
+ meths.win_set_option(win1, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg")
+ local win2 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=2, col=6, zindex=50})
+ meths.win_set_option(win2, "winhl", "Normal:Search,EndOfBuffer:Search")
+ local win3 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=3, col=7, zindex=40})
+ meths.win_set_option(win3, "winhl", "Normal:Question,EndOfBuffer:Question")
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7: }|
+ {7:~ }|
+ {7:~ }|
+ ## grid 5
+ {17: }|
+ {17:~ }|
+ {17:~ }|
+ ## grid 6
+ {8: }|
+ {8:~ }|
+ {8:~ }|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 1, 5, true, 30};
+ [5] = {{id = 1002}, "NW", 1, 2, 6, true, 50};
+ [6] = {{id = 1003}, "NW", 1, 3, 7, true, 40};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }{7: }{0: }|
+ {0:~ }{7:~}{17: }{0: }|
+ {0:~ }{7:~}{17:~ }{8: }{0: }|
+ {0:~ }{17:~ }{8: }{0: }|
+ {0:~ }{8:~ }{0: }|
+ |
+ ]]}
+ end
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 9d7719a7c0..c238898244 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -811,7 +811,7 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:^~ }|
]], messages={
- {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with mouse (empty cancels): ' } }, kind = ""}
+ {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""}
}}
feed('1')
@@ -822,7 +822,7 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:^~ }|
]], messages={
- {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with mouse (empty cancels): ' } }, kind = ""},
+ {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""},
{ content = { { "1" } }, kind = "" }
}}
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index fcf6926433..f73d051857 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -429,6 +429,15 @@ screen:redraw_debug() to show all intermediate screen states. ]])
extstate.win_viewport = nil
end
+ if expected.float_pos then
+ expected.float_pos = deepcopy(expected.float_pos)
+ for _, v in pairs(expected.float_pos) do
+ if not v.external and v[7] == nil then
+ v[7] = 50
+ end
+ end
+ end
+
-- Convert assertion errors into invalid screen state descriptions.
for _, k in ipairs(concat_tables(ext_keys, {'mode', 'mouse_enabled'})) do
-- Empty states are considered the default and need not be mentioned.
@@ -1287,6 +1296,11 @@ function Screen:get_snapshot(attrs, ignore)
end
local function fmt_ext_state(name, state)
+ local function remove_all_metatables(item, path)
+ if path[#path] ~= inspect.METATABLE then
+ return item
+ end
+ end
if name == "win_viewport" then
local str = "{\n"
for k,v in pairs(state) do
@@ -1295,13 +1309,18 @@ local function fmt_ext_state(name, state)
..", curcol = "..v.curcol.."};\n")
end
return str .. "}"
- else
- -- TODO(bfredl): improve formatting of more states
- local function remove_all_metatables(item, path)
- if path[#path] ~= inspect.METATABLE then
- return item
+ elseif name == "float_pos" then
+ local str = "{\n"
+ for k,v in pairs(state) do
+ str = str.." ["..k.."] = {{id = "..v[1].id.."}"
+ for i = 2, #v do
+ str = str..", "..inspect(v[i])
end
+ str = str .. "};\n"
end
+ return str .. "}"
+ else
+ -- TODO(bfredl): improve formatting of more states
return inspect(state,{process=remove_all_metatables})
end
end
diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 2c6e586665..de77100cc0 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -36,7 +36,7 @@ describe("'spell'", function()
feed('ggJJJJJJ0')
screen:expect([[
{1:^Lorem} {1:ipsum} dolor sit {1:amet}, {1:consectetur} {1:adipiscing} {1:elit}, {1:sed} do {1:eiusmod} {1:tempor} {1:i}|
- {1:ncididunt} {1:ut} {1:labore} {1:et} {1:dolore} {1:magna} {1:aliqua}. {1:Ut} {1:enim} ad minim {1:veniam}, {1:quis} {1:nostru}|
+ {1:ncididunt} {1:ut} {1:labore} et {1:dolore} {1:magna} {1:aliqua}. {1:Ut} {1:enim} ad minim {1:veniam}, {1:quis} {1:nostru}|
{1:d} {1:exercitation} {1:ullamco} {1:laboris} {1:nisi} {1:ut} {1:aliquip} ex ea {1:commodo} {1:consequat}. {1:Duis} {1:aut}|
{1:e} {1:irure} dolor in {1:reprehenderit} in {1:voluptate} {1:velit} {1:esse} {1:cillum} {1:dolore} {1:eu} {1:fugiat} {1:n}|
{1:ulla} {1:pariatur}. {1:Excepteur} {1:sint} {1:occaecat} {1:cupidatat} non {1:proident}, {1:sunt} in culpa {1:qui}|
@@ -44,6 +44,7 @@ describe("'spell'", function()
{0:~ }|
|
]])
+
end)
it('has correct highlight at start of line', function()