aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/api/buffer_spec.lua123
-rw-r--r--test/functional/api/keymap_spec.lua5
-rw-r--r--test/functional/api/server_notifications_spec.lua16
-rw-r--r--test/functional/api/vim_spec.lua81
-rw-r--r--test/functional/core/startup_spec.lua4
-rw-r--r--test/functional/eval/api_functions_spec.lua4
-rw-r--r--test/functional/eval/environ_spec.lua61
-rw-r--r--test/functional/eval/executable_spec.lua15
-rw-r--r--test/functional/eval/exepath_spec.lua40
-rw-r--r--test/functional/eval/function_spec.lua8
-rwxr-xr-xtest/functional/fixtures/bin/false0
-rwxr-xr-xtest/functional/fixtures/bin/false.cmd0
-rwxr-xr-xtest/functional/fixtures/bin/null0
-rwxr-xr-xtest/functional/fixtures/bin/null.cmd0
-rwxr-xr-xtest/functional/fixtures/bin/true0
-rwxr-xr-xtest/functional/fixtures/bin/true.cmd0
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua17
-rw-r--r--test/functional/fixtures/lua/syntax_error.lua1
-rw-r--r--test/functional/helpers.lua13
-rw-r--r--test/functional/legacy/assert_spec.lua12
-rw-r--r--test/functional/legacy/backspace_opt_spec.lua67
-rw-r--r--test/functional/legacy/memory_usage_spec.lua46
-rw-r--r--test/functional/lua/buffer_updates_spec.lua90
-rw-r--r--test/functional/lua/treesitter_spec.lua922
-rw-r--r--test/functional/lua/vim_spec.lua15
-rw-r--r--test/functional/plugin/lsp_spec.lua42
-rw-r--r--test/functional/provider/clipboard_spec.lua8
-rw-r--r--test/functional/provider/define_spec.lua8
-rw-r--r--test/functional/terminal/tui_spec.lua2
-rw-r--r--test/functional/treesitter/highlight_spec.lua475
-rw-r--r--test/functional/treesitter/language_spec.lua71
-rw-r--r--test/functional/treesitter/parser_spec.lua576
-rw-r--r--test/functional/ui/fold_spec.lua70
-rw-r--r--test/functional/ui/mouse_spec.lua22
-rw-r--r--test/functional/ui/multigrid_spec.lua71
-rw-r--r--test/functional/ui/screen.lua13
-rw-r--r--test/functional/ui/searchhl_spec.lua29
-rw-r--r--test/functional/ui/sign_spec.lua66
38 files changed, 1947 insertions, 1046 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 8ed642b43e..fb8ed6a9d7 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -392,6 +392,129 @@ describe('api/buf', function()
end)
end)
+ describe('nvim_buf_get_lines, nvim_buf_set_text', function()
+ local get_lines, set_text = curbufmeths.get_lines, curbufmeths.set_text
+
+ it('works', function()
+ insert([[
+ hello foo!
+ text
+ ]])
+
+ eq({'hello foo!'}, get_lines(0, 1, true))
+
+
+ -- can replace a single word
+ set_text(0, 6, 0, 9, {'world'})
+ eq({'hello world!', 'text'}, get_lines(0, 2, true))
+
+ -- can insert text
+ set_text(0, 0, 0, 0, {'well '})
+ eq({'well hello world!', 'text'}, get_lines(0, 2, true))
+
+ -- can delete text
+ set_text(0, 0, 0, 5, {''})
+ eq({'hello world!', 'text'}, get_lines(0, 2, true))
+
+ -- can replace with multiple lines
+ set_text(0, 6, 0, 11, {'foo', 'wo', 'more'})
+ eq({'hello foo', 'wo', 'more!', 'text'}, get_lines(0, 4, true))
+
+ -- will join multiple lines if needed
+ set_text(0, 6, 3, 4, {'bar'})
+ eq({'hello bar'}, get_lines(0, 1, true))
+ end)
+
+ it('works with undo', function()
+ insert([[
+ hello world!
+ foo bar
+ ]])
+
+ -- setting text
+ set_text(0, 0, 0, 0, {'well '})
+ feed('u')
+ eq({'hello world!'}, get_lines(0, 1, true))
+
+ -- deleting text
+ set_text(0, 0, 0, 6, {''})
+ feed('u')
+ eq({'hello world!'}, get_lines(0, 1, true))
+
+ -- inserting newlines
+ set_text(0, 0, 0, 0, {'hello', 'mr '})
+ feed('u')
+ eq({'hello world!'}, get_lines(0, 1, true))
+
+ -- deleting newlines
+ set_text(0, 0, 1, 4, {'hello'})
+ feed('u')
+ eq({'hello world!'}, get_lines(0, 1, true))
+ end)
+
+ it('updates the cursor position', function()
+ insert([[
+ hello world!
+ ]])
+
+ -- position the cursor on `!`
+ curwin('set_cursor', {1, 11})
+ -- replace 'world' with 'foo'
+ set_text(0, 6, 0, 11, {'foo'})
+ eq('hello foo!', curbuf_depr('get_line', 0))
+ -- cursor should be moved left by two columns (replacement is shorter by 2 chars)
+ eq({1, 9}, curwin('get_cursor'))
+ end)
+
+ it('can handle NULs', function()
+ set_text(0, 0, 0, 0, {'ab\0cd'})
+ eq('ab\0cd', curbuf_depr('get_line', 0))
+ end)
+
+ it('adjusts extmarks', function()
+ local ns = request('nvim_create_namespace', "my-fancy-plugin")
+ insert([[
+ foo bar
+ baz
+ ]])
+ local id1 = curbufmeths.set_extmark(ns, 0, 1, {})
+ local id2 = curbufmeths.set_extmark(ns, 0, 7, {})
+ local id3 = curbufmeths.set_extmark(ns, 1, 1, {})
+ set_text(0, 4, 0, 7, {"q"})
+
+ eq({'foo q', 'baz'}, get_lines(0, 2, true))
+ -- mark before replacement point is unaffected
+ eq({0, 1}, curbufmeths.get_extmark_by_id(ns, id1, {}))
+ -- mark gets shifted back because the replacement was shorter
+ eq({0, 5}, curbufmeths.get_extmark_by_id(ns, id2, {}))
+ -- mark on the next line is unaffected
+ eq({1, 1}, curbufmeths.get_extmark_by_id(ns, id3, {}))
+
+ -- replacing the text spanning two lines will adjust the mark on the next line
+ set_text(0, 3, 1, 3, {"qux"})
+ eq({'fooqux', ''}, get_lines(0, 2, true))
+ eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id3, {}))
+ -- but mark before replacement point is still unaffected
+ eq({0, 1}, curbufmeths.get_extmark_by_id(ns, id1, {}))
+ -- and the mark in the middle was shifted to the end of the insertion
+ eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id2, {}))
+
+ -- marks should be put back into the same place after undoing
+ set_text(0, 0, 0, 2, {''})
+ feed('u')
+ eq({0, 1}, curbufmeths.get_extmark_by_id(ns, id1, {}))
+ eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id2, {}))
+ eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id3, {}))
+
+ -- marks should be shifted over by the correct number of bytes for multibyte
+ -- chars
+ set_text(0, 0, 0, 0, {'Ø'})
+ eq({0, 3}, curbufmeths.get_extmark_by_id(ns, id1, {}))
+ eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id2, {}))
+ eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id3, {}))
+ end)
+ end)
+
describe('nvim_buf_get_offset', function()
local get_offset = curbufmeths.get_offset
it('works', function()
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index d8a9c3b411..4194945645 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -809,4 +809,9 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
command('normal lhs')
eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1))
end)
+
+ it("does not crash when setting keymap in a non-existing buffer #13541", function()
+ pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
+ helpers.assert_alive()
+ end)
end)
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 29cd38ef0d..9ee2570798 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -3,6 +3,8 @@ local eq, clear, eval, command, nvim, next_msg =
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim,
helpers.next_msg
local meths = helpers.meths
+local exec_lua = helpers.exec_lua
+local retry = helpers.retry
describe('notify', function()
local channel
@@ -72,4 +74,18 @@ describe('notify', function()
nvim('unsubscribe', 'event1')
eq(2, eval('1+1')) -- Still alive?
end)
+
+ it('cancels stale events on channel close', function()
+ if helpers.pending_win32(pending) then return end
+ local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
+ eq({id=catchan, stream='job', mode='rpc', client = {}}, exec_lua ([[
+ vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'})
+ vim.rpcnotify(..., "nvim_subscribe", "daily_rant")
+ return vim.api.nvim_get_chan_info(...)
+ ]], catchan))
+ eq(2, eval('1+1')) -- Still alive?
+ eq({false, 'Invalid channel: '..catchan},
+ exec_lua ([[ return {pcall(vim.rpcrequest, ..., 'nvim_eval', '1+1')}]], catchan))
+ retry(nil, 3000, function() eq({}, meths.get_chan_info(catchan)) end) -- cat be dead :(
+ end)
end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index eb5fd7eca7..30128e9c40 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -972,6 +972,12 @@ describe('API', function()
nvim("input", "gu")
eq({mode='no', blocking=false}, nvim("get_mode"))
end)
+
+ it("at '-- More --' prompt returns blocking=true #11899", function()
+ command('set more')
+ feed(':digraphs<cr>')
+ eq({mode='rm', blocking=true}, nvim("get_mode"))
+ end)
end)
describe('RPC (K_EVENT) #6166', function()
@@ -1921,4 +1927,79 @@ describe('API', function()
eq({}, meths.get_runtime_file("foobarlang/", true))
end)
end)
+
+ describe('nvim_get_all_options_info', function()
+ it('should have key value pairs of option names', function()
+ local options_info = meths.get_all_options_info()
+ neq(nil, options_info.listchars)
+ neq(nil, options_info.tabstop)
+
+ eq(meths.get_option_info'winhighlight', options_info.winhighlight)
+ end)
+ end)
+
+ describe('nvim_get_option_info', function()
+ it('should error for unknown options', function()
+ eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus'))
+ end)
+
+ it('should return the same options for short and long name', function()
+ eq(meths.get_option_info'winhl', meths.get_option_info'winhighlight')
+ end)
+
+ it('should have information about window options', function()
+ eq({
+ commalist = false;
+ default = "";
+ flaglist = false;
+ global_local = false;
+ last_set_chan = 0;
+ last_set_linenr = 0;
+ last_set_sid = 0;
+ name = "winhighlight";
+ scope = "win";
+ shortname = "winhl";
+ type = "string";
+ was_set = false;
+ }, meths.get_option_info'winhl')
+ end)
+
+ it('should have information about buffer options', function()
+ eq({
+ commalist = false,
+ default = "",
+ flaglist = false,
+ global_local = false,
+ last_set_chan = 0,
+ last_set_linenr = 0,
+ last_set_sid = 0,
+ name = "filetype",
+ scope = "buf",
+ shortname = "ft",
+ type = "string",
+ was_set = false
+ }, meths.get_option_info'filetype')
+ end)
+
+ it('should have information about global options', function()
+ -- precondition: the option was changed from its default
+ -- in test setup.
+ eq(false, meths.get_option'showcmd')
+
+ eq({
+ commalist = false,
+ default = true,
+ flaglist = false,
+ global_local = false,
+ last_set_chan = 0,
+ last_set_linenr = 0,
+ last_set_sid = -2,
+ name = "showcmd",
+ scope = "global",
+ shortname = "sc",
+ type = "boolean",
+ was_set = true
+ }, meths.get_option_info'showcmd')
+ end)
+ end)
end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index ff0fdbea45..d5f03db03a 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -428,9 +428,9 @@ end)
describe('clean', function()
clear()
- ok(string.match(meths.get_option('runtimepath'), funcs.stdpath('config')) ~= nil)
+ ok(string.find(meths.get_option('runtimepath'), funcs.stdpath('config'), 1, true) ~= nil)
clear('--clean')
- ok(string.match(meths.get_option('runtimepath'), funcs.stdpath('config')) == nil)
+ ok(string.find(meths.get_option('runtimepath'), funcs.stdpath('config'), 1, true) == nil)
end)
describe('user config init', function()
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua
index ed110efeb4..7d09a652ba 100644
--- a/test/functional/eval/api_functions_spec.lua
+++ b/test/functional/eval/api_functions_spec.lua
@@ -47,6 +47,10 @@ describe('eval-API', function()
eq('Vim(call):E5555: API call: Invalid buffer id: 17', err)
end)
+ it('cannot change texts if textlocked', function()
+ command("autocmd TextYankPost <buffer> ++once call nvim_buf_set_lines(0, 0, -1, v:false, [])")
+ eq('Vim(call):E5555: API call: E523: Not allowed here', pcall_err(command, "normal! yy"))
+ end)
it("use buffer numbers and windows ids as handles", function()
local screen = Screen.new(40, 8)
diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua
index 54d2dc960b..9e19568249 100644
--- a/test/functional/eval/environ_spec.lua
+++ b/test/functional/eval/environ_spec.lua
@@ -3,6 +3,11 @@ local clear = helpers.clear
local eq = helpers.eq
local environ = helpers.funcs.environ
local exists = helpers.funcs.exists
+local system = helpers.funcs.system
+local nvim_prog = helpers.nvim_prog
+local command = helpers.command
+local eval = helpers.eval
+local setenv = helpers.funcs.setenv
describe('environment variables', function()
it('environ() handles empty env variable', function()
@@ -17,3 +22,59 @@ describe('environment variables', function()
eq(0, exists('$DOES_NOT_EXIST'))
end)
end)
+
+describe('empty $HOME', function()
+ local original_home = os.getenv('HOME')
+
+ -- recover $HOME after each test
+ after_each(function()
+ if original_home ~= nil then
+ setenv('HOME', original_home)
+ end
+ os.remove('test_empty_home')
+ os.remove('./~')
+ end)
+
+ local function tilde_in_cwd()
+ -- get files in cwd
+ command("let test_empty_home_cwd_files = split(globpath('.', '*'), '\n')")
+ -- get the index of the file named '~'
+ command('let test_empty_home_tilde_index = index(test_empty_home_cwd_files, "./~")')
+ return eval('test_empty_home_tilde_index') ~= -1
+ end
+
+ local function write_and_test_tilde()
+ system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless',
+ '-c', 'write test_empty_home', '+q'})
+ eq(false, tilde_in_cwd())
+ end
+
+ it("'~' folder not created in cwd if $HOME and related env not defined", function()
+ command("unlet $HOME")
+ write_and_test_tilde()
+
+ command("let $HOMEDRIVE='C:'")
+ command("let $USERPROFILE='C:\\'")
+ write_and_test_tilde()
+
+ command("unlet $HOMEDRIVE")
+ write_and_test_tilde()
+
+ command("unlet $USERPROFILE")
+ write_and_test_tilde()
+
+ command("let $HOME='%USERPROFILE%'")
+ command("let $USERPROFILE='C:\\'")
+ write_and_test_tilde()
+ end)
+
+ it("'~' folder not created in cwd if writing a file with invalid $HOME", function()
+ setenv('HOME', '/path/does/not/exist')
+ write_and_test_tilde()
+ end)
+
+ it("'~' folder not created in cwd if writing a file with $HOME=''", function()
+ command("let $HOME=''")
+ write_and_test_tilde()
+ end)
+end)
diff --git a/test/functional/eval/executable_spec.lua b/test/functional/eval/executable_spec.lua
index a1cf056907..28aefb72e5 100644
--- a/test/functional/eval/executable_spec.lua
+++ b/test/functional/eval/executable_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local eq, clear, call, iswin, write_file, command =
helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file,
helpers.command
+local exc_exec = helpers.exc_exec
local eval = helpers.eval
describe('executable()', function()
@@ -10,6 +11,20 @@ describe('executable()', function()
it('returns 1 for commands in $PATH', function()
local exe = iswin() and 'ping' or 'ls'
eq(1, call('executable', exe))
+ command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
+ eq(1, call('executable', 'null'))
+ eq(1, call('executable', 'true'))
+ eq(1, call('executable', 'false'))
+ end)
+
+ it('fails for invalid values', function()
+ for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do
+ eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
+ end
+ command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
+ for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
+ eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
+ end
end)
it('returns 0 for non-existent files', function()
diff --git a/test/functional/eval/exepath_spec.lua b/test/functional/eval/exepath_spec.lua
index 10a11aeacc..08d2c59af8 100644
--- a/test/functional/eval/exepath_spec.lua
+++ b/test/functional/eval/exepath_spec.lua
@@ -1,14 +1,40 @@
local helpers = require('test.functional.helpers')(after_each)
local eq, clear, call, iswin =
helpers.eq, helpers.clear, helpers.call, helpers.iswin
+local command = helpers.command
+local exc_exec = helpers.exc_exec
+local matches = helpers.matches
-describe('exepath() (Windows)', function()
- if not iswin() then return end -- N/A for Unix.
+describe('exepath()', function()
+ before_each(clear)
- it('append extension if omitted', function()
- local filename = 'cmd'
- local pathext = '.exe'
- clear({env={PATHEXT=pathext}})
- eq(call('exepath', filename..pathext), call('exepath', filename))
+ it('returns 1 for commands in $PATH', function()
+ local exe = iswin() and 'ping' or 'ls'
+ local ext_pat = iswin() and '%.EXE$' or '$'
+ matches(exe .. ext_pat, call('exepath', exe))
+ command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
+ ext_pat = iswin() and '%.CMD$' or '$'
+ matches('null' .. ext_pat, call('exepath', 'null'))
+ matches('true' .. ext_pat, call('exepath', 'true'))
+ matches('false' .. ext_pat, call('exepath', 'false'))
end)
+
+ it('fails for invalid values', function()
+ for _, input in ipairs({'""', 'v:null', 'v:true', 'v:false', '{}', '[]'}) do
+ eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
+ end
+ command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
+ for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
+ eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
+ end
+ end)
+
+ if iswin() then
+ it('append extension if omitted', function()
+ local filename = 'cmd'
+ local pathext = '.exe'
+ clear({env={PATHEXT=pathext}})
+ eq(call('exepath', filename..pathext), call('exepath', filename))
+ end)
+ end
end)
diff --git a/test/functional/eval/function_spec.lua b/test/functional/eval/function_spec.lua
index 776e760aaf..ce8850fcc2 100644
--- a/test/functional/eval/function_spec.lua
+++ b/test/functional/eval/function_spec.lua
@@ -2,7 +2,10 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
+local matches = helpers.matches
local exc_exec = helpers.exc_exec
+local iswin = helpers.iswin
+local eval = helpers.eval
describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
local max_func_args = 20 -- from eval.h
@@ -27,3 +30,8 @@ describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
eq('Vim(call):E740: Too many arguments for function rpcnotify', ret)
end)
end)
+
+it('windowsversion()', function()
+ clear()
+ matches(iswin() and '^%d+%.%d+$' or '^$', eval('windowsversion()'))
+end)
diff --git a/test/functional/fixtures/bin/false b/test/functional/fixtures/bin/false
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/bin/false
diff --git a/test/functional/fixtures/bin/false.cmd b/test/functional/fixtures/bin/false.cmd
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/bin/false.cmd
diff --git a/test/functional/fixtures/bin/null b/test/functional/fixtures/bin/null
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/bin/null
diff --git a/test/functional/fixtures/bin/null.cmd b/test/functional/fixtures/bin/null.cmd
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/bin/null.cmd
diff --git a/test/functional/fixtures/bin/true b/test/functional/fixtures/bin/true
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/bin/true
diff --git a/test/functional/fixtures/bin/true.cmd b/test/functional/fixtures/bin/true.cmd
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/bin/true.cmd
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index a30eb748d0..252db88b6b 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -109,6 +109,23 @@ function tests.basic_init()
}
end
+function tests.check_workspace_configuration()
+ skeleton {
+ on_init = function(_params)
+ return { capabilities = {} }
+ end;
+ body = function()
+ notify('start')
+ notify('workspace/configuration', { items = {
+ { section = "testSetting1" };
+ { section = "testSetting2" };
+ } })
+ expect_notification('workspace/configuration', { true; vim.NIL})
+ notify('shutdown')
+ end;
+ }
+end
+
function tests.basic_check_capabilities()
skeleton {
on_init = function(params)
diff --git a/test/functional/fixtures/lua/syntax_error.lua b/test/functional/fixtures/lua/syntax_error.lua
new file mode 100644
index 0000000000..8c0cf026ee
--- /dev/null
+++ b/test/functional/fixtures/lua/syntax_error.lua
@@ -0,0 +1 @@
+- <= the syntax error
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 0829560b9c..4acb1a7d8d 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -725,6 +725,19 @@ function module.pending_win32(pending_fn)
end
end
+function module.pending_c_parser(pending_fn)
+ local status, msg = unpack(module.exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]]))
+ if not status then
+ if module.isCI() then
+ error("treesitter C parser not found, required on CI: " .. msg)
+ else
+ pending_fn 'no C parser, skipping'
+ return true
+ end
+ end
+ return false
+end
+
-- Calls pending() and returns `true` if the system is too slow to
-- run fragile or expensive tests. Else returns `false`.
function module.skip_fragile(pending_fn, cond)
diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua
index d48b8882af..515d6d91b8 100644
--- a/test/functional/legacy/assert_spec.lua
+++ b/test/functional/legacy/assert_spec.lua
@@ -242,9 +242,9 @@ describe('assert function:', function()
-- assert_fails({cmd}, [, {error}])
describe('assert_fails', function()
it('should change v:errors when error does not match v:errmsg', function()
- eq(1, eval([[assert_fails('xxx', {})]]))
- command([[call assert_match("Expected {} but got 'E731:", v:errors[0])]])
- expected_errors({"Expected {} but got 'E731: using Dictionary as a String'"})
+ eq(1, eval([[assert_fails('xxx', 'E12345')]]))
+ command([[call assert_match("Expected 'E12345' but got 'E492:", v:errors[0])]])
+ expected_errors({"Expected 'E12345' but got 'E492: Not an editor command: xxx': xxx"})
end)
it('should not change v:errors when cmd errors', function()
@@ -258,9 +258,9 @@ describe('assert function:', function()
end)
it('can specify and get a message about what failed', function()
- eq(1, eval([[assert_fails('xxx', {}, 'stupid')]]))
- command([[call assert_match("stupid: Expected {} but got 'E731:", v:errors[0])]])
- expected_errors({"stupid: Expected {} but got 'E731: using Dictionary as a String'"})
+ eq(1, eval([[assert_fails('xxx', 'E9876', 'stupid')]]))
+ command([[call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0])]])
+ expected_errors({"stupid: Expected 'E9876' but got 'E492: Not an editor command: xxx': stupid"})
end)
it('can specify and get a message even when cmd succeeds', function()
diff --git a/test/functional/legacy/backspace_opt_spec.lua b/test/functional/legacy/backspace_opt_spec.lua
deleted file mode 100644
index 90bc6f74f0..0000000000
--- a/test/functional/legacy/backspace_opt_spec.lua
+++ /dev/null
@@ -1,67 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local call, clear = helpers.call, helpers.clear
-local source, eq, nvim = helpers.source, helpers.eq, helpers.meths
-
-describe("test 'backspace' settings", function()
- before_each(function()
- clear()
-
- source([[
- func Exec(expr)
- let str=''
- try
- exec a:expr
- catch /.*/
- let str=v:exception
- endtry
- return str
- endfunc
-
- func Test_backspace_option()
- set backspace=
- call assert_equal('', &backspace)
- set backspace=indent
- call assert_equal('indent', &backspace)
- set backspace=eol
- call assert_equal('eol', &backspace)
- set backspace=start
- call assert_equal('start', &backspace)
- " Add the value
- set backspace=
- set backspace=indent
- call assert_equal('indent', &backspace)
- set backspace+=eol
- call assert_equal('indent,eol', &backspace)
- set backspace+=start
- call assert_equal('indent,eol,start', &backspace)
- " Delete the value
- set backspace-=indent
- call assert_equal('eol,start', &backspace)
- set backspace-=start
- call assert_equal('eol', &backspace)
- set backspace-=eol
- call assert_equal('', &backspace)
- " Check the error
- call assert_equal(0, match(Exec('set backspace=ABC'), '.*E474'))
- call assert_equal(0, match(Exec('set backspace+=def'), '.*E474'))
- " NOTE: Vim doesn't check following error...
- "call assert_equal(0, match(Exec('set backspace-=ghi'), '.*E474'))
-
- " Check backwards compatibility with version 5.4 and earlier
- set backspace=0
- call assert_equal('0', &backspace)
- set backspace=1
- call assert_equal('1', &backspace)
- set backspace=2
- call assert_equal('2', &backspace)
- call assert_false(match(Exec('set backspace=3'), '.*E474'))
- call assert_false(match(Exec('set backspace=10'), '.*E474'))
- endfunc
- ]])
- end)
-
- it('works', function()
- call('Test_backspace_option')
- eq({}, nvim.get_vvar('errors'))
- end)
-end)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index fb0bacc2d2..5f7bbd887f 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -10,6 +10,29 @@ local source = helpers.source
local poke_eventloop = helpers.poke_eventloop
local uname = helpers.uname
local load_adjust = helpers.load_adjust
+local isCI = helpers.isCI
+
+local function isasan()
+ local version = eval('execute("version")')
+ return version:match('-fsanitize=[a-z,]*address')
+end
+
+clear()
+if isasan() then
+ pending('ASAN build is difficult to estimate memory usage', function() end)
+ return
+elseif iswin() then
+ if isCI('github') then
+ pending('Windows runners in Github Actions do not have a stable environment to estimate memory usage', function() end)
+ return
+ elseif eval("executable('wmic')") == 0 then
+ pending('missing "wmic" command', function() end)
+ return
+ end
+elseif eval("executable('ps')") == 0 then
+ pending('missing "ps" command', function() end)
+ return
+end
local monitor_memory_usage = {
memory_usage = function(self)
@@ -71,11 +94,6 @@ describe('memory usage', function()
end
end
- local function isasan()
- local version = eval('execute("version")')
- return version:match('-fsanitize=[a-z,]*address')
- end
-
before_each(clear)
--[[
@@ -83,15 +101,6 @@ describe('memory usage', function()
just after it finishes.
]]--
it('function capture vargs', function()
- if isasan() then
- pending('ASAN build is difficult to estimate memory usage')
- end
- if iswin() and eval("executable('wmic')") == 0 then
- pending('missing "wmic" command')
- elseif eval("executable('ps')") == 0 then
- pending('missing "ps" command')
- end
-
local pid = eval('getpid()')
local before = monitor_memory_usage(pid)
source([[
@@ -125,15 +134,6 @@ describe('memory usage', function()
increase so much even when rerun Xtest.vim since system memory caches.
]]--
it('function capture lvars', function()
- if isasan() then
- pending('ASAN build is difficult to estimate memory usage')
- end
- if iswin() and eval("executable('wmic')") == 0 then
- pending('missing "wmic" command')
- elseif eval("executable('ps')") == 0 then
- pending('missing "ps" command')
- end
-
local pid = eval('getpid()')
local before = monitor_memory_usage(pid)
local fname = source([[
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 7e4de7c39a..67dc5f5a16 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -25,14 +25,14 @@ local function attach_buffer(evname)
local evname = ...
local events = {}
- function test_register(bufnr, id, changedtick, utf_sizes)
+ function test_register(bufnr, id, changedtick, utf_sizes, preview)
local function callback(...)
table.insert(events, {id, ...})
if test_unreg == id then
return true
end
end
- local opts = {[evname]=callback, on_detach=callback, utf_sizes=utf_sizes}
+ local opts = {[evname]=callback, on_detach=callback, utf_sizes=utf_sizes, preview=preview}
if changedtick then
opts.on_changedtick = callback
end
@@ -288,9 +288,10 @@ describe('lua: nvim_buf_attach on_bytes', function()
-- TODO: while we are brewing the real strong coffe,
-- verify should check buf_get_offset after every check_events
if verify then
- meths.buf_get_offset(0, meths.buf_line_count(0))
+ local len = meths.buf_get_offset(0, meths.buf_line_count(0))
+ eq(len == -1 and 1 or len, string.len(shadowbytes))
end
- exec_lua("return test_register(...)", 0, "test1",false, nil)
+ exec_lua("return test_register(...)", 0, "test1", false, false, true)
meths.buf_get_changedtick(0)
local verify_name = "test1"
@@ -493,6 +494,87 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+
+ it('inccomand=nosplit and substitute', function()
+ if verify then pending("Verification can't be done when previewing") end
+
+ local check_events = setup_eventcheck(verify, {"abcde"})
+ meths.set_option('inccommand', 'nosplit')
+
+ feed ':%s/bcd/'
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 };
+ }
+
+ feed 'a'
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 };
+ }
+ end)
+
+ it('nvim_buf_set_text insert', function()
+ local check_events = setup_eventcheck(verify, {"bastext"})
+ meths.buf_set_text(0, 0, 3, 0, 3, {"fiol","kontra"})
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 3, 3, 0, 0, 0, 1, 6, 11 };
+ }
+
+ meths.buf_set_text(0, 1, 6, 1, 6, {"punkt","syntgitarr","övnings"})
+ check_events {
+ { "test1", "bytes", 1, 4, 1, 6, 14, 0, 0, 0, 2, 8, 25 };
+ }
+
+ eq({ "basfiol", "kontrapunkt", "syntgitarr", "övningstext" },
+ meths.buf_get_lines(0, 0, -1, true))
+ end)
+
+ it('nvim_buf_set_text replace', function()
+ local check_events = setup_eventcheck(verify, origlines)
+
+ meths.buf_set_text(0, 2, 3, 2, 8, {"very text"})
+ check_events {
+ { "test1", "bytes", 1, 3, 2, 3, 35, 0, 5, 5, 0, 9, 9 };
+ }
+
+ meths.buf_set_text(0, 3, 5, 3, 7, {" splitty","line "})
+ check_events {
+ { "test1", "bytes", 1, 4, 3, 5, 57, 0, 2, 2, 1, 5, 14 };
+ }
+
+ meths.buf_set_text(0, 0, 8, 1, 2, {"JOINY"})
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 8, 8, 1, 2, 10, 0, 5, 5 };
+ }
+
+ meths.buf_set_text(0, 4, 0, 6, 0, {"was 5,6",""})
+ check_events {
+ { "test1", "bytes", 1, 6, 4, 0, 75, 2, 0, 32, 1, 0, 8 };
+ }
+
+ eq({ "originalJOINYiginal line 2", "orivery text line 3", "origi splitty",
+ "line l line 4", "was 5,6", " indented line" },
+ meths.buf_get_lines(0, 0, -1, true))
+
+ end)
+
+ it('nvim_buf_set_text delete', function()
+ local check_events = setup_eventcheck(verify, origlines)
+
+ -- really {""} but accepts {} as a shorthand
+ meths.buf_set_text(0, 0, 0, 1, 0, {})
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 };
+ }
+
+ -- TODO(bfredl): this works but is not as convenient as set_lines
+ meths.buf_set_text(0, 4, 15, 5, 17, {""})
+ check_events {
+ { "test1", "bytes", 1, 4, 4, 15, 79, 1, 17, 18, 0, 0, 0 };
+ }
+ eq({ "original line 2", "original line 3", "original line 4",
+ "original line 5", "original line 6" },
+ meths.buf_get_lines(0, 0, -1, true))
+ end)
end
describe('(with verify) handles', function()
diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua
deleted file mode 100644
index 65dc1b3e03..0000000000
--- a/test/functional/lua/treesitter_spec.lua
+++ /dev/null
@@ -1,922 +0,0 @@
--- Test suite for testing interactions with API bindings
-local helpers = require('test.functional.helpers')(after_each)
-local Screen = require('test.functional.ui.screen')
-
-local clear = helpers.clear
-local eq = helpers.eq
-local insert = helpers.insert
-local exec_lua = helpers.exec_lua
-local feed = helpers.feed
-local pcall_err = helpers.pcall_err
-local matches = helpers.matches
-
-before_each(clear)
-
-describe('treesitter API', function()
- -- error tests not requiring a parser library
- it('handles missing language', function()
- eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
- pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')"))
-
- -- actual message depends on platform
- matches("Error executing lua: Failed to load parser: uv_dlopen: .+",
- pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')"))
-
- eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
- pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')"))
- end)
-end)
-
-describe('treesitter API with C parser', function()
- local function check_parser()
- local status, msg = unpack(exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]]))
- if not status then
- if helpers.isCI() then
- error("treesitter C parser not found, required on CI: " .. msg)
- else
- pending('no C parser, skipping')
- end
- end
- return status
- end
-
- it('parses buffer', function()
- if helpers.pending_win32(pending) or not check_parser() then return end
-
- insert([[
- int main() {
- int x = 3;
- }]])
-
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- root = tree:root()
- lang = vim.treesitter.inspect_language('c')
- ]])
-
- eq("<tree>", exec_lua("return tostring(tree)"))
- eq("<node translation_unit>", exec_lua("return tostring(root)"))
- eq({0,0,3,0}, exec_lua("return {root:range()}"))
-
- eq(1, exec_lua("return root:child_count()"))
- exec_lua("child = root:child(0)")
- eq("<node function_definition>", exec_lua("return tostring(child)"))
- eq({0,0,2,1}, exec_lua("return {child:range()}"))
-
- eq("function_definition", exec_lua("return child:type()"))
- eq(true, exec_lua("return child:named()"))
- eq("number", type(exec_lua("return child:symbol()")))
- eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]"))
-
- exec_lua("anon = root:descendant_for_range(0,8,0,9)")
- eq("(", exec_lua("return anon:type()"))
- eq(false, exec_lua("return anon:named()"))
- eq("number", type(exec_lua("return anon:symbol()")))
- eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]"))
-
- exec_lua("descendant = root:descendant_for_range(1,2,1,12)")
- eq("<node declaration>", exec_lua("return tostring(descendant)"))
- eq({1,2,1,12}, exec_lua("return {descendant:range()}"))
- eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()"))
-
- feed("2G7|ay")
- exec_lua([[
- tree2 = parser:parse()[1]
- root2 = tree2:root()
- descendant2 = root2:descendant_for_range(1,2,1,13)
- ]])
- eq(false, exec_lua("return tree2 == tree1"))
- eq(false, exec_lua("return root2 == root"))
- eq("<node declaration>", exec_lua("return tostring(descendant2)"))
- eq({1,2,1,13}, exec_lua("return {descendant2:range()}"))
-
- eq(true, exec_lua("return child == child"))
- -- separate lua object, but represents same node
- eq(true, exec_lua("return child == root:child(0)"))
- eq(false, exec_lua("return child == descendant2"))
- eq(false, exec_lua("return child == nil"))
- eq(false, exec_lua("return child == tree"))
-
- eq("string", exec_lua("return type(child:id())"))
- eq(true, exec_lua("return child:id() == child:id()"))
- -- separate lua object, but represents same node
- eq(true, exec_lua("return child:id() == root:child(0):id()"))
- eq(false, exec_lua("return child:id() == descendant2:id()"))
- eq(false, exec_lua("return child:id() == nil"))
- eq(false, exec_lua("return child:id() == tree"))
-
- -- unchanged buffer: return the same tree
- eq(true, exec_lua("return parser:parse()[1] == tree2"))
- end)
-
- local test_text = [[
-void ui_refresh(void)
-{
- int width = INT_MAX, height = INT_MAX;
- bool ext_widgets[kUIExtCount];
- for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
- ext_widgets[i] = true;
- }
-
- bool inclusive = ui_override();
- for (size_t i = 0; i < ui_count; i++) {
- UI *ui = uis[i];
- width = MIN(ui->width, width);
- height = MIN(ui->height, height);
- foo = BAR(ui->bazaar, bazaar);
- for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
- }
- }
-}]]
-
- it('allows to iterate over nodes children', function()
- if not check_parser() then return end
-
- insert(test_text);
-
- local res = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
-
- func_node = parser:parse()[1]:root():child(0)
-
- res = {}
- for node, field in func_node:iter_children() do
- table.insert(res, {node:type(), field})
- end
- return res
- ]])
-
- eq({
- {"primitive_type", "type"},
- {"function_declarator", "declarator"},
- {"compound_statement", "body"}
- }, res)
- end)
-
- it('allows to get a child by field', function()
- if not check_parser() then return end
-
- insert(test_text);
-
- local res = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
-
- func_node = parser:parse()[1]:root():child(0)
-
- local res = {}
- for _, node in ipairs(func_node:field("type")) do
- table.insert(res, {node:type(), node:range()})
- end
- return res
- ]])
-
- eq({{ "primitive_type", 0, 0, 0, 4 }}, res)
-
- local res_fail = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
-
- return #func_node:field("foo") == 0
- ]])
-
- assert(res_fail)
- end)
-
- local query = [[
- ((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN"))
- "for" @keyword
- (primitive_type) @type
- (field_expression argument: (identifier) @fieldarg)
- ]]
-
- it("supports runtime queries", function()
- if not check_parser() then return end
-
- local ret = exec_lua [[
- return require"vim.treesitter.query".get_query("c", "highlights").captures[1]
- ]]
-
- eq('variable', ret)
- end)
-
- it('support query and iter by capture', function()
- if not check_parser() then return end
-
- insert(test_text)
-
- local res = exec_lua([[
- cquery = vim.treesitter.parse_query("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
- -- can't transmit node over RPC. just check the name and range
- table.insert(res, {cquery.captures[cid], node:type(), node:range()})
- end
- return res
- ]], query)
-
- eq({
- { "type", "primitive_type", 8, 2, 8, 6 },
- { "keyword", "for", 9, 2, 9, 5 },
- { "type", "primitive_type", 9, 7, 9, 13 },
- { "minfunc", "identifier", 11, 12, 11, 15 },
- { "fieldarg", "identifier", 11, 16, 11, 18 },
- { "min_id", "identifier", 11, 27, 11, 32 },
- { "minfunc", "identifier", 12, 13, 12, 16 },
- { "fieldarg", "identifier", 12, 17, 12, 19 },
- { "min_id", "identifier", 12, 29, 12, 35 },
- { "fieldarg", "identifier", 13, 14, 13, 16 }
- }, res)
- end)
-
- it('support query and iter by match', function()
- if not check_parser() then return end
-
- insert(test_text)
-
- local res = exec_lua([[
- cquery = vim.treesitter.parse_query("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) 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
- ]], query)
-
- eq({
- { 3, { { "type", "primitive_type", 8, 2, 8, 6 } } },
- { 2, { { "keyword", "for", 9, 2, 9, 5 } } },
- { 3, { { "type", "primitive_type", 9, 7, 9, 13 } } },
- { 4, { { "fieldarg", "identifier", 11, 16, 11, 18 } } },
- { 1, { { "minfunc", "identifier", 11, 12, 11, 15 }, { "min_id", "identifier", 11, 27, 11, 32 } } },
- { 4, { { "fieldarg", "identifier", 12, 17, 12, 19 } } },
- { 1, { { "minfunc", "identifier", 12, 13, 12, 16 }, { "min_id", "identifier", 12, 29, 12, 35 } } },
- { 4, { { "fieldarg", "identifier", 13, 14, 13, 16 } } }
- }, res)
- end)
-
- it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function()
- if not check_parser() then return end
-
- insert('char* astring = "Hello World!";')
-
- local res = exec_lua([[
- cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))')
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) 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({
- { 1, { { "quote", '"', 0, 16, 0, 17 } } },
- { 2, { { "quote", '"', 0, 16, 0, 17 } } },
- { 1, { { "quote", '"', 0, 29, 0, 30 } } },
- { 2, { { "quote", '"', 0, 29, 0, 30 } } },
- }, res)
- end)
-
- it('allows to add predicates', function()
- insert([[
- int main(void) {
- return 0;
- }
- ]])
-
- local custom_query = "((identifier) @main (#is-main? @main))"
-
- local res = exec_lua([[
- local query = require"vim.treesitter.query"
-
- local function is_main(match, pattern, bufnr, predicate)
- local node = match[ predicate[2] ]
-
- return query.get_node_text(node, bufnr)
- end
-
- local parser = vim.treesitter.get_parser(0, "c")
-
- query.add_predicate("is-main?", is_main)
-
- local query = query.parse_query("c", ...)
-
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
- table.insert(nodes, {node:range()})
- end
-
- return nodes
- ]], custom_query)
-
- eq({{0, 4, 0, 8}}, res)
-
- local res_list = exec_lua[[
- local query = require'vim.treesitter.query'
-
- local list = query.list_predicates()
-
- table.sort(list)
-
- return list
- ]]
-
- eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
- end)
-
- local hl_text = [[
-/// Schedule Lua callback on main loop's event queue
-static int nlua_schedule(lua_State *const lstate)
-{
- if (lua_type(lstate, 1) != LUA_TFUNCTION
- || lstate != lstate) {
- lua_pushliteral(lstate, "vim.schedule: expected function");
- return lua_error(lstate);
- }
-
- LuaRef cb = nlua_ref(lstate, 1);
-
- multiqueue_put(main_loop.events, nlua_schedule_event,
- 1, (void *)(ptrdiff_t)cb);
- return 0;
-}]]
-
-local hl_query = [[
-(ERROR) @ErrorMsg
-
-"if" @keyword
-"else" @keyword
-"for" @keyword
-"return" @keyword
-
-"const" @type
-"static" @type
-"struct" @type
-"enum" @type
-"extern" @type
-
-(string_literal) @string
-
-(number_literal) @number
-(char_literal) @string
-
-(type_identifier) @type
-((type_identifier) @Special (#eq? @Special "LuaRef"))
-
-(primitive_type) @type
-(sized_type_specifier) @type
-
-; Use lua regexes
-((identifier) @Identifier (#contains? @Identifier "lua_"))
-((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$"))
-((identifier) @Normal (#vim-match? @Constant "^lstate$"))
-
-((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right))
-
-(comment) @comment
-]]
-
- describe('when highlighting', function()
- local screen
-
- before_each(function()
- screen = Screen.new(65, 18)
- screen:attach()
- screen:set_default_attr_ids({
- [1] = {bold = true, foreground = Screen.colors.Blue1},
- [2] = {foreground = Screen.colors.Blue1},
- [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
- [4] = {bold = true, foreground = Screen.colors.Brown},
- [5] = {foreground = Screen.colors.Magenta},
- [6] = {foreground = Screen.colors.Red},
- [7] = {bold = true, foreground = Screen.colors.SlateBlue},
- [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red},
- [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red},
- [11] = {foreground = Screen.colors.Cyan4},
- })
- end)
-
- it('supports highlighting', function()
- if not check_parser() then return end
-
- insert(hl_text)
- screen:expect{grid=[[
- /// Schedule Lua callback on main loop's event queue |
- static int nlua_schedule(lua_State *const lstate) |
- { |
- if (lua_type(lstate, 1) != LUA_TFUNCTION |
- || lstate != lstate) { |
- lua_pushliteral(lstate, "vim.schedule: expected function"); |
- return lua_error(lstate); |
- } |
- |
- LuaRef cb = nlua_ref(lstate, 1); |
- |
- multiqueue_put(main_loop.events, nlua_schedule_event, |
- 1, (void *)(ptrdiff_t)cb); |
- return 0; |
- ^} |
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- exec_lua([[
- local parser = vim.treesitter.get_parser(0, "c")
- local highlighter = vim.treesitter.highlighter
- local query = ...
- test_hl = highlighter.new(parser, {queries = {c = query}})
- ]], hl_query)
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- ^} |
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- feed("5Goc<esc>dd")
-
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- } |
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- feed('7Go*/<esc>')
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- {8:*^/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- } |
- {1:~ }|
- |
- ]]}
-
- feed('3Go/*<esc>')
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/^*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- {8:}} |
- |
- ]]}
-
- feed("gg$")
- feed("~")
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queu^E} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- {8:}} |
- |
- ]]}
-
-
- feed("re")
- screen:expect{grid=[[
- {2:/// Schedule Lua callback on main loop's event queu^e} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- {8:}} |
- |
- ]]}
- end)
-
- it("supports highlighting with custom parser", function()
- if not check_parser() then return end
-
- screen:set_default_attr_ids({ {bold = true, foreground = Screen.colors.SeaGreen4} })
-
- insert(test_text)
-
- screen:expect{ grid= [[
- int width = INT_MAX, height = INT_MAX; |
- bool ext_widgets[kUIExtCount]; |
- for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- bool inclusive = ui_override(); |
- for (size_t i = 0; i < ui_count; i++) { |
- UI *ui = uis[i]; |
- width = MIN(ui->width, width); |
- height = MIN(ui->height, height); |
- foo = BAR(ui->bazaar, bazaar); |
- for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]] }
-
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
- query = vim.treesitter.parse_query("c", "(declaration) @decl")
-
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
- table.insert(nodes, node)
- end
-
- parser:set_included_regions({nodes})
-
- local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}})
- ]])
-
- screen:expect{ grid = [[
- int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
- bool {1:ext_widgets}[{1:kUIExtCount}]; |
- for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- bool {1:inclusive} = {1:ui_override}(); |
- for (size_t {1:i} = 0; i < ui_count; i++) { |
- UI *{1:ui} = {1:uis}[{1:i}]; |
- width = MIN(ui->width, width); |
- height = MIN(ui->height, height); |
- foo = BAR(ui->bazaar, bazaar); |
- for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]] }
- end)
-
- it("supports highlighting injected languages", function()
- if not check_parser() then return end
-
- insert([[
- int x = INT_MAX;
- #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
- #define foo void main() { \
- return 42; \
- }
- ]])
-
- screen:expect{grid=[[
- int x = INT_MAX; |
- #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))|
- #define foo void main() { \ |
- return 42; \ |
- } |
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- |
- ]]}
-
- exec_lua([[
- local parser = vim.treesitter.get_parser(0, "c", {
- queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}
- })
- local highlighter = vim.treesitter.highlighter
- local query = ...
- test_hl = highlighter.new(parser, {queries = {c = query}})
- ]], hl_query)
-
- screen:expect{grid=[[
- {3:int} x = {5:INT_MAX}; |
- #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))|
- #define foo {3:void} main() { \ |
- {4:return} {5:42}; \ |
- } |
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- |
- ]]}
- end)
- end)
-
- it('inspects language', function()
- if not check_parser() then return end
-
- local keys, fields, symbols = unpack(exec_lua([[
- local lang = vim.treesitter.inspect_language('c')
- local keys, symbols = {}, {}
- for k,_ in pairs(lang) do
- keys[k] = true
- end
-
- -- symbols array can have "holes" and is thus not a valid msgpack array
- -- but we don't care about the numbers here (checked in the parser test)
- for _, v in pairs(lang.symbols) do
- table.insert(symbols, v)
- end
- return {keys, lang.fields, symbols}
- ]]))
-
- eq({fields=true, symbols=true}, keys)
-
- local fset = {}
- for _,f in pairs(fields) do
- eq("string", type(f))
- fset[f] = true
- end
- eq(true, fset["directive"])
- eq(true, fset["initializer"])
-
- local has_named, has_anonymous
- for _,s in pairs(symbols) do
- eq("string", type(s[1]))
- eq("boolean", type(s[2]))
- if s[1] == "for_statement" and s[2] == true then
- has_named = true
- elseif s[1] == "|=" and s[2] == false then
- has_anonymous = true
- end
- end
- eq({true,true}, {has_named,has_anonymous})
- end)
- it('allows to set simple ranges', function()
- if not check_parser() then return end
-
- insert(test_text)
-
- local res = exec_lua [[
- parser = vim.treesitter.get_parser(0, "c")
- return { parser:parse()[1]:root():range() }
- ]]
-
- eq({0, 0, 19, 0}, res)
-
- -- The following sets the included ranges for the current parser
- -- As stated here, this only includes the function (thus the whole buffer, without the last line)
- local res2 = exec_lua [[
- local root = parser:parse()[1]:root()
- parser:set_included_regions({{root:child(0)}})
- parser:invalidate()
- return { parser:parse()[1]:root():range() }
- ]]
-
- eq({0, 0, 18, 1}, res2)
-
- local range = exec_lua [[
- local res = {}
- for _, region in ipairs(parser:included_regions()) do
- for _, node in ipairs(region) do
- table.insert(res, {node:range()})
- end
- end
- return res
- ]]
-
- eq(range, { { 0, 0, 18, 1 } })
-
- local range_tbl = exec_lua [[
- parser:set_included_regions { { { 0, 0, 17, 1 } } }
- parser:parse()
- return parser:included_regions()
- ]]
-
- eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } })
- end)
- it("allows to set complex ranges", function()
- if not check_parser() then return end
-
- insert(test_text)
-
- local res = exec_lua [[
- parser = vim.treesitter.get_parser(0, "c")
- query = vim.treesitter.parse_query("c", "(declaration) @decl")
-
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
- table.insert(nodes, node)
- end
-
- parser:set_included_regions({nodes})
-
- local root = parser:parse()[1]:root()
-
- local res = {}
- for i=0,(root:named_child_count() - 1) do
- table.insert(res, { root:named_child(i):range() })
- end
- return res
- ]]
-
- eq({
- { 2, 2, 2, 40 },
- { 3, 2, 3, 32 },
- { 4, 7, 4, 25 },
- { 8, 2, 8, 33 },
- { 9, 7, 9, 20 },
- { 10, 4, 10, 20 },
- { 14, 9, 14, 27 } }, res)
- end)
-
- it("allows to create string parsers", function()
- local ret = exec_lua [[
- local parser = vim.treesitter.get_string_parser("int foo = 42;", "c")
- return { parser:parse()[1]:root():range() }
- ]]
-
- eq({ 0, 0, 0, 13 }, ret)
- end)
-
- it("allows to run queries with string parsers", function()
- local txt = [[
- int foo = 42;
- int bar = 13;
- ]]
-
- local ret = exec_lua([[
- local str = ...
- local parser = vim.treesitter.get_string_parser(str, "c")
-
- local nodes = {}
- local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))')
-
- for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do
- table.insert(nodes, { node:range() })
- end
-
- return nodes]], txt)
-
- eq({ {0, 10, 0, 13} }, ret)
- end)
-
- describe("when creating a language tree", function()
- local function get_ranges()
- return exec_lua([[
- local result = {}
- parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end)
- return result
- ]])
- end
-
- before_each(function()
- insert([[
- int x = INT_MAX;
- #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
- #define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
- #define VALUE 0
- #define VALUE1 1
- #define VALUE2 2
- ]])
- end)
-
- describe("when parsing regions independently", function()
- it("should inject a language", function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
- queries = {
- c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}})
- ]])
-
- eq("table", exec_lua("return type(parser:children().c)"))
- eq(5, exec_lua("return #parser:children().c:trees()"))
- eq({
- {0, 2, 7, 0}, -- root tree
- {3, 16, 3, 17}, -- VALUE 0
- {4, 17, 4, 18}, -- VALUE1 1
- {5, 17, 5, 18}, -- VALUE2 2
- {1, 28, 1, 67}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
- {2, 31, 2, 70} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
- }, get_ranges())
- end)
- end)
-
- describe("when parsing regions combined", function()
- it("should inject a language", function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
- queries = {
- c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}})
- ]])
-
- eq("table", exec_lua("return type(parser:children().c)"))
- eq(2, exec_lua("return #parser:children().c:trees()"))
- eq({
- {0, 2, 7, 0}, -- root tree
- {3, 16, 5, 18}, -- VALUE 0
- -- VALUE1 1
- -- VALUE2 2
- {1, 28, 2, 70} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
- -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
- }, get_ranges())
- end)
- end)
- end)
-
-end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index e9e1f7ec12..e253db5297 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -1453,3 +1453,18 @@ describe('lua stdlib', function()
end)
end)
end)
+
+describe('lua: require("mod") from packages', function()
+ before_each(function()
+ command('set rtp+=test/functional/fixtures')
+ end)
+
+ it('propagates syntax error', function()
+ local syntax_error_msg = exec_lua [[
+ local _, err = pcall(require, "syntax_error")
+ return err
+ ]]
+
+ matches("unexpected symbol", syntax_error_msg)
+ end)
+end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index f01d90bbeb..ec06cb0639 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -262,6 +262,48 @@ describe('LSP', function()
}
end)
+ it('client should return settings via workspace/configuration handler', function()
+ local expected_callbacks = {
+ {NIL, "shutdown", {}, 1};
+ {NIL, "workspace/configuration", { items = {
+ { section = "testSetting1" };
+ { section = "testSetting2" };
+ }}, 1};
+ {NIL, "start", {}, 1};
+ }
+ local client
+ test_rpc_server {
+ test_name = "check_workspace_configuration";
+ on_init = function(_client)
+ client = _client
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_callback = function(err, method, params, client_id)
+ eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback")
+ if method == 'start' then
+ exec_lua([=[
+ local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID)
+ client.config.settings = {
+ testSetting1 = true;
+ testSetting2 = false;
+ }]=])
+ end
+ if method == 'workspace/configuration' then
+ local result = exec_lua([=[
+ local method, params = ...
+ return require'vim.lsp.handlers'['workspace/configuration'](err, method, params, TEST_RPC_CLIENT_ID)]=], method, params)
+ client.notify('workspace/configuration', result)
+ end
+ if method == 'shutdown' then
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('should verify capabilities sent', function()
local expected_callbacks = {
{NIL, "shutdown", {}, 1};
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 1431054494..2c681eb9d8 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -605,10 +605,10 @@ describe('clipboard (with fake clipboard.vim)', function()
{0:~ }|
{4: }|
:registers |
- {1:--- Registers ---} |
- "* some{2:^J}star data{2:^J} |
- "+ such{2:^J}plus{2:^J}stuff |
- ": let g:test_clip['+'] = ['such', 'plus', 'stuff'] |
+ {1:Type Name Content} |
+ l "* some{2:^J}star data{2:^J} |
+ c "+ such{2:^J}plus{2:^J}stuff |
+ c ": let g:test_clip['+'] = ['such', 'plus', 'stuff'] |
{3:Press ENTER or type command to continue}^ |
]], {
[0] = {bold = true, foreground = Screen.colors.Blue},
diff --git a/test/functional/provider/define_spec.lua b/test/functional/provider/define_spec.lua
index 1d50ce0a56..12efbec326 100644
--- a/test/functional/provider/define_spec.lua
+++ b/test/functional/provider/define_spec.lua
@@ -136,7 +136,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init)
end)
it('with nargs/count', function()
- call(fn, args..', {"nargs": "1", "range": "5"}')
+ call(fn, args..', {"nargs": "1", "count": "5"}')
local function on_setup()
command('5RpcCommand arg')
end
@@ -152,7 +152,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init)
end)
it('with nargs/count/bang', function()
- call(fn, args..', {"nargs": "1", "range": "5", "bang": ""}')
+ call(fn, args..', {"nargs": "1", "count": "5", "bang": ""}')
local function on_setup()
command('5RpcCommand! arg')
end
@@ -169,7 +169,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init)
end)
it('with nargs/count/bang/register', function()
- call(fn, args..', {"nargs": "1", "range": "5", "bang": "",'..
+ call(fn, args..', {"nargs": "1", "count": "5", "bang": "",'..
' "register": ""}')
local function on_setup()
command('5RpcCommand! b arg')
@@ -188,7 +188,7 @@ local function command_specs_for(fn, sync, first_arg_factory, init)
end)
it('with nargs/count/bang/register/eval', function()
- call(fn, args..', {"nargs": "1", "range": "5", "bang": "",'..
+ call(fn, args..', {"nargs": "1", "count": "5", "bang": "",'..
' "register": "", "eval": "@<reg>"}')
local function on_setup()
command('let @b = "regb"')
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 3ef41fde1d..8a5dd7ef18 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -1477,7 +1477,7 @@ describe("TUI", function()
retry(nil, 3000, function() -- Wait for log file to be flushed.
local log = read_file('Xtest_tui_verbose_log') or ''
- eq('--- Terminal info --- {{{\n', string.match(log, '--- Terminal.-\n'))
+ eq('--- Terminal info --- {{{\n', string.match(log, '%-%-%- Terminal.-\n'))
ok(#log > 50)
end)
end)
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
new file mode 100644
index 0000000000..cb73bfbbe1
--- /dev/null
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -0,0 +1,475 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear = helpers.clear
+local insert = helpers.insert
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+local pending_c_parser = helpers.pending_c_parser
+
+before_each(clear)
+
+local hl_query = [[
+ (ERROR) @ErrorMsg
+
+ "if" @keyword
+ "else" @keyword
+ "for" @keyword
+ "return" @keyword
+
+ "const" @type
+ "static" @type
+ "struct" @type
+ "enum" @type
+ "extern" @type
+
+ (string_literal) @string
+
+ (number_literal) @number
+ (char_literal) @string
+
+ (type_identifier) @type
+ ((type_identifier) @Special (#eq? @Special "LuaRef"))
+
+ (primitive_type) @type
+ (sized_type_specifier) @type
+
+ ; Use lua regexes
+ ((identifier) @Identifier (#contains? @Identifier "lua_"))
+ ((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$"))
+ ((identifier) @Normal (#vim-match? @Constant "^lstate$"))
+
+ ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right))
+
+ (comment) @comment
+]]
+
+local hl_text = [[
+/// Schedule Lua callback on main loop's event queue
+static int nlua_schedule(lua_State *const lstate)
+{
+ if (lua_type(lstate, 1) != LUA_TFUNCTION
+ || lstate != lstate) {
+ lua_pushliteral(lstate, "vim.schedule: expected function");
+ return lua_error(lstate);
+ }
+
+ LuaRef cb = nlua_ref(lstate, 1);
+
+ multiqueue_put(main_loop.events, nlua_schedule_event,
+ 1, (void *)(ptrdiff_t)cb);
+ return 0;
+}]]
+
+local test_text = [[
+void ui_refresh(void)
+{
+ int width = INT_MAX, height = INT_MAX;
+ bool ext_widgets[kUIExtCount];
+ for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
+ ext_widgets[i] = true;
+ }
+
+ bool inclusive = ui_override();
+ for (size_t i = 0; i < ui_count; i++) {
+ UI *ui = uis[i];
+ width = MIN(ui->width, width);
+ height = MIN(ui->height, height);
+ foo = BAR(ui->bazaar, bazaar);
+ for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
+ }
+ }
+}]]
+
+describe('treesitter highlighting', function()
+ local screen
+
+ before_each(function()
+ screen = Screen.new(65, 18)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {foreground = Screen.colors.Blue1};
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4};
+ [4] = {bold = true, foreground = Screen.colors.Brown};
+ [5] = {foreground = Screen.colors.Magenta};
+ [6] = {foreground = Screen.colors.Red};
+ [7] = {bold = true, foreground = Screen.colors.SlateBlue};
+ [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
+ [9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red};
+ [10] = {foreground = Screen.colors.Red, background = Screen.colors.Red};
+ [11] = {foreground = Screen.colors.Cyan4};
+ }
+
+ exec_lua([[ hl_query = ... ]], hl_query)
+ end)
+
+ it('is updated with edits', function()
+ if pending_c_parser(pending) then return end
+
+ insert(hl_text)
+ screen:expect{grid=[[
+ /// Schedule Lua callback on main loop's event queue |
+ static int nlua_schedule(lua_State *const lstate) |
+ { |
+ if (lua_type(lstate, 1) != LUA_TFUNCTION |
+ || lstate != lstate) { |
+ lua_pushliteral(lstate, "vim.schedule: expected function"); |
+ return lua_error(lstate); |
+ } |
+ |
+ LuaRef cb = nlua_ref(lstate, 1); |
+ |
+ multiqueue_put(main_loop.events, nlua_schedule_event, |
+ 1, (void *)(ptrdiff_t)cb); |
+ return 0; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ exec_lua [[
+ local parser = vim.treesitter.get_parser(0, "c")
+ local highlighter = vim.treesitter.highlighter
+ test_hl = highlighter.new(parser, {queries = {c = hl_query}})
+ ]]
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed("5Goc<esc>dd")
+
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:^lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed('7Go*/<esc>')
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ {8:*^/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|
+ |
+ ]]}
+
+ feed('3Go/*<esc>')
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {2:/^*} |
+ {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {2: || lstate != lstate) {} |
+ {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {2: return lua_error(lstate);} |
+ {2:*/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ {8:}} |
+ |
+ ]]}
+
+ feed("gg$")
+ feed("~")
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queu^E} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {2:/*} |
+ {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {2: || lstate != lstate) {} |
+ {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {2: return lua_error(lstate);} |
+ {2:*/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ {8:}} |
+ |
+ ]]}
+
+
+ feed("re")
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queu^e} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {2:/*} |
+ {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {2: || lstate != lstate) {} |
+ {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {2: return lua_error(lstate);} |
+ {2:*/} |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ {8:}} |
+ |
+ ]]}
+ end)
+
+ it('is updated with :sort', function()
+ if pending_c_parser(pending) then return end
+
+ insert(test_text)
+ exec_lua [[
+ local parser = vim.treesitter.get_parser(0, "c")
+ test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}})
+ ]]
+ screen:expect{grid=[[
+ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
+ {3:bool} ext_widgets[kUIExtCount]; |
+ {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ {3:bool} inclusive = ui_override(); |
+ {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
+ {3:UI} *ui = uis[i]; |
+ width = {5:MIN}(ui->width, width); |
+ height = {5:MIN}(ui->height, height); |
+ foo = {5:BAR}(ui->bazaar, bazaar); |
+ {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]]}
+
+ feed ":sort<cr>"
+ screen:expect{grid=[[
+ ^ |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ {3:UI} *ui = uis[i]; |
+ ext_widgets[i] = true; |
+ foo = {5:BAR}(ui->bazaar, bazaar); |
+ {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
+ height = {5:MIN}(ui->height, height); |
+ width = {5:MIN}(ui->width, width); |
+ } |
+ {3:bool} ext_widgets[kUIExtCount]; |
+ {3:bool} inclusive = ui_override(); |
+ {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
+ {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
+ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
+ } |
+ } |
+ {3:void} ui_refresh({3:void}) |
+ :sort |
+ ]]}
+
+ feed "u"
+
+ screen:expect{grid=[[
+ {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
+ {3:bool} ext_widgets[kUIExtCount]; |
+ {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ {3:bool} inclusive = ui_override(); |
+ {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
+ {3:UI} *ui = uis[i]; |
+ width = {5:MIN}(ui->width, width); |
+ height = {5:MIN}(ui->height, height); |
+ foo = {5:BAR}(ui->bazaar, bazaar); |
+ {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ 19 changes; before #2 {MATCH:.*}|
+ ]]}
+ end)
+
+ it("supports with custom parser", function()
+ if pending_c_parser(pending) then return end
+
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen4};
+ }
+
+ insert(test_text)
+
+ screen:expect{ grid= [[
+ int width = INT_MAX, height = INT_MAX; |
+ bool ext_widgets[kUIExtCount]; |
+ for (UIExtension i = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool inclusive = ui_override(); |
+ for (size_t i = 0; i < ui_count; i++) { |
+ UI *ui = uis[i]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+
+ exec_lua [[
+ parser = vim.treesitter.get_parser(0, "c")
+ query = vim.treesitter.parse_query("c", "(declaration) @decl")
+
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
+ table.insert(nodes, node)
+ end
+
+ parser:set_included_regions({nodes})
+
+ local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}})
+ ]]
+
+ screen:expect{ grid = [[
+ int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
+ bool {1:ext_widgets}[{1:kUIExtCount}]; |
+ for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool {1:inclusive} = {1:ui_override}(); |
+ for (size_t {1:i} = 0; i < ui_count; i++) { |
+ UI *{1:ui} = {1:uis}[{1:i}]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]] }
+ end)
+
+ it("supports injected languages", function()
+ if pending_c_parser(pending) then return end
+
+ insert([[
+ int x = INT_MAX;
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ #define foo void main() { \
+ return 42; \
+ }
+ ]])
+
+ screen:expect{grid=[[
+ int x = INT_MAX; |
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))|
+ #define foo void main() { \ |
+ return 42; \ |
+ } |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ exec_lua [[
+ local parser = vim.treesitter.get_parser(0, "c", {
+ queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}
+ })
+ local highlighter = vim.treesitter.highlighter
+ test_hl = highlighter.new(parser, {queries = {c = hl_query}})
+ ]]
+
+ screen:expect{grid=[[
+ {3:int} x = {5:INT_MAX}; |
+ #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))|
+ #define foo {3:void} main() { \ |
+ {4:return} {5:42}; \ |
+ } |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+end)
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
new file mode 100644
index 0000000000..a5801271cb
--- /dev/null
+++ b/test/functional/treesitter/language_spec.lua
@@ -0,0 +1,71 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local pcall_err = helpers.pcall_err
+local matches = helpers.matches
+local pending_c_parser = helpers.pending_c_parser
+
+before_each(clear)
+
+describe('treesitter API', function()
+ -- error tests not requiring a parser library
+ it('handles missing language', function()
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')"))
+
+ -- actual message depends on platform
+ matches("Error executing lua: Failed to load parser: uv_dlopen: .+",
+ pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')"))
+
+ -- Should not throw an error when silent
+ eq(false, exec_lua("return vim.treesitter.require_language('borklang', nil, true)"))
+ eq(false, exec_lua("return vim.treesitter.require_language('borklang', 'borkbork.so', true)"))
+
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')"))
+ end)
+
+ it('inspects language', function()
+ if pending_c_parser(pending) then return end
+
+ local keys, fields, symbols = unpack(exec_lua([[
+ local lang = vim.treesitter.inspect_language('c')
+ local keys, symbols = {}, {}
+ for k,_ in pairs(lang) do
+ keys[k] = true
+ end
+
+ -- symbols array can have "holes" and is thus not a valid msgpack array
+ -- but we don't care about the numbers here (checked in the parser test)
+ for _, v in pairs(lang.symbols) do
+ table.insert(symbols, v)
+ end
+ return {keys, lang.fields, symbols}
+ ]]))
+
+ eq({fields=true, symbols=true}, keys)
+
+ local fset = {}
+ for _,f in pairs(fields) do
+ eq("string", type(f))
+ fset[f] = true
+ end
+ eq(true, fset["directive"])
+ eq(true, fset["initializer"])
+
+ local has_named, has_anonymous
+ for _,s in pairs(symbols) do
+ eq("string", type(s[1]))
+ eq("boolean", type(s[2]))
+ if s[1] == "for_statement" and s[2] == true then
+ has_named = true
+ elseif s[1] == "|=" and s[2] == false then
+ has_anonymous = true
+ end
+ end
+ eq({true,true}, {has_named,has_anonymous})
+ end)
+end)
+
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
new file mode 100644
index 0000000000..520574c08a
--- /dev/null
+++ b/test/functional/treesitter/parser_spec.lua
@@ -0,0 +1,576 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local insert = helpers.insert
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+local pending_c_parser = helpers.pending_c_parser
+
+before_each(clear)
+
+describe('treesitter parser API', function()
+
+ it('parses buffer', function()
+ if helpers.pending_win32(pending) or pending_c_parser(pending) then return end
+
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ root = tree:root()
+ lang = vim.treesitter.inspect_language('c')
+ ]])
+
+ eq("<tree>", exec_lua("return tostring(tree)"))
+ eq("<node translation_unit>", exec_lua("return tostring(root)"))
+ eq({0,0,3,0}, exec_lua("return {root:range()}"))
+
+ eq(1, exec_lua("return root:child_count()"))
+ exec_lua("child = root:child(0)")
+ eq("<node function_definition>", exec_lua("return tostring(child)"))
+ eq({0,0,2,1}, exec_lua("return {child:range()}"))
+
+ eq("function_definition", exec_lua("return child:type()"))
+ eq(true, exec_lua("return child:named()"))
+ eq("number", type(exec_lua("return child:symbol()")))
+ eq({'function_definition', true}, exec_lua("return lang.symbols[child:symbol()]"))
+
+ exec_lua("anon = root:descendant_for_range(0,8,0,9)")
+ eq("(", exec_lua("return anon:type()"))
+ eq(false, exec_lua("return anon:named()"))
+ eq("number", type(exec_lua("return anon:symbol()")))
+ eq({'(', false}, exec_lua("return lang.symbols[anon:symbol()]"))
+
+ exec_lua("descendant = root:descendant_for_range(1,2,1,12)")
+ eq("<node declaration>", exec_lua("return tostring(descendant)"))
+ eq({1,2,1,12}, exec_lua("return {descendant:range()}"))
+ eq("(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))", exec_lua("return descendant:sexpr()"))
+
+ feed("2G7|ay")
+ exec_lua([[
+ tree2 = parser:parse()[1]
+ root2 = tree2:root()
+ descendant2 = root2:descendant_for_range(1,2,1,13)
+ ]])
+ eq(false, exec_lua("return tree2 == tree1"))
+ eq(false, exec_lua("return root2 == root"))
+ eq("<node declaration>", exec_lua("return tostring(descendant2)"))
+ eq({1,2,1,13}, exec_lua("return {descendant2:range()}"))
+
+ eq(true, exec_lua("return child == child"))
+ -- separate lua object, but represents same node
+ eq(true, exec_lua("return child == root:child(0)"))
+ eq(false, exec_lua("return child == descendant2"))
+ eq(false, exec_lua("return child == nil"))
+ eq(false, exec_lua("return child == tree"))
+
+ eq("string", exec_lua("return type(child:id())"))
+ eq(true, exec_lua("return child:id() == child:id()"))
+ -- separate lua object, but represents same node
+ eq(true, exec_lua("return child:id() == root:child(0):id()"))
+ eq(false, exec_lua("return child:id() == descendant2:id()"))
+ eq(false, exec_lua("return child:id() == nil"))
+ eq(false, exec_lua("return child:id() == tree"))
+
+ -- unchanged buffer: return the same tree
+ eq(true, exec_lua("return parser:parse()[1] == tree2"))
+ end)
+
+ local test_text = [[
+void ui_refresh(void)
+{
+ int width = INT_MAX, height = INT_MAX;
+ bool ext_widgets[kUIExtCount];
+ for (UIExtension i = 0; (int)i < kUIExtCount; i++) {
+ ext_widgets[i] = true;
+ }
+
+ bool inclusive = ui_override();
+ for (size_t i = 0; i < ui_count; i++) {
+ UI *ui = uis[i];
+ width = MIN(ui->width, width);
+ height = MIN(ui->height, height);
+ foo = BAR(ui->bazaar, bazaar);
+ for (UIExtension j = 0; (int)j < kUIExtCount; j++) {
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive);
+ }
+ }
+}]]
+
+ it('allows to iterate over nodes children', function()
+ if pending_c_parser(pending) then return end
+
+ insert(test_text);
+
+ local res = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+
+ func_node = parser:parse()[1]:root():child(0)
+
+ res = {}
+ for node, field in func_node:iter_children() do
+ table.insert(res, {node:type(), field})
+ end
+ return res
+ ]])
+
+ eq({
+ {"primitive_type", "type"},
+ {"function_declarator", "declarator"},
+ {"compound_statement", "body"}
+ }, res)
+ end)
+
+ it('allows to get a child by field', function()
+ if pending_c_parser(pending) then return end
+
+ insert(test_text);
+
+ local res = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+
+ func_node = parser:parse()[1]:root():child(0)
+
+ local res = {}
+ for _, node in ipairs(func_node:field("type")) do
+ table.insert(res, {node:type(), node:range()})
+ end
+ return res
+ ]])
+
+ eq({{ "primitive_type", 0, 0, 0, 4 }}, res)
+
+ local res_fail = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+
+ return #func_node:field("foo") == 0
+ ]])
+
+ assert(res_fail)
+ end)
+
+ local query = [[
+ ((call_expression function: (identifier) @minfunc (argument_list (identifier) @min_id)) (eq? @minfunc "MIN"))
+ "for" @keyword
+ (primitive_type) @type
+ (field_expression argument: (identifier) @fieldarg)
+ ]]
+
+ it("supports runtime queries", function()
+ if pending_c_parser(pending) then return end
+
+ local ret = exec_lua [[
+ return require"vim.treesitter.query".get_query("c", "highlights").captures[1]
+ ]]
+
+ eq('variable', ret)
+ end)
+
+ it('support query and iter by capture', function()
+ if pending_c_parser(pending) then return end
+
+ insert(test_text)
+
+ local res = exec_lua([[
+ cquery = vim.treesitter.parse_query("c", ...)
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ res = {}
+ for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
+ -- can't transmit node over RPC. just check the name and range
+ table.insert(res, {cquery.captures[cid], node:type(), node:range()})
+ end
+ return res
+ ]], query)
+
+ eq({
+ { "type", "primitive_type", 8, 2, 8, 6 },
+ { "keyword", "for", 9, 2, 9, 5 },
+ { "type", "primitive_type", 9, 7, 9, 13 },
+ { "minfunc", "identifier", 11, 12, 11, 15 },
+ { "fieldarg", "identifier", 11, 16, 11, 18 },
+ { "min_id", "identifier", 11, 27, 11, 32 },
+ { "minfunc", "identifier", 12, 13, 12, 16 },
+ { "fieldarg", "identifier", 12, 17, 12, 19 },
+ { "min_id", "identifier", 12, 29, 12, 35 },
+ { "fieldarg", "identifier", 13, 14, 13, 16 }
+ }, res)
+ end)
+
+ it('support query and iter by match', function()
+ if pending_c_parser(pending) then return end
+
+ insert(test_text)
+
+ local res = exec_lua([[
+ cquery = vim.treesitter.parse_query("c", ...)
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) 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
+ ]], query)
+
+ eq({
+ { 3, { { "type", "primitive_type", 8, 2, 8, 6 } } },
+ { 2, { { "keyword", "for", 9, 2, 9, 5 } } },
+ { 3, { { "type", "primitive_type", 9, 7, 9, 13 } } },
+ { 4, { { "fieldarg", "identifier", 11, 16, 11, 18 } } },
+ { 1, { { "minfunc", "identifier", 11, 12, 11, 15 }, { "min_id", "identifier", 11, 27, 11, 32 } } },
+ { 4, { { "fieldarg", "identifier", 12, 17, 12, 19 } } },
+ { 1, { { "minfunc", "identifier", 12, 13, 12, 16 }, { "min_id", "identifier", 12, 29, 12, 35 } } },
+ { 4, { { "fieldarg", "identifier", 13, 14, 13, 16 } } }
+ }, res)
+ 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
+
+ insert('char* astring = "Hello World!";')
+
+ local res = exec_lua([[
+ cquery = vim.treesitter.parse_query("c", '((_) @quote (vim-match? @quote "^\\"$")) ((_) @quote (lua-match? @quote "^\\"$"))')
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 0, 1) 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({
+ { 1, { { "quote", '"', 0, 16, 0, 17 } } },
+ { 2, { { "quote", '"', 0, 16, 0, 17 } } },
+ { 1, { { "quote", '"', 0, 29, 0, 30 } } },
+ { 2, { { "quote", '"', 0, 29, 0, 30 } } },
+ }, res)
+ end)
+
+ it('allows to add predicates', function()
+ insert([[
+ int main(void) {
+ return 0;
+ }
+ ]])
+
+ local custom_query = "((identifier) @main (#is-main? @main))"
+
+ local res = exec_lua([[
+ local query = require"vim.treesitter.query"
+
+ local function is_main(match, pattern, bufnr, predicate)
+ local node = match[ predicate[2] ]
+
+ return query.get_node_text(node, bufnr)
+ end
+
+ local parser = vim.treesitter.get_parser(0, "c")
+
+ query.add_predicate("is-main?", is_main)
+
+ local query = query.parse_query("c", ...)
+
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
+ table.insert(nodes, {node:range()})
+ end
+
+ return nodes
+ ]], custom_query)
+
+ eq({{0, 4, 0, 8}}, res)
+
+ local res_list = exec_lua[[
+ local query = require'vim.treesitter.query'
+
+ local list = query.list_predicates()
+
+ table.sort(list)
+
+ return list
+ ]]
+
+ eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
+ end)
+
+
+ it('allows to set simple ranges', function()
+ if pending_c_parser(pending) then return end
+
+ insert(test_text)
+
+ local res = exec_lua [[
+ parser = vim.treesitter.get_parser(0, "c")
+ return { parser:parse()[1]:root():range() }
+ ]]
+
+ eq({0, 0, 19, 0}, res)
+
+ -- The following sets the included ranges for the current parser
+ -- As stated here, this only includes the function (thus the whole buffer, without the last line)
+ local res2 = exec_lua [[
+ local root = parser:parse()[1]:root()
+ parser:set_included_regions({{root:child(0)}})
+ parser:invalidate()
+ return { parser:parse()[1]:root():range() }
+ ]]
+
+ eq({0, 0, 18, 1}, res2)
+
+ local range = exec_lua [[
+ local res = {}
+ for _, region in ipairs(parser:included_regions()) do
+ for _, node in ipairs(region) do
+ table.insert(res, {node:range()})
+ end
+ end
+ return res
+ ]]
+
+ eq(range, { { 0, 0, 18, 1 } })
+
+ local range_tbl = exec_lua [[
+ parser:set_included_regions { { { 0, 0, 17, 1 } } }
+ parser:parse()
+ return parser:included_regions()
+ ]]
+
+ eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } })
+ end)
+ it("allows to set complex ranges", function()
+ if pending_c_parser() then return end
+
+ insert(test_text)
+
+ local res = exec_lua [[
+ parser = vim.treesitter.get_parser(0, "c")
+ query = vim.treesitter.parse_query("c", "(declaration) @decl")
+
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
+ table.insert(nodes, node)
+ end
+
+ parser:set_included_regions({nodes})
+
+ local root = parser:parse()[1]:root()
+
+ local res = {}
+ for i=0,(root:named_child_count() - 1) do
+ table.insert(res, { root:named_child(i):range() })
+ end
+ return res
+ ]]
+
+ eq({
+ { 2, 2, 2, 40 },
+ { 3, 2, 3, 32 },
+ { 4, 7, 4, 25 },
+ { 8, 2, 8, 33 },
+ { 9, 7, 9, 20 },
+ { 10, 4, 10, 20 },
+ { 14, 9, 14, 27 } }, res)
+ end)
+
+ it("allows to create string parsers", function()
+ local ret = exec_lua [[
+ local parser = vim.treesitter.get_string_parser("int foo = 42;", "c")
+ return { parser:parse()[1]:root():range() }
+ ]]
+
+ eq({ 0, 0, 0, 13 }, ret)
+ end)
+
+ it("allows to run queries with string parsers", function()
+ local txt = [[
+ int foo = 42;
+ int bar = 13;
+ ]]
+
+ local ret = exec_lua([[
+ local str = ...
+ local parser = vim.treesitter.get_string_parser(str, "c")
+
+ local nodes = {}
+ local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))')
+
+ for _, node in query:iter_captures(parser:parse()[1]:root(), str, 0, 2) do
+ table.insert(nodes, { node:range() })
+ end
+
+ return nodes]], txt)
+
+ eq({ {0, 10, 0, 13} }, ret)
+ end)
+
+ describe("when creating a language tree", function()
+ local function get_ranges()
+ return exec_lua([[
+ local result = {}
+ parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end)
+ return result
+ ]])
+ end
+
+ before_each(function()
+ insert([[
+int x = INT_MAX;
+#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+#define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+#define VALUE 123
+#define VALUE1 123
+#define VALUE2 123
+ ]])
+ end)
+
+ describe("when parsing regions independently", function()
+ it("should inject a language", function()
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c", {
+ queries = {
+ c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}})
+ ]])
+
+ eq("table", exec_lua("return type(parser:children().c)"))
+ eq(5, exec_lua("return #parser:children().c:trees()"))
+ eq({
+ {0, 0, 7, 0}, -- root tree
+ {3, 14, 3, 17}, -- VALUE 123
+ {4, 15, 4, 18}, -- VALUE1 123
+ {5, 15, 5, 18}, -- VALUE2 123
+ {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ }, get_ranges())
+ end)
+ end)
+
+ describe("when parsing regions combined", function()
+ it("should inject a language", function()
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c", {
+ queries = {
+ c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}})
+ ]])
+
+ eq("table", exec_lua("return type(parser:children().c)"))
+ eq(2, exec_lua("return #parser:children().c:trees()"))
+ eq({
+ {0, 0, 7, 0}, -- root tree
+ {3, 14, 5, 18}, -- VALUE 123
+ -- VALUE1 123
+ -- VALUE2 123
+ {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ }, get_ranges())
+ end)
+ end)
+
+ describe("when using the offset directive", function()
+ it("should shift the range by the directive amount", function()
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c", {
+ queries = {
+ c = "(preproc_def ((preproc_arg) @c (#offset! @c 0 2 0 -1))) (preproc_function_def value: (preproc_arg) @c)"}})
+ ]])
+
+ eq("table", exec_lua("return type(parser:children().c)"))
+ eq({
+ {0, 0, 7, 0}, -- root tree
+ {3, 15, 3, 16}, -- VALUE 123
+ {4, 16, 4, 17}, -- VALUE1 123
+ {5, 16, 5, 17}, -- VALUE2 123
+ {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ }, get_ranges())
+ end)
+ end)
+ end)
+
+ describe("when getting the language for a range", function()
+ before_each(function()
+ insert([[
+int x = INT_MAX;
+#define VALUE 123456789
+ ]])
+ end)
+
+ it("should return the correct language tree", function()
+ local result = exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c", {
+ queries = { c = "(preproc_def (preproc_arg) @c)"}})
+
+ local sub_tree = parser:language_for_range({1, 18, 1, 19})
+
+ return sub_tree == parser:children().c
+ ]])
+
+ eq(result, true)
+ end)
+ end)
+
+ describe("when getting/setting match data", function()
+ describe("when setting for the whole match", function()
+ it("should set/get the data correctly", function()
+ insert([[
+ int x = 3;
+ ]])
+
+ local result = exec_lua([[
+ local result
+
+ query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))')
+ parser = vim.treesitter.get_parser(0, "c")
+
+ for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, 1) do
+ result = metadata.key
+ end
+
+ return result
+ ]])
+
+ eq(result, "value")
+ end)
+ end)
+
+ describe("when setting for a capture match", function()
+ it("should set/get the data correctly", function()
+ insert([[
+ int x = 3;
+ ]])
+
+ local result = exec_lua([[
+ local result
+
+ 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, 0, 1) do
+ result = metadata[pattern].key
+ end
+
+ return result
+ ]])
+
+ eq(result, "value")
+ end)
+ end)
+ end)
+end)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 7b05e90459..6ce8b33a63 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -886,6 +886,41 @@ describe("folded lines", function()
|
]])
end
+ command("set foldcolumn=auto")
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+}{5:^+-- 2 lines: line 1························}|
+ {7: }line 3 |
+ {7: }line 4 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]], unchanged=true}
+ else
+ screen:expect{grid=[[
+ {7:+}{5:^+-- 2 lines: line 1························}|
+ {7: }line 3 |
+ {7: }line 4 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], unchanged=true}
+ end
-- fdc should not change with a new fold as the maximum is 1
feed("zf3j")
@@ -924,6 +959,41 @@ describe("folded lines", function()
]])
end
+ command("set foldcolumn=auto:1")
+ if multigrid then screen:expect{grid=[[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+}{5:^+-- 4 lines: line 1························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]], unchanged=true}
+ else
+ screen:expect{grid=[[
+ {7:+}{5:^+-- 4 lines: line 1························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], unchanged=true}
+ end
+
-- relax the maximum fdc thus fdc should expand to
-- accomodate the current number of folds
command("set foldcolumn=auto:4")
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index a741136111..7bca741ae3 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -45,13 +45,33 @@ describe('ui/mouse/input', function()
it('single left click moves cursor', function()
feed('<LeftMouse><2,1>')
- screen:expect([[
+ screen:expect{grid=[[
testing |
mo^use |
support and selection |
{0:~ }|
|
+ ]], mouse_enabled=true}
+ feed('<LeftMouse><0,0>')
+ screen:expect([[
+ ^testing |
+ mouse |
+ support and selection |
+ {0:~ }|
+ |
]])
+ end)
+
+ it("in external ui works with unset 'mouse'", function()
+ meths.set_option('mouse', '')
+ feed('<LeftMouse><2,1>')
+ screen:expect{grid=[[
+ testing |
+ mo^use |
+ support and selection |
+ {0:~ }|
+ |
+ ]], mouse_enabled=false}
feed('<LeftMouse><0,0>')
screen:expect([[
^testing |
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 6601c2d68e..719e2ee82a 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -1562,6 +1562,77 @@ describe('ext_multigrid', function()
{1:~ }|
]]}
+ command('tabnext')
+ command('$tabnew')
+ screen:expect{grid=[[
+ ## grid 1
+ {16: }{17:2}{16: [No Name] }{17:2}{16: [No Name] }{7: [No Name] }{12: }{16:X}|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ [7:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2 (hidden)
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4 (hidden)
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 5 (hidden)
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 6 (hidden)
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 7
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+
+ command('tabclose')
command('tabclose')
screen:expect{grid=[[
## grid 1
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 8fa9fcc42f..fcf6926433 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -170,7 +170,7 @@ function Screen.new(width, height)
ruler = {},
hl_groups = {},
_default_attr_ids = nil,
- _mouse_enabled = true,
+ mouse_enabled = true,
_attrs = {},
_hl_info = {[0]={}},
_attr_table = {[0]={{},{}}},
@@ -318,7 +318,7 @@ function Screen:expect(expected, attr_ids, ...)
assert(next({...}) == nil, "invalid args to expect()")
if type(expected) == "table" then
assert(not (attr_ids ~= nil))
- local is_key = {grid=true, attr_ids=true, condition=true,
+ local is_key = {grid=true, attr_ids=true, condition=true, mouse_enabled=true,
any=true, mode=true, unchanged=true, intermediate=true,
reset=true, timeout=true, request_cb=true, hl_groups=true}
for _, v in ipairs(ext_keys) do
@@ -422,12 +422,15 @@ screen:redraw_debug() to show all intermediate screen states. ]])
if expected.mode ~= nil then
extstate.mode = self.mode
end
+ if expected.mouse_enabled ~= nil then
+ extstate.mouse_enabled = self.mouse_enabled
+ end
if expected.win_viewport == nil then
extstate.win_viewport = nil
end
-- Convert assertion errors into invalid screen state descriptions.
- for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
+ for _, k in ipairs(concat_tables(ext_keys, {'mode', 'mouse_enabled'})) do
-- Empty states are considered the default and need not be mentioned.
if (not (expected[k] == nil and isempty(extstate[k]))) then
local status, res = pcall(eq, expected[k], extstate[k], k)
@@ -799,11 +802,11 @@ function Screen:_handle_busy_stop()
end
function Screen:_handle_mouse_on()
- self._mouse_enabled = true
+ self.mouse_enabled = true
end
function Screen:_handle_mouse_off()
- self._mouse_enabled = false
+ self.mouse_enabled = false
end
function Screen:_handle_mode_change(mode, idx)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 222275eb4d..656f613c6a 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -20,6 +20,7 @@ describe('search highlighting', function()
[2] = {background = colors.Yellow}, -- Search
[3] = {reverse = true},
[4] = {foreground = colors.Red}, -- Message
+ [6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded
})
end)
@@ -38,6 +39,21 @@ describe('search highlighting', function()
]])
end)
+ it('is disabled in folded text', function()
+ insert("some text\nmore text")
+ feed_command('1,2fold')
+ feed("gg/text")
+ screen:expect([[
+ {6:+-- 2 lines: some text·················}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /text^ |
+ ]])
+ end)
+
it('works', function()
insert([[
some text
@@ -455,6 +471,19 @@ describe('search highlighting', function()
{4:search hit BOTTOM, continuing at TOP} |
]])
+ -- check hilights work also in folds
+ feed("zf4j")
+ command("%foldopen")
+ screen:expect([[
+ very {5:spec^ial}{2: te}{6:xt} |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
+ ]])
+
feed_command("call clearmatches()")
screen:expect([[
very spec{2:^ial te}xt |
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 0ed62b21b2..d1b8de5e4e 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -76,6 +76,28 @@ describe('Signs', function()
]])
end)
+ it('allows signs with no text', function()
+ feed('ia<cr>b<cr><esc>')
+ command('sign define piet1 text= texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ screen:expect([[
+ a |
+ b |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
it('can be called right after :split', function()
feed('ia<cr>b<cr>c<cr><esc>gg')
-- This used to cause a crash due to :sign using a special redraw
@@ -244,6 +266,50 @@ describe('Signs', function()
]]}
end)
+ it('ignores signs with no icon and text when calculting the signcolumn width', function()
+ feed('ia<cr>b<cr>c<cr><esc>')
+ command('set number')
+ command('set signcolumn=auto:2')
+ command('sign define pietSearch text=>> texthl=Search')
+ command('sign define pietError text= texthl=Error')
+ command('sign place 2 line=1 name=pietError buffer=1')
+ -- no signcolumn with only empty sign
+ screen:expect([[
+ {6: 1 }a |
+ {6: 2 }b |
+ {6: 3 }c |
+ {6: 4 }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ -- single column with 1 sign with text and one sign without
+ command('sign place 1 line=1 name=pietSearch buffer=1')
+ screen:expect([[
+ {1:>>}{6: 1 }a |
+ {2: }{6: 2 }b |
+ {2: }{6: 3 }c |
+ {2: }{6: ^4 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
it('can have 32bit sign IDs', function()
command('sign define piet text=>> texthl=Search')
command('sign place 100000 line=1 name=piet buffer=1')