aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/api/buffer_spec.lua22
-rw-r--r--test/functional/api/vim_spec.lua75
-rw-r--r--test/functional/api/window_spec.lua40
-rw-r--r--test/functional/autoread/focus_spec.lua7
-rw-r--r--test/functional/core/job_spec.lua26
-rw-r--r--test/functional/eval/null_spec.lua26
-rw-r--r--test/functional/eval/writefile_spec.lua10
-rw-r--r--test/functional/ex_cmds/dict_notifications_spec.lua75
-rw-r--r--test/functional/ex_cmds/excmd_spec.lua2
-rw-r--r--test/functional/ex_cmds/source_spec.lua47
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua13
-rw-r--r--test/functional/fixtures/smile2.cat32
-rw-r--r--test/functional/legacy/memory_usage_spec.lua4
-rw-r--r--test/functional/legacy/options_spec.lua61
-rw-r--r--test/functional/lua/buffer_updates_spec.lua502
-rw-r--r--test/functional/lua/command_line_completion_spec.lua171
-rw-r--r--test/functional/lua/vim_spec.lua5
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua63
-rw-r--r--test/functional/plugin/lsp_spec.lua269
-rw-r--r--test/functional/terminal/buffer_spec.lua7
-rw-r--r--test/functional/treesitter/highlight_spec.lua100
-rw-r--r--test/functional/treesitter/language_spec.lua2
-rw-r--r--test/functional/treesitter/parser_spec.lua59
-rw-r--r--test/functional/ui/cmdline_spec.lua13
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/decorations_spec.lua279
-rw-r--r--test/functional/ui/diff_spec.lua20
-rw-r--r--test/functional/ui/float_spec.lua588
-rw-r--r--test/functional/ui/fold_spec.lua567
-rw-r--r--test/functional/ui/highlight_spec.lua6
-rw-r--r--test/functional/ui/input_spec.lua38
-rw-r--r--test/functional/ui/messages_spec.lua42
-rw-r--r--test/functional/ui/screen_basic_spec.lua44
-rw-r--r--test/functional/ui/searchhl_spec.lua14
-rw-r--r--test/functional/ui/sign_spec.lua18
-rw-r--r--test/functional/viml/completion_spec.lua43
-rw-r--r--test/functional/viml/errorlist_spec.lua13
-rw-r--r--test/helpers.lua6
-rw-r--r--test/symbolic/klee/nvim/charset.c4
-rw-r--r--test/symbolic/klee/nvim/memory.c4
40 files changed, 3140 insertions, 181 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index fb8ed6a9d7..81fad206da 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -513,6 +513,28 @@ describe('api/buf', function()
eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id2, {}))
eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id3, {}))
end)
+
+ it("correctly marks changed region for redraw #13890", function()
+ local screen = Screen.new(20, 5)
+ screen:attach()
+
+ insert([[
+ AAA
+ BBB
+ ]])
+
+ curbufmeths.set_text(0, 0, 1, 3, {'XXX', 'YYY'})
+
+ screen:expect([[
+ XXX |
+ YYY |
+ ^ |
+ ~ |
+ |
+
+ ]])
+
+ end)
end)
describe('nvim_buf_get_offset', function()
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 3ff3efb8c9..3db44f3f11 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -475,6 +475,18 @@ describe('API', function()
end)
end)
+ describe('nvim_notify', function()
+ it('can notify a info message', function()
+ nvim("notify", "hello world", 2, {})
+ end)
+
+ it('can be overriden', function()
+ command("lua vim.notify = function(...) return 42 end")
+ eq(42, meths.exec_lua("return vim.notify('Hello world')", {}))
+ nvim("notify", "hello world", 4, {})
+ end)
+ end)
+
describe('nvim_input', function()
it("VimL error: does NOT fail, updates v:errmsg", function()
local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>")
@@ -2075,4 +2087,67 @@ describe('API', function()
eq("", meths.exec("messages", true))
end)
end)
+
+
+ describe('nvim_open_term', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(100, 35)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {background = Screen.colors.Plum1};
+ [2] = {background = tonumber('0xffff40'), bg_indexed = true};
+ [3] = {background = Screen.colors.Plum1, fg_indexed = true, foreground = tonumber('0x00e000')};
+ [4] = {bold = true, reverse = true, background = Screen.colors.Plum1};
+ })
+ end)
+
+ it('can batch process sequences', function()
+ local b = meths.create_buf(true,true)
+ meths.open_win(b, false, {width=79, height=31, row=1, col=1, relative='editor'})
+ local t = meths.open_term(b, {})
+
+ meths.chan_send(t, io.open("test/functional/fixtures/smile2.cat", "r"):read("*a"))
+ screen:expect{grid=[[
+ ^ |
+ {0:~}{1::smile }{0: }|
+ {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }|
+ {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{0: }|
+ {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:o$}{1: }{2:$$}{1: }{2:o$}{1: }{0: }|
+ {0:~}{1: }{2:o}{1: }{2:$}{1: }{2:oo}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:$$}{1: }{2:$$}{1: }{2:$$o$}{1: }{0: }|
+ {0:~}{1: }{2:oo}{1: }{2:$}{1: }{2:$}{1: "}{2:$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$o}{1: }{2:$$$o$$o$}{1: }{0: }|
+ {0:~}{1: "}{2:$$$$$$o$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$o}{1: }{2:$$$$$$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$}{1: """}{2:$$$}{1: }{0: }|
+ {0:~}{1: "}{2:$$$}{1:""""}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$o}{1: }{0: }|
+ {0:~}{1: }{2:o$$}{1:" }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$o}{1: }{0: }|
+ {0:~}{1: }{2:$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" "}{2:$$$$$$ooooo$$$$o}{1: }{0: }|
+ {0:~}{1: }{2:o$$$oooo$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:o$$$$$$$$$$$$$$$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$$$$$$}{1:"}{2:$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$}{1:"""""""" }{0: }|
+ {0:~}{1: """" }{2:$$$$}{1: "}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" }{2:o$$$}{1: }{0: }|
+ {0:~}{1: "}{2:$$$o}{1: """}{2:$$$$$$$$$$$$$$$$$$}{1:"}{2:$$}{1:" }{2:$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$o}{1: "}{2:$$}{1:""}{2:$$$$$$}{1:"""" }{2:o$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$$o}{1: }{2:o$$$}{1:" }{0: }|
+ {0:~}{1: "}{2:$$$$o}{1: }{2:o$$$$$$o}{1:"}{2:$$$$o}{1: }{2:o$$$$}{1: }{0: }|
+ {0:~}{1: "}{2:$$$$$oo}{1: ""}{2:$$$$o$$$$$o}{1: }{2:o$$$$}{1:"" }{0: }|
+ {0:~}{1: ""}{2:$$$$$oooo}{1: "}{2:$$$o$$$$$$$$$}{1:""" }{0: }|
+ {0:~}{1: ""}{2:$$$$$$$oo}{1: }{2:$$$$$$$$$$}{1: }{0: }|
+ {0:~}{1: """"}{2:$$$$$$$$$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$$$$$$$$$$}{1: }{0: }|
+ {0:~}{1: }{2:$$$$$$$$$$}{1:" }{0: }|
+ {0:~}{1: "}{2:$$$}{1:"""" }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{3:Press ENTER or type command to continue}{1: }{0: }|
+ {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }|
+ {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end)
+ end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 7471f50dbd..ceeb84cec9 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -347,4 +347,44 @@ describe('API/win', function()
eq('', funcs.getcmdwintype())
end)
end)
+
+ describe('hide', function()
+ it('can hide current window', function()
+ local oldwin = meths.get_current_win()
+ command('split')
+ local newwin = meths.get_current_win()
+ meths.win_hide(newwin)
+ eq({oldwin}, meths.list_wins())
+ end)
+ it('can hide noncurrent window', function()
+ local oldwin = meths.get_current_win()
+ command('split')
+ local newwin = meths.get_current_win()
+ meths.win_hide(oldwin)
+ eq({newwin}, meths.list_wins())
+ end)
+ it('does not close the buffer', function()
+ local oldwin = meths.get_current_win()
+ local oldbuf = meths.get_current_buf()
+ local buf = meths.create_buf(true, false)
+ local newwin = meths.open_win(buf, true, {
+ relative='win', row=3, col=3, width=12, height=3
+ })
+ meths.win_hide(newwin)
+ eq({oldwin}, meths.list_wins())
+ eq({oldbuf, buf}, meths.list_bufs())
+ end)
+ it('deletes the buffer when bufhidden=wipe', function()
+ local oldwin = meths.get_current_win()
+ local oldbuf = meths.get_current_buf()
+ local buf = meths.create_buf(true, false)
+ local newwin = meths.open_win(buf, true, {
+ relative='win', row=3, col=3, width=12, height=3
+ })
+ meths.buf_set_option(buf, 'bufhidden', 'wipe')
+ meths.win_hide(newwin)
+ eq({oldwin}, meths.list_wins())
+ eq({oldbuf}, meths.list_bufs())
+ end)
+ end)
end)
diff --git a/test/functional/autoread/focus_spec.lua b/test/functional/autoread/focus_spec.lua
index 1d52e9948f..3f9a0ad09b 100644
--- a/test/functional/autoread/focus_spec.lua
+++ b/test/functional/autoread/focus_spec.lua
@@ -9,6 +9,7 @@ local feed_data = thelpers.feed_data
if helpers.pending_win32(pending) then return end
describe('autoread TUI FocusGained/FocusLost', function()
+ local f1 = 'xtest-foo'
local screen
before_each(function()
@@ -17,8 +18,12 @@ describe('autoread TUI FocusGained/FocusLost', function()
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]')
end)
+ teardown(function()
+ os.remove(f1)
+ end)
+
it('external file change', function()
- local path = 'xtest-foo'
+ local path = f1
local expected_addition = [[
line 1
line 2
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 6d1182478a..9de0d08e79 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -31,9 +31,9 @@ describe('jobs', function()
nvim('set_var', 'channel', channel)
source([[
function! Normalize(data) abort
- " Windows: remove ^M
+ " Windows: remove ^M and term escape sequences
return type([]) == type(a:data)
- \ ? map(a:data, 'substitute(v:val, "\r", "", "g")')
+ \ ? map(a:data, 'substitute(substitute(v:val, "\r", "", "g"), "\x1b\\%(\\]\\d\\+;.\\{-}\x07\\|\\[.\\{-}[\x40-\x7E]\\)", "", "g")')
\ : a:data
endfunction
function! OnEvent(id, data, event) dict
@@ -63,6 +63,7 @@ describe('jobs', function()
it('append environment #env', function()
nvim('command', "let $VAR = 'abc'")
+ nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
if iswin() then
nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
@@ -75,8 +76,24 @@ describe('jobs', function()
})
end)
+ it('append environment with pty #env', function()
+ nvim('command', "let $VAR = 'abc'")
+ nvim('command', "let $TOTO = 'goodbye world'")
+ nvim('command', "let g:job_opts.pty = v:true")
+ nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
+ if iswin() then
+ nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
+ else
+ nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
+ end
+ expect_msg_seq({
+ {'notification', 'stdout', {0, {'hello world abc', ''}}},
+ })
+ end)
+
it('replace environment #env', function()
nvim('command', "let $VAR = 'abc'")
+ nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
nvim('command', "let g:job_opts.clear_env = 1")
@@ -946,8 +963,10 @@ describe('jobs', function()
return rv
end
+ local j
local function send(str)
- nvim('command', 'call jobsend(j, "'..str..'")')
+ -- check no nvim_chan_free double free with pty job (#14198)
+ meths.chan_send(j, str)
end
before_each(function()
@@ -962,6 +981,7 @@ describe('jobs', function()
nvim('command', 'let g:job_opts.pty = 1')
nvim('command', 'let exec = [expand("<cfile>:p")]')
nvim('command', "let j = jobstart(exec, g:job_opts)")
+ j = eval'j'
eq('tty ready', next_chunk())
end)
diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua
index fa8f7d873f..d403fbc878 100644
--- a/test/functional/eval/null_spec.lua
+++ b/test/functional/eval/null_spec.lua
@@ -14,7 +14,8 @@ describe('NULL', function()
clear()
command('let L = v:_null_list')
command('let D = v:_null_dict')
- command('let S = $XXX_NONEXISTENT_VAR_XXX')
+ command('let S = v:_null_string')
+ command('let V = $XXX_NONEXISTENT_VAR_XXX')
end)
local tmpfname = 'Xtest-functional-viml-null'
after_each(function()
@@ -129,6 +130,7 @@ describe('NULL', function()
null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0)
null_test('is accepted by :cexpr', 'cexpr L', 0)
null_test('is accepted by :lexpr', 'lexpr L', 0)
+ null_expr_test('does not crash execute()', 'execute(L)', 0, '')
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()
@@ -142,4 +144,26 @@ describe('NULL', function()
null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1)
null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1)
end)
+ describe('string', function()
+ null_test('does not crash :echomsg', 'echomsg S', 0)
+ null_test('does not crash :execute', 'execute S', 0)
+ null_expr_test('does not crash execute()', 'execute(S)', 0, '')
+ null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0)
+ null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0)
+ null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0)
+ null_expr_test('does not crash fnamemodify()', 'fnamemodify(S, S)', 0, '')
+ null_expr_test('does not crash getfperm()', 'getfperm(S)', 0, '')
+ null_expr_test('does not crash getfsize()', 'getfsize(S)', 0, -1)
+ null_expr_test('does not crash getftime()', 'getftime(S)', 0, -1)
+ null_expr_test('does not crash getftype()', 'getftype(S)', 0, '')
+ null_expr_test('does not crash glob()', 'glob(S)', 0, '')
+ null_expr_test('does not crash globpath()', 'globpath(S, S)', 0, '')
+ null_expr_test('does not crash mkdir()', 'mkdir(S)', 0, 0)
+ null_expr_test('does not crash sort()', 'sort(["b", S, "a"])', 0, {'', 'a', 'b'})
+ null_expr_test('does not crash split()', 'split(S)', 0, {})
+
+ null_test('can be used to set an option', 'let &grepprg = S', 0)
+
+ null_expr_test('is equal to non-existent variable', 'S == V', 0, 1)
+ end)
end)
diff --git a/test/functional/eval/writefile_spec.lua b/test/functional/eval/writefile_spec.lua
index 0bb7523d7e..356680ba7c 100644
--- a/test/functional/eval/writefile_spec.lua
+++ b/test/functional/eval/writefile_spec.lua
@@ -59,6 +59,16 @@ describe('writefile()', function()
eq('\n', read_file(fname))
end)
+ it('writes list with a null string to a file', function()
+ eq(0, exc_exec(
+ ('call writefile([v:_null_string], "%s", "b")'):format(
+ fname)))
+ eq('', read_file(fname))
+ eq(0, exc_exec(('call writefile([v:_null_string], "%s")'):format(
+ fname)))
+ eq('\n', read_file(fname))
+ end)
+
it('appends to a file', function()
eq(nil, read_file(fname))
eq(0, funcs.writefile({'abc', 'def', 'ghi'}, fname))
diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua
index 5c67431221..e5c9a20db3 100644
--- a/test/functional/ex_cmds/dict_notifications_spec.lua
+++ b/test/functional/ex_cmds/dict_notifications_spec.lua
@@ -371,4 +371,79 @@ describe('VimL dictionary notifications', function()
eq(1, eval('g:called'))
end)
+ it('does not crash when using dictwatcherdel in callback', function()
+ source([[
+ let g:d = {}
+
+ function! W1(...)
+ " Delete current and following watcher.
+ call dictwatcherdel(g:d, '*', function('W1'))
+ call dictwatcherdel(g:d, '*', function('W2'))
+ try
+ call dictwatcherdel({}, 'meh', function('tr'))
+ catch
+ let g:exc = v:exception
+ endtry
+ endfunction
+ call dictwatcheradd(g:d, '*', function('W1'))
+
+ function! W2(...)
+ endfunction
+ call dictwatcheradd(g:d, '*', function('W2'))
+
+ let g:d.foo = 23
+ ]])
+ eq(23, eval('g:d.foo'))
+ eq("Vim(call):Couldn't find a watcher matching key and callback", eval('g:exc'))
+ end)
+
+ it('does not call watcher added in callback', function()
+ source([[
+ let g:d = {}
+ let g:calls = []
+
+ function! W1(...) abort
+ call add(g:calls, 'W1')
+ call dictwatcheradd(g:d, '*', function('W2'))
+ endfunction
+
+ function! W2(...) abort
+ call add(g:calls, 'W2')
+ endfunction
+
+ call dictwatcheradd(g:d, '*', function('W1'))
+ let g:d.foo = 23
+ ]])
+ eq(23, eval('g:d.foo'))
+ eq({"W1"}, eval('g:calls'))
+ end)
+
+ it('calls watcher deleted in callback', function()
+ source([[
+ let g:d = {}
+ let g:calls = []
+
+ function! W1(...) abort
+ call add(g:calls, "W1")
+ call dictwatcherdel(g:d, '*', function('W2'))
+ endfunction
+
+ function! W2(...) abort
+ call add(g:calls, "W2")
+ endfunction
+
+ call dictwatcheradd(g:d, '*', function('W1'))
+ call dictwatcheradd(g:d, '*', function('W2'))
+ let g:d.foo = 123
+
+ unlet g:d
+ let g:d = {}
+ call dictwatcheradd(g:d, '*', function('W2'))
+ call dictwatcheradd(g:d, '*', function('W1'))
+ let g:d.foo = 123
+ ]])
+ eq(123, eval('g:d.foo'))
+ eq({"W1", "W2", "W2", "W1"}, eval('g:calls'))
+ end)
+
end)
diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua
index aac2a9f469..33794eb50d 100644
--- a/test/functional/ex_cmds/excmd_spec.lua
+++ b/test/functional/ex_cmds/excmd_spec.lua
@@ -24,8 +24,6 @@ describe('Ex cmds', function()
pcall_err(command, ':menu 9999999999999999999999999999999999999999'))
eq('Vim(bdelete):E939: Positive count required',
pcall_err(command, ':bdelete 9999999999999999999999999999999999999999'))
- eq('Vim(retab):E487: Argument must be positive',
- pcall_err(command, ':retab 9999999999999999999999999999999999999999'))
assert_alive()
end)
end)
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
new file mode 100644
index 0000000000..16d0dfb6a1
--- /dev/null
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -0,0 +1,47 @@
+local helpers = require('test.functional.helpers')(after_each)
+local command = helpers.command
+local insert = helpers.insert
+local eq = helpers.eq
+local clear = helpers.clear
+local meths = helpers.meths
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+
+describe(':source', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('current buffer', function()
+ insert('let a = 2')
+ command('source')
+ eq('2', meths.exec('echo a', true))
+ end)
+
+ it('selection in current buffer', function()
+ insert(
+ 'let a = 2\n'..
+ 'let a = 3\n'..
+ 'let a = 4\n')
+
+ -- Source the 2nd line only
+ feed('ggjV')
+ feed_command(':source')
+ eq('3', meths.exec('echo a', true))
+
+ -- Source from 2nd line to end of file
+ feed('ggjVG')
+ feed_command(':source')
+ eq('4', meths.exec('echo a', true))
+ end)
+
+ it('multiline heredoc command', function()
+ insert(
+ 'lua << EOF\n'..
+ 'y = 4\n'..
+ 'EOF\n')
+
+ command('source')
+ eq('4', meths.exec('echo luaeval("y")', true))
+ end)
+end)
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 252db88b6b..bcd5e22492 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -70,11 +70,11 @@ local function expect_notification(method, params, ...)
..., "expect_notification", "message")
end
-local function expect_request(method, callback, ...)
+local function expect_request(method, handler, ...)
local req = read_message()
assert_eq(method, req.method,
..., "expect_request", "method")
- local err, result = callback(req.params)
+ local err, result = handler(req.params)
respond(req.id, err, result)
end
@@ -154,6 +154,7 @@ function tests.capabilities_for_client_supports_method()
hoverProvider = true;
definitionProvider = false;
referencesProvider = false;
+ codeLensProvider = { resolveProvider = true; };
}
}
end;
@@ -402,11 +403,11 @@ function tests.basic_check_buffer_open_and_change_incremental()
contentChanges = {
{
range = {
- start = { line = 1; character = 0; };
- ["end"] = { line = 2; character = 0; };
+ start = { line = 1; character = 3; };
+ ["end"] = { line = 1; character = 3; };
};
- rangeLength = 4;
- text = "boop\n";
+ rangeLength = 0;
+ text = "boop";
};
}
})
diff --git a/test/functional/fixtures/smile2.cat b/test/functional/fixtures/smile2.cat
new file mode 100644
index 0000000000..0feb32f293
--- /dev/null
+++ b/test/functional/fixtures/smile2.cat
@@ -0,0 +1,32 @@
+31,79
+[?25l:smile
+ oooo$$$$$$$$$$$$oooo(B
+ oo$$$$$$$$$$$$$$$$$$$$$$$$o(B
+ oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o(B o$(B $$(B o$(B
+ o(B $(B oo(B o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o(B $$(B $$(B $$o$(B
+ oo(B $(B $(B "$(B o$$$$$$$$$(B $$$$$$$$$$$$$(B $$$$$$$$$o(B $$$o$$o$(B
+ "$$$$$$o$(B o$$$$$$$$$(B $$$$$$$$$$$(B $$$$$$$$$$o(B $$$$$$$$(B
+ $$$$$$$(B $$$$$$$$$$$(B $$$$$$$$$$$(B $$$$$$$$$$$$$$$$$$$$$$$(B
+ $$$$$$$$$$$$$$$$$$$$$$$(B $$$$$$$$$$$$$(B $$$$$$$$$$$$$$(B """$$$(B
+ "$$$(B""""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B "$$$(B
+ $$$(B o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B "$$$o(B
+ o$$(B" $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B $$$o(B
+ $$$(B $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B" "$$$$$$ooooo$$$$o(B
+ o$$$oooo$$$$$(B $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B o$$$$$$$$$$$$$$$$$(B
+ $$$$$$$$(B"$$$$(B $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B $$$$(B""""""""
+ """" $$$$(B "$$$$$$$$$$$$$$$$$$$$$$$$$$$$(B" o$$$(B
+ "$$$o(B """$$$$$$$$$$$$$$$$$$(B"$$(B" $$$(B
+ $$$o(B "$$(B""$$$$$$(B"""" o$$$(B
+ $$$$o(B o$$$(B"
+ "$$$$o(B o$$$$$$o(B"$$$$o(B o$$$$(B
+ "$$$$$oo(B ""$$$$o$$$$$o(B o$$$$(B""
+ ""$$$$$oooo(B "$$$o$$$$$$$$$(B"""
+ ""$$$$$$$oo(B $$$$$$$$$$(B
+ """"$$$$$$$$$$$(B
+ $$$$$$$$$$$$(B
+ $$$$$$$$$$(B"
+ "$$$(B""""
+
+Press ENTER or type command to continue(B
+(Bterm://~/config2/docs/pres//32693:vim --clean +smile 29,39 All
+(B:call nvim__screenshot("smile2.cat") [?25h \ No newline at end of file
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index 5f7bbd887f..97ac96804e 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -157,8 +157,8 @@ describe('memory usage', function()
-- The usage may be a bit less than the last value, use 80%.
-- Allow for 20% tolerance at the upper limit. That's very permissive, but
-- otherwise the test fails sometimes. On Sourcehut CI with FreeBSD we need to
- -- be even more permissive.
- local upper_multiplier = uname() == 'freebsd' and 15 or 12
+ -- be even much more permissive.
+ local upper_multiplier = uname() == 'freebsd' and 19 or 12
local lower = before.last * 8 / 10
local upper = load_adjust((after.max + (after.last - before.last)) * upper_multiplier / 10)
check_result({before=before, after=after, last=last},
diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua
index 1db7afc7a7..023cdd4ae1 100644
--- a/test/functional/legacy/options_spec.lua
+++ b/test/functional/legacy/options_spec.lua
@@ -1,6 +1,10 @@
+-- See also: src/nvim/testdir/test_options.vim
local helpers = require('test.functional.helpers')(after_each)
local command, clear = helpers.command, helpers.clear
local source, expect = helpers.source, helpers.expect
+local exc_exec = helpers.exc_exec;
+local matches = helpers.matches;
+local Screen = require('test.functional.ui.screen')
describe('options', function()
setup(clear)
@@ -11,7 +15,7 @@ describe('options', function()
end)
describe('set', function()
- setup(clear)
+ before_each(clear)
it("should keep two comma when 'path' is changed", function()
source([[
@@ -24,4 +28,59 @@ describe('set', function()
foo,,bar]])
end)
+
+ it('winminheight works', function()
+ local screen = Screen.new(20, 11)
+ screen:attach()
+ source([[
+ set wmh=0 stal=2
+ below sp | wincmd _
+ below sp | wincmd _
+ below sp | wincmd _
+ below sp
+ ]])
+ matches('E36: Not enough room', exc_exec('set wmh=1'))
+ end)
+
+ it('winminheight works with tabline', function()
+ local screen = Screen.new(20, 11)
+ screen:attach()
+ source([[
+ set wmh=0 stal=2
+ split
+ split
+ split
+ split
+ tabnew
+ ]])
+ matches('E36: Not enough room', exc_exec('set wmh=1'))
+ end)
+
+ it('scroll works', function()
+ local screen = Screen.new(42, 16)
+ screen:attach()
+ source([[
+ set scroll=2
+ set laststatus=2
+ ]])
+ command('verbose set scroll?')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ scroll=7 |
+ Last set from changed window size |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
end)
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 67dc5f5a16..5da8452a51 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -1,5 +1,6 @@
-- Test suite for testing interactions with API bindings
local helpers = require('test.functional.helpers')(after_each)
+local lfs = require('lfs')
local command = helpers.command
local meths = helpers.meths
@@ -9,8 +10,9 @@ local eq = helpers.eq
local fail = helpers.fail
local exec_lua = helpers.exec_lua
local feed = helpers.feed
-local deepcopy = helpers.deepcopy
local expect_events = helpers.expect_events
+local write_file = helpers.write_file
+local dedent = helpers.dedent
local origlines = {"original line 1",
"original line 2",
@@ -20,19 +22,20 @@ local origlines = {"original line 1",
"original line 6",
" indented line"}
-local function attach_buffer(evname)
- exec_lua([[
+before_each(function ()
+ clear()
+ exec_lua [[
local evname = ...
local events = {}
- function test_register(bufnr, id, changedtick, utf_sizes, preview)
+ function test_register(bufnr, evname, id, changedtick, utf_sizes, preview)
local function callback(...)
table.insert(events, {id, ...})
if test_unreg == id then
return true
end
end
- local opts = {[evname]=callback, on_detach=callback, utf_sizes=utf_sizes, preview=preview}
+ local opts = {[evname]=callback, on_detach=callback, on_reload=callback, utf_sizes=utf_sizes, preview=preview}
if changedtick then
opts.on_changedtick = callback
end
@@ -44,41 +47,30 @@ local function attach_buffer(evname)
events = {}
return ret_events
end
- ]], evname)
-end
+ ]]
+end)
describe('lua buffer event callbacks: on_lines', function()
- before_each(function()
- clear()
- attach_buffer('on_lines')
- end)
-
-
- -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
- -- assert the wrong thing), but masks errors with unflushed lines (as
- -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
- -- test both ways.
- local function check(verify,utf_sizes)
+ local function setup_eventcheck(verify, utf_sizes, lines)
local lastsize
- meths.buf_set_lines(0, 0, -1, true, origlines)
+ meths.buf_set_lines(0, 0, -1, true, lines)
if verify then
lastsize = meths.buf_get_offset(0, meths.buf_line_count(0))
end
- exec_lua("return test_register(...)", 0, "test1",false,utf_sizes)
- local tick = meths.buf_get_changedtick(0)
-
+ exec_lua("return test_register(...)", 0, "on_lines", "test1",false,utf_sizes)
local verify_name = "test1"
+
local function check_events(expected)
local events = exec_lua("return get_events(...)" )
if utf_sizes then
-- this test case uses ASCII only, so sizes should be the same.
-- Unicode is tested below.
for _, event in ipairs(expected) do
- event[9] = event[8]
- event[10] = event[8]
+ event[9] = event[9] or event[8]
+ event[10] = event[10] or event[9]
end
end
- eq(expected, events)
+ expect_events(expected, events, "line updates")
if verify then
for _, event in ipairs(events) do
if event[1] == verify_name and event[2] == "lines" then
@@ -92,25 +84,38 @@ describe('lua buffer event callbacks: on_lines', function()
end
end
end
+ return check_events, function(new) verify_name = new end
+ end
+
+
+ -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
+ -- assert the wrong thing), but masks errors with unflushed lines (as
+ -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
+ -- test both ways.
+ local function check(verify,utf_sizes)
+ local check_events, verify_name = setup_eventcheck(verify, utf_sizes, origlines)
+ local tick = meths.buf_get_changedtick(0)
command('set autoindent')
command('normal! GyyggP')
tick = tick + 1
- check_events({{ "test1", "lines", 1, tick, 0, 0, 1, 0}})
+ check_events {{ "test1", "lines", 1, tick, 0, 0, 1, 0}}
meths.buf_set_lines(0, 3, 5, true, {"changed line"})
tick = tick + 1
- check_events({{ "test1", "lines", 1, tick, 3, 5, 4, 32 }})
+ check_events {{ "test1", "lines", 1, tick, 3, 5, 4, 32 }}
- exec_lua("return test_register(...)", 0, "test2", true, utf_sizes)
+ exec_lua("return test_register(...)", 0, "on_lines", "test2", true, utf_sizes)
tick = tick + 1
command('undo')
-- plugins can opt in to receive changedtick events, or choose
-- to only receive actual changes.
- check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 },
- { "test2", "lines", 1, tick, 3, 4, 5, 13 },
- { "test2", "changedtick", 1, tick+1 } })
+ check_events {
+ { "test1", "lines", 1, tick, 3, 4, 5, 13 };
+ { "test2", "lines", 1, tick, 3, 4, 5, 13 };
+ { "test2", "changedtick", 1, tick+1 };
+ }
tick = tick + 1
-- simulate next callback returning true
@@ -121,38 +126,40 @@ describe('lua buffer event callbacks: on_lines', function()
-- plugins can opt in to receive changedtick events, or choose
-- to only receive actual changes.
- check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 },
- { "test2", "lines", 1, tick, 6, 7, 9, 16 }})
+ check_events {
+ { "test1", "lines", 1, tick, 6, 7, 9, 16 };
+ { "test2", "lines", 1, tick, 6, 7, 9, 16 };
+ }
- verify_name = "test2"
+ verify_name "test2"
meths.buf_set_lines(0, 1, 1, true, {"added"})
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 1, 1, 2, 0 }})
+ check_events {{ "test2", "lines", 1, tick, 1, 1, 2, 0 }}
feed('wix')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 16 }})
+ check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 16 }}
-- check hot path for multiple insert
feed('yz')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 17 }})
+ check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 17 }}
feed('<bs>')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 19 }})
+ check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 19 }}
feed('<esc>Go')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 11, 11, 12, 0 }})
+ check_events {{ "test2", "lines", 1, tick, 11, 11, 12, 0 }}
feed('x')
tick = tick + 1
- check_events({{ "test2", "lines", 1, tick, 11, 12, 12, 5 }})
+ check_events {{ "test2", "lines", 1, tick, 11, 12, 12, 5 }}
command('bwipe!')
- check_events({{ "test2", "detach", 1 }})
+ check_events {{ "test2", "detach", 1 }}
end
it('works', function()
@@ -167,51 +174,63 @@ describe('lua buffer event callbacks: on_lines', function()
check(false,true)
end)
- it('works with utf_sizes and unicode text', function()
+ local function check_unicode(verify)
local unicode_text = {"ascii text",
"latin text åäö",
"BMP text ɧ αλφά",
"BMP text 汉语 ↥↧",
"SMP 🤦 🦄🦃",
"combining å بِيَّة"}
- meths.buf_set_lines(0, 0, -1, true, unicode_text)
- feed('gg')
- exec_lua("return test_register(...)", 0, "test1", false, true)
+ local check_events, verify_name = setup_eventcheck(verify, true, unicode_text)
+
local tick = meths.buf_get_changedtick(0)
- feed('dd')
+ feed('ggdd')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}
feed('A<bs>')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}
feed('<esc>jylp')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}
feed('+eea<cr>')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}
feed('<esc>jdw')
tick = tick + 1
-- non-BMP chars count as 2 UTF-2 codeunits
- eq({{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}
feed('+rx')
tick = tick + 1
-- count the individual codepoints of a composed character.
- eq({{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+ check_events {{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}
feed('kJ')
tick = tick + 1
+ -- verification fails with multiple line updates, sorry about that
+ verify_name ""
-- NB: this is inefficient (but not really wrong).
- eq({{ "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 },
- { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+ check_events {
+ { "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 };
+ { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 };
+ }
+ end
+
+ it('works with utf_sizes and unicode text', function()
+ check_unicode(false)
+ end)
+
+ it('works with utf_sizes and unicode text with verify', function()
+ check_unicode(true)
end)
+
it('has valid cursor position while shifting', function()
meths.buf_set_lines(0, 0, -1, true, {'line1'})
exec_lua([[
@@ -225,6 +244,14 @@ describe('lua buffer event callbacks: on_lines', function()
eq(1, meths.get_var('listener_cursor_line'))
end)
+ it('has valid cursor position while deleting lines', function()
+ meths.buf_set_lines(0, 0, -1, true, { "line_1", "line_2", "line_3", "line_4"})
+ meths.win_set_cursor(0, {2, 0})
+ eq(2, meths.win_get_cursor(0)[1])
+ meths.buf_set_lines(0, 0, -1, true, { "line_1", "line_2", "line_3"})
+ eq(2, meths.win_get_cursor(0)[1])
+ end)
+
it('does not SEGFAULT when calling win_findbuf in on_detach', function()
exec_lua[[
@@ -272,26 +299,24 @@ describe('lua buffer event callbacks: on_lines', function()
end)
describe('lua: nvim_buf_attach on_bytes', function()
- before_each(function()
- clear()
- attach_buffer('on_bytes')
- end)
-
-- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
-- assert the wrong thing), but masks errors with unflushed lines (as
-- nvim_buf_get_offset forces a flush of the memline). To be safe run the
-- test both ways.
local function setup_eventcheck(verify, start_txt)
- meths.buf_set_lines(0, 0, -1, true, start_txt)
- local shadow = deepcopy(start_txt)
- local shadowbytes = table.concat(shadow, '\n') .. '\n'
+ if start_txt then
+ meths.buf_set_lines(0, 0, -1, true, start_txt)
+ else
+ start_txt = meths.buf_get_lines(0, 0, -1, true)
+ end
+ local shadowbytes = table.concat(start_txt, '\n') .. '\n'
-- TODO: while we are brewing the real strong coffe,
-- verify should check buf_get_offset after every check_events
if verify then
local len = meths.buf_get_offset(0, meths.buf_line_count(0))
eq(len == -1 and 1 or len, string.len(shadowbytes))
end
- exec_lua("return test_register(...)", 0, "test1", false, false, true)
+ exec_lua("return test_register(...)", 0, "on_bytes", "test1", false, false, true)
meths.buf_get_changedtick(0)
local verify_name = "test1"
@@ -318,6 +343,8 @@ describe('lua: nvim_buf_attach on_bytes', function()
local unknown = string.rep('\255', new_byte)
local after = string.sub(shadowbytes, start_byte + old_byte + 1)
shadowbytes = before .. unknown .. after
+ elseif event[1] == verify_name and event[2] == "reload" then
+ shadowbytes = table.concat(meths.buf_get_lines(0, 0, -1, true), '\n') .. '\n'
end
end
@@ -434,6 +461,36 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+ it("deleting lines", function()
+ local check_events = setup_eventcheck(verify, origlines)
+
+ feed("dd")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 };
+ }
+
+ feed("d2j")
+
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 0, 0, 3, 0, 48, 0, 0, 0 };
+ }
+
+ feed("ld<c-v>2j")
+
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 1, 1, 16, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 2, 1, 31, 0, 1, 1, 0, 0, 0 };
+ }
+
+ feed("vjwd")
+
+ check_events {
+ { "test1", "bytes", 1, 10, 0, 1, 1, 1, 9, 23, 0, 0, 0 };
+ }
+ end)
+
it("changing lines", function()
local check_events = setup_eventcheck(verify, origlines)
@@ -495,20 +552,79 @@ describe('lua: nvim_buf_attach on_bytes', function()
end)
- it('inccomand=nosplit and substitute', function()
- if verify then pending("Verification can't be done when previewing") end
+ it("linewise paste", function()
+ local check_events = setup_eventcheck(verify, origlines)
+
+ feed'yyp'
+ check_events {
+ { "test1", "bytes", 1, 3, 1, 0, 16, 0, 0, 0, 1, 0, 16 };
+ }
+
+ feed'Gyyp'
+ check_events {
+ { "test1", "bytes", 1, 4, 8, 0, 130, 0, 0, 0, 1, 0, 18 };
+ }
+ end)
- local check_events = setup_eventcheck(verify, {"abcde"})
+ it('inccomand=nosplit and substitute', function()
+ local check_events = setup_eventcheck(verify,
+ {"abcde", "12345"})
meths.set_option('inccommand', 'nosplit')
- feed ':%s/bcd/'
+ -- linewise substitute
+ feed(':%s/bcd/')
check_events {
{ "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 };
}
- feed 'a'
+ feed('a')
check_events {
{ "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 };
+ }
+
+ feed("<esc>")
+
+ -- splitting lines
+ feed([[:%s/abc/\r]])
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 1, 0, 1 };
+ { "test1", "bytes", 1, 6, 0, 0, 0, 1, 0, 1, 0, 3, 3 };
+ }
+
+ feed("<esc>")
+ -- multi-line regex
+ feed([[:%s/de\n123/a]])
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 3, 3, 1, 3, 6, 0, 1, 1 };
+ { "test1", "bytes", 1, 6, 0, 3, 3, 0, 1, 1, 1, 3, 6 };
+ }
+
+ feed("<esc>")
+ -- replacing with unicode
+ feed(":%s/b/→")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 3, 3 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 3, 3, 0, 1, 1 };
+ }
+
+ feed("<esc>")
+ -- replacing with escaped characters
+ feed([[:%s/b/\\]])
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ }
+
+ feed("<esc>")
+ -- replacing with expression register
+ feed([[:%s/b/\=5+5]])
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 };
}
end)
@@ -575,6 +691,256 @@ describe('lua: nvim_buf_attach on_bytes', function()
"original line 5", "original line 6" },
meths.buf_get_lines(0, 0, -1, true))
end)
+
+ it('checktime autoread', function()
+ write_file("Xtest-reload", dedent [[
+ old line 1
+ old line 2]])
+ lfs.touch("Xtest-reload", os.time() - 10)
+ command "e Xtest-reload"
+ command "set autoread"
+
+ local check_events = setup_eventcheck(verify, nil)
+
+ write_file("Xtest-reload", dedent [[
+ new line 1
+ new line 2
+ new line 3]])
+
+ command "checktime"
+ check_events {
+ { "test1", "reload", 1 };
+ }
+
+ feed 'ggJ'
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 10, 10, 1, 0, 1, 0, 1, 1 };
+ }
+
+ eq({'new line 1 new line 2', 'new line 3'}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- check we can undo and redo a reload event.
+ feed 'u'
+ check_events {
+ { "test1", "bytes", 1, 8, 0, 10, 10, 0, 1, 1, 1, 0, 1 };
+ }
+
+ feed 'u'
+ check_events {
+ { "test1", "reload", 1 };
+ }
+
+ feed '<c-r>'
+ check_events {
+ { "test1", "reload", 1 };
+ }
+
+ feed '<c-r>'
+ check_events {
+ { "test1", "bytes", 1, 14, 0, 10, 10, 1, 0, 1, 0, 1, 1 };
+ }
+ end)
+
+ it("tab with noexpandtab and softtabstop", function()
+ command("set noet")
+ command("set ts=4")
+ command("set sw=2")
+ command("set sts=4")
+
+ local check_events = setup_eventcheck(verify, {'asdfasdf'})
+
+ feed("gg0i<tab>")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
+ }
+ feed("<tab>")
+
+ -- when spaces are merged into a tabstop
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 2, 2, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 6, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
+ }
+
+
+ feed("<esc>u")
+ check_events {
+ { "test1", "bytes", 1, 8, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
+ { "test1", "bytes", 1, 8, 0, 0, 0, 0, 4, 4, 0, 0, 0 }
+ }
+
+ -- in REPLACE mode
+ feed("R<tab><tab>")
+ check_events {
+ { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 1, 1 },
+ { "test1", "bytes", 1, 10, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 11, 0, 2, 2, 0, 1, 1, 0, 1, 1 },
+ { "test1", "bytes", 1, 12, 0, 3, 3, 0, 0, 0, 0, 1, 1 },
+ { "test1", "bytes", 1, 13, 0, 0, 0, 0, 4, 4, 0, 1, 1 },
+ }
+ feed("<esc>u")
+ check_events {
+ { "test1", "bytes", 1, 14, 0, 0, 0, 0, 1, 1, 0, 4, 4 },
+ { "test1", "bytes", 1, 14, 0, 2, 2, 0, 2, 2, 0, 1, 1 },
+ { "test1", "bytes", 1, 14, 0, 0, 0, 0, 2, 2, 0, 1, 1 }
+ }
+
+ -- in VISUALREPLACE mode
+ feed("gR<tab><tab>")
+ check_events {
+ { "test1", "bytes", 1, 15, 0, 0, 0, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 16, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 17, 0, 2, 2, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 18, 0, 3, 3, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 19, 0, 3, 3, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 20, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 22, 0, 2, 2, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 23, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 25, 0, 1, 1, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 26, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 28, 0, 0, 0, 0, 1, 1, 0, 0, 0 };
+ { "test1", "bytes", 1, 29, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 31, 0, 0, 0, 0, 4, 4, 0, 1, 1 };
+ }
+
+ -- inserting tab after other tabs
+ command("set sw=4")
+ feed("<esc>0a<tab>")
+ check_events {
+ { "test1", "bytes", 1, 32, 0, 1, 1, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 33, 0, 2, 2, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 34, 0, 3, 3, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 35, 0, 4, 4, 0, 0, 0, 0, 1, 1 };
+ { "test1", "bytes", 1, 36, 0, 1, 1, 0, 4, 4, 0, 1, 1 };
+ }
+ end)
+
+ it("retab", function()
+ command("set noet")
+ command("set ts=4")
+
+ local check_events = setup_eventcheck(verify, {" asdf"})
+ command("retab 8")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 7, 7, 0, 9, 9 };
+ }
+ end)
+
+ it("sends events when undoing with undofile", function()
+ write_file("Xtest-undofile", dedent([[
+ 12345
+ hello world
+ ]]))
+
+ command("e! Xtest-undofile")
+ command("set undodir=. | set undofile")
+
+ local ns = helpers.request('nvim_create_namespace', "ns1")
+ meths.buf_set_extmark(0, ns, 0, 0, {})
+
+ eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- splice
+ feed("gg0d2l")
+
+ eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- move
+ command(".m+1")
+
+ eq({"hello world", "345"}, meths.buf_get_lines(0, 0, -1, true))
+
+ -- reload undofile and undo changes
+ command("w")
+ command("set noundofile")
+ command("bw!")
+ command("e! Xtest-undofile")
+
+ command("set undofile")
+
+ local check_events = setup_eventcheck(verify, nil)
+
+ feed("u")
+ eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ check_events {
+ { "test1", "bytes", 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 },
+ { "test1", "bytes", 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 }
+ }
+
+ feed("u")
+ eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true))
+
+ check_events {
+ { "test1", "bytes", 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 }
+ }
+ command("bw!")
+ end)
+
+ it("blockwise paste with uneven line lengths", function()
+ local check_events = setup_eventcheck(verify, {'aaaa', 'aaa', 'aaa'})
+
+ -- eq({}, meths.buf_get_lines(0, 0, -1, true))
+ feed("gg0<c-v>jj$d")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0 },
+ { "test1", "bytes", 1, 3, 1, 0, 1, 0, 3, 3, 0, 0, 0 },
+ { "test1", "bytes", 1, 3, 2, 0, 2, 0, 3, 3, 0, 0, 0 },
+ }
+
+ feed("p")
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4 },
+ { "test1", "bytes", 1, 4, 1, 0, 5, 0, 0, 0, 0, 3, 3 },
+ { "test1", "bytes", 1, 4, 2, 0, 9, 0, 0, 0, 0, 3, 3 },
+ }
+
+ end)
+
+ it(":luado", function()
+ local check_events = setup_eventcheck(verify, {"abc", "12345"})
+
+ command(".luado return 'a'")
+
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 0, 1, 1 };
+ }
+
+ command("luado return 10")
+
+ check_events {
+ { "test1", "bytes", 1, 4, 0, 0, 0, 0, 1, 1, 0, 2, 2 };
+ { "test1", "bytes", 1, 5, 1, 0, 3, 0, 5, 5, 0, 2, 2 };
+ }
+
+ end)
+
+ it("flushes deleted bytes on move", function()
+ local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC", "DDD"})
+
+ feed(":.move+1<cr>")
+
+ check_events {
+ { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 4, 0, 0, 0 };
+ { "test1", "bytes", 1, 5, 1, 0, 4, 0, 0, 0, 1, 0, 4 };
+ }
+
+ feed("jd2j")
+
+ check_events {
+ { "test1", "bytes", 1, 6, 2, 0, 8, 2, 0, 8, 0, 0, 0 };
+ }
+ end)
+
+ teardown(function()
+ os.remove "Xtest-reload"
+ os.remove "Xtest-undofile"
+ os.remove ".Xtest-undofile.un~"
+ end)
end
describe('(with verify) handles', function()
diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua
new file mode 100644
index 0000000000..3ba7e1589f
--- /dev/null
+++ b/test/functional/lua/command_line_completion_spec.lua
@@ -0,0 +1,171 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+
+local get_completions = function(input, env)
+ return exec_lua("return {vim._expand_pat(...)}", '^' .. input, env)
+end
+
+local get_compl_parts = function(parts)
+ return exec_lua("return {vim._expand_pat_get_parts(...)}", parts)
+end
+
+before_each(clear)
+
+describe('nlua_expand_pat', function()
+ it('should complete exact matches', function()
+ eq({{'exact'}, 0}, get_completions('exact', { exact = true }))
+ end)
+
+ it('should return empty table when nothing matches', function()
+ eq({{}, 0}, get_completions('foo', { bar = true }))
+ end)
+
+ it('should return nice completions with function call prefix', function()
+ eq({{'FOO'}, 6}, get_completions('print(F', { FOO = true, bawr = true }))
+ end)
+
+ it('should return keys for nested dictionaries', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 8
+ },
+ get_completions('vim.api.nvim_buf_', {
+ vim = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('it should work with colons', function()
+ eq(
+ {{
+ 'bawr',
+ 'baz',
+ }, 8
+ },
+ get_completions('MyClass:b', {
+ MyClass = {
+ baz = true,
+ bawr = true,
+ foo = false,
+ }
+ })
+ )
+ end)
+
+ it('should return keys for string reffed dictionaries', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 11
+ },
+ get_completions('vim["api"].nvim_buf_', {
+ vim = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('should return keys for string reffed dictionaries', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 21
+ },
+ get_completions('vim["nested"]["api"].nvim_buf_', {
+ vim = {
+ nested = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('should be able to interpolate globals', function()
+ eq(
+ {{
+ 'nvim_buf_set_lines',
+ 'nvim_buf_set_option'
+ }, 12
+ },
+ get_completions('vim[MY_VAR].nvim_buf_', {
+ MY_VAR = "api",
+ vim = {
+ api = {
+ nvim_buf_set_lines = true,
+ nvim_buf_set_option = true,
+ nvim_win_doesnt_match = true,
+ },
+ other_key = true,
+ }
+ })
+ )
+ end)
+
+ it('should return everything if the input is of length 0', function()
+ eq({{"other", "vim"}, 0}, get_completions('', { vim = true, other = true }))
+ end)
+
+ describe('get_parts', function()
+ it('should return an empty list for no separators', function()
+ eq({{}, 1}, get_compl_parts("vim"))
+ end)
+
+ it('just the first item before a period', function()
+ eq({{"vim"}, 5}, get_compl_parts("vim.ap"))
+ end)
+
+ it('should return multiple parts just for period', function()
+ eq({{"vim", "api"}, 9}, get_compl_parts("vim.api.nvim_buf"))
+ end)
+
+ it('should be OK with colons', function()
+ eq({{"vim", "api"}, 9}, get_compl_parts("vim:api.nvim_buf"))
+ end)
+
+ it('should work for just one string ref', function()
+ eq({{"vim", "api"}, 12}, get_compl_parts("vim['api'].nvim_buf"))
+ end)
+
+ it('should work for just one string ref, with double quote', function()
+ eq({{"vim", "api"}, 12}, get_compl_parts('vim["api"].nvim_buf'))
+ end)
+
+ it('should allows back-to-back string ref', function()
+ eq({{"vim", "nested", "api"}, 22}, get_compl_parts('vim["nested"]["api"].nvim_buf'))
+ end)
+
+ it('should allows back-to-back string ref with spaces before and after', function()
+ eq({{"vim", "nested", "api"}, 25}, get_compl_parts('vim[ "nested" ]["api"].nvim_buf'))
+ end)
+
+ it('should allow VAR style loolup', function()
+ eq({{"vim", {"NESTED"}, "api"}, 20}, get_compl_parts('vim[NESTED]["api"].nvim_buf'))
+ end)
+ end)
+end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index e253db5297..9bf00b594b 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -715,6 +715,11 @@ describe('lua stdlib', function()
eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
end)
+ it('vim.fn should error when calling API function', function()
+ eq('Error executing lua: vim.lua:0: Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead',
+ pcall_err(exec_lua, "vim.fn.nvim_get_current_line()"))
+ end)
+
it('vim.rpcrequest and vim.rpcnotify', function()
exec_lua([[
chan = vim.fn.jobstart({'cat'}, {rpc=true})
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 4705a76465..8c91c4ab2c 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -208,6 +208,69 @@ describe('vim.lsp.diagnostic', function()
]]))
end)
+ describe('reset', function()
+ it('diagnostic count is 0 and displayed diagnostics are 0 after call', function()
+ -- 1 Error (1)
+ -- 1 Warning (2)
+ -- 1 Warning (2) + 1 Warning (1)
+ -- 2 highlights and 2 underlines (since error)
+ -- 1 highlight + 1 underline
+ local all_highlights = {1, 1, 2, 4, 2}
+ eq(all_highlights, exec_lua [[
+ local server_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local server_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1)
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2)
+ return {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]])
+
+ -- Reset diagnostics from server 1
+ exec_lua([[ vim.lsp.diagnostic.reset(1, { [ diagnostic_bufnr ] = { [ 1 ] = true ; [ 2 ] = true } } )]])
+
+ -- Make sure we have the right diagnostic count
+ eq({0, 1, 1, 0, 2} , exec_lua [[
+ local diagnostic_count = {}
+ vim.wait(100, function () diagnostic_count = {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ } end )
+ return diagnostic_count
+ ]])
+
+ -- Reset diagnostics from server 2
+ exec_lua([[ vim.lsp.diagnostic.reset(2, { [ diagnostic_bufnr ] = { [ 1 ] = true ; [ 2 ] = true } } )]])
+
+ -- Make sure we have the right diagnostic count
+ eq({0, 0, 0, 0, 0}, exec_lua [[
+ local diagnostic_count = {}
+ vim.wait(100, function () diagnostic_count = {
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
+ vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", nil),
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ } end )
+ return diagnostic_count
+ ]])
+
+ end)
+ end)
+
describe('get_next_diagnostic_pos', function()
it('can find the next pos with only one client', function()
eq({1, 1}, exec_lua [[
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 41fdf845df..557f8a206f 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -11,6 +11,8 @@ local pesc = helpers.pesc
local insert = helpers.insert
local retry = helpers.retry
local NIL = helpers.NIL
+local read_file = require('test.helpers').read_file
+local write_file = require('test.helpers').write_file
-- Use these to get access to a coroutine so that I can run async tests and use
-- yield.
@@ -27,13 +29,24 @@ teardown(function()
os.remove(fake_lsp_logfile)
end)
-local function fake_lsp_server_setup(test_name, timeout_ms)
+local function clear_notrace()
+ -- problem: here be dragons
+ -- solution: don't look for dragons to closely
+ clear {env={
+ NVIM_LUA_NOTRACK="1";
+ VIMRUNTIME=os.getenv"VIMRUNTIME";
+ }}
+end
+
+
+local function fake_lsp_server_setup(test_name, timeout_ms, options)
exec_lua([=[
lsp = require('vim.lsp')
- local test_name, fixture_filename, logfile, timeout = ...
+ local test_name, fixture_filename, logfile, timeout, options = ...
TEST_RPC_CLIENT_ID = lsp.start_client {
cmd_env = {
NVIM_LOG_FILE = logfile;
+ NVIM_LUA_NOTRACK = "1";
};
cmd = {
vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
@@ -41,10 +54,10 @@ local function fake_lsp_server_setup(test_name, timeout_ms)
"-c", string.format("lua TIMEOUT = %d", timeout),
"-c", "luafile "..fixture_filename,
};
- callbacks = setmetatable({}, {
+ handlers = setmetatable({}, {
__index = function(t, method)
return function(...)
- return vim.rpcrequest(1, 'callback', ...)
+ return vim.rpcrequest(1, 'handler', ...)
end
end;
});
@@ -52,18 +65,19 @@ local function fake_lsp_server_setup(test_name, timeout_ms)
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;
on_exit = function(...)
vim.rpcnotify(1, "exit", ...)
end;
}
- ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3)
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {})
end
local function test_rpc_server(config)
if config.test_name then
- clear()
- fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3)
+ clear_notrace()
+ fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options)
end
local client = setmetatable({}, {
__index = function(_, name)
@@ -89,7 +103,7 @@ local function test_rpc_server(config)
end
return NIL
end
- if method == 'callback' then
+ if method == 'handler' then
if config.on_callback then
config.on_callback(unpack(args))
end
@@ -117,7 +131,7 @@ end
describe('LSP', function()
describe('server_name specified', function()
before_each(function()
- clear()
+ clear_notrace()
-- Run an instance of nvim on the file which contains our "scripts".
-- Pass TEST_NAME to pick the script.
local test_name = "basic_init"
@@ -193,13 +207,19 @@ describe('LSP', function()
end)
describe('basic_init test', function()
+ after_each(function()
+ stop()
+ exec_lua("lsp.stop_client(lsp.get_active_clients())")
+ exec_lua("lsp._vim_exit_handler()")
+ end)
+
it('should run correctly', function()
local expected_callbacks = {
{NIL, "test", {}, 1};
}
test_rpc_server {
test_name = "basic_init";
- on_init = function(client, _init_result)
+ on_init = function(client, _)
-- client is a dummy object which will queue up commands to be run
-- once the server initializes. It can't accept lua callbacks or
-- other types that may be unserializable for now.
@@ -241,6 +261,10 @@ describe('LSP', function()
end)
it('should succeed with manual shutdown', function()
+ if 'openbsd' == helpers.uname() then
+ pending('hangs the build on openbsd #14028, re-enable with freeze timeout #14204')
+ return
+ end
local expected_callbacks = {
{NIL, "shutdown", {}, 1, NIL};
{NIL, "test", {}, 1};
@@ -251,6 +275,7 @@ describe('LSP', function()
eq(0, client.resolved_capabilities().text_document_did_change)
client.request('shutdown')
client.notify('exit')
+ client.stop()
end;
on_exit = function(code, signal)
eq(0, code, "exit code", fake_lsp_logfile)
@@ -304,11 +329,9 @@ describe('LSP', function()
}
end)
it('workspace/configuration returns NIL per section if client was started without config.settings', function()
+ clear_notrace()
fake_lsp_server_setup('workspace/configuration no settings')
- eq({
- NIL,
- NIL,
- }, exec_lua [[
+ eq({ NIL, NIL, }, exec_lua [[
local params = {
items = {
{section = 'foo'},
@@ -329,6 +352,9 @@ describe('LSP', function()
client.stop()
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
eq(full_kind, client.resolved_capabilities().text_document_did_change)
+ eq(true, client.resolved_capabilities().text_document_save)
+ eq(false, client.resolved_capabilities().code_lens)
+ eq(false, client.resolved_capabilities().code_lens_resolve)
end;
on_exit = function(code, signal)
eq(0, code, "exit code", fake_lsp_logfile)
@@ -354,6 +380,8 @@ describe('LSP', function()
eq(true, client.resolved_capabilities().hover)
eq(false, client.resolved_capabilities().goto_definition)
eq(false, client.resolved_capabilities().rename)
+ eq(true, client.resolved_capabilities().code_lens)
+ eq(true, client.resolved_capabilities().code_lens_resolve)
-- known methods for resolved capabilities
eq(true, client.supports_method("textDocument/hover"))
@@ -382,7 +410,7 @@ describe('LSP', function()
exec_lua([=[
BUFFER = vim.api.nvim_get_current_buf()
lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.lsp.callbacks['textDocument/typeDefinition'] = function(err, method)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function(err, method)
vim.lsp._last_lsp_callback = { err = err; method = method }
end
vim.lsp._unsupported_method = function(method)
@@ -421,7 +449,7 @@ describe('LSP', function()
test_name = "capabilities_for_client_supports_method";
on_setup = function()
exec_lua([=[
- vim.lsp.callbacks['textDocument/typeDefinition'] = function(err, method)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function(err, method)
vim.lsp._last_lsp_callback = { err = err; method = method }
end
vim.lsp._unsupported_method = function(method)
@@ -675,8 +703,7 @@ describe('LSP', function()
}
end)
- -- TODO(askhan) we don't support full for now, so we can disable these tests.
- pending('should check the body and didChange incremental', function()
+ it('should check the body and didChange incremental', function()
local expected_callbacks = {
{NIL, "shutdown", {}, 1};
{NIL, "finish", {}, 1};
@@ -685,6 +712,7 @@ describe('LSP', function()
local client
test_rpc_server {
test_name = "basic_check_buffer_open_and_change_incremental";
+ options = { allow_incremental_sync = true };
on_setup = function()
exec_lua [[
BUFFER = vim.api.nvim_create_buf(false, true)
@@ -711,7 +739,7 @@ describe('LSP', function()
if method == 'start' then
exec_lua [[
vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ "123boop";
})
]]
client.notify('finish')
@@ -893,8 +921,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_callback = function(err, method, params, client_id)
- eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback")
+ on_handler = function(err, method, params, client_id)
+ eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected handler")
end;
}
end)
@@ -928,7 +956,7 @@ end)
describe('LSP', function()
before_each(function()
- clear()
+ clear_notrace()
end)
local function make_edit(y_0, x_0, y_1, x_1, text)
@@ -1028,6 +1056,20 @@ describe('LSP', function()
'å ä ɧ 汉语 ↥ 🤦 🦄';
}, buf_lines(1))
end)
+ it('applies text edits at the end of the document', function()
+ local edits = {
+ make_edit(5, 0, 5, 0, "foobar");
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ 'Second line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ 'foobar';
+ }, buf_lines(1))
+ end)
describe('with LSP end line after what Vim considers to be the end line', function()
it('applies edits when the last linebreak is considered a new line', function()
@@ -1082,14 +1124,14 @@ describe('LSP', function()
'2nd line of 语text';
}, buf_lines(target_bufnr))
end)
- it('correctly goes ahead with the edit if the version is vim.NIL', function()
- -- we get vim.NIL when we decode json null value.
- local json = exec_lua[[
- return vim.fn.json_decode("{ \"a\": 1, \"b\": null }")
- ]]
- eq(json.b, exec_lua("return vim.NIL"))
-
- exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(exec_lua("return vim.NIL")))
+ it('always accepts edit with version = 0', function()
+ exec_lua([[
+ local args = {...}
+ 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)
+ ]], target_bufnr, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text';
'2nd line of 语text';
@@ -1238,6 +1280,99 @@ describe('LSP', function()
return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
]], make_workspace_edit(edits), target_bufnr))
end)
+ it('Supports file creation with CreateFile payload', function()
+ local tmpfile = helpers.tmpname()
+ os.remove(tmpfile) -- Should not exist, only interested in a tmpname
+ local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
+ local edit = {
+ documentChanges = {
+ {
+ kind = 'create',
+ uri = uri,
+ },
+ }
+ }
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ 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()
+ local tmpfile = helpers.tmpname()
+ write_file(tmpfile, 'Dummy content')
+ local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
+ local edit = {
+ documentChanges = {
+ {
+ kind = 'create',
+ uri = uri,
+ options = {
+ ignoreIfExists = true,
+ },
+ },
+ }
+ }
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq('Dummy content', read_file(tmpfile))
+ end)
+ it('createFile overrides file if overwrite is set', function()
+ local tmpfile = helpers.tmpname()
+ write_file(tmpfile, 'Dummy content')
+ local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
+ local edit = {
+ documentChanges = {
+ {
+ kind = 'create',
+ uri = uri,
+ options = {
+ overwrite = true,
+ ignoreIfExists = true, -- overwrite must win over ignoreIfExists
+ },
+ },
+ }
+ }
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ eq('', read_file(tmpfile))
+ end)
+ it('DeleteFile delete file and buffer', function()
+ local tmpfile = helpers.tmpname()
+ write_file(tmpfile, 'Be gone')
+ local uri = exec_lua([[
+ local fname = select(1, ...)
+ local bufnr = vim.fn.bufadd(fname)
+ vim.fn.bufload(bufnr)
+ return vim.uri_from_fname(fname)
+ ]], tmpfile)
+ local edit = {
+ documentChanges = {
+ {
+ kind = 'delete',
+ uri = uri,
+ }
+ }
+ }
+ eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
+ 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)
+ it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function()
+ local tmpfile = helpers.tmpname()
+ os.remove(tmpfile)
+ local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
+ local edit = {
+ documentChanges = {
+ {
+ kind = 'delete',
+ uri = uri,
+ options = {
+ ignoreIfNotExists = false,
+ }
+ }
+ }
+ }
+ eq(false, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
+ eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ end)
end)
describe('completion_list_to_complete_items', function()
@@ -1284,6 +1419,72 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.rename', function()
+ it('Can rename an existing file', function()
+ local old = helpers.tmpname()
+ write_file(old, 'Test content')
+ local new = helpers.tmpname()
+ os.remove(new) -- only reserve the name, file must not exist for the test scenario
+ local lines = exec_lua([[
+ local old = select(1, ...)
+ local new = select(2, ...)
+ vim.lsp.util.rename(old, new)
+
+ -- after rename the target file must have the contents of the source file
+ local bufnr = vim.fn.bufadd(new)
+ return vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
+ ]], old, new)
+ eq({'Test content'}, lines)
+ local exists = exec_lua('return vim.loop.fs_stat(...) ~= nil', old)
+ eq(false, exists)
+ exists = exec_lua('return vim.loop.fs_stat(...) ~= nil', new)
+ eq(true, exists)
+ os.remove(new)
+ end)
+ it('Does not rename file if target exists and ignoreIfExists is set or overwrite is false', function()
+ local old = helpers.tmpname()
+ write_file(old, 'Old File')
+ local new = helpers.tmpname()
+ write_file(new, 'New file')
+
+ exec_lua([[
+ local old = select(1, ...)
+ local new = select(2, ...)
+
+ vim.lsp.util.rename(old, new, { ignoreIfExists = true })
+ ]], old, new)
+
+ eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', old))
+ eq('New file', read_file(new))
+
+ exec_lua([[
+ local old = select(1, ...)
+ local new = select(2, ...)
+
+ vim.lsp.util.rename(old, new, { overwrite = false })
+ ]], old, new)
+
+ eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', old))
+ eq('New file', read_file(new))
+ end)
+ it('Does override target if overwrite is true', function()
+ local old = helpers.tmpname()
+ write_file(old, 'Old file')
+ local new = helpers.tmpname()
+ write_file(new, 'New file')
+ exec_lua([[
+ local old = select(1, ...)
+ local new = select(2, ...)
+
+ vim.lsp.util.rename(old, new, { overwrite = true })
+ ]], old, new)
+
+ eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', old))
+ eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new))
+ eq('Old file\n', read_file(new))
+ end)
+ end)
+
describe('lsp.util.locations_to_items', function()
it('Convert Location[] to items', function()
local expected = {
@@ -1761,8 +1962,8 @@ describe('LSP', function()
uri = "file:///src/main.rs"
}
} }
- local callback = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
- callback(nil, nil, rust_analyzer_response)
+ local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
+ handler(nil, nil, rust_analyzer_response)
return vim.fn.getqflist()
]=])
@@ -1833,8 +2034,8 @@ describe('LSP', function()
} }
} }
- local callback = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
- callback(nil, nil, rust_analyzer_response)
+ local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
+ handler(nil, nil, rust_analyzer_response)
return vim.fn.getqflist()
]=])
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 209537831f..c61bf108cb 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -258,6 +258,13 @@ describe(':terminal buffer', function()
it('handles wqall', function()
eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
end)
+
+ it('does not segfault when pasting empty buffer #13955', function()
+ feed_command('terminal')
+ feed('<c-\\><c-n>')
+ feed_command('put a') -- buffer a is empty
+ helpers.assert_alive()
+ end)
end)
describe('No heap-buffer-overflow when using', function()
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index cb73bfbbe1..05e0c5fe2c 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -445,7 +445,7 @@ describe('treesitter highlighting', function()
exec_lua [[
local parser = vim.treesitter.get_parser(0, "c", {
- queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}
+ injections = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}
})
local highlighter = vim.treesitter.highlighter
test_hl = highlighter.new(parser, {queries = {c = hl_query}})
@@ -472,4 +472,102 @@ describe('treesitter highlighting', function()
|
]]}
end)
+
+ it("supports overriding queries, like ", function()
+ if pending_c_parser(pending) then return end
+
+ insert([[
+ int x = INT_MAX;
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ #define foo void main() { \
+ return 42; \
+ }
+ ]])
+
+ exec_lua [[
+ local injection_query = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"
+ require('vim.treesitter.query').set_query("c", "highlights", hl_query)
+ require('vim.treesitter.query').set_query("c", "injections", injection_query)
+
+ vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, "c"))
+ ]]
+
+ screen:expect{grid=[[
+ {3:int} x = {5:INT_MAX}; |
+ #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))|
+ #define foo {3:void} main() { \ |
+ {4:return} {5:42}; \ |
+ } |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it("supports highlighting with custom highlight groups", function()
+ if pending_c_parser(pending) then return end
+
+ insert(hl_text)
+
+ exec_lua [[
+ local parser = vim.treesitter.get_parser(0, "c")
+ test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}})
+ ]]
+
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ -- This will change ONLY the literal strings to look like comments
+ -- The only literal string is the "vim.schedule: expected function" in this test.
+ exec_lua [[vim.cmd("highlight link cString comment")]]
+ screen:expect{grid=[[
+ {2:/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {2:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ screen:expect{ unchanged=true }
+ end)
end)
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index a5801271cb..afb17dd2cf 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -45,7 +45,7 @@ describe('treesitter API', function()
return {keys, lang.fields, symbols}
]]))
- eq({fields=true, symbols=true}, keys)
+ eq({fields=true, symbols=true, _abi_version=true}, keys)
local fset = {}
for _,f in pairs(fields) do
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index f99362fbdf..72ff6f2fb6 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -468,7 +468,7 @@ int x = INT_MAX;
it("should inject a language", function()
exec_lua([[
parser = vim.treesitter.get_parser(0, "c", {
- queries = {
+ injections = {
c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}})
]])
@@ -489,7 +489,7 @@ int x = INT_MAX;
it("should inject a language", function()
exec_lua([[
parser = vim.treesitter.get_parser(0, "c", {
- queries = {
+ injections = {
c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}})
]])
@@ -506,11 +506,39 @@ int x = INT_MAX;
end)
end)
+ describe("when providing parsing information through a directive", function()
+ it("should inject a language", function()
+ exec_lua([=[
+ vim.treesitter.add_directive("inject-clang!", function(match, _, _, pred, metadata)
+ metadata.language = "c"
+ metadata.combined = true
+ metadata.content = pred[2]
+ end)
+
+ parser = vim.treesitter.get_parser(0, "c", {
+ injections = {
+ c = "(preproc_def ((preproc_arg) @_c (#inject-clang! @_c)))" ..
+ "(preproc_function_def value: ((preproc_arg) @_a (#inject-clang! @_a)))"}})
+ ]=])
+
+ eq("table", exec_lua("return type(parser:children().c)"))
+ eq(2, exec_lua("return #parser:children().c:trees()"))
+ eq({
+ {0, 0, 7, 0}, -- root tree
+ {3, 14, 5, 18}, -- VALUE 123
+ -- VALUE1 123
+ -- VALUE2 123
+ {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
+ }, get_ranges())
+ end)
+ end)
+
describe("when using the offset directive", function()
it("should shift the range by the directive amount", function()
exec_lua([[
parser = vim.treesitter.get_parser(0, "c", {
- queries = {
+ injections = {
c = "(preproc_def ((preproc_arg) @c (#offset! @c 0 2 0 -1))) (preproc_function_def value: (preproc_arg) @c)"}})
]])
@@ -538,7 +566,7 @@ int x = INT_MAX;
it("should return the correct language tree", function()
local result = exec_lua([[
parser = vim.treesitter.get_parser(0, "c", {
- queries = { c = "(preproc_def (preproc_arg) @c)"}})
+ injections = { c = "(preproc_def (preproc_arg) @c)"}})
local sub_tree = parser:language_for_range({1, 18, 1, 19})
@@ -572,28 +600,5 @@ int x = INT_MAX;
eq(result, "value")
end)
end)
-
- describe("when setting for a capture match", function()
- it("should set/get the data correctly", function()
- insert([[
- int x = 3;
- ]])
-
- local result = exec_lua([[
- local result
-
- query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))')
- parser = vim.treesitter.get_parser(0, "c")
-
- for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do
- result = metadata[pattern].key
- end
-
- return result
- ]])
-
- eq(result, "value")
- end)
- end)
end)
end)
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 21c01b3458..0ea8bab957 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local command = helpers.command
+local assert_alive = helpers.assert_alive
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -758,6 +759,7 @@ local function test_cmdline(linegrid)
end)
it("doesn't send invalid events when aborting mapping #10000", function()
+ command('set notimeout')
command('cnoremap ab c')
feed(':xa')
@@ -842,3 +844,14 @@ describe('cmdline redraw', function()
]], unchanged=true}
end)
end)
+
+describe("cmdline height", function()
+ it("does not crash resized screen #14263", function()
+ clear()
+ local screen = Screen.new(25, 10)
+ screen:attach()
+ command('set cmdheight=9999')
+ screen:try_resize(25, 5)
+ assert_alive()
+ end)
+end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index e1a72ced05..f75f700fb5 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -212,10 +212,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end
end
if m.hl_id then
- m.hl_id = 55
+ m.hl_id = 56
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 56 end
+ if m.id_lm then m.id_lm = 57 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 781fdf7203..82d3075be2 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua
local exec = helpers.exec
local expect_events = helpers.expect_events
local meths = helpers.meths
+local command = helpers.command
describe('decorations providers', function()
local screen
@@ -28,6 +29,7 @@ describe('decorations providers', function()
[10] = {italic = true, background = Screen.colors.Magenta};
[11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')};
[12] = {foreground = tonumber('0x990000')};
+ [13] = {background = Screen.colors.LightBlue};
}
end)
@@ -178,7 +180,7 @@ describe('decorations providers', function()
|
]]}
- meths.set_hl_ns(ns1)
+ meths._set_hl_ns(ns1)
screen:expect{grid=[[
{10: 1 }{11:// just to see if there was an accid}|
{10: }{11:ent} |
@@ -204,7 +206,7 @@ describe('decorations providers', function()
local ns2 = a.nvim_create_namespace 'ns2'
a.nvim_set_decoration_provider (ns2, {
on_win = function (_, win, buf)
- a.nvim_set_hl_ns(win == thewin and _G.ns1 or ns2)
+ a.nvim__set_hl_ns(win == thewin and _G.ns1 or ns2)
end;
})
]]
@@ -251,7 +253,7 @@ describe('decorations providers', function()
]]}
meths.set_hl(ns1, 'LinkGroup', {fg = 'Blue'})
- meths.set_hl_ns(ns1)
+ meths._set_hl_ns(ns1)
screen:expect{grid=[[
// just to see if there was an accident |
@@ -287,7 +289,7 @@ describe('decorations providers', function()
]]}
meths.set_hl(ns1, 'LinkGroup', {fg = 'Blue', default=true})
- meths.set_hl_ns(ns1)
+ meths._set_hl_ns(ns1)
feed 'k'
screen:expect{grid=[[
@@ -301,4 +303,273 @@ describe('decorations providers', function()
|
]]}
end)
+
+ it('can have virtual text', function()
+ insert(mulholland)
+ setup_provider [[
+ local hl = a.nvim_get_hl_id_by_name "ErrorMsg"
+ local test_ns = a.nvim_create_namespace "mulholland"
+ function on_do(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
+ virt_text = {{'+', 'ErrorMsg'}};
+ virt_text_pos='overlay';
+ ephemeral = true;
+ })
+ end
+ end
+ ]]
+
+ screen:expect{grid=[[
+ {2:+}/ just to see if there was an accident |
+ {2:+}/ on Mulholland Drive |
+ {2:+}ry_start(); |
+ {2:+}ufref_T save_buf; |
+ {2:+}witch_buffer(&save_buf, buf); |
+ {2:+}osp = getmark(mark, false); |
+ {2:+}estore_buffer(&save_buf);^ |
+ |
+ ]]}
+ end)
+
+ it('can highlight beyond EOL', function()
+ insert(mulholland)
+ setup_provider [[
+ local test_ns = a.nvim_create_namespace "veberod"
+ function on_do(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ if string.find(a.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then
+ a.nvim_buf_set_extmark(buf, test_ns, line, 0, {
+ end_line = line+1;
+ hl_group = 'DiffAdd';
+ hl_eol = true;
+ ephemeral = true;
+ })
+ end
+ end
+ end
+ ]]
+
+ screen:expect{grid=[[
+ // just to see if there was an accident |
+ // on Mulholland Drive |
+ try_start(); |
+ {13:bufref_T save_buf; }|
+ {13:switch_buffer(&save_buf, buf); }|
+ posp = getmark(mark, false); |
+ {13:restore_buffer(&save_buf);^ }|
+ |
+ ]]}
+ end)
+end)
+
+describe('extmark decorations', function()
+ local screen
+ before_each( function()
+ clear()
+ screen = Screen.new(50, 15)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {foreground = Screen.colors.Brown};
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen};
+ [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100};
+ [5] = {foreground = Screen.colors.Brown, bold = true};
+ [6] = {foreground = Screen.colors.DarkCyan};
+ [7] = {foreground = Screen.colors.Grey0, background = tonumber('0xff4c4c')};
+ [8] = {foreground = tonumber('0x180606'), background = tonumber('0xff4c4c')};
+ [9] = {foreground = tonumber('0xe40c0c'), background = tonumber('0xff4c4c'), bold = true};
+ [10] = {foreground = tonumber('0xb20000'), background = tonumber('0xff4c4c')};
+ [11] = {blend = 30, background = Screen.colors.Red1};
+ [12] = {foreground = Screen.colors.Brown, blend = 30, background = Screen.colors.Red1, bold = true};
+ [13] = {foreground = Screen.colors.Fuchsia};
+ [14] = {background = Screen.colors.Red1, foreground = Screen.colors.Black};
+ [15] = {background = Screen.colors.Red1, foreground = tonumber('0xb20000')};
+ [16] = {blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1};
+ [17] = {bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey};
+ [18] = {background = Screen.colors.LightGrey};
+ [19] = {foreground = Screen.colors.Cyan4, background = Screen.colors.LightGrey};
+ [20] = {foreground = tonumber('0x180606'), background = tonumber('0xf13f3f')};
+ [21] = {foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f')};
+ [22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')};
+ [23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey};
+ [24] = {bold = true};
+ }
+ end)
+
+ local example_text = [[
+for _,item in ipairs(items) do
+ local text, hl_id_cell, count = unpack(item)
+ if hl_id_cell ~= nil then
+ hl_id = hl_id_cell
+ end
+ for _ = 1, (count or 1) do
+ local cell = line[colpos]
+ cell.text = text
+ cell.hl_id = hl_id
+ colpos = colpos+1
+ end
+end]]
+
+ it('can have virtual text of overlay position', function()
+ insert(example_text)
+ feed 'gg'
+
+ local ns = meths.create_namespace 'test'
+ for i = 1,9 do
+ meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'})
+ if i == 3 or (i >= 6 and i <= 9) then
+ meths.buf_set_extmark(0, ns, i, 4, { virt_text={{'|', 'NonText'}}, virt_text_pos='overlay'})
+ end
+ end
+ meths.buf_set_extmark(0, ns, 9, 10, { virt_text={{'foo'}, {'bar', 'MoreMsg'}, {'!!', 'ErrorMsg'}}, virt_text_pos='overlay'})
+
+ -- can "float" beyond end of line
+ meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
+ -- bound check: right edge of window
+ meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+
+ screen:expect{grid=[[
+ ^for _,item in ipairs(items) do |
+ {2:|} local text, hl_id_cell, count = unpack(item) |
+ {2:|} if hl_id_cell ~= nil tbork bork bork {4:bork bork}|
+ {2:|} {1:|} hl_id = hl_id_cell |
+ {2:|} end |
+ {2:|} for _ = 1, (count or 1) {4:loopy} |
+ {2:|} {1:|} local cell = line[colpos] |
+ {2:|} {1:|} cell.text = text |
+ {2:|} {1:|} cell.hl_id = hl_id |
+ {2:|} {1:|} cofoo{3:bar}{4:!!}olpos+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+
+ -- handles broken lines
+ screen:try_resize(22, 25)
+ screen:expect{grid=[[
+ ^for _,item in ipairs(i|
+ tems) do |
+ {2:|} local text, hl_id_|
+ cell, count = unpack(i|
+ tem) |
+ {2:|} if hl_id_cell ~= n|
+ il tbork bork bork {4:bor}|
+ {2:|} {1:|} hl_id = hl_id_|
+ cell |
+ {2:|} end |
+ {2:|} for _ = 1, (count |
+ or 1) {4:loopy} |
+ {2:|} {1:|} local cell = l|
+ ine[colpos] |
+ {2:|} {1:|} cell.text = te|
+ xt |
+ {2:|} {1:|} cell.hl_id = h|
+ l_id |
+ {2:|} {1:|} cofoo{3:bar}{4:!!}olpo|
+ s+1 |
+ end |
+ end |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('can have virtual text of overlay position and styling', function()
+ insert(example_text)
+ feed 'gg'
+ local ns = meths.create_namespace 'test'
+
+ command 'set ft=lua'
+ command 'syntax on'
+
+ screen:expect{grid=[[
+ {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
+ {5:local} text, hl_id_cell, count = unpack(item) |
+ {5:if} hl_id_cell ~= {13:nil} {5:then} |
+ hl_id = hl_id_cell |
+ {5:end} |
+ {5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do} |
+ {5:local} cell = line[colpos] |
+ cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+{13:1} |
+ {5:end} |
+ {5:end} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ command 'hi Blendy guibg=Red blend=30'
+ meths.buf_set_extmark(0, ns, 1, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend'})
+ meths.buf_set_extmark(0, ns, 2, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine'})
+ meths.buf_set_extmark(0, ns, 3, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace'})
+
+ meths.buf_set_extmark(0, ns, 4, 5, { virt_text={{'blendy text - here', 'Blendy'}}, virt_text_pos='overlay', hl_mode='blend', virt_text_hide=true})
+ meths.buf_set_extmark(0, ns, 5, 5, { virt_text={{'combining color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='combine', virt_text_hide=true})
+ meths.buf_set_extmark(0, ns, 6, 5, { virt_text={{'replacing color', 'Blendy'}}, virt_text_pos='overlay', hl_mode='replace', virt_text_hide=true})
+
+ screen:expect{grid=[[
+ {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
+ {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) |
+ {5:i}{12:c}{11:ombining color} {13:nil} {5:then} |
+ {11:replacing color}d_cell |
+ {5:e}{8:bl}{14:endy}{15:i}{14:text}{15:o}{14:-}{15:o}{14:h}{7:ere} |
+ {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
+ {11:replacing color} line[colpos] |
+ cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+{13:1} |
+ {5:end} |
+ {5:end} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed 'V5G'
+ screen:expect{grid=[[
+ {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
+ {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
+ {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
+ {18: }{11:replacing color}{18:d_cell} |
+ {18: }{5:^e}{17:nd} |
+ {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
+ {11:replacing color} line[colpos] |
+ cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+{13:1} |
+ {5:end} |
+ {5:end} |
+ {1:~ }|
+ {1:~ }|
+ {24:-- VISUAL LINE --} |
+ ]]}
+
+ feed 'jj'
+ screen:expect{grid=[[
+ {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
+ {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
+ {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
+ {18: }{11:replacing color}{18:d_cell} |
+ {18: }{17:end} |
+ {18: }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} |
+ {18: }^ {18: }{17:local}{18: cell = line[colpos]} |
+ cell.text = text |
+ cell.hl_id = hl_id |
+ colpos = colpos+{13:1} |
+ {5:end} |
+ {5:end} |
+ {1:~ }|
+ {1:~ }|
+ {24:-- VISUAL LINE --} |
+ ]]}
+ end)
end)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index 69b6ab8cf0..a8d9fb02fc 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -1049,6 +1049,8 @@ it('diff updates line numbers below filler lines', function()
[9] = {background = Screen.colors.LightMagenta},
[10] = {bold = true, foreground = Screen.colors.Brown},
[11] = {foreground = Screen.colors.Brown},
+ [12] = {foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red};
+ [13] = {background = Screen.colors.Gray90};
})
source([[
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
@@ -1107,4 +1109,22 @@ it('diff updates line numbers below filler lines', function()
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
+ command("set signcolumn number tgc cursorline")
+ command("hi CursorLineNr guibg=red")
+ screen:expect{grid=[[
+ {1: }a {3:│}{11: 2 }a |
+ {1: }a {3:│}{11: 1 }a |
+ {1: }a {3:│}{12:3 }{13:^a }|
+ {1: }{8:x}{9: }{3:│}{11: 1 }{8:y}{9: }|
+ {1: }{4:x }{3:│}{11: }{2:----------------}|
+ {1: }{4:x }{3:│}{11: }{2:----------------}|
+ {1: }b {3:│}{11: 2 }b |
+ {1: }b {3:│}{11: 3 }b |
+ {1: }b {3:│}{11: 4 }b |
+ {1: }b {3:│}{11: 5 }b |
+ {1: }b {3:│}{11: 6 }b |
+ {6:~ }{3:│}{6:~ }|
+ {3:[No Name] [+] }{7:[No Name] [+] }|
+ signcolumn=auto |
+ ]]}
end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 32f9ae030f..3e73d8b3de 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -14,7 +14,7 @@ local funcs = helpers.funcs
local run = helpers.run
local pcall_err = helpers.pcall_err
-describe('floatwin', function()
+describe('float window', function()
before_each(function()
clear()
end)
@@ -42,6 +42,10 @@ describe('floatwin', function()
[20] = {bold = true, foreground = Screen.colors.Brown},
[21] = {background = Screen.colors.Gray90},
[22] = {background = Screen.colors.LightRed},
+ [23] = {foreground = Screen.colors.Black, background = Screen.colors.White};
+ [24] = {foreground = Screen.colors.Black, background = Screen.colors.Grey80};
+ [25] = {blend = 100, background = Screen.colors.Gray0};
+ [26] = {blend = 80, background = Screen.colors.Gray0};
}
it('behavior', function()
@@ -131,7 +135,7 @@ describe('floatwin', function()
local screen
before_each(function()
screen = Screen.new(40,7)
- screen:attach({ext_multigrid=multigrid})
+ screen:attach {ext_multigrid=multigrid}
screen:set_default_attr_ids(attrs)
end)
@@ -595,6 +599,437 @@ describe('floatwin', function()
end
end)
+ it('can have border', function()
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',
+ ' BORDAA '})
+ local win = meths.open_win(buf, false, {relative='editor', width=9, height=2, row=2, col=5, border="double"})
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔═════════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {border="single"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌─────────┐}|
+ {5:│}{1: halloj! }{5:│}|
+ {5:│}{1: BORDAA }{5:│}|
+ {5:└─────────┘}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:┌─────────┐}{0: }|
+ {0:~ }{5:│}{1: halloj! }{5:│}{0: }|
+ {0:~ }{5:│}{1: BORDAA }{5:│}{0: }|
+ {0:~ }{5:└─────────┘}{0: }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {border="solid"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5: }|
+ {5: }{1: halloj! }{5: }|
+ {5: }{1: BORDAA }{5: }|
+ {5: }|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5: }{0: }|
+ {0:~ }{5: }{1: halloj! }{5: }{0: }|
+ {0:~ }{5: }{1: BORDAA }{5: }{0: }|
+ {0:~ }{5: }{0: }|
+ |
+ ]]}
+ end
+
+ -- support: ascii char, UTF-8 char, composed char, highlight per char
+ meths.win_set_config(win, {border={"x", {"å", "ErrorMsg"}, {"\\"}, {"n̈̊", "Search"}}})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:x}{7:ååååååååå}{5:\}|
+ {17:n̈̊}{1: halloj! }{17:n̈̊}|
+ {17:n̈̊}{1: BORDAA }{17:n̈̊}|
+ {5:\}{7:ååååååååå}{5:x}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:x}{7:ååååååååå}{5:\}{0: }|
+ {0:~ }{17:n̈̊}{1: halloj! }{17:n̈̊}{0: }|
+ {0:~ }{17:n̈̊}{1: BORDAA }{17:n̈̊}{0: }|
+ {0:~ }{5:\}{7:ååååååååå}{5:x}{0: }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {border="none"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1: halloj! }|
+ {1: BORDAA }|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{1: halloj! }{0: }|
+ {0:~ }{1: BORDAA }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {border={"", "", "", ">", "", "", "", "<"}})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:<}{1: halloj! }{5:>}|
+ {5:<}{1: BORDAA }{5:>}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:<}{1: halloj! }{5:>}{0: }|
+ {0:~ }{5:<}{1: BORDAA }{5:>}{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ insert [[
+ neeed some dummy
+ background text
+ to show the effect
+ of color blending
+ of border shadow
+ ]]
+
+ meths.win_set_config(win, {border="shadow"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ neeed some dummy |
+ background text |
+ to show the effect |
+ of color blending |
+ of border shadow |
+ ^ |
+ ## grid 3
+ |
+ ## grid 5
+ {1: halloj! }{25: }|
+ {1: BORDAA }{26: }|
+ {25: }{26: }|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ neeed some dummy |
+ background text |
+ to {1: halloj! }{23:e}ffect |
+ of {1: BORDAA }{24:n}ding |
+ of {23:b}{24:order sha}dow |
+ ^ |
+ |
+ ]]}
+ end
+ end)
+
+ it('with border show popupmenu', function()
+ screen:try_resize(40,10)
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {'aaa aab ',
+ 'abb acc ', ''})
+ meths.open_win(buf, true, {relative='editor', width=9, height=3, row=0, col=5, border="double"})
+ feed 'G'
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔═════════╗}|
+ {5:║}{1:aaa aab }{5:║}|
+ {5:║}{1:abb acc }{5:║}|
+ {5:║}{1:^ }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 0, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ {5:╔═════════╗} |
+ {0:~ }{5:║}{1:aaa aab }{5:║}{0: }|
+ {0:~ }{5:║}{1:abb acc }{5:║}{0: }|
+ {0:~ }{5:║}{1:^ }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ feed 'i<c-x><c-p>'
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- }{8:match 1 of 4} |
+ ## grid 5
+ {5:╔═════════╗}|
+ {5:║}{1:aaa aab }{5:║}|
+ {5:║}{1:abb acc }{5:║}|
+ {5:║}{1:acc^ }{5:║}|
+ {5:╚═════════╝}|
+ ## grid 6
+ {1: aaa }|
+ {1: aab }|
+ {1: abb }|
+ {13: acc }|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 0, 5, true },
+ [6] = { { id = -1 }, "NW", 5, 4, 0, false }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3};
+ }}
+ else
+ screen:expect{grid=[[
+ {5:╔═════════╗} |
+ {0:~ }{5:║}{1:aaa aab }{5:║}{0: }|
+ {0:~ }{5:║}{1:abb acc }{5:║}{0: }|
+ {0:~ }{5:║}{1:acc^ }{5:║}{0: }|
+ {0:~ }{1: aaa }{0: }|
+ {0:~ }{1: aab }{0: }|
+ {0:~ }{1: abb }{0: }|
+ {0:~ }{13: acc }{0: }|
+ {0:~ }|
+ {3:-- }{8:match 1 of 4} |
+ ]]}
+ end
+ end)
+
it('can have minimum size', function()
insert("the background text")
local buf = meths.create_buf(false, true)
@@ -5433,6 +5868,155 @@ describe('floatwin', function()
]])
end
end)
+
+ it("correctly redraws when overlaid windows are resized #13991", function()
+ helpers.source([[
+ let popup_config = {"relative" : "editor",
+ \ "width" : 7,
+ \ "height" : 3,
+ \ "row" : 1,
+ \ "col" : 1,
+ \ "style" : "minimal"}
+
+ let border_config = {"relative" : "editor",
+ \ "width" : 9,
+ \ "height" : 5,
+ \ "row" : 0,
+ \ "col" : 0,
+ \ "style" : "minimal"}
+
+ let popup_buffer = nvim_create_buf(v:false, v:true)
+ let border_buffer = nvim_create_buf(v:false, v:true)
+ let popup_win = nvim_open_win(popup_buffer, v:true, popup_config)
+ let border_win = nvim_open_win(border_buffer, v:false, border_config)
+
+ call nvim_buf_set_lines(popup_buffer, 0, -1, v:true,
+ \ ["long", "longer", "longest"])
+
+ call nvim_buf_set_lines(border_buffer, 0, -1, v:true,
+ \ ["---------", "- -", "- -"])
+ ]])
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {2:^long }|
+ {2:longer }|
+ {2:longest}|
+ ## grid 6
+ {2:---------}|
+ {2:- -}|
+ {2:- -}|
+ {2: }|
+ {2: }|
+ ]], attr_ids={
+ [1] = {foreground = Screen.colors.Blue1, bold = true};
+ [2] = {background = Screen.colors.LightMagenta};
+ }, float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 1, 1, 1, true },
+ [6] = { {
+ id = 1003
+ }, "NW", 1, 0, 0, true }
+ }}
+ else
+ screen:expect([[
+ {1:---------} |
+ {1:-^long -}{0: }|
+ {1:-longer -}{0: }|
+ {1: longest }{0: }|
+ {1: }{0: }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ helpers.source([[
+ let new_popup_config = {"width" : 1, "height" : 3}
+ let new_border_config = {"width" : 3, "height" : 5}
+
+ function! Resize()
+ call nvim_win_set_config(g:popup_win, g:new_popup_config)
+ call nvim_win_set_config(g:border_win, g:new_border_config)
+
+ call nvim_buf_set_lines(g:border_buffer, 0, -1, v:true,
+ \ ["---", "- -", "- -"])
+ endfunction
+
+ nnoremap zz <cmd>call Resize()<cr>
+ ]])
+
+ helpers.feed("zz")
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {2:^l}|
+ {2:o}|
+ {2:n}|
+ ## grid 6
+ {2:---}|
+ {2:- -}|
+ {2:- -}|
+ {2: }|
+ {2: }|
+ ]], attr_ids={
+ [1] = {foreground = Screen.colors.Blue1, bold = true};
+ [2] = {background = Screen.colors.LightMagenta};
+ }, float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 1, 1, 1, true },
+ [6] = { {
+ id = 1003
+ }, "NW", 1, 0, 0, true }
+ }}
+ else
+ screen:expect([[
+ {1:---} |
+ {1:-^l-}{0: }|
+ {1:-o-}{0: }|
+ {1: n }{0: }|
+ {1: }{0: }|
+ {0:~ }|
+ |
+ ]])
+ end
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 6ce8b33a63..8883ad8270 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -38,7 +38,9 @@ describe("folded lines", function()
[6] = {background = Screen.colors.Yellow},
[7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
[8] = {foreground = Screen.colors.Brown },
- [9] = {bold = true, foreground = Screen.colors.Brown}
+ [9] = {bold = true, foreground = Screen.colors.Brown},
+ [10] = {background = Screen.colors.LightGrey, underline = true},
+ [11] = {bold=true},
})
end)
@@ -290,6 +292,569 @@ describe("folded lines", function()
end
end)
+ it("works with split", function()
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=1")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ feed('zO')
+ feed_command("rightbelow new")
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=1")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 0, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:-}bb |
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}^aa |
+ {7:+}{5:+--- 4 lines: bb···························}|
+ {7:│}ff |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 3, 0)
+ screen:expect([[
+ {7:-}aa |
+ {7:-}bb |
+ {2:[No Name] [+] }|
+ {7:-}^aa |
+ {7:+}{5:+--- 4 lines: bb···························}|
+ {7:│}ff |
+ {3:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 1, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:-}bb |
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}^aa |
+ {7:-}bb |
+ {7:2}cc |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 4, 0)
+ screen:expect([[
+ {7:-}aa |
+ {7:-}bb |
+ {2:[No Name] [+] }|
+ {7:-}^aa |
+ {7:-}bb |
+ {7:2}cc |
+ {3:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 1, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:+}{5:^+--- 4 lines: bb···························}|
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {7:-}aa |
+ {7:+}{5:^+--- 4 lines: bb···························}|
+ {3:[No Name] [+] }|
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {2:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ {3:[No Name] [+] }|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ {2:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+}{5:^+-- 6 lines: aa····························}|
+ {1:~ }|
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ screen:expect([[
+ {7:+}{5:^+-- 6 lines: aa····························}|
+ {1:~ }|
+ {3:[No Name] [+] }|
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {2:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+ end)
+
+ it("works with vsplit", function()
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=1")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ feed('zO')
+ feed_command("rightbelow vnew")
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=1")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 0, 0)
+ screen:expect([[
+ ## grid 1
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {7:2}dd |
+ {7:2}ee |
+ {7:│}ff |
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}^aa |
+ {7:+}{5:+--- 4 lines: bb····}|
+ {7:│}ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 0, 23)
+ screen:expect([[
+ {7:-}aa {2:│}{7:-}^aa |
+ {7:-}bb {2:│}{7:+}{5:+--- 4 lines: bb····}|
+ {7:2}cc {2:│}{7:│}ff |
+ {7:2}dd {2:│}{1:~ }|
+ {7:2}ee {2:│}{1:~ }|
+ {7:│}ff {2:│}{1:~ }|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 1, 0)
+ screen:expect([[
+ ## grid 1
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {7:2}dd |
+ {7:2}ee |
+ {7:│}ff |
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}^aa |
+ {7:-}bb |
+ {7:2}cc |
+ {7:2}dd |
+ {7:2}ee |
+ {7:│}ff |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 23)
+ screen:expect([[
+ {7:-}aa {2:│}{7:-}^aa |
+ {7:-}bb {2:│}{7:-}bb |
+ {7:2}cc {2:│}{7:2}cc |
+ {7:2}dd {2:│}{7:2}dd |
+ {7:2}ee {2:│}{7:2}ee |
+ {7:│}ff {2:│}{7:│}ff |
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 1, 0)
+ screen:expect([[
+ ## grid 1
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:-}aa |
+ {7:+}{5:^+--- 4 lines: bb····}|
+ {7:│}ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {7:2}dd |
+ {7:2}ee |
+ {7:│}ff |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {7:-}aa {2:│}{7:-}aa |
+ {7:+}{5:^+--- 4 lines: bb····}{2:│}{7:-}bb |
+ {7:│}ff {2:│}{7:2}cc |
+ {1:~ }{2:│}{7:2}dd |
+ {1:~ }{2:│}{7:2}ee |
+ {1:~ }{2:│}{7:│}ff |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
+ screen:expect([[
+ ## grid 1
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ [2:----------------------]{2:│}[4:----------------------]|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+}{5:^+-- 6 lines: aa·····}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :1 |
+ ## grid 4
+ {7:-}aa |
+ {7:-}bb |
+ {7:2}cc |
+ {7:2}dd |
+ {7:2}ee |
+ {7:│}ff |
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ screen:expect([[
+ {7:+}{5:^+-- 6 lines: aa·····}{2:│}{7:-}aa |
+ {1:~ }{2:│}{7:-}bb |
+ {1:~ }{2:│}{7:2}cc |
+ {1:~ }{2:│}{7:2}dd |
+ {1:~ }{2:│}{7:2}ee |
+ {1:~ }{2:│}{7:│}ff |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ :1 |
+ ]])
+ end
+ end)
+
+ it("works with tab", function()
+ insert([[
+ aa
+ bb
+ cc
+ dd
+ ee
+ ff]])
+ feed_command('2')
+ command("set foldcolumn=2")
+ feed('zf3j')
+ feed_command('1')
+ feed('zf2j')
+ feed('zO')
+ feed_command("tab split")
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 1, 1)
+ screen:expect([[
+ ## grid 1
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2 (hidden)
+ {7:- }aa |
+ {7:│-}bb |
+ {7:││}cc |
+ {7:││}dd |
+ {7:││}ee |
+ {7:│ }ff |
+ {1:~ }|
+ ## grid 3
+ :tab split |
+ ## grid 4
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 1)
+ screen:expect([[
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tab split |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 4, 0, 0)
+ screen:expect([[
+ ## grid 1
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [4:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2 (hidden)
+ {7:- }aa |
+ {7:│-}bb |
+ {7:││}cc |
+ {7:││}dd |
+ {7:││}ee |
+ {7:│ }ff |
+ {1:~ }|
+ ## grid 3
+ :tab split |
+ ## grid 4
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {10: + [No Name] }{11: + [No Name] }{2: }{10:X}|
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tab split |
+ ]])
+ end
+
+ feed_command("tabnext")
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 1, 1)
+ screen:expect([[
+ ## grid 1
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :tabnext |
+ ## grid 4 (hidden)
+ {7:+ }{5:+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 2, 1)
+ screen:expect([[
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ {7:- }^aa |
+ {7:│+}{5:+--- 4 lines: bb··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tabnext |
+ ]])
+ end
+
+ if multigrid then
+ meths.input_mouse('left', 'press', '', 2, 0, 0)
+ screen:expect([[
+ ## grid 1
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :tabnext |
+ ## grid 4 (hidden)
+ {7:+ }{5:+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ else
+ meths.input_mouse('left', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {11: + [No Name] }{10: + [No Name] }{2: }{10:X}|
+ {7:+ }{5:^+-- 6 lines: aa···························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :tabnext |
+ ]])
+ end
+ end)
+
it("works with multibyte text", function()
-- Currently the only allowed value of 'maxcombine'
eq(6, meths.get_option('maxcombine'))
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index ef3acd7d2e..8992ee27ce 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -333,10 +333,10 @@ describe('highlight defaults', function()
command('highlight clear EndOfBuffer')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
|
- ]], hl_groups={EndOfBuffer=0, MsgSeparator=2}}
+ ]], hl_groups={EndOfBuffer=1, MsgSeparator=2}}
end)
end)
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index 9313a35708..ea8968a653 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -1,16 +1,18 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, feed_command, nvim = helpers.clear, helpers.feed_command, helpers.nvim
+local clear, feed_command = helpers.clear, helpers.feed_command
local feed, next_msg, eq = helpers.feed, helpers.next_msg, helpers.eq
local command = helpers.command
local expect = helpers.expect
+local meths = helpers.meths
+local exec_lua = helpers.exec_lua
local write_file = helpers.write_file
local Screen = require('test.functional.ui.screen')
-describe('mappings', function()
- local cid
+before_each(clear)
+describe('mappings', function()
local add_mapping = function(mapping, send)
- local cmd = "nnoremap "..mapping.." :call rpcnotify("..cid..", 'mapped', '"
+ local cmd = "nnoremap "..mapping.." :call rpcnotify(1, 'mapped', '"
..send:gsub('<', '<lt>').."')<cr>"
feed_command(cmd)
end
@@ -21,8 +23,6 @@ describe('mappings', function()
end
before_each(function()
- clear()
- cid = nvim('get_api_info')[1]
add_mapping('<C-L>', '<C-L>')
add_mapping('<C-S-L>', '<C-S-L>')
add_mapping('<s-up>', '<s-up>')
@@ -115,7 +115,6 @@ describe('mappings', function()
end)
describe('input utf sequences that contain CSI/K_SPECIAL', function()
- before_each(clear)
it('ok', function()
feed('i…<esc>')
expect('…')
@@ -129,7 +128,6 @@ describe('input non-printable chars', function()
it("doesn't crash when echoing them back", function()
write_file("Xtest-overwrite", [[foobar]])
- clear()
local screen = Screen.new(60,8)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
@@ -215,3 +213,27 @@ describe('input non-printable chars', function()
]])
end)
end)
+
+describe("event processing and input", function()
+ it('not blocked by event bursts', function()
+ meths.set_keymap('', '<f2>', "<cmd>lua vim.rpcnotify(1, 'stop') winning = true <cr>", {noremap=true})
+
+ exec_lua [[
+ winning = false
+ burst = vim.schedule_wrap(function(tell)
+ if tell then
+ vim.rpcnotify(1, 'start')
+ end
+ -- Are we winning, son?
+ if not winning then
+ burst(false)
+ end
+ end)
+ burst(true)
+ ]]
+
+ eq({'notification', 'start', {}}, next_msg())
+ feed '<f2>'
+ eq({'notification', 'stop', {}}, next_msg())
+ end)
+end)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 5df4a1d533..9d7719a7c0 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -29,6 +29,7 @@ describe('ui/ext_messages', function()
[6] = {bold = true, reverse = true},
[7] = {background = Screen.colors.Yellow},
[8] = {foreground = Screen.colors.Red},
+ [9] = {special = Screen.colors.Red, undercurl = true},
})
end)
after_each(function()
@@ -455,6 +456,8 @@ describe('ui/ext_messages', function()
{1:~ }|
]], messages={
{kind="echomsg", content={{"stuff"}}},
+ }, showmode={
+ { "-- INSERT --", 3 }
}}
end)
@@ -795,6 +798,45 @@ describe('ui/ext_messages', function()
pos = 9,
}}}
end)
+
+ it('hides prompt_for_number messages', function()
+ command('set spell')
+ feed('ihelllo<esc>')
+
+ feed('z=')
+ screen:expect{grid=[[
+ {9:helllo} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:^~ }|
+ ]], messages={
+ {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with mouse (empty cancels): ' } }, kind = ""}
+ }}
+
+ feed('1')
+ screen:expect{grid=[[
+ {9:helllo} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:^~ }|
+ ]], messages={
+ {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with mouse (empty cancels): ' } }, kind = ""},
+ { content = { { "1" } }, kind = "" }
+ }}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^Hello |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+
+ end)
+
end)
describe('ui/builtin messages', function()
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index ff9f30d0a1..958e137f65 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -24,10 +24,6 @@ describe('screen', function()
} )
end)
- after_each(function()
- screen:detach()
- end)
-
it('default initial screen', function()
screen:expect([[
^ |
@@ -67,10 +63,6 @@ local function screen_tests(linegrid)
} )
end)
- after_each(function()
- screen:detach()
- end)
-
describe(':suspend', function()
it('is forwarded to the UI', function()
local function check()
@@ -1004,3 +996,39 @@ describe('Screen default colors', function()
end}
end)
end)
+
+
+describe('screen with msgsep deactivated on startup', function()
+ local screen
+
+ before_each(function()
+ clear('--cmd', 'set display-=msgsep')
+ screen = Screen.new()
+ screen:attach()
+ screen:set_default_attr_ids {
+ [0] = {bold=true, foreground=255};
+ [7] = {bold = true, foreground = Screen.colors.SeaGreen};
+ }
+ end)
+
+ it('execute command with multi-line output', function()
+ feed ':ls<cr>'
+ screen:expect([[
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+ feed '<cr>' -- skip the "Press ENTER..." state or tests will hang
+ end)
+end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 656f613c6a..5540b3c2dc 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -507,7 +507,21 @@ describe('search highlighting', function()
{1:~ }|
:syntax keyword MyGroup special |
]])
+ end)
+ it('highlights entire pattern on :%g@a/b', function()
+ command('set inccommand=nosplit')
+ feed('ia/b/c<Esc>')
+ feed(':%g@a/b')
+ screen:expect([[
+ {3:a/b}/c |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :%g@a/b^ |
+ ]])
end)
end)
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 1937102782..06c92a4b10 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -264,6 +264,24 @@ describe('Signs', function()
{0:~ }|
|
]]}
+ -- line deletion deletes signs.
+ command('2d')
+ screen:expect([[
+ {1:>>}XX{2: }{6: 1 }a |
+ XX{1:>>}WW{6: 2 }^c |
+ {2: }{6: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
end)
it('auto-resize sign column with minimum size (#13783)', function()
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 01fc50289d..a4241fe5aa 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed = helpers.clear, helpers.feed
local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
local feed_command, source, expect = helpers.feed_command, helpers.source, helpers.expect
+local funcs = helpers.funcs
local curbufmeths = helpers.curbufmeths
local command = helpers.command
local meths = helpers.meths
@@ -26,6 +27,7 @@ describe('completion', function()
[7] = {foreground = Screen.colors.White, background = Screen.colors.Red},
[8] = {reverse = true},
[9] = {bold = true, reverse = true},
+ [10] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow},
})
end)
@@ -895,8 +897,47 @@ describe('completion', function()
]])
end)
- describe('from the commandline window', function()
+ describe('lua completion', function()
+ it('expands when there is only one match', function()
+ feed(':lua CURRENT_TESTING_VAR = 1<CR>')
+ feed(':lua CURRENT_TESTING_<TAB>')
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :lua CURRENT_TESTING_VAR^ |
+ ]]}
+ end)
+ it('expands when there is only one match', function()
+ feed(':lua CURRENT_TESTING_FOO = 1<CR>')
+ feed(':lua CURRENT_TESTING_BAR = 1<CR>')
+ feed(':lua CURRENT_TESTING_<TAB>')
+ screen:expect{ grid = [[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }|
+ :lua CURRENT_TESTING_BAR^ |
+ ]], unchanged = true }
+ end)
+
+ it('provides completion from `getcompletion()`', function()
+ eq({'vim'}, funcs.getcompletion('vi', 'lua'))
+ eq({'api'}, funcs.getcompletion('vim.ap', 'lua'))
+ eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua'))
+ eq({'vim'}, funcs.getcompletion('print(vi', 'lua'))
+ end)
+ end)
+
+ describe('from the commandline window', function()
it('is cleared after CTRL-C', function ()
feed('q:')
feed('ifoo faa fee f')
diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua
index 9acc61e398..077d816903 100644
--- a/test/functional/viml/errorlist_spec.lua
+++ b/test/functional/viml/errorlist_spec.lua
@@ -68,4 +68,17 @@ describe('setloclist()', function()
command('lclose | wincmd w | lopen')
eq('foo', get_cur_win_var('quickfix_title'))
end)
+
+ it("doesn't crash when when window is closed in the middle #13721", function()
+ helpers.insert([[
+ hello world]])
+
+ command("vsplit")
+ command("autocmd WinLeave * :call nvim_win_close(0, v:true)")
+
+ command("call setloclist(0, [])")
+ command("lopen")
+
+ helpers.assert_alive()
+ end)
end)
diff --git a/test/helpers.lua b/test/helpers.lua
index 8dbd82cb8c..12d9f19187 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -365,7 +365,11 @@ function module.check_cores(app, force)
db_cmd = lldb_db_cmd
else
initial_path = '.'
- re = '/core[^/]*$'
+ if 'freebsd' == module.uname() then
+ re = '/nvim.core$'
+ else
+ re = '/core[^/]*$'
+ end
exc_re = { '^/%.deps$', '^/%'..deps_prefix()..'$', local_tmpdir, '^/%node_modules$' }
db_cmd = gdb_db_cmd
random_skip = true
diff --git a/test/symbolic/klee/nvim/charset.c b/test/symbolic/klee/nvim/charset.c
index f9bc3fabc4..fd1c5ee4b9 100644
--- a/test/symbolic/klee/nvim/charset.c
+++ b/test/symbolic/klee/nvim/charset.c
@@ -62,7 +62,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
goto vim_str2nr_dec;
}
default: {
- assert(false);
+ abort();
}
}
} else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
@@ -102,7 +102,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
- assert(false); // Should’ve used goto earlier.
+ abort(); // Should’ve used goto earlier.
#define PARSE_NUMBER(base, cond, conv) \
do { \
while (!STRING_ENDED(ptr) && (cond)) { \
diff --git a/test/symbolic/klee/nvim/memory.c b/test/symbolic/klee/nvim/memory.c
index df422cea3e..1614f813d7 100644
--- a/test/symbolic/klee/nvim/memory.c
+++ b/test/symbolic/klee/nvim/memory.c
@@ -45,7 +45,7 @@ void xfree(void *const p)
return;
}
}
- assert(false);
+ abort();
}
void *xrealloc(void *const p, size_t new_size)
@@ -63,7 +63,7 @@ void *xrealloc(void *const p, size_t new_size)
return ret;
}
}
- assert(false);
+ abort();
return (void *)(intptr_t)1;
}