aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/api/autocmd_spec.lua920
-rw-r--r--test/functional/api/buffer_spec.lua35
-rw-r--r--test/functional/api/buffer_updates_spec.lua1
-rw-r--r--test/functional/api/command_spec.lua66
-rw-r--r--test/functional/api/highlight_spec.lua30
-rw-r--r--test/functional/api/keymap_spec.lua31
-rw-r--r--test/functional/api/vim_spec.lua445
-rw-r--r--test/functional/api/window_spec.lua44
-rw-r--r--test/functional/autocmd/autocmd_oldtest_spec.lua86
-rw-r--r--test/functional/autocmd/autocmd_spec.lua167
-rw-r--r--test/functional/autocmd/cursormoved_spec.lua1
-rw-r--r--test/functional/autocmd/show_spec.lua35
-rw-r--r--test/functional/autocmd/termxx_spec.lua4
-rw-r--r--test/functional/core/channels_spec.lua21
-rw-r--r--test/functional/core/job_spec.lua1
-rw-r--r--test/functional/core/remote_spec.lua142
-rw-r--r--test/functional/core/startup_spec.lua4
-rw-r--r--test/functional/editor/completion_spec.lua19
-rw-r--r--test/functional/editor/put_spec.lua4
-rw-r--r--test/functional/ex_cmds/map_spec.lua221
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua1
-rw-r--r--test/functional/ex_cmds/verbose_spec.lua168
-rw-r--r--test/functional/legacy/autochdir_spec.lua94
-rw-r--r--test/functional/legacy/delete_spec.lua43
-rw-r--r--test/functional/legacy/file_perm_spec.lua43
-rw-r--r--test/functional/legacy/searchpos_spec.lua35
-rw-r--r--test/functional/legacy/set_spec.lua30
-rw-r--r--test/functional/lua/api_spec.lua7
-rw-r--r--test/functional/lua/command_line_completion_spec.lua8
-rw-r--r--test/functional/lua/thread_spec.lua408
-rw-r--r--test/functional/lua/vim_spec.lua134
-rw-r--r--test/functional/options/autochdir_spec.lua31
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua1
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua48
-rw-r--r--test/functional/plugin/shada_spec.lua8
-rw-r--r--test/functional/provider/clipboard_spec.lua16
-rw-r--r--test/functional/provider/python3_spec.lua8
-rw-r--r--test/functional/terminal/buffer_spec.lua1
-rw-r--r--test/functional/terminal/channel_spec.lua87
-rw-r--r--test/functional/terminal/cursor_spec.lua3
-rw-r--r--test/functional/terminal/edit_spec.lua1
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua7
-rw-r--r--test/functional/terminal/helpers.lua2
-rw-r--r--test/functional/terminal/highlight_spec.lua16
-rw-r--r--test/functional/terminal/scrollback_spec.lua2
-rw-r--r--test/functional/terminal/tui_spec.lua14
-rw-r--r--test/functional/terminal/window_spec.lua1
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua13
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/decorations_spec.lua369
-rw-r--r--test/functional/ui/diff_spec.lua26
-rw-r--r--test/functional/ui/global_statusline_spec.lua233
-rw-r--r--test/functional/ui/highlight_spec.lua60
-rw-r--r--test/functional/ui/hlstate_spec.lua4
-rw-r--r--test/functional/ui/messages_spec.lua1
-rw-r--r--test/functional/ui/output_spec.lua1
-rw-r--r--test/functional/ui/popupmenu_spec.lua2
-rw-r--r--test/functional/ui/screen.lua19
-rw-r--r--test/functional/ui/sign_spec.lua8
-rw-r--r--test/helpers.lua10
-rw-r--r--test/unit/strings_spec.lua12
-rw-r--r--test/unit/viml/expressions/parser_spec.lua1
62 files changed, 3883 insertions, 374 deletions
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
new file mode 100644
index 0000000000..372cbf2c30
--- /dev/null
+++ b/test/functional/api/autocmd_spec.lua
@@ -0,0 +1,920 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local neq = helpers.neq
+local exec_lua = helpers.exec_lua
+local matches = helpers.matches
+local meths = helpers.meths
+local source = helpers.source
+local pcall_err = helpers.pcall_err
+
+before_each(clear)
+
+describe('autocmd api', function()
+ describe('nvim_create_autocmd', function()
+ it('does not allow "command" and "callback" in the same autocmd', function()
+ local ok, _ = pcall(meths.create_autocmd, "BufReadPost", {
+ pattern = "*.py,*.pyi",
+ command = "echo 'Should Have Errored",
+ callback = "not allowed",
+ })
+
+ eq(false, ok)
+ end)
+
+ it('doesnt leak when you use ++once', function()
+ eq(1, exec_lua([[
+ local count = 0
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = function() count = count + 1 end,
+ once = true
+ })
+
+ vim.cmd "set filetype=txt"
+ vim.cmd "set filetype=python"
+
+ return count
+ ]], {}))
+ end)
+
+ it('allows passing buffer by key', function()
+ meths.set_var('called', 0)
+
+ meths.create_autocmd("FileType", {
+ command = "let g:called = g:called + 1",
+ buffer = 0,
+ })
+
+ meths.command "set filetype=txt"
+ eq(1, meths.get_var('called'))
+
+ -- switch to a new buffer
+ meths.command "new"
+ meths.command "set filetype=python"
+
+ eq(1, meths.get_var('called'))
+ end)
+
+ it('does not allow passing buffer and patterns', function()
+ local ok = pcall(meths.create_autocmd, "Filetype", {
+ command = "let g:called = g:called + 1",
+ buffer = 0,
+ pattern = "*.py",
+ })
+
+ eq(false, ok)
+ end)
+
+ it('does not allow passing invalid buffers', function()
+ local ok, msg = pcall(meths.create_autocmd, "Filetype", {
+ command = "let g:called = g:called + 1",
+ buffer = -1,
+ })
+
+ eq(false, ok)
+ matches('Invalid buffer id', msg)
+ end)
+
+ it('errors on non-functions for cb', function()
+ eq(false, pcall(exec_lua, [[
+ vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*.py,*.pyi",
+ callback = 5,
+ })
+ ]]))
+ end)
+
+ it('allow passing pattern and <buffer> in same pattern', function()
+ local ok = pcall(meths.create_autocmd, "BufReadPost", {
+ pattern = "*.py,<buffer>",
+ command = "echo 'Should Not Error'"
+ })
+
+ eq(true, ok)
+ end)
+
+ it('should handle multiple values as comma separated list', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*.py,*.pyi",
+ command = "echo 'Should Not Have Errored'"
+ })
+
+ -- We should have one autocmd for *.py and one for *.pyi
+ eq(2, #meths.get_autocmds { event = "BufReadPost" })
+ end)
+
+ it('should handle multiple values as array', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = { "*.py", "*.pyi", },
+ command = "echo 'Should Not Have Errored'"
+ })
+
+ -- We should have one autocmd for *.py and one for *.pyi
+ eq(2, #meths.get_autocmds { event = "BufReadPost" })
+ end)
+
+ describe('desc', function()
+ it('can add description to one autocmd', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ command = "echo 'Should Not Have Errored'",
+ desc = "Can show description",
+ })
+
+ eq("Can show description", meths.get_autocmds { event = "BufReadPost" }[1].desc)
+ end)
+
+ it('can add description to multiple autocmd', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = {"*.py", "*.pyi"},
+ command = "echo 'Should Not Have Errored'",
+ desc = "Can show description",
+ })
+
+ local aus = meths.get_autocmds { event = "BufReadPost" }
+ eq(2, #aus)
+ eq("Can show description", aus[1].desc)
+ eq("Can show description", aus[2].desc)
+ end)
+ end)
+
+ pending('script and verbose settings', function()
+ it('marks API client', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ command = "echo 'Should Not Have Errored'",
+ desc = "Can show description",
+ })
+
+ local aus = meths.get_autocmds { event = "BufReadPost" }
+ eq(1, #aus, aus)
+ end)
+ end)
+ end)
+
+ describe('nvim_get_autocmds', function()
+ describe('events', function()
+ it('should return one autocmd when there is only one for an event', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ eq(1, #aus)
+ end)
+
+ it('should return two autocmds when there are two for an event', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+ command [[au InsertEnter * :echo "2"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ eq(2, #aus)
+ end)
+
+ it('should return the same thing if you use string or list', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+ command [[au InsertEnter * :echo "2"]]
+
+ local string_aus = meths.get_autocmds { event = "InsertEnter" }
+ local array_aus = meths.get_autocmds { event = { "InsertEnter" } }
+ eq(string_aus, array_aus)
+ end)
+
+ it('should return two autocmds when there are two for an event', function()
+ command [[au! InsertEnter]]
+ command [[au! InsertLeave]]
+ command [[au InsertEnter * :echo "1"]]
+ command [[au InsertEnter * :echo "2"]]
+
+ local aus = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(2, #aus)
+ end)
+
+ it('should return different IDs for different autocmds', function()
+ command [[au! InsertEnter]]
+ command [[au! InsertLeave]]
+ command [[au InsertEnter * :echo "1"]]
+ source [[
+ call nvim_create_autocmd("InsertLeave", #{
+ \ command: ":echo 2",
+ \ })
+ ]]
+
+ local aus = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ local first = aus[1]
+ eq(first.id, nil)
+
+ -- TODO: Maybe don't have this number, just assert it's not nil
+ local second = aus[2]
+ neq(second.id, nil)
+
+ meths.del_autocmd(second.id)
+ local new_aus = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(1, #new_aus)
+ eq(first, new_aus[1])
+ end)
+
+ it('should return event name', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ eq({ { buflocal = false, command = ':echo "1"', event = "InsertEnter", once = false, pattern = "*" } }, aus)
+ end)
+
+ it('should work with buffer numbers', function()
+ command [[new]]
+ command [[au! InsertEnter]]
+ command [[au InsertEnter <buffer=1> :echo "1"]]
+ command [[au InsertEnter <buffer=2> :echo "2"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter", buffer = 0 }
+ eq({{
+ buffer = 2,
+ buflocal = true,
+ command = ':echo "2"',
+ event = 'InsertEnter',
+ once = false,
+ pattern = '<buffer=2>',
+ }}, aus)
+
+ aus = meths.get_autocmds { event = "InsertEnter", buffer = 1 }
+ eq({{
+ buffer = 1,
+ buflocal = true,
+ command = ':echo "1"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=1>",
+ }}, aus)
+
+ aus = meths.get_autocmds { event = "InsertEnter", buffer = { 1, 2 } }
+ eq({{
+ buffer = 1,
+ buflocal = true,
+ command = ':echo "1"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=1>",
+ }, {
+ buffer = 2,
+ buflocal = true,
+ command = ':echo "2"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=2>",
+ }}, aus)
+
+ eq("Invalid value for 'buffer': must be an integer or array of integers", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" }))
+ eq("Invalid value for 'buffer': must be an integer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } }))
+ eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } }))
+
+ local bufs = {}
+ for _ = 1, 257 do
+ table.insert(bufs, meths.create_buf(true, false))
+ end
+
+ eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs }))
+ end)
+
+ it('should return autocmds when group is specified by id', function()
+ local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
+ meths.create_autocmd("FileType", { group = auid, command = 'echo "1"' })
+ meths.create_autocmd("FileType", { group = auid, command = 'echo "2"' })
+
+ local aus = meths.get_autocmds { group = auid }
+ eq(2, #aus)
+
+ local aus2 = meths.get_autocmds { group = auid, event = "InsertEnter" }
+ eq(0, #aus2)
+ end)
+
+ it('should return autocmds when group is specified by name', function()
+ local auname = "nvim_test_augroup"
+ meths.create_augroup(auname, { clear = true })
+ meths.create_autocmd("FileType", { group = auname, command = 'echo "1"' })
+ meths.create_autocmd("FileType", { group = auname, command = 'echo "2"' })
+
+ local aus = meths.get_autocmds { group = auname }
+ eq(2, #aus)
+
+ local aus2 = meths.get_autocmds { group = auname, event = "InsertEnter" }
+ eq(0, #aus2)
+ end)
+ end)
+
+ describe('groups', function()
+ before_each(function()
+ command [[au! InsertEnter]]
+
+ command [[au InsertEnter * :echo "No Group"]]
+
+ command [[augroup GroupOne]]
+ command [[ au InsertEnter * :echo "GroupOne:1"]]
+ command [[augroup END]]
+
+ command [[augroup GroupTwo]]
+ command [[ au InsertEnter * :echo "GroupTwo:2"]]
+ command [[ au InsertEnter * :echo "GroupTwo:3"]]
+ command [[augroup END]]
+ end)
+
+ it('should return all groups if no group is specified', function()
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ if #aus ~= 4 then
+ eq({}, aus)
+ end
+
+ eq(4, #aus)
+ end)
+
+ it('should return only the group specified', function()
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ group = "GroupOne",
+ }
+
+ eq(1, #aus)
+ eq([[:echo "GroupOne:1"]], aus[1].command)
+ end)
+
+ it('should return only the group specified, multiple values', function()
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ group = "GroupTwo",
+ }
+
+ eq(2, #aus)
+ eq([[:echo "GroupTwo:2"]], aus[1].command)
+ eq([[:echo "GroupTwo:3"]], aus[2].command)
+ end)
+ end)
+
+ describe('groups: 2', function()
+ it('raises error for undefined augroup name', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = "NotDefined",
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches('invalid augroup: NotDefined', code)
+ end)
+
+ it('raises error for undefined augroup id', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ -- Make sure the augroup is deleted
+ vim.api.nvim_del_augroup_by_id(1)
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = 1,
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches('invalid augroup: 1', code)
+ end)
+
+ it('raises error for invalid group type', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = true,
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches("'group' must be a string or an integer", code)
+ end)
+ end)
+
+ describe('patterns', function()
+ before_each(function()
+ command [[au! InsertEnter]]
+
+ command [[au InsertEnter * :echo "No Group"]]
+ command [[au InsertEnter *.one :echo "GroupOne:1"]]
+ command [[au InsertEnter *.two :echo "GroupTwo:2"]]
+ command [[au InsertEnter *.two :echo "GroupTwo:3"]]
+ command [[au InsertEnter <buffer> :echo "Buffer"]]
+ end)
+
+ it('should should return for literal match', function()
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "*"
+ }
+
+ eq(1, #aus)
+ eq([[:echo "No Group"]], aus[1].command)
+ end)
+
+ it('should return for multiple matches', function()
+ -- vim.api.nvim_get_autocmds
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = { "*.one", "*.two" },
+ }
+
+ eq(3, #aus)
+ eq([[:echo "GroupOne:1"]], aus[1].command)
+ eq([[:echo "GroupTwo:2"]], aus[2].command)
+ eq([[:echo "GroupTwo:3"]], aus[3].command)
+ end)
+
+ it('should work for buffer autocmds', function()
+ local normalized_aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "<buffer=1>",
+ }
+
+ local raw_aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "<buffer>",
+ }
+
+ local zero_aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "<buffer=0>",
+ }
+
+ eq(normalized_aus, raw_aus)
+ eq(normalized_aus, zero_aus)
+ eq([[:echo "Buffer"]], normalized_aus[1].command)
+ end)
+ end)
+ end)
+
+ describe('nvim_do_autocmd', function()
+ it("can trigger builtin autocmds", function()
+ meths.set_var("autocmd_executed", false)
+
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*",
+ command = "let g:autocmd_executed = v:true",
+ })
+
+ eq(false, meths.get_var("autocmd_executed"))
+ meths.do_autocmd("BufReadPost", {})
+ eq(true, meths.get_var("autocmd_executed"))
+ end)
+
+ it("can pass the buffer", function()
+ meths.set_var("buffer_executed", -1)
+ eq(-1, meths.get_var("buffer_executed"))
+
+ meths.create_autocmd("BufLeave", {
+ pattern = "*",
+ command = 'let g:buffer_executed = +expand("<abuf>")',
+ })
+
+ -- Doesn't execute for other non-matching events
+ meths.do_autocmd("CursorHold", { buffer = 1 })
+ eq(-1, meths.get_var("buffer_executed"))
+
+ meths.do_autocmd("BufLeave", { buffer = 1 })
+ eq(1, meths.get_var("buffer_executed"))
+ end)
+
+ it("can pass the filename, pattern match", function()
+ meths.set_var("filename_executed", 'none')
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.create_autocmd("BufEnter", {
+ pattern = "*.py",
+ command = 'let g:filename_executed = expand("<afile>")',
+ })
+
+ -- Doesn't execute for other non-matching events
+ meths.do_autocmd("CursorHold", { buffer = 1 })
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.command('edit __init__.py')
+ eq('__init__.py', meths.get_var("filename_executed"))
+ end)
+
+ it('cannot pass buf and fname', function()
+ local ok = pcall(meths.do_autocmd, "BufReadPre", { pattern = "literally_cannot_error.rs", buffer = 1 })
+ eq(false, ok)
+ end)
+
+ it("can pass the filename, exact match", function()
+ meths.set_var("filename_executed", 'none')
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.command('edit other_file.txt')
+ meths.command('edit __init__.py')
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.create_autocmd("CursorHoldI", {
+ pattern = "__init__.py",
+ command = 'let g:filename_executed = expand("<afile>")',
+ })
+
+ -- Doesn't execute for other non-matching events
+ meths.do_autocmd("CursorHoldI", { buffer = 1 })
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.do_autocmd("CursorHoldI", { buffer = tonumber(meths.get_current_buf()) })
+ eq('__init__.py', meths.get_var("filename_executed"))
+
+ -- Reset filename
+ meths.set_var("filename_executed", 'none')
+
+ meths.do_autocmd("CursorHoldI", { pattern = '__init__.py' })
+ eq('__init__.py', meths.get_var("filename_executed"))
+ end)
+
+ it("works with user autocmds", function()
+ meths.set_var("matched", 'none')
+
+ meths.create_autocmd("User", {
+ pattern = "TestCommand",
+ command = 'let g:matched = "matched"'
+ })
+
+ meths.do_autocmd("User", { pattern = "OtherCommand" })
+ eq('none', meths.get_var('matched'))
+ meths.do_autocmd("User", { pattern = "TestCommand" })
+ eq('matched', meths.get_var('matched'))
+ end)
+
+ it('can pass group by id', function()
+ meths.set_var("group_executed", false)
+
+ local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
+ meths.create_autocmd("FileType", {
+ group = auid,
+ command = 'let g:group_executed = v:true',
+ })
+
+ eq(false, meths.get_var("group_executed"))
+ meths.do_autocmd("FileType", { group = auid })
+ eq(true, meths.get_var("group_executed"))
+ end)
+
+ it('can pass group by name', function()
+ meths.set_var("group_executed", false)
+
+ local auname = "nvim_test_augroup"
+ meths.create_augroup(auname, { clear = true })
+ meths.create_autocmd("FileType", {
+ group = auname,
+ command = 'let g:group_executed = v:true',
+ })
+
+ eq(false, meths.get_var("group_executed"))
+ meths.do_autocmd("FileType", { group = auname })
+ eq(true, meths.get_var("group_executed"))
+ end)
+ end)
+
+ describe('nvim_create_augroup', function()
+ before_each(function()
+ clear()
+
+ meths.set_var('executed', 0)
+ end)
+
+ local make_counting_autocmd = function(opts)
+ opts = opts or {}
+
+ local resulting = {
+ pattern = "*",
+ command = "let g:executed = g:executed + 1",
+ }
+
+ resulting.group = opts.group
+ resulting.once = opts.once
+
+ meths.create_autocmd("FileType", resulting)
+ end
+
+ local set_ft = function(ft)
+ ft = ft or "txt"
+ source(string.format("set filetype=%s", ft))
+ end
+
+ local get_executed_count = function()
+ return meths.get_var('executed')
+ end
+
+ it('can be added in a group', function()
+ local augroup = "TestGroup"
+ meths.create_augroup(augroup, { clear = true })
+ make_counting_autocmd { group = augroup }
+
+ set_ft("txt")
+ set_ft("python")
+
+ eq(get_executed_count(), 2)
+ end)
+
+ it('works getting called multiple times', function()
+ make_counting_autocmd()
+ set_ft()
+ set_ft()
+ set_ft()
+
+ eq(get_executed_count(), 3)
+ end)
+
+ it('handles ++once', function()
+ make_counting_autocmd {once = true}
+ set_ft('txt')
+ set_ft('help')
+ set_ft('txt')
+ set_ft('help')
+
+ eq(get_executed_count(), 1)
+ end)
+
+ it('errors on unexpected keys', function()
+ local success, code = pcall(meths.create_autocmd, "FileType", {
+ pattern = "*",
+ not_a_valid_key = "NotDefined",
+ })
+
+ eq(false, success)
+ matches('not_a_valid_key', code)
+ end)
+
+ it('can execute simple callback', function()
+ exec_lua([[
+ vim.g.executed = false
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = function() vim.g.executed = true end,
+ })
+ ]], {})
+
+
+ eq(true, exec_lua([[
+ vim.cmd "set filetype=txt"
+ return vim.g.executed
+ ]], {}))
+ end)
+
+ it('calls multiple lua callbacks for the same autocmd execution', function()
+ eq(4, exec_lua([[
+ local count = 0
+ local counter = function()
+ count = count + 1
+ end
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = counter,
+ })
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = counter,
+ })
+
+ vim.cmd "set filetype=txt"
+ vim.cmd "set filetype=txt"
+
+ return count
+ ]], {}))
+ end)
+
+ it('properly releases functions with ++once', function()
+ exec_lua([[
+ WeakTable = setmetatable({}, { __mode = "k" })
+
+ OnceCount = 0
+
+ MyVal = {}
+ WeakTable[MyVal] = true
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = function()
+ OnceCount = OnceCount + 1
+ MyVal = {}
+ end,
+ once = true
+ })
+ ]])
+
+ command [[set filetype=txt]]
+ eq(1, exec_lua([[return OnceCount]], {}))
+
+ exec_lua([[collectgarbage()]], {})
+
+ command [[set filetype=txt]]
+ eq(1, exec_lua([[return OnceCount]], {}))
+
+ eq(0, exec_lua([[
+ local count = 0
+ for _ in pairs(WeakTable) do
+ count = count + 1
+ end
+
+ return count
+ ]]), "Should have no keys remaining")
+ end)
+
+ it('groups can be cleared', function()
+ local augroup = "TestGroup"
+ meths.create_augroup(augroup, { clear = true })
+ meths.create_autocmd("FileType", {
+ group = augroup,
+ command = "let g:executed = g:executed + 1"
+ })
+
+ set_ft("txt")
+ set_ft("txt")
+ eq(2, get_executed_count(), "should only count twice")
+
+ meths.create_augroup(augroup, { clear = true })
+ eq({}, meths.get_autocmds { group = augroup })
+
+ set_ft("txt")
+ set_ft("txt")
+ eq(2, get_executed_count(), "No additional counts")
+ end)
+
+ it('groups work with once', function()
+ local augroup = "TestGroup"
+
+ meths.create_augroup(augroup, { clear = true })
+ make_counting_autocmd { group = augroup, once = true }
+
+ set_ft("txt")
+ set_ft("python")
+
+ eq(get_executed_count(), 1)
+ end)
+
+ it('autocmds can be registered multiple times.', function()
+ local augroup = "TestGroup"
+
+ meths.create_augroup(augroup, { clear = true })
+ make_counting_autocmd { group = augroup, once = false }
+ make_counting_autocmd { group = augroup, once = false }
+ make_counting_autocmd { group = augroup, once = false }
+
+ set_ft("txt")
+ set_ft("python")
+
+ eq(get_executed_count(), 3 * 2)
+ end)
+
+ it('can be deleted', function()
+ local augroup = "WillBeDeleted"
+
+ meths.create_augroup(augroup, { clear = true })
+ meths.create_autocmd({"Filetype"}, {
+ pattern = "*",
+ command = "echo 'does not matter'",
+ })
+
+ -- Clears the augroup from before, which erases the autocmd
+ meths.create_augroup(augroup, { clear = true })
+
+ local result = #meths.get_autocmds { group = augroup }
+
+ eq(0, result)
+ end)
+
+ it('can be used for buffer local autocmds', function()
+ local augroup = "WillBeDeleted"
+
+ meths.set_var("value_set", false)
+
+ meths.create_augroup(augroup, { clear = true })
+ meths.create_autocmd("Filetype", {
+ pattern = "<buffer>",
+ command = "let g:value_set = v:true",
+ })
+
+ command "new"
+ command "set filetype=python"
+
+ eq(false, meths.get_var("value_set"))
+ end)
+
+ it('can accept vimscript functions', function()
+ source [[
+ let g:vimscript_executed = 0
+
+ function! MyVimscriptFunction() abort
+ let g:vimscript_executed = g:vimscript_executed + 1
+ endfunction
+
+ call nvim_create_autocmd("FileType", #{
+ \ pattern: ["python", "javascript"],
+ \ callback: "MyVimscriptFunction",
+ \ })
+
+ set filetype=txt
+ set filetype=python
+ set filetype=txt
+ set filetype=javascript
+ set filetype=txt
+ ]]
+
+ eq(2, meths.get_var("vimscript_executed"))
+ end)
+ end)
+
+ describe('augroup!', function()
+ it('legacy: should clear and not return any autocmds for delete groups', function()
+ command('augroup TEMP_A')
+ command(' autocmd! BufReadPost *.py :echo "Hello"')
+ command('augroup END')
+
+ command('augroup! TEMP_A')
+
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_A' }))
+
+ -- For some reason, augroup! doesn't clear the autocmds themselves, which is just wild
+ -- but we managed to keep this behavior.
+ eq(1, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('legacy: remove augroups that have no autocmds', function()
+ command('augroup TEMP_AB')
+ command('augroup END')
+
+ command('augroup! TEMP_AB')
+
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_AB' }))
+ eq(0, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('legacy: multiple remove and add augroup', function()
+ command('augroup TEMP_ABC')
+ command(' au!')
+ command(' autocmd BufReadPost *.py echo "Hello"')
+ command('augroup END')
+
+ command('augroup! TEMP_ABC')
+
+ -- Should still have one autocmd :'(
+ local aus = meths.get_autocmds { event = 'BufReadPost' }
+ eq(1, #aus, aus)
+
+ command('augroup TEMP_ABC')
+ command(' au!')
+ command(' autocmd BufReadPost *.py echo "Hello"')
+ command('augroup END')
+
+ -- Should now have two autocmds :'(
+ aus = meths.get_autocmds { event = 'BufReadPost' }
+ eq(2, #aus, aus)
+
+ command('augroup! TEMP_ABC')
+
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_ABC' }))
+ eq(2, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('api: should clear and not return any autocmds for delete groups by id', function()
+ command('augroup TEMP_ABCD')
+ command('autocmd! BufReadPost *.py :echo "Hello"')
+ command('augroup END')
+
+ local augroup_id = meths.create_augroup("TEMP_ABCD", { clear = false })
+ meths.del_augroup_by_id(augroup_id)
+
+ -- For good reason, we kill all the autocmds from del_augroup,
+ -- so now this works as expected
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_ABCD' }))
+ eq(0, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('api: should clear and not return any autocmds for delete groups by name', function()
+ command('augroup TEMP_ABCDE')
+ command('autocmd! BufReadPost *.py :echo "Hello"')
+ command('augroup END')
+
+ meths.del_augroup_by_name("TEMP_ABCDE")
+
+ -- For good reason, we kill all the autocmds from del_augroup,
+ -- so now this works as expected
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_ABCDE' }))
+ eq(0, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+ end)
+end)
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 688f3abba5..dd3af8c28f 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -423,6 +423,13 @@ describe('api/buf', function()
-- will join multiple lines if needed
set_text(0, 6, 3, 4, {'bar'})
eq({'hello bar'}, get_lines(0, 1, true))
+
+ -- can use negative line numbers
+ set_text(-2, 0, -2, 5, {'goodbye'})
+ eq({'goodbye bar', ''}, get_lines(0, -1, true))
+
+ set_text(-1, 0, -1, 0, {'text'})
+ eq({'goodbye bar', 'text'}, get_lines(0, 2, true))
end)
it('works with undo', function()
@@ -537,6 +544,34 @@ describe('api/buf', function()
end)
end)
+ describe('nvim_buf_get_text', function()
+ local get_text = curbufmeths.get_text
+
+ it('works', function()
+ insert([[
+ hello foo!
+ text]])
+
+ eq({'hello'}, get_text(0, 0, 0, 5, {}))
+ eq({'hello foo!'}, get_text(0, 0, 0, 42, {}))
+ eq({'foo!'}, get_text(0, 6, 0, 10, {}))
+ eq({'foo!', 'tex'}, get_text(0, 6, 1, 3, {}))
+ eq({'foo!', 'tex'}, get_text(-2, 6, -1, 3, {}))
+ eq({''}, get_text(0, 18, 0, 20, {}))
+ eq({'ext'}, get_text(-1, 1, -1, 4, {}))
+ end)
+
+ it('errors on out-of-range', function()
+ eq(false, pcall(get_text, 2, 0, 3, 0, {}))
+ eq(false, pcall(get_text, 0, 0, 4, 0, {}))
+ end)
+
+ it('errors when start is greater than end', function()
+ eq(false, pcall(get_text, 1, 0, 0, 0, {}))
+ eq(false, pcall(get_text, 0, 1, 0, 0, {}))
+ end)
+ end)
+
describe('nvim_buf_get_offset', function()
local get_offset = curbufmeths.get_offset
it('works', function()
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index c9c9be5406..fc09e4cde0 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -827,6 +827,7 @@ describe('API: buffer events:', function()
end
it('when :terminal lines change', function()
+ if helpers.pending_win32(pending) then return end
local buffer_lines = {}
local expected_lines = {}
command('terminal "'..nvim_prog..'" -u NONE -i NONE -n -c "set shortmess+=A"')
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index de22c9078c..b80004f67c 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -107,7 +107,8 @@ describe('nvim_add_user_command', function()
]]
eq({
- args = "hello",
+ args = [[hello my\ friend how\ are\ you?]],
+ fargs = {[[hello]], [[my\ friend]], [[how\ are\ you?]]},
bang = false,
line1 = 1,
line2 = 1,
@@ -115,13 +116,14 @@ describe('nvim_add_user_command', function()
range = 0,
count = 2,
reg = "",
- }, exec_lua [[
- vim.api.nvim_command('CommandWithLuaCallback hello')
+ }, exec_lua [=[
+ vim.api.nvim_command([[CommandWithLuaCallback hello my\ friend how\ are\ you?]])
return result
- ]])
+ ]=])
eq({
- args = "",
+ args = 'h\tey',
+ fargs = {[[h]], [[ey]]},
bang = true,
line1 = 10,
line2 = 10,
@@ -129,13 +131,14 @@ describe('nvim_add_user_command', function()
range = 1,
count = 10,
reg = "",
- }, exec_lua [[
- vim.api.nvim_command('botright 10CommandWithLuaCallback!')
+ }, exec_lua [=[
+ vim.api.nvim_command('botright 10CommandWithLuaCallback! h\tey')
return result
- ]])
+ ]=])
eq({
- args = "",
+ args = "h",
+ fargs = {"h"},
bang = false,
line1 = 1,
line2 = 42,
@@ -144,9 +147,52 @@ describe('nvim_add_user_command', function()
count = 42,
reg = "",
}, exec_lua [[
- vim.api.nvim_command('CommandWithLuaCallback 42')
+ vim.api.nvim_command('CommandWithLuaCallback 42 h')
return result
]])
+
+ eq({
+ args = "",
+ fargs = {""}, -- fargs works without args
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithLuaCallback')
+ return result
+ ]])
+
+ -- f-args doesn't split when command nargs is 1 or "?"
+ exec_lua [[
+ result = {}
+ vim.api.nvim_add_user_command('CommandWithOneArg', function(opts)
+ result = opts
+ end, {
+ nargs = "?",
+ bang = true,
+ count = 2,
+ })
+ ]]
+
+ eq({
+ args = "hello I'm one argmuent",
+ fargs = {"hello I'm one argmuent"}, -- Doesn't split args
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithOneArg hello I\'m one argmuent')
+ return result
+ ]])
+
end)
it('can define buffer-local commands', function()
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 03b407f4e0..06cdb0bc19 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -28,8 +28,11 @@ describe('API: highlight',function()
bold = true,
italic = true,
reverse = true,
- undercurl = true,
underline = true,
+ underlineline = true,
+ undercurl = true,
+ underdot = true,
+ underdash = true,
strikethrough = true,
}
@@ -52,7 +55,7 @@ describe('API: highlight',function()
eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
-- Test all highlight properties.
- command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse,strikethrough')
+ command('hi NewHighlight gui=underline,bold,underlineline,undercurl,underdot,underdash,italic,reverse,strikethrough')
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
-- Test nil argument.
@@ -195,6 +198,9 @@ describe("API: set highlight", function()
reverse = true,
undercurl = true,
underline = true,
+ underdash = true,
+ underdot = true,
+ underlineline = true,
strikethrough = true,
cterm = {
italic = true,
@@ -211,6 +217,9 @@ describe("API: set highlight", function()
reverse = true,
undercurl = true,
underline = true,
+ underdash = true,
+ underdot = true,
+ underlineline = true,
strikethrough = true,
}
local highlight3_result_cterm = {
@@ -274,7 +283,7 @@ describe("API: set highlight", function()
exec_capture('highlight Test_hl'))
meths.set_hl(0, 'Test_hl2', highlight3_config)
- eq('Test_hl2 xxx cterm=undercurl,italic,reverse,strikethrough ctermfg=8 ctermbg=15 gui=bold,underline,undercurl,italic,reverse,strikethrough guifg=#ff0000 guibg=#0032aa',
+ eq('Test_hl2 xxx cterm=undercurl,italic,reverse,strikethrough ctermfg=8 ctermbg=15 gui=bold,underline,underlineline,undercurl,underdot,underdash,italic,reverse,strikethrough guifg=#ff0000 guibg=#0032aa',
exec_capture('highlight Test_hl2'))
-- Colors are stored exactly as they are defined.
@@ -304,10 +313,6 @@ describe("API: set highlight", function()
eq('Test_hl3 xxx ctermbg=9',
exec_capture('highlight Test_hl3'))
- meths.set_hl(0, 'Test_hl3', {})
- eq('Test_hl3 xxx cleared',
- exec_capture('highlight Test_hl3'))
-
eq("'redd' is not a valid color",
pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'}))
@@ -320,5 +325,16 @@ describe("API: set highlight", function()
eq("'#FF00FF' is not a valid color",
pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'}))
+
+ for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do
+ meths.set_hl(0, 'Test_hl3', {fg = fg_val})
+ eq('Test_hl3 xxx cleared',
+ exec_capture('highlight Test_hl3'))
+ end
+
+ meths.set_hl(0, 'Test_hl3', {fg='#FF00FF', blend=50})
+ eq('Test_hl3 xxx guifg=#FF00FF blend=50',
+ exec_capture('highlight Test_hl3'))
+
end)
end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index e49e0b8cc4..c0edcde476 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -15,6 +15,9 @@ local pcall_err = helpers.pcall_err
local shallowcopy = helpers.shallowcopy
local sleep = helpers.sleep
+local sid_api_client = -9
+local sid_lua = -8
+
describe('nvim_get_keymap', function()
before_each(clear)
@@ -340,7 +343,7 @@ describe('nvim_get_keymap', function()
script=0,
silent=0,
expr=0,
- sid=0,
+ sid=sid_lua,
buffer=0,
nowait=0,
mode='n',
@@ -357,7 +360,7 @@ describe('nvim_get_keymap', function()
script=0,
silent=0,
expr=0,
- sid=0,
+ sid=sid_api_client,
buffer=0,
nowait=0,
mode='n',
@@ -400,7 +403,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.silent = not opts.silent and 0 or 1
to_return.nowait = not opts.nowait and 0 or 1
to_return.expr = not opts.expr and 0 or 1
- to_return.sid = not opts.sid and 0 or opts.sid
+ to_return.sid = not opts.sid and sid_api_client or opts.sid
to_return.buffer = not opts.buffer and 0 or opts.buffer
to_return.lnum = not opts.lnum and 0 or opts.lnum
to_return.desc = opts.desc
@@ -625,7 +628,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
it('interprets control sequences in expr-quotes correctly when called '
..'inside vim', function()
command([[call nvim_set_keymap('i', "\<space>", "\<tab>", {})]])
- eq(generate_mapargs('i', '<Space>', '\t', {}),
+ eq(generate_mapargs('i', '<Space>', '\t', {sid=0}),
get_mapargs('i', '<Space>'))
feed('i ')
eq({'\t'}, curbufmeths.get_lines(0, -1, 0))
@@ -807,7 +810,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
local mapargs = funcs.maparg('asdf', 'n', false, true)
assert.Truthy(type(mapargs.callback) == 'number', 'callback is not luaref number')
mapargs.callback = nil
- eq(generate_mapargs('n', 'asdf', nil, {}), mapargs)
+ eq(generate_mapargs('n', 'asdf', nil, {sid=sid_lua}), mapargs)
end)
it('can make lua expr mappings', function()
@@ -877,24 +880,6 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq("\nn lhs rhs\n map description",
helpers.exec_capture("nmap lhs"))
end)
-
- it ('can :filter maps based on description', function()
- meths.set_keymap('n', 'asdf1', 'qwert', {desc='do the one thing'})
- meths.set_keymap('n', 'asdf2', 'qwert', {desc='doesnot really do anything'})
- meths.set_keymap('n', 'asdf3', 'qwert', {desc='do the other thing'})
- eq([[
-
-n asdf3 qwert
- do the other thing
-n asdf1 qwert
- do the one thing]],
- helpers.exec_capture('filter the nmap'))
- end)
-
- it ('shows <nop> as map rhs', function()
- meths.set_keymap('n', 'asdf', '<nop>', {})
- eq('\nn asdf <Nop>', helpers.exec_capture('nmap asdf'))
- end)
end)
describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 71cd055e08..af6872760a 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -636,34 +636,374 @@ describe('API', function()
eq('Invalid phase: 4',
pcall_err(request, 'nvim_paste', 'foo', true, 4))
end)
- it('stream: multiple chunks form one undo-block', function()
- nvim('paste', '1/chunk 1 (start)\n', true, 1)
- nvim('paste', '1/chunk 2 (end)\n', true, 3)
- local expected1 = [[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- ]]
- expect(expected1)
- nvim('paste', '2/chunk 1 (start)\n', true, 1)
- nvim('paste', '2/chunk 2\n', true, 2)
- expect([[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- 2/chunk 1 (start)
- 2/chunk 2
- ]])
- nvim('paste', '2/chunk 3\n', true, 2)
- nvim('paste', '2/chunk 4 (end)\n', true, 3)
- expect([[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- 2/chunk 1 (start)
- 2/chunk 2
- 2/chunk 3
- 2/chunk 4 (end)
- ]])
- feed('u') -- Undo.
- expect(expected1)
+ local function run_streamed_paste_tests()
+ it('stream: multiple chunks form one undo-block', function()
+ nvim('paste', '1/chunk 1 (start)\n', true, 1)
+ nvim('paste', '1/chunk 2 (end)\n', true, 3)
+ local expected1 = [[
+ 1/chunk 1 (start)
+ 1/chunk 2 (end)
+ ]]
+ expect(expected1)
+ nvim('paste', '2/chunk 1 (start)\n', true, 1)
+ nvim('paste', '2/chunk 2\n', true, 2)
+ expect([[
+ 1/chunk 1 (start)
+ 1/chunk 2 (end)
+ 2/chunk 1 (start)
+ 2/chunk 2
+ ]])
+ nvim('paste', '2/chunk 3\n', true, 2)
+ nvim('paste', '2/chunk 4 (end)\n', true, 3)
+ expect([[
+ 1/chunk 1 (start)
+ 1/chunk 2 (end)
+ 2/chunk 1 (start)
+ 2/chunk 2
+ 2/chunk 3
+ 2/chunk 4 (end)
+ ]])
+ feed('u') -- Undo.
+ expect(expected1)
+ end)
+ it('stream: Insert mode', function()
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('i')
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('aaaaaabbbbbbccccccdddddd')
+ feed('<Esc>u')
+ expect('')
+ end)
+ describe('stream: Normal mode', function()
+ describe('on empty line', function()
+ before_each(function()
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ end)
+ after_each(function()
+ feed('u')
+ expect('')
+ end)
+ it('pasting one line', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('aaaaaabbbbbbccccccdddddd')
+ end)
+ it('pasting multiple lines', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ end)
+ describe('not at the end of a line', function()
+ before_each(function()
+ feed('i||<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('0')
+ end)
+ after_each(function()
+ feed('u')
+ expect('||')
+ end)
+ it('pasting one line', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('|aaaaaabbbbbbccccccdddddd|')
+ end)
+ it('pasting multiple lines', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ |aaaaaa
+ bbbbbb
+ cccccc
+ dddddd|]])
+ end)
+ end)
+ describe('at the end of a line', function()
+ before_each(function()
+ feed('i||<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('2|')
+ end)
+ after_each(function()
+ feed('u')
+ expect('||')
+ end)
+ it('pasting one line', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||aaaaaabbbbbbccccccdddddd')
+ end)
+ it('pasting multiple lines', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ ||aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ end)
+ end)
+ describe('stream: Visual mode', function()
+ describe('neither end at the end of a line', function()
+ before_each(function()
+ feed('i|xxx<CR>xxx|<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('3|vhk')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ |xxx
+ xxx|]])
+ end)
+ it('with non-empty chunks', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('|aaaaaabbbbbbccccccdddddd|')
+ end)
+ it('with empty first chunk', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('|bbbbbbccccccdddddd|')
+ end)
+ it('with all chunks empty', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', '', false, 2)
+ nvim('paste', '', false, 2)
+ nvim('paste', '', false, 3)
+ expect('||')
+ end)
+ end)
+ describe('cursor at the end of a line', function()
+ before_each(function()
+ feed('i||xxx<CR>xxx<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('3|vko')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ ||xxx
+ xxx]])
+ end)
+ it('with non-empty chunks', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||aaaaaabbbbbbccccccdddddd')
+ end)
+ it('with empty first chunk', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||bbbbbbccccccdddddd')
+ end)
+ end)
+ describe('other end at the end of a line', function()
+ before_each(function()
+ feed('i||xxx<CR>xxx<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('3|vk')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ ||xxx
+ xxx]])
+ end)
+ it('with non-empty chunks', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||aaaaaabbbbbbccccccdddddd')
+ end)
+ it('with empty first chunk', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||bbbbbbccccccdddddd')
+ end)
+ end)
+ end)
+ describe('stream: linewise Visual mode', function()
+ before_each(function()
+ feed('i123456789<CR>987654321<CR>123456789<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ 123456789
+ 987654321
+ 123456789]])
+ end)
+ describe('selecting the start of a file', function()
+ before_each(function()
+ feed('ggV')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd987654321
+ 123456789]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ 987654321
+ 123456789]])
+ end)
+ end)
+ describe('selecting the middle of a file', function()
+ before_each(function()
+ feed('2ggV')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ 123456789
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd123456789]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ 123456789
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ 123456789]])
+ end)
+ end)
+ describe('selecting the end of a file', function()
+ before_each(function()
+ feed('3ggV')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ 123456789
+ 987654321
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ 123456789
+ 987654321
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ ]])
+ end)
+ end)
+ describe('selecting the whole file', function()
+ before_each(function()
+ feed('ggVG')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ ]])
+ end)
+ end)
+ end)
+ end
+ describe('without virtualedit,', function()
+ run_streamed_paste_tests()
+ end)
+ describe('with virtualedit=onemore,', function()
+ before_each(function()
+ command('set virtualedit=onemore')
+ end)
+ run_streamed_paste_tests()
end)
it('non-streaming', function()
-- With final "\n".
@@ -738,6 +1078,37 @@ describe('API', function()
eeffgghh
iijjkkll]])
end)
+ it('when searching in Visual mode', function()
+ feed('v/')
+ nvim('paste', 'aabbccdd', true, -1)
+ eq('aabbccdd', funcs.getcmdline())
+ expect('')
+ end)
+ it('pasting with empty last chunk in Cmdline mode', function()
+ local screen = Screen.new(20, 4)
+ screen:attach()
+ feed(':')
+ nvim('paste', 'Foo', true, 1)
+ nvim('paste', '', true, 3)
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ :Foo^ |
+ ]])
+ end)
+ it('pasting text with control characters in Cmdline mode', function()
+ local screen = Screen.new(20, 4)
+ screen:attach()
+ feed(':')
+ nvim('paste', 'normal! \023\022\006\027', true, -1)
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ :normal! ^W^V^F^[^ |
+ ]])
+ end)
it('crlf=false does not break lines at CR, CRLF', function()
nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1)
expect('line 1\r\n\r\rline 2\nline 3\rline 4\r')
@@ -2621,24 +2992,24 @@ describe('API', function()
eq({ str = 'a━━━b', width = 5 },
meths.eval_statusline('a%=b', { fillchar = '━', maxwidth = 5 }))
end)
- it('rejects double-width fillchar', function()
- eq('fillchar must be a single-width character',
- pcall_err(meths.eval_statusline, '', { fillchar = '哦' }))
+ it('treats double-width fillchar as single-width', function()
+ eq({ str = 'a哦哦哦b', width = 5 },
+ meths.eval_statusline('a%=b', { fillchar = '哦', maxwidth = 5 }))
end)
- it('rejects control character fillchar', function()
- eq('fillchar must be a single-width character',
- pcall_err(meths.eval_statusline, '', { fillchar = '\a' }))
+ it('treats control character fillchar as single-width', function()
+ eq({ str = 'a\031\031\031b', width = 5 },
+ meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 }))
end)
it('rejects multiple-character fillchar', function()
- eq('fillchar must be a single-width character',
+ eq('fillchar must be a single character',
pcall_err(meths.eval_statusline, '', { fillchar = 'aa' }))
end)
it('rejects empty string fillchar', function()
- eq('fillchar must be a single-width character',
+ eq('fillchar must be a single character',
pcall_err(meths.eval_statusline, '', { fillchar = '' }))
end)
it('rejects non-string fillchar', function()
- eq('fillchar must be a single-width character',
+ eq('fillchar must be a single character',
pcall_err(meths.eval_statusline, '', { fillchar = 1 }))
end)
describe('highlight parsing', function()
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 4d2ffa316a..c31ab2060a 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
ok, feed, insert, eval, tabpage = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
@@ -73,8 +74,7 @@ describe('API/win', function()
eq('typing\n some dumb text', curbuf_contents())
end)
- it('does not leak memory when using invalid window ID with invalid pos',
- function()
+ it('does not leak memory when using invalid window ID with invalid pos', function()
eq('Invalid window id: 1', pcall_err(meths.win_set_cursor, 1, {"b\na"}))
end)
@@ -147,6 +147,46 @@ describe('API/win', function()
eq({2, 5}, window('get_cursor', win))
end)
+ it('updates cursorline and statusline ruler in non-current window', function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {background = Screen.colors.Grey90}, -- CursorLine
+ [3] = {bold = true, reverse = true}, -- StatusLine
+ [4] = {reverse = true}, -- VertSplit, StatusLineNC
+ })
+ screen:attach()
+ command('set ruler')
+ command('set cursorline')
+ insert([[
+ aaa
+ bbb
+ ccc
+ ddd]])
+ local oldwin = curwin()
+ command('vsplit')
+ screen:expect([[
+ aaa {4:│}aaa |
+ bbb {4:│}bbb |
+ ccc {4:│}ccc |
+ {2:dd^d }{4:│}{2:ddd }|
+ {1:~ }{4:│}{1:~ }|
+ {1:~ }{4:│}{1:~ }|
+ {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 4,3 All}|
+ |
+ ]])
+ window('set_cursor', oldwin, {1, 0})
+ screen:expect([[
+ aaa {4:│}{2:aaa }|
+ bbb {4:│}bbb |
+ ccc {4:│}ccc |
+ {2:dd^d }{4:│}ddd |
+ {1:~ }{4:│}{1:~ }|
+ {1:~ }{4:│}{1:~ }|
+ {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 1,1 All}|
+ |
+ ]])
+ end)
end)
describe('{get,set}_height', function()
diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua
new file mode 100644
index 0000000000..ad3687d7b0
--- /dev/null
+++ b/test/functional/autocmd/autocmd_oldtest_spec.lua
@@ -0,0 +1,86 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local meths = helpers.meths
+local funcs = helpers.funcs
+
+local exec = function(str)
+ meths.exec(str, false)
+end
+
+describe('oldtests', function()
+ before_each(clear)
+
+ local exec_lines = function(str)
+ return funcs.split(funcs.execute(str), "\n")
+ end
+
+ local add_an_autocmd = function()
+ exec [[
+ augroup vimBarTest
+ au BufReadCmd * echo 'hello'
+ augroup END
+ ]]
+
+ eq(3, #exec_lines('au vimBarTest'))
+ eq(1, #meths.get_autocmds({ group = 'vimBarTest' }))
+ end
+
+ it('should recognize a bar before the {event}', function()
+ -- Good spacing
+ add_an_autocmd()
+ exec [[ augroup vimBarTest | au! | augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+ eq({}, meths.get_autocmds({ group = 'vimBarTest' }))
+
+ -- Sad spacing
+ add_an_autocmd()
+ exec [[ augroup vimBarTest| au!| augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+
+
+ -- test that a bar is recognized after the {event}
+ add_an_autocmd()
+ exec [[ augroup vimBarTest| au!BufReadCmd| augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+
+ add_an_autocmd()
+ exec [[ au! vimBarTest|echo 'hello' ]]
+ eq(1, #exec_lines('au vimBarTest'))
+ end)
+
+ it('should fire on unload buf', function()
+ funcs.writefile({'Test file Xxx1'}, 'Xxx1')
+ funcs.writefile({'Test file Xxx2'}, 'Xxx2')
+
+ local content = [[
+ func UnloadAllBufs()
+ let i = 1
+ while i <= bufnr('$')
+ if i != bufnr('%') && bufloaded(i)
+ exe i . 'bunload'
+ endif
+ let i += 1
+ endwhile
+ endfunc
+ au BufUnload * call UnloadAllBufs()
+ au VimLeave * call writefile(['Test Finished'], 'Xout')
+ set nohidden
+ edit Xxx1
+ split Xxx2
+ q
+ ]]
+
+ funcs.writefile(funcs.split(content, "\n"), 'Xtest')
+
+ funcs.delete('Xout')
+ funcs.system(meths.get_vvar('progpath') .. ' -u NORC -i NONE -N -S Xtest')
+ eq(1, funcs.filereadable('Xout'))
+
+ funcs.delete('Xxx1')
+ funcs.delete('Xxx2')
+ funcs.delete('Xtest')
+ funcs.delete('Xout')
+ end)
+end)
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 93d71a9e45..f37f04b32f 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -2,8 +2,10 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_visible = helpers.assert_visible
+local assert_alive = helpers.assert_alive
local dedent = helpers.dedent
local eq = helpers.eq
+local neq = helpers.neq
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
@@ -13,6 +15,7 @@ local funcs = helpers.funcs
local expect = helpers.expect
local command = helpers.command
local exc_exec = helpers.exc_exec
+local exec_lua = helpers.exec_lua
local curbufmeths = helpers.curbufmeths
local source = helpers.source
@@ -333,6 +336,68 @@ describe('autocmd', function()
pcall_err(command, "call nvim_set_current_win(g:winid)"))
end)
+ it("`aucmd_win` cannot be changed into a normal window #13699", function()
+ local screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {reverse = true},
+ [3] = {bold = true, reverse = true},
+ }
+
+ -- Create specific layout and ensure it's left unchanged.
+ -- Use nvim_buf_call on a hidden buffer so aucmd_win is used.
+ exec_lua [[
+ vim.cmd "wincmd s | wincmd _"
+ _G.buf = vim.api.nvim_create_buf(true, true)
+ vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd J" end)
+ ]]
+ screen:expect [[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ ]]
+ -- This used to crash after making aucmd_win a normal window via the above.
+ exec_lua [[
+ vim.cmd "tabnew | tabclose # | wincmd s | wincmd _"
+ vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd K" end)
+ ]]
+ assert_alive()
+ screen:expect_unchanged()
+
+ -- Ensure splitting still works from inside the aucmd_win.
+ exec_lua [[vim.api.nvim_buf_call(_G.buf, function() vim.cmd "split" end)]]
+ screen:expect [[
+ ^ |
+ {1:~ }|
+ {3:[No Name] }|
+ |
+ {1:~ }|
+ {2:[Scratch] }|
+ |
+ {1:~ }|
+ {2:[No Name] }|
+ |
+ ]]
+
+ -- After all of our messing around, aucmd_win should still be floating.
+ -- Use :only to ensure _G.buf is hidden again (so the aucmd_win is used).
+ eq("editor", exec_lua [[
+ vim.cmd "only"
+ vim.api.nvim_buf_call(_G.buf, function()
+ _G.config = vim.api.nvim_win_get_config(0)
+ end)
+ return _G.config.relative
+ ]])
+ end)
+
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
screen:attach()
@@ -354,4 +419,106 @@ describe('autocmd', function()
:doautocmd SessionLoadPost |
]]}
end)
+
+ describe('old_tests', function()
+ it('vimscript: WinNew ++once', function()
+ source [[
+ " Without ++once WinNew triggers twice
+ let g:did_split = 0
+ augroup Testing
+ au!
+ au WinNew * let g:did_split += 1
+ augroup END
+ split
+ split
+ call assert_equal(2, g:did_split)
+ call assert_true(exists('#WinNew'))
+ close
+ close
+
+ " With ++once WinNew triggers once
+ let g:did_split = 0
+ augroup Testing
+ au!
+ au WinNew * ++once let g:did_split += 1
+ augroup END
+ split
+ split
+ call assert_equal(1, g:did_split)
+ call assert_false(exists('#WinNew'))
+ close
+ close
+
+ call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+ ]]
+
+ meths.set_var('did_split', 0)
+
+ source [[
+ augroup Testing
+ au!
+ au WinNew * let g:did_split += 1
+ augroup END
+
+ split
+ split
+ ]]
+
+ eq(2, meths.get_var('did_split'))
+ eq(1, funcs.exists('#WinNew'))
+
+ -- Now with once
+ meths.set_var('did_split', 0)
+
+ source [[
+ augroup Testing
+ au!
+ au WinNew * ++once let g:did_split += 1
+ augroup END
+
+ split
+ split
+ ]]
+
+ eq(1, meths.get_var('did_split'))
+ eq(0, funcs.exists('#WinNew'))
+
+ -- call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+ local ok, msg = pcall(source, [[
+ au WinNew * ++once ++once echo bad
+ ]])
+
+ eq(false, ok)
+ eq(true, not not string.find(msg, 'E983:'))
+ end)
+
+ it('should have autocmds in filetypedetect group', function()
+ source [[filetype on]]
+ neq({}, meths.get_autocmds { group = "filetypedetect" })
+ end)
+
+ it('should not access freed mem', function()
+ source [[
+ au BufEnter,BufLeave,WinEnter,WinLeave 0 vs xxx
+ arg 0
+ argadd
+ all
+ all
+ au!
+ bwipe xxx
+ ]]
+ end)
+
+ it('should allow comma-separated patterns', function()
+ source [[
+ augroup TestingPatterns
+ au!
+ autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] echo 'hello'
+ autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] echo 'hello'
+ augroup END
+ ]]
+
+ eq(4, #meths.get_autocmds { event = "BufReadCmd", group = "TestingPatterns" })
+ end)
+ end)
end)
diff --git a/test/functional/autocmd/cursormoved_spec.lua b/test/functional/autocmd/cursormoved_spec.lua
index 9641d4b096..85d8628d7e 100644
--- a/test/functional/autocmd/cursormoved_spec.lua
+++ b/test/functional/autocmd/cursormoved_spec.lua
@@ -35,6 +35,7 @@ describe('CursorMoved', function()
it("is not triggered by cursor movement prior to first CursorMoved instantiation", function()
source([[
let g:cursormoved = 0
+ autocmd! CursorMoved
autocmd CursorMoved * let g:cursormoved += 1
]])
eq(0, eval('g:cursormoved'))
diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua
new file mode 100644
index 0000000000..59757a7d61
--- /dev/null
+++ b/test/functional/autocmd/show_spec.lua
@@ -0,0 +1,35 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local dedent = helpers.dedent
+local eq = helpers.eq
+local funcs = helpers.funcs
+
+describe(":autocmd", function()
+ before_each(clear)
+
+ it("should not segfault when you just do autocmd", function()
+ command ":autocmd"
+ end)
+
+ it("should filter based on ++once", function()
+ command "autocmd! BufEnter"
+ command "autocmd BufEnter * :echo 'Hello'"
+ command [[augroup TestingOne]]
+ command [[ autocmd BufEnter * :echo "Line 1"]]
+ command [[ autocmd BufEnter * :echo "Line 2"]]
+ command [[augroup END]]
+
+ eq(dedent([[
+
+ --- Autocommands ---
+ BufEnter
+ * :echo 'Hello'
+ TestingOne BufEnter
+ * :echo "Line 1"
+ :echo "Line 2"]]),
+ funcs.execute('autocmd BufEnter'))
+
+ end)
+end)
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index 1e8f981437..bc7a6d6c36 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -32,7 +32,7 @@ describe('autocmd TermClose', function()
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end)
end)
- it('kills job trapping SIGTERM', function()
+ pending('kills job trapping SIGTERM', function()
if iswin() then return end
nvim('set_option', 'shell', 'sh')
nvim('set_option', 'shellcmdflag', '-c')
@@ -52,7 +52,7 @@ describe('autocmd TermClose', function()
ok(duration <= 4000) -- Epsilon for slow CI
end)
- it('kills PTY job trapping SIGHUP and SIGTERM', function()
+ pending('kills PTY job trapping SIGHUP and SIGTERM', function()
if iswin() then return end
nvim('set_option', 'shell', 'sh')
nvim('set_option', 'shellcmdflag', '-c')
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index c28300f0f4..ca52404d3b 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -10,6 +10,8 @@ local nvim_prog = helpers.nvim_prog
local is_os = helpers.is_os
local retry = helpers.retry
local expect_twostreams = helpers.expect_twostreams
+local assert_alive = helpers.assert_alive
+local pcall_err = helpers.pcall_err
describe('channels', function()
local init = [[
@@ -314,3 +316,22 @@ describe('channels', function()
eq({"notification", "exit", {id, 1, {''}}}, next_msg())
end)
end)
+
+describe('loopback', function()
+ before_each(function()
+ clear()
+ command("let chan = sockconnect('pipe', v:servername, {'rpc': v:true})")
+ end)
+
+ it('does not crash when sending raw data', function()
+ eq("Vim(call):Can't send raw data to rpc channel",
+ pcall_err(command, "call chansend(chan, 'test')"))
+ assert_alive()
+ end)
+
+ it('are released when closed', function()
+ local chans = eval('len(nvim_list_chans())')
+ command('call chanclose(chan)')
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 0a69660871..a0df3b7767 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -78,6 +78,7 @@ describe('jobs', function()
end)
it('append environment with pty #env', function()
+ if helpers.pending_win32(pending) then return end
nvim('command', "let $VAR = 'abc'")
nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.pty = v:true")
diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua
new file mode 100644
index 0000000000..602a5a71eb
--- /dev/null
+++ b/test/functional/core/remote_spec.lua
@@ -0,0 +1,142 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local expect = helpers.expect
+local funcs = helpers.funcs
+local insert = helpers.insert
+local meths = helpers.meths
+local new_argv = helpers.new_argv
+local neq = helpers.neq
+local set_session = helpers.set_session
+local spawn = helpers.spawn
+local tmpname = helpers.tmpname
+local write_file = helpers.write_file
+
+describe('Remote', function()
+ local fname, other_fname
+ local contents = 'The call is coming from outside the process'
+ local other_contents = "A second file's contents"
+
+ before_each(function()
+ fname = tmpname() .. ' with spaces in the filename'
+ other_fname = tmpname()
+ write_file(fname, contents)
+ write_file(other_fname, other_contents)
+ end)
+
+ describe('connect to server and', function()
+ local server
+ before_each(function()
+ server = spawn(new_argv(), true)
+ set_session(server)
+ end)
+
+ after_each(function()
+ server:close()
+ end)
+
+ local function run_remote(...)
+ set_session(server)
+ local addr = funcs.serverlist()[1]
+ local client_argv = new_argv({args={'--server', addr, ...}})
+
+ -- Create an nvim instance just to run the remote-invoking nvim. We want
+ -- to wait for the remote instance to exit and calling jobwait blocks
+ -- the event loop. If the server event loop is blocked, it can't process
+ -- our incoming --remote calls.
+ local client_starter = spawn(new_argv(), false, nil, true)
+ set_session(client_starter)
+ local client_job_id = funcs.jobstart(client_argv)
+ eq({ 0 }, funcs.jobwait({client_job_id}))
+ client_starter:close()
+ set_session(server)
+ end
+
+ it('edit a single file', function()
+ run_remote('--remote', fname)
+ expect(contents)
+ eq(2, #funcs.getbufinfo())
+ end)
+
+ it('tab edit a single file with a non-changed buffer', function()
+ run_remote('--remote-tab', fname)
+ expect(contents)
+ eq(1, #funcs.gettabinfo())
+ end)
+
+ it('tab edit a single file with a changed buffer', function()
+ insert('hello')
+ run_remote('--remote-tab', fname)
+ expect(contents)
+ eq(2, #funcs.gettabinfo())
+ end)
+
+ it('edit multiple files', function()
+ run_remote('--remote', fname, other_fname)
+ expect(contents)
+ command('next')
+ expect(other_contents)
+ eq(3, #funcs.getbufinfo())
+ end)
+
+ it('send keys', function()
+ run_remote('--remote-send', ':edit '..fname..'<CR><C-W>v')
+ expect(contents)
+ eq(2, #funcs.getwininfo())
+ -- Only a single buffer as we're using edit and not drop like --remote does
+ eq(1, #funcs.getbufinfo())
+ end)
+
+ it('evaluate expressions', function()
+ run_remote('--remote-expr', 'setline(1, "Yo")')
+ expect('Yo')
+ end)
+ end)
+
+ it('creates server if not found', function()
+ clear('--remote', fname)
+ expect(contents)
+ eq(1, #funcs.getbufinfo())
+ -- Since we didn't pass silent, we should get a complaint
+ neq(nil, string.find(meths.exec('messages', true), 'E247'))
+ end)
+
+ it('creates server if not found with tabs', function()
+ clear('--remote-tab-silent', fname, other_fname)
+ expect(contents)
+ eq(2, #funcs.gettabinfo())
+ eq(2, #funcs.getbufinfo())
+ -- We passed silent, so no message should be issued about the server not being found
+ eq(nil, string.find(meths.exec('messages', true), 'E247'))
+ end)
+
+ describe('exits with error on', function()
+ local function run_and_check_exit_code(...)
+ local bogus_argv = new_argv(...)
+
+ -- Create an nvim instance just to run the remote-invoking nvim. We want
+ -- to wait for the remote instance to exit and calling jobwait blocks
+ -- the event loop. If the server event loop is blocked, it can't process
+ -- our incoming --remote calls.
+ clear()
+ local bogus_job_id = funcs.jobstart(bogus_argv)
+ eq({2}, funcs.jobwait({bogus_job_id}))
+ end
+ it('bogus subcommand', function()
+ run_and_check_exit_code('--remote-bogus')
+ end)
+
+ it('send without server', function()
+ run_and_check_exit_code('--remote-send', 'i')
+ end)
+
+ it('expr without server', function()
+ run_and_check_exit_code('--remote-expr', 'setline(1, "Yo")')
+ end)
+ it('wait subcommand', function()
+ run_and_check_exit_code('--remote-wait', fname)
+ end)
+ end)
+end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 2fa84e8313..3da7f6ffde 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -53,6 +53,7 @@ describe('startup', function()
]])
end)
it('in a TTY: has("ttyin")==1 has("ttyout")==1', function()
+ if helpers.pending_win32(pending) then return end
local screen = Screen.new(25, 4)
screen:attach()
if iswin() then
@@ -104,6 +105,7 @@ describe('startup', function()
end)
end)
it('input from pipe (implicit) #7679', function()
+ if helpers.pending_win32(pending) then return end
local screen = Screen.new(25, 4)
screen:attach()
if iswin() then
@@ -259,6 +261,7 @@ describe('startup', function()
end)
it('ENTER dismisses early message #7967', function()
+ if helpers.pending_win32(pending) then return end
local screen
screen = Screen.new(60, 6)
screen:attach()
@@ -491,6 +494,7 @@ describe('sysinit', function()
end)
it('fixed hang issue with -D (#12647)', function()
+ if helpers.pending_win32(pending) then return end
local screen
screen = Screen.new(60, 6)
screen:attach()
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index befad29922..1a0ee54505 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -1193,4 +1193,23 @@ describe('completion', function()
eq('foobar', eval('g:word'))
feed('<esc>')
end)
+
+ it('does not crash if text is changed by first call to complete function #17489', function()
+ source([[
+ func Complete(findstart, base) abort
+ if a:findstart
+ let col = col('.')
+ call complete_add('#')
+ return col - 1
+ else
+ return []
+ endif
+ endfunc
+
+ set completeopt=longest
+ set completefunc=Complete
+ ]])
+ feed('ifoo#<C-X><C-U>')
+ assert_alive()
+ end)
end)
diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua
index c367f8fdd0..cc9fce8f67 100644
--- a/test/functional/editor/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
@@ -138,9 +138,9 @@ describe('put command', function()
end -- create_test_defs() }}}
local function find_cursor_position(expect_string) -- {{{
- -- There must only be one occurance of the character 'x' in
+ -- There must only be one occurrence of the character 'x' in
-- expect_string.
- -- This function removes that occurance, and returns the position that
+ -- This function removes that occurrence, and returns the position that
-- it was in.
-- This returns the cursor position that would leave the 'x' in that
-- place if we feed 'ix<esc>' and the string existed before it.
diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua
index 84d5bc2335..eae36b9ae9 100644
--- a/test/functional/ex_cmds/map_spec.lua
+++ b/test/functional/ex_cmds/map_spec.lua
@@ -1,11 +1,15 @@
local helpers = require("test.functional.helpers")(after_each)
+local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
+local exec = helpers.exec
local feed = helpers.feed
local meths = helpers.meths
local clear = helpers.clear
local command = helpers.command
local expect = helpers.expect
+local insert = helpers.insert
+local eval = helpers.eval
describe(':*map', function()
before_each(clear)
@@ -25,4 +29,221 @@ describe(':*map', function()
feed('i-<M-">-')
expect('-foo-')
end)
+
+ it('shows <nop> as mapping rhs', function()
+ command('nmap asdf <Nop>')
+ eq([[
+
+n asdf <Nop>]],
+ helpers.exec_capture('nmap asdf'))
+ end)
+
+ it('mappings with description can be filtered', function()
+ meths.set_keymap('n', 'asdf1', 'qwert', {desc='do the one thing'})
+ meths.set_keymap('n', 'asdf2', 'qwert', {desc='doesnot really do anything'})
+ meths.set_keymap('n', 'asdf3', 'qwert', {desc='do the other thing'})
+ eq([[
+
+n asdf3 qwert
+ do the other thing
+n asdf1 qwert
+ do the one thing]],
+ helpers.exec_capture('filter the nmap'))
+ end)
+
+ it('<Plug> mappings ignore nore', function()
+ command('let x = 0')
+ eq(0, meths.eval('x'))
+ command [[
+ nnoremap <Plug>(Increase_x) <cmd>let x+=1<cr>
+ nmap increase_x_remap <Plug>(Increase_x)
+ nnoremap increase_x_noremap <Plug>(Increase_x)
+ ]]
+ feed('increase_x_remap')
+ eq(1, meths.eval('x'))
+ feed('increase_x_noremap')
+ eq(2, meths.eval('x'))
+ end)
+
+ it("Doesn't auto ignore nore for keys before or after <Plug> mapping", function()
+ command('let x = 0')
+ eq(0, meths.eval('x'))
+ command [[
+ nnoremap x <nop>
+ nnoremap <Plug>(Increase_x) <cmd>let x+=1<cr>
+ nmap increase_x_remap x<Plug>(Increase_x)x
+ nnoremap increase_x_noremap x<Plug>(Increase_x)x
+ ]]
+ insert("Some text")
+ eq('Some text', eval("getline('.')"))
+
+ feed('increase_x_remap')
+ eq(1, meths.eval('x'))
+ eq('Some text', eval("getline('.')"))
+ feed('increase_x_noremap')
+ eq(2, meths.eval('x'))
+ eq('Some te', eval("getline('.')"))
+ end)
+end)
+
+describe(':*map cursor and redrawing', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(20, 5)
+ screen:attach()
+ end)
+
+ it('cursor is restored after :map <expr> which calls input()', function()
+ command('map <expr> x input("> ")')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed('x')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ > ^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ > |
+ ]])
+ end)
+
+ it('cursor is restored after :imap <expr> which calls input()', function()
+ command('imap <expr> x input("> ")')
+ feed('i')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ feed('x')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ > ^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ > |
+ ]])
+ end)
+
+ it('cursor is restored after :map <expr> which redraws statusline vim-patch:8.1.2336', function()
+ exec([[
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ set ls=2
+ hi! link StatusLine ErrorMsg
+ noremap <expr> <C-B> Func()
+ func Func()
+ let g:on = !get(g:, 'on', 0)
+ redraws
+ return ''
+ endfunc
+ func Status()
+ return get(g:, 'on', 0) ? '[on]' : ''
+ endfunc
+ set stl=%{Status()}
+ ]])
+ feed('<C-B>')
+ screen:expect([[
+ one |
+ ^two |
+ three |
+ [on] |
+ |
+ ]])
+ end)
+
+ it('error in :nmap <expr> does not mess up display vim-patch:4.2.4338', function()
+ screen:try_resize(40, 5)
+ command('nmap <expr> <F2> execute("throw 42")')
+ feed('<F2>')
+ screen:expect([[
+ |
+ |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ Press ENTER or type command to continue^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ end)
+
+ it('error in :cmap <expr> handled correctly vim-patch:4.2.4338', function()
+ screen:try_resize(40, 5)
+ command('cmap <expr> <F2> execute("throw 42")')
+ feed(':echo "foo')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ :echo "foo^ |
+ ]])
+ feed('<F2>')
+ screen:expect([[
+ |
+ :echo "foo |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ :echo "foo^ |
+ ]])
+ feed('"')
+ screen:expect([[
+ |
+ :echo "foo |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ :echo "foo"^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ :echo "foo |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ foo |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+
+ it('listing mappings clears command line vim-patch:8.2.4401', function()
+ screen:try_resize(40, 5)
+ command('nmap a b')
+ feed(': nmap a<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ n a b |
+ ]])
+ end)
end)
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index aefcc53cab..2702fb196f 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -14,6 +14,7 @@ local rmdir = helpers.rmdir
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
describe(':mksession', function()
+ if helpers.pending_win32(pending) then return end
local session_file = file_prefix .. '.vim'
local tab_dir = file_prefix .. '.d'
diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua
new file mode 100644
index 0000000000..326104dc3c
--- /dev/null
+++ b/test/functional/ex_cmds/verbose_spec.lua
@@ -0,0 +1,168 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec = helpers.exec
+local exec_capture = helpers.exec_capture
+local write_file = helpers.write_file
+local call_viml_function = helpers.meths.call_function
+
+describe('lua :verbose', function()
+ local script_location, script_file
+ -- All test cases below use the same nvim instance.
+ setup(function()
+ clear{args={'-V1'}}
+ script_file = 'test_verbose.lua'
+ local current_dir = call_viml_function('getcwd', {})
+ current_dir = call_viml_function('fnamemodify', {current_dir, ':~'})
+ script_location = table.concat{current_dir, helpers.get_pathsep(), script_file}
+
+ write_file(script_file, [[
+vim.api.nvim_set_option('hlsearch', false)
+vim.bo.expandtab = true
+vim.opt.number = true
+vim.api.nvim_set_keymap('n', '<leader>key1', ':echo "test"<cr>', {noremap = true})
+vim.keymap.set('n', '<leader>key2', ':echo "test"<cr>')
+
+vim.api.nvim_exec("augroup test_group\
+ autocmd!\
+ autocmd FileType c setl cindent\
+ augroup END\
+ ", false)
+
+vim.api.nvim_command("command Bdelete :bd")
+vim.api.nvim_add_user_command("TestCommand", ":echo 'Hello'", {})
+
+vim.api.nvim_exec ("\
+function Close_Window() abort\
+ wincmd -\
+endfunction\
+", false)
+
+local ret = vim.api.nvim_exec ("\
+function! s:return80()\
+ return 80\
+endfunction\
+let &tw = s:return80()\
+", true)
+]])
+ exec(':source '..script_file)
+ end)
+
+ teardown(function()
+ os.remove(script_file)
+ end)
+
+ it('"Last set" for option set by Lua', function()
+ local result = exec_capture(':verbose set hlsearch?')
+ eq(string.format([[
+nohlsearch
+ Last set from %s line 1]],
+ script_location), result)
+ end)
+
+ it('"Last set" for option set by vim.o', function()
+ local result = exec_capture(':verbose set expandtab?')
+ eq(string.format([[
+ expandtab
+ Last set from %s line 2]],
+ script_location), result)
+ end)
+
+ it('"Last set" for option set by vim.opt', function()
+ local result = exec_capture(':verbose set number?')
+ eq(string.format([[
+ number
+ Last set from %s line 3]],
+ script_location), result)
+ end)
+
+ it('"Last set" for keymap set by Lua', function()
+ local result = exec_capture(':verbose map <leader>key1')
+ eq(string.format([[
+
+n \key1 * :echo "test"<CR>
+ Last set from %s line 4]],
+ script_location), result)
+ end)
+
+ it('"Last set" for keymap set by vim.keymap', function()
+ local result = exec_capture(':verbose map <leader>key2')
+ eq(string.format([[
+
+n \key2 * :echo "test"<CR>
+ Last set from %s line 5]],
+ script_location), result)
+ end)
+
+ it('"Last set" for autocmd by vim.api.nvim_exec', function()
+ local result = exec_capture(':verbose autocmd test_group Filetype c')
+ eq(string.format([[
+--- Autocommands ---
+test_group FileType
+ c setl cindent
+ Last set from %s line 7]],
+ script_location), result)
+ end)
+
+ it('"Last set" for command defined by nvim_command', function()
+ local result = exec_capture(':verbose command Bdelete')
+ eq(string.format([[
+ Name Args Address Complete Definition
+ Bdelete 0 :bd
+ Last set from %s line 13]],
+ script_location), result)
+ end)
+
+ it('"Last set" for command defined by nvim_add_user_command', function()
+ local result = exec_capture(':verbose command TestCommand')
+ eq(string.format([[
+ Name Args Address Complete Definition
+ TestCommand 0 :echo 'Hello'
+ Last set from %s line 14]],
+ script_location), result)
+ end)
+
+ it('"Last set for function', function()
+ local result = exec_capture(':verbose function Close_Window')
+ eq(string.format([[
+ function Close_Window() abort
+ Last set from %s line 16
+1 wincmd -
+ endfunction]],
+ script_location), result)
+ end)
+
+ it('"Last set" works with anonymous sid', function()
+ local result = exec_capture(':verbose set tw?')
+ eq(string.format([[
+ textwidth=80
+ Last set from %s line 22]],
+ script_location), result)
+ end)
+end)
+
+describe('lua verbose:', function()
+ local script_file
+
+ setup(function()
+ clear()
+ script_file = 'test_luafile.lua'
+ write_file(script_file, [[
+ vim.api.nvim_set_option('hlsearch', false)
+ ]])
+ exec(':source '..script_file)
+ end)
+
+ teardown(function()
+ os.remove(script_file)
+ end)
+
+ it('is disabled when verbose = 0', function()
+ local result = exec_capture(':verbose set hlsearch?')
+ eq([[
+nohlsearch
+ Last set from Lua]], result)
+ end)
+end)
+
diff --git a/test/functional/legacy/autochdir_spec.lua b/test/functional/legacy/autochdir_spec.lua
index 37a94476a0..13cb6cd287 100644
--- a/test/functional/legacy/autochdir_spec.lua
+++ b/test/functional/legacy/autochdir_spec.lua
@@ -1,8 +1,12 @@
local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local clear, eq, matches = helpers.clear, helpers.eq, helpers.matches
-local eval, command, call = helpers.eval, helpers.command, helpers.call
-local exec_capture = helpers.exec_capture
+local eval, command, call, meths = helpers.eval, helpers.command, helpers.call, helpers.meths
+local source, exec_capture = helpers.source, helpers.exec_capture
+
+local function expected_empty()
+ eq({}, meths.get_vvar('errors'))
+end
describe('autochdir behavior', function()
local dir = 'Xtest_functional_legacy_autochdir'
@@ -10,19 +14,66 @@ describe('autochdir behavior', function()
before_each(function()
lfs.mkdir(dir)
clear()
+ command('set shellslash')
end)
after_each(function()
helpers.rmdir(dir)
end)
- -- Tests vim/vim/777 without test_autochdir().
+ -- Tests vim/vim#777 without test_autochdir().
it('sets filename', function()
command('set acd')
command('new')
command('w '..dir..'/Xtest')
eq('Xtest', eval("expand('%')"))
- eq(dir, eval([[substitute(getcwd(), '.*[/\\]\(\k*\)', '\1', '')]]))
+ eq(dir, eval([[substitute(getcwd(), '.*/\(\k*\)', '\1', '')]]))
+ end)
+
+ it(':file in win_execute() does not cause wrong directory', function()
+ command('cd '..dir)
+ source([[
+ func Test_set_filename_other_window()
+ let cwd = getcwd()
+ call mkdir('Xa')
+ call mkdir('Xb')
+ call mkdir('Xc')
+ try
+ args Xa/aaa.txt Xb/bbb.txt
+ set acd
+ let winid = win_getid()
+ snext
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt')
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ finally
+ set noacd
+ call chdir(cwd)
+ call delete('Xa', 'rf')
+ call delete('Xb', 'rf')
+ call delete('Xc', 'rf')
+ bwipe! aaa.txt
+ bwipe! bbb.txt
+ bwipe! ccc.txt
+ endtry
+ endfunc
+ ]])
+ call('Test_set_filename_other_window')
+ expected_empty()
+ end)
+
+ it('win_execute() does not change directory', function()
+ local subdir = 'Xfile'
+ command('cd '..dir)
+ command('set acd')
+ call('mkdir', subdir)
+ local winid = eval('win_getid()')
+ command('new '..subdir..'/file')
+ matches(dir..'/'..subdir..'$', eval('getcwd()'))
+ command('cd ..')
+ matches(dir..'$', eval('getcwd()'))
+ call('win_execute', winid, 'echo')
+ matches(dir..'$', eval('getcwd()'))
end)
it(':verbose pwd shows whether autochdir is used', function()
@@ -30,29 +81,36 @@ describe('autochdir behavior', function()
command('cd '..dir)
local cwd = eval('getcwd()')
command('edit global.txt')
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
call('mkdir', subdir)
command('split '..subdir..'/local.txt')
command('lcd '..subdir)
- matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
- command('set autochdir')
+ matches('%[window%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('set acd')
command('wincmd w')
- matches('%[autochdir%].*'..dir, exec_capture('verbose pwd'))
- command('lcd '..cwd)
- matches('%[window%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'$', exec_capture('verbose pwd'))
command('tcd '..cwd)
- matches('%[tabpage%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[tabpage%].*'..dir..'$', exec_capture('verbose pwd'))
command('cd '..cwd)
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('lcd '..cwd)
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
command('edit')
- matches('%[autochdir%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('enew')
command('wincmd w')
- matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
- command('set noautochdir')
- matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
command('wincmd w')
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('wincmd w')
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('set noacd')
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('wincmd w')
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('cd '..cwd)
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
command('wincmd w')
- matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
+ matches('%[window%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
end)
end)
diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua
index 141d9583e6..623b6b14a5 100644
--- a/test/functional/legacy/delete_spec.lua
+++ b/test/functional/legacy/delete_spec.lua
@@ -1,7 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, source = helpers.clear, helpers.source
local eq, eval, command = helpers.eq, helpers.eval, helpers.command
-local exc_exec = helpers.exc_exec
describe('Test for delete()', function()
before_each(clear)
@@ -9,42 +8,6 @@ describe('Test for delete()', function()
os.remove('Xfile')
end)
- it('file delete', function()
- command('split Xfile')
- command("call setline(1, ['a', 'b'])")
- command('wq')
- eq(eval("['a', 'b']"), eval("readfile('Xfile')"))
- eq(0, eval("delete('Xfile')"))
- eq(-1, eval("delete('Xfile')"))
- end)
-
- it('directory delete', function()
- command("call mkdir('Xdir1')")
- eq(1, eval("isdirectory('Xdir1')"))
- eq(0, eval("delete('Xdir1', 'd')"))
- eq(0, eval("isdirectory('Xdir1')"))
- eq(-1, eval("delete('Xdir1', 'd')"))
- end)
- it('recursive delete', function()
- command("call mkdir('Xdir1')")
- command("call mkdir('Xdir1/subdir')")
- command("call mkdir('Xdir1/empty')")
- command('split Xdir1/Xfile')
- command("call setline(1, ['a', 'b'])")
- command('w')
- command('w Xdir1/subdir/Xfile')
- command('close')
-
- eq(1, eval("isdirectory('Xdir1')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir1/Xfile')"))
- eq(1, eval("isdirectory('Xdir1/subdir')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir1/subdir/Xfile')"))
- eq(1, eval("'Xdir1/empty'->isdirectory()"))
- eq(0, eval("delete('Xdir1', 'rf')"))
- eq(0, eval("isdirectory('Xdir1')"))
- eq(-1, eval("delete('Xdir1', 'd')"))
- end)
-
it('symlink delete', function()
source([[
split Xfile
@@ -115,10 +78,4 @@ describe('Test for delete()', function()
eq(0, eval("delete('Xdir4/Xfile')"))
eq(0, eval("delete('Xdir4', 'd')"))
end)
-
- it('gives correct emsgs', function()
- eq('Vim(call):E474: Invalid argument', exc_exec("call delete('')"))
- eq('Vim(call):E15: Invalid expression: 0',
- exc_exec("call delete('foo', 0)"))
- end)
end)
diff --git a/test/functional/legacy/file_perm_spec.lua b/test/functional/legacy/file_perm_spec.lua
deleted file mode 100644
index ccdbfe0534..0000000000
--- a/test/functional/legacy/file_perm_spec.lua
+++ /dev/null
@@ -1,43 +0,0 @@
--- Test getting and setting file permissions.
-require('os')
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear, call, eq = helpers.clear, helpers.call, helpers.eq
-local neq, exc_exec, eval = helpers.neq, helpers.exc_exec, helpers.eval
-
-describe('Test getting and setting file permissions', function()
- local tempfile = helpers.tmpname()
-
- before_each(function()
- os.remove(tempfile)
- clear()
- end)
-
- it('file permissions', function()
- -- eval() is used to test VimL method syntax for setfperm() and getfperm()
- eq('', call('getfperm', tempfile))
- eq(0, eval("'" .. tempfile .. "'->setfperm('r--------')"))
-
- call('writefile', {'one'}, tempfile)
- eq(9, eval("len('" .. tempfile .. "'->getfperm())"))
-
- eq(1, call('setfperm', tempfile, 'rwx------'))
- if helpers.is_os('win') then
- eq('rw-rw-rw-', call('getfperm', tempfile))
- else
- eq('rwx------', call('getfperm', tempfile))
- end
-
- eq(1, call('setfperm', tempfile, 'r--r--r--'))
- eq('r--r--r--', call('getfperm', tempfile))
-
- local err = exc_exec(('call setfperm("%s", "---")'):format(tempfile))
- neq(err:find('E475:'), nil)
-
- eq(1, call('setfperm', tempfile, 'rwx------'))
- end)
-
- after_each(function()
- os.remove(tempfile)
- end)
-end)
diff --git a/test/functional/legacy/searchpos_spec.lua b/test/functional/legacy/searchpos_spec.lua
deleted file mode 100644
index fc18341c38..0000000000
--- a/test/functional/legacy/searchpos_spec.lua
+++ /dev/null
@@ -1,35 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local call = helpers.call
-local clear = helpers.clear
-local command = helpers.command
-local eq = helpers.eq
-local eval = helpers.eval
-local insert = helpers.insert
-
-describe('searchpos', function()
- before_each(clear)
-
- it('is working', function()
- insert([[
- 1a3
- 123xyz]])
-
- call('cursor', 1, 1)
- eq({1, 1, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
- call('cursor', 1, 2)
- eq({2, 1, 1}, eval([['\%(\([a-z]\)\|\_.\)\{-}xyz'->searchpos('pcW')]]))
-
- command('set cpo-=c')
- call('cursor', 1, 2)
- eq({1, 2, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
- call('cursor', 1, 3)
- eq({1, 3, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
-
- -- Now with \zs, first match is in column 0, "a" is matched.
- call('cursor', 1, 3)
- eq({2, 4, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcW')]]))
- -- With z flag start at cursor column, don't see the "a".
- call('cursor', 1, 3)
- eq({2, 4, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcWz')]]))
- end)
-end)
diff --git a/test/functional/legacy/set_spec.lua b/test/functional/legacy/set_spec.lua
deleted file mode 100644
index deb268b1e8..0000000000
--- a/test/functional/legacy/set_spec.lua
+++ /dev/null
@@ -1,30 +0,0 @@
--- Tests for :set
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear, command, eval, eq =
- helpers.clear, helpers.command, helpers.eval, helpers.eq
-
-describe(':set', function()
- before_each(clear)
-
- it('handles backslash properly', function()
- command('set iskeyword=a,b,c')
- command('set iskeyword+=d')
- eq('a,b,c,d', eval('&iskeyword'))
-
- command([[set iskeyword+=\\,e]])
- eq([[a,b,c,d,\,e]], eval('&iskeyword'))
-
- command('set iskeyword-=e')
- eq([[a,b,c,d,\]], eval('&iskeyword'))
-
- command([[set iskeyword-=\]])
- eq('a,b,c,d', eval('&iskeyword'))
- end)
-
- it('recognizes a trailing comma with +=', function()
- command('set wildignore=*.png,')
- command('set wildignore+=*.jpg')
- eq('*.png,*.jpg', eval('&wildignore'))
- end)
-end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index cb37fb9a1c..f173a15d32 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -102,6 +102,13 @@ describe('luaeval(vim.api.…)', function()
eq(false, funcs.luaeval('vim.api.nvim__id(false)'))
eq(NIL, funcs.luaeval('vim.api.nvim__id(nil)'))
+ -- API strings from Blobs can work as NUL-terminated C strings
+ eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ',
+ exc_exec('call nvim_eval(v:_null_blob)'))
+ eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ',
+ exc_exec('call nvim_eval(0z)'))
+ eq(1, eval('nvim_eval(0z31)'))
+
eq(0, eval([[type(luaeval('vim.api.nvim__id(1)'))]]))
eq(1, eval([[type(luaeval('vim.api.nvim__id("1")'))]]))
eq(3, eval([[type(luaeval('vim.api.nvim__id({1})'))]]))
diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua
index 3ba7e1589f..3a5966755e 100644
--- a/test/functional/lua/command_line_completion_spec.lua
+++ b/test/functional/lua/command_line_completion_spec.lua
@@ -106,6 +106,14 @@ describe('nlua_expand_pat', function()
)
end)
+ it('should work with lazy submodules of "vim" global', function()
+ eq({{ 'inspect' }, 4 },
+ get_completions('vim.inspec'))
+
+ eq({{ 'set' }, 11 },
+ get_completions('vim.keymap.se'))
+ end)
+
it('should be able to interpolate globals', function()
eq(
{{
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
new file mode 100644
index 0000000000..e183ce3a57
--- /dev/null
+++ b/test/functional/lua/thread_spec.lua
@@ -0,0 +1,408 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
+local clear = helpers.clear
+local feed = helpers.feed
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local next_msg = helpers.next_msg
+local NIL = helpers.NIL
+local pcall_err = helpers.pcall_err
+
+describe('thread', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {bold = true},
+ })
+ end)
+
+ it('entry func is executed in protected mode', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ error('Error in thread entry func')
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error in luv thread:} |
+ {3:[string "<nvim>"]:2: Error in thread entry func} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+ assert_alive()
+ end)
+
+ it('callback is executed in protected mode', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ local timer = vim.loop.new_timer()
+ local function ontimeout()
+ timer:stop()
+ timer:close()
+ error('Error in thread callback')
+ end
+ timer:start(10, 0, ontimeout)
+ vim.loop.run()
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error in luv callback, thread:} |
+ {3:[string "<nvim>"]:6: Error in thread callback} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+ assert_alive()
+ end)
+
+ describe('print', function()
+ it('works', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ print('print in thread')
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ print in thread |
+ ]])
+ end)
+
+ it('vim.inspect', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ print(vim.inspect({1,2}))
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ { 1, 2 } |
+ ]])
+ end)
+ end)
+
+ describe('vim.*', function()
+ before_each(function()
+ clear()
+ exec_lua [[
+ Thread_Test = {}
+
+ Thread_Test.entry_func = function(async, entry_str, args)
+ local decoded_args = vim.mpack.decode(args)
+ assert(loadstring(entry_str))(async, decoded_args)
+ end
+
+ function Thread_Test:do_test()
+ local async
+ local on_async = self.on_async
+ async = vim.loop.new_async(function(ret)
+ on_async(ret)
+ async:close()
+ end)
+ local thread =
+ vim.loop.new_thread(self.entry_func, async, self.entry_str, self.args)
+ vim.loop.thread_join(thread)
+ end
+
+ Thread_Test.new = function(entry, on_async, ...)
+ self = {}
+ setmetatable(self, {__index = Thread_Test})
+ self.args = vim.mpack.encode({...})
+ self.entry_str = string.dump(entry)
+ self.on_async = on_async
+ return self
+ end
+ ]]
+ end)
+
+ it('is_thread', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.is_thread())
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {true}}, next_msg())
+ end)
+
+ it('loop', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.loop.version())
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, ret)
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ local msg = next_msg()
+ eq(msg[1], 'notification')
+ assert(tonumber(msg[2]) >= 72961)
+ end)
+
+ it('mpack', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.mpack.encode({33, vim.NIL, 'text'}))
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', vim.mpack.decode(ret))
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('json', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.json.encode({33, vim.NIL, 'text'}))
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', vim.json.decode(ret))
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('diff', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.diff('Hello\n', 'Helli\n'))
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result',
+ {table.concat({
+ '@@ -1 +1 @@',
+ '-Hello',
+ '+Helli',
+ ''
+ }, '\n')}},
+ next_msg())
+ end)
+ end)
+end)
+
+describe('threadpool', function()
+ before_each(clear)
+
+ it('is_thread', function()
+ eq(false, exec_lua [[return vim.is_thread()]])
+
+ exec_lua [[
+ local work_fn = function()
+ return vim.is_thread()
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local work = vim.loop.new_work(work_fn, after_work_fn)
+ work:queue()
+ ]]
+
+ eq({'notification', 'result', {true}}, next_msg())
+ end)
+
+ it('with invalid argument', function()
+ local status = pcall_err(exec_lua, [[
+ local work = vim.loop.new_thread(function() end, function() end)
+ work:queue({})
+ ]])
+
+ eq([[Error executing lua: [string "<nvim>"]:0: Error: thread arg not support type 'function' at 1]],
+ status)
+ end)
+
+ it('with invalid return value', function()
+ local screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {bold = true},
+ })
+
+ exec_lua [[
+ local work = vim.loop.new_work(function() return {} end, function() end)
+ work:queue()
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error in luv thread:} |
+ {3:Error: thread arg not support type 'table' at 1} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ describe('vim.*', function()
+ before_each(function()
+ clear()
+ exec_lua [[
+ Threadpool_Test = {}
+
+ Threadpool_Test.work_fn = function(work_fn_str, args)
+ local decoded_args = vim.mpack.decode(args)
+ return assert(loadstring(work_fn_str))(decoded_args)
+ end
+
+ function Threadpool_Test:do_test()
+ local work =
+ vim.loop.new_work(self.work_fn, self.after_work)
+ work:queue(self.work_fn_str, self.args)
+ end
+
+ Threadpool_Test.new = function(work_fn, after_work, ...)
+ self = {}
+ setmetatable(self, {__index = Threadpool_Test})
+ self.args = vim.mpack.encode({...})
+ self.work_fn_str = string.dump(work_fn)
+ self.after_work = after_work
+ return self
+ end
+ ]]
+ end)
+
+ it('loop', function()
+ exec_lua [[
+ local work_fn = function()
+ return vim.loop.version()
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, ret)
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ local msg = next_msg()
+ eq(msg[1], 'notification')
+ assert(tonumber(msg[2]) >= 72961)
+ end)
+
+ it('mpack', function()
+ exec_lua [[
+ local work_fn = function()
+ local var = vim.mpack.encode({33, vim.NIL, 'text'})
+ return var
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', vim.mpack.decode(ret))
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('json', function()
+ exec_lua [[
+ local work_fn = function()
+ local var = vim.json.encode({33, vim.NIL, 'text'})
+ return var
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', vim.json.decode(ret))
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('work', function()
+ exec_lua [[
+ local work_fn = function()
+ return vim.diff('Hello\n', 'Helli\n')
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ eq({'notification', 'result',
+ {table.concat({
+ '@@ -1 +1 @@',
+ '-Hello',
+ '+Helli',
+ ''
+ }, '\n')}},
+ next_msg())
+ end)
+ end)
+end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 7ec986acdd..5b4daf02ea 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -14,7 +14,7 @@ local feed = helpers.feed
local pcall_err = helpers.pcall_err
local exec_lua = helpers.exec_lua
local matches = helpers.matches
-local source = helpers.source
+local exec = helpers.exec
local NIL = helpers.NIL
local retry = helpers.retry
local next_msg = helpers.next_msg
@@ -23,9 +23,9 @@ local mkdir_p = helpers.mkdir_p
local rmdir = helpers.rmdir
local write_file = helpers.write_file
-before_each(clear)
describe('lua stdlib', function()
+ before_each(clear)
-- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has
-- length 2 (in bytes).
-- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has
@@ -743,7 +743,7 @@ describe('lua stdlib', function()
-- compat: nvim_call_function uses "special" value for vimL float
eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]]))
- source([[
+ exec([[
func! FooFunc(test)
let g:test = a:test
return {}
@@ -771,6 +771,12 @@ describe('lua stdlib', function()
-- error handling
eq({false, 'Vim:E897: List or Blob required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
+
+ -- conversion between LuaRef and Vim Funcref
+ eq(true, exec_lua([[
+ local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end)
+ return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar'
+ ]]))
end)
it('vim.fn should error when calling API function', function()
@@ -993,8 +999,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.g.AddCounter = function() counter = counter + 1 end
- vim.g.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.g.AddCounter = add_counter
+ vim.g.GetCounter = get_counter
+ vim.g.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('g:GetCounter()'))
@@ -1006,11 +1015,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.g.GetCounter()]]))
exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
+ exec_lua([[vim.g.funcs.add()]])
+ eq(5, exec_lua([[return vim.g.funcs.get()]]))
+ exec_lua([[vim.api.nvim_get_var('funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_set_var('AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_set_var('GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_set_var('AddCounter', add_counter)
+ vim.api.nvim_set_var('GetCounter', get_counter)
+ vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('g:GetCounter()'))
@@ -1022,6 +1038,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.g.GetCounter()]]))
exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
+ exec_lua([[vim.g.funcs.add()]])
+ eq(5, exec_lua([[return vim.g.funcs.get()]]))
+ exec_lua([[vim.api.nvim_get_var('funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
-- Check if autoload works properly
local pathsep = helpers.get_pathsep()
@@ -1072,8 +1092,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.b.AddCounter = function() counter = counter + 1 end
- vim.b.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.b.AddCounter = add_counter
+ vim.b.GetCounter = get_counter
+ vim.b.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('b:GetCounter()'))
@@ -1085,11 +1108,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.b.GetCounter()]]))
exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.b.funcs.add()]])
+ eq(5, exec_lua([[return vim.b.funcs.get()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_buf_set_var(0, 'AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_buf_set_var(0, 'GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('b:GetCounter()'))
@@ -1101,6 +1131,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.b.GetCounter()]]))
exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.b.funcs.add()]])
+ eq(5, exec_lua([[return vim.b.funcs.get()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
exec_lua [[
vim.cmd "vnew"
@@ -1141,8 +1175,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.w.AddCounter = function() counter = counter + 1 end
- vim.w.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.w.AddCounter = add_counter
+ vim.w.GetCounter = get_counter
+ vim.w.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('w:GetCounter()'))
@@ -1154,11 +1191,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.w.GetCounter()]]))
exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.w.funcs.add()]])
+ eq(5, exec_lua([[return vim.w.funcs.get()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_win_set_var(0, 'AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_win_set_var(0, 'GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_win_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_win_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('w:GetCounter()'))
@@ -1170,6 +1214,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.w.GetCounter()]]))
exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.w.funcs.add()]])
+ eq(5, exec_lua([[return vim.w.funcs.get()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
exec_lua [[
vim.cmd "vnew"
@@ -1205,8 +1253,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.t.AddCounter = function() counter = counter + 1 end
- vim.t.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.t.AddCounter = add_counter
+ vim.t.GetCounter = get_counter
+ vim.t.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('t:GetCounter()'))
@@ -1218,11 +1269,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.t.GetCounter()]]))
exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.t.funcs.add()]])
+ eq(5, exec_lua([[return vim.t.funcs.get()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_tabpage_set_var(0, 'AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_tabpage_set_var(0, 'GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('t:GetCounter()'))
@@ -1234,6 +1292,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.t.GetCounter()]]))
exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.t.funcs.add()]])
+ eq(5, exec_lua([[return vim.t.funcs.get()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
exec_lua [[
vim.cmd "tabnew"
@@ -2534,9 +2596,39 @@ describe('lua stdlib', function()
end)
end)
+describe('lua: builtin modules', function()
+ local function do_tests()
+ eq(2, exec_lua[[return vim.tbl_count {x=1,y=2}]])
+ eq('{ 10, "spam" }', exec_lua[[return vim.inspect {10, 'spam'}]])
+ end
+
+ it('works', function()
+ clear()
+ do_tests()
+ end)
+
+ it('works when disabled', function()
+ clear('--luamod-dev')
+ do_tests()
+ end)
+
+ it('works without runtime', function()
+ clear{env={VIMRUNTIME='fixtures/a'}}
+ do_tests()
+ end)
+
+
+ it('does not work when disabled without runtime', function()
+ clear{args={'--luamod-dev'}, env={VIMRUNTIME='fixtures/a'}}
+ -- error checking could be better here. just check that --luamod-dev
+ -- does anything at all by breaking with missing runtime..
+ eq(nil, exec_lua[[return vim.tbl_count {x=1,y=2}]])
+ end)
+end)
+
describe('lua: require("mod") from packages', function()
before_each(function()
- command('set rtp+=test/functional/fixtures pp+=test/functional/fixtures')
+ clear('--cmd', 'set rtp+=test/functional/fixtures pp+=test/functional/fixtures')
end)
it('propagates syntax error', function()
@@ -2559,6 +2651,8 @@ describe('lua: require("mod") from packages', function()
end)
describe('vim.keymap', function()
+ before_each(clear)
+
it('can make a mapping', function()
eq(0, exec_lua [[
GlobalCount = 0
diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua
index 2fce0a5ed9..74959a8e76 100644
--- a/test/functional/options/autochdir_spec.lua
+++ b/test/functional/options/autochdir_spec.lua
@@ -1,7 +1,9 @@
+local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
-local getcwd = helpers.funcs.getcwd
+local funcs = helpers.funcs
+local command = helpers.command
describe("'autochdir'", function()
it('given on the shell gets processed properly', function()
@@ -9,11 +11,34 @@ describe("'autochdir'", function()
-- By default 'autochdir' is off, thus getcwd() returns the repo root.
clear(targetdir..'/tty-test.c')
- local rootdir = getcwd()
+ local rootdir = funcs.getcwd()
local expected = rootdir .. '/' .. targetdir
-- With 'autochdir' on, we should get the directory of tty-test.c.
clear('--cmd', 'set autochdir', targetdir..'/tty-test.c')
- eq(helpers.iswin() and expected:gsub('/', '\\') or expected, getcwd())
+ eq(helpers.iswin() and expected:gsub('/', '\\') or expected, funcs.getcwd())
+ end)
+
+ it('is not overwritten by getwinvar() call #17609',function()
+ local curdir = string.gsub(lfs.currentdir(), '\\', '/')
+ local dir_a = curdir..'/Xtest-functional-options-autochdir.dir_a'
+ local dir_b = curdir..'/Xtest-functional-options-autochdir.dir_b'
+ lfs.mkdir(dir_a)
+ lfs.mkdir(dir_b)
+ clear()
+ command('set shellslash')
+ command('set autochdir')
+ command('edit '..dir_a..'/file1')
+ eq(dir_a, funcs.getcwd())
+ command('lcd '..dir_b)
+ eq(dir_b, funcs.getcwd())
+ command('botright vnew ../file2')
+ eq(curdir, funcs.getcwd())
+ command('wincmd w')
+ eq(dir_a, funcs.getcwd())
+ funcs.getwinvar(2, 'foo')
+ eq(dir_a, funcs.getcwd())
+ helpers.rmdir(dir_a)
+ helpers.rmdir(dir_b)
end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 1269a2350c..83d794b620 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -110,6 +110,7 @@ describe('vim.lsp.diagnostic', function()
}
]]
eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp)
+ eq(42, result[1].code)
eq(42, result[2].code)
eq({"foo", "bar"}, result[2].tags)
eq("Hello world", result[2].data)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 4e3eddb960..4985da9cd7 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -207,16 +207,16 @@ describe('incremental synchronization', function()
{
range = {
['start'] = {
- character = 0,
- line = 1
+ character = 11,
+ line = 0,
},
['end'] = {
character = 0,
line = 1
}
},
- rangeLength = 0,
- text = 'hello world\n'
+ rangeLength = 1,
+ text = '\nhello world\n'
}
}
test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n')
@@ -226,19 +226,57 @@ describe('incremental synchronization', function()
{
range = {
['start'] = {
+ character = 11,
+ line = 0
+ },
+ ['end'] = {
character = 0,
line = 1
+ }
+ },
+ rangeLength = 1,
+ text = '\n\n'
+ }
+ }
+ test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('adding a line to an empty buffer', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
},
['end'] = {
character = 0,
line = 1
}
},
+ rangeLength = 1,
+ text = '\n\n'
+ }
+ }
+ test_edit({""}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('insert a line above the current line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
+ },
+ ['end'] = {
+ character = 0,
+ line = 0
+ }
+ },
rangeLength = 0,
text = '\n'
}
}
- test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ test_edit({""}, {"O"}, expected_text_changes, 'utf-16', '\n')
end)
end)
describe('multi line edit', function()
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index a4d78682ad..6f22f865e6 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
-local eq, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
- helpers.eq, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
+local eq, meths, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
+ helpers.eq, helpers.meths, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
helpers.funcs, helpers.feed, helpers.curbuf
local neq = helpers.neq
local read_file = helpers.read_file
@@ -2162,6 +2162,10 @@ describe('plugin/shada.vim', function()
wshada('\004\000\009\147\000\196\002ab\196\001a')
wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
+
+ local bufread_commands = meths.get_autocmds({ group = "ShaDaCommands", event = "BufReadCmd" })
+ eq(2, #bufread_commands--[[, vim.inspect(bufread_commands) ]])
+
-- Need to set nohidden so that the buffer containing 'fname' is not unloaded
-- after loading 'fname_tmp', otherwise the '++opt not supported' test below
-- won't work since the BufReadCmd autocmd won't be triggered.
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 986db96a18..5bdfec574e 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -50,29 +50,33 @@ local function basic_register_test(noblock)
text, stuff and some more
some some text, stuff and some more]])
- -- deleting a word to named ("a) updates "1 (and not "-)
+ -- deleting a word to named ("a) doesn't update "1 or "-
feed('gg"adwj"1P^"-P')
expect([[
, stuff and some more
- some textsome some text, stuff and some more]])
+ some some random text
+ some some text, stuff and some more]])
-- deleting a line does update ""
feed('ggdd""P')
expect([[
, stuff and some more
- some textsome some text, stuff and some more]])
+ some some random text
+ some some text, stuff and some more]])
feed('ggw<c-v>jwyggP')
if noblock then
expect([[
stuf
- me t
+ me s
, stuff and some more
- some textsome some text, stuff and some more]])
+ some some random text
+ some some text, stuff and some more]])
else
expect([[
stuf, stuff and some more
- me tsome textsome some text, stuff and some more]])
+ me ssome some random text
+ some some text, stuff and some more]])
end
-- pasting in visual does unnamed delete of visual selection
diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index 603f4d91b9..d9c44c3315 100644
--- a/test/functional/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -9,6 +9,7 @@ local missing_provider = helpers.missing_provider
local matches = helpers.matches
local pcall_err = helpers.pcall_err
local funcs = helpers.funcs
+local dedent = helpers.dedent
do
clear()
@@ -49,7 +50,12 @@ describe('python3 provider', function()
local very_long_symbol = string.rep('a', 1200)
feed_command(':silent! py3 print('..very_long_symbol..' b)')
-- Error message will contain this (last) line.
- eq('Error invoking \'python_execute\' on channel 3 (python3-script-host):\n File "<string>", line 1\n print('..very_long_symbol..' b)\n '..string.rep(' ',1200)..' ^\nSyntaxError: invalid syntax', eval('v:errmsg'))
+ matches(string.format(dedent([[
+ ^Error invoking 'python_execute' on channel 3 %%(python3%%-script%%-host%%):
+ File "<string>", line 1
+ print%%(%s b%%)
+ %%C*
+ SyntaxError: invalid syntax%%C*$]]), very_long_symbol), eval('v:errmsg'))
end)
it('python3_execute with nested commands', function()
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index beb43e0271..1cef771f0d 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -258,6 +258,7 @@ describe(':terminal buffer', function()
end)
it('it works with set rightleft #11438', function()
+ if helpers.pending_win32(pending) then return end
local columns = eval('&columns')
feed(string.rep('a', columns))
command('set rightleft')
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 7223f5ba61..b5f3c2bd31 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -1,45 +1,94 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local eq = helpers.eq
+local eval = helpers.eval
local command = helpers.command
local pcall_err = helpers.pcall_err
local feed = helpers.feed
-local sleep = helpers.sleep
local poke_eventloop = helpers.poke_eventloop
-describe('associated channel is closed and later freed for terminal', function()
- before_each(clear)
+describe('terminal channel is closed and later released if', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new()
+ screen:attach()
+ end)
it('opened by nvim_open_term() and deleted by :bdelete!', function()
command([[let id = nvim_open_term(0, {})]])
- -- channel hasn't been freed yet
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[bdelete! | call chansend(id, 'test')]]))
- -- channel has been freed after one main loop iteration
- eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
+ local chans = eval('len(nvim_list_chans())')
+ -- channel hasn't been released yet
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[bdelete! | call chansend(id, 'test')]]))
+ -- channel has been released after one main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+
+ it('opened by nvim_open_term(), closed by chanclose(), and deleted by pressing a key', function()
+ command('let id = nvim_open_term(0, {})')
+ local chans = eval('len(nvim_list_chans())')
+ -- channel has been closed but not released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
+ screen:expect({any='%[Terminal closed%]'})
+ eq(chans, eval('len(nvim_list_chans())'))
+ -- delete terminal
+ feed('i<CR>')
+ -- need to first process input
+ poke_eventloop()
+ -- channel has been released after another main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+
+ it('opened by nvim_open_term(), closed by chanclose(), and deleted by :bdelete', function()
+ command('let id = nvim_open_term(0, {})')
+ local chans = eval('len(nvim_list_chans())')
+ -- channel has been closed but not released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
+ screen:expect({any='%[Terminal closed%]'})
+ eq(chans, eval('len(nvim_list_chans())'))
+ -- channel still hasn't been released yet
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
+ -- channel has been released after one main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
end)
it('opened by termopen(), exited, and deleted by pressing a key', function()
command([[let id = termopen('echo')]])
- sleep(500)
- -- process has exited
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[call chansend(id, 'test')]]))
+ local chans = eval('len(nvim_list_chans())')
+ -- wait for process to exit
+ screen:expect({any='%[Process exited 0%]'})
+ -- process has exited but channel has't been released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chansend(id, 'test')]]))
+ eq(chans, eval('len(nvim_list_chans())'))
-- delete terminal
feed('i<CR>')
-- need to first process input
poke_eventloop()
- -- channel has been freed after another main loop iteration
- eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
+ -- channel has been released after another main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
end)
-- This indirectly covers #16264
it('opened by termopen(), exited, and deleted by :bdelete', function()
command([[let id = termopen('echo')]])
- sleep(500)
- -- process has exited
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[call chansend(id, 'test')]]))
- -- channel hasn't been freed yet
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
- -- channel has been freed after one main loop iteration
- eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
+ local chans = eval('len(nvim_list_chans())')
+ -- wait for process to exit
+ screen:expect({any='%[Process exited 0%]'})
+ -- process has exited but channel hasn't been released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chansend(id, 'test')]]))
+ eq(chans, eval('len(nvim_list_chans())'))
+ -- channel still hasn't been released yet
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
+ -- channel has been released after one main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
end)
end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index e9495f45a2..3b905f1f56 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -87,6 +87,7 @@ describe(':terminal cursor', function()
describe('when invisible', function()
it('is not highlighted and is detached from screen cursor', function()
+ if helpers.pending_win32(pending) then return end
hide_cursor()
screen:expect([[
tty ready |
@@ -176,6 +177,7 @@ describe('cursor with customized highlighting', function()
end)
describe('buffer cursor position is correct in terminal without number column', function()
+ if helpers.pending_win32(pending) then return end
local screen
local function setup_ex_register(str)
@@ -526,6 +528,7 @@ describe('buffer cursor position is correct in terminal without number column',
end)
describe('buffer cursor position is correct in terminal with number column', function()
+ if helpers.pending_win32(pending) then return end
local screen
local function setup_ex_register(str)
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index fabc5524ed..e7025d6739 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -36,6 +36,7 @@ describe(':edit term://*', function()
end)
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
+ if helpers.pending_win32(pending) then return end
local columns, lines = 20, 4
local scr = get_screen(columns, lines)
local rep = 97
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 065dd72485..b4f29a586a 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -142,6 +142,7 @@ describe(':terminal (with fake shell)', function()
end
it('with no argument, acts like termopen()', function()
+ if helpers.pending_win32(pending) then return end
terminal_with_fake_shell()
retry(nil, 4 * screen.timeout, function()
screen:expect([[
@@ -165,6 +166,7 @@ describe(':terminal (with fake shell)', function()
end)
it("with no argument, but 'shell' has arguments, acts like termopen()", function()
+ if helpers.pending_win32(pending) then return end
nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
terminal_with_fake_shell()
screen:expect([[
@@ -176,6 +178,7 @@ describe(':terminal (with fake shell)', function()
end)
it('executes a given command through the shell', function()
+ if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
screen:expect([[
@@ -187,6 +190,7 @@ describe(':terminal (with fake shell)', function()
end)
it("executes a given command through the shell, when 'shell' has arguments", function()
+ if helpers.pending_win32(pending) then return end
nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
@@ -199,6 +203,7 @@ describe(':terminal (with fake shell)', function()
end)
it('allows quotes and slashes', function()
+ if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo 'hello' \ "world"]])
screen:expect([[
@@ -235,6 +240,7 @@ describe(':terminal (with fake shell)', function()
end)
it('works with :find', function()
+ if helpers.pending_win32(pending) then return end
terminal_with_fake_shell()
screen:expect([[
^ready $ |
@@ -253,6 +259,7 @@ describe(':terminal (with fake shell)', function()
end)
it('works with gf', function()
+ if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo "scripts/shadacat.py"]])
retry(nil, 4 * screen.timeout, function()
diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua
index d909888613..c5315d0185 100644
--- a/test/functional/terminal/helpers.lua
+++ b/test/functional/terminal/helpers.lua
@@ -94,7 +94,7 @@ local function screen_setup(extra_rows, command, cols, opts)
table.insert(expected, '{3:-- TERMINAL --}' .. ((' '):rep(cols - 14)))
screen:expect(table.concat(expected, '|\n')..'|')
else
- -- This eval also acts as a wait().
+ -- This eval also acts as a poke_eventloop().
if 0 == nvim('eval', "exists('b:terminal_job_id')") then
error("terminal job failed to start")
end
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 8d3f0218af..ab4b4e9147 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -117,6 +117,7 @@ describe(':terminal highlight', function()
end)
it(':terminal highlight has lower precedence than editor #9964', function()
+ if helpers.pending_win32(pending) then return end
clear()
local screen = Screen.new(30, 4)
screen:set_default_attr_ids({
@@ -304,10 +305,17 @@ describe('synIDattr()', function()
eq('79', eval('synIDattr(hlID("Keyword"), "fg")'))
end)
- it('returns "1" if group has "strikethrough" attribute', function()
- eq('', eval('synIDattr(hlID("Normal"), "strikethrough")'))
- eq('1', eval('synIDattr(hlID("Keyword"), "strikethrough")'))
- eq('1', eval('synIDattr(hlID("Keyword"), "strikethrough", "gui")'))
+ it('returns "1" if group has given highlight attribute', function()
+ local hl_attrs = {
+ 'underline', 'underlineline', 'undercurl', 'underdot', 'underdash', 'strikethrough'
+ }
+ for _,hl_attr in ipairs(hl_attrs) do
+ local context = 'using ' .. hl_attr .. ' attr'
+ command('highlight Keyword cterm=' .. hl_attr .. ' gui=' .. hl_attr)
+ eq('', eval('synIDattr(hlID("Normal"), "'.. hl_attr .. '")'), context)
+ eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '")'), context)
+ eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '", "gui")'), context)
+ end
end)
end)
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 11bdc73a47..d1cfc7e91b 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -345,6 +345,7 @@ end)
describe(':terminal prints more lines than the screen height and exits', function()
it('will push extra lines to scrollback', function()
+ if helpers.pending_win32(pending) then return end
clear()
local screen = Screen.new(30, 7)
screen:attach({rgb=false})
@@ -576,6 +577,7 @@ describe("pending scrollback line handling", function()
end)
it("does not crash after nvim_buf_call #14891", function()
+ if helpers.pending_win32(pending) then return end
exec_lua [[
local a = vim.api
local bufnr = a.nvim_create_buf(false, true)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index faf44fa01d..c37cde06ab 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -323,7 +323,7 @@ describe('TUI', function()
feed_data('just paste it™')
feed_data('\027[201~')
screen:expect{grid=[[
- thisjust paste it™{1:3} is here |
+ thisjust paste it{1:™}3 is here |
|
{4:~ }|
{4:~ }|
@@ -379,7 +379,7 @@ describe('TUI', function()
end)
it('paste: normal-mode (+CRLF #10872)', function()
- feed_data(':set ruler')
+ feed_data(':set ruler | echo')
wait_for_mode('c')
feed_data('\n')
wait_for_mode('n')
@@ -423,13 +423,13 @@ describe('TUI', function()
expect_child_buf_lines(expected_crlf)
feed_data('u')
expect_child_buf_lines({''})
+ feed_data(':echo')
+ wait_for_mode('c')
+ feed_data('\n')
+ wait_for_mode('n')
-- CRLF input
feed_data('\027[200~'..table.concat(expected_lf,'\r\n')..'\027[201~')
- screen:expect{
- grid=expected_grid1:gsub(
- ':set ruler *',
- '3 fewer lines; before #1 0 seconds ago '),
- attr_ids=expected_attr}
+ screen:expect{grid=expected_grid1, attr_ids=expected_attr}
expect_child_buf_lines(expected_crlf)
end)
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index 9f278fd157..0d3295cf32 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -18,6 +18,7 @@ describe(':terminal window', function()
end)
it('sets topline correctly #8556', function()
+ if helpers.pending_win32(pending) then return end
-- Test has hardcoded assumptions of dimensions.
eq(7, eval('&lines'))
feed_data('\n\n\n') -- Add blank lines.
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 9c746b99bd..384761ab17 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -33,7 +33,7 @@ before_each(function()
let g:NUM_LVLS = 4
function Redraw()
mode
- return ''
+ return "\<Ignore>"
endfunction
let g:id = ''
cnoremap <expr> {REDRAW} Redraw()
@@ -42,7 +42,7 @@ before_each(function()
let Cb = g:Nvim_color_input{g:id}
let out = input({'prompt': ':', 'highlight': Cb})
let g:out{id} = out
- return (a:do_return ? out : '')
+ return (a:do_return ? out : "\<Ignore>")
endfunction
nnoremap <expr> {PROMPT} DoPrompt(0)
cnoremap <expr> {PROMPT} DoPrompt(1)
@@ -410,7 +410,7 @@ describe('Command-line coloring', function()
end)
it('stops executing callback after a number of errors', function()
set_color_cb('SplittedMultibyteStart')
- start_prompt('let x = "«»«»«»«»«»"\n')
+ start_prompt('let x = "«»«»«»«»«»"')
screen:expect([[
{EOB:~ }|
{EOB:~ }|
@@ -419,7 +419,7 @@ describe('Command-line coloring', function()
:let x = " |
{ERR:E5405: Chunk 0 start 10 splits multibyte}|
{ERR: character} |
- ^:let x = "«»«»«»«»«»" |
+ :let x = "«»«»«»«»«»"^ |
]])
feed('\n')
screen:expect([[
@@ -432,6 +432,7 @@ describe('Command-line coloring', function()
{EOB:~ }|
|
]])
+ feed('\n')
eq('let x = "«»«»«»«»«»"', meths.get_var('out'))
local msg = '\nE5405: Chunk 0 start 10 splits multibyte character'
eq(msg:rep(1), funcs.execute('messages'))
@@ -474,14 +475,14 @@ describe('Command-line coloring', function()
]])
feed('\n')
screen:expect([[
- |
+ ^ |
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
- ^:echo 42 |
+ :echo 42 |
]])
feed('\n')
eq('echo 42', meths.get_var('out'))
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 03cd4bfd06..4c51547e2c 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -212,10 +212,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end
end
if m.hl_id then
- m.hl_id = 60
+ m.hl_id = 61
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 61 end
+ if m.id_lm then m.id_lm = 62 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 1575cab591..7e71ada02d 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1362,3 +1362,372 @@ if (h->n_buckets < new_n_buckets) { // expand
end)
end)
+
+describe('decorations: signs', function()
+ local screen, ns
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {foreground = Screen.colors.Blue4, background = Screen.colors.Grey};
+ [2] = {foreground = Screen.colors.Blue1, bold = true};
+ [3] = {background = Screen.colors.Yellow1, foreground = Screen.colors.Blue1};
+ }
+
+ ns = meths.create_namespace 'test'
+ meths.win_set_option(0, 'signcolumn', 'auto:9')
+ end)
+
+ local example_text = [[
+l1
+l2
+l3
+l4
+l5
+]]
+
+ it('can add a single sign (no end row)', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S'})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add a single sign (with end row)', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row=1})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add multiple signs (single extmark)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row = 2})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S l2 |
+ S l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add multiple signs (multiple extmarks)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+ insert(example_text)
+ feed'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 3, -1, {sign_text='S2', end_row = 4})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S1l2 |
+ {1: }l3 |
+ S2l4 |
+ S2l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add multiple signs (multiple extmarks) 2', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S2S1l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ -- TODO(lewis6991): Support ranged signs
+ -- meths.buf_set_extmark(1, ns, 1, -1, {sign_text='S3', end_row = 2})
+
+ -- screen:expect{grid=[[
+ -- {1: }^l1 |
+ -- S3S2S1l2 |
+ -- S3{1: }l3 |
+ -- {1: }l4 |
+ -- {1: }l5 |
+ -- {1: } |
+ -- {2:~ }|
+ -- {2:~ }|
+ -- {2:~ }|
+ -- |
+ -- ]]}
+
+ end)
+
+ it('can add multiple signs (multiple extmarks) 3', function()
+ pending('TODO(lewis6991): Support ranged signs')
+
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1', end_row=2})
+ meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S2', end_row=3})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S1{1: }l2 |
+ S2S1l3 |
+ S2{1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('can add multiple signs (multiple extmarks) 4', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=0})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row=1})
+
+ screen:expect{grid=[[
+ S1^l1 |
+ S2l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with old signs', function()
+ insert(example_text)
+ feed 'gg'
+
+ helpers.command('sign define Oldsign text=x')
+ helpers.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
+
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
+ meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
+
+ screen:expect{grid=[[
+ S4S1^l1 |
+ S2x l2 |
+ S5{1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with old signs (with range)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+ insert(example_text)
+ feed 'gg'
+
+ helpers.command('sign define Oldsign text=x')
+ helpers.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
+
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S3', end_row = 4})
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
+ meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
+
+ screen:expect{grid=[[
+ S3S4S1^l1 |
+ S2S3x l2 |
+ S5S3{1: }l3 |
+ S3{1: }l4 |
+ S3{1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('can add a ranged sign (with start out of view)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+
+ insert(example_text)
+ command 'set signcolumn=yes:2'
+ feed 'gg'
+ feed '2<C-e>'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='X', end_row=3})
+
+ screen:expect{grid=[[
+ X {1: }^l3 |
+ X {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add lots of signs', function()
+ screen:try_resize(40, 10)
+ command 'normal 10oa b c d e f g h'
+
+ for i = 1, 10 do
+ meths.buf_set_extmark(0, ns, i, 0, { end_col = 1, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 2, { end_col = 3, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 4, { end_col = 5, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 6, { end_col = 7, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 8, { end_col = 9, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 10, { end_col = 11, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 12, { end_col = 13, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 14, { end_col = 15, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='W' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='X' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='Y' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='Z' })
+ end
+
+ screen:expect{grid=[[
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:^h} |
+ |
+ ]]}
+ end)
+
+end)
+
+describe('decorations: virt_text', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {foreground = Screen.colors.Brown};
+ [2] = {foreground = Screen.colors.Fuchsia};
+ [3] = {bold = true, foreground = Screen.colors.Blue1};
+ }
+ end)
+
+ it('avoids regression in #17638', function()
+ exec_lua[[
+ vim.wo.number = true
+ vim.wo.relativenumber = true
+ ]]
+
+ command 'normal 4ohello'
+ command 'normal aVIRTUAL'
+
+ local ns = meths.create_namespace('test')
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_text = {{"hello", "String"}},
+ virt_text_win_col = 20,
+ })
+
+ screen:expect{grid=[[
+ {1: 4 } |
+ {1: 3 }hello |
+ {1: 2 }hello {2:hello} |
+ {1: 1 }hello |
+ {1:5 }helloVIRTUA^L |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+
+ -- Trigger a screen update
+ feed('k')
+
+ screen:expect{grid=[[
+ {1: 3 } |
+ {1: 2 }hello |
+ {1: 1 }hello {2:hello} |
+ {1:4 }hell^o |
+ {1: 1 }helloVIRTUAL |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ end)
+
+end)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index bd2692d19a..3a25d7e813 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -6,7 +6,7 @@ local clear = helpers.clear
local command = helpers.command
local insert = helpers.insert
local write_file = helpers.write_file
-local source = helpers.source
+local exec = helpers.exec
describe('Diff mode screen', function()
local fname = 'Xtest-functional-diff-screen-1'
@@ -1075,10 +1075,8 @@ it('diff updates line numbers below filler lines', function()
[9] = {background = Screen.colors.LightMagenta},
[10] = {bold = true, foreground = Screen.colors.Brown},
[11] = {foreground = Screen.colors.Brown},
- [12] = {foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red};
- [13] = {background = Screen.colors.Gray90};
})
- source([[
+ exec([[
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
vnew
call setline(1, ['a', 'a', 'a', 'x', 'x', 'x', 'b', 'b', 'b', 'b', 'b'])
@@ -1135,24 +1133,6 @@ it('diff updates line numbers below filler lines', function()
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
- command("set signcolumn number tgc cursorline cursorlineopt=number,line")
- command("hi CursorLineNr guibg=red")
- screen:expect{grid=[[
- {1: }a {3:│}{11: 2 }a |
- {1: }a {3:│}{11: 1 }a |
- {1: }a {3:│}{12:3 }{13:^a }|
- {1: }{8:x}{9: }{3:│}{11: 1 }{8:y}{9: }|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }b {3:│}{11: 2 }b |
- {1: }b {3:│}{11: 3 }b |
- {1: }b {3:│}{11: 4 }b |
- {1: }b {3:│}{11: 5 }b |
- {1: }b {3:│}{11: 6 }b |
- {6:~ }{3:│}{6:~ }|
- {3:[No Name] [+] }{7:[No Name] [+] }|
- signcolumn=auto |
- ]]}
end)
it('Align the filler lines when changing text in diff mode', function()
@@ -1169,7 +1149,7 @@ it('Align the filler lines when changing text in diff mode', function()
[7] = {foreground = Screen.colors.Blue1, bold = true};
[8] = {reverse = true, bold = true};
})
- source([[
+ exec([[
call setline(1, range(1, 15))
vnew
call setline(1, range(9, 15))
diff --git a/test/functional/ui/global_statusline_spec.lua b/test/functional/ui/global_statusline_spec.lua
new file mode 100644
index 0000000000..6b37e5e2f1
--- /dev/null
+++ b/test/functional/ui/global_statusline_spec.lua
@@ -0,0 +1,233 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, command, feed = helpers.clear, helpers.command, helpers.feed
+
+describe('global statusline', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 16)
+ screen:attach()
+ command('set laststatus=3')
+ command('set ruler')
+ end)
+
+ it('works', function()
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {bold = true, reverse = true};
+ }}
+
+ feed('i<CR><CR>')
+ screen:expect{grid=[[
+ |
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] 3,1 All}|
+ {3:-- INSERT --} |
+ ]], attr_ids={
+ [1] = {bold = true, foreground = Screen.colors.Blue};
+ [2] = {bold = true, reverse = true};
+ [3] = {bold = true};
+ }}
+ end)
+
+ it('works with splits', function()
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:────────────────────┴────────────────┴─┤}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {bold = true, foreground = Screen.colors.Blue1};
+ [3] = {bold = true, reverse = true};
+ }}
+ end)
+
+ it('works when switching between values of laststatus', function()
+ command('set laststatus=1')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ 0,0-1 All |
+ ]], attr_ids={
+ [1] = {foreground = Screen.colors.Blue, bold = true};
+ }}
+
+ command('set laststatus=3')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {foreground = Screen.colors.Blue, bold = true};
+ [2] = {reverse = true, bold = true};
+ }}
+
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ command('set laststatus=2')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│< Name] 0,0-1 │}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{3:<No Name] 0,0-1 All}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:<No Name] 0,0-1 All < Name] 0,0-1 <│}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {1:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+
+ command('set laststatus=3')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:────────────────────┴────────────────┴─┤}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+
+ command('set laststatus=0')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│< Name] 0,0-1 │}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{3:<No Name] 0,0-1 All}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:<No Name] 0,0-1 All < Name] 0,0-1 <│}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ 0,0-1 All |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+
+ command('set laststatus=3')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:────────────────────┴────────────────┴─┤}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+ end)
+end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 12643eec1e..64f0ba3419 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -840,7 +840,7 @@ describe("'listchars' highlight", function()
end)
end)
-describe('CursorLine highlight', function()
+describe('CursorLine and CursorLineNr highlights', function()
before_each(clear)
it('overridden by Error, ColorColumn if fg not set', function()
@@ -1081,7 +1081,7 @@ describe('CursorLine highlight', function()
]])
end)
- it('with split-windows in diff-mode', function()
+ it('with split windows in diff mode', function()
local screen = Screen.new(50,12)
screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
@@ -1093,7 +1093,6 @@ describe('CursorLine highlight', function()
[7] = {background = Screen.colors.Red, foreground = Screen.colors.White},
[8] = {bold = true, foreground = Screen.colors.Blue1},
[9] = {bold = true, reverse = true},
- [10] = {bold = true},
})
screen:attach()
@@ -1170,6 +1169,61 @@ describe('CursorLine highlight', function()
background = Screen.colors.Red},
})
end)
+
+ it('CursorLineNr shows correctly just below filler lines', function()
+ local screen = Screen.new(50,12)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [2] = {background = Screen.colors.LightCyan1, bold = true, foreground = Screen.colors.Blue1},
+ [3] = {reverse = true},
+ [4] = {background = Screen.colors.LightBlue},
+ [5] = {background = Screen.colors.Red, foreground = Screen.colors.White},
+ [6] = {background = Screen.colors.White, bold = true, foreground = Screen.colors.Black},
+ [7] = {bold = true, foreground = Screen.colors.Blue1},
+ [8] = {bold = true, reverse = true},
+ [9] = {foreground = Screen.colors.Brown},
+ })
+ screen:attach()
+
+ command('hi CursorLine guibg=red guifg=white')
+ command('hi CursorLineNr guibg=white guifg=black gui=bold')
+ command('set cursorline number')
+ command('call setline(1, ["baz", "foo", "foo", "bar"])')
+ feed('2gg0')
+ command('vnew')
+ command('call setline(1, ["foo", "foo", "bar"])')
+ command('windo diffthis')
+ command('1wincmd w')
+ screen:expect([[
+ {1: }{9: }{2:-------------------}{3:│}{1: }{9: 1 }{4:baz }|
+ {1: }{6: 1 }{5:^foo }{3:│}{1: }{6: 2 }{5:foo }|
+ {1: }{9: 2 }foo {3:│}{1: }{9: 3 }foo |
+ {1: }{9: 3 }bar {3:│}{1: }{9: 4 }bar |
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ command('set cursorlineopt=number')
+ screen:expect([[
+ {1: }{9: }{2:-------------------}{3:│}{1: }{9: 1 }{4:baz }|
+ {1: }{6: 1 }^foo {3:│}{1: }{6: 2 }{5:foo }|
+ {1: }{9: 2 }foo {3:│}{1: }{9: 3 }foo |
+ {1: }{9: 3 }bar {3:│}{1: }{9: 4 }bar |
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ end)
end)
describe('ColorColumn highlight', function()
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index 2a567b28ee..dcea2c76dd 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -59,7 +59,7 @@ describe('ext_hlstate detailed highlights', function()
it('work with cleared UI highlights', function()
screen:set_default_attr_ids({
- [1] = {{}, {{hi_name = "VertSplit", ui_name = "VertSplit", kind = "ui"}}},
+ [1] = {{}, {{hi_name = "VertSplit", ui_name = "WinSeparator", kind = "ui"}}},
[2] = {{bold = true, foreground = Screen.colors.Blue1},
{{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
[3] = {{bold = true, reverse = true},
@@ -179,6 +179,8 @@ describe('ext_hlstate detailed highlights', function()
end)
it("work with :terminal", function()
+ if helpers.pending_win32(pending) then return end
+
screen:set_default_attr_ids({
[1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}},
[2] = {{foreground = tonumber('0x00ccff'), fg_indexed=true}, {{kind = "term"}}},
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index f038348253..949591870a 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1206,6 +1206,7 @@ end)
describe('ui/msg_puts_printf', function()
it('output multibyte characters correctly', function()
+ if helpers.pending_win32(pending) then return end
local screen
local cmd = ''
local locale_dir = test_build_dir..'/share/locale/ja/LC_MESSAGES'
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 50e5dfac84..7305baa761 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -14,6 +14,7 @@ local has_powershell = helpers.has_powershell
local set_shell_powershell = helpers.set_shell_powershell
describe("shell command :!", function()
+ if helpers.pending_win32(pending) then return end
local screen
before_each(function()
clear()
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index c44e59cfd3..d521e3cd25 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -2324,7 +2324,7 @@ describe('builtin popupmenu', function()
it('is closed by :stopinsert from timer #12976', function()
screen:try_resize(32,14)
command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]])
- feed('Gah<C-N>')
+ feed('Gah<c-x><c-n>')
screen:expect([[
hello |
hullo |
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 61f19c3794..3e94fdbf44 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -576,16 +576,16 @@ to the test if they make sense.
print([[
warning: Screen changes were received after the expected state. This indicates
-indeterminism in the test. Try adding screen:expect(...) (or wait()) between
-asynchronous (feed(), nvim_input()) and synchronous API calls.
+indeterminism in the test. Try adding screen:expect(...) (or poke_eventloop())
+between asynchronous (feed(), nvim_input()) and synchronous API calls.
- Use screen:redraw_debug() to investigate; it may find relevant intermediate
states that should be added to the test to make it more robust.
- If the purpose of the test is to assert state after some user input sent
with feed(), adding screen:expect() before the feed() will help to ensure
the input is sent when Nvim is in a predictable state. This is preferable
- to wait(), for being closer to real user interaction.
- - wait() can trigger redraws and consequently generate more indeterminism.
- Try removing wait().
+ to poke_eventloop(), for being closer to real user interaction.
+ - poke_eventloop() can trigger redraws and thus generate more indeterminism.
+ Try removing poke_eventloop().
]])
did_warn = true
end
@@ -1559,10 +1559,11 @@ end
function Screen:_equal_attrs(a, b)
return a.bold == b.bold and a.standout == b.standout and
- a.underline == b.underline and a.undercurl == b.undercurl and
- a.italic == b.italic and a.reverse == b.reverse and
- a.foreground == b.foreground and a.background == b.background and
- a.special == b.special and a.blend == b.blend and
+ a.underline == b.underline and a.underlineline == b.underlineline and
+ a.undercurl == b.undercurl and a.underdot == b.underdot and
+ a.underdash == b.underdash and a.italic == b.italic and
+ a.reverse == b.reverse and a.foreground == b.foreground and
+ a.background == b.background and a.special == b.special and a.blend == b.blend and
a.strikethrough == b.strikethrough and
a.fg_indexed == b.fg_indexed and a.bg_indexed == b.bg_indexed
end
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index a0b7c98c51..dbc92ca222 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -446,7 +446,7 @@ describe('Signs', function()
{1:>>>>>>>>}{6: 1 }a |
{2: }{6: 2 }b |
{2: }{6: 3 }c |
- {2: }{6:^ 4 } |
+ {2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -468,7 +468,7 @@ describe('Signs', function()
{1:>>>>>>>>>>}{6: 1 }a |
{2: }{6: 2 }b |
{2: }{6: 3 }c |
- {2: ^ }{6: 4 } |
+ {2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -482,7 +482,7 @@ describe('Signs', function()
]])
end)
- it('ignores signs with no icon and text when calculting the signcolumn width', function()
+ it('ignores signs with no icon and text when calculating the signcolumn width', function()
feed('ia<cr>b<cr>c<cr><esc>')
command('set number')
command('set signcolumn=auto:2')
@@ -512,7 +512,7 @@ describe('Signs', function()
{1:>>}{6: 1 }a |
{2: }{6: 2 }b |
{2: }{6: 3 }c |
- {2: }{6: ^4 } |
+ {2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
{0:~ }|
diff --git a/test/helpers.lua b/test/helpers.lua
index 333e98d495..7d2f8f760a 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -58,9 +58,9 @@ local check_logs_useless_lines = {
--- Invokes `fn` and includes the tail of `logfile` in the error message if it
--- fails.
---
----@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog'
----@param fn Function to invoke
----@param ... Function arguments
+---@param logfile string Log file, defaults to $NVIM_LOG_FILE or '.nvimlog'
+---@param fn string Function to invoke
+---@param ... string Function arguments
local function dumplog(logfile, fn, ...)
-- module.validate({
-- logfile={logfile,'s',true},
@@ -102,8 +102,8 @@ end
--- Asserts that `pat` matches one or more lines in the tail of $NVIM_LOG_FILE.
---
----@param pat (string) Lua pattern to search for in the log file.
----@param logfile (string, default=$NVIM_LOG_FILE) full path to log file.
+---@param pat string Lua pattern to search for in the log file
+---@param logfile string Full path to log file (default=$NVIM_LOG_FILE)
function module.assert_log(pat, logfile)
logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
local nrlines = 10
diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua
index e54c82b26a..e085ac749d 100644
--- a/test/unit/strings_spec.lua
+++ b/test/unit/strings_spec.lua
@@ -138,3 +138,15 @@ describe('vim_strchr()', function()
eq(nil, vim_strchr('«\237\175\191\237\188\128»', 0x10FF00))
end)
end)
+
+describe('strcase_save()' , function()
+ local strcase_save = function(input_string, upper)
+ local res = strings.strcase_save(to_cstr(input_string), upper)
+ return ffi.string(res)
+ end
+
+ itp('decodes overlong encoded characters.', function()
+ eq("A", strcase_save("\xc1\x81", true))
+ eq("a", strcase_save("\xc1\x81", false))
+ end)
+end)
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index 8342044b5e..51a703b593 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -48,6 +48,7 @@ local predefined_hl_defs = {
TermCursor=true,
VertSplit=true,
WildMenu=true,
+ WinSeparator=true,
EndOfBuffer=true,
QuickFixLine=true,
Substitute=true,