aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/README.md14
-rw-r--r--test/functional/api/buffer_spec.lua96
-rw-r--r--test/functional/api/buffer_updates_spec.lua4
-rw-r--r--test/functional/api/menu_spec.lua8
-rw-r--r--test/functional/api/server_notifications_spec.lua7
-rw-r--r--test/functional/api/server_requests_spec.lua7
-rw-r--r--test/functional/api/tabpage_spec.lua2
-rw-r--r--test/functional/api/version_spec.lua74
-rw-r--r--test/functional/api/vim_spec.lua79
-rw-r--r--test/functional/api/window_spec.lua2
-rw-r--r--test/functional/core/channels_spec.lua2
-rw-r--r--test/functional/core/job_spec.lua18
-rw-r--r--test/functional/core/startup_spec.lua6
-rw-r--r--test/functional/eval/execute_spec.lua4
-rw-r--r--test/functional/eval/input_spec.lua24
-rw-r--r--test/functional/eval/special_vars_spec.lua12
-rw-r--r--test/functional/eval/system_spec.lua40
-rw-r--r--test/functional/eval/timer_spec.lua30
-rw-r--r--test/functional/ex_cmds/cmd_map_spec.lua40
-rw-r--r--test/functional/ex_cmds/ctrl_c_spec.lua2
-rw-r--r--test/functional/ex_cmds/digraphs_spec.lua14
-rw-r--r--test/functional/ex_cmds/oldfiles_spec.lua2
-rw-r--r--test/functional/ex_cmds/recover_spec.lua76
-rw-r--r--test/functional/ex_cmds/sign_spec.lua2
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua154
-rw-r--r--test/functional/helpers.lua13
-rw-r--r--test/functional/legacy/003_cindent_spec.lua17
-rw-r--r--test/functional/legacy/008_autocommands_spec.lua45
-rw-r--r--test/functional/legacy/011_autocommands_spec.lua8
-rw-r--r--test/functional/legacy/packadd_spec.lua25
-rw-r--r--test/functional/legacy/search_spec.lua21
-rw-r--r--test/functional/normal/put_spec.lua13
-rw-r--r--test/functional/options/defaults_spec.lua7
-rw-r--r--test/functional/options/fillchars_spec.lua7
-rw-r--r--test/functional/options/shortmess_spec.lua99
-rw-r--r--test/functional/plugin/helpers.lua2
-rw-r--r--test/functional/plugin/msgpack_spec.lua22
-rw-r--r--test/functional/plugin/shada_spec.lua1
-rw-r--r--test/functional/shada/helpers.lua5
-rw-r--r--test/functional/shada/marks_spec.lua4
-rw-r--r--test/functional/shada/shada_spec.lua6
-rw-r--r--test/functional/terminal/buffer_spec.lua8
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua2
-rw-r--r--test/functional/terminal/scrollback_spec.lua26
-rw-r--r--test/functional/terminal/tui_spec.lua35
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua22
-rw-r--r--test/functional/ui/bufhl_spec.lua234
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua32
-rw-r--r--test/functional/ui/cmdline_spec.lua645
-rw-r--r--test/functional/ui/cursor_spec.lua52
-rw-r--r--test/functional/ui/embed_spec.lua81
-rw-r--r--test/functional/ui/fold_spec.lua8
-rw-r--r--test/functional/ui/highlight_spec.lua137
-rw-r--r--test/functional/ui/hlstate_spec.lua287
-rw-r--r--test/functional/ui/inccommand_spec.lua71
-rw-r--r--test/functional/ui/mode_spec.lua116
-rw-r--r--test/functional/ui/mouse_spec.lua31
-rw-r--r--test/functional/ui/options_spec.lua111
-rw-r--r--test/functional/ui/output_spec.lua33
-rw-r--r--test/functional/ui/popupmenu_spec.lua260
-rw-r--r--test/functional/ui/screen.lua800
-rw-r--r--test/functional/ui/screen_basic_spec.lua146
-rw-r--r--test/functional/ui/searchhl_spec.lua66
-rw-r--r--test/functional/ui/sign_spec.lua66
-rw-r--r--test/functional/ui/tabline_spec.lua12
-rw-r--r--test/functional/ui/wildmode_spec.lua81
-rw-r--r--test/functional/viml/completion_spec.lua105
-rw-r--r--test/helpers.lua76
-rw-r--r--test/unit/os/shell_spec.lua31
69 files changed, 3350 insertions, 1238 deletions
diff --git a/test/README.md b/test/README.md
index 9b1f0d084a..0999f412ac 100644
--- a/test/README.md
+++ b/test/README.md
@@ -3,7 +3,9 @@ Tests
Tests are run by `/cmake/RunTests.cmake` file, using `busted`.
-For some failures, `.nvimlog` (or `$NVIM_LOG_FILE`) may provide insight.
+For some failures, `.nvimlog` (or `$NVIM_LOG_FILE`) may provide insight.
+
+Depending on the presence of binaries (e.g., `xclip`) some tests will be ignored. You must compile with libintl to prevent `E319: The command is not available in this version` errors.
---
@@ -62,9 +64,9 @@ To run a *specific* functional test:
TEST_FILE=test/functional/foo.lua make functionaltest
-To *repeat* a test many times:
+To *repeat* a test:
- .deps/usr/bin/busted --filter 'foo' --repeat 1000 test/functional/ui/foo_spec.lua
+ .deps/usr/bin/busted --lpath='build/?.lua' --filter 'foo' --repeat 1000 test/functional/ui/foo_spec.lua
### Filter by tag
@@ -189,12 +191,12 @@ minutes](http://learnxinyminutes.com/docs/lua/).
## Checklist for migrating legacy tests
-**Note:** Only "old style" (`src/testdir/*.in`) legacy tests should be
-converted. Please _do not_ convert "new style" Vim tests (`src/testdir/*.vim`).
+**Note:** Only "old style" (`src/nvim/testdir/*.in`) legacy tests should be
+converted. Please _do not_ convert "new style" Vim tests
+(`src/nvim/testdir/*.vim`).
The "new style" Vim tests are faster than the old ones, and converting them
takes time and effort better spent elsewhere.
-- Remove the test from the Makefile (`src/nvim/testdir/Makefile`).
- Remove the associated `test.in`, `test.out`, and `test.ok` files from
`src/nvim/testdir/`.
- Make sure the lua test ends in `_spec.lua`.
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 823c134ebd..d9412f0f13 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -35,8 +35,37 @@ describe('api/buf', function()
-- There's always at least one line
eq(1, curbuf_depr('line_count'))
end)
- end)
+ it('line_count has defined behaviour for unloaded buffers', function()
+ -- we'll need to know our bufnr for when it gets unloaded
+ local bufnr = curbuf('get_number')
+ -- replace the buffer contents with these three lines
+ request('nvim_buf_set_lines', bufnr, 0, -1, 1, {"line1", "line2", "line3", "line4"})
+ -- check the line count is correct
+ eq(4, request('nvim_buf_line_count', bufnr))
+ -- force unload the buffer (this will discard changes)
+ command('new')
+ command('bunload! '..bufnr)
+ -- line count for an unloaded buffer should always be 0
+ eq(0, request('nvim_buf_line_count', bufnr))
+ end)
+
+ it('get_lines has defined behaviour for unloaded buffers', function()
+ -- we'll need to know our bufnr for when it gets unloaded
+ local bufnr = curbuf('get_number')
+ -- replace the buffer contents with these three lines
+ buffer('set_lines', bufnr, 0, -1, 1, {"line1", "line2", "line3", "line4"})
+ -- confirm that getting lines works
+ eq({"line2", "line3"}, buffer('get_lines', bufnr, 1, 3, 1))
+ -- force unload the buffer (this will discard changes)
+ command('new')
+ command('bunload! '..bufnr)
+ -- attempting to get lines now always gives empty list
+ eq({}, buffer('get_lines', bufnr, 1, 3, 1))
+ -- it's impossible to get out-of-bounds errors for an unloaded buffer
+ eq({}, buffer('get_lines', bufnr, 8888, 9999, 1))
+ end)
+ end)
describe('{get,set,del}_line', function()
it('works', function()
@@ -70,7 +99,6 @@ describe('api/buf', function()
end)
end)
-
describe('{get,set}_line_slice', function()
it('get_line_slice: out-of-bounds returns empty array', function()
curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
@@ -273,6 +301,43 @@ describe('api/buf', function()
end)
end)
+ describe('get_offset', function()
+ local get_offset = curbufmeths.get_offset
+ it('works', function()
+ curbufmeths.set_lines(0,-1,true,{'Some\r','exa\000mple', '', 'buf\rfer', 'text'})
+ eq(5, curbufmeths.line_count())
+ eq(0, get_offset(0))
+ eq(6, get_offset(1))
+ eq(15, get_offset(2))
+ eq(16, get_offset(3))
+ eq(24, get_offset(4))
+ eq(29, get_offset(5))
+ eq({false,'Index out of bounds'}, meth_pcall(get_offset, 6))
+ eq({false,'Index out of bounds'}, meth_pcall(get_offset, -1))
+
+ curbufmeths.set_option('eol', false)
+ curbufmeths.set_option('fixeol', false)
+ eq(28, get_offset(5))
+
+ -- fileformat is ignored
+ curbufmeths.set_option('fileformat', 'dos')
+ eq(0, get_offset(0))
+ eq(6, get_offset(1))
+ eq(15, get_offset(2))
+ eq(16, get_offset(3))
+ eq(24, get_offset(4))
+ eq(28, get_offset(5))
+ curbufmeths.set_option('eol', true)
+ eq(29, get_offset(5))
+
+ command("set hidden")
+ command("enew")
+ eq(6, bufmeths.get_offset(1,1))
+ command("bunload! 1")
+ eq(-1, bufmeths.get_offset(1,1))
+ end)
+ end)
+
describe('{get,set,del}_var', function()
it('works', function()
curbuf('set_var', 'lua', {1, 2, {['3'] = 1}})
@@ -281,7 +346,7 @@ describe('api/buf', function()
eq(1, funcs.exists('b:lua'))
curbufmeths.del_var('lua')
eq(0, funcs.exists('b:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
+ eq({false, 'Key not found: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
curbufmeths.set_var('lua', 1)
command('lockvar b:lua')
eq({false, 'Key is locked: lua'}, meth_pcall(curbufmeths.del_var, 'lua'))
@@ -345,6 +410,31 @@ describe('api/buf', function()
end)
end)
+ describe('is_loaded', function()
+ it('works', function()
+ -- record our buffer number for when we unload it
+ local bufnr = curbuf('get_number')
+ -- api should report that the buffer is loaded
+ ok(buffer('is_loaded', bufnr))
+ -- hide the current buffer by switching to a new empty buffer
+ -- Careful! we need to modify the buffer first or vim will just reuse it
+ buffer('set_lines', bufnr, 0, -1, 1, {'line1'})
+ command('hide enew')
+ -- confirm the buffer is hidden, but still loaded
+ local infolist = nvim('eval', 'getbufinfo('..bufnr..')')
+ eq(1, #infolist)
+ eq(1, infolist[1].hidden)
+ eq(1, infolist[1].loaded)
+ -- now force unload the buffer
+ command('bunload! '..bufnr)
+ -- confirm the buffer is unloaded
+ infolist = nvim('eval', 'getbufinfo('..bufnr..')')
+ eq(0, infolist[1].loaded)
+ -- nvim_buf_is_loaded() should also report the buffer as unloaded
+ eq(false, buffer('is_loaded', bufnr))
+ end)
+ end)
+
describe('is_valid', function()
it('works', function()
nvim('command', 'new')
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index e5cc747f8a..b54d9e1f6e 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -538,10 +538,6 @@ describe('API: buffer events:', function()
end)
it('works with :diffput and :diffget', function()
- if os.getenv("APPVEYOR") then
- pending("Fails on appveyor for some reason.", function() end)
- end
-
local b1, tick1 = editoriginal(true, {"AAA", "BBB"})
local channel = nvim('get_api_info')[1]
command('diffthis')
diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua
index d55b7b118a..2cfa0e3e47 100644
--- a/test/functional/api/menu_spec.lua
+++ b/test/functional/api/menu_spec.lua
@@ -20,15 +20,15 @@ describe("update_menu notification", function()
end)
local function expect_sent(expected)
- screen:wait(function()
+ screen:expect{condition=function()
if screen.update_menu ~= expected then
if expected then
- return 'update_menu was expected but not sent'
+ error('update_menu was expected but not sent')
else
- return 'update_menu was sent unexpectedly'
+ error('update_menu was sent unexpectedly')
end
end
- end)
+ end, unchanged=(not expected)}
end
it("should be sent when adding a menu", function()
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 1d64ae7103..29cd38ef0d 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -65,4 +65,11 @@ describe('notify', function()
eq(nest_level, act_nest_level)
end)
end)
+
+ it('unsubscribe non-existing event #8745', function()
+ nvim('subscribe', 'event1')
+ nvim('unsubscribe', 'doesnotexist')
+ nvim('unsubscribe', 'event1')
+ eq(2, eval('1+1')) -- Still alive?
+ end)
end)
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 856e5ca4d2..4d25ba0819 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -9,7 +9,7 @@ local nvim_prog, command, funcs = helpers.nvim_prog, helpers.command, helpers.fu
local source, next_msg = helpers.source, helpers.next_msg
local ok = helpers.ok
local meths = helpers.meths
-local spawn, nvim_argv = helpers.spawn, helpers.nvim_argv
+local spawn, merge_args = helpers.spawn, helpers.merge_args
local set_session = helpers.set_session
local expect_err = helpers.expect_err
@@ -23,7 +23,7 @@ describe('server -> client', function()
it('handles unexpected closed stream while preparing RPC response', function()
source([[
- let g:_nvim_args = [v:progpath, '--embed', '-n', '-u', 'NONE', '-i', 'NONE', ]
+ let g:_nvim_args = [v:progpath, '--embed', '--headless', '-n', '-u', 'NONE', '-i', 'NONE', ]
let ch1 = jobstart(g:_nvim_args, {'rpc': v:true})
let child1_ch = rpcrequest(ch1, "nvim_get_api_info")[0]
call rpcnotify(ch1, 'nvim_eval', 'rpcrequest('.child1_ch.', "nvim_get_api_info")')
@@ -189,7 +189,7 @@ describe('server -> client', function()
end
before_each(function()
- command("let vim = rpcstart('"..nvim_prog.."', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed'])")
+ command("let vim = rpcstart('"..nvim_prog.."', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed', '--headless'])")
neq(0, eval('vim'))
end)
@@ -268,6 +268,7 @@ describe('server -> client', function()
end)
describe('connecting to another (peer) nvim', function()
+ local nvim_argv = merge_args(helpers.nvim_argv, {'--headless'})
local function connect_test(server, mode, address)
local serverpid = funcs.getpid()
local client = spawn(nvim_argv)
diff --git a/test/functional/api/tabpage_spec.lua b/test/functional/api/tabpage_spec.lua
index 260a91a80c..c49091db02 100644
--- a/test/functional/api/tabpage_spec.lua
+++ b/test/functional/api/tabpage_spec.lua
@@ -34,7 +34,7 @@ describe('api/tabpage', function()
eq(1, funcs.exists('t:lua'))
curtabmeths.del_var('lua')
eq(0, funcs.exists('t:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
+ eq({false, 'Key not found: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
curtabmeths.set_var('lua', 1)
command('lockvar t:lua')
eq({false, 'Key is locked: lua'}, meth_pcall(curtabmeths.del_var, 'lua'))
diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua
index 7bf54c0d1e..b4ae17d963 100644
--- a/test/functional/api/version_spec.lua
+++ b/test/functional/api/version_spec.lua
@@ -46,12 +46,12 @@ end)
describe("api functions", function()
before_each(clear)
- local function func_table(metadata)
- local functions = {}
- for _,f in ipairs(metadata.functions) do
- functions[f.name] = f
+ local function name_table(entries)
+ local by_name = {}
+ for _,e in ipairs(entries) do
+ by_name[e.name] = e
end
- return functions
+ return by_name
end
-- Remove metadata that is not essential to backwards-compatibility.
@@ -67,6 +67,15 @@ describe("api functions", function()
return f
end
+ local function check_ui_event_compatible(old_e, new_e)
+ -- check types of existing params are the same
+ -- adding parameters is ok, but removing params is not (gives nil error)
+ eq(old_e.since, new_e.since, old_e.name)
+ for i,p in ipairs(old_e.parameters) do
+ eq(new_e.parameters[i][1], p[1], old_e.name)
+ end
+ end
+
-- Level 0 represents methods from 0.1.5 and earlier, when 'since' was not
-- yet defined, and metadata was not filtered of internal keys like 'async'.
local function clean_level_0(metadata)
@@ -89,8 +98,10 @@ describe("api functions", function()
stable = api_level
end
- local funcs_new = func_table(api)
+ local funcs_new = name_table(api.functions)
+ local ui_events_new = name_table(api.ui_events)
local funcs_compat = {}
+ local ui_events_compat = {}
for level = compat, stable do
local path = ('test/functional/fixtures/api_level_'..
tostring(level)..'.mpack')
@@ -119,8 +130,18 @@ describe("api functions", function()
filter_function_metadata(funcs_new[f.name]))
end
end
-
- funcs_compat[level] = func_table(old_api)
+ funcs_compat[level] = name_table(old_api.functions)
+
+ -- UI events were formalized in level 3
+ if level >= 3 then
+ for _,e in ipairs(old_api.ui_events) do
+ local new_e = ui_events_new[e.name]
+ if new_e ~= nil then
+ check_ui_event_compatible(e, new_e)
+ end
+ end
+ ui_events_compat[level] = name_table(old_api.ui_events)
+ end
end
for _,f in ipairs(api.functions) do
@@ -140,9 +161,38 @@ describe("api functions", function()
end
end
elseif f.since > api_level then
- error("function "..f.name.." has since value > api_level. "..
- "Please bump NVIM_API_CURRENT and set "..
- "NVIM_API_PRERELEASE to true in CMakeLists.txt.")
+ if api.version.api_prerelease then
+ error("New function "..f.name.." should use since value "..
+ api_level)
+ else
+ error("function "..f.name.." has since value > api_level. "..
+ "Bump NVIM_API_CURRENT and set "..
+ "NVIM_API_PRERELEASE to true in CMakeLists.txt.")
+ end
+ end
+ end
+
+ for _,e in ipairs(api.ui_events) do
+ if e.since <= stable then
+ local e_old = ui_events_compat[e.since][e.name]
+ if e_old == nil then
+ local errstr = ("UI event "..e.name.." has too low since value. "..
+ "For new events set it to "..(stable+1)..".")
+ if not api.version.api_prerelease then
+ errstr = (errstr.." Also bump NVIM_API_CURRENT and set "..
+ "NVIM_API_PRERELEASE to true in CMakeLists.txt.")
+ end
+ error(errstr)
+ end
+ elseif e.since > api_level then
+ if api.version.api_prerelease then
+ error("New UI event "..e.name.." should use since value "..
+ api_level)
+ else
+ error("UI event "..e.name.." has since value > api_level. "..
+ "Bump NVIM_API_CURRENT and set "..
+ "NVIM_API_PRERELEASE to true in CMakeLists.txt.")
+ end
end
end
end)
@@ -156,6 +206,6 @@ describe("ui_options in metadata", function()
local api = helpers.call('api_info')
local options = api.ui_options
eq({'rgb', 'ext_cmdline', 'ext_popupmenu',
- 'ext_tabline', 'ext_wildmenu'}, options)
+ 'ext_tabline', 'ext_wildmenu', 'ext_linegrid', 'ext_hlstate'}, options)
end)
end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index e4b343c123..a9d137391e 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -24,13 +24,25 @@ describe('API', function()
before_each(clear)
it('validates requests', function()
- expect_err('Invalid method: bogus',
+ -- RPC
+ expect_err('Invalid method: bogus$',
request, 'bogus')
- expect_err('Invalid method: … の り 。…',
+ expect_err('Invalid method: … の り 。…$',
request, '… の り 。…')
- expect_err('Invalid method: <empty>',
+ expect_err('Invalid method: <empty>$',
request, '')
- expect_err("can't serialize object",
+
+ -- Non-RPC: rpcrequest(v:servername) uses internal channel.
+ expect_err('Invalid method: … の り 。…$',
+ request, 'nvim_eval',
+ [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), '… の り 。…')]=])
+ expect_err('Invalid method: bogus$',
+ request, 'nvim_eval',
+ [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), 'bogus')]=])
+
+ -- XXX: This must be the last one, else next one will fail:
+ -- "Packer instance already working. Use another Packer ..."
+ expect_err("can't serialize object$",
request, nil)
end)
@@ -158,7 +170,7 @@ describe('API', function()
end)
it("VimL error: returns error details, does NOT update v:errmsg", function()
- expect_err('E121: Undefined variable: bogus', request,
+ expect_err('E121: Undefined variable: bogus$', request,
'nvim_eval', 'bogus expression')
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
end)
@@ -173,7 +185,7 @@ describe('API', function()
end)
it("VimL validation error: returns specific error, does NOT update v:errmsg", function()
- expect_err('E117: Unknown function: bogus function', request,
+ expect_err('E117: Unknown function: bogus function$', request,
'nvim_call_function', 'bogus function', {'arg1'})
expect_err('E119: Not enough arguments for function: atan', request,
'nvim_call_function', 'atan', {})
@@ -182,11 +194,11 @@ describe('API', function()
end)
it("VimL error: returns error details, does NOT update v:errmsg", function()
- expect_err('E808: Number or Float required', request,
+ expect_err('E808: Number or Float required$', request,
'nvim_call_function', 'atan', {'foo'})
- expect_err('Invalid channel stream "xxx"', request,
+ expect_err('Invalid channel stream "xxx"$', request,
'nvim_call_function', 'chanclose', {999, 'xxx'})
- expect_err('E900: Invalid channel id', request,
+ expect_err('E900: Invalid channel id$', request,
'nvim_call_function', 'chansend', {999, 'foo'})
eq('', eval('v:exception'))
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
@@ -198,7 +210,7 @@ describe('API', function()
throw 'wtf'
endfunction
]])
- expect_err('wtf', request,
+ expect_err('wtf$', request,
'nvim_call_function', 'Foo', {})
eq('', eval('v:exception'))
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
@@ -212,7 +224,7 @@ describe('API', function()
endfunction
]])
-- E740
- expect_err('Function called with too many arguments', request,
+ expect_err('Function called with too many arguments$', request,
'nvim_call_function', 'Foo', too_many_args)
end)
end)
@@ -248,23 +260,23 @@ describe('API', function()
it('validates args', function()
command('let g:d={"baz":"zub","meep":[]}')
- expect_err('Not found: bogus', request,
+ expect_err('Not found: bogus$', request,
'nvim_call_dict_function', 'g:d', 'bogus', {1,2})
- expect_err('Not a function: baz', request,
+ expect_err('Not a function: baz$', request,
'nvim_call_dict_function', 'g:d', 'baz', {1,2})
- expect_err('Not a function: meep', request,
+ expect_err('Not a function: meep$', request,
'nvim_call_dict_function', 'g:d', 'meep', {1,2})
- expect_err('E117: Unknown function: f', request,
+ expect_err('E117: Unknown function: f$', request,
'nvim_call_dict_function', { f = '' }, 'f', {1,2})
- expect_err('Not a function: f', request,
+ expect_err('Not a function: f$', request,
'nvim_call_dict_function', "{ 'f': '' }", 'f', {1,2})
- expect_err('dict argument type must be String or Dictionary', request,
+ expect_err('dict argument type must be String or Dictionary$', request,
'nvim_call_dict_function', 42, 'f', {1,2})
- expect_err('Failed to evaluate dict expression', request,
+ expect_err('Failed to evaluate dict expression$', request,
'nvim_call_dict_function', 'foo', 'f', {1,2})
- expect_err('dict not found', request,
+ expect_err('dict not found$', request,
'nvim_call_dict_function', '42', 'f', {1,2})
- expect_err('Invalid %(empty%) function name', request,
+ expect_err('Invalid %(empty%) function name$', request,
'nvim_call_dict_function', "{ 'f': '' }", '', {1,2})
end)
end)
@@ -337,7 +349,7 @@ describe('API', function()
eq(1, funcs.exists('g:lua'))
meths.del_var('lua')
eq(0, funcs.exists('g:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(meths.del_var, 'lua'))
+ eq({false, "Key not found: lua"}, meth_pcall(meths.del_var, 'lua'))
meths.set_var('lua', 1)
command('lockvar lua')
eq({false, 'Key is locked: lua'}, meth_pcall(meths.del_var, 'lua'))
@@ -829,10 +841,6 @@ describe('API', function()
end)
it('works for job channel', function()
- if iswin() and os.getenv('APPVEYOR') ~= nil then
- pending("jobstart(['cat']) unreliable on appveyor")
- return
- end
eq(3, eval("jobstart(['cat'], {'rpc': v:true})"))
local info = {
stream='job',
@@ -948,7 +956,7 @@ describe('API', function()
}
local status, err = pcall(meths.call_atomic, req)
eq(false, status)
- ok(err:match(' All items in calls array must be arrays of size 2') ~= nil)
+ ok(err:match('Items in calls array must be arrays of size 2') ~= nil)
-- call before was done, but not after
eq(1, meths.get_var('avar'))
@@ -958,7 +966,7 @@ describe('API', function()
}
status, err = pcall(meths.call_atomic, req)
eq(false, status)
- ok(err:match('All items in calls array must be arrays') ~= nil)
+ ok(err:match('Items in calls array must be arrays') ~= nil)
eq({2,3}, meths.get_var('bvar'))
req = {
@@ -1242,6 +1250,8 @@ describe('API', function()
ext_popupmenu = false,
ext_tabline = false,
ext_wildmenu = false,
+ ext_linegrid = screen._options.ext_linegrid or false,
+ ext_hlstate=false,
height = 4,
rgb = true,
width = 20,
@@ -1252,18 +1262,9 @@ describe('API', function()
screen:detach()
screen = Screen.new(44, 99)
screen:attach({ rgb = false })
- expected = {
- {
- chan = 1,
- ext_cmdline = false,
- ext_popupmenu = false,
- ext_tabline = false,
- ext_wildmenu = false,
- height = 99,
- rgb = false,
- width = 44,
- }
- }
+ expected[1].rgb = false
+ expected[1].width = 44
+ expected[1].height = 99
eq(expected, nvim("list_uis"))
end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index d404ef5426..27d7aa11b4 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -169,7 +169,7 @@ describe('api/win', function()
eq(1, funcs.exists('w:lua'))
curwinmeths.del_var('lua')
eq(0, funcs.exists('w:lua'))
- eq({false, 'Key does not exist: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
+ eq({false, 'Key not found: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
curwinmeths.set_var('lua', 1)
command('lockvar w:lua')
eq({false, 'Key is locked: lua'}, meth_pcall(curwinmeths.del_var, 'lua'))
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index f79f208b69..7b89172f92 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -192,7 +192,6 @@ describe('channels', function()
end)
it('can use buffered output mode', function()
- if helpers.pending_win32(pending) then return end
source([[
let g:job_opts = {
\ 'on_stdout': function('OnEvent'),
@@ -225,7 +224,6 @@ describe('channels', function()
end)
it('can use buffered output mode with no stream callback', function()
- if helpers.pending_win32(pending) then return end
source([[
function! OnEvent(id, data, event) dict
call rpcnotify(1, a:event, a:id, a:data, self.stdout)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 4a21444ee0..eb02610df0 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -17,6 +17,7 @@ local pathroot = helpers.pathroot
local nvim_set = helpers.nvim_set
local expect_twostreams = helpers.expect_twostreams
local expect_msg_seq = helpers.expect_msg_seq
+local expect_err = helpers.expect_err
local Screen = require('test.functional.ui.screen')
-- Kill process with given pid
@@ -115,6 +116,17 @@ describe('jobs', function()
ok(string.find(err, "E475: Invalid argument: expected valid directory$") ~= nil)
end)
+ it('produces error when using non-executable `cwd`', function()
+ if iswin() then return end -- N/A for Windows
+
+ local dir = 'Xtest_not_executable_dir'
+ mkdir(dir)
+ funcs.setfperm(dir, 'rw-------')
+ expect_err('E475: Invalid argument: expected valid directory$', nvim,
+ 'command', "call jobstart('pwd', {'cwd': '" .. dir .. "'})")
+ rmdir(dir)
+ end)
+
it('returns 0 when it fails to start', function()
eq("", eval("v:errmsg"))
feed_command("let g:test_jobid = jobstart([])")
@@ -417,7 +429,7 @@ describe('jobs', function()
\ })
]])
- screen:expect("{2:E120: Using <SID> not in a script context: s:OnEvent}",nil,nil,nil,true)
+ screen:expect{any="{2:E120: Using <SID> not in a script context: s:OnEvent}"}
end)
it('does not repeat output with slow output handlers', function()
@@ -663,7 +675,7 @@ describe('jobs', function()
call rpcnotify(g:channel, 'wait', jobwait([
\ jobstart('exit 4'),
\ jobstart((has('win32') ? 'Start-Sleep 10' : 'sleep 10').'; exit 5'),
- \ ], has('win32') ? 3000 : 100))
+ \ ], has('win32') ? 6000 : 100))
]])
eq({'notification', 'wait', {{4, -1}}}, next_msg())
end)
@@ -731,7 +743,7 @@ describe('jobs', function()
local children
retry(nil, nil, function()
children = meths.get_proc_children(ppid)
- eq(3, #children)
+ eq((iswin() and 4 or 3), #children)
end)
-- Assert that nvim_get_proc() sees the children.
for _, child_pid in ipairs(children) do
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 2a67453bce..15121261c7 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local eval = helpers.eval
local feed = helpers.feed
local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
@@ -196,5 +197,10 @@ describe('startup', function()
funcs.system({nvim_prog, '-n', '-es' },
{ 'set encoding', '' }))
end)
+
+ it('does not crash if --embed is given twice', function()
+ clear{args={'--embed'}}
+ eq(2, eval('1+1'))
+ end)
end)
diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua
index 925e311c7d..af37ab8d55 100644
--- a/test/functional/eval/execute_spec.lua
+++ b/test/functional/eval/execute_spec.lua
@@ -161,13 +161,13 @@ describe('execute()', function()
eq('42', eval('g:mes'))
command('let g:mes = execute("echon 13", "silent")')
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
|
- ]])
+ ]], unchanged=true}
eq('13', eval('g:mes'))
end)
diff --git a/test/functional/eval/input_spec.lua b/test/functional/eval/input_spec.lua
index 777f49462d..8c65297ac6 100644
--- a/test/functional/eval/input_spec.lua
+++ b/test/functional/eval/input_spec.lua
@@ -149,14 +149,14 @@ describe('input()', function()
{EOB:~ }|
{T:Foo>}Bar^ |
]])
- command('redraw!')
- screen:expect([[
+ command('mode')
+ screen:expect{grid=[[
|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{T:Foo>}Bar^ |
- ]])
+ ]], reset=true}
feed('<BS>')
screen:expect([[
|
@@ -165,14 +165,14 @@ describe('input()', function()
{EOB:~ }|
{T:Foo>}Ba^ |
]])
- command('redraw!')
- screen:expect([[
+ command('mode')
+ screen:expect{grid=[[
|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{T:Foo>}Ba^ |
- ]])
+ ]], reset=true}
end)
it('allows omitting everything with dictionary argument', function()
command('echohl Test')
@@ -347,14 +347,14 @@ describe('inputdialog()', function()
{EOB:~ }|
{T:Foo>}Bar^ |
]])
- command('redraw!')
- screen:expect([[
+ command('mode')
+ screen:expect{grid=[[
|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{T:Foo>}Bar^ |
- ]])
+ ]], reset=true}
feed('<BS>')
screen:expect([[
|
@@ -363,14 +363,14 @@ describe('inputdialog()', function()
{EOB:~ }|
{T:Foo>}Ba^ |
]])
- command('redraw!')
- screen:expect([[
+ command('mode')
+ screen:expect{grid=[[
|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{T:Foo>}Ba^ |
- ]])
+ ]], reset=true}
end)
it('allows omitting everything with dictionary argument', function()
command('echohl Test')
diff --git a/test/functional/eval/special_vars_spec.lua b/test/functional/eval/special_vars_spec.lua
index b5773a5529..97a12d490d 100644
--- a/test/functional/eval/special_vars_spec.lua
+++ b/test/functional/eval/special_vars_spec.lua
@@ -174,5 +174,17 @@ describe('Special values', function()
command('let count = []') -- v:count is readonly
eq(1, eval('count is# g:["count"]'))
end)
+ it('v:errmsg is distinct from errmsg', function()
+ command('let errmsg = 1')
+ eq(1, eval('errmsg is# g:["errmsg"]'))
+ end)
+ it('v:shell_error is distinct from shell_error', function()
+ command('let shell_error = []') -- v:shell_error is readonly
+ eq(1, eval('shell_error is# g:["shell_error"]'))
+ end)
+ it('v:this_session is distinct from this_session', function()
+ command('let this_session = []')
+ eq(1, eval('this_session is# g:["this_session"]'))
+ end)
end)
end)
diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua
index 5e12b6a6a4..5cbf34365b 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -124,7 +124,6 @@ describe('system()', function()
local screen
before_each(function()
- clear()
screen = Screen.new()
screen:attach()
end)
@@ -203,6 +202,38 @@ describe('system()', function()
]])
end)
+ it('prints verbose information', function()
+ screen:try_resize(72, 14)
+ feed(':4verbose echo system("echo hi")<cr>')
+ if iswin() then
+ screen:expect{any=[[Executing command: "'cmd.exe' '/s' '/c' '"echo hi"'"]]}
+ else
+ screen:expect{any=[[Executing command: "'/[^']*sh' '%-c' 'echo hi'"]]}
+ end
+ feed('<cr>')
+ end)
+
+ it('self and total time recorded separately', function()
+ local tempfile = helpers.tmpname()
+
+ feed(':function! AlmostNoSelfTime()<cr>')
+ feed('echo system("echo hi")<cr>')
+ feed('endfunction<cr>')
+
+ feed(':profile start ' .. tempfile .. '<cr>')
+ feed(':profile func AlmostNoSelfTime<cr>')
+ feed(':call AlmostNoSelfTime()<cr>')
+ feed(':profile dump<cr>')
+
+ feed(':edit ' .. tempfile .. '<cr>')
+
+ local command_total_time = tonumber(helpers.funcs.split(helpers.funcs.getline(7))[2])
+ local command_self_time = tonumber(helpers.funcs.split(helpers.funcs.getline(7))[3])
+
+ helpers.neq(nil, command_total_time)
+ helpers.neq(nil, command_self_time)
+ end)
+
it('`yes` interrupted with CTRL-C', function()
feed(':call system("' .. (iswin()
and 'for /L %I in (1,0,2) do @echo y'
@@ -386,13 +417,12 @@ describe('systemlist()', function()
local screen
before_each(function()
- clear()
- screen = Screen.new()
- screen:attach()
+ screen = Screen.new()
+ screen:attach()
end)
after_each(function()
- screen:detach()
+ screen:detach()
end)
it('`echo` and waits for its return', function()
diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua
index 2dd9968a01..124b9625c3 100644
--- a/test/functional/eval/timer_spec.lua
+++ b/test/functional/eval/timer_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local ok, feed, eq, eval = helpers.ok, helpers.feed, helpers.eq, helpers.eval
+local feed, eq, eval = helpers.feed, helpers.eq, helpers.eval
local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs
local curbufmeths = helpers.curbufmeths
@@ -72,7 +72,8 @@ describe('timers', function()
run(nil, nil, nil, 300)
feed("<cr>")
local diff = eval("g:val") - count
- ok(0 <= diff and diff <= 4)
+ assert(0 <= diff and diff <= 4,
+ 'expected (0 <= diff <= 4), got: '..tostring(diff))
end)
it('are triggered in blocking getchar() call', function()
@@ -81,7 +82,7 @@ describe('timers', function()
run(nil, nil, nil, 300)
feed("c")
local count = eval("g:val")
- ok(count >= 4)
+ assert(count >= 3, 'expected count >= 3, got: '..tostring(count))
eq(99, eval("g:c"))
end)
@@ -96,6 +97,7 @@ describe('timers', function()
source([[
func! AddItem(timer)
call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3'])
+ call getchar(1)
redraw
endfunc
call timer_start(200, 'AddItem')
@@ -111,7 +113,6 @@ describe('timers', function()
^ |
]])
- screen:sleep(200)
screen:expect([[
ITEM 1 |
ITEM 2 |
@@ -141,9 +142,10 @@ describe('timers', function()
local count = eval("g:val")
run(nil, nil, nil, 300)
local count2 = eval("g:val")
- ok(4 <= count and count <= 7)
-- when count is eval:ed after timer_stop this should be non-racy
eq(count, count2)
+ assert(3 <= count and count <= 7,
+ 'expected (3 <= count <= 7), got: '..tostring(count))
end)
it('can be stopped from the handler', function()
@@ -170,8 +172,8 @@ describe('timers', function()
let g:val2 += 1
endfunc
]])
- command("call timer_start(50, 'MyHandler', {'repeat': 3})")
- command("call timer_start(100, 'MyHandler2', {'repeat': 2})")
+ command("call timer_start(20, 'MyHandler', {'repeat': 3})")
+ command("call timer_start(40, 'MyHandler2', {'repeat': 2})")
run(nil, nil, nil, 300)
eq(3,eval("g:val"))
eq(2,eval("g:val2"))
@@ -197,13 +199,14 @@ describe('timers', function()
screen:attach()
screen:set_default_attr_ids( {[0] = {bold=true, foreground=255}} )
source([[
+ let g:val = 0
func! MyHandler(timer)
echo "evil"
+ let g:val = 1
endfunc
]])
command("call timer_start(100, 'MyHandler', {'repeat': 1})")
feed(":good")
- screen:sleep(200)
screen:expect([[
|
{0:~ }|
@@ -212,6 +215,17 @@ describe('timers', function()
{0:~ }|
:good^ |
]])
+
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :good^ |
+ ]], intermediate=true, timeout=200}
+
+ eq(1, eval('g:val'))
end)
end)
diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 77d025dcc7..67b3ab49d6 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -8,6 +8,7 @@ local eval = helpers.eval
local funcs = helpers.funcs
local insert = helpers.insert
local exc_exec = helpers.exc_exec
+local source = helpers.source
local Screen = require('test.functional.ui.screen')
describe('mappings with <Cmd>', function()
@@ -656,7 +657,6 @@ describe('mappings with <Cmd>', function()
end)
it('works in cmdline mode', function()
- cmdmap('<F2>', 'call setcmdpos(2)')
feed(':text<F3>')
eq('c', eval('m'))
-- didn't leave cmdline mode
@@ -768,5 +768,43 @@ describe('mappings with <Cmd>', function()
end)
+ it("doesn't crash when invoking cmdline mode recursively #8859", function()
+ cmdmap('<F2>', 'norm! :foo')
+ feed(':bar')
+ screen:expect([[
+ some short lines |
+ of test text |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :bar^ |
+ ]])
+
+ feed('<f2>x')
+ screen:expect([[
+ some short lines |
+ of test text |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :barx^ |
+ ]])
+ end)
+
+ it("works with <SID> mappings", function()
+ source([[
+ map <f2> <Cmd>call <SID>do_it()<Cr>
+ function! s:do_it()
+ let g:x = 10
+ endfunction
+ ]])
+ feed('<f2>')
+ eq('', eval('v:errmsg'))
+ eq(10, eval('g:x'))
+ end)
end)
diff --git a/test/functional/ex_cmds/ctrl_c_spec.lua b/test/functional/ex_cmds/ctrl_c_spec.lua
index 8f76099f79..4c5383b712 100644
--- a/test/functional/ex_cmds/ctrl_c_spec.lua
+++ b/test/functional/ex_cmds/ctrl_c_spec.lua
@@ -43,7 +43,7 @@ describe("CTRL-C (mapped)", function()
feed(":global/^/p<CR>")
screen:sleep(ms)
feed("<C-C>")
- screen:expect([[Interrupt]], nil, nil, nil, true)
+ screen:expect{any="Interrupt"}
end
-- The test is time-sensitive. Try different sleep values.
diff --git a/test/functional/ex_cmds/digraphs_spec.lua b/test/functional/ex_cmds/digraphs_spec.lua
index f2d0b76739..37d3814136 100644
--- a/test/functional/ex_cmds/digraphs_spec.lua
+++ b/test/functional/ex_cmds/digraphs_spec.lua
@@ -23,13 +23,13 @@ describe(':digraphs', function()
it('displays digraphs', function()
feed(':digraphs<CR>')
screen:expect([[
- A@ {6:Å} 197 E` {6:È} 200 E^ {6:Ê} 202 E" {6:Ë} 203 I` {6:Ì} 204 |
- I^ {6:Î} 206 I" {6:Ï} 207 N~ {6:Ñ} 209 O` {6:Ò} 210 O^ {6:Ô} 212 |
- O~ {6:Õ} 213 /\ {6:×} 215 U` {6:Ù} 217 U^ {6:Û} 219 Ip {6:Þ} 222 |
- a` {6:à} 224 a^ {6:â} 226 a~ {6:ã} 227 a" {6:ä} 228 a@ {6:å} 229 |
- e` {6:è} 232 e^ {6:ê} 234 e" {6:ë} 235 i` {6:ì} 236 i^ {6:î} 238 |
- n~ {6:ñ} 241 o` {6:ò} 242 o^ {6:ô} 244 o~ {6:õ} 245 u` {6:ù} 249 |
- u^ {6:û} 251 y" {6:ÿ} 255 |
+ E` {6:È} 200 E^ {6:Ê} 202 E" {6:Ë} 203 I` {6:Ì} 204 I^ {6:Î} 206 |
+ I" {6:Ï} 207 N~ {6:Ñ} 209 O` {6:Ò} 210 O^ {6:Ô} 212 O~ {6:Õ} 213 |
+ /\ {6:×} 215 U` {6:Ù} 217 U^ {6:Û} 219 Ip {6:Þ} 222 a` {6:à} 224 |
+ a^ {6:â} 226 a~ {6:ã} 227 a" {6:ä} 228 a@ {6:å} 229 e` {6:è} 232 |
+ e^ {6:ê} 234 e" {6:ë} 235 i` {6:ì} 236 i^ {6:î} 238 n~ {6:ñ} 241 |
+ o` {6:ò} 242 o^ {6:ô} 244 o~ {6:õ} 245 u` {6:ù} 249 u^ {6:û} 251 |
+ y" {6:ÿ} 255 |
{3:Press ENTER or type command to continue}^ |
]])
end)
diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua
index 448326cdfb..e2958c2924 100644
--- a/test/functional/ex_cmds/oldfiles_spec.lua
+++ b/test/functional/ex_cmds/oldfiles_spec.lua
@@ -9,7 +9,7 @@ local eval = helpers.eval
local shada_file = 'Xtest.shada'
local function _clear()
- set_session(spawn({nvim_prog, '--embed', '-u', 'NONE',
+ set_session(spawn({nvim_prog, '--embed', '--headless', '-u', 'NONE',
-- Need shada for these tests.
'-i', shada_file,
'--cmd', 'set noswapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'}))
diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua
deleted file mode 100644
index cb68c29b9a..0000000000
--- a/test/functional/ex_cmds/recover_spec.lua
+++ /dev/null
@@ -1,76 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local lfs = require('lfs')
-local feed_command, eq, clear, eval, feed, expect, source =
- helpers.feed_command, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
- helpers.expect, helpers.source
-local command = helpers.command
-local ok = helpers.ok
-local rmdir = helpers.rmdir
-
-describe(':recover', function()
- before_each(clear)
-
- it('fails if given a non-existent swapfile', function()
- local swapname = 'bogus-swapfile'
- feed_command('recover '..swapname) -- This should not segfault. #2117
- eq('E305: No swap file found for '..swapname, eval('v:errmsg'))
- end)
-
-end)
-
-describe(':preserve', function()
- local swapdir = lfs.currentdir()..'/testdir_recover_spec'
- before_each(function()
- clear()
- rmdir(swapdir)
- lfs.mkdir(swapdir)
- end)
- after_each(function()
- command('%bwipeout!')
- rmdir(swapdir)
- end)
-
- it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
- local testfile = 'testfile_recover_spec'
- -- Put swapdir at the start of the 'directory' list. #1836
- -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
- -- attempt to create a swapfile in different directory.
- local init = [[
- set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//
- set swapfile fileformat=unix undolevels=-1
- ]]
-
- source(init)
- command('edit! '..testfile)
- feed('isometext<esc>')
- command('preserve')
- source('redir => g:swapname | silent swapname | redir END')
-
- local swappath1 = eval('g:swapname')
-
- --TODO(justinmk): this is an ugly hack to force `helpers` to support
- --multiple sessions.
- local nvim2 = helpers.spawn({helpers.nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
- true)
- helpers.set_session(nvim2)
-
- source(init)
-
- -- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
- command('autocmd SwapExists * let v:swapchoice = "r"')
- command('silent edit! '..testfile)
- source('redir => g:swapname | silent swapname | redir END')
-
- local swappath2 = eval('g:swapname')
-
- expect('sometext')
- -- swapfile from session 1 should end in .swp
- eq(testfile..'.swp', string.match(swappath1, '[^%%]+$'))
- -- swapfile from session 2 should end in .swo
- eq(testfile..'.swo', string.match(swappath2, '[^%%]+$'))
- -- Verify that :swapname was not truncated (:help 'shortmess').
- ok(nil == string.find(swappath1, '%.%.%.'))
- ok(nil == string.find(swappath2, '%.%.%.'))
- end)
-
-end)
diff --git a/test/functional/ex_cmds/sign_spec.lua b/test/functional/ex_cmds/sign_spec.lua
index df0f5db860..9d08a66625 100644
--- a/test/functional/ex_cmds/sign_spec.lua
+++ b/test/functional/ex_cmds/sign_spec.lua
@@ -7,7 +7,7 @@ describe('sign', function()
describe('without specifying buffer', function()
it('deletes the sign from all buffers', function()
-- place a sign with id 34 to first buffer
- nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment')
+ nvim('command', 'sign define Foo text=+ texthl=Delimiter linehl=Comment numhl=Number')
local buf1 = nvim('eval', 'bufnr("%")')
nvim('command', 'sign place 34 line=3 name=Foo buffer='..buf1)
-- create a second buffer and place the sign on it as well
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
new file mode 100644
index 0000000000..577a26178a
--- /dev/null
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -0,0 +1,154 @@
+local Screen = require('test.functional.ui.screen')
+local helpers = require('test.functional.helpers')(after_each)
+local lfs = require('lfs')
+local feed_command, eq, eval, expect, source =
+ helpers.feed_command, helpers.eq, helpers.eval, helpers.expect, helpers.source
+local clear = helpers.clear
+local command = helpers.command
+local feed = helpers.feed
+local nvim_prog = helpers.nvim_prog
+local ok = helpers.ok
+local rmdir = helpers.rmdir
+local set_session = helpers.set_session
+local spawn = helpers.spawn
+
+describe(':recover', function()
+ before_each(clear)
+
+ it('fails if given a non-existent swapfile', function()
+ local swapname = 'bogus-swapfile'
+ feed_command('recover '..swapname) -- This should not segfault. #2117
+ eq('E305: No swap file found for '..swapname, eval('v:errmsg'))
+ end)
+
+end)
+
+describe(':preserve', function()
+ local swapdir = lfs.currentdir()..'/Xtest_recover_dir'
+ before_each(function()
+ clear()
+ rmdir(swapdir)
+ lfs.mkdir(swapdir)
+ end)
+ after_each(function()
+ command('%bwipeout!')
+ rmdir(swapdir)
+ end)
+
+ it("saves to custom 'directory' and (R)ecovers #1836", function()
+ local testfile = 'Xtest_recover_file1'
+ -- Put swapdir at the start of the 'directory' list. #1836
+ -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
+ -- attempt to create a swapfile in different directory.
+ local init = [[
+ set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//
+ set swapfile fileformat=unix undolevels=-1
+ ]]
+
+ source(init)
+ command('edit! '..testfile)
+ feed('isometext<esc>')
+ command('preserve')
+ source('redir => g:swapname | silent swapname | redir END')
+
+ local swappath1 = eval('g:swapname')
+
+ -- Start another Nvim instance.
+ local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
+ true)
+ set_session(nvim2)
+
+ source(init)
+
+ -- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
+ command('autocmd SwapExists * let v:swapchoice = "r"')
+ command('silent edit! '..testfile)
+ source('redir => g:swapname | silent swapname | redir END')
+
+ local swappath2 = eval('g:swapname')
+
+ expect('sometext')
+ -- swapfile from session 1 should end in .swp
+ eq(testfile..'.swp', string.match(swappath1, '[^%%]+$'))
+ -- swapfile from session 2 should end in .swo
+ eq(testfile..'.swo', string.match(swappath2, '[^%%]+$'))
+ -- Verify that :swapname was not truncated (:help 'shortmess').
+ ok(nil == string.find(swappath1, '%.%.%.'))
+ ok(nil == string.find(swappath2, '%.%.%.'))
+ end)
+
+end)
+
+describe('swapfile detection', function()
+ local swapdir = lfs.currentdir()..'/Xtest_swapdialog_dir'
+ before_each(function()
+ clear()
+ rmdir(swapdir)
+ lfs.mkdir(swapdir)
+ end)
+ after_each(function()
+ command('%bwipeout!')
+ rmdir(swapdir)
+ end)
+
+ it('always show swapfile dialog #8840 #9027', function()
+ local testfile = 'Xtest_swapdialog_file1'
+ -- Put swapdir at the start of the 'directory' list. #1836
+ -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
+ -- attempt to create a swapfile in different directory.
+ local init = [[
+ set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[//
+ set swapfile fileformat=unix undolevels=-1 hidden
+ ]]
+
+ local expected_no_dialog = '^'..(' '):rep(256)..'|\n'
+ for _=1,37 do
+ expected_no_dialog = expected_no_dialog..'~'..(' '):rep(255)..'|\n'
+ end
+ expected_no_dialog = expected_no_dialog..testfile..(' '):rep(216)..'0,0-1 All|\n'
+ expected_no_dialog = expected_no_dialog..(' '):rep(256)..'|\n'
+
+ source(init)
+ command('edit! '..testfile)
+ feed('isometext<esc>')
+ command('preserve')
+
+ -- Start another Nvim instance.
+ local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
+ true)
+ set_session(nvim2)
+ local screen2 = Screen.new(256, 40)
+ screen2:attach()
+ source(init)
+
+ -- With shortmess+=F
+ command('set shortmess+=F')
+ feed(':edit '..testfile..'<CR>')
+ screen2:expect{any=[[E325: ATTENTION.*]]..'\n'..[[Found a swap file by the name ".*]]
+ ..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]}
+ feed('e') -- Chose "Edit" at the swap dialog.
+ screen2:expect(expected_no_dialog)
+
+ -- With :silent and shortmess+=F
+ feed(':silent edit %<CR>')
+ screen2:expect{any=[[Found a swap file by the name ".*]]
+ ..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]}
+ feed('e') -- Chose "Edit" at the swap dialog.
+ screen2:expect(expected_no_dialog)
+
+ -- With :silent! and shortmess+=F
+ feed(':silent! edit %<CR>')
+ screen2:expect{any=[[Found a swap file by the name ".*]]
+ ..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]}
+ feed('e') -- Chose "Edit" at the swap dialog.
+ screen2:expect(expected_no_dialog)
+
+ -- With API (via eval/VimL) call and shortmess+=F
+ feed(':call nvim_command("edit %")<CR>')
+ screen2:expect{any=[[Found a swap file by the name ".*]]
+ ..[[Xtest_swapdialog_dir[/\].*]]..testfile..[[%.swp"]]}
+ feed('e') -- Chose "Edit" at the swap dialog.
+ feed('<c-c>')
+ screen2:expect(expected_no_dialog)
+ end)
+end)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index a6d2764187..db90cb559f 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -18,6 +18,7 @@ local expect_err = global_helpers.expect_err
local filter = global_helpers.filter
local map = global_helpers.map
local matches = global_helpers.matches
+local near = global_helpers.near
local neq = global_helpers.neq
local ok = global_helpers.ok
local read_file = global_helpers.read_file
@@ -299,8 +300,10 @@ end
-- Calls fn() until it succeeds, up to `max` times or until `max_ms`
-- milliseconds have passed.
local function retry(max, max_ms, fn)
+ assert(max == nil or max > 0)
+ assert(max_ms == nil or max_ms > 0)
local tries = 1
- local timeout = (max_ms and max_ms > 0) and max_ms or 10000
+ local timeout = (max_ms and max_ms or 10000)
local start_time = luv.now()
while true do
local status, result = pcall(fn)
@@ -329,6 +332,7 @@ local function clear(...)
local new_args
local env = nil
local opts = select(1, ...)
+ local headless = true
if type(opts) == 'table' then
if opts.env then
local env_tbl = {}
@@ -354,9 +358,15 @@ local function clear(...)
end
end
new_args = opts.args or {}
+ if opts.headless == false then
+ headless = false
+ end
else
new_args = {...}
end
+ if headless then
+ table.insert(args, '--headless')
+ end
for _, arg in ipairs(new_args) do
table.insert(args, arg)
end
@@ -699,6 +709,7 @@ local module = {
meths = meths,
missing_provider = missing_provider,
mkdir = lfs.mkdir,
+ near = near,
neq = neq,
new_pipename = new_pipename,
next_msg = next_msg,
diff --git a/test/functional/legacy/003_cindent_spec.lua b/test/functional/legacy/003_cindent_spec.lua
index 1cede8a7d7..061904c42f 100644
--- a/test/functional/legacy/003_cindent_spec.lua
+++ b/test/functional/legacy/003_cindent_spec.lua
@@ -4754,4 +4754,21 @@ describe('cindent', function()
4
/* end of define */]=])
end)
+
+ it('* immediately follows comment / vim-patch 8.0.1291', function()
+ insert_([=[
+ {
+ a = second/*bug*/*line;
+ }]=])
+
+ feed_command('set cin cino&')
+ feed_command('/a = second')
+ feed('ox')
+
+ expect([=[
+ {
+ a = second/*bug*/*line;
+ x
+ }]=])
+ end)
end)
diff --git a/test/functional/legacy/008_autocommands_spec.lua b/test/functional/legacy/008_autocommands_spec.lua
index 453638ce45..939404cb5e 100644
--- a/test/functional/legacy/008_autocommands_spec.lua
+++ b/test/functional/legacy/008_autocommands_spec.lua
@@ -2,9 +2,9 @@
-- Test for BufUnload autocommand that unloads all other buffers.
local helpers = require('test.functional.helpers')(after_each)
-local feed, source = helpers.feed, helpers.source
-local clear, feed_command, expect, eq, eval = helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.eval
-local write_file, wait, dedent = helpers.write_file, helpers.wait, helpers.dedent
+local source = helpers.source
+local clear, command, expect, eq, eval = helpers.clear, helpers.command, helpers.expect, helpers.eq, helpers.eval
+local write_file, dedent = helpers.write_file, helpers.dedent
local read_file = helpers.read_file
describe('autocommands that delete and unload buffers:', function()
@@ -26,29 +26,25 @@ describe('autocommands that delete and unload buffers:', function()
before_each(clear)
it('BufWritePre, BufUnload', function()
- feed_command('au BufWritePre Xxx1 bunload')
- feed_command('au BufWritePre Xxx2 bwipe')
- feed_command('e Xxx2')
+ command('au BufWritePre Xxx1 bunload')
+ command('au BufWritePre Xxx2 bwipe')
+ command('e Xxx2')
eq('Xxx2', eval('bufname("%")'))
- feed_command('e Xxx1')
+ command('e Xxx1')
eq('Xxx1', eval('bufname("%")'))
-- The legacy test file did not check the error message.
- feed_command('let v:errmsg = "no error"')
- feed_command('write')
- -- Discard all "hit enter" prompts and messages.
- feed('<C-L>')
+ command('let v:errmsg = "no error"')
+ command('silent! write')
eq('E203: Autocommands deleted or unloaded buffer to be written',
eval('v:errmsg'))
eq('Xxx2', eval('bufname("%")'))
expect(text2)
-- Start editing Xxx2.
- feed_command('e! Xxx2')
+ command('e! Xxx2')
-- The legacy test file did not check the error message.
- feed_command('let v:errmsg = "no error"')
+ command('let v:errmsg = "no error"')
-- Write Xxx2, will delete the buffer and give an error msg.
- feed_command('w')
- -- Discard all "hit enter" prompts and messages.
- feed('<C-L>')
+ command('silent! write')
eq('E203: Autocommands deleted or unloaded buffer to be written',
eval('v:errmsg'))
eq('Xxx1', eval('bufname("%")'))
@@ -75,18 +71,11 @@ describe('autocommands that delete and unload buffers:', function()
au BufUnload * call CloseAll()
au VimLeave * call WriteToOut()
]])
- feed_command('e Xxx2')
- -- Discard all "hit enter" prompts and messages.
- feed('<C-L>')
- feed_command('e Xxx1')
- -- Discard all "hit enter" prompts and messages.
- feed('<C-L>')
- feed_command('e Makefile') -- an existing file
- feed('<C-L>')
- feed_command('sp new2')
- feed('<C-L>')
- feed_command('q')
- wait()
+ command('silent! edit Xxx2')
+ command('silent! edit Xxx1')
+ command('silent! edit Makefile') -- an existing file
+ command('silent! split new2')
+ command('silent! quit')
eq('VimLeave done',
string.match(read_file(test_file), "^%s*(.-)%s*$"))
end)
diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua
index 379646b2ba..7cc31dc787 100644
--- a/test/functional/legacy/011_autocommands_spec.lua
+++ b/test/functional/legacy/011_autocommands_spec.lua
@@ -18,6 +18,7 @@ local clear, feed_command, expect, eq, neq, dedent, write_file, feed =
helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.neq,
helpers.dedent, helpers.write_file, helpers.feed
local iswin = helpers.iswin
+local read_file = helpers.read_file
local function has_gzip()
local null = iswin() and 'nul' or '/dev/null'
@@ -60,7 +61,7 @@ describe('file reading, writing and bufnew and filter autocommands', function()
os.remove('test.out')
end)
- if iswin() or not has_gzip() then
+ if not has_gzip() then
pending('skipped (missing `gzip` utility)', function() end)
else
@@ -77,7 +78,7 @@ describe('file reading, writing and bufnew and filter autocommands', function()
it('BufReadPre, BufReadPost (using gzip)', function()
prepare_gz_file('Xtestfile', text1)
- local gzip_data = io.open('Xtestfile.gz'):read('*all')
+ local gzip_data = read_file('Xtestfile.gz')
feed_command('let $GZIP = ""')
-- Setup autocommands to decompress before reading and re-compress afterwards.
feed_command("au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand('<afile>'))")
@@ -91,7 +92,7 @@ describe('file reading, writing and bufnew and filter autocommands', function()
-- Expect the decompressed file in the buffer.
expect(text1)
-- Expect the original file to be unchanged.
- eq(gzip_data, io.open('Xtestfile.gz'):read('*all'))
+ eq(gzip_data, read_file('Xtestfile.gz'))
end)
-- luacheck: ignore 621 (Indentation)
@@ -142,7 +143,6 @@ describe('file reading, writing and bufnew and filter autocommands', function()
end)
it('FilterReadPre, FilterReadPost', function()
- if helpers.pending_win32(pending) then return end
-- Write a special input file for this test block.
write_file('test.out', dedent([[
startstart
diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua
index fb308475c0..7c3d48317b 100644
--- a/test/functional/legacy/packadd_spec.lua
+++ b/test/functional/legacy/packadd_spec.lua
@@ -15,7 +15,7 @@ describe('packadd', function()
source([=[
func SetUp()
- let s:topdir = expand(expand('%:p:h') . '/Xdir')
+ let s:topdir = expand(getcwd() . '/Xdir')
exe 'set packpath=' . s:topdir
let s:plugdir = expand(s:topdir . '/pack/mine/opt/mytest')
endfunc
@@ -58,6 +58,24 @@ describe('packadd', function()
call assert_fails("packadd", 'E471:')
endfunc
+ func Test_packadd_start()
+ let plugdir = expand(s:topdir . '/pack/mine/start/other')
+ call mkdir(plugdir . '/plugin', 'p')
+ set rtp&
+ let rtp = &rtp
+ filetype on
+
+ exe 'split ' . plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 24')
+ wq
+
+ packadd other
+
+ call assert_equal(24, g:plugin_works)
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_true(&rtp =~ (escape(plugdir, '\') . '\($\|,\)'))
+ endfunc
+
func Test_packadd_noload()
call mkdir(s:plugdir . '/plugin', 'p')
call mkdir(s:plugdir . '/syntax', 'p')
@@ -286,6 +304,11 @@ describe('packadd', function()
expected_empty()
end)
+ it('loads packages from "start" directory', function()
+ call('Test_packadd_start')
+ expected_empty()
+ end)
+
describe('command line completion', function()
local Screen = require('test.functional.ui.screen')
local screen
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index 277d8d6c7f..3ed06a22e7 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -92,6 +92,7 @@ describe('search cmdline', function()
9 {inc:the}se |
/the^ |
]])
+ screen.bell = false
feed('<C-G>')
if wrapscan == 'wrapscan' then
screen:expect([[
@@ -100,11 +101,13 @@ describe('search cmdline', function()
/the^ |
]])
else
- screen:expect([[
+ screen:expect{grid=[[
8 them |
9 {inc:the}se |
/the^ |
- ]])
+ ]], condition=function()
+ eq(true, screen.bell)
+ end}
feed('<CR>')
eq({0, 0, 0, 0}, funcs.getpos('"'))
end
@@ -120,6 +123,7 @@ describe('search cmdline', function()
10 foobar |
?the^ |
]])
+ screen.bell = false
if wrapscan == 'wrapscan' then
feed('<C-G>')
screen:expect([[
@@ -135,11 +139,13 @@ describe('search cmdline', function()
]])
else
feed('<C-G>')
- screen:expect([[
+ screen:expect{grid=[[
9 {inc:the}se |
10 foobar |
?the^ |
- ]])
+ ]], condition=function()
+ eq(true, screen.bell)
+ end}
feed('<CR>')
screen:expect([[
9 ^these |
@@ -173,6 +179,7 @@ describe('search cmdline', function()
3 the |
?the^ |
]])
+ screen.bell = false
feed('<C-T>')
if wrapscan == 'wrapscan' then
screen:expect([[
@@ -181,11 +188,13 @@ describe('search cmdline', function()
?the^ |
]])
else
- screen:expect([[
+ screen:expect{grid=[[
2 {inc:the}se |
3 the |
?the^ |
- ]])
+ ]], condition=function()
+ eq(true, screen.bell)
+ end}
end
end
diff --git a/test/functional/normal/put_spec.lua b/test/functional/normal/put_spec.lua
index 148a35ec6b..29cef13e39 100644
--- a/test/functional/normal/put_spec.lua
+++ b/test/functional/normal/put_spec.lua
@@ -874,20 +874,23 @@ describe('put command', function()
local function bell_test(actions, should_ring)
local screen = Screen.new()
screen:attach()
+ if should_ring then
+ -- check bell is not set by nvim before the action
+ screen:sleep(50)
+ end
helpers.ok(not screen.bell and not screen.visualbell)
actions()
- helpers.wait()
- screen:wait(function()
+ screen:expect{condition=function()
if should_ring then
if not screen.bell and not screen.visualbell then
- return 'Bell was not rung after action'
+ error('Bell was not rung after action')
end
else
if screen.bell or screen.visualbell then
- return 'Bell was rung after action'
+ error('Bell was rung after action')
end
end
- end)
+ end, unchanged=(not should_ring)}
screen:detach()
end
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 787ec366b8..f6f3f02f45 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -118,6 +118,13 @@ describe('startup defaults', function()
clear('-u', 'NORC', '-c', 'syntax off')
eq(0, eval('exists("g:syntax_on")'))
end)
+
+ it('":if 0|syntax on|endif" does not affect default #8728', function()
+ clear('-u', 'NORC', '--cmd', ':if 0|syntax on|endif')
+ eq(1, eval('exists("g:syntax_on")'))
+ clear('-u', 'NORC', '--cmd', ':if 0|syntax off|endif')
+ eq(1, eval('exists("g:syntax_on")'))
+ end)
end)
describe("'fillchars'", function()
diff --git a/test/functional/options/fillchars_spec.lua b/test/functional/options/fillchars_spec.lua
index ab61935d4c..99177a11b4 100644
--- a/test/functional/options/fillchars_spec.lua
+++ b/test/functional/options/fillchars_spec.lua
@@ -36,6 +36,13 @@ describe("'fillchars'", function()
]])
end)
it('supports whitespace', function()
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
command('set fillchars=eob:\\ ')
screen:expect([[
^ |
diff --git a/test/functional/options/shortmess_spec.lua b/test/functional/options/shortmess_spec.lua
index 96823476de..8ea9a19464 100644
--- a/test/functional/options/shortmess_spec.lua
+++ b/test/functional/options/shortmess_spec.lua
@@ -1,43 +1,96 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
local command = helpers.command
-local clear, feed_command = helpers.clear, helpers.feed_command
-
-if helpers.pending_win32(pending) then return end
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
describe("'shortmess'", function()
local screen
before_each(function()
clear()
- screen = Screen.new(25, 5)
+ screen = Screen.new(42, 5)
screen:attach()
end)
- after_each(function()
- screen:detach()
- end)
-
describe('"F" flag', function()
- it('hides messages about the files read', function()
- command("set shortmess-=F")
- feed_command('e test')
+ it('hides :edit fileinfo messages', function()
+ command('set hidden')
+ command('set shortmess-=F')
+ feed(':edit foo<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ "foo" [New File] |
+ ]])
+ eq(1, eval('bufnr("%")'))
+
+ command('set shortmess+=F')
+ feed(':edit bar<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ :edit bar |
+ ]])
+ eq(2, eval('bufnr("%")'))
+ end)
+
+ it('hides :bnext, :bprevious fileinfo messages', function()
+ command('set hidden')
+ command('set shortmess-=F')
+ feed(':edit foo<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ "foo" [New File] |
+ ]])
+ eq(1, eval('bufnr("%")'))
+ feed(':edit bar<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ "bar" [New File] |
+ ]])
+ eq(2, eval('bufnr("%")'))
+ feed(':bprevious<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ "foo" [New file] --No lines in buffer-- |
+ ]])
+ eq(1, eval('bufnr("%")'))
+
+ command('set shortmess+=F')
+ feed(':bnext<CR>')
screen:expect([[
- ^ |
- ~ |
- ~ |
- ~ |
- "test" is a directory |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ :bnext |
]])
- feed_command('set shortmess=F')
- feed_command('e test')
+ eq(2, eval('bufnr("%")'))
+ feed(':bprevious<CR>')
screen:expect([[
- ^ |
- ~ |
- ~ |
- ~ |
- :e test |
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ :bprevious |
]])
+ eq(1, eval('bufnr("%")'))
end)
end)
end)
diff --git a/test/functional/plugin/helpers.lua b/test/functional/plugin/helpers.lua
index 2024e6ebbf..4359380bd7 100644
--- a/test/functional/plugin/helpers.lua
+++ b/test/functional/plugin/helpers.lua
@@ -13,7 +13,7 @@ local function nvim_argv(shada_file)
'--cmd', 'set shortmess+=I background=light noswapfile belloff= noshowcmd noruler',
'--cmd', 'let &runtimepath=' .. rtp_value,
'--cmd', additional_cmd,
- '--embed'}
+ '--embed', '--headless'}
if helpers.prepend_argv then
return merge_args(helpers.prepend_argv, nvim_args)
else
diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua
index 4b014cbc73..2ce9974812 100644
--- a/test/functional/plugin/msgpack_spec.lua
+++ b/test/functional/plugin/msgpack_spec.lua
@@ -581,6 +581,8 @@ describe('autoload/msgpack.vim', function()
eval_eq('binary', {'', 'abc', '', '', 'def'}, '"\\nabc\\n\\n\\ndef"')
eval_eq('binary', {''}, '""')
eval_eq('binary', {'"'}, '"\\""')
+ eval_eq('binary', {'py3 print(sys.version_info)'},
+ '"py3 print(sys.version_info)"')
end)
it('correctly loads strings', function()
@@ -595,6 +597,8 @@ describe('autoload/msgpack.vim', function()
eval_eq('string', {'', 'abc', '', '', 'def'}, '="\\nabc\\n\\n\\ndef"')
eval_eq('string', {''}, '=""')
eval_eq('string', {'"'}, '="\\""')
+ eval_eq('string', {'py3 print(sys.version_info)'},
+ '="py3 print(sys.version_info)"')
end)
it('correctly loads ext values', function()
@@ -625,6 +629,9 @@ describe('autoload/msgpack.vim', function()
'+(-1)"\\nabc\\n\\n\\ndef"')
eval_eq('ext', {-1, {''}}, '+(-1)""')
eval_eq('ext', {-1, {'"'}}, '+(-1)"\\""')
+
+ eval_eq('ext', {42, {'py3 print(sys.version_info)'}},
+ '+(42)"py3 print(sys.version_info)"')
end)
it('correctly loads floats', function()
@@ -676,6 +683,13 @@ describe('autoload/msgpack.vim', function()
eval_eq('map', {{{_TYPE={}, _VAL={{1, 2}}}, {_TYPE={}, _VAL={{3, 4}}}},
{1, 2}},
'{{1: 2}: {3: 4}, 1: 2}')
+
+ eval_eq('map', {{{_TYPE={}, _VAL={
+ {{_TYPE={}, _VAL={'py3 print(sys.version_info)'}},
+ 2}}},
+ {_TYPE={}, _VAL={{3, 4}}}},
+ {1, 2}},
+ '{{"py3 print(sys.version_info)": 2}: {3: 4}, 1: 2}')
end)
it('correctly loads arrays', function()
@@ -684,6 +698,9 @@ describe('autoload/msgpack.vim', function()
eval_eq('array', {{_TYPE={}, _VAL=1}}, '[TRUE]')
eval_eq('array', {{{_TYPE={}, _VAL={{1, 2}}}}, {_TYPE={}, _VAL={{3, 4}}}},
'[[{1: 2}], {3: 4}]')
+
+ eval_eq('array', {{_TYPE={}, _VAL={'py3 print(sys.version_info)'}}},
+ '["py3 print(sys.version_info)"]')
end)
it('errors out when needed', function()
@@ -711,6 +728,11 @@ describe('autoload/msgpack.vim', function()
exc_exec('call msgpack#eval("0x", {})'))
eq('name-unknown:Unknown name FOO: FOO',
exc_exec('call msgpack#eval("FOO", {})'))
+
+ eq('name-unknown:Unknown name py3: py3 print(sys.version_info)',
+ exc_exec('call msgpack#eval("py3 print(sys.version_info)", {})'))
+ eq('name-unknown:Unknown name o: o',
+ exc_exec('call msgpack#eval("-info", {})'))
end)
end)
end)
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 5a5b4df1ef..1482d83ee6 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -2301,7 +2301,6 @@ describe('plugin/shada.vim', function()
describe('event FileWriteCmd', function()
it('works', function()
- if helpers.pending_win32(pending) then return end
nvim('set_var', 'shada#add_own_header', 0)
curbuf('set_lines', 0, 1, true, {
'Jump with timestamp ' .. epoch .. ':',
diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua
index 1312d762d8..d5e061bb50 100644
--- a/test/functional/shada/helpers.lua
+++ b/test/functional/shada/helpers.lua
@@ -9,9 +9,12 @@ local tmpname = helpers.tmpname()
local append_argv = nil
local function nvim_argv(shada_file, embed)
+ if embed == nil then
+ embed = true
+ end
local argv = {nvim_prog, '-u', 'NONE', '-i', shada_file or tmpname, '-N',
'--cmd', 'set shortmess+=I background=light noswapfile',
- embed or '--embed'}
+ '--headless', embed and '--embed' or nil}
if helpers.prepend_argv or append_argv then
return merge_args(helpers.prepend_argv, argv, append_argv)
else
diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua
index 4cceae1aa3..c2f6351e00 100644
--- a/test/functional/shada/marks_spec.lua
+++ b/test/functional/shada/marks_spec.lua
@@ -224,7 +224,7 @@ describe('ShaDa support code', function()
it('does not create incorrect file for non-existent buffers when writing from -c',
function()
add_argv('--cmd', 'silent edit ' .. non_existent_testfilename, '-c', 'qall')
- local argv = nvim_argv(nil, '--headless')
+ local argv = nvim_argv(nil, false) -- no --embed
eq('', funcs.system(argv))
eq(0, exc_exec('rshada'))
end)
@@ -233,7 +233,7 @@ describe('ShaDa support code', function()
function()
add_argv('-c', 'silent edit ' .. non_existent_testfilename,
'-c', 'autocmd VimEnter * qall')
- local argv = nvim_argv(nil, '--headless')
+ local argv = nvim_argv(nil, false) -- no --embed
eq('', funcs.system(argv))
eq(0, exc_exec('rshada'))
end)
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index 720855860a..5f7daf73e5 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -137,7 +137,7 @@ describe('ShaDa support code', function()
it('does not write NONE file', function()
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
- '--cmd', 'qall'}, true)
+ '--headless', '--cmd', 'qall'}, true)
session:close()
eq(nil, lfs.attributes('NONE'))
eq(nil, lfs.attributes('NONE.tmp.a'))
@@ -145,8 +145,8 @@ describe('ShaDa support code', function()
it('does not read NONE file', function()
write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-')
- local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
- true)
+ local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
+ '--headless'}, true)
set_session(session)
eq('', funcs.getreg('a'))
session:close()
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index c290031fbe..4d6b125f9f 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -207,18 +207,18 @@ describe('terminal buffer', function()
feed_command('terminal')
feed('<c-\\><c-n>')
feed_command('confirm bdelete')
- screen:expect('Close "term://', nil, true, nil, true)
+ screen:expect{any='Close "term://', attr_ignore=true}
end)
it('with &confirm', function()
feed_command('terminal')
feed('<c-\\><c-n>')
feed_command('bdelete')
- screen:expect('E89', nil, true, nil, true)
+ screen:expect{any='E89', attr_ignore=true}
feed('<cr>')
eq('terminal', eval('&buftype'))
feed_command('set confirm | bdelete')
- screen:expect('Close "term://', nil, true, nil, true)
+ screen:expect{any='Close "term://', attr_ignore=true}
feed('y')
neq('terminal', eval('&buftype'))
end)
@@ -242,7 +242,7 @@ describe('No heap-buffer-overflow when using', function()
feed('$')
-- Let termopen() modify the buffer
feed_command('call termopen("echo")')
- wait()
+ eq(2, eval('1+1')) -- check nvim still running
feed_command('bdelete!')
end)
end)
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index f98add41a0..dbee9bdb49 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -54,7 +54,7 @@ describe(':terminal', function()
else
feed_command([[terminal printf '\e[6n'; sleep 0.5 ]])
end
- screen:expect('%^%[%[1;1R', nil, nil, nil, true)
+ screen:expect{any='%^%[%[1;1R'}
end)
it("in normal-mode :split does not move cursor", function()
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index c665e64a80..1c97441213 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -396,19 +396,18 @@ describe("'scrollback' option", function()
it('set to 0 behaves as 1', function()
local screen
if iswin() then
- screen = thelpers.screen_setup(nil,
- "['powershell.exe', '-NoLogo', '-NoProfile', '-NoExit', '-Command', 'function global:prompt {return "..'"$"'.."}']", 30)
+ screen = thelpers.screen_setup(nil, "['cmd.exe']", 30)
else
screen = thelpers.screen_setup(nil, "['sh']", 30)
end
curbufmeths.set_option('scrollback', 0)
if iswin() then
- feed_data('for($i=1;$i -le 30;$i++){Write-Host \"line$i\"}\r')
+ feed_data('for /L %I in (1,1,30) do @(echo line%I)\r')
else
feed_data('for i in $(seq 1 30); do echo "line$i"; done\n')
end
- screen:expect('line30 ', nil, nil, nil, true)
+ screen:expect{any='line30 '}
retry(nil, nil, function() expect_lines(7) end)
screen:detach()
@@ -417,8 +416,8 @@ describe("'scrollback' option", function()
it('deletes lines (only) if necessary', function()
local screen
if iswin() then
- screen = thelpers.screen_setup(nil,
- "['powershell.exe', '-NoLogo', '-NoProfile', '-NoExit', '-Command', 'function global:prompt {return "..'"$"'.."}']", 30)
+ command([[let $PROMPT='$$']])
+ screen = thelpers.screen_setup(nil, "['cmd.exe']", 30)
else
screen = thelpers.screen_setup(nil, "['sh']", 30)
end
@@ -426,16 +425,15 @@ describe("'scrollback' option", function()
curbufmeths.set_option('scrollback', 200)
-- Wait for prompt.
- screen:expect('$', nil, nil, nil, true)
+ screen:expect{any='%$'}
- wait()
if iswin() then
- feed_data('for($i=1;$i -le 30;$i++){Write-Host \"line$i\"}\r')
+ feed_data('for /L %I in (1,1,30) do @(echo line%I)\r')
else
feed_data('for i in $(seq 1 30); do echo "line$i"; done\n')
end
- screen:expect('line30 ', nil, nil, nil, true)
+ screen:expect{any='line30 '}
retry(nil, nil, function() expect_lines(33, 2) end)
curbufmeths.set_option('scrollback', 10)
@@ -447,17 +445,17 @@ describe("'scrollback' option", function()
-- 'scrollback' option is synchronized with the internal sb_buffer.
command('sleep 100m')
if iswin() then
- feed_data('for($i=1;$i -le 40;$i++){Write-Host \"line$i\"}\r')
+ feed_data('for /L %I in (1,1,40) do @(echo line%I)\r')
else
feed_data('for i in $(seq 1 40); do echo "line$i"; done\n')
end
- screen:expect('line40 ', nil, nil, nil, true)
+ screen:expect{any='line40 '}
retry(nil, nil, function() expect_lines(58) end)
-- Verify off-screen state
- eq('line35', eval("getline(line('w0') - 1)"))
- eq('line26', eval("getline(line('w0') - 10)"))
+ eq((iswin() and 'line36' or 'line35'), eval("getline(line('w0') - 1)"))
+ eq((iswin() and 'line27' or 'line26'), eval("getline(line('w0') - 10)"))
screen:detach()
end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 5603224975..365bd2a0be 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -17,7 +17,6 @@ local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
-local wait = helpers.wait
if helpers.pending_win32(pending) then return end
@@ -207,7 +206,7 @@ describe('tui', function()
screen:set_default_attr_ids({
[1] = {reverse = true},
[2] = {foreground = 13, special = Screen.colors.Grey0},
- [3] = {special = Screen.colors.Grey0, bold = true, reverse = true},
+ [3] = {bold = true, reverse = true, special = Screen.colors.Grey0},
[4] = {bold = true},
[5] = {special = Screen.colors.Grey0, reverse = true, foreground = 4},
[6] = {foreground = 4, special = Screen.colors.Grey0},
@@ -257,11 +256,11 @@ describe('tui', function()
it('shows up in nvim_list_uis', function()
feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(v))})\013')
screen:expect([=[
- {5: }|
- [[['ext_cmdline', v:false], ['ext_popupmenu', v:fa|
- lse], ['ext_tabline', v:false], ['ext_wildmenu', v|
- :false], ['height', 6], ['rgb', v:false], ['width'|
- , 50]]] |
+ [[['ext_cmdline', v:false], ['ext_hlstate', v:fals|
+ e], ['ext_linegrid', v:true], ['ext_popupmenu', v:|
+ false], ['ext_tabline', v:false], ['ext_wildmenu',|
+ v:false], ['height', 6], ['rgb', v:false], ['widt|
+ h', 50]]] |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
]=])
@@ -371,7 +370,7 @@ describe('tui FocusGained/FocusLost', function()
{3:-- TERMINAL --} |
]])
feed_data('\027[O')
- screen:expect([[
+ screen:expect{grid=[[
|
{4:~ }|
{4:~ }|
@@ -379,7 +378,7 @@ describe('tui FocusGained/FocusLost', function()
{5:[No Name] }|
:{1: } |
{3:-- TERMINAL --} |
- ]])
+ ]], unchanged=true}
end)
it('in cmdline-mode', function()
@@ -400,7 +399,7 @@ describe('tui FocusGained/FocusLost', function()
-- Exit cmdline-mode. Redraws from timers/events are blocked during
-- cmdline-mode, so the buffer won't be updated until we exit cmdline-mode.
feed_data('\n')
- screen:expect('lost'..(' '):rep(46)..'\ngained', nil, nil, nil, true)
+ screen:expect{any='lost'..(' '):rep(46)..'\ngained'}
end)
end)
@@ -473,14 +472,24 @@ describe("tui 't_Co' (terminal colors)", function()
nvim_prog,
nvim_set))
- feed_data(":echo &t_Co\n")
- wait()
local tline
if maxcolors == 8 or maxcolors == 16 then
tline = "~ "
else
tline = "{4:~ }"
end
+
+ screen:expect(string.format([[
+ {1: } |
+ %s|
+ %s|
+ %s|
+ %s|
+ |
+ {3:-- TERMINAL --} |
+ ]], tline, tline, tline, tline))
+
+ feed_data(":echo &t_Co\n")
screen:expect(string.format([[
{1: } |
%s|
@@ -740,7 +749,7 @@ describe("tui 'term' option", function()
screen.timeout = 250 -- We want screen:expect() to fail quickly.
retry(nil, 2 * full_timeout, function() -- Wait for TUI thread to set 'term'.
feed_data(":echo 'term='.(&term)\n")
- screen:expect('term='..term_expected, nil, nil, nil, true)
+ screen:expect{any='term='..term_expected}
end)
end
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 714c2476ce..fecffe3295 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -6,6 +6,8 @@ local feed_command = helpers.feed_command
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
+local iswin = helpers.iswin
+local retry = helpers.retry
describe('terminal', function()
local screen
@@ -66,8 +68,22 @@ describe('terminal', function()
end)
it('forwards resize request to the program', function()
- feed([[<C-\><C-N>:]]) -- Go to cmdline-mode, so cursor is at bottom.
- screen:try_resize(screen._width - 3, screen._height - 2)
+ feed([[<C-\><C-N>G:]]) -- Go to cmdline-mode, so cursor is at bottom.
+ local w1, h1 = screen._width - 3, screen._height - 2
+ local w2, h2 = w1 - 6, h1 - 3
+
+ if iswin() then
+ -- win: SIGWINCH is unreliable, use a weaker test. #7506
+ retry(3, 30000, function()
+ screen:try_resize(w1, h1)
+ screen:expect{any='rows: 7, cols: 47'}
+ screen:try_resize(w2, h2)
+ screen:expect{any='rows: 4, cols: 41'}
+ end)
+ return
+ end
+
+ screen:try_resize(w1, h1)
screen:expect([[
tty ready |
rows: 7, cols: 47 |
@@ -78,7 +94,7 @@ describe('terminal', function()
|
:^ |
]])
- screen:try_resize(screen._width - 6, screen._height - 3)
+ screen:try_resize(w2, h2)
screen:expect([[
tty ready |
rows: 7, cols: 47 |
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 5b38921e50..95c9427399 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -3,7 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command, neq = helpers.command, helpers.neq
-local curbufmeths = helpers.curbufmeths
+local curbufmeths, eq = helpers.curbufmeths, helpers.eq
describe('Buffer highlighting', function()
local screen
@@ -23,7 +23,13 @@ describe('Buffer highlighting', function()
[7] = {bold = true},
[8] = {underline = true, bold = true, foreground = Screen.colors.SlateBlue},
[9] = {foreground = Screen.colors.SlateBlue, underline = true},
- [10] = {foreground = Screen.colors.Red}
+ [10] = {foreground = Screen.colors.Red},
+ [11] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [12] = {foreground = Screen.colors.Blue1},
+ [13] = {background = Screen.colors.LightGrey},
+ [14] = {background = Screen.colors.Gray90},
+ [15] = {background = Screen.colors.Gray90, bold = true, foreground = Screen.colors.Brown},
+ [16] = {foreground = Screen.colors.Magenta, background = Screen.colors.Gray90},
})
end)
@@ -77,7 +83,7 @@ describe('Buffer highlighting', function()
|
]])
- clear_hl(-1, 0 , -1)
+ clear_hl(-1, 0, -1)
screen:expect([[
these are some lines |
^ |
@@ -275,4 +281,226 @@ describe('Buffer highlighting', function()
|
]])
end)
+
+ describe('virtual text annotations', function()
+ local set_virtual_text = curbufmeths.set_virtual_text
+ local id1, id2
+ before_each(function()
+ insert([[
+ 1 + 2
+ 3 +
+ x = 4]])
+ feed('O<esc>20A5, <esc>gg')
+ screen:expect([[
+ ^1 + 2 |
+ 3 + |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, |
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ id1 = set_virtual_text(0, 0, {{"=", "Statement"}, {" 3", "Number"}}, {})
+ set_virtual_text(id1, 1, {{"ERROR:", "ErrorMsg"}, {" invalid syntax"}}, {})
+ id2 = set_virtual_text(0, 2, {{"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}}, {})
+ neq(id2, id1)
+
+ end)
+
+ it('works', function()
+ screen:expect([[
+ ^1 + 2 {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ clear_hl(id1, 0, -1)
+ screen:expect([[
+ ^1 + 2 |
+ 3 + |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ -- Handles doublewidth chars, leaving a space if truncating
+ -- in the middle of a char
+ eq(-1, set_virtual_text(-1, 1, {{"暗x事zz速野谷質結育副住新覚丸活解終事", "Comment"}}, {}))
+ screen:expect([[
+ ^1 + 2 |
+ 3 + {12:暗x事zz速野谷質結育副住新覚丸活解終 }|
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed("2Gx")
+ screen:expect([[
+ 1 + 2 |
+ ^ + {12:暗x事zz速野谷質結育副住新覚丸活解終事}|
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed("2Gdd")
+ screen:expect([[
+ 1 + 2 |
+ ^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('is not highlighted by visual selection', function()
+ feed("ggVG")
+ screen:expect([[
+ {13:1 + 2} {3:=}{2: 3} |
+ {13:3 +} {11:ERROR:} invalid syntax |
+ {13:5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}|
+ {13:, 5, 5, 5, 5, 5, 5, } Lorem ipsum dolor s|
+ ^x{13: = 4} |
+ {1:~ }|
+ {1:~ }|
+ {7:-- VISUAL LINE --} |
+ ]])
+
+ feed("<esc>")
+ screen:expect([[
+ 1 + 2 {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ ^x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ -- special case: empty line has extra eol highlight
+ feed("ggd$")
+ screen:expect([[
+ ^ {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed("jvk")
+ screen:expect([[
+ ^ {3:=}{2: 3} |
+ {13:3} + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ {7:-- VISUAL --} |
+ ]])
+
+ feed("o")
+ screen:expect([[
+ {13: }{3:=}{2: 3} |
+ ^3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ {7:-- VISUAL --} |
+ ]])
+ end)
+
+
+ it('works with listchars', function()
+ command("set list listchars+=eol:$")
+ screen:expect([[
+ ^1 + 2{1:$}{3:=}{2: 3} |
+ 3 +{1:$}{11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5,{1:-$}Lorem ipsum dolor s|
+ x = 4{1:$} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ clear_hl(-1, 0, -1)
+ screen:expect([[
+ ^1 + 2{1:$} |
+ 3 +{1:$} |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5,{1:-$} |
+ x = 4{1:$} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('works with cursorline', function()
+ command("set cursorline")
+
+ screen:expect([[
+ {14:^1 + 2 }{15:=}{16: 3}{14: }|
+ 3 + {11:ERROR:} invalid syntax |
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ feed('j')
+ screen:expect([[
+ 1 + 2 {3:=}{2: 3} |
+ {14:^3 + }{11:ERROR:}{14: invalid syntax }|
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
+ , 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+
+ feed('j')
+ screen:expect([[
+ 1 + 2 {3:=}{2: 3} |
+ 3 + {11:ERROR:} invalid syntax |
+ {14:^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}|
+ {14:, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s}|
+ x = 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+ end)
+
end)
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 5d9fffdf23..1568b7816e 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -32,7 +32,7 @@ before_each(function()
highlight RBP4 guibg=Blue
let g:NUM_LVLS = 4
function Redraw()
- redraw!
+ mode
return ''
endfunction
let g:id = ''
@@ -267,7 +267,7 @@ describe('Command-line coloring', function()
:echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
]])
redraw_input()
- screen:expect([[
+ screen:expect{grid=[[
|
{EOB:~ }|
{EOB:~ }|
@@ -276,7 +276,7 @@ describe('Command-line coloring', function()
{EOB:~ }|
{EOB:~ }|
:echo {RBP1:(}{RBP2:(}42{RBP2:)}^ |
- ]])
+ ]], reset=true}
end)
for _, func_part in ipairs({'', 'n', 'msg'}) do
it('disables :echo' .. func_part .. ' messages', function()
@@ -755,7 +755,7 @@ describe('Command-line coloring', function()
eq(1, meths.eval('1'))
end)
end)
-describe('Ex commands coloring support', function()
+describe('Ex commands coloring', function()
it('works', function()
meths.set_var('Nvim_color_cmdline', 'RainBowParens')
feed(':echo (((1)))')
@@ -831,7 +831,7 @@ describe('Ex commands coloring support', function()
|
]])
end)
- it('does not prevent mapping error from cancelling prompt', function()
+ it('mapping error does not cancel prompt', function()
command("cnoremap <expr> x execute('throw 42')[-1]")
feed(':#x')
screen:expect([[
@@ -846,27 +846,17 @@ describe('Ex commands coloring support', function()
]])
feed('<CR>')
screen:expect([[
- ^ |
- {EOB:~ }|
- {EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
- {EOB:~ }|
- |
+ :# |
+ {ERR:Error detected while processing :} |
+ {ERR:E605: Exception not caught: 42} |
+ {ERR:E749: empty buffer} |
+ {PE:Press ENTER or type command to continue}^ |
]])
feed('<CR>')
- screen:expect([[
- ^ |
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- {EOB:~ }|
- |
- ]])
- eq('Error detected while processing :\nE605: Exception not caught: 42',
+ eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer',
meths.command_output('messages'))
end)
it('errors out when failing to get callback', function()
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 5ce49822e5..0ebb62f78f 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -1,23 +1,16 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq
+local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
-local ok = helpers.ok
local command = helpers.command
-describe('external cmdline', function()
+local function test_cmdline(linegrid)
local screen
- local last_level = 0
- local cmdline = {}
- local block = nil
- local wild_items = nil
- local wild_selected = nil
before_each(function()
clear()
- cmdline, block = {}, nil
screen = Screen.new(25, 5)
- screen:attach({rgb=true, ext_cmdline=true})
+ screen:attach({rgb=true, ext_cmdline=true, ext_linegrid=linegrid})
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {reverse = true},
@@ -25,138 +18,73 @@ describe('external cmdline', function()
[4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[5] = {bold = true, foreground = Screen.colors.SeaGreen4},
})
- screen:set_on_event_handler(function(name, data)
- if name == "cmdline_show" then
- local content, pos, firstc, prompt, indent, level = unpack(data)
- ok(level > 0)
- cmdline[level] = {content=content, pos=pos, firstc=firstc,
- prompt=prompt, indent=indent}
- last_level = level
- elseif name == "cmdline_hide" then
- local level = data[1]
- cmdline[level] = nil
- elseif name == "cmdline_special_char" then
- local char, shift, level = unpack(data)
- cmdline[level].special = {char, shift}
- elseif name == "cmdline_pos" then
- local pos, level = unpack(data)
- cmdline[level].pos = pos
- elseif name == "cmdline_block_show" then
- block = data[1]
- elseif name == "cmdline_block_append" then
- block[#block+1] = data[1]
- elseif name == "cmdline_block_hide" then
- block = nil
- elseif name == "wildmenu_show" then
- wild_items = data[1]
- elseif name == "wildmenu_select" then
- wild_selected = data[1]
- elseif name == "wildmenu_hide" then
- wild_items, wild_selected = nil, nil
- end
- end)
end)
after_each(function()
screen:detach()
end)
- local function expect_cmdline(level, expected)
- local attr_ids = screen._default_attr_ids
- local attr_ignore = screen._default_attr_ignore
- local actual = ''
- for _, chunk in ipairs(cmdline[level] and cmdline[level].content or {}) do
- local attrs, text = chunk[1], chunk[2]
- if screen:_equal_attrs(attrs, {}) then
- actual = actual..text
- else
- local attr_id = screen:_get_attr_id(attr_ids, attr_ignore, attrs)
- actual = actual..'{' .. attr_id .. ':' .. text .. '}'
- end
- end
- eq(expected, actual)
- end
-
it('works', function()
feed(':')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(1, last_level)
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 0,
- pos = 0,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}}
feed('sign')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign"}},
+ pos = 4,
+ }}}
feed('<Left>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign" } },
- firstc = ":",
- indent = 0,
- pos = 3,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign"}},
+ pos = 3,
+ }}}
feed('<bs>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sin" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sin"}},
+ pos = 2,
+ }}}
feed('<Esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
end)
describe("redraws statusline on entering", function()
@@ -166,28 +94,32 @@ describe('external cmdline', function()
end)
it('from normal mode', function()
- feed(':')
- screen:expect([[
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {3:n }|
|
+ ]]}
+
+ feed(':')
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
- {3:c^ }|
+ {3:c }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 0,
- pos = 0,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}}
end)
it('but not with scrolled messages', function()
screen:try_resize(50,10)
feed(':echoerr doesnotexist<cr>')
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
@@ -198,9 +130,9 @@ describe('external cmdline', function()
{4:E121: Undefined variable: doesnotexist} |
{4:E15: Invalid expression: doesnotexist} |
{5:Press ENTER or type command to continue}^ |
- ]])
+ ]]}
feed(':echoerr doesnotexist<cr>')
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
@@ -211,10 +143,10 @@ describe('external cmdline', function()
{4:E121: Undefined variable: doesnotexist} |
{4:E15: Invalid expression: doesnotexist} |
{5:Press ENTER or type command to continue}^ |
- ]])
+ ]]}
feed(':echoerr doesnotexist<cr>')
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{3: }|
@@ -225,10 +157,10 @@ describe('external cmdline', function()
{4:E121: Undefined variable: doesnotexist} |
{4:E15: Invalid expression: doesnotexist} |
{5:Press ENTER or type command to continue}^ |
- ]])
+ ]]}
feed('<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
@@ -239,372 +171,308 @@ describe('external cmdline', function()
{1:~ }|
{3:n }|
|
- ]])
+ ]]}
end)
end)
it("works with input()", function()
feed(':call input("input", "default")<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "default" } },
- firstc = "",
- indent = 0,
- pos = 7,
- prompt = "input"
- }}, cmdline)
- end)
+ ]], cmdline={{
+ prompt = "input",
+ content = {{"default"}},
+ pos = 7,
+ }}}
+
feed('<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
-
+ ]]}
end)
it("works with special chars and nested cmdline", function()
feed(':xx<c-r>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "xx" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = "",
- special = {'"', true},
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"xx"}},
+ pos = 2,
+ special = {'"', true},
+ }}}
feed('=')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "xx" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = "",
- special = {'"', true},
- },{
- content = { { {}, "" } },
- firstc = "=",
- indent = 0,
- pos = 0,
- prompt = "",
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"xx"}},
+ pos = 2,
+ special = {'"', true},
+ }, {
+ firstc = "=",
+ content = {{""}},
+ pos = 0,
+ }}}
feed('1+2')
local expectation = {{
- content = { { {}, "xx" } },
- firstc = ":",
- indent = 0,
- pos = 2,
- prompt = "",
- special = {'"', true},
- },{
- content = {
- { {}, "1" },
- { {}, "+" },
- { {}, "2" },
- },
- firstc = "=",
- indent = 0,
- pos = 3,
- prompt = "",
- }}
- screen:expect([[
+ firstc = ":",
+ content = {{"xx"}},
+ pos = 2,
+ special = {'"', true},
+ }, {
+ firstc = "=",
+ content = {{"1"}, {"+"}, {"2"}},
+ pos = 3,
+ }}
+
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(expectation, cmdline)
- end)
+ ]], cmdline=expectation}
-- erase information, so we check if it is retransmitted
- cmdline = {}
- command("redraw!")
- -- redraw! forgets cursor position. Be OK with that, as UI should indicate
- -- focus is at external cmdline anyway.
- screen:expect([[
- |
+ command("mode")
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq(expectation, cmdline)
- end)
+ |
+ ]], cmdline=expectation, reset=true}
feed('<cr>')
- screen:expect([[
- |
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq({{
- content = { { {}, "xx3" } },
- firstc = ":",
- indent = 0,
- pos = 3,
- prompt = "",
- }}, cmdline)
- end)
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"xx3"}},
+ pos = 3,
+ }}}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
end)
it("works with function definitions", function()
feed(':function Foo()<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 2,
- pos = 0,
- prompt = "",
- }}, cmdline)
- eq({ { { {}, 'function Foo()'} } }, block)
- end)
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Foo()'}},
+ }}
feed('line1<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({ { { {}, 'function Foo()'} },
- { { {}, ' line1'} } }, block)
- end)
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Foo()'}},
+ {{' line1'}},
+ }}
- block = {}
- command("redraw!")
- screen:expect([[
- |
+ command("mode")
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq({ { { {}, 'function Foo()'} },
- { { {}, ' line1'} } }, block)
- end)
+ |
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Foo()'}},
+ {{' line1'}},
+ }, reset=true}
feed('endfunction<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(nil, block)
- end)
+ ]]}
-- Try once more, to check buffer is reinitialized. #8007
feed(':function Bar()<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "" } },
- firstc = ":",
- indent = 2,
- pos = 0,
- prompt = "",
- }}, cmdline)
- eq({ { { {}, 'function Bar()'} } }, block)
- end)
+ ]], cmdline={{
+ indent = 2,
+ firstc = ":",
+ content = {{""}},
+ pos = 0,
+ }}, cmdline_block = {
+ {{'function Bar()'}},
+ }}
feed('endfunction<cr>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq(nil, block)
- end)
+ ]]}
+
end)
it("works with cmdline window", function()
feed(':make')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "make" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"make"}},
+ pos = 4,
+ }}}
feed('<c-f>')
- screen:expect([[
+ screen:expect{grid=[[
|
{2:[No Name] }|
{1::}make^ |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
-- nested cmdline
feed(':yank')
- screen:expect([[
+ screen:expect{grid=[[
|
{2:[No Name] }|
{1::}make^ |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({nil, {
- content = { { {}, "yank" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={nil, {
+ firstc = ":",
+ content = {{"yank"}},
+ pos = 4,
+ }}}
- cmdline = {}
- command("redraw!")
- screen:expect([[
+ command("mode")
+ screen:expect{grid=[[
|
{2:[No Name] }|
- {1::}make |
+ {1::}make^ |
{3:[Command Line] }|
- ^ |
- ]], nil, nil, function()
- eq({nil, {
- content = { { {}, "yank" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ |
+ ]], cmdline={nil, {
+ firstc = ":",
+ content = {{"yank"}},
+ pos = 4,
+ }}, reset=true}
feed("<c-c>")
- screen:expect([[
+ screen:expect{grid=[[
|
{2:[No Name] }|
{1::}make^ |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({}, cmdline)
- end)
+ ]]}
feed("<c-c>")
- screen:expect([[
- |
+ screen:expect{grid=[[
+ ^ |
{2:[No Name] }|
- {1::}make^ |
+ {1::}make |
{3:[Command Line] }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "make" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"make"}},
+ pos = 4,
+ }}}
- cmdline = {}
command("redraw!")
- screen:expect([[
- |
+ screen:expect{grid=[[
+ ^ |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
- ]], nil, nil, function()
- eq({{
- content = { { {}, "make" } },
- firstc = ":",
- indent = 0,
- pos = 4,
- prompt = ""
- }}, cmdline)
- end)
+ |
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"make"}},
+ pos = 4,
+ }}}
end)
it('works with inputsecret()', function()
feed(":call inputsecret('secret:')<cr>abc123")
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "******" } },
- firstc = "",
- indent = 0,
- pos = 6,
- prompt = "secret:"
- }}, cmdline)
- end)
+ ]], cmdline={{
+ prompt = "secret:",
+ content = {{"******"}},
+ pos = 6,
+ }}}
end)
it('works with highlighted cmdline', function()
@@ -636,23 +504,21 @@ describe('external cmdline', function()
screen:set_default_attr_ids({
RBP1={background = Screen.colors.Red},
RBP2={background = Screen.colors.Yellow},
- RBP3={background = Screen.colors.Green},
- RBP4={background = Screen.colors.Blue},
EOB={bold = true, foreground = Screen.colors.Blue1},
- ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- SK={foreground = Screen.colors.Blue},
- PE={bold = true, foreground = Screen.colors.SeaGreen4}
})
feed('<f5>(a(b)a)')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
|
- ]], nil, nil, function()
- expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}')
- end)
+ ]], cmdline={{
+ prompt = '>',
+ content = {{'(', 'RBP1'}, {'a'}, {'(', 'RBP2'}, {'b'},
+ { ')', 'RBP2'}, {'a'}, {')', 'RBP1'}},
+ pos = 7,
+ }}}
end)
it('works together with ext_wildmenu', function()
@@ -670,98 +536,73 @@ describe('external cmdline', function()
screen:set_option('ext_wildmenu', true)
feed(':sign <tab>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign define"} },
- firstc = ":",
- indent = 0,
- pos = 11,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(0, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign define"}},
+ pos = 11,
+ }}, wildmenu_items=expected, wildmenu_pos=0}
feed('<tab>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign jump"} },
- firstc = ":",
- indent = 0,
- pos = 9,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(1, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign jump"}},
+ pos = 9,
+ }}, wildmenu_items=expected, wildmenu_pos=1}
feed('<left><left>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign "} },
- firstc = ":",
- indent = 0,
- pos = 5,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(-1, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign "}},
+ pos = 5,
+ }}, wildmenu_items=expected, wildmenu_pos=-1}
feed('<right>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign define"} },
- firstc = ":",
- indent = 0,
- pos = 11,
- prompt = ""
- }}, cmdline)
- eq(expected, wild_items)
- eq(0, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign define"}},
+ pos = 11,
+ }}, wildmenu_items=expected, wildmenu_pos=0}
feed('a')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
|
- ]], nil, nil, function()
- eq({{
- content = { { {}, "sign definea"} },
- firstc = ":",
- indent = 0,
- pos = 12,
- prompt = ""
- }}, cmdline)
- eq(nil, wild_items)
- eq(nil, wild_selected)
- end)
+ ]], cmdline={{
+ firstc = ":",
+ content = {{"sign definea"}},
+ pos = 12,
+ }}}
end)
-end)
+end
+
+-- the representation of cmdline and cmdline_block contents changed with ext_linegrid
+-- (which uses indexed highlights) so make sure to test both
+describe('ui/ext_cmdline', function() test_cmdline(true) end)
+describe('ui/ext_cmdline (legacy highlights)', function() test_cmdline(false) end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 812c095add..3e0370db14 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -28,6 +28,8 @@ describe('ui/cursor', function()
name = 'normal',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'n' },
[2] = {
@@ -39,6 +41,8 @@ describe('ui/cursor', function()
name = 'visual',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'v' },
[3] = {
@@ -50,6 +54,8 @@ describe('ui/cursor', function()
name = 'insert',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'i' },
[4] = {
@@ -61,6 +67,8 @@ describe('ui/cursor', function()
name = 'replace',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'r' },
[5] = {
@@ -72,6 +80,8 @@ describe('ui/cursor', function()
name = 'cmdline_normal',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'c' },
[6] = {
@@ -83,6 +93,8 @@ describe('ui/cursor', function()
name = 'cmdline_insert',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'ci' },
[7] = {
@@ -94,6 +106,8 @@ describe('ui/cursor', function()
name = 'cmdline_replace',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'cr' },
[8] = {
@@ -105,6 +119,8 @@ describe('ui/cursor', function()
name = 'operator',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 'o' },
[9] = {
@@ -116,6 +132,8 @@ describe('ui/cursor', function()
name = 'visual_select',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
mouse_shape = 0,
short_name = 've' },
[10] = {
@@ -155,6 +173,8 @@ describe('ui/cursor', function()
name = 'showmatch',
hl_id = 0,
id_lm = 0,
+ attr = {},
+ attr_lm = {},
short_name = 'sm' },
}
@@ -168,17 +188,18 @@ describe('ui/cursor', function()
-- Event is published ONLY if the cursor style changed.
screen._mode_info = nil
command("echo 'test'")
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
test |
- ]], nil, nil, function()
+ ]], condition=function()
eq(nil, screen._mode_info)
- end)
+ end}
-- Change the cursor style.
+ helpers.command('hi Cursor guibg=DarkGray')
helpers.command('set guicursor=n-v-c:block,i-ci-ve:ver25,r-cr-o:hor20'
..',a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor'
..',sm:block-blinkwait175-blinkoff150-blinkon175')
@@ -194,7 +215,10 @@ describe('ui/cursor', function()
if m.blinkoff then m.blinkoff = 400 end
if m.blinkwait then m.blinkwait = 700 end
end
- if m.hl_id then m.hl_id = 49 end
+ if m.hl_id then
+ m.hl_id = 49
+ m.attr = {background = Screen.colors.DarkGray}
+ end
if m.id_lm then m.id_lm = 50 end
end
@@ -205,6 +229,26 @@ describe('ui/cursor', function()
eq('normal', screen.mode)
end)
+ -- Change hl groups only, should update the styles
+ helpers.command('hi Cursor guibg=Red')
+ helpers.command('hi lCursor guibg=Green')
+
+ -- Update the expected values.
+ for _, m in ipairs(expected_mode_info) do
+ if m.hl_id then
+ m.attr = {background = Screen.colors.Red}
+ end
+ if m.id_lm then
+ m.attr_lm = {background = Screen.colors.Green}
+ end
+ end
+ -- Assert the new expectation.
+ screen:expect(function()
+ eq(expected_mode_info, screen._mode_info)
+ eq(true, screen._cursor_style_enabled)
+ eq('normal', screen.mode)
+ end)
+
-- Another cursor style.
meths.set_option('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173'
..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42')
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
new file mode 100644
index 0000000000..4fc93c3b63
--- /dev/null
+++ b/test/functional/ui/embed_spec.lua
@@ -0,0 +1,81 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local feed = helpers.feed
+local eq = helpers.eq
+local clear = helpers.clear
+
+local function test_embed(ext_linegrid)
+ local screen
+ local function startup(...)
+ clear{headless=false, args={...}}
+
+ -- attach immediately after startup, for early UI
+ screen = Screen.new(60, 8)
+ screen:attach{ext_linegrid=ext_linegrid}
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [3] = {bold = true, foreground = Screen.colors.Blue1},
+ })
+ end
+
+ it('can display errors', function()
+ startup('--cmd', 'echoerr invalid+')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ Error detected while processing pre-vimrc command line: |
+ E121: Undefined variable: invalid |
+ E15: Invalid expression: invalid+ |
+ Press ENTER or type command to continue^ |
+ ]])
+
+ feed('<cr>')
+ screen:expect([[
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+
+ it("doesn't erase output when setting color scheme", function()
+ startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ Error detected while processing pre-vimrc command line: |
+ foo |
+ {1:bar} |
+ {2:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ it("doesn't erase output when setting Normal colors", function()
+ startup('--cmd', 'echoerr "foo"', '--cmd', 'hi Normal guibg=Green', '--cmd', 'echoerr "bar"')
+ screen:expect{grid=[[
+ |
+ |
+ |
+ |
+ Error detected while processing pre-vimrc command line: |
+ foo |
+ bar |
+ Press ENTER or type command to continue^ |
+ ]], condition=function()
+ eq(Screen.colors.Green, screen.default_colors.rgb_bg)
+ end}
+ end)
+end
+
+describe('--embed UI on startup (ext_linegrid=true)', function() test_embed(true) end)
+describe('--embed UI on startup (ext_linegrid=false)', function() test_embed(false) end)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 9c5a59b58d..39a5c10bb7 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -65,7 +65,7 @@ describe("folded lines", function()
{1:~ }|
{1:~ }|
{1:~ }|
- |
+ :set noarabicshape |
]])
feed_command("set number foldcolumn=2")
@@ -114,7 +114,7 @@ describe("folded lines", function()
{1: ~}|
{1: ~}|
{1: ~}|
- |
+ :set arabicshape |
]])
feed('zo')
@@ -126,7 +126,7 @@ describe("folded lines", function()
{1: ~}|
{1: ~}|
{1: ~}|
- |
+ :set arabicshape |
]])
feed_command('set noarabicshape')
@@ -138,7 +138,7 @@ describe("folded lines", function()
{1: ~}|
{1: ~}|
{1: ~}|
- |
+ :set noarabicshape |
]])
end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index b46a6c1e46..55fc343e4c 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -40,24 +40,24 @@ describe('highlight: `:syntax manual`', function()
end)
it("works with buffer switch and 'hidden'", function()
- feed_command('e tmp1.vim')
- feed_command('e Xtest-functional-ui-highlight.tmp.vim')
- feed_command('filetype on')
- feed_command('syntax manual')
- feed_command('set ft=vim')
- feed_command('set syntax=ON')
+ command('e tmp1.vim')
+ command('e Xtest-functional-ui-highlight.tmp.vim')
+ command('filetype on')
+ command('syntax manual')
+ command('set ft=vim')
+ command('set syntax=ON')
feed('iecho 1<esc>0')
- feed_command('set hidden')
- feed_command('w')
- feed_command('bn')
+ command('set hidden')
+ command('w')
+ command('bn')
feed_command('bp')
screen:expect([[
{1:^echo} 1 |
{0:~ }|
{0:~ }|
{0:~ }|
- <f 1 --100%-- col 1 |
+ :bp |
]])
end)
@@ -122,7 +122,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
-- navigate to verify that the attributes are properly moved
feed('<c-w>j')
@@ -140,7 +140,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{1:[No Name] }|
- |
+ :vsp |
]])
-- note that when moving to a window with small width nvim will increase
-- the width of the new active window at the expense of a inactive window
@@ -160,7 +160,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
feed('<c-w>l')
screen:expect([[
@@ -177,7 +177,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
feed('<c-w>h<c-w>h')
screen:expect([[
@@ -194,7 +194,7 @@ describe('highlight defaults', function()
{0:~ }|
{0:~ }|
{2:[No Name] }|
- |
+ :vsp |
]])
end)
@@ -677,6 +677,7 @@ end)
describe('CursorLine highlight', function()
before_each(clear)
+
it('overridden by Error, ColorColumn if fg not set', function()
local screen = Screen.new(50,5)
screen:set_default_attr_ids({
@@ -690,9 +691,9 @@ describe('CursorLine highlight', function()
})
screen:attach()
- feed_command('filetype on')
- feed_command('syntax on')
- feed_command('set cursorline ft=json')
+ command('filetype on')
+ command('syntax on')
+ command('set cursorline ft=json')
feed('i{<cr>"a" : abc // 10;<cr>}<cr><esc>')
screen:expect([[
{1:{} |
@@ -702,7 +703,7 @@ describe('CursorLine highlight', function()
|
]])
- feed_command('set colorcolumn=3')
+ command('set colorcolumn=3')
feed('i <esc>')
screen:expect([[
{1:{} {7: } |
@@ -712,6 +713,62 @@ describe('CursorLine highlight', function()
|
]])
end)
+
+ it('with split-windows in diff-mode', function()
+ local screen = Screen.new(50,12)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [2] = {bold = true, background = Screen.colors.Red},
+ [3] = {background = Screen.colors.LightMagenta},
+ [4] = {reverse = true},
+ [5] = {background = Screen.colors.LightBlue},
+ [6] = {background = Screen.colors.LightCyan1, bold = true, foreground = Screen.colors.Blue1},
+ [7] = {background = Screen.colors.Red, foreground = Screen.colors.White},
+ [8] = {bold = true, foreground = Screen.colors.Blue1},
+ [9] = {bold = true, reverse = true},
+ [10] = {bold = true},
+ })
+ screen:attach()
+
+ command('hi CursorLine ctermbg=red ctermfg=white guibg=red guifg=white')
+ command('set cursorline')
+ feed('iline 1 some text<cr>line 2 more text<cr>extra line!<cr>extra line!<cr>last line ...<cr>')
+ feed('<esc>gg')
+ command('vsplit')
+ command('enew')
+ feed('iline 1 some text<cr>line 2 moRe text!<cr>extra line!<cr>extra line!<cr>extra line!<cr>last line ...<cr>')
+ feed('<esc>gg')
+ command('windo diffthis')
+ screen:expect([[
+ {1: }{7:line 1 some text }{4:│}{1: }{7:^line 1 some text }|
+ {1: }{3:line 2 mo}{2:Re text!}{3: }{4:│}{1: }{3:line 2 mo}{2:re text}{3: }|
+ {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }last line ... {4:│}{1: }last line ... |
+ {1: } {4:│}{1: } |
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {4:[No Name] [+] }{9:[No Name] [+] }|
+ |
+ ]])
+ feed('jjjjj')
+ screen:expect([[
+ {1: }line 1 some text {4:│}{1: }line 1 some text |
+ {1: }{3:line 2 mo}{2:Re text!}{3: }{4:│}{1: }{3:line 2 mo}{2:re text}{3: }|
+ {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }extra line! {4:│}{1: }extra line! |
+ {1: }last line ... {4:│}{1: }last line ... |
+ {1: }{7: }{4:│}{1: }{7:^ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {1: }{8:~ }{4:│}{1: }{8:~ }|
+ {4:[No Name] [+] }{9:[No Name] [+] }|
+ |
+ ]])
+ end)
end)
@@ -834,7 +891,7 @@ describe("'winhighlight' highlight", function()
{1:a^a }|
{2:~ }|
{2:~ }|
- {11:[No Name] [+] }|
+ {3:[No Name] [+] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
@@ -846,7 +903,7 @@ describe("'winhighlight' highlight", function()
{1:^ }|
{2:~ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
@@ -870,7 +927,7 @@ describe("'winhighlight' highlight", function()
eq('Vim(set):E474: Invalid argument: winhl=xxx:yyy',
exc_exec("set winhl=xxx:yyy"))
eq('Normal:Background1', eval('&winhl'))
- screen:expect([[
+ screen:expect{grid=[[
{1:^ }|
{2:~ }|
{2:~ }|
@@ -879,7 +936,7 @@ describe("'winhighlight' highlight", function()
{2:~ }|
{2:~ }|
|
- ]])
+ ]], unchanged=true}
end)
@@ -891,7 +948,7 @@ describe("'winhighlight' highlight", function()
{1:a^a }|
{2:~ }|
{2:~ }|
- {11:[No Name] [+] }|
+ {3:[No Name] [+] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
@@ -915,11 +972,11 @@ describe("'winhighlight' highlight", function()
{1:^aa }|
{2:~ }|
{2:~ }|
- {11:[No Name] [+] }|
+ {3:[No Name] [+] }|
aa |
{0:~ }|
{4:[No Name] [+] }|
- <f 1 --100%-- col 1 |
+ |
]])
end)
@@ -931,10 +988,10 @@ describe("'winhighlight' highlight", function()
{1:^ }|
{2:~ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
{5: }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
|
]])
@@ -943,10 +1000,10 @@ describe("'winhighlight' highlight", function()
{5: }|
{6:~ }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
{1:^ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
|
]])
@@ -955,10 +1012,10 @@ describe("'winhighlight' highlight", function()
{1:^ }|
{2:~ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
{5: }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
|
]])
end)
@@ -974,7 +1031,7 @@ describe("'winhighlight' highlight", function()
{3:[No Name] }|
{7: }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
|
]])
@@ -983,7 +1040,7 @@ describe("'winhighlight' highlight", function()
{7: }|
{8:~ }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
^ |
{0:~ }|
{3:[No Name] }|
@@ -997,10 +1054,10 @@ describe("'winhighlight' highlight", function()
{7: }|
{8:~ }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
{1:^ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
|
]])
@@ -1012,7 +1069,7 @@ describe("'winhighlight' highlight", function()
{3:[No Name] }|
{1: }|
{2:~ }|
- {14:[No Name] }|
+ {4:[No Name] }|
|
]])
@@ -1022,10 +1079,10 @@ describe("'winhighlight' highlight", function()
{7: }|
{8:~ }|
{8:~ }|
- {13:[No Name] }|
+ {4:[No Name] }|
{1:^ }|
{2:~ }|
- {11:[No Name] }|
+ {3:[No Name] }|
|
]])
@@ -1037,7 +1094,7 @@ describe("'winhighlight' highlight", function()
{3:[No Name] }|
{5: }|
{6:~ }|
- {12:[No Name] }|
+ {4:[No Name] }|
|
]])
end)
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
new file mode 100644
index 0000000000..672af5fb22
--- /dev/null
+++ b/test/functional/ui/hlstate_spec.lua
@@ -0,0 +1,287 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear, insert = helpers.clear, helpers.insert
+local command = helpers.command
+local meths = helpers.meths
+local iswin = helpers.iswin
+local nvim_dir = helpers.nvim_dir
+local thelpers = require('test.functional.terminal.helpers')
+
+describe('ext_hlstate detailed highlights', function()
+ local screen
+
+ before_each(function()
+ clear()
+ command('syntax on')
+ screen = Screen.new(40, 8)
+ screen:attach({ext_hlstate=true})
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+
+ it('work with combined UI and syntax highlights', function()
+ insert([[
+ these are some lines
+ with colorful text]])
+ meths.buf_add_highlight(0, -1, "String", 0 , 10, 14)
+ meths.buf_add_highlight(0, -1, "Statement", 1 , 5, -1)
+ command("/th co")
+
+ screen:expect([[
+ these are {1:some} lines |
+ ^wi{2:th }{4:co}{3:lorful text} |
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {6:search hit BOTTOM, continuing at TOP} |
+ ]], {
+ [1] = {{foreground = Screen.colors.Magenta},
+ {{hi_name = "Constant", kind = "syntax"}}},
+ [2] = {{background = Screen.colors.Yellow},
+ {{hi_name = "Search", ui_name = "Search", kind = "ui"}}},
+ [3] = {{bold = true, foreground = Screen.colors.Brown},
+ {{hi_name = "Statement", kind = "syntax"}}},
+ [4] = {{bold = true, background = Screen.colors.Yellow, foreground = Screen.colors.Brown}, {3, 2}},
+ [5] = {{bold = true, foreground = Screen.colors.Blue1},
+ {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [6] = {{foreground = Screen.colors.Red},
+ {{hi_name = "WarningMsg", ui_name = "WarningMsg", kind = "ui"}}},
+ })
+ end)
+
+ it('work with cleared UI highlights', function()
+ screen:set_default_attr_ids({
+ [1] = {{}, {{hi_name = "VertSplit", ui_name = "VertSplit", kind = "ui"}}},
+ [2] = {{bold = true, foreground = Screen.colors.Blue1},
+ {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [3] = {{bold = true, reverse = true},
+ {{hi_name = "StatusLine", ui_name = "StatusLine", kind = "ui"}}} ,
+ [4] = {{reverse = true},
+ {{hi_name = "StatusLineNC", ui_name = "StatusLineNC" , kind = "ui"}}},
+ [5] = {{}, {{hi_name = "StatusLine", ui_name = "StatusLine", kind = "ui"}}},
+ [6] = {{}, {{hi_name = "StatusLineNC", ui_name = "StatusLineNC", kind = "ui"}}},
+ })
+ command("hi clear VertSplit")
+ command("vsplit")
+
+ screen:expect([[
+ ^ {1:│} |
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] }{4:[No Name] }|
+ |
+ ]])
+
+ command("hi clear StatusLine | hi clear StatuslineNC")
+ screen:expect([[
+ ^ {1:│} |
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {5:[No Name] }{6:[No Name] }|
+ |
+ ]])
+
+ -- redrawing is done even if visible highlights didn't change
+ command("wincmd w")
+ screen:expect([[
+ {1:│}^ |
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {6:[No Name] }{5:[No Name] }|
+ |
+ ]])
+
+ end)
+
+ it("work with window-local highlights", function()
+ screen:set_default_attr_ids({
+ [1] = {{foreground = Screen.colors.Brown}, {{hi_name = "LineNr", ui_name = "LineNr", kind = "ui"}}},
+ [2] = {{bold = true, foreground = Screen.colors.Blue1}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [3] = {{bold = true, reverse = true}, {{hi_name = "StatusLine", ui_name = "StatusLine", kind = "ui"}}},
+ [4] = {{reverse = true}, {{hi_name = "StatusLineNC", ui_name = "StatusLineNC", kind = "ui"}}},
+ [5] = {{background = Screen.colors.Red, foreground = Screen.colors.Grey100}, {{hi_name = "ErrorMsg", ui_name = "LineNr", kind = "ui"}}},
+ [6] = {{bold = true, reverse = true}, {{hi_name = "MsgSeparator", ui_name = "Normal", kind = "ui"}}},
+ [7] = {{foreground = Screen.colors.Brown, bold = true, reverse = true}, {6, 1}},
+ [8] = {{foreground = Screen.colors.Blue1, bold = true, reverse = true}, {6, 2}},
+ [9] = {{bold = true, foreground = Screen.colors.Brown}, {{hi_name = "Statement", ui_name = "NormalNC", kind = "ui"}}},
+ [10] = {{bold = true, foreground = Screen.colors.Brown}, {9, 1}},
+ [11] = {{bold = true, foreground = Screen.colors.Blue1}, {9, 2}}
+ })
+
+ command("set number")
+ command("split")
+ -- NormalNC is not applied if not set, to avoid spurious redraws
+ screen:expect([[
+ {1: 1 }^ |
+ {2:~ }|
+ {2:~ }|
+ {3:[No Name] }|
+ {1: 1 } |
+ {2:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+
+ command("set winhl=LineNr:ErrorMsg")
+ screen:expect([[
+ {5: 1 }^ |
+ {2:~ }|
+ {2:~ }|
+ {3:[No Name] }|
+ {1: 1 } |
+ {2:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+
+ command("set winhl=Normal:MsgSeparator,NormalNC:Statement")
+ screen:expect([[
+ {7: 1 }{6:^ }|
+ {8:~ }|
+ {8:~ }|
+ {3:[No Name] }|
+ {1: 1 } |
+ {2:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+
+ command("wincmd w")
+ screen:expect([[
+ {10: 1 }{9: }|
+ {11:~ }|
+ {11:~ }|
+ {4:[No Name] }|
+ {1: 1 }^ |
+ {2:~ }|
+ {3:[No Name] }|
+ |
+ ]])
+ end)
+
+ it("work with :terminal", function()
+ screen:set_default_attr_ids({
+ [1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}},
+ [2] = {{special = Screen.colors.Grey0, foreground = 52479}, {{kind = "term"}}},
+ [3] = {{special = Screen.colors.Grey0, bold = true, foreground = 52479}, {{kind = "term"}}},
+ [4] = {{special = Screen.colors.Grey0, foreground = 52479}, {2, 1}},
+ [5] = {{special = Screen.colors.Grey0, foreground = 4259839}, {{kind = "term"}}},
+ [6] = {{special = Screen.colors.Grey0, foreground = 4259839}, {5, 1}},
+ })
+ command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
+ screen:expect([[
+ ^tty ready |
+ {1: } |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]])
+
+ thelpers.feed_data('x ')
+ thelpers.set_fg(45)
+ thelpers.feed_data('y ')
+ thelpers.set_bold()
+ thelpers.feed_data('z\n')
+ -- TODO(bfredl): check if this distinction makes sense
+ if iswin() then
+ screen:expect([[
+ ^tty ready |
+ x {5:y z} |
+ {1: } |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ else
+ screen:expect([[
+ ^tty ready |
+ x {2:y }{3:z} |
+ {1: } |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ end
+
+ thelpers.feed_termcode("[A")
+ thelpers.feed_termcode("[2C")
+ if iswin() then
+ screen:expect([[
+ ^tty ready |
+ x {6:y}{5: z} |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ else
+ screen:expect([[
+ ^tty ready |
+ x {4:y}{2: }{3:z} |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]])
+ end
+ end)
+
+ it("can use independent cterm and rgb colors", function()
+ -- tell test module to save all attributes (doesn't change nvim options)
+ screen:set_hlstate_cterm(true)
+
+ screen:set_default_attr_ids({
+ [1] = {{bold = true, foreground = Screen.colors.Blue1}, {foreground = 12}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ [2] = {{reverse = true, foreground = Screen.colors.Red}, {foreground = 10, italic=true}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+
+ command("hi NonText guifg=Red gui=reverse ctermfg=Green cterm=italic")
+ screen:expect([[
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+
+ end)
+end)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 9cc697a4b6..bb6cb543ed 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -495,6 +495,18 @@ describe(":substitute, 'inccommand' preserves undo", function()
for _, case in pairs(cases) do
clear()
common_setup(screen, case, default_text)
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ ^ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ |
+ ]])
feed_command("set undolevels=1")
feed("1G0")
@@ -745,20 +757,35 @@ describe(":substitute, inccommand=split", function()
it("shows preview when cmd modifiers are present", function()
-- one modifier
feed(':keeppatterns %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- multiple modifiers
feed(':keeppatterns silent %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- non-modifier prefix
feed(':silent tabedit %s/tw/to')
- screen:expect([[two lines]], nil, nil, nil, true)
- feed('<Esc>')
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :silent tabedit %s/tw/to^ |
+ ]])
end)
it('shows split window when typing the pattern', function()
@@ -866,7 +893,6 @@ describe(":substitute, inccommand=split", function()
it('does not show split window for :s/', function()
feed("2gg")
feed(":s/tw")
- screen:sleep(1)
screen:expect([[
Inc substitution on |
{12:tw}o lines |
@@ -1222,20 +1248,30 @@ describe("inccommand=nosplit", function()
it("shows preview when cmd modifiers are present", function()
-- one modifier
feed(':keeppatterns %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- multiple modifiers
feed(':keeppatterns silent %s/tw/to')
- screen:expect([[{12:to}o lines]], nil, nil, nil, true)
+ screen:expect{any=[[{12:to}o lines]]}
feed('<Esc>')
- screen:expect([[two lines]], nil, nil, nil, true)
+ screen:expect{any=[[two lines]]}
-- non-modifier prefix
feed(':silent tabedit %s/tw/to')
- screen:expect([[two lines]], nil, nil, nil, true)
- feed('<Esc>')
+ screen:expect([[
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :silent tabedit %s/t|
+ w/to^ |
+ ]])
end)
it("does not show window after toggling :set inccommand", function()
@@ -1503,7 +1539,7 @@ describe("'inccommand' and :cnoremap", function()
end
end)
- it('does not work with a failing mapping', function()
+ it('still works with a broken mapping', function()
for _, case in pairs(cases) do
refresh(case)
feed_command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
@@ -1512,7 +1548,10 @@ describe("'inccommand' and :cnoremap", function()
-- error thrown b/c of the mapping
neq(nil, eval('v:errmsg'):find('^E523:'))
- expect(default_text)
+ expect([[
+ Inc substitution on
+ toxo lines
+ ]])
end
end)
@@ -2473,7 +2512,7 @@ describe(":substitute", function()
end)
it(':substitute with inccommand during :terminal activity', function()
- retry(2, nil, function()
+ retry(2, 40000, function()
local screen = Screen.new(30,15)
clear()
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index f0cedfeeb5..f6b3c1c3c9 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -21,207 +21,169 @@ describe('ui mode_change event', function()
end)
it('works in normal mode', function()
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
feed('d')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("operator", screen.mode)
- end)
+ ]], mode="operator"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
it('works in insert mode', function()
feed('i')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]],nil,nil,function ()
- eq("insert", screen.mode)
- end)
+ ]], mode="insert"}
feed('word<esc>')
- screen:expect([[
+ screen:expect{grid=[[
wor^d |
{0:~ }|
{0:~ }|
|
- ]], nil, nil, function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
command("set showmatch")
eq(eval('&matchtime'), 5) -- tenths of seconds
feed('a(stuff')
- screen:expect([[
+ screen:expect{grid=[[
word(stuff^ |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]], nil, nil, function ()
- eq("insert", screen.mode)
- end)
+ ]], mode="insert"}
feed(')')
- screen:expect([[
+ screen:expect{grid=[[
word^(stuff) |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]], nil, nil, function ()
- eq("showmatch", screen.mode)
- end)
+ ]], mode="showmatch"}
screen:sleep(400)
- screen:expect([[
+ screen:expect{grid=[[
word(stuff)^ |
{0:~ }|
{0:~ }|
{2:-- INSERT --} |
- ]], nil, nil, function ()
- eq("insert", screen.mode)
- end)
+ ]], mode="insert"}
end)
it('works in replace mode', function()
feed('R')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
{2:-- REPLACE --} |
- ]], nil, nil, function ()
- eq("replace", screen.mode)
- end)
+ ]], mode="replace"}
feed('word<esc>')
- screen:expect([[
+ screen:expect{grid=[[
wor^d |
{0:~ }|
{0:~ }|
|
- ]], nil, nil, function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
it('works in cmdline mode', function()
feed(':')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:^ |
- ]],nil,nil,function ()
- eq("cmdline_normal", screen.mode)
- end)
+ ]], mode="cmdline_normal"}
feed('x<left>')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:^x |
- ]],nil,nil,function ()
- eq("cmdline_insert", screen.mode)
- end)
+ ]], mode="cmdline_insert"}
feed('<insert>')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:^x |
- ]],nil,nil,function ()
- eq("cmdline_replace", screen.mode)
- end)
+ ]], mode="cmdline_replace"}
feed('<right>')
- screen:expect([[
+ screen:expect{grid=[[
|
{0:~ }|
{0:~ }|
:x^ |
- ]],nil,nil,function ()
- eq("cmdline_normal", screen.mode)
- end)
+ ]], mode="cmdline_normal"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
^ |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
- it('works in visal mode', function()
+ it('works in visual mode', function()
insert("text")
feed('v')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
{2:-- VISUAL --} |
- ]],nil,nil,function ()
- eq("visual", screen.mode)
- end)
+ ]], mode="visual"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
command('set selection=exclusive')
feed('v')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
{2:-- VISUAL --} |
- ]],nil,nil,function ()
- eq("visual_select", screen.mode)
- end)
+ ]], mode="visual_select"}
feed('<esc>')
- screen:expect([[
+ screen:expect{grid=[[
tex^t |
{0:~ }|
{0:~ }|
|
- ]],nil,nil,function ()
- eq("normal", screen.mode)
- end)
+ ]], mode="normal"}
end)
end)
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index debd324977..c531f838c1 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -168,13 +168,13 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftMouse><11,0>')
- screen:expect([[
+ screen:expect{grid=[[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><6,0>')
screen:expect([[
{sel: + bar }{tab: + foo }{fill: }{tab:X}|
@@ -236,13 +236,13 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftDrag><4,1>')
- screen:expect([[
+ screen:expect{grid=[[
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
this is fo^o |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><14,1>')
screen:expect([[
{tab: + bar }{sel: + foo }{fill: }{tab:X}|
@@ -254,13 +254,6 @@ describe('ui/mouse/input', function()
end)
it('out of tabline to the left moves tab left', function()
- if helpers.skip_fragile(pending,
- os.getenv("TRAVIS") and (helpers.os_name() == "osx"
- or os.getenv("CLANG_SANITIZER") == "ASAN_UBSAN")) -- #4874
- then
- return
- end
-
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
@@ -273,21 +266,21 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftMouse><11,0>')
- screen:expect([[
+ screen:expect{grid=[[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><11,1>')
- screen:expect([[
+ screen:expect{grid=[[
{tab: + foo }{sel: + bar }{fill: }{tab:X}|
this is ba^r |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><6,1>')
screen:expect([[
{sel: + bar }{tab: + foo }{fill: }{tab:X}|
@@ -319,13 +312,13 @@ describe('ui/mouse/input', function()
|
]])
feed('<LeftDrag><4,1>')
- screen:expect([[
+ screen:expect{grid=[[
{sel: + foo }{tab: + bar }{fill: }{tab:X}|
this is fo^o |
{0:~ }|
{0:~ }|
|
- ]])
+ ]], unchanged=true}
feed('<LeftDrag><7,1>')
screen:expect([[
{tab: + bar }{sel: + foo }{fill: }{tab:X}|
@@ -537,7 +530,7 @@ describe('ui/mouse/input', function()
mouse |
support and selectio^n |
{0:~ }|
- |
+ :tabprevious |
]])
feed('<LeftMouse><10,0><LeftRelease>') -- go to second tab
helpers.wait()
@@ -547,7 +540,7 @@ describe('ui/mouse/input', function()
^this is bar |
{0:~ }|
{0:~ }|
- |
+ :tabprevious |
]])
feed('<LeftDrag><4,1>')
screen:expect([[
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 62b08c0967..32e8faf7d3 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -1,79 +1,85 @@
+local global_helpers = require('test.helpers')
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local shallowcopy = global_helpers.shallowcopy
describe('ui receives option updates', function()
local screen
- before_each(function()
- clear()
+ local function reset(opts, ...)
+ local defaults = {
+ ambiwidth='single',
+ arabicshape=true,
+ emoji=true,
+ guifont='',
+ guifontset='',
+ guifontwide='',
+ linespace=0,
+ showtabline=1,
+ termguicolors=false,
+ ext_cmdline=false,
+ ext_popupmenu=false,
+ ext_tabline=false,
+ ext_wildmenu=false,
+ ext_linegrid=false,
+ ext_hlstate=false,
+ }
+
+ clear(...)
screen = Screen.new(20,5)
- end)
+ screen:attach(opts)
+ -- NB: UI test suite can be run in both "linegrid" and legacy grid mode.
+ -- In both cases check that the received value is the one requested.
+ defaults.ext_linegrid = screen._options.ext_linegrid or false
+ return defaults
+ end
after_each(function()
screen:detach()
end)
- local defaults = {
- ambiwidth='single',
- arabicshape=true,
- emoji=true,
- guifont='',
- guifontset='',
- guifontwide='',
- linespace=0,
- showtabline=1,
- termguicolors=false,
- ext_cmdline=false,
- ext_popupmenu=false,
- ext_tabline=false,
- ext_wildmenu=false,
- }
-
it("for defaults", function()
- screen:attach()
+ local expected = reset()
screen:expect(function()
- eq(defaults, screen.options)
+ eq(expected, screen.options)
end)
end)
it("when setting options", function()
- screen:attach()
- local changed = {}
- for k,v in pairs(defaults) do
- changed[k] = v
- end
+ local expected = reset()
+ local defaults = shallowcopy(expected)
command("set termguicolors")
- changed.termguicolors = true
+ expected.termguicolors = true
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set guifont=Comic\\ Sans")
- changed.guifont = "Comic Sans"
+ expected.guifont = "Comic Sans"
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set showtabline=0")
- changed.showtabline = 0
+ expected.showtabline = 0
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set linespace=13")
- changed.linespace = 13
+ expected.linespace = 13
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set linespace=-11")
- changed.linespace = -11
+ expected.linespace = -11
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
command("set all&")
@@ -83,28 +89,35 @@ describe('ui receives option updates', function()
end)
it('with UI extensions', function()
- local changed = {}
- for k,v in pairs(defaults) do
- changed[k] = v
- end
-
- screen:attach({ext_cmdline=true, ext_wildmenu=true})
- changed.ext_cmdline = true
- changed.ext_wildmenu = true
+ local expected = reset({ext_cmdline=true, ext_wildmenu=true})
+
+ expected.ext_cmdline = true
+ expected.ext_wildmenu = true
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
screen:set_option('ext_popupmenu', true)
- changed.ext_popupmenu = true
+ expected.ext_popupmenu = true
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
screen:set_option('ext_wildmenu', false)
- changed.ext_wildmenu = false
+ expected.ext_wildmenu = false
screen:expect(function()
- eq(changed, screen.options)
+ eq(expected, screen.options)
end)
end)
+
+ local function startup_test(headless)
+ local expected = reset(nil,{headless=headless,args={'--cmd', 'set guifont=Comic\\ Sans\\ 12'}})
+ expected.guifont = "Comic Sans 12"
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+ end
+
+ it('from startup options with --headless', function() startup_test(true) end)
+ it('from startup options with --embed', function() startup_test(false) end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 93d8965cb1..1850d436ac 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -51,25 +51,20 @@ describe("shell command :!", function()
end)
it("throttles shell-command output greater than ~10KB", function()
- if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
- pending("[Unreliable on Travis macOS.]", function() end)
- return
- end
-
- screen.timeout = 20000 -- Avoid false failure on slow systems.
child_session.feed_data(
- ":!for i in $(seq 2 3000); do echo XXXXXXXXXX $i; done\n")
+ ":!for i in $(seq 2 30000); do echo XXXXXXXXXX $i; done\n")
-- If we observe any line starting with a dot, then throttling occurred.
- screen:expect("\n.", nil, nil, nil, true)
+ -- Avoid false failure on slow systems.
+ screen:expect{any="\n%.", timeout=20000}
-- Final chunk of output should always be displayed, never skipped.
-- (Throttling is non-deterministic, this test is merely a sanity check.)
screen:expect([[
- XXXXXXXXXX 2997 |
- XXXXXXXXXX 2998 |
- XXXXXXXXXX 2999 |
- XXXXXXXXXX 3000 |
+ XXXXXXXXXX 29997 |
+ XXXXXXXXXX 29998 |
+ XXXXXXXXXX 29999 |
+ XXXXXXXXXX 30000 |
|
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
@@ -92,7 +87,7 @@ describe("shell command :!", function()
eq(2, eval('1+1')) -- Still alive?
end)
- it([[handles control codes]], function()
+ it('handles control codes', function()
if iswin() then
pending('missing printf', function() end)
return
@@ -112,14 +107,14 @@ describe("shell command :!", function()
-- Print BELL control code. #4338
screen.bell = false
feed([[:!printf '\007\007\007\007text'<CR>]])
- screen:expect([[
+ screen:expect{grid=[[
~ |
:!printf '\007\007\007\007text' |
text |
Press ENTER or type command to continue^ |
- ]], nil, nil, function()
+ ]], condition=function()
eq(true, screen.bell)
- end)
+ end}
feed([[<CR>]])
-- Print BS control code.
feed([[:echo system('printf ''\010\n''')<CR>]])
@@ -188,7 +183,7 @@ describe("shell command :!", function()
it('handles binary and multibyte data', function()
feed_command('!cat test/functional/fixtures/shell_data.txt')
screen.bell = false
- screen:expect([[
+ screen:expect{grid=[[
|
{1:~ }|
{4: }|
@@ -199,9 +194,9 @@ describe("shell command :!", function()
t {2:<ff>} |
|
{3:Press ENTER or type command to continue}^ |
- ]], nil, nil, function()
+ ]], condition=function()
eq(true, screen.bell)
- end)
+ end}
end)
it('handles multibyte sequences split over buffer boundaries', function()
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
new file mode 100644
index 0000000000..606c7c1e26
--- /dev/null
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -0,0 +1,260 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, feed = helpers.clear, helpers.feed
+local source = helpers.source
+
+describe('ui/ext_popupmenu', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 8)
+ screen:attach({rgb=true, ext_popupmenu=true})
+ screen:set_default_attr_ids({
+ [1] = {bold=true, foreground=Screen.colors.Blue},
+ [2] = {bold = true},
+ [3] = {reverse = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen}
+ })
+ end)
+
+ it('works', function()
+ source([[
+ function! TestComplete() abort
+ call complete(1, ['foo', 'bar', 'spam'])
+ return ''
+ endfunction
+ ]])
+ local expected = {
+ {'foo', '', '', ''},
+ {'bar', '', '', ''},
+ {'spam', '', '', ''},
+ }
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect{grid=[[
+ |
+ foo^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=0,
+ anchor={1,0},
+ }}
+
+ feed('<c-p>')
+ screen:expect{grid=[[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=-1,
+ anchor={1,0},
+ }}
+
+ -- down moves the selection in the menu, but does not insert anything
+ feed('<down><down>')
+ screen:expect{grid=[[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=1,
+ anchor={1,0},
+ }}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ |
+ bar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]]}
+ end)
+end)
+
+describe('popup placement', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(32, 20)
+ screen:attach()
+ screen:set_default_attr_ids({
+ -- popup selected item / scrollbar track
+ ['s'] = {background = Screen.colors.WebGray},
+ -- popup non-selected item
+ ['n'] = {background = Screen.colors.LightMagenta},
+ -- popup scrollbar knob
+ ['c'] = {background = Screen.colors.Grey0},
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true},
+ [3] = {reverse = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen}
+ })
+ end)
+
+ it('works with preview-window above', function()
+ feed(':ped<CR><c-w>4+')
+ feed('iaa bb cc dd ee ff gg hh ii jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa bb cc dd ee ff gg hh ii jj |
+ aa |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] [Preview][+] }|
+ aa bb cc dd ee ff gg hh ii jj |
+ aa^ |
+ {s:aa }{c: }{1: }|
+ {n:bb }{c: }{1: }|
+ {n:cc }{c: }{1: }|
+ {n:dd }{c: }{1: }|
+ {n:ee }{c: }{1: }|
+ {n:ff }{c: }{1: }|
+ {n:gg }{s: }{1: }|
+ {n:hh }{s: }{4: }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+
+ it('works with preview-window below', function()
+ feed(':ped<CR><c-w>4+<c-w>r')
+ feed('iaa bb cc dd ee ff gg hh ii jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa bb cc dd ee ff gg hh ii jj |
+ aa^ |
+ {s:aa }{c: }{1: }|
+ {n:bb }{c: }{1: }|
+ {n:cc }{c: }{1: }|
+ {n:dd }{c: }{1: }|
+ {n:ee }{c: }{1: }|
+ {n:ff }{c: }{1: }|
+ {n:gg }{s: }{1: }|
+ {n:hh }{s: }{4: }|
+ aa bb cc dd ee ff gg hh ii jj |
+ aa |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] [Preview][+] }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+
+ it('works with preview-window above and tall and inverted', function()
+ feed(':ped<CR><c-w>8+')
+ feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>')
+ feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>')
+ feed('kk<cr>ll<cr>mm<cr>nn<cr>oo<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa |
+ bb |
+ cc |
+ dd |
+ {s:aa }{c: }{3:ew][+] }|
+ {n:bb }{c: } |
+ {n:cc }{c: } |
+ {n:dd }{c: } |
+ {n:ee }{c: } |
+ {n:ff }{c: } |
+ {n:gg }{c: } |
+ {n:hh }{c: } |
+ {n:ii }{c: } |
+ {n:jj }{c: } |
+ {n:kk }{c: } |
+ {n:ll }{s: } |
+ {n:mm }{s: } |
+ aa^ |
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 15} |
+ ]])
+ end)
+
+ it('works with preview-window above and short and inverted', function()
+ feed(':ped<CR><c-w>4+')
+ feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>')
+ feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ {s:aa } |
+ {n:bb }{3:iew][+] }|
+ {n:cc } |
+ {n:dd } |
+ {n:ee } |
+ {n:ff } |
+ {n:gg } |
+ {n:hh } |
+ {n:ii } |
+ {n:jj } |
+ aa^ |
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+
+ it('works with preview-window below and inverted', function()
+ feed(':ped<CR><c-w>4+<c-w>r')
+ feed('iaa<cr>bb<cr>cc<cr>dd<cr>ee<cr>')
+ feed('ff<cr>gg<cr>hh<cr>ii<cr>jj<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ {s:aa }{c: } |
+ {n:bb }{c: } |
+ {n:cc }{c: } |
+ {n:dd }{c: } |
+ {n:ee }{c: } |
+ {n:ff }{c: } |
+ {n:gg }{s: } |
+ {n:hh }{s: } |
+ aa^ |
+ {4:[No Name] [+] }|
+ aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ hh |
+ {3:[No Name] [Preview][+] }|
+ {2:-- }{5:match 1 of 10} |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 7607131e9b..af036913d8 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -71,24 +71,35 @@
-- To help write screen tests, see Screen:snapshot_util().
-- To debug screen tests, see Screen:redraw_debug().
+local global_helpers = require('test.helpers')
+local shallowcopy = global_helpers.shallowcopy
local helpers = require('test.functional.helpers')(nil)
local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
+local eq = helpers.eq
local dedent = helpers.dedent
+local inspect = require('inspect')
+
+local function isempty(v)
+ return type(v) == 'table' and next(v) == nil
+end
+
local Screen = {}
Screen.__index = Screen
local debug_screen
-local default_screen_timeout = 3500
+local default_timeout_factor = 1
if os.getenv('VALGRIND') then
- default_screen_timeout = default_screen_timeout * 3
+ default_timeout_factor = default_timeout_factor * 3
end
if os.getenv('CI') then
- default_screen_timeout = default_screen_timeout * 3
+ default_timeout_factor = default_timeout_factor * 3
end
+local default_screen_timeout = default_timeout_factor * 3500
+
do
local spawn, nvim_prog = helpers.spawn, helpers.nvim_prog
local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'})
@@ -138,16 +149,26 @@ function Screen.new(width, height)
suspended = false,
mode = 'normal',
options = {},
+ popupmenu = nil,
+ cmdline = {},
+ cmdline_block = {},
+ wildmenu_items = nil,
+ wildmenu_selected = nil,
_default_attr_ids = nil,
_default_attr_ignore = nil,
_mouse_enabled = true,
_attrs = {},
+ _hl_info = {},
+ _attr_table = {[0]={{},{}}},
+ _clear_attrs = {},
+ _new_attrs = false,
+ _width = width,
+ _height = height,
_cursor = {
row = 1, col = 1
},
_busy = false
}, Screen)
- self:_handle_resize(width, height)
return self
end
@@ -159,11 +180,26 @@ function Screen:set_default_attr_ignore(attr_ignore)
self._default_attr_ignore = attr_ignore
end
+function Screen:set_hlstate_cterm(val)
+ self._hlstate_cterm = val
+end
+
function Screen:attach(options)
if options == nil then
- options = {rgb=true}
+ options = {}
end
+ if options.ext_linegrid == nil then
+ options.ext_linegrid = true
+ end
+ self._options = options
+ self._clear_attrs = (options.ext_linegrid and {{},{}}) or {}
+ self:_handle_resize(self._width, self._height)
uimeths.attach(self._width, self._height, options)
+ if self._options.rgb == nil then
+ -- nvim defaults to rgb=true internally,
+ -- simplify test code by doing the same.
+ self._options.rgb = true
+ end
end
function Screen:detach()
@@ -176,41 +212,123 @@ end
function Screen:set_option(option, value)
uimeths.set_option(option, value)
+ self._options[option] = value
end
--- Asserts that `expected` eventually matches the screen state.
+-- canonical order of ext keys, used to generate asserts
+local ext_keys = {
+ 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos'
+}
+
+-- Asserts that the screen state eventually matches an expected state
+--
+-- This function can either be called with the positional forms
+--
+-- screen:expect(grid, [attr_ids, attr_ignore])
+-- screen:expect(condition)
+--
+-- or to use additional arguments (or grid and condition at the same time)
+-- the keyword form has to be used:
--
--- expected: Expected screen state (string). Each line represents a screen
+-- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end}
+--
+--
+-- grid: Expected screen state (string). Each line represents a screen
-- row. Last character of each row (typically "|") is stripped.
-- Common indentation is stripped.
--- Used as `condition` if NOT a string; must be the ONLY arg then.
-- attr_ids: Expected text attributes. Screen rows are transformed according
-- to this table, as follows: each substring S composed of
-- characters having the same attributes will be substituted by
-- "{K:S}", where K is a key in `attr_ids`. Any unexpected
-- attributes in the final state are an error.
--- attr_ignore: Ignored text attributes, or `true` to ignore all.
--- condition: Function asserting some arbitrary condition.
--- any: true: Succeed if `expected` matches ANY screen line(s).
--- false (default): `expected` must match screen exactly.
-function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
+-- Use screen:set_default_attr_ids() to define attributes for many
+-- expect() calls.
+-- attr_ignore: Ignored text attributes, or `true` to ignore all. By default
+-- nothing is ignored.
+-- condition: Function asserting some arbitrary condition. Return value is
+-- ignored, throw an error (use eq() or similar) to signal failure.
+-- any: Lua pattern string expected to match a screen line. NB: the
+-- following chars are magic characters
+-- ( ) . % + - * ? [ ^ $
+-- and must be escaped with a preceding % for a literal match.
+-- mode: Expected mode as signaled by "mode_change" event
+-- unchanged: Test that the screen state is unchanged since the previous
+-- expect(...). Any flush event resulting in a different state is
+-- considered an error. Not observing any events until timeout
+-- is acceptable.
+-- intermediate:Test that the final state is the same as the previous expect,
+-- but expect an intermediate state that is different. If possible
+-- it is better to use an explicit screen:expect(...) for this
+-- intermediate state.
+-- reset: Reset the state internal to the test Screen before starting to
+-- receive updates. This should be used after command("redraw!")
+-- or some other mechanism that will invoke "redraw!", to check
+-- that all screen state is transmitted again. This includes
+-- state related to ext_ features as mentioned below.
+-- timeout: maximum time that will be waited until the expected state is
+-- seen (or maximum time to observe an incorrect change when
+-- `unchanged` flag is used)
+--
+-- The following keys should be used to expect the state of various ext_
+-- features. Note that an absent key will assert that the item is currently
+-- NOT present on the screen, also when positional form is used.
+--
+-- popupmenu: Expected ext_popupmenu state,
+-- cmdline: Expected ext_cmdline state, as an array of cmdlines of
+-- different level.
+-- cmdline_block: Expected ext_cmdline block (for function definitions)
+-- wildmenu_items: Expected items for ext_wildmenu
+-- wildmenu_pos: Expected position for ext_wildmenu
+function Screen:expect(expected, attr_ids, attr_ignore)
+ local grid, condition = nil, nil
local expected_rows = {}
- if type(expected) ~= "string" then
- assert(not (attr_ids or attr_ignore or condition or any))
+ if type(expected) == "table" then
+ assert(not (attr_ids ~= nil or attr_ignore ~= nil))
+ local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
+ any=true, mode=true, unchanged=true, intermediate=true,
+ reset=true, timeout=true}
+ for _, v in ipairs(ext_keys) do
+ is_key[v] = true
+ end
+ for k, _ in pairs(expected) do
+ if not is_key[k] then
+ error("Screen:expect: Unknown keyword argument '"..k.."'")
+ end
+ end
+ grid = expected.grid
+ attr_ids = expected.attr_ids
+ attr_ignore = expected.attr_ignore
+ condition = expected.condition
+ assert(not (expected.any ~= nil and grid ~= nil))
+ elseif type(expected) == "string" then
+ grid = expected
+ expected = {}
+ elseif type(expected) == "function" then
+ assert(not (attr_ids ~= nil or attr_ignore ~= nil))
condition = expected
- expected = nil
+ expected = {}
else
+ assert(false)
+ end
+
+ if grid ~= nil then
-- Remove the last line and dedent. Note that gsub returns more then one
-- value.
- expected = dedent(expected:gsub('\n[ ]+$', ''), 0)
- for row in expected:gmatch('[^\n]+') do
+ grid = dedent(grid:gsub('\n[ ]+$', ''), 0)
+ for row in grid:gmatch('[^\n]+') do
row = row:sub(1, #row - 1) -- Last char must be the screen delimiter.
table.insert(expected_rows, row)
end
end
- local ids = attr_ids or self._default_attr_ids
- local ignore = attr_ignore or self._default_attr_ignore
- self:wait(function()
+ local attr_state = {
+ ids = attr_ids or self._default_attr_ids,
+ ignore = attr_ignore or self._default_attr_ignore,
+ }
+ if self._options.ext_hlstate then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
+ end
+ self._new_attrs = false
+ self:_wait(function()
if condition ~= nil then
local status, res = pcall(condition)
if not status then
@@ -218,28 +336,32 @@ function Screen:expect(expected, attr_ids, attr_ignore, condition, any)
end
end
- if expected and not any and self._height ~= #expected_rows then
+ if grid ~= nil and self._height ~= #expected_rows then
return ("Expected screen state's row count(" .. #expected_rows
.. ') differs from configured height(' .. self._height .. ') of Screen.')
end
+ if self._options.ext_hlstate and self._new_attrs then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
+ end
+
local actual_rows = {}
for i = 1, self._height do
- actual_rows[i] = self:_row_repr(self._rows[i], ids, ignore)
+ actual_rows[i] = self:_row_repr(self._rows[i], attr_state)
end
- if expected == nil then
- return
- elseif any then
- -- Search for `expected` anywhere in the screen lines.
+ if expected.any ~= nil then
+ -- Search for `any` anywhere in the screen lines.
local actual_screen_str = table.concat(actual_rows, '\n')
- if nil == string.find(actual_screen_str, expected) then
+ if nil == string.find(actual_screen_str, expected.any) then
return (
'Failed to match any screen lines.\n'
- .. 'Expected (anywhere): "' .. expected .. '"\n'
+ .. 'Expected (anywhere): "' .. expected.any .. '"\n'
.. 'Actual:\n |' .. table.concat(actual_rows, '|\n |') .. '|\n\n')
end
- else
+ end
+
+ if grid ~= nil then
-- `expected` must match the screen lines exactly.
for i = 1, self._height do
if expected_rows[i] ~= actual_rows[i] then
@@ -259,21 +381,87 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
end
- end)
+
+ -- Extension features. The default expectations should cover the case of
+ -- the ext_ feature being disabled, or the feature currently not activated
+ -- (for instance no external cmdline visible). Some extensions require
+ -- preprocessing to represent highlights in a reproducible way.
+ local extstate = self:_extstate_repr(attr_state)
+
+ -- convert assertion errors into invalid screen state descriptions
+ local status, res = pcall(function()
+ for _, k in ipairs(ext_keys) do
+ -- Empty states is considered the default and need not be mentioned
+ if not (expected[k] == nil and isempty(extstate[k])) then
+ eq(expected[k], extstate[k], k)
+ end
+ end
+ if expected.mode ~= nil then
+ eq(expected.mode, self.mode, "mode")
+ end
+ end)
+ if not status then
+ return tostring(res)
+ end
+ end, expected)
end
-function Screen:wait(check, timeout)
- local err, checked = false
+function Screen:_wait(check, flags)
+ local err, checked = false, false
local success_seen = false
local failure_after_success = false
+ local did_flush = true
+ local warn_immediate = not (flags.unchanged or flags.intermediate)
+
+ if flags.intermediate and flags.unchanged then
+ error("Choose only one of 'intermediate' and 'unchanged', not both")
+ end
+
+ if flags.reset then
+ -- throw away all state, we expect it to be retransmitted
+ self:_reset()
+ end
+
+ -- Maximum timeout, after which a incorrect state will be regarded as a
+ -- failure
+ local timeout = flags.timeout or self.timeout
+
+ -- Minimal timeout before the loop is allowed to be stopped so we
+ -- always do some check for failure after success.
+ local minimal_timeout = default_timeout_factor * 2
+
+ local immediate_seen, intermediate_seen = false, false
+ if not check() then
+ minimal_timeout = default_timeout_factor * 20
+ immediate_seen = true
+ end
+
+ -- for an unchanged test, flags.timeout means the time during the state is
+ -- expected to be unchanged, so always wait this full time.
+ if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then
+ minimal_timeout = timeout
+ end
+
+ assert(timeout >= minimal_timeout)
+ local did_miminal_timeout = false
+
local function notification_cb(method, args)
assert(method == 'redraw')
- self:_redraw(args)
+ did_flush = self:_redraw(args)
+ if not did_flush then
+ return
+ end
err = check()
checked = true
+ if err and immediate_seen then
+ intermediate_seen = true
+ end
+
if not err then
success_seen = true
- helpers.stop()
+ if did_miminal_timeout then
+ helpers.stop()
+ end
elseif success_seen and #args > 0 then
failure_after_success = true
--print(require('inspect')(args))
@@ -281,37 +469,88 @@ function Screen:wait(check, timeout)
return true
end
- run(nil, notification_cb, nil, timeout or self.timeout)
- if not checked then
+ run(nil, notification_cb, nil, minimal_timeout)
+ if not did_flush then
+ err = "no flush received"
+ elseif not checked then
err = check()
+ if not err and flags.unchanged then
+ -- expecting NO screen change: use a shorter timout
+ success_seen = true
+ end
+ end
+
+ if not success_seen then
+ did_miminal_timeout = true
+ run(nil, notification_cb, nil, timeout-minimal_timeout)
+ end
+
+ local did_warn = false
+ if warn_immediate and immediate_seen then
+ print([[
+
+Warning: A screen test has immediate success. Try to avoid this unless the
+purpose of the test really requires it.]])
+ if intermediate_seen then
+ print([[
+There are intermediate states between the two identical expects.
+Use screen:snapshot_util() or screen:redraw_debug() to find them, and add them
+to the test if they make sense.
+]])
+ else
+ print([[If necessary, silence this warning by
+supplying the 'unchanged' argument to screen:expect.]])
+ end
+ did_warn = true
end
if failure_after_success then
print([[
Warning: Screen changes were received after the expected state. This indicates
-indeterminism in the test. Try adding wait() (or screen:expect(...)) between
+indeterminism in the test. Try adding screen:expect(...) (or wait()) between
asynchronous (feed(), nvim_input()) and synchronous API calls.
- - Use Screen:redraw_debug() to investigate the problem.
+ - Use Screen:redraw_debug() to investigate the problem. It might find
+ relevant intermediate states that should be added to the test to make it
+ more robust.
+ - If the point of the test is to assert the state after some user input
+ sent with feed(...), also adding an screen:expect(...) before the feed(...)
+ will help ensure the input is sent to nvim when nvim is in a predictable
+ state. This is preferable to using wait(), as it is more closely emulates
+ real user interaction.
- wait() can trigger redraws and consequently generate more indeterminism.
In that case try removing every wait().
]])
+ did_warn = true
+ end
+
+
+ if err then
+ assert(false, err)
+ elseif did_warn then
local tb = debug.traceback()
local index = string.find(tb, '\n%s*%[C]')
print(string.sub(tb,1,index))
end
- if err then
- assert(false, err)
+ if flags.intermediate then
+ assert(intermediate_seen, "expected intermediate screen state before final screen state")
+ elseif flags.unchanged then
+ assert(not intermediate_seen, "expected screen state to be unchanged")
end
end
function Screen:sleep(ms)
- pcall(function() self:wait(function() return "error" end, ms) end)
+ local function notification_cb(method, args)
+ assert(method == 'redraw')
+ self:_redraw(args)
+ end
+ run(nil, notification_cb, nil, ms)
end
function Screen:_redraw(updates)
- for _, update in ipairs(updates) do
+ local did_flush = false
+ for k, update in ipairs(updates) do
-- print('--')
-- print(require('inspect')(update))
local method = update[1]
@@ -326,8 +565,11 @@ function Screen:_redraw(updates)
self._on_event(method, update[i])
end
end
- -- print(self:_current_screen())
+ if k == #updates and method == "flush" then
+ did_flush = true
+ end
end
+ return did_flush
end
function Screen:set_on_event_handler(callback)
@@ -339,7 +581,7 @@ function Screen:_handle_resize(width, height)
for _ = 1, height do
local cols = {}
for _ = 1, width do
- table.insert(cols, {text = ' ', attrs = {}})
+ table.insert(cols, {text = ' ', attrs = self._clear_attrs, hl_id = 0})
end
table.insert(rows, cols)
end
@@ -353,14 +595,59 @@ function Screen:_handle_resize(width, height)
}
end
+function Screen:_handle_flush()
+end
+
+function Screen:_handle_grid_resize(grid, width, height)
+ assert(grid == 1)
+ self:_handle_resize(width, height)
+end
+
+function Screen:_reset()
+ -- TODO: generalize to multigrid later
+ self:_handle_grid_clear(1)
+
+ -- TODO: share with initialization, so it generalizes?
+ self.popupmenu = nil
+ self.cmdline = {}
+ self.cmdline_block = {}
+ self.wildmenu_items = nil
+ self.wildmenu_pos = nil
+end
+
+
function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
self._cursor_style_enabled = cursor_style_enabled
+ for _, item in pairs(mode_info) do
+ -- attr IDs are not stable, but their value should be
+ if item.attr_id ~= nil then
+ item.attr = self._attr_table[item.attr_id][1]
+ item.attr_id = nil
+ end
+ if item.attr_id_lm ~= nil then
+ item.attr_lm = self._attr_table[item.attr_id_lm][1]
+ item.attr_id_lm = nil
+ end
+ end
self._mode_info = mode_info
end
function Screen:_handle_clear()
- self:_clear_block(self._scroll_region.top, self._scroll_region.bot,
- self._scroll_region.left, self._scroll_region.right)
+ -- the first implemented UI protocol clients (python-gui and builitin TUI)
+ -- allowed the cleared region to be restricted by setting the scroll region.
+ -- this was never used by nvim tough, and not documented and implemented by
+ -- newer clients, to check we remain compatible with both kind of clients,
+ -- ensure the scroll region is in a reset state.
+ local expected_region = {
+ top = 1, bot = self._height, left = 1, right = self._width
+ }
+ eq(expected_region, self._scroll_region)
+ self:_clear_block(1, self._height, 1, self._width)
+end
+
+function Screen:_handle_grid_clear(grid)
+ assert(grid == 1)
+ self:_clear_block(1, self._height, 1, self._width)
end
function Screen:_handle_eol_clear()
@@ -373,6 +660,12 @@ function Screen:_handle_cursor_goto(row, col)
self._cursor.col = col + 1
end
+function Screen:_handle_grid_cursor_goto(grid, row, col)
+ assert(grid == 1)
+ self._cursor.row = row + 1
+ self._cursor.col = col + 1
+end
+
function Screen:_handle_busy_start()
self._busy = true
end
@@ -406,45 +699,85 @@ function Screen:_handle_scroll(count)
local bot = self._scroll_region.bot
local left = self._scroll_region.left
local right = self._scroll_region.right
+ self:_handle_grid_scroll(1, top-1, bot, left-1, right, count, 0)
+end
+
+function Screen:_handle_grid_scroll(grid, top, bot, left, right, rows, cols)
+ top = top+1
+ left = left+1
+ assert(grid == 1)
+ assert(cols == 0)
local start, stop, step
- if count > 0 then
+ if rows > 0 then
start = top
- stop = bot - count
+ stop = bot - rows
step = 1
else
start = bot
- stop = top - count
+ stop = top - rows
step = -1
end
-- shift scroll region
for i = start, stop, step do
local target = self._rows[i]
- local source = self._rows[i + count]
+ local source = self._rows[i + rows]
for j = left, right do
target[j].text = source[j].text
target[j].attrs = source[j].attrs
+ target[j].hl_id = source[j].hl_id
end
end
-- clear invalid rows
- for i = stop + step, stop + count, step do
+ for i = stop + step, stop + rows, step do
self:_clear_row_section(i, left, right)
end
end
+function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
+ self._attr_table[id] = {rgb_attrs, cterm_attrs}
+ self._hl_info[id] = info
+ self._new_attrs = true
+end
+
function Screen:_handle_highlight_set(attrs)
self._attrs = attrs
end
function Screen:_handle_put(str)
+ assert(not self._options.ext_linegrid)
local cell = self._rows[self._cursor.row][self._cursor.col]
cell.text = str
cell.attrs = self._attrs
+ cell.hl_id = -1
self._cursor.col = self._cursor.col + 1
end
+function Screen:_handle_grid_line(grid, row, col, items)
+ assert(self._options.ext_linegrid)
+ assert(grid == 1)
+ local line = self._rows[row+1]
+ local colpos = col+1
+ local hl = self._clear_attrs
+ local hl_id = 0
+ 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
+ hl = self._attr_table[hl_id]
+ end
+ for _ = 1, (count or 1) do
+ local cell = line[colpos]
+ cell.text = text
+ cell.hl_id = hl_id
+ cell.attrs = hl
+ colpos = colpos+1
+ end
+ end
+end
+
function Screen:_handle_bell()
self.bell = true
end
@@ -453,7 +786,14 @@ function Screen:_handle_visual_bell()
self.visual_bell = true
end
-function Screen:_handle_default_colors_set()
+function Screen:_handle_default_colors_set(rgb_fg, rgb_bg, rgb_sp, cterm_fg, cterm_bg)
+ self.default_colors = {
+ rgb_fg=rgb_fg,
+ rgb_bg=rgb_bg,
+ rgb_sp=rgb_sp,
+ cterm_fg=cterm_fg,
+ cterm_bg=cterm_bg
+ }
end
function Screen:_handle_update_fg(fg)
@@ -488,6 +828,63 @@ function Screen:_handle_option_set(name, value)
self.options[name] = value
end
+function Screen:_handle_popupmenu_show(items, selected, row, col)
+ self.popupmenu = {items=items,pos=selected, anchor={row, col}}
+end
+
+function Screen:_handle_popupmenu_select(selected)
+ self.popupmenu.pos = selected
+end
+
+function Screen:_handle_popupmenu_hide()
+ self.popupmenu = nil
+end
+
+function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level)
+ if firstc == '' then firstc = nil end
+ if prompt == '' then prompt = nil end
+ if indent == 0 then indent = nil end
+ self.cmdline[level] = {content=content, pos=pos, firstc=firstc,
+ prompt=prompt, indent=indent}
+end
+
+function Screen:_handle_cmdline_hide(level)
+ self.cmdline[level] = nil
+end
+
+function Screen:_handle_cmdline_special_char(char, shift, level)
+ -- cleared by next cmdline_show on the same level
+ self.cmdline[level].special = {char, shift}
+end
+
+function Screen:_handle_cmdline_pos(pos, level)
+ self.cmdline[level].pos = pos
+end
+
+function Screen:_handle_cmdline_block_show(block)
+ self.cmdline_block = block
+end
+
+function Screen:_handle_cmdline_block_append(item)
+ self.cmdline_block[#self.cmdline_block+1] = item
+end
+
+function Screen:_handle_cmdline_block_hide()
+ self.cmdline_block = {}
+end
+
+function Screen:_handle_wildmenu_show(items)
+ self.wildmenu_items = items
+end
+
+function Screen:_handle_wildmenu_select(pos)
+ self.wildmenu_pos = pos
+end
+
+function Screen:_handle_wildmenu_hide()
+ self.wildmenu_items, self.wildmenu_pos = nil, nil
+end
+
function Screen:_clear_block(top, bot, left, right)
for i = top, bot do
self:_clear_row_section(i, left, right)
@@ -498,15 +895,19 @@ function Screen:_clear_row_section(rownum, startcol, stopcol)
local row = self._rows[rownum]
for i = startcol, stopcol do
row[i].text = ' '
- row[i].attrs = {}
+ row[i].attrs = self._clear_attrs
end
end
-function Screen:_row_repr(row, attr_ids, attr_ignore)
+function Screen:_row_repr(row, attr_state)
local rv = {}
local current_attr_id
for i = 1, self._width do
- local attr_id = self:_get_attr_id(attr_ids, attr_ignore, row[i].attrs)
+ local attrs = row[i].attrs
+ if self._options.ext_linegrid then
+ attrs = attrs[(self._options.rgb and 1) or 2]
+ end
+ local attr_id = self:_get_attr_id(attr_state, attrs, row[i].hl_id)
if current_attr_id and attr_id ~= current_attr_id then
-- close current attribute bracket, add it before any whitespace
-- up to the current cell
@@ -532,14 +933,42 @@ function Screen:_row_repr(row, attr_ids, attr_ignore)
return table.concat(rv, '')--:gsub('%s+$', '')
end
+function Screen:_extstate_repr(attr_state)
+ local cmdline = {}
+ for i, entry in pairs(self.cmdline) do
+ entry = shallowcopy(entry)
+ entry.content = self:_chunks_repr(entry.content, attr_state)
+ cmdline[i] = entry
+ end
+
+ local cmdline_block = {}
+ for i, entry in ipairs(self.cmdline_block) do
+ cmdline_block[i] = self:_chunks_repr(entry, attr_state)
+ end
-function Screen:_current_screen()
- -- get a string that represents the current screen state(debugging helper)
- local rv = {}
- for i = 1, self._height do
- table.insert(rv, "'"..self:_row_repr(self._rows[i]).."'")
+ return {
+ popupmenu=self.popupmenu,
+ cmdline=cmdline,
+ cmdline_block=cmdline_block,
+ wildmenu_items=self.wildmenu_items,
+ wildmenu_pos=self.wildmenu_pos,
+ }
+end
+
+function Screen:_chunks_repr(chunks, attr_state)
+ local repr_chunks = {}
+ for i, chunk in ipairs(chunks) do
+ local hl, text = unpack(chunk)
+ local attrs
+ if self._options.ext_linegrid then
+ attrs = self._attr_table[hl][1]
+ else
+ attrs = hl
+ end
+ local attr_id = self:_get_attr_id(attr_state, attrs, hl)
+ repr_chunks[i] = {text, attr_id}
end
- return table.concat(rv, '\n')
+ return repr_chunks
end
-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
@@ -570,56 +999,179 @@ function Screen:redraw_debug(attrs, ignore, timeout)
end
function Screen:print_snapshot(attrs, ignore)
+ attrs = attrs or self._default_attr_ids
if ignore == nil then
ignore = self._default_attr_ignore
end
- if attrs == nil then
- attrs = {}
- if self._default_attr_ids ~= nil then
- for i, a in pairs(self._default_attr_ids) do
- attrs[i] = a
+ local attr_state = {
+ ids = {},
+ ignore = ignore,
+ mutable = true, -- allow _row_repr to add missing highlights
+ }
+
+ if attrs ~= nil then
+ for i, a in pairs(attrs) do
+ attr_state.ids[i] = a
+ end
+ end
+ if self._options.ext_hlstate then
+ attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids)
+ end
+
+ local lines = {}
+ for i = 1, self._height do
+ table.insert(lines, " "..self:_row_repr(self._rows[i], attr_state).."|")
+ end
+
+ local ext_state = self:_extstate_repr(attr_state)
+ local keys = false
+ for k, v in pairs(ext_state) do
+ if isempty(v) then
+ ext_state[k] = nil -- deleting keys while iterating is ok
+ else
+ keys = true
+ end
+ end
+
+ local attrstr = ""
+ if attr_state.modified then
+ local attrstrs = {}
+ for i, a in pairs(attr_state.ids) do
+ local dict
+ if self._options.ext_hlstate then
+ dict = self:_pprint_hlstate(a)
+ else
+ dict = "{"..self:_pprint_attrs(a).."}"
end
+ local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
+ table.insert(attrstrs, " "..keyval.." = "..dict..",")
end
+ attrstr = (", "..(keys and "attr_ids=" or "")
+ .."{\n"..table.concat(attrstrs, "\n").."\n}")
+ end
+ print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[")
+ print( table.concat(lines, '\n'))
+ io.stdout:write( "]]"..attrstr)
+ for _, k in ipairs(ext_keys) do
+ if ext_state[k] ~= nil then
+ io.stdout:write(", "..k.."="..inspect(ext_state[k]))
+ end
+ end
+ print((keys and "}" or ")").."\n")
+ io.stdout:flush()
+end
- if ignore ~= true then
- for i = 1, self._height do
- local row = self._rows[i]
- for j = 1, self._width do
- local attr = row[j].attrs
- if self:_attr_index(attrs, attr) == nil and self:_attr_index(ignore, attr) == nil then
- if not self:_equal_attrs(attr, {}) then
- table.insert(attrs, attr)
+function Screen:_insert_hl_id(attr_state, hl_id)
+ if attr_state.id_to_index[hl_id] ~= nil then
+ return attr_state.id_to_index[hl_id]
+ end
+ local raw_info = self._hl_info[hl_id]
+ local info = {}
+ if #raw_info > 1 then
+ for i, item in ipairs(raw_info) do
+ info[i] = self:_insert_hl_id(attr_state, item.id)
+ end
+ else
+ info[1] = {}
+ for k, v in pairs(raw_info[1]) do
+ if k ~= "id" then
+ info[1][k] = v
+ end
+ end
+ end
+
+ local entry = self._attr_table[hl_id]
+ local attrval
+ if self._hlstate_cterm then
+ attrval = {entry[1], entry[2], info} -- unpack() doesn't work
+ else
+ attrval = {entry[1], info}
+ end
+
+
+ table.insert(attr_state.ids, attrval)
+ attr_state.id_to_index[hl_id] = #attr_state.ids
+ return #attr_state.ids
+end
+
+function Screen:hlstate_check_attrs(attrs)
+ local id_to_index = {}
+ for i = 1,#self._attr_table do
+ local iinfo = self._hl_info[i]
+ local matchinfo = {}
+ if #iinfo > 1 then
+ for k,item in ipairs(iinfo) do
+ matchinfo[k] = id_to_index[item.id]
+ end
+ else
+ matchinfo = iinfo
+ end
+ for k,v in pairs(attrs) do
+ local attr, info, attr_rgb, attr_cterm
+ if self._hlstate_cterm then
+ attr_rgb, attr_cterm, info = unpack(v)
+ attr = {attr_rgb, attr_cterm}
+ else
+ attr, info = unpack(v)
+ end
+ if self:_equal_attr_def(attr, self._attr_table[i]) then
+ if #info == #matchinfo then
+ local match = false
+ if #info == 1 then
+ if self:_equal_info(info[1],matchinfo[1]) then
+ match = true
+ end
+ else
+ match = true
+ for j = 1,#info do
+ if info[j] ~= matchinfo[j] then
+ match = false
+ end
end
end
+ if match then
+ id_to_index[i] = k
+ end
end
end
end
end
+ return id_to_index
+end
- local rv = {}
- for i = 1, self._height do
- table.insert(rv, " "..self:_row_repr(self._rows[i],attrs, ignore).."|")
- end
- local attrstrs = {}
- local alldefault = true
- for i, a in ipairs(attrs) do
- if self._default_attr_ids == nil or self._default_attr_ids[i] ~= a then
- alldefault = false
- end
- local dict = "{"..self:_pprint_attrs(a).."}"
- table.insert(attrstrs, "["..tostring(i).."] = "..dict)
- end
- local attrstr = "{"..table.concat(attrstrs, ", ").."}"
- print( "\nscreen:expect([[")
- print( table.concat(rv, '\n'))
- if alldefault then
- print( "]])\n")
+
+function Screen:_pprint_hlstate(item)
+ --print(require('inspect')(item))
+ local attrdict = "{"..self:_pprint_attrs(item[1]).."}, "
+ local attrdict2, hlinfo
+ if self._hlstate_cterm then
+ attrdict2 = "{"..self:_pprint_attrs(item[2]).."}, "
+ hlinfo = item[3]
+ else
+ attrdict2 = ""
+ hlinfo = item[2]
+ end
+ local descdict = "{"..self:_pprint_hlinfo(hlinfo).."}"
+ return "{"..attrdict..attrdict2..descdict.."}"
+end
+
+function Screen:_pprint_hlinfo(states)
+ if #states == 1 then
+ local items = {}
+ for f, v in pairs(states[1]) do
+ local desc = tostring(v)
+ if type(v) == type("") then
+ desc = '"'..desc..'"'
+ end
+ table.insert(items, f.." = "..desc)
+ end
+ return "{"..table.concat(items, ", ").."}"
else
- print( "]], "..attrstr..")\n")
+ return table.concat(states, ", ")
end
- io.stdout:flush()
end
+
function Screen:_pprint_attrs(attrs)
local items = {}
for f, v in pairs(attrs) do
@@ -643,32 +1195,64 @@ local function backward_find_meaningful(tbl, from) -- luacheck: no unused
return from
end
-function Screen:_get_attr_id(attr_ids, ignore, attrs)
- if not attr_ids then
+function Screen:_get_attr_id(attr_state, attrs, hl_id)
+ if not attr_state.ids then
return
end
- for id, a in pairs(attr_ids) do
- if self:_equal_attrs(a, attrs) then
- return id
- end
+
+ if self._options.ext_hlstate then
+ local id = attr_state.id_to_index[hl_id]
+ if id ~= nil or hl_id == 0 then
+ return id
+ end
+ if attr_state.mutable then
+ id = self:_insert_hl_id(attr_state, hl_id)
+ attr_state.modified = true
+ return id
+ end
+ return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
+ else
+ for id, a in pairs(attr_state.ids) do
+ if self:_equal_attrs(a, attrs) then
+ return id
+ end
+ end
+ if self:_equal_attrs(attrs, {}) or
+ attr_state.ignore == true or
+ self:_attr_index(attr_state.ignore, attrs) ~= nil then
+ -- ignore this attrs
+ return nil
+ end
+ if attr_state.mutable then
+ table.insert(attr_state.ids, attrs)
+ attr_state.modified = true
+ return #attr_state.ids
+ end
+ return "UNEXPECTED "..self:_pprint_attrs(attrs)
end
- if self:_equal_attrs(attrs, {}) or
- ignore == true or self:_attr_index(ignore, attrs) ~= nil then
- -- ignore this attrs
- return nil
+end
+
+function Screen:_equal_attr_def(a, b)
+ if self._hlstate_cterm then
+ return self:_equal_attrs(a[1],b[1]) and self:_equal_attrs(a[2],b[2])
+ else
+ return self:_equal_attrs(a,b[1])
end
- return "UNEXPECTED "..self:_pprint_attrs(attrs)
end
function Screen:_equal_attrs(a, b)
return a.bold == b.bold and a.standout == b.standout and
a.underline == b.underline and a.undercurl == b.undercurl and
a.italic == b.italic and a.reverse == b.reverse and
- a.foreground == b.foreground and
- a.background == b.background and
+ a.foreground == b.foreground and a.background == b.background and
a.special == b.special
end
+function Screen:_equal_info(a, b)
+ return a.kind == b.kind and a.hi_name == b.hi_name and
+ a.ui_name == b.ui_name
+end
+
function Screen:_attr_index(attrs, attr)
if not attrs then
return nil
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 6f04cde4d4..1a8b7d543a 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -48,13 +48,13 @@ describe('screen', function()
end)
end)
-describe('Screen', function()
+local function screen_tests(linegrid)
local screen
before_each(function()
clear()
screen = Screen.new()
- screen:attach()
+ screen:attach({rgb=true,ext_linegrid=linegrid})
screen:set_default_attr_ids( {
[0] = {bold=true, foreground=255},
[1] = {bold=true, reverse=true},
@@ -354,6 +354,140 @@ describe('Screen', function()
{0:~ }|
|
]])
+
+ feed(':echo "'..string.rep('x\\n', 12)..'"<cr>')
+ screen:expect([[
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ x |
+ |
+ {7:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed('<cr>')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ end)
+
+ it('redraws properly with :tab split right after scroll', function()
+ feed('15Ofoo<esc>15Obar<esc>gg')
+
+ command('vsplit')
+ screen:expect([[
+ ^foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ {1:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+
+ feed('<PageDown>')
+ screen:expect([[
+ ^foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ foo {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ bar {3:│}foo |
+ {1:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ command('tab split')
+ screen:expect([[
+ {4: }{5:2}{4:+ [No Name] }{2: + [No Name] }{3: }{4:X}|
+ ^foo |
+ foo |
+ foo |
+ foo |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ bar |
+ |
+ ]])
+ end)
+
+ it('redraws unvisited tab #9152', function()
+ insert('hello')
+ -- create a tab without visiting it
+ command('tabnew|tabnext')
+ screen:expect([[
+ {2: + [No Name] }{4: [No Name] }{3: }{4:X}|
+ hell^o |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('gT')
+ screen:expect([[
+ {4: + [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
end)
end)
@@ -741,4 +875,12 @@ describe('Screen', function()
|
]])
end)
+end
+
+describe("Screen (char-based)", function()
+ screen_tests(false)
+end)
+
+describe("Screen (line-based)", function()
+ screen_tests(true)
end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 168080a092..a46670d8a2 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local command = helpers.command
local feed_command = helpers.feed_command
local eq = helpers.eq
local eval = helpers.eval
@@ -93,6 +94,59 @@ describe('search highlighting', function()
]])
end)
+ it('highlights after EOL', function()
+ insert("\n\n\n\n\n\n")
+
+ feed("gg/^<cr>")
+ screen:expect([[
+ {2: } |
+ {2:^ } |
+ {2: } |
+ {2: } |
+ {2: } |
+ {2: } |
+ /^ |
+ ]])
+
+ -- Test that highlights are preserved after moving the cursor.
+ feed("j")
+ screen:expect([[
+ {2: } |
+ {2: } |
+ {2:^ } |
+ {2: } |
+ {2: } |
+ {2: } |
+ /^ |
+ ]])
+
+ -- Repeat the test in rightleft mode.
+ command("nohlsearch")
+ command("set rightleft")
+ feed("gg/^<cr>")
+
+ screen:expect([[
+ {2: }|
+ {2:^ }|
+ {2: }|
+ {2: }|
+ {2: }|
+ {2: }|
+ ^/ |
+ ]])
+
+ feed("j")
+ screen:expect([[
+ {2: }|
+ {2: }|
+ {2:^ }|
+ {2: }|
+ {2: }|
+ {2: }|
+ ^/ |
+ ]])
+ end)
+
it('is preserved during :terminal activity', function()
if iswin() then
feed([[:terminal for /L \%I in (1,1,5000) do @(echo xxx & echo xxx & echo xxx)<cr>]])
@@ -270,7 +324,17 @@ describe('search highlighting', function()
]])
-- same, for C-t
- feed('<ESC>/<C-t>')
+ feed('<ESC>')
+ screen:expect([[
+ the first line |
+ in a ^little file |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('/<C-t>')
screen:expect([[
the first line |
in a little file |
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index c00d99cf90..6abeb0b2f4 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
+local source = helpers.source
describe('Signs', function()
local screen
@@ -13,6 +14,12 @@ describe('Signs', function()
[0] = {bold=true, foreground=255},
[1] = {background = Screen.colors.Yellow},
[2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey},
+ [3] = {background = Screen.colors.Gray90},
+ [4] = {bold = true, reverse = true},
+ [5] = {reverse = true},
+ [6] = {foreground = Screen.colors.Brown},
+ [7] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
+ [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
} )
end)
@@ -45,5 +52,64 @@ describe('Signs', function()
|
]])
end)
+
+ it('can be called right after :split', function()
+ feed('ia<cr>b<cr>c<cr><esc>gg')
+ -- This used to cause a crash due to :sign using a special redraw
+ -- (not updating nvim's specific highlight data structures)
+ -- without proper redraw first, as split just flags for redraw later.
+ source([[
+ set cursorline
+ sign define piet text=>> texthl=Search
+ split
+ sign place 3 line=2 name=piet buffer=1
+ ]])
+ screen:expect([[
+ {2: }{3:^a }|
+ {1:>>}b |
+ {2: }c |
+ {2: } |
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {4:[No Name] [+] }|
+ {2: }{3:a }|
+ {1:>>}b |
+ {2: }c |
+ {2: } |
+ {2: }{0:~ }|
+ {5:[No Name] [+] }|
+ |
+ ]])
+ end)
+
+ it('can combine text, linehl and numhl', function()
+ feed('ia<cr>b<cr>c<cr><esc>')
+ command('set number')
+ command('sign define piet text=>> texthl=Search')
+ command('sign define pietx linehl=ErrorMsg')
+ command('sign define pietxx numhl=Folded')
+ command('sign place 1 line=1 name=piet buffer=1')
+ command('sign place 2 line=2 name=pietx buffer=1')
+ command('sign place 3 line=3 name=pietxx buffer=1')
+ command('sign place 4 line=4 name=piet buffer=1')
+ command('sign place 5 line=4 name=pietx buffer=1')
+ command('sign place 6 line=4 name=pietxx buffer=1')
+ screen:expect([[
+ {1:>>}{6: 1 }a |
+ {2: }{6: 2 }{8:b }|
+ {2: }{7: 3 }c |
+ {1:>>}{7: 4 }{8:^ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ {2: }{0:~ }|
+ |
+ ]])
+ end)
end)
end)
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index e8271de0bf..dcab9f7ef4 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -28,27 +28,27 @@ describe('ui/ext_tabline', function()
{tab = { id = 1 }, name = '[No Name]'},
{tab = { id = 2 }, name = 'another-tab'},
}
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
|
- ]], nil, nil, function()
+ ]], condition=function()
eq({ id = 2 }, event_curtab)
eq(expected_tabs, event_tabs)
- end)
+ end}
command("tabNext")
- screen:expect([[
+ screen:expect{grid=[[
^ |
~ |
~ |
~ |
|
- ]], nil, nil, function()
+ ]], condition=function()
eq({ id = 1 }, event_curtab)
eq(expected_tabs, event_tabs)
- end)
+ end}
end)
end)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index b60d520ca0..8931d9245b 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -1,3 +1,5 @@
+local global_helpers = require('test.helpers')
+local shallowcopy = global_helpers.shallowcopy
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
@@ -18,6 +20,14 @@ describe("'wildmenu'", function()
screen:detach()
end)
+ -- expect the screen stayed unchanged some time after first seen success
+ local function expect_stay_unchanged(args)
+ screen:expect(args)
+ args = shallowcopy(args)
+ args.unchanged = true
+ screen:expect(args)
+ end
+
it(':sign <tab> shows wildmenu completions', function()
command('set wildmode=full')
command('set wildmenu')
@@ -76,10 +86,6 @@ describe("'wildmenu'", function()
end)
it('is preserved during :terminal activity', function()
- -- Because this test verifies a _lack_ of activity after screen:sleep(), we
- -- must wait the full timeout. So make it reasonable.
- screen.timeout = 1000
-
command('set wildmenu wildmode=full')
command('set scrollback=4')
if iswin() then
@@ -90,26 +96,24 @@ describe("'wildmenu'", function()
feed([[<C-\><C-N>gg]])
feed([[:sign <Tab>]]) -- Invoke wildmenu.
- screen:sleep(50) -- Allow some terminal output.
- screen:expect([[
+ expect_stay_unchanged{grid=[[
foo |
foo |
foo |
define jump list > |
:sign define^ |
- ]])
+ ]]}
-- cmdline CTRL-D display should also be preserved.
feed([[<C-\><C-N>]])
feed([[:sign <C-D>]]) -- Invoke cmdline CTRL-D.
- screen:sleep(50) -- Allow some terminal output.
- screen:expect([[
+ expect_stay_unchanged{grid=[[
:sign |
define place |
jump undefine |
list unplace |
:sign ^ |
- ]])
+ ]]}
-- Exiting cmdline should show the buffer.
feed([[<C-\><C-N>]])
@@ -123,22 +127,17 @@ describe("'wildmenu'", function()
end)
it('ignores :redrawstatus called from a timer #7108', function()
- -- Because this test verifies a _lack_ of activity after screen:sleep(), we
- -- must wait the full timeout. So make it reasonable.
- screen.timeout = 1000
-
command('set wildmenu wildmode=full')
command([[call timer_start(10, {->execute('redrawstatus')}, {'repeat':-1})]])
feed([[<C-\><C-N>]])
feed([[:sign <Tab>]]) -- Invoke wildmenu.
- screen:sleep(30) -- Allow some timer activity.
- screen:expect([[
+ expect_stay_unchanged{grid=[[
|
~ |
~ |
define jump list > |
:sign define^ |
- ]])
+ ]]}
end)
it('with laststatus=0, :vsplit, :term #2255', function()
@@ -164,10 +163,9 @@ describe("'wildmenu'", function()
feed([[<C-\><C-N>]])
feed([[:<Tab>]]) -- Invoke wildmenu.
- screen:sleep(10) -- Flush
-- Check only the last 2 lines, because the shell output is
-- system-dependent.
- screen:expect('! # & < = > @ > \n:!^', nil, nil, nil, true)
+ expect_stay_unchanged{any='! # & < = > @ > \n:!^'}
end)
end)
@@ -204,21 +202,11 @@ end)
describe('ui/ext_wildmenu', function()
local screen
- local items, selected = nil, nil
before_each(function()
clear()
screen = Screen.new(25, 5)
screen:attach({rgb=true, ext_wildmenu=true})
- screen:set_on_event_handler(function(name, data)
- if name == "wildmenu_show" then
- items = data[1]
- elseif name == "wildmenu_select" then
- selected = data[1]
- elseif name == "wildmenu_hide" then
- items, selected = nil, nil
- end
- end)
end)
after_each(function()
@@ -238,63 +226,48 @@ describe('ui/ext_wildmenu', function()
command('set wildmode=full')
command('set wildmenu')
feed(':sign <tab>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign define^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(0, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=0}
feed('<tab>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign jump^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(1, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=1}
feed('<left><left>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign ^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(-1, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=-1}
feed('<right>')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign define^ |
- ]], nil, nil, function()
- eq(expected, items)
- eq(0, selected)
- end)
+ ]], wildmenu_items=expected, wildmenu_pos=0}
feed('a')
- screen:expect([[
+ screen:expect{grid=[[
|
~ |
~ |
~ |
:sign definea^ |
- ]], nil, nil, function()
- eq(nil, items)
- eq(nil, selected)
- end)
+ ]]}
end)
end)
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index c14f7fc1a6..70b4717c32 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -757,7 +757,7 @@ describe('completion', function()
eval('1 + 1')
-- popupmenu still visible
- screen:expect([[
+ screen:expect{grid=[[
foobar fooegg |
fooegg^ |
{1:foobar }{0: }|
@@ -766,7 +766,7 @@ describe('completion', function()
{0:~ }|
{0:~ }|
{3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
- ]])
+ ]], unchanged=true}
feed('<c-p>')
-- Didn't restart completion: old matches still used
@@ -873,107 +873,6 @@ describe('completion', function()
{3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} |
]])
end)
-end)
-
-describe('ui/ext_popupmenu', function()
- local screen
- local items, selected, anchor
- before_each(function()
- clear()
- screen = Screen.new(60, 8)
- screen:attach({rgb=true, ext_popupmenu=true})
- screen:set_default_attr_ids({
- [1] = {bold=true, foreground=Screen.colors.Blue},
- [2] = {bold = true},
- })
- screen:set_on_event_handler(function(name, data)
- if name == "popupmenu_show" then
- local row, col
- items, selected, row, col = unpack(data)
- anchor = {row, col}
- elseif name == "popupmenu_select" then
- selected = data[1]
- elseif name == "popupmenu_hide" then
- items = nil
- end
- end)
- end)
-
- it('works', function()
- source([[
- function! TestComplete() abort
- call complete(1, ['foo', 'bar', 'spam'])
- return ''
- endfunction
- ]])
- local expected = {
- {'foo', '', '', ''},
- {'bar', '', '', ''},
- {'spam', '', '', ''},
- }
- feed('o<C-r>=TestComplete()<CR>')
- screen:expect([[
- |
- foo^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]], nil, nil, function()
- eq(expected, items)
- eq(0, selected)
- eq({1,0}, anchor)
- end)
-
- feed('<c-p>')
- screen:expect([[
- |
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]], nil, nil, function()
- eq(expected, items)
- eq(-1, selected)
- eq({1,0}, anchor)
- end)
-
- -- down moves the selection in the menu, but does not insert anything
- feed('<down><down>')
- screen:expect([[
- |
- ^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]], nil, nil, function()
- eq(expected, items)
- eq(1, selected)
- eq({1,0}, anchor)
- end)
-
- feed('<cr>')
- screen:expect([[
- |
- bar^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]], nil, nil, function()
- eq(nil, items) -- popupmenu was hidden
- end)
- end)
it('TextChangedP autocommand', function()
curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar'})
diff --git a/test/helpers.lua b/test/helpers.lua
index a774a67df3..6ef7a456f4 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -1,6 +1,7 @@
local assert = require('luassert')
local luv = require('luv')
local lfs = require('lfs')
+local relpath = require('pl.path').relpath
local quote_me = '[^.%w%+%-%@%_%/]' -- complement (needn't quote)
local function shell_quote(str)
@@ -45,8 +46,8 @@ local check_logs_useless_lines = {
['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3,
}
-local function eq(expected, actual)
- return assert.are.same(expected, actual)
+local function eq(expected, actual, ctx)
+ return assert.are.same(expected, actual, ctx)
end
local function neq(expected, actual)
return assert.are_not.same(expected, actual)
@@ -54,6 +55,9 @@ end
local function ok(res)
return assert.is_true(res)
end
+local function near(actual, expected, tolerance)
+ return assert.is.near(actual, expected, tolerance)
+end
local function matches(pat, actual)
if nil ~= string.match(actual, pat) then
return true
@@ -133,7 +137,6 @@ local function check_logs()
fd:close()
os.remove(file)
if #lines > 0 then
- -- local out = os.getenv('TRAVIS_CI_BUILD') and io.stdout or io.stderr
local out = io.stdout
out:write(start_msg .. '\n')
out:write('= ' .. table.concat(lines, '\n= ') .. '\n')
@@ -242,7 +245,7 @@ local function check_cores(app, force)
-- Workspace-local $TMPDIR, scrubbed and pattern-escaped.
-- "./Xtest-tmpdir/" => "Xtest%-tmpdir"
local local_tmpdir = (tmpdir_is_local(tmpdir_get())
- and tmpdir_get():gsub('^[ ./]+',''):gsub('%/+$',''):gsub('([^%w])', '%%%1')
+ and relpath(tmpdir_get()):gsub('^[ ./]+',''):gsub('%/+$',''):gsub('([^%w])', '%%%1')
or nil)
local db_cmd
if hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
@@ -643,8 +646,38 @@ local function hexdump(str)
return dump .. hex .. string.rep(" ", 8 - len % 8) .. asc
end
-local function read_file(name)
- local file = io.open(name, 'r')
+-- Reads text lines from `filename` into a table.
+--
+-- filename: path to file
+-- start: start line (1-indexed), negative means "lines before end" (tail)
+local function read_file_list(filename, start)
+ local lnum = (start ~= nil and type(start) == 'number') and start or 1
+ local tail = (lnum < 0)
+ local maxlines = tail and math.abs(lnum) or nil
+ local file = io.open(filename, 'r')
+ if not file then
+ return nil
+ end
+ local lines = {}
+ local i = 1
+ for line in file:lines() do
+ if i >= start then
+ table.insert(lines, line)
+ if #lines > maxlines then
+ table.remove(lines, 1)
+ end
+ end
+ i = i + 1
+ end
+ file:close()
+ return lines
+end
+
+-- Reads the entire contents of `filename` into a string.
+--
+-- filename: path to file
+local function read_file(filename)
+ local file = io.open(filename, 'r')
if not file then
return nil
end
@@ -671,6 +704,32 @@ local function write_file(name, text, no_dedent, append)
file:close()
end
+local function isCI()
+ local is_travis = nil ~= os.getenv('TRAVIS')
+ local is_appveyor = nil ~= os.getenv('APPVEYOR')
+ local is_quickbuild = nil ~= os.getenv('PR_NUMBER')
+ return is_travis or is_appveyor or is_quickbuild
+end
+
+-- Gets the contents of $NVIM_LOG_FILE for printing to the build log.
+-- Also removes the file, if the current environment looks like CI.
+local function read_nvim_log()
+ local logfile = os.getenv('NVIM_LOG_FILE') or '.nvimlog'
+ local keep = isCI() and 999 or 10
+ local lines = read_file_list(logfile, -keep) or {}
+ local log = (('-'):rep(78)..'\n'
+ ..string.format('$NVIM_LOG_FILE: %s\n', logfile)
+ ..(#lines > 0 and '(last '..tostring(keep)..' lines)\n' or '(empty)\n'))
+ for _,line in ipairs(lines) do
+ log = log..line..'\n'
+ end
+ log = log..('-'):rep(78)..'\n'
+ if isCI() then
+ os.remove(logfile)
+ end
+ return log
+end
+
local module = {
REMOVE_THIS = REMOVE_THIS,
argss_to_cmd = argss_to_cmd,
@@ -694,14 +753,17 @@ local module = {
map = map,
matches = matches,
mergedicts_copy = mergedicts_copy,
+ near = near,
neq = neq,
ok = ok,
popen_r = popen_r,
popen_w = popen_w,
read_file = read_file,
+ read_file_list = read_file_list,
+ read_nvim_log = read_nvim_log,
repeated_read_cmd = repeated_read_cmd,
- sleep = sleep,
shallowcopy = shallowcopy,
+ sleep = sleep,
table_flatten = table_flatten,
tmpname = tmpname,
uname = uname,
diff --git a/test/unit/os/shell_spec.lua b/test/unit/os/shell_spec.lua
index 37274502de..a73fc8e47e 100644
--- a/test/unit/os/shell_spec.lua
+++ b/test/unit/os/shell_spec.lua
@@ -25,6 +25,7 @@ describe('shell functions', function()
local res = cimported.shell_build_argv(
cmd and to_cstr(cmd),
extra_args and to_cstr(extra_args))
+ -- `res` is zero-indexed (C pointer, not Lua table)!
local argc = 0
local ret = {}
-- Explicitly free everything, so if it is not in allocated memory it will
@@ -38,6 +39,26 @@ describe('shell functions', function()
return ret
end
+ local function shell_argv_to_str(argv_table)
+ -- C string array (char **).
+ local argv = (argv_table
+ and ffi.new("char*[?]", #argv_table+1)
+ or NULL)
+
+ local argc = 1
+ while argv_table ~= nil and argv_table[argc] ~= nil do
+ -- `argv` is zero-indexed (C pointer, not Lua table)!
+ argv[argc - 1] = to_cstr(argv_table[argc])
+ argc = argc + 1
+ end
+ if argv_table ~= nil then
+ argv[argc - 1] = NULL
+ end
+
+ local res = cimported.shell_argv_to_str(argv)
+ return ffi.string(res)
+ end
+
local function os_system(cmd, input)
local input_or = input and to_cstr(input) or NULL
local input_len = (input ~= nil) and string.len(input) or 0
@@ -151,4 +172,14 @@ describe('shell functions', function()
eq(nil, argv[3])
end)
end)
+
+ itp('shell_argv_to_str', function()
+ eq('', shell_argv_to_str({ nil }))
+ eq("''", shell_argv_to_str({ '' }))
+ eq("'foo' '' 'bar'", shell_argv_to_str({ 'foo', '', 'bar' }))
+ eq("'/bin/sh' '-c' 'abc def'", shell_argv_to_str({'/bin/sh', '-c', 'abc def'}))
+ eq("'abc def' 'ghi jkl'", shell_argv_to_str({'abc def', 'ghi jkl'}))
+ eq("'/bin/sh' '-c' 'abc def' '"..('x'):rep(225).."...",
+ shell_argv_to_str({'/bin/sh', '-c', 'abc def', ('x'):rep(999)}))
+ end)
end)