aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/api/command_spec.lua135
-rw-r--r--test/functional/api/extmark_spec.lua71
-rw-r--r--test/functional/api/keymap_spec.lua223
-rw-r--r--test/functional/api/vim_spec.lua48
-rw-r--r--test/functional/autocmd/recording_spec.lua28
-rw-r--r--test/functional/core/channels_spec.lua32
-rw-r--r--test/functional/core/startup_spec.lua23
-rw-r--r--test/functional/editor/K_spec.lua23
-rw-r--r--test/functional/editor/meta_key_spec.lua33
-rw-r--r--test/functional/editor/mode_insert_spec.lua60
-rw-r--r--test/functional/editor/mode_visual_spec.lua27
-rw-r--r--test/functional/editor/put_spec.lua16
-rw-r--r--test/functional/ex_cmds/append_spec.lua70
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua15
-rw-r--r--test/functional/ex_cmds/script_spec.lua2
-rw-r--r--test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua1
-rw-r--r--test/functional/helpers.lua1
-rw-r--r--test/functional/legacy/listchars_spec.lua81
-rw-r--r--test/functional/legacy/memory_usage_spec.lua4
-rw-r--r--test/functional/legacy/options_spec.lua5
-rw-r--r--test/functional/legacy/visual_mode_spec.lua44
-rw-r--r--test/functional/lua/api_spec.lua13
-rw-r--r--test/functional/lua/commands_spec.lua18
-rw-r--r--test/functional/lua/diagnostic_spec.lua29
-rw-r--r--test/functional/lua/filetype_spec.lua98
-rw-r--r--test/functional/lua/luaeval_spec.lua1
-rw-r--r--test/functional/lua/spell_spec.lua53
-rw-r--r--test/functional/lua/uri_spec.lua8
-rw-r--r--test/functional/lua/vim_spec.lua244
-rw-r--r--test/functional/plugin/lsp_spec.lua186
-rw-r--r--test/functional/provider/python3_spec.lua43
-rw-r--r--test/functional/provider/python_spec.lua123
-rw-r--r--test/functional/terminal/buffer_spec.lua7
-rw-r--r--test/functional/terminal/mouse_spec.lua122
-rw-r--r--test/functional/terminal/tui_spec.lua36
-rw-r--r--test/functional/treesitter/parser_spec.lua36
-rw-r--r--test/functional/ui/bufhl_spec.lua18
-rw-r--r--test/functional/ui/input_spec.lua21
-rw-r--r--test/functional/ui/popupmenu_spec.lua278
-rw-r--r--test/functional/ui/screen_basic_spec.lua58
-rw-r--r--test/functional/vimscript/eval_spec.lua2
-rw-r--r--test/functional/vimscript/functions_spec.lua2
42 files changed, 2020 insertions, 318 deletions
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index 6f929ad1ca..d64d324a88 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -6,12 +6,18 @@ local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq = helpers.eq
local meths = helpers.meths
+local bufmeths = helpers.bufmeths
+local matches = helpers.matches
local source = helpers.source
local pcall_err = helpers.pcall_err
+local exec_lua = helpers.exec_lua
+local assert_alive = helpers.assert_alive
+local feed = helpers.feed
+local funcs = helpers.funcs
describe('nvim_get_commands', function()
- local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, script_id=0, }
- local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', range=NIL, register=false, script_id=0, }
+ local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, keepscript=false, script_id=0, }
+ local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', range=NIL, register=false, keepscript=false, script_id=0, }
before_each(clear)
it('gets empty list if no commands were defined', function()
@@ -53,11 +59,11 @@ describe('nvim_get_commands', function()
end)
it('gets various command attributes', function()
- local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, script_id=0, }
- local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, script_id=1, }
- local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, script_id=2, }
- local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, script_id=3, }
- local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, script_id=4, }
+ local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, keepscript=false, script_id=0, }
+ local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, keepscript=false, script_id=1, }
+ local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, keepscript=false, script_id=2, }
+ local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, keepscript=false, script_id=3, }
+ local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, keepscript=false, script_id=4, }
source([[
command -complete=custom,ListUsers -nargs=+ Finger !finger <args>
]])
@@ -78,3 +84,118 @@ describe('nvim_get_commands', function()
eq({Cmd2=cmd2, Cmd3=cmd3, Cmd4=cmd4, Finger=cmd1, TestCmd=cmd0}, meths.get_commands({builtin=false}))
end)
end)
+
+describe('nvim_add_user_command', function()
+ before_each(clear)
+
+ it('works with strings', function()
+ meths.add_user_command('SomeCommand', 'let g:command_fired = <args>', {nargs = 1})
+ meths.command('SomeCommand 42')
+ eq(42, meths.eval('g:command_fired'))
+ end)
+
+ it('works with Lua functions', function()
+ exec_lua [[
+ result = {}
+ vim.api.nvim_add_user_command('CommandWithLuaCallback', function(opts)
+ result = opts
+ end, {
+ nargs = "*",
+ bang = true,
+ count = 2,
+ })
+ ]]
+
+ eq({
+ args = "hello",
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithLuaCallback hello')
+ return result
+ ]])
+
+ eq({
+ args = "",
+ bang = true,
+ line1 = 10,
+ line2 = 10,
+ mods = "botright",
+ range = 1,
+ count = 10,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('botright 10CommandWithLuaCallback!')
+ return result
+ ]])
+
+ eq({
+ args = "",
+ bang = false,
+ line1 = 1,
+ line2 = 42,
+ mods = "",
+ range = 1,
+ count = 42,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithLuaCallback 42')
+ return result
+ ]])
+ end)
+
+ it('can define buffer-local commands', function()
+ local bufnr = meths.create_buf(false, false)
+ bufmeths.add_user_command(bufnr, "Hello", "", {})
+ matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
+ meths.set_current_buf(bufnr)
+ meths.command("Hello")
+ assert_alive()
+ end)
+
+ it('can use a Lua complete function', function()
+ exec_lua [[
+ vim.api.nvim_add_user_command('Test', '', {
+ nargs = "*",
+ complete = function(arg, cmdline, pos)
+ local options = {"aaa", "bbb", "ccc"}
+ local t = {}
+ for _, v in ipairs(options) do
+ if string.find(v, "^" .. arg) then
+ table.insert(t, v)
+ end
+ end
+ return t
+ end,
+ })
+ ]]
+
+ feed(':Test a<Tab>')
+ eq('Test aaa', funcs.getcmdline())
+ feed('<C-U>Test b<Tab>')
+ eq('Test bbb', funcs.getcmdline())
+ end)
+end)
+
+describe('nvim_del_user_command', function()
+ before_each(clear)
+
+ it('can delete global commands', function()
+ meths.add_user_command('Hello', 'echo "Hi"', {})
+ meths.command('Hello')
+ meths.del_user_command('Hello')
+ matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
+ end)
+
+ it('can delete buffer-local commands', function()
+ bufmeths.add_user_command(0, 'Hello', 'echo "Hi"', {})
+ meths.command('Hello')
+ bufmeths.del_user_command(0, 'Hello')
+ matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
+ end)
+end)
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index a8f538b951..3f96efd4ef 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -110,6 +110,22 @@ describe('API/extmarks', function()
pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 }))
end)
+ it("can end extranges past final newline when strict mode is false", function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 1,
+ end_row = 1,
+ strict = false,
+ })
+ end)
+
+ it("can end extranges past final column when strict mode is false", function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 6,
+ end_row = 0,
+ strict = false,
+ })
+ end)
+
it('adds, updates and deletes marks', function()
local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2])
eq(marks[1], rv)
@@ -1430,7 +1446,60 @@ describe('API/extmarks', function()
end_col = 0,
end_line = 1
})
- eq({ {1, 0, 0, { end_col = 0, end_row = 1 }} }, get_extmarks(ns, 0, -1, {details=true}))
+ eq({ {1, 0, 0, {
+ end_col = 0,
+ end_row = 1,
+ right_gravity = true,
+ end_right_gravity = false,
+ }} }, get_extmarks(ns, 0, -1, {details=true}))
+ end)
+
+ it('can get details', function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 0,
+ end_row = 1,
+ right_gravity = false,
+ end_right_gravity = true,
+ priority = 0,
+ hl_eol = true,
+ hl_mode = "blend",
+ hl_group = "String",
+ virt_text = { { "text", "Statement" } },
+ virt_text_pos = "right_align",
+ virt_text_hide = true,
+ virt_lines = { { { "lines", "Statement" } }},
+ virt_lines_above = true,
+ virt_lines_leftcol = true,
+ })
+ set_extmark(ns, marks[2], 0, 0, {
+ priority = 0,
+ virt_text = { { "text", "Statement" } },
+ virt_text_win_col = 1,
+ })
+ eq({0, 0, {
+ end_col = 0,
+ end_row = 1,
+ right_gravity = false,
+ end_right_gravity = true,
+ priority = 0,
+ hl_eol = true,
+ hl_mode = "blend",
+ hl_group = "String",
+ virt_text = { { "text", "Statement" } },
+ virt_text_pos = "right_align",
+ virt_text_hide = true,
+ virt_lines = { { { "lines", "Statement" } }},
+ virt_lines_above = true,
+ virt_lines_leftcol = true,
+ } }, get_extmark_by_id(ns, marks[1], { details = true }))
+ eq({0, 0, {
+ right_gravity = true,
+ priority = 0,
+ virt_text = { { "text", "Statement" } },
+ virt_text_hide = false,
+ virt_text_pos = "win_col",
+ virt_text_win_col = 1,
+ } }, get_extmark_by_id(ns, marks[2], { details = true }))
end)
end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index dd8eef7ca0..450a76ddac 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -5,6 +5,7 @@ local clear = helpers.clear
local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq, neq = helpers.eq, helpers.neq
+local exec_lua = helpers.exec_lua
local feed = helpers.feed
local funcs = helpers.funcs
local meths = helpers.meths
@@ -316,6 +317,55 @@ describe('nvim_get_keymap', function()
command('nnoremap \\|<Char-0x20><Char-32><Space><Bar> \\|<Char-0x20><Char-32><Space> <Bar>')
eq({space_table}, meths.get_keymap('n'))
end)
+
+ it('can handle lua keymaps', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+ eq(1, exec_lua[[return GlobalCount]])
+
+ eq(2, exec_lua[[
+ vim.api.nvim_get_keymap('n')[1].callback()
+ return GlobalCount
+ ]])
+ local mapargs = meths.get_keymap('n')
+ assert.Truthy(type(mapargs[1].callback) == 'number', 'callback is not luaref number')
+ mapargs[1].callback = nil
+ eq({
+ lhs='asdf',
+ script=0,
+ silent=0,
+ expr=0,
+ sid=0,
+ buffer=0,
+ nowait=0,
+ mode='n',
+ noremap=0,
+ lnum=0,
+ }, mapargs[1])
+ end)
+
+ it ('can handle map descriptions', function()
+ meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
+ eq({
+ lhs='lhs',
+ rhs='rhs',
+ script=0,
+ silent=0,
+ expr=0,
+ sid=0,
+ buffer=0,
+ nowait=0,
+ mode='n',
+ noremap=0,
+ lnum=0,
+ desc='map description'
+ }, meths.get_keymap('n')[1])
+ end)
end)
describe('nvim_set_keymap, nvim_del_keymap', function()
@@ -353,6 +403,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.sid = not opts.sid and 0 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
return to_return
end
@@ -717,6 +768,115 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end)
end
end
+
+ it('can make lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ end)
+
+ it (':map command shows lua keymap correctly', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+ ]]
+ assert.truthy(string.match(exec_lua[[return vim.api.nvim_exec(':nmap asdf', true)]],
+ "^\nn asdf <Lua function %d+>"))
+ end)
+
+ it ('mapcheck() returns lua keymap correctly', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+ ]]
+ assert.truthy(string.match(funcs.mapcheck('asdf', 'n'),
+ "^<Lua function %d+>"))
+ end)
+
+ it ('maparg() returns lua keymap correctly', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+ ]]
+ assert.truthy(string.match(funcs.maparg('asdf', 'n'),
+ "^<Lua function %d+>"))
+ 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)
+ end)
+
+ it('can make lua expr mappings', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'aa', '', {callback = function() return vim.api.nvim_replace_termcodes(':lua SomeValue = 99<cr>', true, false, true) end, expr = true })
+ ]]
+
+ feed('aa')
+
+ eq(99, exec_lua[[return SomeValue]])
+ end)
+
+ it('does not reset pum in lua mapping', function()
+ eq(0, exec_lua [[
+ VisibleCount = 0
+ vim.api.nvim_set_keymap ('i', '<F2>', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end})
+ return VisibleCount
+ ]])
+ feed('i<C-X><C-V><F2><F2><esc>')
+ eq(2, exec_lua[[return VisibleCount]])
+ end)
+
+ it('can overwrite lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
+ ]]
+
+ feed('asdf\n')
+
+ eq(0, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can unmap lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_del_keymap('n', 'asdf' )
+ ]]
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
+ end)
+
+ it('can set descriptions on keymaps', function()
+ meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
+ eq(generate_mapargs('n', 'lhs', 'rhs', {desc="map description"}), get_mapargs('n', 'lhs'))
+ eq("\nn lhs rhs\n map description",
+ helpers.exec_capture("nmap lhs"))
+ end)
end)
describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
@@ -814,4 +974,67 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
helpers.assert_alive()
end)
+
+ it('can make lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can make lua expr mappings', function()
+ exec_lua [[
+ vim.api.nvim_buf_set_keymap (0, 'n', 'aa', '', {callback = function() return vim.api.nvim_replace_termcodes(':lua SomeValue = 99<cr>', true, false, true) end, expr = true })
+ ]]
+
+ feed('aa')
+
+ eq(99, exec_lua[[return SomeValue ]])
+ end)
+
+ it('can overwrite lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
+ ]]
+
+ feed('asdf\n')
+
+ eq(0, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can unmap lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_buf_del_keymap(0, 'n', 'asdf' )
+ ]]
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
+ end)
end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 112adfaf2d..201ba45803 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1154,8 +1154,8 @@ describe('API', function()
end)
end)
- describe('RPC (K_EVENT) #6166', function()
- it('does not complete ("interrupt") normal-mode operator-pending', function()
+ describe('RPC (K_EVENT)', function()
+ it('does not complete ("interrupt") normal-mode operator-pending #6166', function()
helpers.insert([[
FIRST LINE
SECOND LINE]])
@@ -1191,7 +1191,7 @@ describe('API', function()
]])
end)
- it('does not complete ("interrupt") normal-mode map-pending', function()
+ it('does not complete ("interrupt") normal-mode map-pending #6166', function()
command("nnoremap dd :let g:foo='it worked...'<CR>")
helpers.insert([[
FIRST LINE
@@ -1207,7 +1207,8 @@ describe('API', function()
SECOND LINE]])
eq('it worked...', helpers.eval('g:foo'))
end)
- it('does not complete ("interrupt") insert-mode map-pending', function()
+
+ it('does not complete ("interrupt") insert-mode map-pending #6166', function()
command('inoremap xx foo')
command('set timeoutlen=9999')
helpers.insert([[
@@ -1222,6 +1223,37 @@ describe('API', function()
FIRST LINE
SECOND LINfooE]])
end)
+
+ it('does not interrupt Insert mode i_CTRL-O #10035', function()
+ feed('iHello World<c-o>')
+ eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
+ feed('dd')
+ eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
+ expect('') -- executed the command
+ end)
+
+ it('does not interrupt Select mode v_CTRL-O #15688', function()
+ feed('iHello World<esc>gh<c-o>')
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
+ feed('^')
+ eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode
+ feed('h')
+ eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode
+ expect('h') -- selection is the whole line and is replaced
+ end)
+
+ it('does not interrupt Insert mode i_0_CTRL-D #13997', function()
+ command('set timeoutlen=9999')
+ feed('i<Tab><Tab>a0')
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ feed('<C-D>')
+ expect('a') -- recognized i_0_CTRL-D
+ end)
end)
describe('nvim_get_context', function()
@@ -1335,18 +1367,18 @@ describe('API', function()
end)
describe('nvim_feedkeys', function()
- it('CSI escaping', function()
+ it('K_SPECIAL escaping', function()
local function on_setup()
-- notice the special char(…) \xe2\80\xa6
nvim('feedkeys', ':let x1="…"\n', '', true)
-- Both nvim_replace_termcodes and nvim_feedkeys escape \x80
local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true)
- nvim('feedkeys', inp, '', true) -- escape_csi=true
+ nvim('feedkeys', inp, '', true) -- escape_ks=true
- -- nvim_feedkeys with CSI escaping disabled
+ -- nvim_feedkeys with K_SPECIAL escaping disabled
inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true)
- nvim('feedkeys', inp, '', false) -- escape_csi=false
+ nvim('feedkeys', inp, '', false) -- escape_ks=false
helpers.stop()
end
diff --git a/test/functional/autocmd/recording_spec.lua b/test/functional/autocmd/recording_spec.lua
index 81152758de..b9aec774f1 100644
--- a/test/functional/autocmd/recording_spec.lua
+++ b/test/functional/autocmd/recording_spec.lua
@@ -11,7 +11,7 @@ describe('RecordingEnter', function()
source_vim [[
let g:recorded = 0
autocmd RecordingEnter * let g:recorded += 1
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq(1, eval('g:recorded'))
end)
@@ -20,7 +20,7 @@ describe('RecordingEnter', function()
source_vim [[
let g:recording = ''
autocmd RecordingEnter * let g:recording = reg_recording()
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq('q', eval('g:recording'))
end)
@@ -32,7 +32,7 @@ describe('RecordingLeave', function()
source_vim [[
let g:recorded = 0
autocmd RecordingLeave * let g:recorded += 1
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq(1, eval('g:recorded'))
end)
@@ -43,10 +43,30 @@ describe('RecordingLeave', function()
let g:recording = ''
autocmd RecordingLeave * let g:recording = reg_recording()
autocmd RecordingLeave * let g:recorded = reg_recorded()
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq('q', eval 'g:recording')
eq('', eval 'g:recorded')
eq('q', eval 'reg_recorded()')
end)
+
+ it('populates v:event', function()
+ source_vim [[
+ let g:regname = ''
+ let g:regcontents = ''
+ autocmd RecordingLeave * let g:regname = v:event.regname
+ autocmd RecordingLeave * let g:regcontents = v:event.regcontents
+ call feedkeys("qqyyq", 'xt')
+ ]]
+ eq('q', eval 'g:regname')
+ eq('yy', eval 'g:regcontents')
+ end)
+
+ it('resets v:event', function()
+ source_vim [[
+ autocmd RecordingLeave * let g:event = v:event
+ call feedkeys("qqyyq", 'xt')
+ ]]
+ eq(0, eval 'len(v:event)')
+ end)
end)
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index 93dec9fb35..c28300f0f4 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -100,6 +100,38 @@ describe('channels', function()
eq({"notification", "exit", {3,0}}, next_msg())
end)
+ it('can use stdio channel and on_print callback', function()
+ source([[
+ let g:job_opts = {
+ \ 'on_stdout': function('OnEvent'),
+ \ 'on_stderr': function('OnEvent'),
+ \ 'on_exit': function('OnEvent'),
+ \ }
+ ]])
+ meths.set_var("nvim_prog", nvim_prog)
+ meths.set_var("code", [[
+ function! OnStdin(id, data, event) dict
+ echo string([a:id, a:data, a:event])
+ if a:data == ['']
+ quit
+ endif
+ endfunction
+ function! OnPrint(text) dict
+ call chansend(g:x, ['OnPrint:' .. a:text])
+ endfunction
+ let g:x = stdioopen({'on_stdin': funcref('OnStdin'), 'on_print':'OnPrint'})
+ call chansend(x, "hello")
+ ]])
+ command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
+ local id = eval("g:id")
+ ok(id > 0)
+
+ eq({ "notification", "stdout", {id, { "hello" } } }, next_msg())
+
+ command("call chansend(id, 'howdy')")
+ eq({"notification", "stdout", {id, {"OnPrint:[1, ['howdy'], 'stdin']"}}}, next_msg())
+ end)
+
local function expect_twoline(id, stream, line1, line2, nobr)
local msg = next_msg()
local joined = nobr and {line1..line2} or {line1, line2}
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 4220d68ee1..2fa84e8313 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -224,6 +224,23 @@ describe('startup', function()
end
end)
+ it('-e sets ex mode', function()
+ local screen = Screen.new(25, 3)
+ clear('-e')
+ screen:attach()
+ -- Verify we set the proper mode both before and after :vi.
+ feed("put =mode(1)<CR>vi<CR>:put =mode(1)<CR>")
+ screen:expect([[
+ cv |
+ ^n |
+ :put =mode(1) |
+ ]])
+
+ eq('cv\n',
+ funcs.system({nvim_prog, '-n', '-es' },
+ { 'put =mode(1)', 'print', '' }))
+ end)
+
it('fails on --embed with -es/-Es', function()
matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es',
funcs.system({nvim_prog, '--embed', '-es' }))
@@ -651,11 +668,7 @@ describe('runtime:', function()
mkdir_p(ftdetect_folder)
write_file(ftdetect_file , [[vim.g.lua_ftdetect = 1]])
- -- TODO(shadmansaleh): Figure out why this test fails without
- -- setting VIMRUNTIME
- clear{ args_rm={'-u'}, env={XDG_CONFIG_HOME=xconfig,
- XDG_DATA_HOME=xdata,
- VIMRUNTIME='runtime/'}}
+ clear{ args_rm={'-u'}, env=xenv }
eq(1, eval('g:lua_ftdetect'))
rmdir(ftdetect_folder)
diff --git a/test/functional/editor/K_spec.lua b/test/functional/editor/K_spec.lua
index 40f36491e4..8ad81ac3d6 100644
--- a/test/functional/editor/K_spec.lua
+++ b/test/functional/editor/K_spec.lua
@@ -33,6 +33,29 @@ describe('K', function()
feed('i'..test_file..'<ESC>K')
retry(nil, nil, function() eq(1, eval('filereadable("'..test_file..'")')) end)
eq({'fnord'}, eval("readfile('"..test_file.."')"))
+ -- Confirm that Neovim is still in terminal mode after K is pressed (#16692).
+ helpers.sleep(500)
+ eq('t', eval('mode()'))
+ feed('<space>') -- Any key, not just <space>, can be used here to escape.
+ eq('n', eval('mode()'))
+ end)
+
+ it("<esc> kills the buffer for a running 'keywordprg' command", function()
+ helpers.source('set keywordprg=less')
+ eval('writefile(["hello", "world"], "' .. test_file .. '")')
+ feed('i' .. test_file .. '<esc>K')
+ eq('t', eval('mode()'))
+ -- Confirm that an arbitrary keypress doesn't escape (i.e., the process is
+ -- still running). If the process were no longer running, an arbitrary
+ -- keypress would escape.
+ helpers.sleep(500)
+ feed('<space>')
+ eq('t', eval('mode()'))
+ -- Confirm that <esc> kills the buffer for the running command.
+ local bufnr = eval('bufnr()')
+ feed('<esc>')
+ eq('n', eval('mode()'))
+ helpers.neq(bufnr, eval('bufnr()'))
end)
end)
diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua
index 2280f5bb24..8efcc81616 100644
--- a/test/functional/editor/meta_key_spec.lua
+++ b/test/functional/editor/meta_key_spec.lua
@@ -27,6 +27,14 @@ describe('meta-keys #8226 #13042', function()
command('nnoremap <A-j> Aalt-j<Esc>')
feed('<A-j><M-l>')
expect('llo<ESC>;<ESC>;alt-jmeta-l')
+ -- Unmapped ALT-chord with characters containing K_SPECIAL bytes
+ command('nnoremap … A…<Esc>')
+ feed('<A-…><M-…>')
+ expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…')
+ command("execute 'nnoremap' nr2char(0x40000000) 'AMAX<Esc>'")
+ command("call nvim_input('<A-'.nr2char(0x40000000).'>')")
+ command("call nvim_input('<M-'.nr2char(0x40000000).'>')")
+ expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX')
end)
it('ALT/META, visual-mode', function()
@@ -36,13 +44,20 @@ describe('meta-keys #8226 #13042', function()
expect('peach')
-- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869
command('vnoremap <ESC> A<lt>ESC>')
- feed('viw<A-;><ESC>viw<M-;><ESC>')
+ feed('viw<A-;><Esc>viw<M-;><Esc>')
expect('peach<ESC>;<ESC>;')
-- Mapped ALT-chord behaves as mapped.
command('vnoremap <M-l> Ameta-l<Esc>')
command('vnoremap <A-j> Aalt-j<Esc>')
feed('viw<A-j>viw<M-l>')
expect('peach<ESC>;<ESC>;alt-jmeta-l')
+ -- Unmapped ALT-chord with characters containing K_SPECIAL bytes
+ feed('viw<A-…><Esc>viw<M-…><Esc>')
+ expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…')
+ command("execute 'inoremap' nr2char(0x40000000) 'MAX'")
+ command("call nvim_input('viw<A-'.nr2char(0x40000000).'><Esc>')")
+ command("call nvim_input('viw<M-'.nr2char(0x40000000).'><Esc>')")
+ expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX')
end)
it('ALT/META insert-mode', function()
@@ -89,4 +104,20 @@ describe('meta-keys #8226 #13042', function()
eq({ 0, 2, 1, 0, }, funcs.getpos('.'))
eq('nt', eval('mode(1)'))
end)
+
+ it('ALT/META when recording a macro #13235', function()
+ feed('ifoo<CR>bar<CR>baz<Esc>gg0')
+ -- <M-"> is reinterpreted as <Esc>"
+ feed('qrviw"ayC// This is some text: <M-">apq')
+ expect([[
+ // This is some text: foo
+ bar
+ baz]])
+ -- Should not insert an extra double quote when replaying
+ feed('j0@rj0@@')
+ expect([[
+ // This is some text: foo
+ // This is some text: bar
+ // This is some text: baz]])
+ end)
end)
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index 46ab483036..528e228121 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -6,7 +6,6 @@ local expect = helpers.expect
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
-local meths = helpers.meths
describe('insert-mode', function()
before_each(function()
@@ -75,15 +74,58 @@ describe('insert-mode', function()
feed('ooo')
expect('hello oooworld')
end)
+ end)
+
+ describe('Ctrl-V', function()
+ it('supports entering the decimal value of a character', function()
+ feed('i<C-V>076<C-V>167')
+ expect('L§')
+ end)
+
+ it('supports entering the octal value of a character with "o"', function()
+ feed('i<C-V>o114<C-V>o247<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the octal value of a character with "O"', function()
+ feed('i<C-V>O114<C-V>O247<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "x"', function()
+ feed('i<C-V>x4c<C-V>xA7<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "X"', function()
+ feed('i<C-V>X4c<C-V>XA7<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "u"', function()
+ feed('i<C-V>u25ba<C-V>u25C7<Esc>')
+ expect('►◇')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "U"', function()
+ feed('i<C-V>U0001f600<C-V>U0001F601<Esc>')
+ expect('😀😁')
+ end)
+
+ it('entering character by value is interrupted by invalid character', function()
+ feed('i<C-V>76c<C-V>76<C-F2><C-V>u3c0j<C-V>u3c0<M-F3><C-V>U1f600j<C-V>U1f600<D-F4><Esc>')
+ expect('LcL<C-F2>πjπ<M-F3>😀j😀<D-F4>')
+ end)
- it("doesn't cancel Ctrl-O mode when processing event", function()
- feed('iHello World<c-o>')
- eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('dd')
- eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- expect('') -- executed the command
+ it('shows o, O, u, U, x, X, and digits with modifiers', function()
+ feed('i<C-V><M-o><C-V><D-o><C-V><M-O><C-V><D-O><Esc>')
+ expect('<M-o><D-o><M-O><D-O>')
+ feed('cc<C-V><M-u><C-V><D-u><C-V><M-U><C-V><D-U><Esc>')
+ expect('<M-u><D-u><M-U><D-U>')
+ feed('cc<C-V><M-x><C-V><D-x><C-V><M-X><C-V><D-X><Esc>')
+ expect('<M-x><D-x><M-X><D-X>')
+ feed('cc<C-V><M-1><C-V><D-2><C-V><M-7><C-V><D-8><Esc>')
+ expect('<M-1><D-2><M-7><D-8>')
end)
end)
end)
diff --git a/test/functional/editor/mode_visual_spec.lua b/test/functional/editor/mode_visual_spec.lua
deleted file mode 100644
index 468ae00e01..0000000000
--- a/test/functional/editor/mode_visual_spec.lua
+++ /dev/null
@@ -1,27 +0,0 @@
--- Visual-mode tests.
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear = helpers.clear
-local eq = helpers.eq
-local eval = helpers.eval
-local expect = helpers.expect
-local feed = helpers.feed
-local meths = helpers.meths
-
-describe('visual-mode', function()
- before_each(clear)
-
- it("select-mode Ctrl-O doesn't cancel Ctrl-O mode when processing event #15688", function()
- feed('iHello World<esc>gh<c-o>')
- eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event
- eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('^')
- eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- feed('h')
- eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode
- expect('h') -- selection is the whole line and is replaced
- end)
-end)
-
diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua
index 26967ecbba..fdda2be131 100644
--- a/test/functional/editor/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
@@ -64,7 +64,7 @@ describe('put command', function()
-- one place to the right (unless we were at the end of the
-- line when we pasted).
if not (exception_table.undo_position and after_undo) then
- eq(funcs.getcurpos(), init_cursorpos)
+ eq(init_cursorpos, funcs.getcurpos())
end
end
@@ -86,7 +86,7 @@ describe('put command', function()
-- If we paste the ". register with a count we can't avoid
-- changing this register, hence avoid this check.
if not test.exception_table.dot_reg_changed then
- eq(funcs.getreg('.'), orig_dotstr)
+ eq(orig_dotstr, funcs.getreg('.'))
end
-- Doing something, undoing it, and then redoing it should
@@ -507,9 +507,9 @@ describe('put command', function()
return function(exception_table, after_redo)
test_expect(exception_table, after_redo)
if selection_string then
- eq(getreg('"'), selection_string)
+ eq(selection_string, getreg('"'))
else
- eq(getreg('"'), 'test_string"')
+ eq('test_string"', getreg('"'))
end
end
end
@@ -714,7 +714,7 @@ describe('put command', function()
expect_base, conversion_table)
return function(exception_table, after_redo)
test_expect(exception_table, after_redo)
- eq(getreg('"'), 'Line of words 1\n')
+ eq('Line of words 1\n', getreg('"'))
end
end
local base_expect_string = [[
@@ -748,7 +748,7 @@ describe('put command', function()
end, expect_base, conversion_table)
return function(e,c)
test_expect(e,c)
- eq(getreg('"'), 'Lin\nLin')
+ eq('Lin\nLin', getreg('"'))
end
end
@@ -800,9 +800,9 @@ describe('put command', function()
feed('u')
-- Have to use feed('u') here to set curswant, because
-- ex_undo() doesn't do that.
- eq(funcs.getcurpos(), {0, 1, 1, 0, 1})
+ eq({0, 1, 1, 0, 1}, funcs.getcurpos())
feed('<C-r>')
- eq(funcs.getcurpos(), {0, 1, 1, 0, 1})
+ eq({0, 1, 1, 0, 1}, funcs.getcurpos())
end
end
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index 0a4d701794..fadb5c9b42 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -1,23 +1,26 @@
local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
+local dedent = helpers.dedent
+local exec = helpers.exec
local feed = helpers.feed
local clear = helpers.clear
local funcs = helpers.funcs
local command = helpers.command
local curbufmeths = helpers.curbufmeths
-
-before_each(function()
- clear()
- curbufmeths.set_lines(0, 1, true, { 'foo', 'bar', 'baz' })
-end)
-
-local buffer_contents = function()
- return curbufmeths.get_lines(0, -1, false)
-end
+local Screen = require('test.functional.ui.screen')
local cmdtest = function(cmd, prep, ret1)
describe(':' .. cmd, function()
+ before_each(function()
+ clear()
+ curbufmeths.set_lines(0, 1, true, { 'foo', 'bar', 'baz' })
+ end)
+
+ local buffer_contents = function()
+ return curbufmeths.get_lines(0, -1, false)
+ end
+
it(cmd .. 's' .. prep .. ' the current line by default', function()
command(cmd .. '\nabc\ndef\n')
eq(ret1, buffer_contents())
@@ -52,3 +55,52 @@ end
cmdtest('insert', ' before', { 'abc', 'def', 'foo', 'bar', 'baz' })
cmdtest('append', ' after', { 'foo', 'abc', 'def', 'bar', 'baz' })
cmdtest('change', '', { 'abc', 'def', 'bar', 'baz' })
+
+describe('the first line is redrawn correctly after inserting text in an empty buffer', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(20, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true, reverse = true},
+ })
+ screen:attach()
+ end)
+
+ it('using :append', function()
+ exec(dedent([[
+ append
+ aaaaa
+ bbbbb
+ .]]))
+ screen:expect([[
+ aaaaa |
+ ^bbbbb |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('using :insert', function()
+ exec(dedent([[
+ insert
+ aaaaa
+ bbbbb
+ .]]))
+ screen:expect([[
+ aaaaa |
+ ^bbbbb |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index 09eaa36686..aefcc53cab 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -5,6 +5,7 @@ local clear = helpers.clear
local command = helpers.command
local get_pathsep = helpers.get_pathsep
local eq = helpers.eq
+local neq = helpers.neq
local funcs = helpers.funcs
local matches = helpers.matches
local pesc = helpers.pesc
@@ -30,7 +31,8 @@ describe(':mksession', function()
-- If the same :terminal is displayed in multiple windows, :mksession
-- should restore it as such.
- -- Create two windows showing the same :terminal buffer.
+ -- Create three windows: first two from top show same terminal, third -
+ -- another one (created earlier).
command('terminal')
command('split')
command('terminal')
@@ -43,8 +45,8 @@ describe(':mksession', function()
-- Restore session.
command('source '..session_file)
- eq({2,2,4},
- {funcs.winbufnr(1), funcs.winbufnr(2), funcs.winbufnr(3)})
+ eq(funcs.winbufnr(1), funcs.winbufnr(2))
+ neq(funcs.winbufnr(1), funcs.winbufnr(3))
end)
it('restores tab-local working directories', function()
@@ -91,12 +93,7 @@ describe(':mksession', function()
command('tabnext 1')
eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '1', funcs.expand('%:p'))
command('tabnext 2')
- -- :mksession stores paths using unix slashes, but Nvim doesn't adjust these
- -- for absolute paths in all cases yet. Absolute paths are used in the
- -- session file after :tcd, so we need to expect unix slashes here for now
- -- eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p'))
- eq(cwd_dir:gsub([[\]], '/') .. '/' .. tmpfile_base .. '2',
- funcs.expand('%:p'))
+ eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p'))
end)
it('restores CWD for :terminal buffers #11288', function()
diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua
index 0a772c559b..f249b9ba7c 100644
--- a/test/functional/ex_cmds/script_spec.lua
+++ b/test/functional/ex_cmds/script_spec.lua
@@ -62,10 +62,10 @@ describe('script_get-based command', function()
-- Provider-based scripts
test_garbage_exec('ruby', not missing_provider('ruby'))
- test_garbage_exec('python', not missing_provider('python'))
test_garbage_exec('python3', not missing_provider('python3'))
-- Missing scripts
+ test_garbage_exec('python', false)
test_garbage_exec('tcl', false)
test_garbage_exec('mzscheme', false)
test_garbage_exec('perl', false)
diff --git a/test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua b/test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua
new file mode 100644
index 0000000000..c1c33d787e
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua
@@ -0,0 +1 @@
+return {doit=function() return 9004 end}
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index f152a487af..1845786c4b 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -451,6 +451,7 @@ function module.new_argv(...)
'GCOV_ERROR_FILE',
'XDG_DATA_DIRS',
'TMPDIR',
+ 'VIMRUNTIME',
}) do
if not env_tbl[k] then
env_tbl[k] = os.getenv(k)
diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua
index dc6ccd3628..7a1afa1fd6 100644
--- a/test/functional/legacy/listchars_spec.lua
+++ b/test/functional/legacy/listchars_spec.lua
@@ -1,7 +1,8 @@
-- Tests for 'listchars' display with 'list' and :list.
local helpers = require('test.functional.helpers')(after_each)
-local feed, insert, source = helpers.feed, helpers.insert, helpers.source
+local Screen = require('test.functional.ui.screen')
+local feed, insert, exec = helpers.feed, helpers.insert, helpers.exec
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
-- luacheck: ignore 621 (Indentation)
@@ -13,7 +14,7 @@ describe("'listchars'", function()
-- luacheck: ignore 613 (Trailing whitespace in a string)
it("works with 'list'", function()
- source([[
+ exec([[
function GetScreenCharsForLine(lnum)
return join(map(range(1, virtcol('$')), 'nr2char(screenchar(a:lnum, v:val))'), '')
endfunction
@@ -98,4 +99,80 @@ describe("'listchars'", function()
.....h>-$
iii<<<<><<$]])
end)
+
+ it('"exceeds" character does not appear in foldcolumn vim-patch:8.2.3121', function()
+ local screen = Screen.new(60, 10)
+ screen:attach()
+ exec([[
+ call setline(1, ['aaa', '', 'a', 'aaaaaa'])
+ vsplit
+ vsplit
+ windo set signcolumn=yes foldcolumn=1 winminwidth=0 nowrap list listchars=extends:>,precedes:<
+ ]])
+ feed('13<C-W>>')
+ screen:expect([[
+ aaa │ a>│ ^aaa |
+ │ │ |
+ a │ a │ a |
+ aaaaaa │ a>│ aaaaaa |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ [No Name] [+] <[+] [No Name] [+] |
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ aaa │ >│ ^aaa |
+ │ │ |
+ a │ a│ a |
+ aaaaaa │ >│ aaaaaa |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ [No Name] [+] <+] [No Name] [+] |
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ aaa │ │ ^aaa |
+ │ │ |
+ a │ │ a |
+ aaaaaa │ │ aaaaaa |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ [No Name] [+] <] [No Name] [+] |
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ aaa │ │ ^aaa |
+ │ │ |
+ a │ │ a |
+ aaaaaa │ │ aaaaaa |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ ~ │~ │~ |
+ [No Name] [+] < [No Name] [+] |
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ aaa │ │ ^aaa |
+ │ │ |
+ a │ │ a |
+ aaaaaa │ │ aaaaaa |
+ ~ │~│~ |
+ ~ │~│~ |
+ ~ │~│~ |
+ ~ │~│~ |
+ [No Name] [+] < [No Name] [+] |
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index d86caca0e9..8d25b9d927 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -195,10 +195,10 @@ describe('memory usage', function()
local after = monitor_memory_usage(pid)
source('bwipe!')
poke_eventloop()
- -- Allow for an increase of 5% in memory usage, which accommodates minor fluctuation,
+ -- Allow for an increase of 10% in memory usage, which accommodates minor fluctuation,
-- but is small enough that if memory were not released (prior to PR #14884), the test
-- would fail.
- local upper = before.last * 1.05
+ local upper = before.last * 1.10
check_result({before=before, after=after}, pcall(ok, after.last <= upper))
end)
end)
diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua
index 023cdd4ae1..bd14f3bc53 100644
--- a/test/functional/legacy/options_spec.lua
+++ b/test/functional/legacy/options_spec.lua
@@ -83,4 +83,9 @@ describe('set', function()
Press ENTER or type command to continue^ |
]])
end)
+
+ it('foldcolumn and signcolumn to empty string is disallowed', function()
+ matches('E474: Invalid argument: fdc=', exc_exec('set fdc='))
+ matches('E474: Invalid argument: scl=', exc_exec('set scl='))
+ end)
end)
diff --git a/test/functional/legacy/visual_mode_spec.lua b/test/functional/legacy/visual_mode_spec.lua
index c8e83ed649..8b5dd0c2dc 100644
--- a/test/functional/legacy/visual_mode_spec.lua
+++ b/test/functional/legacy/visual_mode_spec.lua
@@ -1,5 +1,3 @@
--- Test visual line mode selection redraw after scrolling
-
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
@@ -10,6 +8,7 @@ local feed_command = helpers.feed_command
local funcs = helpers.funcs
local meths = helpers.meths
local eq = helpers.eq
+local exec = helpers.exec
describe('visual line mode', function()
local screen
@@ -40,3 +39,44 @@ describe('visual line mode', function()
]])
end)
end)
+
+describe('visual block mode', function()
+ it('shows selection correctly with virtualedit=block', function()
+ clear()
+ local screen = Screen.new(30, 7)
+ screen:set_default_attr_ids({
+ [1] = {bold = true}, -- ModeMsg
+ [2] = {background = Screen.colors.LightGrey}, -- Visual
+ [3] = {foreground = Screen.colors.Blue, bold = true} -- NonText
+ })
+ screen:attach()
+
+ exec([[
+ call setline(1, ['aaaaaa', 'bbbb', 'cc'])
+ set virtualedit=block
+ normal G
+ ]])
+
+ feed('<C-V>gg$')
+ screen:expect([[
+ {2:aaaaaa}^ |
+ {2:bbbb } |
+ {2:cc } |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL BLOCK --} |
+ ]])
+
+ feed('<Esc>gg<C-V>G$')
+ screen:expect([[
+ {2:aaaaaa } |
+ {2:bbbb } |
+ {2:cc}^ {2: } |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL BLOCK --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index 81e00bba6d..cb37fb9a1c 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -8,6 +8,7 @@ local clear = helpers.clear
local eval = helpers.eval
local NIL = helpers.NIL
local eq = helpers.eq
+local exec_lua = helpers.exec_lua
before_each(clear)
@@ -111,6 +112,12 @@ describe('luaeval(vim.api.…)', function()
eq(7, eval([[type(luaeval('vim.api.nvim__id(nil)'))]]))
eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api.nvim__id({foo=1, bar={42, {{baz=true}, 5}}})'))
+
+ eq(true, funcs.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)'))
+ eq(42, exec_lua [[
+ local f = vim.api.nvim__id({42, vim.api.nvim__id})
+ return f[2](f[1])
+ ]])
end)
it('correctly converts container objects with type_idx to API objects', function()
@@ -159,12 +166,8 @@ describe('luaeval(vim.api.…)', function()
it('errors out correctly when working with API', function()
-- Conversion errors
- eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
- remove_trace(exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]])))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table',
remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]])))
- eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
- remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]])))
-- Errors in number of arguments
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument',
remove_trace(exc_exec([[call luaeval("vim.api.nvim__id()")]])))
@@ -180,6 +183,8 @@ describe('luaeval(vim.api.…)', function()
remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]])))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral',
remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]])))
+ eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected Lua number',
+ remove_trace(exc_exec([[call luaeval("vim.api.nvim_win_is_valid(nil)")]])))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]])))
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index 9b9ba531b0..b8346df290 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -141,6 +141,24 @@ describe(':lua command', function()
{4:Press ENTER or type command to continue}^ |
]]}
end)
+
+ it('Can print results of =expr', function()
+ helpers.exec_lua("x = 5")
+ eq("5", helpers.exec_capture(':lua =x'))
+ helpers.exec_lua("function x() return 'hello' end")
+ eq([["hello"]], helpers.exec_capture(':lua = x()'))
+ helpers.exec_lua("x = {a = 1, b = 2}")
+ eq("{\n a = 1,\n b = 2\n}", helpers.exec_capture(':lua =x'))
+ helpers.exec_lua([[function x(success)
+ if success then
+ return true, "Return value"
+ else
+ return false, nil, "Error message"
+ end
+ end]])
+ eq([[true "Return value"]], helpers.exec_capture(':lua =x(true)'))
+ eq([[false nil "Error message"]], helpers.exec_capture(':lua =x(false)'))
+ end)
end)
describe(':luado command', function()
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index a88da63e90..b58fad1cab 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -208,10 +208,10 @@ describe('vim.diagnostic', function()
eq(all_highlights, exec_lua [[
local ns_1_diags = {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 3),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ make_warning("Warning 1", 2, 1, 2, 3),
}
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
@@ -255,10 +255,10 @@ describe('vim.diagnostic', function()
eq({0, 2}, exec_lua [[
local ns_1_diags = {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 3),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ make_warning("Warning 1", 2, 1, 2, 3),
}
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
@@ -599,10 +599,10 @@ describe('vim.diagnostic', function()
eq(all_highlights, exec_lua [[
local ns_1_diags = {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 3),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ make_warning("Warning 1", 2, 1, 2, 3),
}
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
@@ -787,7 +787,7 @@ describe('vim.diagnostic', function()
eq(2, exec_lua [[
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 3),
})
return #vim.diagnostic.get(diagnostic_bufnr)
@@ -798,9 +798,9 @@ describe('vim.diagnostic', function()
eq({2, 3, 2}, exec_lua [[
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 5),
- make_info("Ignored information", 1, 1, 2, 5),
- make_hint("Here's a hint", 1, 1, 2, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 3),
+ make_info("Ignored information", 1, 1, 2, 3),
+ make_hint("Here's a hint", 1, 1, 2, 3),
})
return {
@@ -820,8 +820,8 @@ describe('vim.diagnostic', function()
eq(1, exec_lua [[
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 5),
- make_info("Ignored information", 1, 1, 2, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 3),
+ make_info("Ignored information", 1, 1, 2, 3),
make_error("Error On Other Line", 2, 1, 1, 5),
})
@@ -1119,6 +1119,11 @@ describe('vim.diagnostic', function()
end)
describe('set()', function()
+ it('validates its arguments', function()
+ matches("expected a list of diagnostics",
+ pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]]))
+ end)
+
it('can perform updates after insert_leave', function()
exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
nvim("input", "o")
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
new file mode 100644
index 0000000000..729ebc601b
--- /dev/null
+++ b/test/functional/lua/filetype_spec.lua
@@ -0,0 +1,98 @@
+local helpers = require('test.functional.helpers')(after_each)
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local clear = helpers.clear
+local pathroot = helpers.pathroot
+
+local root = pathroot()
+
+describe('vim.filetype', function()
+ before_each(function()
+ clear()
+
+ exec_lua [[
+ local bufnr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(bufnr)
+ ]]
+ end)
+
+ it('works with extensions', function()
+ eq('radicalscript', exec_lua [[
+ vim.filetype.add({
+ extension = {
+ rs = 'radicalscript',
+ },
+ })
+ vim.filetype.match('main.rs')
+ return vim.bo.filetype
+ ]])
+ end)
+
+ it('prioritizes filenames over extensions', function()
+ eq('somethingelse', exec_lua [[
+ vim.filetype.add({
+ extension = {
+ rs = 'radicalscript',
+ },
+ filename = {
+ ['main.rs'] = 'somethingelse',
+ },
+ })
+ vim.filetype.match('main.rs')
+ return vim.bo.filetype
+ ]])
+ end)
+
+ it('works with filenames', function()
+ eq('nim', exec_lua [[
+ vim.filetype.add({
+ filename = {
+ ['s_O_m_e_F_i_l_e'] = 'nim',
+ },
+ })
+ vim.filetype.match('s_O_m_e_F_i_l_e')
+ return vim.bo.filetype
+ ]])
+
+ eq('dosini', exec_lua([[
+ local root = ...
+ vim.filetype.add({
+ filename = {
+ ['config'] = 'toml',
+ [root .. '/.config/fun/config'] = 'dosini',
+ },
+ })
+ vim.filetype.match(root .. '/.config/fun/config')
+ return vim.bo.filetype
+ ]], root))
+ end)
+
+ it('works with patterns', function()
+ eq('markdown', exec_lua([[
+ local root = ...
+ vim.filetype.add({
+ pattern = {
+ ['~/blog/.*%.txt'] = 'markdown',
+ }
+ })
+ vim.filetype.match('~/blog/why_neovim_is_awesome.txt')
+ return vim.bo.filetype
+ ]], root))
+ end)
+
+ it('works with functions', function()
+ eq('foss', exec_lua [[
+ vim.filetype.add({
+ pattern = {
+ ["relevant_to_(%a+)"] = function(path, bufnr, capture)
+ if capture == "me" then
+ return "foss"
+ end
+ end,
+ }
+ })
+ vim.filetype.match('relevant_to_me')
+ return vim.bo.filetype
+ ]])
+ end)
+end)
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index c543dd1995..1322155595 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -532,6 +532,7 @@ describe('v:lua', function()
command('set pp+=test/functional/fixtures')
eq('\tbadval', eval("v:lua.require'leftpad'('badval')"))
eq(9003, eval("v:lua.require'bar'.doit()"))
+ eq(9004, eval("v:lua.require'baz-quux'.doit()"))
end)
it('throw errors for invalid use', function()
diff --git a/test/functional/lua/spell_spec.lua b/test/functional/lua/spell_spec.lua
new file mode 100644
index 0000000000..7e831f16a7
--- /dev/null
+++ b/test/functional/lua/spell_spec.lua
@@ -0,0 +1,53 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local pcall_err = helpers.pcall_err
+
+describe('vim.spell', function()
+ before_each(function()
+ clear()
+ end)
+
+ describe('.check', function()
+ local check = function(x, exp)
+ return eq(exp, exec_lua("return vim.spell.check(...)", x))
+ end
+
+ it('can handle nil', function()
+ eq([[Error executing lua: [string "<nvim>"]:0: bad argument #1 to 'check' (expected string)]],
+ pcall_err(exec_lua, [[vim.spell.check(nil)]]))
+ end)
+
+ it('can check spellings', function()
+ check('hello', {})
+
+ check(
+ 'helloi',
+ {{"helloi", "bad", 1}}
+ )
+
+ check(
+ 'hello therei',
+ {{"therei", "bad", 7}}
+ )
+
+ check(
+ 'hello. there',
+ {{"there", "caps", 8}}
+ )
+
+ check(
+ 'neovim cna chkc spellins. okay?',
+ {
+ {"neovim" , "bad" , 1},
+ {"cna" , "bad" , 8},
+ {"chkc" , "bad" , 12},
+ {"spellins", "bad" , 17},
+ {"okay" , "caps", 27}
+ }
+ )
+ end)
+
+ end)
+end)
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index dbfbe2dbfe..4635f17557 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -101,7 +101,7 @@ describe('URI methods', function()
eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
end)
- it('file path includes only ascii charactors with encoded colon character', function()
+ it('file path includes only ascii characters with encoded colon character', function()
local test_case = [[
local uri = 'file:///C%3A/Foo/Bar/Baz.txt'
return vim.uri_to_fname(uri)
@@ -155,6 +155,12 @@ describe('URI methods', function()
return pcall(vim.uri_to_fname, 'not_an_uri.txt')
]])
end)
+
+ it('uri_to_fname should not treat comma as a scheme character', function()
+ eq(false, exec_lua [[
+ return pcall(vim.uri_to_fname, 'foo,://bar')
+ ]])
+ end)
end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 317f92fcdc..ddcf7687f5 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -906,6 +906,7 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={nil, 'thread', true }}")
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
+ exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}")
matches('expected table, got number',
pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
@@ -935,6 +936,8 @@ describe('lua stdlib', function()
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
matches('arg1: expected %?, got 3',
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
+ matches('arg1: expected number|string, got nil',
+ pcall_err(exec_lua, "vim.validate{ arg1={ nil, {'n', 's'} }}"))
-- Pass an additional message back.
matches('arg1: expected %?, got 3. Info: TEST_MSG',
@@ -984,6 +987,38 @@ describe('lua stdlib', function()
matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.g[0].testing'))
+
+ exec_lua [[
+ local counter = 0
+ vim.g.AddCounter = function() counter = counter + 1 end
+ vim.g.GetCounter = function() return counter end
+ ]]
+
+ eq(0, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(1, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(2, eval('g:GetCounter()'))
+ exec_lua([[vim.g.AddCounter()]])
+ 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 [[
+ local counter = 0
+ vim.api.nvim_set_var('AddCounter', function() counter = counter + 1 end)
+ vim.api.nvim_set_var('GetCounter', function() return counter end)
+ ]]
+
+ eq(0, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(1, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(2, eval('g:GetCounter()'))
+ exec_lua([[vim.g.AddCounter()]])
+ 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')()]]))
end)
it('vim.b', function()
@@ -1019,6 +1054,38 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.b.to_delete")
exec_lua [[
+ local counter = 0
+ vim.b.AddCounter = function() counter = counter + 1 end
+ vim.b.GetCounter = function() return counter end
+ ]]
+
+ eq(0, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(1, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(2, eval('b:GetCounter()'))
+ exec_lua([[vim.b.AddCounter()]])
+ 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 [[
+ 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)
+ ]]
+
+ eq(0, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(1, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(2, eval('b:GetCounter()'))
+ exec_lua([[vim.b.AddCounter()]])
+ 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.cmd "vnew"
]]
@@ -1056,6 +1123,38 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.w.to_delete")
exec_lua [[
+ local counter = 0
+ vim.w.AddCounter = function() counter = counter + 1 end
+ vim.w.GetCounter = function() return counter end
+ ]]
+
+ eq(0, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(1, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(2, eval('w:GetCounter()'))
+ exec_lua([[vim.w.AddCounter()]])
+ 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 [[
+ 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)
+ ]]
+
+ eq(0, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(1, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(2, eval('w:GetCounter()'))
+ exec_lua([[vim.w.AddCounter()]])
+ 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.cmd "vnew"
]]
@@ -1088,6 +1187,38 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.t.to_delete")
exec_lua [[
+ local counter = 0
+ vim.t.AddCounter = function() counter = counter + 1 end
+ vim.t.GetCounter = function() return counter end
+ ]]
+
+ eq(0, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(1, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(2, eval('t:GetCounter()'))
+ exec_lua([[vim.t.AddCounter()]])
+ 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 [[
+ 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)
+ ]]
+
+ eq(0, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(1, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(2, eval('t:GetCounter()'))
+ exec_lua([[vim.t.AddCounter()]])
+ 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.cmd "tabnew"
]]
@@ -2200,6 +2331,40 @@ describe('lua stdlib', function()
end)
end)
+ it('vim.notify_once', function()
+ local screen = Screen.new(60,5)
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {foreground=Screen.colors.Red},
+ })
+ screen:attach()
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ exec_lua [[vim.notify_once("I'll only tell you this once...", vim.log.levels.WARN)]]
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:I'll only tell you this once...} |
+ ]]}
+ feed('<C-l>')
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ exec_lua [[vim.notify_once("I'll only tell you this once...")]]
+ screen:expect_unchanged()
+ end)
+
describe('vim.schedule_wrap', function()
it('preserves argument lists', function()
exec_lua [[
@@ -2295,3 +2460,82 @@ describe('lua: require("mod") from packages', function()
eq('I am fancy_z.lua', exec_lua [[ return require'fancy_z' ]])
end)
end)
+
+describe('vim.keymap', function()
+ it('can make a mapping', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end)
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can make an expr mapping', function()
+ exec_lua [[
+ vim.keymap.set('n', 'aa', function() return ':lua SomeValue = 99<cr>' end, {expr = true})
+ ]]
+
+ feed('aa')
+
+ eq(99, exec_lua[[return SomeValue]])
+ end)
+
+ it('can overwrite a mapping', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end)
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount - 1 end)
+ ]]
+
+ feed('asdf\n')
+
+ eq(0, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can unmap a mapping', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end)
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.keymap.del('n', 'asdf')
+ ]]
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
+ end)
+
+ it('can do <Plug> mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.keymap.set('n', '<plug>(asdf)', function() GlobalCount = GlobalCount + 1 end)
+ vim.keymap.set('n', 'ww', '<plug>(asdf)')
+ return GlobalCount
+ ]])
+
+ feed('ww\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ end)
+
+end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 1af31c38f8..eab520948f 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -73,8 +73,11 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options)
on_init = function(client, result)
TEST_RPC_CLIENT = client
vim.rpcrequest(1, "init", result)
- client.config.flags.allow_incremental_sync = options.allow_incremental_sync or false
end;
+ flags = {
+ allow_incremental_sync = options.allow_incremental_sync or false;
+ debounce_text_changes = options.debounce_text_changes or 0;
+ };
on_exit = function(...)
vim.rpcnotify(1, "exit", ...)
end;
@@ -926,7 +929,60 @@ describe('LSP', function()
local client
test_rpc_server {
test_name = "basic_check_buffer_open_and_change_incremental";
- options = { allow_incremental_sync = true };
+ options = {
+ allow_incremental_sync = true,
+ };
+ on_setup = function()
+ exec_lua [[
+ BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
+ "testing";
+ "123";
+ })
+ ]]
+ end;
+ on_init = function(_client)
+ client = _client
+ local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ eq(sync_kind, client.resolved_capabilities().text_document_did_change)
+ eq(true, client.resolved_capabilities().text_document_open_close)
+ exec_lua [[
+ assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
+ ]]
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
+ exec_lua [[
+ vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
+ "123boop";
+ })
+ ]]
+ client.notify('finish')
+ end
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
+ client.stop()
+ end
+ end;
+ }
+ end)
+ it('should check the body and didChange incremental with debounce', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "basic_check_buffer_open_and_change_incremental";
+ options = {
+ allow_incremental_sync = true,
+ debounce_text_changes = 5
+ };
on_setup = function()
exec_lua [[
BUFFER = vim.api.nvim_create_buf(false, true)
@@ -1235,7 +1291,7 @@ describe('LSP', function()
make_edit(2, 0, 2, 2, {"3"});
make_edit(3, 2, 3, 4, {""});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'123First line of text';
'2econd line of text';
@@ -1255,7 +1311,7 @@ describe('LSP', function()
make_edit(3, #'', 3, #"Fourth", {"another line of text", "before this"});
make_edit(3, #'Fourth', 3, #"Fourth line of text", {"!"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'';
'123';
@@ -1279,7 +1335,7 @@ describe('LSP', function()
make_edit(3, #"Fourth", 3, #'', {"another line of text", "before this"});
make_edit(3, #"Fourth line of text", 3, #'Fourth', {"!"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'';
'123';
@@ -1296,7 +1352,7 @@ describe('LSP', function()
local edits = {
make_edit(4, 3, 4, 4, {"ä"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1309,7 +1365,7 @@ describe('LSP', function()
local edits = {
make_edit(5, 0, 5, 0, "foobar");
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1319,6 +1375,20 @@ describe('LSP', function()
'foobar';
}, buf_lines(1))
end)
+ it('applies multiple text edits at the end of the document', function()
+ local edits = {
+ make_edit(4, 0, 5, 0, "");
+ make_edit(5, 0, 5, 0, "foobar");
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
+ eq({
+ 'First line of text';
+ 'Second line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'foobar';
+ }, buf_lines(1))
+ end)
describe('cursor position', function()
it('don\'t fix the cursor if the range contains the cursor', function()
@@ -1326,7 +1396,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 0, 1, 19, 'Second line of text')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1343,7 +1413,7 @@ describe('LSP', function()
make_edit(1, 0, 1, 6, ''),
make_edit(1, 6, 1, 19, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'';
@@ -1360,7 +1430,7 @@ describe('LSP', function()
make_edit(1, 0, 1, 6, ''),
make_edit(0, 18, 5, 0, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
}, buf_lines(1))
@@ -1372,7 +1442,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 0, 2, 0, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Third line of text';
@@ -1387,7 +1457,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 7, 1, 11, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second of text';
@@ -1403,7 +1473,7 @@ describe('LSP', function()
local edits = {
make_edit(0, 11, 1, 12, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Third line of text';
@@ -1419,21 +1489,21 @@ describe('LSP', function()
local edits = {
make_edit(0, 0, 5, 0, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
it('applies edits when the end line is 2 larger than vim\'s', function()
local edits = {
make_edit(0, 0, 6, 0, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
it('applies edits with a column offset', function()
local edits = {
make_edit(0, 0, 5, 2, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
end)
@@ -1461,7 +1531,7 @@ describe('LSP', function()
]]
end)
it('correctly goes ahead with the edit if all is normal', function()
- exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(5))
+ exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5))
eq({
'First ↥ 🤦 🦄 line of text';
'2nd line of 语text';
@@ -1473,7 +1543,7 @@ describe('LSP', function()
local bufnr = select(1, ...)
local text_edit = select(2, ...)
vim.lsp.util.buf_versions[bufnr] = 10
- vim.lsp.util.apply_text_document_edit(text_edit)
+ vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
]], target_bufnr, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text';
@@ -1486,7 +1556,7 @@ describe('LSP', function()
local args = {...}
local versionedBuf = args[2]
vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
- vim.lsp.util.apply_text_document_edit(args[1])
+ vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
]], edit, versionedBuf)
end
@@ -1512,17 +1582,36 @@ describe('LSP', function()
describe('workspace_apply_edit', function()
it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function()
- local expected = {
- applied = true;
- failureReason = nil;
+ local expected_handlers = {
+ {NIL, {}, {method="test", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = "basic_init";
+ on_init = function(client, _)
+ client.stop()
+ end;
+ -- If the program timed out, then code will be nil.
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ -- Note that NIL must be used here.
+ -- on_handler(err, method, result, client_id)
+ on_handler = function(...)
+ local expected = {
+ applied = true;
+ failureReason = nil;
+ }
+ eq(expected, exec_lua [[
+ local apply_edit = {
+ label = nil;
+ edit = {};
+ }
+ return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID})
+ ]])
+ eq(table.remove(expected_handlers), {...})
+ end;
}
- eq(expected, exec_lua [[
- local apply_edit = {
- label = nil;
- edit = {};
- }
- return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit)
- ]])
end)
end)
@@ -1596,7 +1685,7 @@ describe('LSP', function()
local workspace_edits = args[1]
local target_bufnr = args[2]
- vim.lsp.util.apply_workspace_edit(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
]], make_workspace_edit(edits), target_bufnr))
@@ -1618,7 +1707,7 @@ describe('LSP', function()
local workspace_edits = args[1]
local target_bufnr = args[2]
- vim.lsp.util.apply_workspace_edit(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
]], make_workspace_edit(edits), target_bufnr))
@@ -1635,7 +1724,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
end)
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
@@ -1653,7 +1742,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq('Dummy content', read_file(tmpfile))
end)
@@ -1673,7 +1762,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq('', read_file(tmpfile))
end)
@@ -1694,7 +1783,7 @@ describe('LSP', function()
}
}
}
- eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
+ eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16'))
eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq(false, exec_lua('return vim.api.nvim_buf_is_loaded(vim.fn.bufadd(...))', tmpfile))
end)
@@ -1855,7 +1944,7 @@ describe('LSP', function()
}
},
}
- return vim.lsp.util.locations_to_items(locations)
+ return vim.lsp.util.locations_to_items(locations, 'utf-16')
]]
eq(expected, actual)
end)
@@ -1885,7 +1974,7 @@ describe('LSP', function()
}
},
}
- return vim.lsp.util.locations_to_items(locations)
+ return vim.lsp.util.locations_to_items(locations, 'utf-16')
]]
eq(expected, actual)
end)
@@ -2189,7 +2278,7 @@ describe('LSP', function()
end
local jump = function(msg)
- eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg))
+ eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg, "utf-16"))
eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]])
return {
line = exec_lua[[return vim.fn.line('.')]],
@@ -2263,6 +2352,27 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.convert_signature_help_to_markdown_lines', function()
+ it('can handle negative activeSignature', function()
+ local result = exec_lua[[
+ local signature_help = {
+ activeParameter = 0,
+ activeSignature = -1,
+ signatures = {
+ {
+ documentation = "",
+ label = "TestEntity.TestEntity()",
+ parameters = {}
+ },
+ }
+ }
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','})
+ ]]
+ local expected = {'```cs', 'TestEntity.TestEntity()', '```', ''}
+ eq(expected, result)
+ end)
+ end)
+
describe('lsp.util.get_effective_tabstop', function()
local function test_tabstop(tabsize, softtabstop)
exec_lua(string.format([[
diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index d100db8de2..603f4d91b9 100644
--- a/test/functional/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -8,6 +8,7 @@ local source = helpers.source
local missing_provider = helpers.missing_provider
local matches = helpers.matches
local pcall_err = helpers.pcall_err
+local funcs = helpers.funcs
do
clear()
@@ -93,16 +94,40 @@ describe('python3 provider', function()
ghi]])
end)
- it('py3eval', function()
- eq({1, 2, {['key'] = 'val'}}, eval([[py3eval('[1, 2, {"key": "val"}]')]]))
+ describe('py3eval()', function()
+ it('works', function()
+ eq({1, 2, {['key'] = 'val'}}, funcs.py3eval('[1, 2, {"key": "val"}]'))
+ end)
+
+ it('errors out when given non-string', function()
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(10)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:_null_dict)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:_null_list)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(0.0)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(function("tr"))'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:true)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:false)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:null)'))
+ end)
+
+ it('accepts NULL string', function()
+ matches('.*SyntaxError.*', pcall_err(eval, 'py3eval($XXX_NONEXISTENT_VAR_XXX)'))
+ end)
end)
it('pyxeval #10758', function()
- eq(0, eval([[&pyxversion]]))
+ eq(3, eval([[&pyxversion]]))
eq(3, eval([[pyxeval('sys.version_info[:3][0]')]]))
eq(3, eval([[&pyxversion]]))
end)
+ it("setting 'pyxversion'", function()
+ command 'set pyxversion=3' -- no error
+ eq('Vim(set):E474: Invalid argument: pyxversion=2', pcall_err(command, 'set pyxversion=2'))
+ command 'set pyxversion=0' -- allowed, but equivalent to pyxversion=3
+ eq(3, eval'&pyxversion')
+ end)
+
it('RPC call to expand("<afile>") during BufDelete #5245 #5617', function()
helpers.add_builddir_to_rtp()
source([=[
@@ -120,3 +145,15 @@ describe('python3 provider', function()
assert_alive()
end)
end)
+
+describe('python2 feature test', function()
+ -- python2 is not supported, so correct behaviour is to return 0
+ it('works', function()
+ eq(0, funcs.has('python2'))
+ eq(0, funcs.has('python'))
+ eq(0, funcs.has('python_compiled'))
+ eq(0, funcs.has('python_dynamic'))
+ eq(0, funcs.has('python_dynamic_'))
+ eq(0, funcs.has('python_'))
+ end)
+end)
diff --git a/test/functional/provider/python_spec.lua b/test/functional/provider/python_spec.lua
deleted file mode 100644
index d60d8d1001..0000000000
--- a/test/functional/provider/python_spec.lua
+++ /dev/null
@@ -1,123 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local eq = helpers.eq
-local neq = helpers.neq
-local feed = helpers.feed
-local clear = helpers.clear
-local funcs = helpers.funcs
-local meths = helpers.meths
-local insert = helpers.insert
-local expect = helpers.expect
-local command = helpers.command
-local exc_exec = helpers.exc_exec
-local write_file = helpers.write_file
-local curbufmeths = helpers.curbufmeths
-local missing_provider = helpers.missing_provider
-local matches = helpers.matches
-local pcall_err = helpers.pcall_err
-
-do
- clear()
- local reason = missing_provider('python')
- if reason then
- it(':python reports E319 if provider is missing', function()
- local expected = [[Vim%(py.*%):E319: No "python" provider found.*]]
- matches(expected, pcall_err(command, 'py print("foo")'))
- matches(expected, pcall_err(command, 'pyfile foo'))
- end)
- pending(string.format('Python 2 (or the pynvim module) is broken/missing (%s)', reason), function() end)
- return
- end
-end
-
-before_each(function()
- clear()
- command('python import vim')
-end)
-
-describe('python feature test', function()
- it('works', function()
- eq(1, funcs.has('python'))
- eq(1, funcs.has('python_compiled'))
- eq(1, funcs.has('python_dynamic'))
- eq(0, funcs.has('python_dynamic_'))
- eq(0, funcs.has('python_'))
- end)
-end)
-
-describe(':python command', function()
- it('works with a line', function()
- command('python vim.vars["set_by_python"] = [100, 0]')
- eq({100, 0}, meths.get_var('set_by_python'))
- end)
-
- -- TODO(ZyX-I): works with << EOF
- -- TODO(ZyX-I): works with execute 'python' line1."\n".line2."\n"…
-
- it('supports nesting', function()
- command([[python vim.command('python vim.command("python vim.command(\'let set_by_nested_python = 555\')")')]])
- eq(555, meths.get_var('set_by_nested_python'))
- end)
-
- it('supports range', function()
- insert([[
- line1
- line2
- line3
- line4]])
- feed('ggjvj:python vim.vars["range"] = vim.current.range[:]<CR>')
- eq({'line2', 'line3'}, meths.get_var('range'))
- end)
-end)
-
-describe(':pyfile command', function()
- it('works', function()
- local fname = 'pyfile.py'
- write_file(fname, 'vim.command("let set_by_pyfile = 123")')
- command('pyfile pyfile.py')
- eq(123, meths.get_var('set_by_pyfile'))
- os.remove(fname)
- end)
-end)
-
-describe(':pydo command', function()
- it('works', function()
- -- :pydo 42 returns None for all lines,
- -- the buffer should not be changed
- command('normal :pydo 42')
- eq(false, curbufmeths.get_option('modified'))
- -- insert some text
- insert('abc\ndef\nghi')
- expect([[
- abc
- def
- ghi]])
- -- go to top and select and replace the first two lines
- feed('ggvj:pydo return str(linenr)<CR>')
- expect([[
- 1
- 2
- ghi]])
- end)
-end)
-
-describe('pyeval()', function()
- it('works', function()
- eq({1, 2, {['key'] = 'val'}}, funcs.pyeval('[1, 2, {"key": "val"}]'))
- end)
-
- it('errors out when given non-string', function()
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(10)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:_null_dict)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:_null_list)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(0.0)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(function("tr"))'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:true)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:false)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:null)'))
- end)
-
- it('accepts NULL string', function()
- neq(0, exc_exec('call pyeval($XXX_NONEXISTENT_VAR_XXX)'))
- end)
-end)
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index f25cfa2039..beb43e0271 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -292,10 +292,9 @@ describe(':terminal buffer', function()
command('quit')
end)
- it('does not segfault when pasting empty buffer #13955', function()
- feed_command('terminal')
+ it('does not segfault when pasting empty register #13955', function()
feed('<c-\\><c-n>')
- feed_command('put a') -- buffer a is empty
+ feed_command('put a') -- register a is empty
helpers.assert_alive()
end)
end)
@@ -350,7 +349,7 @@ describe('on_lines does not emit out-of-bounds line indexes when', function()
end)
it('creating a terminal buffer #16394', function()
- feed_command([[autocmd TermOpen * ++once call v:lua.register_callback(expand("<abuf>"))]])
+ feed_command('autocmd TermOpen * ++once call v:lua.register_callback(str2nr(expand("<abuf>")))')
feed_command('terminal')
sleep(500)
eq('', exec_lua([[return _G.cb_error]]))
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index 3d8441b93c..6e2c851df7 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local clear, eq, eval = helpers.clear, helpers.eq, helpers.eval
-local feed, nvim = helpers.feed, helpers.nvim
+local feed, nvim, command = helpers.feed, helpers.nvim, helpers.command
local feed_data = thelpers.feed_data
describe(':terminal mouse', function()
@@ -10,9 +10,9 @@ describe(':terminal mouse', function()
before_each(function()
clear()
nvim('set_option', 'statusline', '==========')
- nvim('command', 'highlight StatusLine cterm=NONE')
- nvim('command', 'highlight StatusLineNC cterm=NONE')
- nvim('command', 'highlight VertSplit cterm=NONE')
+ command('highlight StatusLine cterm=NONE')
+ command('highlight StatusLineNC cterm=NONE')
+ command('highlight VertSplit cterm=NONE')
screen = thelpers.screen_setup()
local lines = {}
for i = 1, 30 do
@@ -38,6 +38,26 @@ describe(':terminal mouse', function()
eq('nt', eval('mode(1)'))
end)
+ it('will exit focus and trigger Normal mode mapping on mouse click', function()
+ command('let g:got_leftmouse = 0')
+ command('nnoremap <LeftMouse> <Cmd>let g:got_leftmouse = 1<CR>')
+ eq('t', eval('mode(1)'))
+ eq(0, eval('g:got_leftmouse'))
+ feed('<LeftMouse>')
+ eq('nt', eval('mode(1)'))
+ eq(1, eval('g:got_leftmouse'))
+ end)
+
+ it('will exit focus and trigger Normal mode mapping on mouse click with modifier', function()
+ command('let g:got_ctrl_leftmouse = 0')
+ command('nnoremap <C-LeftMouse> <Cmd>let g:got_ctrl_leftmouse = 1<CR>')
+ eq('t', eval('mode(1)'))
+ eq(0, eval('g:got_ctrl_leftmouse'))
+ feed('<C-LeftMouse>')
+ eq('nt', eval('mode(1)'))
+ eq(1, eval('g:got_ctrl_leftmouse'))
+ end)
+
it('will exit focus on <C-\\> + mouse-scroll', function()
eq('t', eval('mode(1)'))
feed('<C-\\>')
@@ -45,6 +65,12 @@ describe(':terminal mouse', function()
eq('nt', eval('mode(1)'))
end)
+ it('does not leave terminal mode on left-release', function()
+ if helpers.pending_win32(pending) then return end
+ feed('<LeftRelease>')
+ eq('t', eval('mode(1)'))
+ end)
+
describe('with mouse events enabled by the program', function()
before_each(function()
thelpers.enable_mouse()
@@ -60,7 +86,7 @@ describe(':terminal mouse', function()
]])
end)
- it('will forward mouse clicks to the program', function()
+ it('will forward mouse press, drag and release to the program', function()
if helpers.pending_win32(pending) then return end
feed('<LeftMouse><1,2>')
screen:expect([[
@@ -72,6 +98,36 @@ describe(':terminal mouse', function()
"#{1: } |
{3:-- TERMINAL --} |
]])
+ feed('<LeftDrag><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ @##{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftDrag><3,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ @$#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftRelease><3,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ #$#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
end)
it('will forward mouse scroll to the program', function()
@@ -88,9 +144,63 @@ describe(':terminal mouse', function()
]])
end)
+ it('dragging and scrolling do not interfere with each other', function()
+ if helpers.pending_win32(pending) then return end
+ feed('<LeftMouse><1,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ "#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<ScrollWheelUp><1,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ `"#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftDrag><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ @##{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<ScrollWheelUp><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ `##{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftRelease><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ ###{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('will forward mouse clicks to the program with the correct even if set nu', function()
if helpers.pending_win32(pending) then return end
- nvim('command', 'set number')
+ command('set number')
-- When the display area such as a number is clicked, it returns to the
-- normal mode.
feed('<LeftMouse><3,0>')
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index bf57b135cb..faf44fa01d 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -20,7 +20,6 @@ local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
-local exec_lua = helpers.exec_lua
if helpers.pending_win32(pending) then return end
@@ -581,34 +580,21 @@ describe('TUI', function()
end)
it("paste: 'nomodifiable' buffer", function()
- local has_luajit = exec_lua('return jit ~= nil')
child_session:request('nvim_command', 'set nomodifiable')
child_session:request('nvim_exec_lua', [[
- -- Stack traces for this test are non-deterministic, so disable them
- _G.debug.traceback = function(msg) return msg end
+ -- Truncate the error message to hide the line number
+ _G.debug.traceback = function(msg) return msg:sub(-49) end
]], {})
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
- if has_luajit then
- screen:expect{grid=[[
- |
- {4:~ }|
- {5: }|
- {8:paste: Error executing lua: vim.lua:0: Vim:E21: Ca}|
- {8:nnot make changes, 'modifiable' is off} |
- {10:Press ENTER or type command to continue}{1: } |
- {3:-- TERMINAL --} |
- ]]}
- else
- screen:expect{grid=[[
- |
- {4:~ }|
- {5: }|
- {8:paste: Error executing lua: Vim:E21: Cannot make c}|
- {8:hanges, 'modifiable' is off} |
- {10:Press ENTER or type command to continue}{1: } |
- {3:-- TERMINAL --} |
- ]]}
- end
+ screen:expect{grid=[[
+ |
+ {4:~ }|
+ {5: }|
+ {8:paste: Error executing lua: Vim:E21: Cannot make c}|
+ {8:hanges, 'modifiable' is off} |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data('\n') -- <Enter>
child_session:request('nvim_command', 'set modifiable')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 911fa017ab..396fe5feab 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -167,6 +167,27 @@ void ui_refresh(void)
eq('variable', ret)
end)
+ it("supports caching queries", function()
+ local long_query = query:rep(100)
+ local first_run = exec_lua ([[
+ local before = vim.loop.hrtime()
+ cquery = vim.treesitter.parse_query("c", ...)
+ local after = vim.loop.hrtime()
+ return after - before
+ ]], long_query)
+
+ local subsequent_runs = exec_lua ([[
+ local before = vim.loop.hrtime()
+ for i=1,100,1 do
+ cquery = vim.treesitter.parse_query("c", ...)
+ end
+ local after = vim.loop.hrtime()
+ return after - before
+ ]], long_query)
+
+ assert.True(1000 * subsequent_runs < first_run)
+ end)
+
it('support query and iter by capture', function()
insert(test_text)
@@ -645,6 +666,21 @@ int x = INT_MAX;
-- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
}, get_ranges())
end)
+
+ it("should not inject bad languages", function()
+ if helpers.pending_win32(pending) then return end
+ exec_lua([=[
+ vim.treesitter.add_directive("inject-bad!", function(match, _, _, pred, metadata)
+ metadata.language = "{"
+ metadata.combined = true
+ metadata.content = pred[2]
+ end)
+
+ parser = vim.treesitter.get_parser(0, "c", {
+ injections = {
+ c = "(preproc_function_def value: ((preproc_arg) @_a (#inject-bad! @_a)))"}})
+ ]=])
+ end)
end)
describe("when using the offset directive", function()
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 16ed3b9486..9f84b71ece 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -755,12 +755,26 @@ describe('Buffer highlighting', function()
-- TODO: only a virtual text from the same ns curretly overrides
-- an existing virtual text. We might add a prioritation system.
set_virtual_text(id1, 0, s1, {})
- eq({{1, 0, 0, { priority = 0, virt_text = s1}}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
+ eq({{1, 0, 0, {
+ priority = 0,
+ virt_text = s1,
+ -- other details
+ right_gravity = true,
+ virt_text_pos = 'eol',
+ virt_text_hide = false,
+ }}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
-- TODO: is this really valid? shouldn't the max be line_count()-1?
local lastline = line_count()
set_virtual_text(id1, line_count(), s2, {})
- eq({{3, lastline, 0, { priority = 0, virt_text = s2}}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
+ eq({{3, lastline, 0, {
+ priority = 0,
+ virt_text = s2,
+ -- other details
+ right_gravity = true,
+ virt_text_pos = 'eol',
+ virt_text_hide = false,
+ }}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
eq({}, get_extmarks(id1, {lastline+9000,0}, {lastline+9000, -1}, {}))
end)
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index ea8968a653..11718a6e18 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -114,11 +114,30 @@ describe('mappings', function()
end)
end)
-describe('input utf sequences that contain CSI/K_SPECIAL', function()
+describe('input utf sequences that contain K_SPECIAL (0x80)', function()
it('ok', function()
feed('i…<esc>')
expect('…')
end)
+
+ it('can be mapped', function()
+ command('inoremap … E280A6')
+ feed('i…<esc>')
+ expect('E280A6')
+ end)
+end)
+
+describe('input utf sequences that contain CSI (0x9B)', function()
+ it('ok', function()
+ feed('iě<esc>')
+ expect('ě')
+ end)
+
+ it('can be mapped', function()
+ command('inoremap ě C49B')
+ feed('iě<esc>')
+ expect('C49B')
+ end)
end)
describe('input non-printable chars', function()
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index aeba049557..c44e59cfd3 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -10,6 +10,7 @@ local funcs = helpers.funcs
local get_pathsep = helpers.get_pathsep
local eq = helpers.eq
local pcall_err = helpers.pcall_err
+local exec_lua = helpers.exec_lua
describe('ui/ext_popupmenu', function()
local screen
@@ -25,6 +26,7 @@ describe('ui/ext_popupmenu', function()
[5] = {bold = true, foreground = Screen.colors.SeaGreen},
[6] = {background = Screen.colors.WebGray},
[7] = {background = Screen.colors.LightMagenta},
+ [8] = {foreground = Screen.colors.Red},
})
source([[
function! TestComplete() abort
@@ -369,6 +371,111 @@ describe('ui/ext_popupmenu', function()
{1:~ }|
{2:-- INSERT --} |
]])
+
+ command('iunmap <f1>')
+ command('iunmap <f2>')
+ command('iunmap <f3>')
+ exec_lua([[
+ vim.keymap.set('i', '<f1>', function() vim.api.nvim_select_popupmenu_item(2, true, false, {}) end)
+ vim.keymap.set('i', '<f2>', function() vim.api.nvim_select_popupmenu_item(-1, false, false, {}) end)
+ vim.keymap.set('i', '<f3>', function() vim.api.nvim_select_popupmenu_item(1, false, true, {}) end)
+ ]])
+ feed('<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ |
+ foo^ |
+ {6:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {7:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f1>')
+ screen:expect([[
+ |
+ spam^ |
+ {7:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {6:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f2>')
+ screen:expect([[
+ |
+ spam^ |
+ {7:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {7:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f3>')
+ screen:expect([[
+ |
+ bar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<esc>ddiaa bb cc<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa bb cc |
+ aa^ |
+ {6:aa }{1: }|
+ {7:bb }{1: }|
+ {7:cc }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- Keyword Local completion (^N^P) }{5:match 1 of 3} |
+ ]])
+
+ feed('<f1>')
+ screen:expect([[
+ aa bb cc |
+ cc^ |
+ {7:aa }{1: }|
+ {7:bb }{1: }|
+ {6:cc }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- Keyword Local completion (^N^P) }{5:match 3 of 3} |
+ ]])
+
+ feed('<f2>')
+ screen:expect([[
+ aa bb cc |
+ cc^ |
+ {7:aa }{1: }|
+ {7:bb }{1: }|
+ {7:cc }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- Keyword Local completion (^N^P) }{8:Back at original} |
+ ]])
+
+ feed('<f3>')
+ screen:expect([[
+ aa bb cc |
+ bb^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
end)
local function source_complete_month()
@@ -2213,4 +2320,175 @@ describe('builtin popupmenu', function()
feed('<c-y>')
assert_alive()
end)
+
+ 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>')
+ screen:expect([[
+ hello |
+ hullo |
+ heeee |
+ hello^ |
+ {s:hello }{1: }|
+ {n:hullo }{1: }|
+ {n:heeee }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ command([[call timer_start(100, { -> execute('stopinsert') })]])
+ helpers.sleep(200)
+ feed('k') -- cursor should move up in Normal mode
+ screen:expect([[
+ hello |
+ hullo |
+ heee^e |
+ hello |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('truncates double-width character correctly when there is no scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=menuone,noselect')
+ feed('i' .. string.rep(' ', 13))
+ funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
+ screen:expect([[
+ ^ |
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+
+ it('truncates double-width character correctly when there is scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=noselect')
+ command('set pumheight=4')
+ feed('i' .. string.rep(' ', 12))
+ local items = {}
+ for _ = 1, 8 do
+ table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
+ end
+ funcs.complete(13, items)
+ screen:expect([[
+ ^ |
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+end)
+
+describe('builtin popupmenu with ui/ext_multigrid', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(32, 20)
+ screen:attach({ext_multigrid=true})
+ screen:set_default_attr_ids({
+ -- popup selected item / scrollbar track
+ ['s'] = {background = Screen.colors.WebGray},
+ -- popup non-selected item
+ ['n'] = {background = Screen.colors.LightMagenta},
+ -- popup scrollbar knob
+ ['c'] = {background = Screen.colors.Grey0},
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true},
+ [3] = {reverse = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ })
+ end)
+
+ it('truncates double-width character correctly when there is no scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=menuone,noselect')
+ feed('i' .. string.rep(' ', 13))
+ funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ {2:-- INSERT --} |
+ ## grid 4
+ {n: 哦哦哦哦哦哦哦哦哦>}|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 12, false, 100}}})
+ end)
+
+ it('truncates double-width character correctly when there is scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=noselect')
+ command('set pumheight=4')
+ feed('i' .. string.rep(' ', 12))
+ local items = {}
+ for _ = 1, 8 do
+ table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
+ end
+ funcs.complete(13, items)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ {2:-- INSERT --} |
+ ## grid 4
+ {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
+ end)
end)
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 958e137f65..09bcbc2bbd 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -6,6 +6,7 @@ local insert = helpers.insert
local eq = helpers.eq
local eval = helpers.eval
local iswin = helpers.iswin
+local funcs, meths, exec_lua = helpers.funcs, helpers.meths, helpers.exec_lua
describe('screen', function()
local screen
@@ -127,14 +128,67 @@ local function screen_tests(linegrid)
end)
it('has correct default title with named file', function()
- local expected = (iswin() and 'myfile (C:\\mydir) - NVIM'
- or 'myfile (/mydir) - NVIM')
+ local expected = (iswin() and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
command('set title')
command(iswin() and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
screen:expect(function()
eq(expected, screen.title)
end)
end)
+
+ describe('is not changed by', function()
+ local file1 = iswin() and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
+ local file2 = iswin() and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
+ local expected = (iswin() and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
+ local buf2
+
+ before_each(function()
+ command('edit '..file1)
+ buf2 = funcs.bufadd(file2)
+ command('set title')
+ end)
+
+ it('calling setbufvar() to set an option in a hidden buffer from i_CTRL-R', function()
+ command([[inoremap <F2> <C-R>=setbufvar(]]..buf2..[[, '&autoindent', 1) ? '' : ''<CR>]])
+ feed('i<F2><Esc>')
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+
+ it('an RPC call to nvim_buf_set_option in a hidden buffer', function()
+ meths.buf_set_option(buf2, 'autoindent', true)
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+
+ it('a Lua callback calling nvim_buf_set_option in a hidden buffer', function()
+ exec_lua(string.format([[
+ vim.schedule(function()
+ vim.api.nvim_buf_set_option(%d, 'autoindent', true)
+ end)
+ ]], buf2))
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+
+ it('a Lua callback calling nvim_buf_call in a hidden buffer', function()
+ exec_lua(string.format([[
+ vim.schedule(function()
+ vim.api.nvim_buf_call(%d, function() end)
+ end)
+ ]], buf2))
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+ end)
end)
describe(':set icon', function()
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index e1459ab5b8..0c2ca8de78 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -5,7 +5,7 @@
-- null_spec.lua
-- operators_spec.lua
--
--- Tests for the Vimscript |functions| library should live in:
+-- Tests for the Vimscript |builtin-functions| library should live in:
-- test/functional/vimscript/<funcname>_spec.lua
-- test/functional/vimscript/functions_spec.lua
diff --git a/test/functional/vimscript/functions_spec.lua b/test/functional/vimscript/functions_spec.lua
index 0ad7fd8010..20c1400030 100644
--- a/test/functional/vimscript/functions_spec.lua
+++ b/test/functional/vimscript/functions_spec.lua
@@ -1,4 +1,4 @@
--- Tests for misc Vimscript |functions|.
+-- Tests for misc Vimscript |builtin-functions|.
--
-- If a function is non-trivial, consider moving its spec to:
-- test/functional/vimscript/<funcname>_spec.lua