aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/busted/outputHandlers/TAP.lua2
-rw-r--r--test/busted/outputHandlers/nvim.lua2
-rw-r--r--test/functional/eval/ctx_functions_spec.lua2
-rw-r--r--test/functional/ex_cmds/echo_spec.lua167
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua (renamed from test/functional/fixtures/lsp-test-rpc-server.lua)37
-rw-r--r--test/functional/helpers.lua4
-rw-r--r--test/functional/legacy/expand_spec.lua39
-rw-r--r--test/functional/lua/treesitter_spec.lua19
-rw-r--r--test/functional/lua/uri_spec.lua9
-rw-r--r--test/functional/lua/vim_spec.lua175
-rw-r--r--test/functional/normal/put_spec.lua4
-rw-r--r--test/functional/options/num_options_spec.lua20
-rw-r--r--test/functional/plugin/lsp_spec.lua136
-rw-r--r--test/functional/terminal/mouse_spec.lua34
-rw-r--r--test/functional/ui/float_spec.lua22
-rw-r--r--test/functional/ui/fold_spec.lua74
-rw-r--r--test/functional/ui/messages_spec.lua17
-rw-r--r--test/functional/ui/multigrid_spec.lua187
-rw-r--r--test/functional/ui/options_spec.lua14
-rw-r--r--test/functional/ui/popupmenu_spec.lua51
-rw-r--r--test/functional/ui/screen.lua67
-rw-r--r--test/functional/ui/wildmode_spec.lua38
-rw-r--r--test/helpers.lua73
-rw-r--r--test/unit/eval/typval_spec.lua2
-rw-r--r--test/unit/helpers.lua2
25 files changed, 1011 insertions, 186 deletions
diff --git a/test/busted/outputHandlers/TAP.lua b/test/busted/outputHandlers/TAP.lua
index 8dc4ff55b6..5de48c0ad3 100644
--- a/test/busted/outputHandlers/TAP.lua
+++ b/test/busted/outputHandlers/TAP.lua
@@ -7,7 +7,7 @@ return function(options)
local handler = require 'busted.outputHandlers.TAP'(options)
local suiteEnd = function()
- io.write(global_helpers.read_nvim_log())
+ io.write(global_helpers.read_nvim_log(nil, true))
return nil, true
end
busted.subscribe({ 'suite', 'end' }, suiteEnd)
diff --git a/test/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua
index 8f3aad776e..5456e9ca98 100644
--- a/test/busted/outputHandlers/nvim.lua
+++ b/test/busted/outputHandlers/nvim.lua
@@ -196,7 +196,7 @@ return function(options)
local tests = (testCount == 1 and 'test' or 'tests')
local files = (fileCount == 1 and 'file' or 'files')
io.write(globalTeardown)
- io.write(global_helpers.read_nvim_log())
+ io.write(global_helpers.read_nvim_log(nil, true))
io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms))
io.write(getSummaryString())
io.flush()
diff --git a/test/functional/eval/ctx_functions_spec.lua b/test/functional/eval/ctx_functions_spec.lua
index c81dad9645..f23adbc556 100644
--- a/test/functional/eval/ctx_functions_spec.lua
+++ b/test/functional/eval/ctx_functions_spec.lua
@@ -6,7 +6,7 @@ local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
-local map = helpers.map
+local map = helpers.tbl_map
local nvim = helpers.nvim
local parse_context = helpers.parse_context
local redir_exec = helpers.redir_exec
diff --git a/test/functional/ex_cmds/echo_spec.lua b/test/functional/ex_cmds/echo_spec.lua
index 10c7230896..408ce52b8c 100644
--- a/test/functional/ex_cmds/echo_spec.lua
+++ b/test/functional/ex_cmds/echo_spec.lua
@@ -11,31 +11,57 @@ local dedent = helpers.dedent
local command = helpers.command
local exc_exec = helpers.exc_exec
local redir_exec = helpers.redir_exec
+local matches = helpers.matches
+
+describe(':echo :echon :echomsg :echoerr', function()
+ local fn_tbl = {'String', 'StringN', 'StringMsg', 'StringErr'}
+ local function assert_same_echo_dump(expected, input, use_eval)
+ for _,v in pairs(fn_tbl) do
+ eq(expected, use_eval and eval(v..'('..input..')') or funcs[v](input))
+ end
+ end
+ local function assert_matches_echo_dump(expected, input, use_eval)
+ for _,v in pairs(fn_tbl) do
+ matches(expected, use_eval and eval(v..'('..input..')') or funcs[v](input))
+ end
+ end
-describe(':echo', function()
before_each(function()
clear()
source([[
function String(s)
return execute('echo a:s')[1:]
endfunction
+ function StringMsg(s)
+ return execute('echomsg a:s')[1:]
+ endfunction
+ function StringN(s)
+ return execute('echon a:s')
+ endfunction
+ function StringErr(s)
+ try
+ execute 'echoerr a:s'
+ catch
+ return substitute(v:exception, '^Vim(echoerr):', '', '')
+ endtry
+ endfunction
]])
end)
describe('used to represent floating-point values', function()
it('dumps NaN values', function()
- eq('str2float(\'nan\')', eval('String(str2float(\'nan\'))'))
+ assert_same_echo_dump("str2float('nan')", "str2float('nan')", true)
end)
it('dumps infinite values', function()
- eq('str2float(\'inf\')', eval('String(str2float(\'inf\'))'))
- eq('-str2float(\'inf\')', eval('String(str2float(\'-inf\'))'))
+ assert_same_echo_dump("str2float('inf')", "str2float('inf')", true)
+ assert_same_echo_dump("-str2float('inf')", "str2float('-inf')", true)
end)
it('dumps regular values', function()
- eq('1.5', funcs.String(1.5))
- eq('1.56e-20', funcs.String(1.56000e-020))
- eq('0.0', eval('String(0.0)'))
+ assert_same_echo_dump('1.5', 1.5)
+ assert_same_echo_dump('1.56e-20', 1.56000e-020)
+ assert_same_echo_dump('0.0', '0.0', true)
end)
it('dumps special v: values', function()
@@ -45,69 +71,81 @@ describe(':echo', function()
eq('v:true', funcs.String(true))
eq('v:false', funcs.String(false))
eq('v:null', funcs.String(NIL))
+ eq('true', eval('StringMsg(v:true)'))
+ eq('false', eval('StringMsg(v:false)'))
+ eq('null', eval('StringMsg(v:null)'))
+ eq('true', funcs.StringMsg(true))
+ eq('false', funcs.StringMsg(false))
+ eq('null', funcs.StringMsg(NIL))
+ eq('true', eval('StringErr(v:true)'))
+ eq('false', eval('StringErr(v:false)'))
+ eq('null', eval('StringErr(v:null)'))
+ eq('true', funcs.StringErr(true))
+ eq('false', funcs.StringErr(false))
+ eq('null', funcs.StringErr(NIL))
end)
it('dumps values with at most six digits after the decimal point',
function()
- eq('1.234568e-20', funcs.String(1.23456789123456789123456789e-020))
- eq('1.234568', funcs.String(1.23456789123456789123456789))
+ assert_same_echo_dump('1.234568e-20', 1.23456789123456789123456789e-020)
+ assert_same_echo_dump('1.234568', 1.23456789123456789123456789)
end)
it('dumps values with at most seven digits before the decimal point',
function()
- eq('1234567.891235', funcs.String(1234567.89123456789123456789))
- eq('1.234568e7', funcs.String(12345678.9123456789123456789))
+ assert_same_echo_dump('1234567.891235', 1234567.89123456789123456789)
+ assert_same_echo_dump('1.234568e7', 12345678.9123456789123456789)
end)
it('dumps negative values', function()
- eq('-1.5', funcs.String(-1.5))
- eq('-1.56e-20', funcs.String(-1.56000e-020))
- eq('-1.234568e-20', funcs.String(-1.23456789123456789123456789e-020))
- eq('-1.234568', funcs.String(-1.23456789123456789123456789))
- eq('-1234567.891235', funcs.String(-1234567.89123456789123456789))
- eq('-1.234568e7', funcs.String(-12345678.9123456789123456789))
+ assert_same_echo_dump('-1.5', -1.5)
+ assert_same_echo_dump('-1.56e-20', -1.56000e-020)
+ assert_same_echo_dump('-1.234568e-20', -1.23456789123456789123456789e-020)
+ assert_same_echo_dump('-1.234568', -1.23456789123456789123456789)
+ assert_same_echo_dump('-1234567.891235', -1234567.89123456789123456789)
+ assert_same_echo_dump('-1.234568e7', -12345678.9123456789123456789)
end)
end)
describe('used to represent numbers', function()
it('dumps regular values', function()
- eq('0', funcs.String(0))
- eq('-1', funcs.String(-1))
- eq('1', funcs.String(1))
+ assert_same_echo_dump('0', 0)
+ assert_same_echo_dump('-1', -1)
+ assert_same_echo_dump('1', 1)
end)
it('dumps large values', function()
- eq('2147483647', funcs.String(2^31-1))
- eq('-2147483648', funcs.String(-2^31))
+ assert_same_echo_dump('2147483647', 2^31-1)
+ assert_same_echo_dump('-2147483648', -2^31)
end)
end)
describe('used to represent strings', function()
it('dumps regular strings', function()
- eq('test', funcs.String('test'))
+ assert_same_echo_dump('test', 'test')
end)
it('dumps empty strings', function()
- eq('', funcs.String(''))
+ assert_same_echo_dump('', '')
end)
- it('dumps strings with \' inside', function()
- eq('\'\'\'', funcs.String('\'\'\''))
- eq('a\'b\'\'', funcs.String('a\'b\'\''))
- eq('\'b\'\'d', funcs.String('\'b\'\'d'))
- eq('a\'b\'c\'d', funcs.String('a\'b\'c\'d'))
+ it("dumps strings with ' inside", function()
+ assert_same_echo_dump("'''", "'''")
+ assert_same_echo_dump("a'b''", "a'b''")
+ assert_same_echo_dump("'b''d", "'b''d")
+ assert_same_echo_dump("a'b'c'd", "a'b'c'd")
end)
it('dumps NULL strings', function()
- eq('', eval('String($XXX_UNEXISTENT_VAR_XXX)'))
+ assert_same_echo_dump('', '$XXX_UNEXISTENT_VAR_XXX', true)
end)
it('dumps NULL lists', function()
- eq('[]', eval('String(v:_null_list)'))
+ assert_same_echo_dump('[]', 'v:_null_list', true)
end)
it('dumps NULL dictionaries', function()
- eq('{}', eval('String(v:_null_dict)'))
+ assert_same_echo_dump('{}', 'v:_null_dict', true)
end)
end)
@@ -129,15 +167,27 @@ describe(':echo', function()
it('dumps references to built-in functions', function()
eq('function', eval('String(function("function"))'))
+ eq("function('function')", eval('StringMsg(function("function"))'))
+ eq("function('function')", eval('StringErr(function("function"))'))
end)
it('dumps references to user functions', function()
eq('Test1', eval('String(function("Test1"))'))
eq('g:Test3', eval('String(function("g:Test3"))'))
+ eq("function('Test1')", eval("StringMsg(function('Test1'))"))
+ eq("function('g:Test3')", eval("StringMsg(function('g:Test3'))"))
+ eq("function('Test1')", eval("StringErr(function('Test1'))"))
+ eq("function('g:Test3')", eval("StringErr(function('g:Test3'))"))
end)
it('dumps references to script functions', function()
eq('<SNR>2_Test2', eval('String(Test2_f)'))
+ eq("function('<SNR>2_Test2')", eval('StringMsg(Test2_f)'))
+ eq("function('<SNR>2_Test2')", eval('StringErr(Test2_f)'))
+ end)
+
+ it('dump references to lambdas', function()
+ assert_matches_echo_dump("function%('<lambda>%d+'%)", '{-> 1234}', true)
end)
it('dumps partials with self referencing a partial', function()
@@ -156,19 +206,23 @@ describe(':echo', function()
end)
it('dumps automatically created partials', function()
- eq('function(\'<SNR>2_Test2\', {\'f\': function(\'<SNR>2_Test2\')})',
- eval('String({"f": Test2_f}.f)'))
- eq('function(\'<SNR>2_Test2\', [1], {\'f\': function(\'<SNR>2_Test2\', [1])})',
- eval('String({"f": function(Test2_f, [1])}.f)'))
+ assert_same_echo_dump(
+ "function('<SNR>2_Test2', {'f': function('<SNR>2_Test2')})",
+ '{"f": Test2_f}.f',
+ true)
+ assert_same_echo_dump(
+ "function('<SNR>2_Test2', [1], {'f': function('<SNR>2_Test2', [1])})",
+ '{"f": function(Test2_f, [1])}.f',
+ true)
end)
it('dumps manually created partials', function()
- eq('function(\'Test3\', [1, 2], {})',
- eval('String(function("Test3", [1, 2], {}))'))
- eq('function(\'Test3\', {})',
- eval('String(function("Test3", {}))'))
- eq('function(\'Test3\', [1, 2])',
- eval('String(function("Test3", [1, 2]))'))
+ assert_same_echo_dump("function('Test3', [1, 2], {})",
+ "function('Test3', [1, 2], {})", true)
+ assert_same_echo_dump("function('Test3', [1, 2])",
+ "function('Test3', [1, 2])", true)
+ assert_same_echo_dump("function('Test3', {})",
+ "function('Test3', {})", true)
end)
it('does not crash or halt when dumping partials with reference cycles in self',
@@ -225,15 +279,19 @@ describe(':echo', function()
describe('used to represent lists', function()
it('dumps empty list', function()
- eq('[]', funcs.String({}))
+ assert_same_echo_dump('[]', {})
+ end)
+
+ it('dumps non-empty list', function()
+ assert_same_echo_dump('[1, 2]', {1,2})
end)
it('dumps nested lists', function()
- eq('[[[[[]]]]]', funcs.String({{{{{}}}}}))
+ assert_same_echo_dump('[[[[[]]]]]', {{{{{}}}}})
end)
it('dumps nested non-empty lists', function()
- eq('[1, [[3, [[5], 4]], 2]]', funcs.String({1, {{3, {{5}, 4}}, 2}}))
+ assert_same_echo_dump('[1, [[3, [[5], 4]], 2]]', {1, {{3, {{5}, 4}}, 2}})
end)
it('does not error when dumping recursive lists', function()
@@ -252,18 +310,18 @@ describe(':echo', function()
describe('used to represent dictionaries', function()
it('dumps empty dictionary', function()
- eq('{}', eval('String({})'))
+ assert_same_echo_dump('{}', '{}', true)
end)
it('dumps list with two same empty dictionaries, also in partials', function()
command('let d = {}')
- eq('[{}, {}]', eval('String([d, d])'))
+ assert_same_echo_dump('[{}, {}]', '[d, d]', true)
eq('[function(\'tr\', {}), {}]', eval('String([function("tr", d), d])'))
eq('[{}, function(\'tr\', {})]', eval('String([d, function("tr", d)])'))
end)
it('dumps non-empty dictionary', function()
- eq('{\'t\'\'est\': 1}', funcs.String({['t\'est']=1}))
+ assert_same_echo_dump("{'t''est': 1}", {["t'est"]=1})
end)
it('does not error when dumping recursive dictionaries', function()
@@ -297,11 +355,20 @@ describe(':echo', function()
eq('<8e>', funcs.String(chr(0x8e)))
eq('<c2>', funcs.String(('«'):sub(1, 1)))
eq('«', funcs.String(('«'):sub(1, 2)))
+
+ eq('<80>', funcs.StringMsg(chr(0x80)))
+ eq('<81>', funcs.StringMsg(chr(0x81)))
+ eq('<8e>', funcs.StringMsg(chr(0x8e)))
+ eq('<c2>', funcs.StringMsg(('«'):sub(1, 1)))
+ eq('«', funcs.StringMsg(('«'):sub(1, 2)))
end)
it('displays ASCII control characters using ^X notation', function()
eq('^C', funcs.String(ctrl('c')))
eq('^A', funcs.String(ctrl('a')))
eq('^F', funcs.String(ctrl('f')))
+ eq('^C', funcs.StringMsg(ctrl('c')))
+ eq('^A', funcs.StringMsg(ctrl('a')))
+ eq('^F', funcs.StringMsg(ctrl('f')))
end)
it('prints CR, NL and tab as-is', function()
eq('\n', funcs.String('\n'))
@@ -311,11 +378,15 @@ describe(':echo', function()
it('prints non-printable UTF-8 in <> notation', function()
-- SINGLE SHIFT TWO, unicode control
eq('<8e>', funcs.String(funcs.nr2char(0x8E)))
+ eq('<8e>', funcs.StringMsg(funcs.nr2char(0x8E)))
-- Surrogate pair: U+1F0A0 PLAYING CARD BACK is represented in UTF-16 as
-- 0xD83C 0xDCA0. This is not valid in UTF-8.
eq('<d83c>', funcs.String(funcs.nr2char(0xD83C)))
eq('<dca0>', funcs.String(funcs.nr2char(0xDCA0)))
eq('<d83c><dca0>', funcs.String(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0)))
+ eq('<d83c>', funcs.StringMsg(funcs.nr2char(0xD83C)))
+ eq('<dca0>', funcs.StringMsg(funcs.nr2char(0xDCA0)))
+ eq('<d83c><dca0>', funcs.StringMsg(funcs.nr2char(0xD83C) .. funcs.nr2char(0xDCA0)))
end)
end)
end)
diff --git a/test/functional/fixtures/lsp-test-rpc-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 798883ced0..dca7f35923 100644
--- a/test/functional/fixtures/lsp-test-rpc-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -1,23 +1,14 @@
local protocol = require 'vim.lsp.protocol'
--- Internal utility methods.
--- TODO replace with a better implementation.
-local function json_encode(data)
- local status, result = pcall(vim.fn.json_encode, data)
- if status then
- return result
- else
- return nil, result
- end
-end
-local function json_decode(data)
- local status, result = pcall(vim.fn.json_decode, data)
- if status then
- return result
- else
- return nil, result
- end
+-- Logs to $NVIM_LOG_FILE.
+--
+-- TODO(justinmk): remove after https://github.com/neovim/neovim/pull/7062
+local function log(loglevel, area, msg)
+ vim.fn.writefile(
+ {string.format('%s %s: %s', loglevel, area, msg)},
+ vim.env.NVIM_LOG_FILE,
+ 'a')
end
local function message_parts(sep, ...)
@@ -49,16 +40,14 @@ local function format_message_with_content_length(encoded_message)
}
end
--- Server utility methods.
-
local function read_message()
local line = io.read("*l")
local length = line:lower():match("content%-length:%s*(%d+)")
- return assert(json_decode(io.read(2 + length):sub(2)), "read_message.json_decode")
+ return vim.fn.json_decode(io.read(2 + length):sub(2))
end
local function send(payload)
- io.stdout:write(format_message_with_content_length(json_encode(payload)))
+ io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload)))
end
local function respond(id, err, result)
@@ -390,7 +379,7 @@ function tests.basic_check_buffer_open_and_change_incremental()
}
end
-function tests.basic_check_buffer_open_and_change_incremental_editting()
+function tests.basic_check_buffer_open_and_change_incremental_editing()
skeleton {
on_init = function(params)
local expected_capabilities = protocol.make_client_capabilities()
@@ -443,6 +432,7 @@ local kill_timer = vim.loop.new_timer()
kill_timer:start(_G.TIMEOUT or 1e3, 0, function()
kill_timer:stop()
kill_timer:close()
+ log('ERROR', 'LSP', 'TIMEOUT')
io.stderr:write("TIMEOUT")
os.exit(100)
end)
@@ -453,7 +443,8 @@ local status, err = pcall(assert(tests[test_name], "Test not found"))
kill_timer:stop()
kill_timer:close()
if not status then
+ log('ERROR', 'LSP', tostring(err))
io.stderr:write(err)
- os.exit(1)
+ os.exit(101)
end
os.exit(0)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 53c4d140b6..e8435cd3b7 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -15,9 +15,9 @@ local check_cores = global_helpers.check_cores
local check_logs = global_helpers.check_logs
local dedent = global_helpers.dedent
local eq = global_helpers.eq
-local filter = global_helpers.filter
+local filter = global_helpers.tbl_filter
local is_os = global_helpers.is_os
-local map = global_helpers.map
+local map = global_helpers.tbl_map
local ok = global_helpers.ok
local sleep = global_helpers.sleep
local tbl_contains = global_helpers.tbl_contains
diff --git a/test/functional/legacy/expand_spec.lua b/test/functional/legacy/expand_spec.lua
index 1b735080f4..f238128b31 100644
--- a/test/functional/legacy/expand_spec.lua
+++ b/test/functional/legacy/expand_spec.lua
@@ -70,6 +70,40 @@ describe('expand file name', function()
call assert_match('\~', expand('%:p'))
bwipe!
endfunc
+
+ func Test_expandcmd()
+ let $FOO = 'Test'
+ call assert_equal('e x/Test/y', expandcmd('e x/$FOO/y'))
+ unlet $FOO
+
+ new
+ edit Xfile1
+ call assert_equal('e Xfile1', expandcmd('e %'))
+ edit Xfile2
+ edit Xfile1
+ call assert_equal('e Xfile2', expandcmd('e #'))
+ edit Xfile2
+ edit Xfile3
+ edit Xfile4
+ let bnum = bufnr('Xfile2')
+ call assert_equal('e Xfile2', expandcmd('e #' . bnum))
+ call setline('.', 'Vim!@#')
+ call assert_equal('e Vim', expandcmd('e <cword>'))
+ call assert_equal('e Vim!@#', expandcmd('e <cWORD>'))
+ enew!
+ edit Xfile.java
+ call assert_equal('e Xfile.py', expandcmd('e %:r.py'))
+ call assert_equal('make abc.java', expandcmd('make abc.%:e'))
+ call assert_equal('make Xabc.java', expandcmd('make %:s?file?abc?'))
+ edit a1a2a3.rb
+ call assert_equal('make b1b2b3.rb a1a2a3 Xfile.o', expandcmd('make %:gs?a?b? %< #<.o'))
+
+ call assert_fails('call expandcmd("make <afile>")', 'E495:')
+ call assert_fails('call expandcmd("make <afile>")', 'E495:')
+ enew
+ call assert_fails('call expandcmd("make %")', 'E499:')
+ close
+ endfunc
]])
end)
@@ -87,4 +121,9 @@ describe('expand file name', function()
call('Test_expand_tilde_filename')
expected_empty()
end)
+
+ it('works with expandcmd()', function()
+ call('Test_expandcmd')
+ expected_empty()
+ end)
end)
diff --git a/test/functional/lua/treesitter_spec.lua b/test/functional/lua/treesitter_spec.lua
index 494d6c84bb..f93185d1f6 100644
--- a/test/functional/lua/treesitter_spec.lua
+++ b/test/functional/lua/treesitter_spec.lua
@@ -245,6 +245,11 @@ static int nlua_schedule(lua_State *const lstate)
(primitive_type) @type
(sized_type_specifier) @type
+; defaults to very magic syntax, for best compatibility
+((identifier) @Identifier (match? @Identifier "^l(u)a_"))
+; still support \M etc prefixes
+((identifier) @Constant (match? @Constant "\M^\[A-Z_]\+$"))
+
((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (eq? @WarningMsg.left @WarningMsg.right))
(comment) @comment
@@ -263,7 +268,7 @@ static int nlua_schedule(lua_State *const lstate)
[8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[9] = {foreground = Screen.colors.Magenta, background = Screen.colors.Red},
[10] = {foreground = Screen.colors.Red, background = Screen.colors.Red},
-
+ [11] = {foreground = Screen.colors.Cyan4},
})
insert(hl_text)
@@ -297,10 +302,10 @@ static int nlua_schedule(lua_State *const lstate)
{2:/// Schedule Lua callback on main loop's event queue} |
{3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) |
{ |
- {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
|| {6:lstate} != {6:lstate}) { |
- lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} lua_error(lstate); |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
} |
|
{7:LuaRef} cb = nlua_ref(lstate, {5:1}); |
@@ -319,10 +324,10 @@ static int nlua_schedule(lua_State *const lstate)
{2:/// Schedule Lua callback on main loop's event queue} |
{3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) |
{ |
- {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
|| {6:lstate} != {6:lstate}) { |
- lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} lua_error(lstate); |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
{8:*^/} |
} |
|
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index 19b1eb1f61..128c7c6137 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -85,6 +85,15 @@ describe('URI methods', function()
eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
end)
+ it('file path includes only ascii charactors with encoded colon character', function()
+ local test_case = [[
+ local uri = 'file:///C%3A/Foo/Bar/Baz.txt'
+ return vim.uri_to_fname(uri)
+ ]]
+
+ eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
+ end)
+
it('file path including white space', function()
local test_case = [[
local uri = 'file:///C:/Foo%20/Bar/Baz.txt'
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index e879f8b925..ca74d185cd 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -7,6 +7,7 @@ local meths = helpers.meths
local command = helpers.command
local clear = helpers.clear
local eq = helpers.eq
+local ok = helpers.ok
local eval = helpers.eval
local feed = helpers.feed
local pcall_err = helpers.pcall_err
@@ -310,18 +311,52 @@ describe('lua stdlib', function()
end)
it("vim.deepcopy", function()
- local is_dc = exec_lua([[
+ ok(exec_lua([[
local a = { x = { 1, 2 }, y = 5}
local b = vim.deepcopy(a)
- local count = 0
- for _ in pairs(b) do count = count + 1 end
-
- return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2
+ return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and vim.tbl_count(b) == 2
and tostring(a) ~= tostring(b)
- ]])
+ ]]))
+
+ ok(exec_lua([[
+ local a = {}
+ local b = vim.deepcopy(a)
+
+ return vim.tbl_islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b)
+ ]]))
- assert(is_dc)
+ ok(exec_lua([[
+ local a = vim.empty_dict()
+ local b = vim.deepcopy(a)
+
+ return not vim.tbl_islist(b) and vim.tbl_count(b) == 0
+ ]]))
+
+ ok(exec_lua([[
+ local a = {x = vim.empty_dict(), y = {}}
+ local b = vim.deepcopy(a)
+
+ return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y)
+ and vim.tbl_count(b) == 2
+ and tostring(a) ~= tostring(b)
+ ]]))
+
+ ok(exec_lua([[
+ local f1 = function() return 1 end
+ local f2 = function() return 2 end
+ local t1 = {f = f1}
+ local t2 = vim.deepcopy(t1)
+ t1.f = f2
+ return t1.f() ~= t2.f()
+ ]]))
+
+ eq('Error executing lua: .../shared.lua: Cannot deepcopy object of type thread',
+ pcall_err(exec_lua, [[
+ local thread = coroutine.create(function () return 0 end)
+ local t = {thr = thread}
+ vim.deepcopy(t)
+ ]]))
end)
it('vim.pesc', function()
@@ -353,6 +388,30 @@ describe('lua stdlib', function()
end
end)
+ it('vim.tbl_map', function()
+ eq({}, exec_lua([[
+ return vim.tbl_map(function(v) return v * 2 end, {})
+ ]]))
+ eq({2, 4, 6}, exec_lua([[
+ return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3})
+ ]]))
+ eq({{i=2}, {i=4}, {i=6}}, exec_lua([[
+ return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}})
+ ]]))
+ end)
+
+ it('vim.tbl_filter', function()
+ eq({}, exec_lua([[
+ return vim.tbl_filter(function(v) return (v % 2) == 0 end, {})
+ ]]))
+ eq({2}, exec_lua([[
+ return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3})
+ ]]))
+ eq({{i=2}}, exec_lua([[
+ return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}})
+ ]]))
+ end)
+
it('vim.tbl_islist', function()
eq(true, exec_lua("return vim.tbl_islist({})"))
eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())"))
@@ -369,6 +428,88 @@ describe('lua stdlib', function()
eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})"))
end)
+ it('vim.tbl_extend', function()
+ ok(exec_lua([[
+ local a = {x = 1}
+ local b = {y = 2}
+ local c = vim.tbl_extend("keep", a, b)
+
+ return c.x == 1 and b.y == 2 and vim.tbl_count(c) == 2
+ ]]))
+
+ ok(exec_lua([[
+ local a = {x = 1}
+ local b = {y = 2}
+ local c = {z = 3}
+ local d = vim.tbl_extend("keep", a, b, c)
+
+ return d.x == 1 and d.y == 2 and d.z == 3 and vim.tbl_count(d) == 3
+ ]]))
+
+ ok(exec_lua([[
+ local a = {x = 1}
+ local b = {x = 3}
+ local c = vim.tbl_extend("keep", a, b)
+
+ return c.x == 1 and vim.tbl_count(c) == 1
+ ]]))
+
+ ok(exec_lua([[
+ local a = {x = 1}
+ local b = {x = 3}
+ local c = vim.tbl_extend("force", a, b)
+
+ return c.x == 3 and vim.tbl_count(c) == 1
+ ]]))
+
+ ok(exec_lua([[
+ local a = vim.empty_dict()
+ local b = {}
+ local c = vim.tbl_extend("keep", a, b)
+
+ return not vim.tbl_islist(c) and vim.tbl_count(c) == 0
+ ]]))
+
+ ok(exec_lua([[
+ local a = {}
+ local b = vim.empty_dict()
+ local c = vim.tbl_extend("keep", a, b)
+
+ return vim.tbl_islist(c) and vim.tbl_count(c) == 0
+ ]]))
+
+ eq('Error executing lua: .../shared.lua: invalid "behavior": nil',
+ pcall_err(exec_lua, [[
+ return vim.tbl_extend()
+ ]])
+ )
+
+ eq('Error executing lua: .../shared.lua: wrong number of arguments (given 1, expected at least 3)',
+ pcall_err(exec_lua, [[
+ return vim.tbl_extend("keep")
+ ]])
+ )
+
+ eq('Error executing lua: .../shared.lua: wrong number of arguments (given 2, expected at least 3)',
+ pcall_err(exec_lua, [[
+ return vim.tbl_extend("keep", {})
+ ]])
+ )
+ end)
+
+ it('vim.tbl_count', function()
+ eq(0, exec_lua [[ return vim.tbl_count({}) ]])
+ eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]])
+ eq(0, exec_lua [[ return vim.tbl_count({nil}) ]])
+ eq(0, exec_lua [[ return vim.tbl_count({a=nil}) ]])
+ eq(1, exec_lua [[ return vim.tbl_count({1}) ]])
+ eq(2, exec_lua [[ return vim.tbl_count({1, 2}) ]])
+ eq(2, exec_lua [[ return vim.tbl_count({1, nil, 3}) ]])
+ eq(1, exec_lua [[ return vim.tbl_count({a=1}) ]])
+ eq(2, exec_lua [[ return vim.tbl_count({a=1, b=2}) ]])
+ eq(2, exec_lua [[ return vim.tbl_count({a=1, b=nil, c=3}) ]])
+ end)
+
it('vim.deep_equal', function()
eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]])
eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]])
@@ -545,6 +686,8 @@ describe('lua stdlib', function()
]]))
eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})"))
+ eq('{}', exec_lua([[ return vim.fn.json_encode(vim.empty_dict()) ]]))
+ eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]]))
end)
it('vim.validate', function()
@@ -700,4 +843,22 @@ describe('lua stdlib', function()
eq('2', funcs.luaeval "BUF")
eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()")
end)
+
+ it('vim.regex', function()
+ exec_lua [[
+ re1 = vim.regex"ab\\+c"
+ vim.cmd "set nomagic ignorecase"
+ re2 = vim.regex"xYz"
+ ]]
+ eq({}, exec_lua[[return {re1:match_str("x ac")}]])
+ eq({3,7}, exec_lua[[return {re1:match_str("ac abbc")}]])
+
+ meths.buf_set_lines(0, 0, -1, true, {"yy", "abc abbc"})
+ eq({}, exec_lua[[return {re1:match_line(0, 0)}]])
+ eq({0,3}, exec_lua[[return {re1:match_line(0, 1)}]])
+ eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1)}]])
+ eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]])
+ eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]])
+ eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]])
+ end)
end)
diff --git a/test/functional/normal/put_spec.lua b/test/functional/normal/put_spec.lua
index 357fafec44..26967ecbba 100644
--- a/test/functional/normal/put_spec.lua
+++ b/test/functional/normal/put_spec.lua
@@ -6,8 +6,8 @@ local insert = helpers.insert
local feed = helpers.feed
local expect = helpers.expect
local eq = helpers.eq
-local map = helpers.map
-local filter = helpers.filter
+local map = helpers.tbl_map
+local filter = helpers.tbl_filter
local feed_command = helpers.feed_command
local curbuf_contents = helpers.curbuf_contents
local funcs = helpers.funcs
diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua
index deda5c9118..4754c14f5b 100644
--- a/test/functional/options/num_options_spec.lua
+++ b/test/functional/options/num_options_spec.lua
@@ -65,14 +65,12 @@ describe(':set validation', function()
should_succeed('regexpengine', 2)
should_fail('report', -1, 'E487')
should_succeed('report', 0)
- should_fail('scrolloff', -1, 'E49')
- should_fail('sidescrolloff', -1, 'E487')
should_fail('sidescroll', -1, 'E487')
should_fail('cmdwinheight', 0, 'E487')
should_fail('updatetime', -1, 'E487')
should_fail('foldlevel', -5, 'E487')
- should_fail('foldcolumn', 13, 'E474')
+ should_fail('foldcolumn', '13', 'E474')
should_fail('conceallevel', 4, 'E474')
should_fail('numberwidth', 21, 'E474')
should_fail('numberwidth', 0, 'E487')
@@ -82,6 +80,22 @@ describe(':set validation', function()
meths.set_option('window', -10)
eq(23, meths.get_option('window'))
eq('', eval("v:errmsg"))
+
+ -- 'scrolloff' and 'sidescrolloff' can have a -1 value when
+ -- set for the current window, but not globally
+ feed_command('setglobal scrolloff=-1')
+ eq('E487', eval("v:errmsg"):match("E%d*"))
+
+ feed_command('setglobal sidescrolloff=-1')
+ eq('E487', eval("v:errmsg"):match("E%d*"))
+
+ feed_command('let v:errmsg=""')
+
+ feed_command('setlocal scrolloff=-1')
+ eq('', eval("v:errmsg"))
+
+ feed_command('setlocal sidescrolloff=-1')
+ eq('', eval("v:errmsg"))
end)
it('set wmh/wh wmw/wiw checks', function()
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 4829a33861..a57443f909 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -1,12 +1,13 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_log = helpers.assert_log
local clear = helpers.clear
local buf_lines = helpers.buf_lines
local dedent = helpers.dedent
local exec_lua = helpers.exec_lua
local eq = helpers.eq
+local pesc = helpers.pesc
local insert = helpers.insert
-local iswin = helpers.iswin
local retry = helpers.retry
local NIL = helpers.NIL
@@ -14,20 +15,27 @@ local NIL = helpers.NIL
-- yield.
local run, stop = helpers.run, helpers.stop
+-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
if helpers.pending_win32(pending) then return end
-local lsp_test_rpc_server_file = "test/functional/fixtures/lsp-test-rpc-server.lua"
-if iswin() then
- lsp_test_rpc_server_file = lsp_test_rpc_server_file:gsub("/", "\\")
-end
+-- Fake LSP server.
+local fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
+local fake_lsp_logfile = 'Xtest-fake-lsp.log'
+
+teardown(function()
+ os.remove(fake_lsp_logfile)
+end)
-local function test_rpc_server_setup(test_name, timeout_ms)
+local function fake_lsp_server_setup(test_name, timeout_ms)
exec_lua([=[
lsp = require('vim.lsp')
- local test_name, fixture_filename, timeout = ...
+ local test_name, fixture_filename, logfile, timeout = ...
TEST_RPC_CLIENT_ID = lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = logfile;
+ };
cmd = {
- vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless',
+ vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
"-c", string.format("lua TEST_NAME = %q", test_name),
"-c", string.format("lua TIMEOUT = %d", timeout),
"-c", "luafile "..fixture_filename,
@@ -48,13 +56,13 @@ local function test_rpc_server_setup(test_name, timeout_ms)
vim.rpcnotify(1, "exit", ...)
end;
}
- ]=], test_name, lsp_test_rpc_server_file, timeout_ms or 1e3)
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3)
end
local function test_rpc_server(config)
if config.test_name then
clear()
- test_rpc_server_setup(config.test_name, config.timeout_ms or 1e3)
+ fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3)
end
local client = setmetatable({}, {
__index = function(_, name)
@@ -114,11 +122,14 @@ describe('LSP', function()
local test_name = "basic_init"
exec_lua([=[
lsp = require('vim.lsp')
- local test_name, fixture_filename = ...
+ local test_name, fixture_filename, logfile = ...
function test__start_client()
return lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = logfile;
+ };
cmd = {
- vim.api.nvim_get_vvar("progpath"), '-Es', '-u', 'NONE', '--headless',
+ vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
"-c", string.format("lua TEST_NAME = %q", test_name),
"-c", "luafile "..fixture_filename;
};
@@ -126,7 +137,7 @@ describe('LSP', function()
}
end
TEST_CLIENT1 = test__start_client()
- ]=], test_name, lsp_test_rpc_server_file)
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile)
end)
after_each(function()
@@ -195,7 +206,8 @@ describe('LSP', function()
end;
-- If the program timed out, then code will be nil.
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
-- Note that NIL must be used here.
-- on_callback(err, method, result, client_id)
@@ -216,7 +228,10 @@ describe('LSP', function()
client.stop()
end;
on_exit = function(code, signal)
- eq(1, code, "exit code") eq(0, signal, "exit signal")
+ eq(101, code, "exit code", fake_lsp_logfile) -- See fake-lsp-server.lua
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ assert_log(pesc([[assert_eq failed: left == "\"shutdown\"", right == "\"test\""]]),
+ fake_lsp_logfile)
end;
on_callback = function(...)
eq(table.remove(expected_callbacks), {...}, "expected callback")
@@ -226,7 +241,7 @@ describe('LSP', function()
it('should succeed with manual shutdown', function()
local expected_callbacks = {
- {NIL, "shutdown", {}, 1};
+ {NIL, "shutdown", {}, 1, NIL};
{NIL, "test", {}, 1};
}
test_rpc_server {
@@ -237,7 +252,8 @@ describe('LSP', function()
client.notify('exit')
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(...)
eq(table.remove(expected_callbacks), {...}, "expected callback")
@@ -255,7 +271,8 @@ describe('LSP', function()
client.stop()
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(...)
eq(table.remove(expected_callbacks), {...}, "expected callback")
@@ -294,7 +311,8 @@ describe('LSP', function()
client.notify('finish')
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback")
@@ -336,7 +354,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -378,7 +397,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -420,7 +440,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -468,7 +489,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -516,7 +538,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -536,7 +559,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 normal mode editting', function()
+ pending('should check the body and didChange incremental normal mode editing', function()
local expected_callbacks = {
{NIL, "shutdown", {}, 1};
{NIL, "finish", {}, 1};
@@ -544,7 +567,7 @@ describe('LSP', function()
}
local client
test_rpc_server {
- test_name = "basic_check_buffer_open_and_change_incremental_editting";
+ test_name = "basic_check_buffer_open_and_change_incremental_editing";
on_setup = function()
exec_lua [[
BUFFER = vim.api.nvim_create_buf(false, true)
@@ -564,7 +587,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -607,7 +631,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -657,7 +682,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
if method == 'start' then
@@ -699,7 +725,8 @@ describe('LSP', function()
client.stop(true)
end;
on_exit = function(code, signal)
- eq(0, code, "exit code") eq(0, signal, "exit signal")
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
end;
on_callback = function(err, method, params, client_id)
eq(table.remove(expected_callbacks), {err, method, params, client_id}, "expected callback")
@@ -785,4 +812,53 @@ describe('LSP', function()
}, buf_lines(1))
end)
end)
+
+ describe('completion_list_to_complete_items', function()
+ -- Completion option precedence:
+ -- textEdit.newText > insertText > label
+ -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+ it('should choose right completion option', function ()
+ local prefix = 'foo'
+ local completion_list = {
+ -- resolves into label
+ { label='foobar' },
+ { label='foobar', textEdit={} },
+ -- resolves into insertText
+ { label='foocar', insertText='foobar' },
+ { label='foocar', insertText='foobar', textEdit={} },
+ -- resolves into textEdit.newText
+ { label='foocar', insertText='foodar', textEdit={newText='foobar'} },
+ { label='foocar', textEdit={newText='foobar'} }
+ }
+ local completion_list_items = {items=completion_list}
+ local expected = {
+ { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ }
+
+ eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix))
+ eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list_items, prefix))
+ eq({}, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], {}, prefix))
+ end)
+ end)
+ describe('buf_diagnostics_save_positions', function()
+ it('stores the diagnostics in diagnostics_by_buf', function ()
+ local diagnostics = {
+ { range = {}; message = "diag1" },
+ { range = {}; message = "diag2" },
+ }
+ exec_lua([[
+ vim.lsp.util.buf_diagnostics_save_positions(...)]], 0, diagnostics)
+ eq(1, exec_lua [[ return #vim.lsp.util.diagnostics_by_buf ]])
+ eq(diagnostics, exec_lua [[
+ for _, diagnostics in pairs(vim.lsp.util.diagnostics_by_buf) do
+ return diagnostics
+ end
+ ]])
+ end)
+ end)
end)
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index ee3db7ae97..0eb5901b3b 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -87,6 +87,36 @@ describe(':terminal mouse', function()
{3:-- TERMINAL --} |
]])
end)
+
+ it('will forward mouse clicks to the program with the correct even if set nu', function()
+ if helpers.pending_win32(pending) then return end
+ nvim('command', 'set number')
+ -- When the display area such as a number is clicked, it returns to the
+ -- normal mode.
+ feed('<LeftMouse><3,0>')
+ eq('n', eval('mode()'))
+ screen:expect([[
+ {7: 11 }^line28 |
+ {7: 12 }line29 |
+ {7: 13 }line30 |
+ {7: 14 }mouse enabled |
+ {7: 15 }rows: 6, cols: 46 |
+ {7: 16 }{2: } |
+ |
+ ]])
+ -- If click on the coordinate (0,1) of the region of the terminal
+ -- (i.e. the coordinate (4,1) of vim), 'CSI !"' is sent to the terminal.
+ feed('i<LeftMouse><4,1>')
+ screen:expect([[
+ {7: 11 }line28 |
+ {7: 12 }line29 |
+ {7: 13 }line30 |
+ {7: 14 }mouse enabled |
+ {7: 15 }rows: 6, cols: 46 |
+ {7: 16 } !"{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
end)
describe('with a split window and other buffer', function()
@@ -148,7 +178,7 @@ describe(':terminal mouse', function()
end)
it('wont lose focus if another window is scrolled', function()
- feed('<ScrollWheelUp><0,0><ScrollWheelUp><0,0>')
+ feed('<ScrollWheelUp><4,0><ScrollWheelUp><4,0>')
screen:expect([[
{7: 21 }line │line30 |
{7: 22 }line │rows: 5, cols: 25 |
@@ -158,7 +188,7 @@ describe(':terminal mouse', function()
========== ========== |
{3:-- TERMINAL --} |
]])
- feed('<S-ScrollWheelDown><0,0>')
+ feed('<S-ScrollWheelDown><4,0>')
screen:expect([[
{7: 26 }line │line30 |
{7: 27 }line │rows: 5, cols: 25 |
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 7a5569c14b..639e311ae6 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -976,6 +976,28 @@ describe('floatwin', function()
{2:~ }|
]], float_pos={
[5] = {{id = 1002}, "NE", 4, 0, 50, true}
+ }, win_viewport = {
+ [2] = {
+ topline = 0,
+ botline = 3,
+ curline = 0,
+ curcol = 3,
+ win = { id = 1000 }
+ },
+ [4] = {
+ topline = 0,
+ botline = 3,
+ curline = 0,
+ curcol = 3,
+ win = { id = 1001 }
+ },
+ [5] = {
+ topline = 0,
+ botline = 2,
+ curline = 0,
+ curcol = 0,
+ win = { id = 1002 }
+ }
}}
else
screen:expect([[
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 0b788e7afb..6ec45064da 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -96,8 +96,20 @@ describe("folded lines", function()
{1: ~}|
:set rightleft |
]]}
- end)
+ feed_command("set norightleft")
+ meths.input_mouse('left', 'press', '', 0, 0, 1)
+ screen:expect{grid=[[
+ {7:▾▸}{5:^+--- 5 lines: aa··························}|
+ {7:│ }ff |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :set norightleft |
+ ]]}
+ end)
it("works with multibyte text", function()
-- Currently the only allowed value of 'maxcombine'
@@ -283,4 +295,64 @@ describe("folded lines", function()
]])
end)
+
+ it("work with autoresize", function()
+
+ funcs.setline(1, 'line 1')
+ funcs.setline(2, 'line 2')
+ funcs.setline(3, 'line 3')
+ funcs.setline(4, 'line 4')
+
+ feed("zfj")
+ command("set foldcolumn=0")
+ screen:expect{grid=[[
+ {5:^+-- 2 lines: line 1·························}|
+ line 3 |
+ line 4 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ -- should adapt to the current nesting of folds (e.g., 1)
+ command("set foldcolumn=auto:1")
+ screen:expect{grid=[[
+ {7:+}{5:^+-- 2 lines: line 1························}|
+ {7: }line 3 |
+ {7: }line 4 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ -- fdc should not change with a new fold as the maximum is 1
+ feed("zf3j")
+
+ screen:expect{grid=[[
+ {7:+}{5:^+-- 4 lines: line 1························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ -- relax the maximum fdc thus fdc should expand to
+ -- accomodate the current number of folds
+ command("set foldcolumn=auto:4")
+ screen:expect{grid=[[
+ {7:+ }{5:^+-- 4 lines: line 1·······················}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
end)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 0b822bc2f2..efc02db159 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -969,6 +969,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
-- edge case: only one window was set NOT_VALID. Orginal report
-- used :make, but fake it using one command to set the current
-- window NOT_VALID and another to show a long message.
+ command("set more")
feed(':new<cr><c-w><c-w>')
screen:expect{grid=[[
|
@@ -982,16 +983,16 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
feed(':set colorcolumn=10 | digraphs<cr>')
screen:expect{grid=[[
- er {5:ㄦ} 12582 i4 {5:ㄧ} 12583 u4 {5:ㄨ} 12584 iu {5:ㄩ} 12585 |
- v4 {5:ㄪ} 12586 nG {5:ㄫ} 12587 gn {5:ㄬ} 12588 1c {5:㈠} 12832 |
- 2c {5:㈡} 12833 3c {5:㈢} 12834 4c {5:㈣} 12835 5c {5:㈤} 12836 |
- 6c {5:㈥} 12837 7c {5:㈦} 12838 8c {5:㈧} 12839 9c {5:㈨} 12840 |
- ff {5:ff} 64256 fi {5:fi} 64257 fl {5:fl} 64258 ft {5:ſt} 64261 |
- st {5:st} 64262 |
- {4:Press ENTER or type command to continue}^ |
+ :set colorcolumn=10 | digraphs |
+ NU {5:^@} 10 SH {5:^A} 1 SX {5:^B} 2 EX {5:^C} 3 |
+ ET {5:^D} 4 EQ {5:^E} 5 AK {5:^F} 6 BL {5:^G} 7 |
+ BS {5:^H} 8 HT {5:^I} 9 LF {5:^@} 10 VT {5:^K} 11 |
+ FF {5:^L} 12 CR {5:^M} 13 SO {5:^N} 14 SI {5:^O} 15 |
+ DL {5:^P} 16 D1 {5:^Q} 17 D2 {5:^R} 18 D3 {5:^S} 19 |
+ {4:-- More --}^ |
]]}
- feed('<cr>')
+ feed('q')
screen:expect{grid=[[
|
{1:~ }|
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 01ffe80be3..e4d1187dea 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -1962,4 +1962,191 @@ describe('ext_multigrid', function()
{1:~ }|
]]}
end)
+
+ it('has viewport information', function()
+ screen:try_resize(48, 8)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {11:[No Name] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0}
+ }}
+ insert([[
+ Lorem ipsum dolor sit amet, consectetur
+ adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua.
+ Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex
+ ea commodo consequat. Duis aute irure dolor in
+ reprehenderit in voluptate velit esse cillum
+ dolore eu fugiat nulla pariatur. Excepteur sint
+ occaecat cupidatat non proident, sunt in culpa
+ qui officia deserunt mollit anim id est
+ laborum.]])
+
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7},
+ }}
+
+
+ feed('<c-u>')
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ incididunt ut labore et dolore magna aliqua. |
+ Ut enim ad minim veniam, quis nostrud |
+ exercitation ullamco laboris nisi ut aliquip ex |
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse cillum |
+ ^dolore eu fugiat nulla pariatur. Excepteur sint |
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0},
+ }}
+
+ command("split")
+ screen:expect{grid=[[
+ ## grid 1
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {12:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ reprehenderit in voluptate velit esse cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ ## grid 3
+ |
+ ## grid 4
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse cillum |
+ ^dolore eu fugiat nulla pariatur. Excepteur sint |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0},
+ [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0},
+ }}
+
+ feed("b")
+ screen:expect{grid=[[
+ ## grid 1
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {12:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ reprehenderit in voluptate velit esse cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ ## grid 3
+ |
+ ## grid 4
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse ^cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0},
+ [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38},
+ }}
+
+ feed("2k")
+ screen:expect{grid=[[
+ ## grid 1
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {12:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ reprehenderit in voluptate velit esse cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ ## grid 3
+ |
+ ## grid 4
+ exercitation ullamco laboris nisi ut a^liquip ex |
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse cillum |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0},
+ [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38},
+ }}
+
+ -- handles non-current window
+ meths.win_set_cursor(1000, {1, 10})
+ screen:expect{grid=[[
+ ## grid 1
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ [4:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {12:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ Lorem ipsum dolor sit amet, consectetur |
+ adipisicing elit, sed do eiusmod tempor |
+ ## grid 3
+ |
+ ## grid 4
+ exercitation ullamco laboris nisi ut a^liquip ex |
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse cillum |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10},
+ [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38},
+ }}
+ end)
end)
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 581e196bbb..9646c3fdad 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -20,6 +20,8 @@ describe('UI receives option updates', function()
pumblend=0,
showtabline=1,
termguicolors=false,
+ ttimeout=true,
+ ttimeoutlen=50,
ext_cmdline=false,
ext_popupmenu=false,
ext_tabline=false,
@@ -108,6 +110,18 @@ describe('UI receives option updates', function()
eq(expected, screen.options)
end)
+ command("set nottimeout")
+ expected.ttimeout = false
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+
+ command("set ttimeoutlen=100")
+ expected.ttimeoutlen = 100
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+
command("set all&")
screen:expect(function()
eq(defaults, screen.options)
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index b2ebf7af19..11c3f4123e 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1338,7 +1338,7 @@ describe('builtin popupmenu', function()
end)
it('with rightleft window', function()
- command("set rl")
+ command("set rl wildoptions+=pum")
feed('isome rightleft ')
screen:expect([[
^ tfelthgir emos|
@@ -1435,6 +1435,55 @@ describe('builtin popupmenu', function()
{1: ~}|
{2:-- INSERT --} |
]])
+
+ -- not rightleft on the cmdline
+ feed('<esc>:sign ')
+ screen:expect{grid=[[
+ drow tfelthgir emos|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ :sign ^ |
+ ]]}
+
+ feed('<tab>')
+ screen:expect{grid=[[
+ drow tfelthgir emos|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: ~}|
+ {1: }{s: define }{1: ~}|
+ {1: }{n: jump }{1: ~}|
+ {1: }{n: list }{1: ~}|
+ {1: }{n: place }{1: ~}|
+ {1: }{n: undefine }{1: ~}|
+ {1: }{n: unplace }{1: ~}|
+ :sign define^ |
+ ]]}
end)
it('with multiline messages', function()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 64f784afe3..bf979e89f4 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -158,6 +158,7 @@ function Screen.new(width, height)
wildmenu_items = nil,
wildmenu_selected = nil,
win_position = {},
+ win_viewport = {},
float_pos = {},
msg_grid = nil,
msg_grid_pos = nil,
@@ -254,7 +255,7 @@ end
-- canonical order of ext keys, used to generate asserts
local ext_keys = {
'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos',
- 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos',
+ 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport'
}
-- Asserts that the screen state eventually matches an expected state.
@@ -421,6 +422,9 @@ screen:redraw_debug() to show all intermediate screen states. ]])
if expected.mode ~= nil then
extstate.mode = self.mode
end
+ if expected.win_viewport == nil then
+ extstate.win_viewport = nil
+ end
-- Convert assertion errors into invalid screen state descriptions.
for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
@@ -726,6 +730,7 @@ function Screen:_handle_grid_destroy(grid)
self._grids[grid] = nil
if self._options.ext_multigrid then
self.win_position[grid] = nil
+ self.win_viewport[grid] = nil
end
end
@@ -746,14 +751,24 @@ function Screen:_handle_grid_cursor_goto(grid, row, col)
end
function Screen:_handle_win_pos(grid, win, startrow, startcol, width, height)
- self.win_position[grid] = {
- win = win,
- startrow = startrow,
- startcol = startcol,
- width = width,
- height = height
- }
- self.float_pos[grid] = nil
+ self.win_position[grid] = {
+ win = win,
+ startrow = startrow,
+ startcol = startcol,
+ width = width,
+ height = height
+ }
+ self.float_pos[grid] = nil
+end
+
+function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol)
+ self.win_viewport[grid] = {
+ win = win,
+ topline = topline,
+ botline = botline,
+ curline = curline,
+ curcol = curcol
+ }
end
function Screen:_handle_win_float_pos(grid, ...)
@@ -1130,6 +1145,8 @@ function Screen:_extstate_repr(attr_state)
messages[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
end
+ local win_viewport = (next(self.win_viewport) and self.win_viewport) or nil
+
return {
popupmenu=self.popupmenu,
cmdline=cmdline,
@@ -1141,7 +1158,8 @@ function Screen:_extstate_repr(attr_state)
showcmd=self:_chunks_repr(self.showcmd, attr_state),
ruler=self:_chunks_repr(self.ruler, attr_state),
msg_history=msg_history,
- float_pos=self.float_pos
+ float_pos=self.float_pos,
+ win_viewport=win_viewport,
}
end
@@ -1216,10 +1234,6 @@ function Screen:render(headers, attr_state, preview)
return rv
end
-local remove_all_metatables = function(item, path)
- if path[#path] ~= inspect.METATABLE then return item end
-end
-
-- Returns the current screen state in the form of a screen:expect()
-- keyword-args map.
function Screen:get_snapshot(attrs, ignore)
@@ -1269,6 +1283,26 @@ function Screen:get_snapshot(attrs, ignore)
return kwargs, ext_state, attr_state
end
+local function fmt_ext_state(name, state)
+ if name == "win_viewport" then
+ local str = "{\n"
+ for k,v in pairs(state) do
+ str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = "
+ ..v.topline..", botline = "..v.botline..", curline = "..v.curline
+ ..", curcol = "..v.curcol.."},\n")
+ end
+ return str .. "}"
+ else
+ -- TODO(bfredl): improve formatting of more states
+ local function remove_all_metatables(item, path)
+ if path[#path] ~= inspect.METATABLE then
+ return item
+ end
+ end
+ return inspect(state,{process=remove_all_metatables})
+ end
+end
+
function Screen:print_snapshot(attrs, ignore)
local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore)
local attrstr = ""
@@ -1291,9 +1325,8 @@ function Screen:print_snapshot(attrs, ignore)
print(kwargs.grid)
io.stdout:write( "]]"..attrstr)
for _, k in ipairs(ext_keys) do
- if ext_state[k] ~= nil then
- -- TODO(bfredl): improve formatting
- io.stdout:write(", "..k.."="..inspect(ext_state[k],{process=remove_all_metatables}))
+ if ext_state[k] ~= nil and not (k == "win_viewport" and not self.options.ext_multigrid) then
+ io.stdout:write(", "..k.."="..fmt_ext_state(k, ext_state[k]))
end
end
print("}\n")
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 56987d7bc2..99ebc4971e 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -16,6 +16,44 @@ describe("'wildmenu'", function()
screen:attach()
end)
+ it('C-E to cancel wildmenu completion restore original input', function()
+ feed(':sign <tab>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ define jump list > |
+ :sign define^ |
+ ]])
+ feed('<C-E>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ :sign ^ |
+ ]])
+ end)
+
+ it('C-Y to apply selection and end wildmenu completion', function()
+ feed(':sign <tab>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ define jump list > |
+ :sign define^ |
+ ]])
+ feed('<tab><C-Y>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ :sign jump^ |
+ ]])
+ end)
+
it(':sign <tab> shows wildmenu completions', function()
command('set wildmenu wildmode=full')
feed(':sign <tab>')
diff --git a/test/helpers.lua b/test/helpers.lua
index 98f003f208..40b93d9935 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -55,17 +55,32 @@ local check_logs_useless_lines = {
['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3,
}
-function module.eq(expected, actual, context)
- return assert.are.same(expected, actual, context)
+--- Invokes `fn` and includes the tail of `logfile` in the error message if it
+--- fails.
+---
+--@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog'
+--@param fn Function to invoke
+--@param ... Function arguments
+local function dumplog(logfile, fn, ...)
+ -- module.validate({
+ -- logfile={logfile,'s',true},
+ -- fn={fn,'f',false},
+ -- })
+ local status, rv = pcall(fn, ...)
+ if status == false then
+ logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
+ local logtail = module.read_nvim_log(logfile)
+ error(string.format('%s\n%s', rv, logtail))
+ end
end
-function module.neq(expected, actual, context)
- return assert.are_not.same(expected, actual, context)
+function module.eq(expected, actual, context, logfile)
+ return dumplog(logfile, assert.are.same, expected, actual, context)
end
-function module.ok(res, msg)
- return assert.is_true(res, msg)
+function module.neq(expected, actual, context, logfile)
+ return dumplog(logfile, assert.are_not.same, expected, actual, context)
end
-function module.near(actual, expected, tolerance)
- return assert.is.near(actual, expected, tolerance)
+function module.ok(res, msg, logfile)
+ return dumplog(logfile, assert.is_true, res, msg)
end
function module.matches(pat, actual)
if nil ~= string.match(actual, pat) then
@@ -74,6 +89,22 @@ function module.matches(pat, actual)
error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual))
end
+--- Asserts that `pat` matches one or more lines in the tail of $NVIM_LOG_FILE.
+---
+--@param pat (string) Lua pattern to search for in the log file.
+--@param logfile (string, default=$NVIM_LOG_FILE) full path to log file.
+function module.assert_log(pat, logfile)
+ logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
+ local nrlines = 10
+ local lines = module.read_file_list(logfile, -nrlines) or {}
+ for _,line in ipairs(lines) do
+ if line:match(pat) then return end
+ end
+ local logtail = module.read_nvim_log(logfile)
+ error(string.format('Pattern %q not found in log (last %d lines): %s:\n%s',
+ pat, nrlines, logfile, logtail))
+end
+
-- Invokes `fn` and returns the error string (may truncate full paths), or
-- raises an error if `fn` succeeds.
--
@@ -259,24 +290,6 @@ module.tmpname = (function()
end)
end)()
-function module.map(func, tab)
- local rettab = {}
- for k, v in pairs(tab) do
- rettab[k] = func(v)
- end
- return rettab
-end
-
-function module.filter(filter_func, tab)
- local rettab = {}
- for _, entry in pairs(tab) do
- if filter_func(entry) then
- table.insert(rettab, entry)
- end
- end
- return rettab
-end
-
function module.hasenv(name)
local env = os.getenv(name)
if env and env ~= '' then
@@ -737,10 +750,10 @@ function module.isCI(name)
end
--- Gets the contents of $NVIM_LOG_FILE for printing to the build log.
+-- Gets the (tail) contents of `logfile`.
-- Also moves the file to "${NVIM_LOG_FILE}.displayed" on CI environments.
-function module.read_nvim_log()
- local logfile = os.getenv('NVIM_LOG_FILE') or '.nvimlog'
+function module.read_nvim_log(logfile, ci_rename)
+ logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
local is_ci = module.isCI()
local keep = is_ci and 999 or 10
local lines = module.read_file_list(logfile, -keep) or {}
@@ -751,7 +764,7 @@ function module.read_nvim_log()
log = log..line..'\n'
end
log = log..('-'):rep(78)..'\n'
- if is_ci then
+ if is_ci and ci_rename then
os.rename(logfile, logfile .. '.displayed')
end
return log
diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua
index 4535d6a0b2..1651eb9bcc 100644
--- a/test/unit/eval/typval_spec.lua
+++ b/test/unit/eval/typval_spec.lua
@@ -14,7 +14,7 @@ local cimport = helpers.cimport
local to_cstr = helpers.to_cstr
local alloc_log_new = helpers.alloc_log_new
local concat_tables = helpers.concat_tables
-local map = helpers.map
+local map = helpers.tbl_map
local a = eval_helpers.alloc_logging_helpers
local int = eval_helpers.int
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index bacdc54416..a77a089763 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -13,7 +13,7 @@ local syscall = nil
local check_cores = global_helpers.check_cores
local dedent = global_helpers.dedent
local neq = global_helpers.neq
-local map = global_helpers.map
+local map = global_helpers.tbl_map
local eq = global_helpers.eq
local trim = global_helpers.trim