aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /test/functional
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-usermarks.tar.gz
rneovim-usermarks.tar.bz2
rneovim-usermarks.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/api/autocmd_spec.lua26
-rw-r--r--test/functional/api/buffer_spec.lua43
-rw-r--r--test/functional/api/buffer_updates_spec.lua2
-rw-r--r--test/functional/api/command_spec.lua107
-rw-r--r--test/functional/api/extmark_spec.lua22
-rw-r--r--test/functional/api/highlight_spec.lua41
-rw-r--r--test/functional/api/keymap_spec.lua46
-rw-r--r--test/functional/api/proc_spec.lua14
-rw-r--r--test/functional/api/server_notifications_spec.lua22
-rw-r--r--test/functional/api/server_requests_spec.lua2
-rw-r--r--test/functional/api/vim_spec.lua317
-rw-r--r--test/functional/api/window_spec.lua183
-rw-r--r--test/functional/autocmd/autocmd_spec.lua42
-rw-r--r--test/functional/autocmd/cmdline_spec.lua35
-rw-r--r--test/functional/autocmd/cursorhold_spec.lua74
-rw-r--r--test/functional/autocmd/dirchanged_spec.lua28
-rw-r--r--test/functional/autocmd/focus_spec.lua25
-rw-r--r--test/functional/autocmd/signal_spec.lua7
-rw-r--r--test/functional/autocmd/termxx_spec.lua13
-rw-r--r--test/functional/autocmd/win_scrolled_resized_spec.lua329
-rw-r--r--test/functional/autocmd/winscrolled_spec.lua85
-rw-r--r--test/functional/core/channels_spec.lua9
-rw-r--r--test/functional/core/exit_spec.lua6
-rw-r--r--test/functional/core/fileio_spec.lua132
-rw-r--r--test/functional/core/job_spec.lua49
-rw-r--r--test/functional/core/log_spec.lua9
-rw-r--r--test/functional/core/main_spec.lua6
-rw-r--r--test/functional/core/path_spec.lua18
-rw-r--r--test/functional/core/remote_spec.lua9
-rw-r--r--test/functional/core/startup_spec.lua307
-rw-r--r--test/functional/editor/K_spec.lua11
-rw-r--r--test/functional/editor/completion_spec.lua49
-rw-r--r--test/functional/editor/mark_spec.lua38
-rw-r--r--test/functional/editor/mode_insert_spec.lua8
-rw-r--r--test/functional/editor/tabpage_spec.lua48
-rw-r--r--test/functional/editor/undo_spec.lua75
-rw-r--r--test/functional/ex_cmds/cd_spec.lua6
-rw-r--r--test/functional/ex_cmds/dict_notifications_spec.lua63
-rw-r--r--test/functional/ex_cmds/map_spec.lua15
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua12
-rw-r--r--test/functional/ex_cmds/normal_spec.lua17
-rw-r--r--test/functional/ex_cmds/quickfix_commands_spec.lua21
-rw-r--r--test/functional/ex_cmds/quit_spec.lua2
-rw-r--r--test/functional/ex_cmds/source_spec.lua12
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua201
-rw-r--r--test/functional/ex_cmds/trust_spec.lua176
-rw-r--r--test/functional/ex_cmds/verbose_spec.lua4
-rw-r--r--test/functional/ex_cmds/write_spec.lua46
-rw-r--r--test/functional/ex_cmds/wviminfo_spec.lua4
-rw-r--r--test/functional/fixtures/CMakeLists.txt23
-rw-r--r--test/functional/fixtures/api_level_10.mpackbin0 -> 30761 bytes
-rw-r--r--test/functional/fixtures/filename_with_unicode_ααα0
-rw-r--r--test/functional/fixtures/printenv-test.c6
-rw-r--r--test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua4
-rw-r--r--test/functional/fixtures/startup-fail.lua7
-rw-r--r--test/functional/fixtures/startup.lua35
-rw-r--r--test/functional/fixtures/tty-test.c18
-rw-r--r--test/functional/helpers.lua262
-rw-r--r--test/functional/legacy/006_argument_list_spec.lua85
-rw-r--r--test/functional/legacy/011_autocommands_spec.lua4
-rw-r--r--test/functional/legacy/025_jump_tag_hidden_spec.lua6
-rw-r--r--test/functional/legacy/030_fileformats_spec.lua2
-rw-r--r--test/functional/legacy/045_folding_spec.lua214
-rw-r--r--test/functional/legacy/055_list_and_dict_types_spec.lua234
-rw-r--r--test/functional/legacy/063_match_and_matchadd_spec.lua100
-rw-r--r--test/functional/legacy/072_undo_file_spec.lua2
-rw-r--r--test/functional/legacy/083_tag_search_with_file_encoding_spec.lua2
-rw-r--r--test/functional/legacy/097_glob_path_spec.lua6
-rw-r--r--test/functional/legacy/arglist_spec.lua228
-rw-r--r--test/functional/legacy/autocmd_option_spec.lua6
-rw-r--r--test/functional/legacy/breakindent_spec.lua44
-rw-r--r--test/functional/legacy/buffer_spec.lua59
-rw-r--r--test/functional/legacy/cmdline_spec.lua183
-rw-r--r--test/functional/legacy/delete_spec.lua2
-rw-r--r--test/functional/legacy/digraph_spec.lua46
-rw-r--r--test/functional/legacy/display_spec.lua148
-rw-r--r--test/functional/legacy/edit_spec.lua64
-rw-r--r--test/functional/legacy/eval_spec.lua2
-rw-r--r--test/functional/legacy/excmd_spec.lua8
-rw-r--r--test/functional/legacy/filechanged_spec.lua4
-rw-r--r--test/functional/legacy/fold_spec.lua335
-rw-r--r--test/functional/legacy/gf_spec.lua3
-rw-r--r--test/functional/legacy/increment_spec.lua2
-rw-r--r--test/functional/legacy/listlbr_spec.lua96
-rw-r--r--test/functional/legacy/match_spec.lua126
-rw-r--r--test/functional/legacy/memory_usage_spec.lua19
-rw-r--r--test/functional/legacy/messages_spec.lua189
-rw-r--r--test/functional/legacy/search_spec.lua73
-rw-r--r--test/functional/legacy/search_stat_spec.lua4
-rw-r--r--test/functional/legacy/source_spec.lua32
-rw-r--r--test/functional/legacy/statusline_spec.lua83
-rw-r--r--test/functional/legacy/substitute_spec.lua (renamed from test/functional/legacy/080_substitute_spec.lua)31
-rw-r--r--test/functional/legacy/syn_attr_spec.lua78
-rw-r--r--test/functional/legacy/tabline_spec.lua100
-rw-r--r--test/functional/legacy/vimscript_spec.lua90
-rw-r--r--test/functional/legacy/visual_mode_spec.lua25
-rw-r--r--test/functional/legacy/window_cmd_spec.lua227
-rw-r--r--test/functional/lua/api_spec.lua2
-rw-r--r--test/functional/lua/buffer_updates_spec.lua20
-rw-r--r--test/functional/lua/diagnostic_spec.lua199
-rw-r--r--test/functional/lua/ffi_spec.lua19
-rw-r--r--test/functional/lua/filetype_spec.lua8
-rw-r--r--test/functional/lua/fs_spec.lua181
-rw-r--r--test/functional/lua/help_spec.lua50
-rw-r--r--test/functional/lua/inspector_spec.lua56
-rw-r--r--test/functional/lua/overrides_spec.lua4
-rw-r--r--test/functional/lua/runtime_spec.lua56
-rw-r--r--test/functional/lua/secure_spec.lua284
-rw-r--r--test/functional/lua/spell_spec.lua2
-rw-r--r--test/functional/lua/thread_spec.lua2
-rw-r--r--test/functional/lua/ui_event_spec.lua147
-rw-r--r--test/functional/lua/ui_spec.lua46
-rw-r--r--test/functional/lua/uri_spec.lua18
-rw-r--r--test/functional/lua/vim_spec.lua264
-rw-r--r--test/functional/lua/xdiff_spec.lua18
-rw-r--r--test/functional/options/autochdir_spec.lua2
-rw-r--r--test/functional/options/defaults_spec.lua99
-rw-r--r--test/functional/options/keymap_spec.lua2
-rw-r--r--test/functional/options/mousescroll_spec.lua18
-rw-r--r--test/functional/plugin/ccomplete_spec.lua61
-rw-r--r--test/functional/plugin/cfilter_spec.lua106
-rw-r--r--test/functional/plugin/editorconfig_spec.lua210
-rw-r--r--test/functional/plugin/health_spec.lua178
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua35
-rw-r--r--test/functional/plugin/lsp/helpers.lua176
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua1219
-rw-r--r--test/functional/plugin/lsp_spec.lua626
-rw-r--r--test/functional/plugin/man_spec.lua38
-rw-r--r--test/functional/plugin/shada_spec.lua73
-rw-r--r--test/functional/preload.lua5
-rw-r--r--test/functional/provider/clipboard_spec.lua64
-rw-r--r--test/functional/provider/perl_spec.lua6
-rw-r--r--test/functional/shada/compatibility_spec.lua2
-rw-r--r--test/functional/shada/merging_spec.lua2
-rw-r--r--test/functional/shada/shada_spec.lua13
-rw-r--r--test/functional/terminal/altscreen_spec.lua12
-rw-r--r--test/functional/terminal/api_spec.lua13
-rw-r--r--test/functional/terminal/buffer_spec.lua20
-rw-r--r--test/functional/terminal/channel_spec.lua15
-rw-r--r--test/functional/terminal/cursor_spec.lua12
-rw-r--r--test/functional/terminal/edit_spec.lua2
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua26
-rw-r--r--test/functional/terminal/helpers.lua34
-rw-r--r--test/functional/terminal/highlight_spec.lua20
-rw-r--r--test/functional/terminal/mouse_spec.lua44
-rw-r--r--test/functional/terminal/scrollback_spec.lua29
-rw-r--r--test/functional/terminal/tui_spec.lua781
-rw-r--r--test/functional/terminal/window_spec.lua15
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua4
-rw-r--r--test/functional/treesitter/highlight_spec.lua126
-rw-r--r--test/functional/treesitter/language_spec.lua46
-rw-r--r--test/functional/treesitter/node_spec.lua54
-rw-r--r--test/functional/treesitter/parser_spec.lua9
-rw-r--r--test/functional/treesitter/utils_spec.lua31
-rw-r--r--test/functional/ui/bufhl_spec.lua2
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua20
-rw-r--r--test/functional/ui/cmdline_spec.lua422
-rw-r--r--test/functional/ui/cursor_spec.lua2
-rw-r--r--test/functional/ui/decorations_spec.lua401
-rw-r--r--test/functional/ui/diff_spec.lua198
-rw-r--r--test/functional/ui/embed_spec.lua16
-rw-r--r--test/functional/ui/float_spec.lua875
-rw-r--r--test/functional/ui/fold_spec.lua189
-rw-r--r--test/functional/ui/highlight_spec.lua163
-rw-r--r--test/functional/ui/hlstate_spec.lua9
-rw-r--r--test/functional/ui/inccommand_spec.lua92
-rw-r--r--test/functional/ui/inccommand_user_spec.lua2
-rw-r--r--test/functional/ui/linematch_spec.lua995
-rw-r--r--test/functional/ui/messages_spec.lua147
-rw-r--r--test/functional/ui/mode_spec.lua20
-rw-r--r--test/functional/ui/mouse_spec.lua284
-rw-r--r--test/functional/ui/multigrid_spec.lua100
-rw-r--r--test/functional/ui/options_spec.lua10
-rw-r--r--test/functional/ui/output_spec.lua21
-rw-r--r--test/functional/ui/popupmenu_spec.lua993
-rw-r--r--test/functional/ui/screen.lua22
-rw-r--r--test/functional/ui/screen_basic_spec.lua127
-rw-r--r--test/functional/ui/searchhl_spec.lua22
-rw-r--r--test/functional/ui/sign_spec.lua97
-rw-r--r--test/functional/ui/spell_spec.lua101
-rw-r--r--test/functional/ui/statuscolumn_spec.lua462
-rw-r--r--test/functional/ui/statusline_spec.lua145
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua85
-rw-r--r--test/functional/ui/tabline_spec.lua42
-rw-r--r--test/functional/ui/wildmode_spec.lua106
-rw-r--r--test/functional/ui/winbar_spec.lua7
-rw-r--r--test/functional/vimscript/api_functions_spec.lua3
-rw-r--r--test/functional/vimscript/container_functions_spec.lua2
-rw-r--r--test/functional/vimscript/ctx_functions_spec.lua12
-rw-r--r--test/functional/vimscript/eval_spec.lua80
-rw-r--r--test/functional/vimscript/executable_spec.lua28
-rw-r--r--test/functional/vimscript/execute_spec.lua4
-rw-r--r--test/functional/vimscript/exepath_spec.lua19
-rw-r--r--test/functional/vimscript/fnamemodify_spec.lua6
-rw-r--r--test/functional/vimscript/functions_spec.lua4
-rw-r--r--test/functional/vimscript/has_spec.lua4
-rw-r--r--test/functional/vimscript/hostname_spec.lua6
-rw-r--r--test/functional/vimscript/input_spec.lua77
-rw-r--r--test/functional/vimscript/json_functions_spec.lua2
-rw-r--r--test/functional/vimscript/map_functions_spec.lua69
-rw-r--r--test/functional/vimscript/msgpack_functions_spec.lua4
-rw-r--r--test/functional/vimscript/null_spec.lua2
-rw-r--r--test/functional/vimscript/server_spec.lua30
-rw-r--r--test/functional/vimscript/system_spec.lua65
-rw-r--r--test/functional/vimscript/timer_spec.lua12
-rw-r--r--test/functional/vimscript/writefile_spec.lua20
206 files changed, 15373 insertions, 2990 deletions
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index a923f5df0e..22a1311ee9 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -14,14 +14,14 @@ before_each(clear)
describe('autocmd api', function()
describe('nvim_create_autocmd', function()
- it('does not allow "command" and "callback" in the same autocmd', function()
- local ok, _ = pcall(meths.create_autocmd, "BufReadPost", {
+ it('"command" and "callback" are mutually exclusive', function()
+ local rv = pcall_err(meths.create_autocmd, "BufReadPost", {
pattern = "*.py,*.pyi",
command = "echo 'Should Have Errored",
- callback = "not allowed",
+ callback = "NotAllowed",
})
- eq(false, ok)
+ eq("specify either 'callback' or 'command', not both", rv)
end)
it('doesnt leak when you use ++once', function()
@@ -60,13 +60,13 @@ describe('autocmd api', function()
end)
it('does not allow passing buffer and patterns', function()
- local ok = pcall(meths.create_autocmd, "Filetype", {
+ local rv = pcall_err(meths.create_autocmd, "Filetype", {
command = "let g:called = g:called + 1",
buffer = 0,
pattern = "*.py",
})
- eq(false, ok)
+ eq("cannot pass both: 'pattern' and 'buffer' for the same autocmd", rv)
end)
it('does not allow passing invalid buffers', function()
@@ -613,6 +613,20 @@ describe('autocmd api', function()
eq(false, success)
matches("'group' must be a string or an integer", code)
end)
+
+ it('raises error for invalid pattern array', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = {{}},
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches("All entries in 'pattern' must be strings", code)
+ end)
end)
describe('patterns', function()
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 8f6fc666c9..6b13729994 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, nvim, buffer = helpers.clear, helpers.nvim, helpers.buffer
local curbuf, curwin, eq = helpers.curbuf, helpers.curwin, helpers.eq
local curbufmeths, ok = helpers.curbufmeths, helpers.ok
+local describe_lua_and_rpc = helpers.describe_lua_and_rpc(describe)
local meths = helpers.meths
local funcs = helpers.funcs
local request = helpers.request
@@ -185,12 +186,13 @@ describe('api/buf', function()
end)
end)
- describe('nvim_buf_get_lines, nvim_buf_set_lines', function()
- local get_lines, set_lines = curbufmeths.get_lines, curbufmeths.set_lines
- local line_count = curbufmeths.line_count
+ describe_lua_and_rpc('nvim_buf_get_lines, nvim_buf_set_lines', function(api)
+ local get_lines = api.curbufmeths.get_lines
+ local set_lines = api.curbufmeths.set_lines
+ local line_count = api.curbufmeths.line_count
it('fails correctly when input is not valid', function()
- eq(1, curbufmeths.get_number())
+ eq(1, api.curbufmeths.get_number())
eq([[String cannot contain newlines]],
pcall_err(bufmeths.set_lines, 1, 1, 2, false, {'b\na'}))
end)
@@ -198,7 +200,7 @@ describe('api/buf', function()
it("fails if 'nomodifiable'", function()
command('set nomodifiable')
eq([[Buffer is not 'modifiable']],
- pcall_err(bufmeths.set_lines, 1, 1, 2, false, {'a','b'}))
+ pcall_err(api.bufmeths.set_lines, 1, 1, 2, false, {'a','b'}))
end)
it('has correct line_count when inserting and deleting', function()
@@ -354,7 +356,7 @@ describe('api/buf', function()
Who would win?
A real window
with proper text]])
- local buf = meths.create_buf(false,true)
+ local buf = api.meths.create_buf(false,true)
screen:expect([[
Who would win? |
A real window |
@@ -363,7 +365,7 @@ describe('api/buf', function()
|
]])
- meths.buf_set_lines(buf, 0, -1, true, {'or some', 'scratchy text'})
+ api.meths.buf_set_lines(buf, 0, -1, true, {'or some', 'scratchy text'})
feed('i') -- provoke redraw
screen:expect([[
Who would win? |
@@ -379,15 +381,15 @@ describe('api/buf', function()
visible buffer line 1
line 2
]])
- local hiddenbuf = meths.create_buf(false,true)
+ local hiddenbuf = api.meths.create_buf(false,true)
command('vsplit')
command('vsplit')
feed('<c-w>l<c-w>l<c-w>l')
eq(3, funcs.winnr())
feed('<c-w>h')
eq(2, funcs.winnr())
- meths.buf_set_lines(hiddenbuf, 0, -1, true,
- {'hidden buffer line 1', 'line 2'})
+ api.meths.buf_set_lines(hiddenbuf, 0, -1, true,
+ {'hidden buffer line 1', 'line 2'})
feed('<c-w>p')
eq(3, funcs.winnr())
end)
@@ -579,13 +581,13 @@ describe('api/buf', function()
end)
end)
- describe('nvim_buf_get_text', function()
- local get_text = curbufmeths.get_text
-
+ describe_lua_and_rpc('nvim_buf_get_text', function(api)
+ local get_text = api.curbufmeths.get_text
before_each(function()
insert([[
hello foo!
- text]])
+ text
+ more]])
end)
it('works', function()
@@ -593,16 +595,17 @@ describe('api/buf', function()
eq({'hello foo!'}, get_text(0, 0, 0, 42, {}))
eq({'foo!'}, get_text(0, 6, 0, 10, {}))
eq({'foo!', 'tex'}, get_text(0, 6, 1, 3, {}))
- eq({'foo!', 'tex'}, get_text(-2, 6, -1, 3, {}))
+ eq({'foo!', 'tex'}, get_text(-3, 6, -2, 3, {}))
eq({''}, get_text(0, 18, 0, 20, {}))
- eq({'ext'}, get_text(-1, 1, -1, 4, {}))
+ eq({'ext'}, get_text(-2, 1, -2, 4, {}))
+ eq({'hello foo!', 'text', 'm'}, get_text(0, 0, 2, 1, {}))
end)
it('errors on out-of-range', function()
- eq('Index out of bounds', pcall_err(get_text, 2, 0, 3, 0, {}))
- eq('Index out of bounds', pcall_err(get_text, -3, 0, 0, 0, {}))
- eq('Index out of bounds', pcall_err(get_text, 0, 0, 2, 0, {}))
- eq('Index out of bounds', pcall_err(get_text, 0, 0, -3, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, 2, 0, 4, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, -4, 0, 0, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, 0, 0, 3, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, 0, 0, -4, 0, {}))
-- no ml_get errors should happen #19017
eq('', meths.get_vvar('errmsg'))
end)
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index 3d257e9477..d5f06c8f1f 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -810,7 +810,7 @@ describe('API: buffer events:', function()
local newlines = args[5]
-- Size of the contained nvim instance is 23 lines, this might change
- -- with the test setup. Note updates are continguous.
+ -- with the test setup. Note updates are contiguous.
assert(#newlines <= 23)
for i = 1,#newlines do
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index 890710b6e6..d0fb26edc7 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -114,8 +114,9 @@ describe('nvim_create_user_command', function()
]]
eq({
- args = [[this is a\ test]],
- fargs = {"this", "is", "a test"},
+ name = "CommandWithLuaCallback",
+ args = [[this\ is a\ test]],
+ fargs = {"this ", "is", "a test"},
bang = false,
line1 = 1,
line2 = 1,
@@ -125,6 +126,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -135,7 +137,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -144,11 +146,12 @@ describe('nvim_create_user_command', function()
count = 2,
reg = "",
}, exec_lua [=[
- vim.api.nvim_command([[CommandWithLuaCallback this is a\ test]])
+ vim.api.nvim_command([[CommandWithLuaCallback this\ is a\ test]])
return result
]=])
eq({
+ name = "CommandWithLuaCallback",
args = [[this includes\ a backslash: \\]],
fargs = {"this", "includes a", "backslash:", "\\"},
bang = false,
@@ -160,6 +163,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -170,7 +174,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -184,6 +188,7 @@ describe('nvim_create_user_command', function()
]=])
eq({
+ name = "CommandWithLuaCallback",
args = "a\\b",
fargs = {"a\\b"},
bang = false,
@@ -195,6 +200,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -205,7 +211,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -219,17 +225,19 @@ describe('nvim_create_user_command', function()
]=])
eq({
+ name = "CommandWithLuaCallback",
args = 'h\tey ',
fargs = {[[h]], [[ey]]},
bang = true,
line1 = 10,
line2 = 10,
- mods = "confirm unsilent botright",
+ mods = "confirm unsilent botright horizontal",
smods = {
browse = false,
confirm = true,
emsg_silent = false,
hide = false,
+ horizontal = true,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -240,7 +248,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "botright",
- tab = 0,
+ tab = -1,
unsilent = true,
verbose = -1,
vertical = false,
@@ -249,11 +257,12 @@ describe('nvim_create_user_command', function()
count = 10,
reg = "",
}, exec_lua [=[
- vim.api.nvim_command('unsilent botright confirm 10CommandWithLuaCallback! h\tey ')
+ vim.api.nvim_command('unsilent horizontal botright confirm 10CommandWithLuaCallback! h\tey ')
return result
]=])
eq({
+ name = "CommandWithLuaCallback",
args = "h",
fargs = {"h"},
bang = false,
@@ -265,6 +274,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -275,7 +285,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -289,6 +299,7 @@ describe('nvim_create_user_command', function()
]])
eq({
+ name = "CommandWithLuaCallback",
args = "",
fargs = {}, -- fargs works without args
bang = false,
@@ -300,6 +311,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -310,7 +322,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -336,6 +348,7 @@ describe('nvim_create_user_command', function()
]]
eq({
+ name = "CommandWithOneOrNoArg",
args = "hello I'm one argument",
fargs = {"hello I'm one argument"}, -- Doesn't split args
bang = false,
@@ -347,6 +360,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -357,7 +371,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -372,6 +386,7 @@ describe('nvim_create_user_command', function()
-- f-args is an empty table if no args were passed
eq({
+ name = "CommandWithOneOrNoArg",
args = "",
fargs = {},
bang = false,
@@ -383,6 +398,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -393,7 +409,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -415,9 +431,11 @@ describe('nvim_create_user_command', function()
nargs = 0,
bang = true,
count = 2,
+ register = true,
})
]]
eq({
+ name = "CommandWithNoArgs",
args = "",
fargs = {},
bang = false,
@@ -429,6 +447,7 @@ describe('nvim_create_user_command', function()
confirm = false,
emsg_silent = false,
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -439,7 +458,7 @@ describe('nvim_create_user_command', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -451,6 +470,43 @@ describe('nvim_create_user_command', function()
vim.cmd('CommandWithNoArgs')
return result
]])
+ -- register can be specified
+ eq({
+ name = "CommandWithNoArgs",
+ args = "",
+ fargs = {},
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ horizontal = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = -1,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
+ range = 0,
+ count = 2,
+ reg = "+",
+ }, exec_lua [[
+ vim.cmd('CommandWithNoArgs +')
+ return result
+ ]])
end)
@@ -514,8 +570,29 @@ describe('nvim_create_user_command', function()
vim.api.nvim_cmd({ cmd = 'echo', args = { '&verbose' }, mods = opts.smods }, {})
end, {})
]]
-
eq("3", meths.cmd({ cmd = 'MyEcho', mods = { verbose = 3 } }, { output = true }))
+
+ eq(1, #meths.list_tabpages())
+ exec_lua[[
+ vim.api.nvim_create_user_command('MySplit', function(opts)
+ vim.api.nvim_cmd({ cmd = 'split', mods = opts.smods }, {})
+ end, {})
+ ]]
+ meths.cmd({ cmd = 'MySplit' }, {})
+ eq(1, #meths.list_tabpages())
+ eq(2, #meths.list_wins())
+ meths.cmd({ cmd = 'MySplit', mods = { tab = 1 } }, {})
+ eq(2, #meths.list_tabpages())
+ eq(2, funcs.tabpagenr())
+ meths.cmd({ cmd = 'MySplit', mods = { tab = 1 } }, {})
+ eq(3, #meths.list_tabpages())
+ eq(2, funcs.tabpagenr())
+ meths.cmd({ cmd = 'MySplit', mods = { tab = 3 } }, {})
+ eq(4, #meths.list_tabpages())
+ eq(4, funcs.tabpagenr())
+ meths.cmd({ cmd = 'MySplit', mods = { tab = 0 } }, {})
+ eq(5, #meths.list_tabpages())
+ eq(1, funcs.tabpagenr())
end)
end)
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index bc8d811c6d..00f5b25b8a 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -1046,7 +1046,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[3], 0, 4, 0, 8)
end)
- it('substitions over multiple lines with newline in pattern', function()
+ it('substitutes over multiple lines with newline in pattern', function()
feed('A<cr>67890<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 3)
set_extmark(ns, marks[2], 0, 4)
@@ -1078,7 +1078,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[6], 1, 2, 0, 5)
end)
- it('substitions with multiple newlines in pattern', function()
+ it('substitutes with multiple newlines in pattern', function()
feed('A<cr>67890<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 4)
set_extmark(ns, marks[2], 0, 5)
@@ -1093,7 +1093,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[5], 2, 0, 0, 6)
end)
- it('substitions over multiple lines with replace in substition', function()
+ it('substitutes over multiple lines with replace in substitution', function()
feed('A<cr>67890<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 1)
set_extmark(ns, marks[2], 0, 2)
@@ -1111,7 +1111,7 @@ describe('API/extmarks', function()
eq({1, 3}, get_extmark_by_id(ns, marks[3]))
end)
- it('substitions over multiple lines with replace in substition', function()
+ it('substitutes over multiple lines with replace in substitution', function()
feed('A<cr>x3<cr>xx<esc>')
set_extmark(ns, marks[1], 1, 0)
set_extmark(ns, marks[2], 1, 1)
@@ -1122,7 +1122,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[3], 1, 2, 2, 0)
end)
- it('substitions over multiple lines with replace in substition', function()
+ it('substitutes over multiple lines with replace in substitution', function()
feed('A<cr>x3<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 1)
set_extmark(ns, marks[2], 0, 2)
@@ -1140,7 +1140,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[3], 0, 4, 1, 3)
end)
- it('substitions with newline in match and sub, delta is 0', function()
+ it('substitutes with newline in match and sub, delta is 0', function()
feed('A<cr>67890<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 3)
set_extmark(ns, marks[2], 0, 4)
@@ -1157,7 +1157,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[6], 2, 0, 2, 0)
end)
- it('substitions with newline in match and sub, delta > 0', function()
+ it('substitutes with newline in match and sub, delta > 0', function()
feed('A<cr>67890<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 3)
set_extmark(ns, marks[2], 0, 4)
@@ -1174,7 +1174,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[6], 2, 0, 3, 0)
end)
- it('substitions with newline in match and sub, delta < 0', function()
+ it('substitutes with newline in match and sub, delta < 0', function()
feed('A<cr>67890<cr>xx<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 3)
set_extmark(ns, marks[2], 0, 4)
@@ -1193,7 +1193,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[7], 3, 0, 2, 0)
end)
- it('substitions with backrefs, newline inserted into sub', function()
+ it('substitutes with backrefs, newline inserted into sub', function()
feed('A<cr>67890<cr>xx<cr>xx<esc>')
set_extmark(ns, marks[1], 0, 3)
set_extmark(ns, marks[2], 0, 4)
@@ -1210,7 +1210,7 @@ describe('API/extmarks', function()
check_undo_redo(ns, marks[6], 2, 0, 3, 0)
end)
- it('substitions a ^', function()
+ it('substitutes a ^', function()
set_extmark(ns, marks[1], 0, 0)
set_extmark(ns, marks[2], 0, 1)
feed([[:s:^:x<cr>]])
@@ -1397,7 +1397,7 @@ describe('API/extmarks', function()
eq({{id, 1, 0}}, bufmeths.get_extmarks(buf, ns, 0, -1, {}))
end)
- it('does not crash with append/delete/undo seqence', function()
+ it('does not crash with append/delete/undo sequence', function()
meths.exec([[
let ns = nvim_create_namespace('myplugin')
call nvim_buf_set_extmark(0, ns, 0, 0, {})
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 2730f7e23d..5941d4c68b 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -11,6 +11,9 @@ local ok = helpers.ok
local assert_alive = helpers.assert_alive
describe('API: highlight',function()
+ clear()
+ Screen.new() -- initialize Screen.colors
+
local expected_rgb = {
background = Screen.colors.Yellow,
foreground = Screen.colors.Red,
@@ -29,13 +32,16 @@ describe('API: highlight',function()
italic = true,
reverse = true,
underline = true,
- undercurl = true,
- underdouble = true,
- underdotted = true,
- underdashed = true,
strikethrough = true,
+ altfont = true,
nocombine = true,
}
+ local expected_undercurl = {
+ background = Screen.colors.Yellow,
+ foreground = Screen.colors.Red,
+ special = Screen.colors.Blue,
+ undercurl = true,
+ }
before_each(function()
clear()
@@ -56,9 +62,13 @@ describe('API: highlight',function()
eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
-- Test all highlight properties.
- command('hi NewHighlight gui=underline,bold,undercurl,underdouble,underdotted,underdashed,italic,reverse,strikethrough,nocombine')
+ command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine')
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
+ -- Test undercurl
+ command('hi NewHighlight gui=undercurl')
+ eq(expected_undercurl, nvim("get_hl_by_id", hl_id, true))
+
-- Test nil argument.
err, emsg = pcall(meths.get_hl_by_id, { nil }, false)
eq(false, err)
@@ -204,17 +214,14 @@ describe("API: set highlight", function()
bold = true,
italic = true,
reverse = true,
- undercurl = true,
underline = true,
- underdashed = true,
- underdotted = true,
- underdouble = true,
strikethrough = true,
+ altfont = true,
cterm = {
italic = true,
reverse = true,
- undercurl = true,
strikethrough = true,
+ altfont = true,
nocombine = true,
}
}
@@ -224,20 +231,17 @@ describe("API: set highlight", function()
bold = true,
italic = true,
reverse = true,
- undercurl = true,
underline = true,
- underdashed = true,
- underdotted = true,
- underdouble = true,
strikethrough = true,
+ altfont = true,
}
local highlight3_result_cterm = {
background = highlight_color.ctermbg,
foreground = highlight_color.ctermfg,
italic = true,
reverse = true,
- undercurl = true,
strikethrough = true,
+ altfont = true,
nocombine = true,
}
@@ -293,7 +297,7 @@ describe("API: set highlight", function()
exec_capture('highlight Test_hl'))
meths.set_hl(0, 'Test_hl2', highlight3_config)
- eq('Test_hl2 xxx cterm=undercurl,italic,reverse,strikethrough,nocombine ctermfg=8 ctermbg=15 gui=bold,underline,undercurl,underdouble,underdotted,underdashed,italic,reverse,strikethrough guifg=#ff0000 guibg=#0032aa',
+ eq('Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underline,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa',
exec_capture('highlight Test_hl2'))
-- Colors are stored with the name they are defined, but
@@ -354,4 +358,9 @@ describe("API: set highlight", function()
meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'})
eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true))
end)
+
+ it('does not segfault on invalid group name #20009', function()
+ eq('Invalid highlight name: foo bar', pcall_err(meths.set_hl, 0, 'foo bar', {bold = true}))
+ assert_alive()
+ end)
end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index a93a4544ff..5be4425162 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -6,6 +6,7 @@ local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq, neq = helpers.eq, helpers.neq
local exec_lua = helpers.exec_lua
+local exec = helpers.exec
local feed = helpers.feed
local funcs = helpers.funcs
local meths = helpers.meths
@@ -336,21 +337,26 @@ describe('nvim_get_keymap', function()
end)
it('can handle lua mappings', function()
- eq(0, exec_lua [[
+ eq(0, exec_lua([[
GlobalCount = 0
- vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
return GlobalCount
- ]])
+ ]]))
feed('asdf\n')
- eq(1, exec_lua[[return GlobalCount]])
+ eq(1, exec_lua([[return GlobalCount]]))
- eq(2, exec_lua[[
+ eq(2, exec_lua([[
vim.api.nvim_get_keymap('n')[1].callback()
return GlobalCount
+ ]]))
+
+ exec([[
+ call nvim_get_keymap('n')[0].callback()
]])
+ eq(3, exec_lua([[return GlobalCount]]))
+
local mapargs = meths.get_keymap('n')
- assert(type(mapargs[1].callback) == 'number', 'callback is not luaref number')
mapargs[1].callback = nil
eq({
lhs='asdf',
@@ -834,17 +840,29 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end)
it ('maparg() returns lua mapping correctly', function()
- exec_lua [[
- vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
- ]]
- assert.truthy(string.match(funcs.maparg('asdf', 'n'),
- "^<Lua %d+>"))
+ eq(0, exec_lua([[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]]))
+
+ assert.truthy(string.match(funcs.maparg('asdf', 'n'), "^<Lua %d+>"))
+
local mapargs = funcs.maparg('asdf', 'n', false, true)
- assert(type(mapargs.callback) == 'number', 'callback is not luaref number')
mapargs.callback = nil
mapargs.lhsraw = nil
mapargs.lhsrawalt = nil
eq(generate_mapargs('n', 'asdf', nil, {sid=sid_lua}), mapargs)
+
+ eq(1, exec_lua([[
+ vim.fn.maparg('asdf', 'n', false, true).callback()
+ return GlobalCount
+ ]]))
+
+ exec([[
+ call maparg('asdf', 'n', v:false, v:true).callback()
+ ]])
+ eq(2, exec_lua([[return GlobalCount]]))
end)
it('can make lua expr mappings replacing keycodes', function()
@@ -867,7 +885,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq({'<space>'}, meths.buf_get_lines(0, 0, -1, false))
end)
- it('lua expr mapping returning nil is equivalent to returnig an empty string', function()
+ it('lua expr mapping returning nil is equivalent to returning an empty string', function()
exec_lua [[
vim.api.nvim_set_keymap ('i', 'aa', '', {callback = function() return nil end, expr = true })
]]
@@ -1048,7 +1066,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1))
end)
- it("does not crash when setting keymap in a non-existing buffer #13541", function()
+ it("does not crash when setting mapping in a non-existing buffer #13541", function()
pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
helpers.assert_alive()
end)
diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua
index 0fbf58a8e7..2028a8fba5 100644
--- a/test/functional/api/proc_spec.lua
+++ b/test/functional/api/proc_spec.lua
@@ -3,12 +3,12 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local funcs = helpers.funcs
-local iswin = helpers.iswin
local neq = helpers.neq
local nvim_argv = helpers.nvim_argv
local request = helpers.request
local retry = helpers.retry
local NIL = helpers.NIL
+local is_os = helpers.is_os
describe('API', function()
before_each(clear)
@@ -19,26 +19,26 @@ describe('API', function()
-- Might be non-zero already (left-over from some other test?),
-- but this is not what is tested here.
- local initial_childs = request('nvim_get_proc_children', this_pid)
+ local initial_children = request('nvim_get_proc_children', this_pid)
local job1 = funcs.jobstart(nvim_argv)
retry(nil, nil, function()
- eq(#initial_childs + 1, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_children + 1, #request('nvim_get_proc_children', this_pid))
end)
local job2 = funcs.jobstart(nvim_argv)
retry(nil, nil, function()
- eq(#initial_childs + 2, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_children + 2, #request('nvim_get_proc_children', this_pid))
end)
funcs.jobstop(job1)
retry(nil, nil, function()
- eq(#initial_childs + 1, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_children + 1, #request('nvim_get_proc_children', this_pid))
end)
funcs.jobstop(job2)
retry(nil, nil, function()
- eq(#initial_childs, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_children, #request('nvim_get_proc_children', this_pid))
end)
end)
@@ -62,7 +62,7 @@ describe('API', function()
it('returns process info', function()
local pid = funcs.getpid()
local pinfo = request('nvim_get_proc', pid)
- eq((iswin() and 'nvim.exe' or 'nvim'), pinfo.name)
+ eq((is_os('win') and 'nvim.exe' or 'nvim'), pinfo.name)
eq(pid, pinfo.pid)
eq('number', type(pinfo.ppid))
neq(pid, pinfo.ppid)
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 1c00f001ff..53642858b2 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -1,12 +1,16 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_log = helpers.assert_log
local eq, clear, eval, command, nvim, next_msg =
helpers.eq, helpers.clear, helpers.eval, helpers.command, helpers.nvim,
helpers.next_msg
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local retry = helpers.retry
-local isCI = helpers.isCI
+local is_ci = helpers.is_ci
local assert_alive = helpers.assert_alive
+local skip = helpers.skip
+
+local testlog = 'Xtest-server-notify-log'
describe('notify', function()
local channel
@@ -16,6 +20,10 @@ describe('notify', function()
channel = nvim('get_api_info')[1]
end)
+ after_each(function()
+ os.remove(testlog)
+ end)
+
describe('passing a valid channel id', function()
it('sends the notification/args to the corresponding channel', function()
eval('rpcnotify('..channel..', "test-event", 1, 2, 3)')
@@ -71,20 +79,18 @@ describe('notify', function()
end)
it('unsubscribe non-existing event #8745', function()
+ clear{env={
+ NVIM_LOG_FILE=testlog,
+ }}
nvim('subscribe', 'event1')
nvim('unsubscribe', 'doesnotexist')
+ assert_log("tried to unsubscribe unknown event 'doesnotexist'", testlog, 10)
nvim('unsubscribe', 'event1')
assert_alive()
end)
it('cancels stale events on channel close', function()
- if isCI() then
- pending('hangs on CI #14083 #15251')
- return
- elseif helpers.skip_fragile(pending) then
- return
- end
- if helpers.pending_win32(pending) then return end
+ skip(is_ci(), 'hangs on CI #14083 #15251')
local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
local catpath = eval('exepath("cat")')
eq({id=catchan, argv={catpath}, stream='job', mode='rpc', client = {}}, exec_lua ([[
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 00a4dd041d..ceff390dc5 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -250,7 +250,7 @@ describe('server -> client', function()
pcall(funcs.jobstop, jobid)
end)
- if helpers.pending_win32(pending) then return end
+ if helpers.skip(helpers.is_os('win')) then return end
it('rpc and text stderr can be combined', function()
local status, rv = pcall(funcs.rpcrequest, jobid, 'poll')
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 72a03c409a..8fcdd9620b 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local lfs = require('lfs')
+local luv = require('luv')
local fmt = string.format
local assert_alive = helpers.assert_alive
@@ -11,9 +12,9 @@ local exec = helpers.exec
local eval = helpers.eval
local expect = helpers.expect
local funcs = helpers.funcs
-local iswin = helpers.iswin
local meths = helpers.meths
local matches = helpers.matches
+local pesc = helpers.pesc
local mkdir_p = helpers.mkdir_p
local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
local is_os = helpers.is_os
@@ -28,6 +29,7 @@ local exec_lua = helpers.exec_lua
local exc_exec = helpers.exc_exec
local insert = helpers.insert
local expect_exit = helpers.expect_exit
+local skip = helpers.skip
local pcall_err = helpers.pcall_err
local format_string = helpers.format_string
@@ -164,7 +166,7 @@ describe('API', function()
echo nvim_exec('echo Avast_ye_hades(''ahoy!'')', 1)
]], true))
- eq('Vim(call):E5555: API call: Vim(echo):E121: Undefined variable: s:pirate',
+ matches('Vim%(echo%):E121: Undefined variable: s:pirate$',
pcall_err(request, 'nvim_exec', [[
let s:pirate = 'script-scoped varrrrr'
call nvim_exec('echo s:pirate', 1)
@@ -206,12 +208,12 @@ describe('API', function()
end)
it('execution error', function()
- eq('Vim:E492: Not an editor command: bogus_command',
+ eq('nvim_exec(): Vim:E492: Not an editor command: bogus_command',
pcall_err(request, 'nvim_exec', 'bogus_command', false))
eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated.
eq('', eval('v:exception'))
- eq('Vim(buffer):E86: Buffer 23487 does not exist',
+ eq('nvim_exec(): Vim(buffer):E86: Buffer 23487 does not exist',
pcall_err(request, 'nvim_exec', 'buffer 23487', false))
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
eq('', eval('v:exception'))
@@ -397,7 +399,7 @@ describe('API', function()
end)
it('returns shell |:!| output', function()
- local win_lf = iswin() and '\r' or ''
+ local win_lf = is_os('win') and '\r' or ''
eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]]))
end)
@@ -483,7 +485,7 @@ describe('API', function()
throw 'wtf'
endfunction
]])
- eq('wtf', pcall_err(request, 'nvim_call_function', 'Foo', {}))
+ eq('function Foo, line 1: wtf', pcall_err(request, 'nvim_call_function', 'Foo', {}))
eq('', eval('v:exception'))
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
end)
@@ -602,10 +604,10 @@ describe('API', function()
eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol]],
pcall_err(meths.exec_lua, 'aa=bb\0', {}))
- eq([[Error executing lua: [string "<nvim>"]:0: attempt to call global 'bork' (a nil value)]],
+ eq([[attempt to call global 'bork' (a nil value)]],
pcall_err(meths.exec_lua, 'bork()', {}))
- eq('Error executing lua: [string "<nvim>"]:0: did\nthe\nfail',
+ eq('did\nthe\nfail',
pcall_err(meths.exec_lua, 'error("did\\nthe\\nfail")', {}))
end)
@@ -1106,6 +1108,14 @@ describe('API', function()
nvim('paste', 'a', true, -1)
eq('a', funcs.getcmdline())
end)
+ it('pasted text is saved in cmdline history when <CR> comes from mapping #20957', function()
+ command('cnoremap <CR> <CR>')
+ feed(':')
+ nvim('paste', 'echo', true, -1)
+ eq('', funcs.histget(':'))
+ feed('<CR>')
+ eq('echo', funcs.histget(':'))
+ end)
it('pasting with empty last chunk in Cmdline mode', function()
local screen = Screen.new(20, 4)
screen:attach()
@@ -1138,7 +1148,7 @@ describe('API', function()
end)
it('vim.paste() failure', function()
nvim('exec_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {})
- eq([[Error executing lua: [string "<nvim>"]:0: fake fail]],
+ eq('fake fail',
pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1))
end)
end)
@@ -1797,9 +1807,11 @@ describe('API', function()
},
['jumps'] = eval(([[
- filter(map(getjumplist()[0], 'filter(
- { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
- { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
+ filter(map(add(
+ getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
+ 'filter(
+ { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
+ { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
]]):gsub('\n', '')),
['bufs'] = eval([[
@@ -1903,11 +1915,32 @@ describe('API', function()
end)
end)
+ describe('nvim_out_write', function()
+ it('prints long messages correctly #20534', function()
+ exec([[
+ set more
+ redir => g:out
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write("\n")
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write(repeat('a', 5000) .. "\n")
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write('a')
+ silent! call nvim_out_write("\n")
+ redir END
+ ]])
+ eq('\naaa\n' .. ('a'):rep(5002) .. '\naaa', meths.get_var('out'))
+ end)
+ end)
+
describe('nvim_err_write', function()
local screen
before_each(function()
- clear()
screen = Screen.new(40, 8)
screen:attach()
screen:set_default_attr_ids({
@@ -2093,7 +2126,7 @@ describe('API', function()
pty='?',
}
local event = meths.get_var("opened_event")
- if not iswin() then
+ if not is_os('win') then
info.pty = event.info.pty
neq(nil, string.match(info.pty, "^/dev/"))
end
@@ -2109,7 +2142,7 @@ describe('API', function()
stream = 'job',
id = 4,
argv = (
- iswin() and {
+ is_os('win') and {
eval('&shell'),
'/s',
'/c',
@@ -2131,7 +2164,7 @@ describe('API', function()
-- :terminal with args + stopped process.
eq(1, eval('jobstop(&channel)'))
eval('jobwait([&channel], 1000)') -- Wait.
- expected2.pty = (iswin() and '?' or '') -- pty stream was closed.
+ expected2.pty = (is_os('win') and '?' or '') -- pty stream was closed.
eq(expected2, eval('nvim_get_chan_info(&channel)'))
end)
end)
@@ -2254,7 +2287,7 @@ describe('API', function()
eq({'a', '', 'b'}, meths.list_runtime_paths())
meths.set_option('runtimepath', ',a,b')
eq({'', 'a', 'b'}, meths.list_runtime_paths())
- -- trailing , is ignored, use ,, if you really really want $CWD
+ -- Trailing "," is ignored. Use ",," if you really really want CWD.
meths.set_option('runtimepath', 'a,b,')
eq({'a', 'b'}, meths.list_runtime_paths())
meths.set_option('runtimepath', 'a,b,,')
@@ -2292,12 +2325,6 @@ describe('API', function()
meths.set_option('isident', '')
end)
- local it_maybe_pending = it
- if helpers.isCI() and os.getenv('CONFIGURATION') == 'MSVC_32' then
- -- For "works with &opt" (flaky on MSVC_32), but not easy to skip alone. #10241
- it_maybe_pending = pending
- end
-
local function simplify_east_api_node(line, east_api_node)
if east_api_node == NIL then
return nil
@@ -2494,7 +2521,7 @@ describe('API', function()
end
end
require('test.unit.viml.expressions.parser_tests')(
- it_maybe_pending, _check_parsing, hl, fmtn)
+ it, _check_parsing, hl, fmtn)
end)
describe('nvim_list_uis', function()
@@ -2698,7 +2725,7 @@ describe('API', function()
eq({}, meths.get_runtime_file("foobarlang/", true))
end)
it('can handle bad patterns', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
eq("Vim:E220: Missing }.", pcall_err(meths.get_runtime_file, "{", false))
@@ -2732,8 +2759,8 @@ describe('API', function()
it('should have information about window options', function()
eq({
- allows_duplicates = true,
- commalist = false;
+ allows_duplicates = false,
+ commalist = true;
default = "";
flaglist = false;
global_local = false;
@@ -3017,7 +3044,7 @@ describe('API', function()
meths.buf_set_mark(buf, 'F', 2, 2, {})
meths.buf_set_name(buf, "mybuf")
local mark = meths.get_mark('F', {})
- -- Compare the path tail ony
+ -- Compare the path tail only
assert(string.find(mark[4], "mybuf$"))
eq({2, 2, buf.id, mark[4]}, mark)
end)
@@ -3101,6 +3128,24 @@ describe('API', function()
eq('E539: Illegal character <}>',
pcall_err(meths.eval_statusline, '%{%}', {}))
end)
+ it('supports various items', function()
+ eq({ str = '0', width = 1 },
+ meths.eval_statusline('%l', { maxwidth = 5 }))
+ command('set readonly')
+ eq({ str = '[RO]', width = 4 },
+ meths.eval_statusline('%r', { maxwidth = 5 }))
+ local screen = Screen.new(80, 24)
+ screen:attach()
+ command('set showcmd')
+ feed('1234')
+ screen:expect({any = '1234'})
+ eq({ str = '1234', width = 4 },
+ meths.eval_statusline('%S', { maxwidth = 5 }))
+ feed('56')
+ screen:expect({any = '123456'})
+ eq({ str = '<3456', width = 5 },
+ meths.eval_statusline('%S', { maxwidth = 5 }))
+ end)
describe('highlight parsing', function()
it('works', function()
eq({
@@ -3168,6 +3213,17 @@ describe('API', function()
'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
{ use_winbar = true, highlights = true }))
end)
+ it('no memory leak with click functions', function()
+ meths.eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {})
+ eq({
+ str = 'StatusLineStringWithClickFunc',
+ width = 29
+ },
+ meths.eval_statusline(
+ '%@ClickFunc@StatusLineStringWithClickFunc%T',
+ {})
+ )
+ end)
end)
end)
describe('nvim_parse_cmd', function()
@@ -3176,9 +3232,6 @@ describe('API', function()
cmd = 'echo',
args = { 'foo' },
bang = false,
- range = {},
- count = -1,
- reg = '',
addr = 'none',
magic = {
file = false,
@@ -3195,6 +3248,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3205,7 +3259,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3218,8 +3272,6 @@ describe('API', function()
args = { '/math.random/math.max/' },
bang = false,
range = { 4, 6 },
- count = -1,
- reg = '',
addr = 'line',
magic = {
file = false,
@@ -3236,6 +3288,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3246,7 +3299,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3260,7 +3313,6 @@ describe('API', function()
bang = false,
range = { 1 },
count = 1,
- reg = '',
addr = 'buf',
magic = {
file = false,
@@ -3277,6 +3329,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3287,7 +3340,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3300,7 +3353,6 @@ describe('API', function()
args = {},
bang = false,
range = {},
- count = -1,
reg = '+',
addr = 'line',
magic = {
@@ -3318,6 +3370,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3328,12 +3381,51 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
}
}, meths.parse_cmd('put +', {}))
+ eq({
+ cmd = 'put',
+ args = {},
+ bang = false,
+ range = {},
+ reg = '',
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = true
+ },
+ nargs = '0',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ horizontal = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = -1,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('put', {}))
end)
it('works with range, count and register', function()
eq({
@@ -3359,6 +3451,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3369,7 +3462,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3382,8 +3475,6 @@ describe('API', function()
args = {},
bang = true,
range = {},
- count = -1,
- reg = '',
addr = 'line',
magic = {
file = true,
@@ -3400,6 +3491,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3410,7 +3502,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3423,8 +3515,6 @@ describe('API', function()
args = { 'foo.txt' },
bang = false,
range = {},
- count = -1,
- reg = '',
addr = '?',
magic = {
file = true,
@@ -3441,6 +3531,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = true,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3451,19 +3542,17 @@ describe('API', function()
sandbox = false,
silent = true,
split = "topleft",
- tab = 2,
+ tab = 1,
unsilent = false,
verbose = 15,
vertical = false,
},
- }, meths.parse_cmd('15verbose silent! aboveleft topleft tab filter /foo/ split foo.txt', {}))
+ }, meths.parse_cmd('15verbose silent! horizontal topleft tab filter /foo/ split foo.txt', {}))
eq({
cmd = 'split',
args = { 'foo.txt' },
bang = false,
range = {},
- count = -1,
- reg = '',
addr = '?',
magic = {
file = true,
@@ -3480,6 +3569,7 @@ describe('API', function()
force = true
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3495,7 +3585,7 @@ describe('API', function()
verbose = 0,
vertical = false,
},
- }, meths.parse_cmd('0verbose unsilent botright confirm filter! /foo/ split foo.txt', {}))
+ }, meths.parse_cmd('0verbose unsilent botright 0tab confirm filter! /foo/ split foo.txt', {}))
end)
it('works with user commands', function()
command('command -bang -nargs=+ -range -addr=lines MyCommand echo foo')
@@ -3504,8 +3594,6 @@ describe('API', function()
args = { 'test', 'it' },
bang = true,
range = { 4, 6 },
- count = -1,
- reg = '',
addr = 'line',
magic = {
file = false,
@@ -3522,6 +3610,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3532,7 +3621,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3545,8 +3634,6 @@ describe('API', function()
args = { 'a.txt' },
bang = false,
range = {},
- count = -1,
- reg = '',
addr = 'arg',
magic = {
file = true,
@@ -3563,6 +3650,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3573,7 +3661,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3586,9 +3674,6 @@ describe('API', function()
cmd = 'MyCommand',
args = { 'test it' },
bang = false,
- range = {},
- count = -1,
- reg = '',
addr = 'none',
magic = {
file = false,
@@ -3605,6 +3690,7 @@ describe('API', function()
force = false
},
hide = false,
+ horizontal = false,
keepalt = false,
keepjumps = false,
keepmarks = false,
@@ -3615,7 +3701,7 @@ describe('API', function()
sandbox = false,
silent = false,
split = "",
- tab = 0,
+ tab = -1,
unsilent = false,
verbose = -1,
vertical = false,
@@ -3668,6 +3754,59 @@ describe('API', function()
:^ |
]])
end)
+ it('does not move cursor or change search history/pattern #19878 #19890', function()
+ meths.buf_set_lines(0, 0, -1, true, {'foo', 'bar', 'foo', 'bar'})
+ eq({1, 0}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('/'))
+ eq('', funcs.histget('search'))
+ feed(':') -- call the API in cmdline mode to test whether it changes search history
+ eq({
+ cmd = 'normal',
+ args = {'x'},
+ bang = true,
+ range = {3, 4},
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = false,
+ },
+ nargs = '+',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false,
+ },
+ hide = false,
+ horizontal = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = -1,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('+2;/bar/normal! x', {}))
+ eq({1, 0}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('/'))
+ eq('', funcs.histget('search'))
+ end)
+ it('result can be used directly by nvim_cmd #20051', function()
+ eq("foo", meths.cmd(meths.parse_cmd('echo "foo"', {}), { output = true }))
+ meths.cmd(meths.parse_cmd("set cursorline", {}), {})
+ eq(true, meths.get_option_value("cursorline", {}))
+ end)
end)
describe('nvim_cmd', function()
it('works', function ()
@@ -3745,15 +3884,28 @@ describe('API', function()
eq("", meths.cmd({ cmd = "Foo", bang = false }, { output = true }))
end)
it('works with modifiers', function()
- -- with :silent output is still captured
+ -- with silent = true output is still captured
eq('1',
meths.cmd({ cmd = 'echomsg', args = { '1' }, mods = { silent = true } },
{ output = true }))
- -- with :silent message isn't added to message history
+ -- but message isn't added to message history
eq('', meths.cmd({ cmd = 'messages' }, { output = true }))
+
meths.create_user_command("Foo", 'set verbose', {})
eq(" verbose=1", meths.cmd({ cmd = "Foo", mods = { verbose = 1 } }, { output = true }))
+
+ meths.create_user_command("Mods", "echo '<mods>'", {})
+ eq('keepmarks keeppatterns silent 3verbose aboveleft horizontal',
+ meths.cmd({ cmd = "Mods", mods = {
+ horizontal = true,
+ keepmarks = true,
+ keeppatterns = true,
+ silent = true,
+ split = 'aboveleft',
+ verbose = 3,
+ } }, { output = true }))
eq(0, meths.get_option_value("verbose", {}))
+
command('edit foo.txt | edit bar.txt')
eq(' 1 #h "foo.txt" line 1',
meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = false } } },
@@ -3761,6 +3913,13 @@ describe('API', function()
eq(' 2 %a "bar.txt" line 1',
meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = true } } },
{ output = true }))
+
+ -- with emsg_silent = true error is suppresed
+ feed([[:lua vim.api.nvim_cmd({ cmd = 'call', mods = { emsg_silent = true } }, {})<CR>]])
+ eq('', meths.cmd({ cmd = 'messages' }, { output = true }))
+ -- error from the next command typed is not suppressed #21420
+ feed(':call<CR><CR>')
+ eq('E471: Argument required', meths.cmd({ cmd = 'messages' }, { output = true }))
end)
it('works with magic.file', function()
exec_lua([[
@@ -3841,11 +4000,23 @@ describe('API', function()
eq({'aa'}, meths.buf_get_lines(0, 0, 1, false))
assert_alive()
end)
+ it('supports filename expansion', function()
+ meths.cmd({ cmd = 'argadd', args = { '%:p:h:t', '%:p:h:t' } }, {})
+ local arg = funcs.expand('%:p:h:t')
+ eq({ arg, arg }, funcs.argv())
+ end)
it("'make' command works when argument count isn't 1 #19696", function()
command('set makeprg=echo')
- meths.cmd({ cmd = 'make' }, {})
+ command('set shellquote=')
+ matches('^:!echo ',
+ meths.cmd({ cmd = 'make' }, { output = true }))
assert_alive()
- meths.cmd({ cmd = 'make', args = { 'foo', 'bar' } }, {})
+ matches('^:!echo foo bar',
+ meths.cmd({ cmd = 'make', args = { 'foo', 'bar' } }, { output = true }))
+ assert_alive()
+ local arg_pesc = pesc(funcs.expand('%:p:h:t'))
+ matches(('^:!echo %s %s'):format(arg_pesc, arg_pesc),
+ meths.cmd({ cmd = 'make', args = { '%:p:h:t', '%:p:h:t' } }, { output = true }))
assert_alive()
end)
it('doesn\'t display messages when output=true', function()
@@ -3878,5 +4049,23 @@ describe('API', function()
15 |
]]}
end)
+ it('works with non-String args', function()
+ eq('2', meths.cmd({cmd = 'echo', args = {2}}, {output = true}))
+ eq('1', meths.cmd({cmd = 'echo', args = {true}}, {output = true}))
+ end)
+ describe('first argument as count', function()
+ before_each(clear)
+
+ it('works', function()
+ command('vsplit | enew')
+ meths.cmd({cmd = 'bdelete', args = {meths.get_current_buf()}}, {})
+ eq(1, meths.get_current_buf().id)
+ end)
+ it('works with :sleep using milliseconds', function()
+ local start = luv.now()
+ meths.cmd({cmd = 'sleep', args = {'100m'}}, {})
+ ok(luv.now() - start <= 300)
+ end)
+ end)
end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 901d24327c..ecab6a4713 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -7,6 +7,7 @@ local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
helpers.tabpage
local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths
+local exec = helpers.exec
local funcs = helpers.funcs
local request = helpers.request
local NIL = helpers.NIL
@@ -15,25 +16,6 @@ local command = helpers.command
local pcall_err = helpers.pcall_err
local assert_alive = helpers.assert_alive
--- check if str is visible at the beginning of some line
-local function is_visible(str)
- local slen = string.len(str)
- local nlines = eval("&lines")
- for i = 1,nlines do
- local iseq = true
- for j = 1,slen do
- if string.byte(str,j) ~= eval("screenchar("..i..","..j..")") then
- iseq = false
- break
- end
- end
- if iseq then
- return true
- end
- end
- return false
-end
-
describe('API/win', function()
before_each(clear)
@@ -79,27 +61,61 @@ describe('API/win', function()
end)
it('updates the screen, and also when the window is unfocused', function()
+ local screen = Screen.new(30, 9)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true, reverse = true};
+ [3] = {reverse = true};
+ })
+ screen:attach()
+
insert("prologue")
feed('100o<esc>')
insert("epilogue")
local win = curwin()
feed('gg')
- poke_eventloop() -- let nvim process the 'gg' command
+ screen:expect{grid=[[
+ ^prologue |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]]}
-- cursor position is at beginning
eq({1, 0}, window('get_cursor', win))
- eq(true, is_visible("prologue"))
- eq(false, is_visible("epilogue"))
-- move cursor to end
window('set_cursor', win, {101, 0})
- eq(false, is_visible("prologue"))
- eq(true, is_visible("epilogue"))
+ screen:expect{grid=[[
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ ^epilogue |
+ |
+ ]]}
-- move cursor to the beginning again
window('set_cursor', win, {1, 0})
- eq(true, is_visible("prologue"))
- eq(false, is_visible("epilogue"))
+ screen:expect{grid=[[
+ ^prologue |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]]}
-- move focus to new window
nvim('command',"new")
@@ -107,18 +123,45 @@ describe('API/win', function()
-- sanity check, cursor position is kept
eq({1, 0}, window('get_cursor', win))
- eq(true, is_visible("prologue"))
- eq(false, is_visible("epilogue"))
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ prologue |
+ |
+ |
+ {3:[No Name] [+] }|
+ |
+ ]]}
-- move cursor to end
window('set_cursor', win, {101, 0})
- eq(false, is_visible("prologue"))
- eq(true, is_visible("epilogue"))
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ |
+ |
+ epilogue |
+ {3:[No Name] [+] }|
+ |
+ ]]}
-- move cursor to the beginning again
window('set_cursor', win, {1, 0})
- eq(true, is_visible("prologue"))
- eq(false, is_visible("epilogue"))
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ prologue |
+ |
+ |
+ {3:[No Name] [+] }|
+ |
+ ]]}
-- curwin didn't change back
neq(win, curwin())
@@ -187,6 +230,46 @@ describe('API/win', function()
|
]])
end)
+
+ it('updates cursorcolumn in non-current window', function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {background = Screen.colors.Grey90}, -- CursorColumn
+ [3] = {bold = true, reverse = true}, -- StatusLine
+ [4] = {reverse = true}, -- StatusLineNC
+ })
+ screen:attach()
+ command('set cursorcolumn')
+ insert([[
+ aaa
+ bbb
+ ccc
+ ddd]])
+ local oldwin = curwin()
+ command('vsplit')
+ screen:expect([[
+ aa{2:a} │aa{2:a} |
+ bb{2:b} │bb{2:b} |
+ cc{2:c} │cc{2:c} |
+ dd^d │ddd |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{4:[No Name] [+] }|
+ |
+ ]])
+ window('set_cursor', oldwin, {2, 0})
+ screen:expect([[
+ aa{2:a} │{2:a}aa |
+ bb{2:b} │bbb |
+ cc{2:c} │{2:c}cc |
+ dd^d │{2:d}dd |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{4:[No Name] [+] }|
+ |
+ ]])
+ end)
end)
describe('{get,set}_height', function()
@@ -201,6 +284,22 @@ describe('API/win', function()
window('set_height', nvim('list_wins')[2], 2)
eq(2, window('get_height', nvim('list_wins')[2]))
end)
+
+ it('do not cause ml_get errors with foldmethod=expr #19989', function()
+ insert([[
+ aaaaa
+ bbbbb
+ ccccc]])
+ command('set foldmethod=expr')
+ exec([[
+ new
+ let w = nvim_get_current_win()
+ wincmd w
+ call nvim_win_set_height(w, 5)
+ ]])
+ feed('l')
+ eq('', meths.get_vvar('errmsg'))
+ end)
end)
describe('{get,set}_width', function()
@@ -215,6 +314,22 @@ describe('API/win', function()
window('set_width', nvim('list_wins')[2], 2)
eq(2, window('get_width', nvim('list_wins')[2]))
end)
+
+ it('do not cause ml_get errors with foldmethod=expr #19989', function()
+ insert([[
+ aaaaa
+ bbbbb
+ ccccc]])
+ command('set foldmethod=expr')
+ exec([[
+ vnew
+ let w = nvim_get_current_win()
+ wincmd w
+ call nvim_win_set_width(w, 5)
+ ]])
+ feed('l')
+ eq('', meths.get_vvar('errmsg'))
+ end)
end)
describe('{get,set,del}_var', function()
@@ -408,6 +523,8 @@ describe('API/win', function()
it('closing current (float) window of another tabpage #15313', function()
command('tabedit')
+ command('botright split')
+ local prevwin = curwin().id
eq(2, eval('tabpagenr()'))
local win = meths.open_win(0, true, {
relative='editor', row=10, col=10, width=50, height=10
@@ -417,7 +534,7 @@ describe('API/win', function()
eq(1, eval('tabpagenr()'))
meths.win_close(win, false)
- eq(1001, meths.tabpage_get_win(tab).id)
+ eq(prevwin, meths.tabpage_get_win(tab).id)
assert_alive()
end)
end)
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 90254b7415..fb5bab445c 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -9,6 +9,7 @@ local neq = helpers.neq
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
+local matches = helpers.matches
local meths = helpers.meths
local pcall_err = helpers.pcall_err
local funcs = helpers.funcs
@@ -424,17 +425,50 @@ describe('autocmd', function()
end)
it('gives E814 when there are no other floating windows', function()
- eq('Vim(close):E814: Cannot close window, only autocmd window would remain',
+ eq('BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain',
pcall_err(command, 'doautoall BufAdd'))
end)
it('gives E814 when there are other floating windows', function()
meths.open_win(0, true, {width = 10, height = 10, relative = 'editor', row = 10, col = 10})
- eq('Vim(close):E814: Cannot close window, only autocmd window would remain',
+ eq('BufAdd Autocommands for "Xa.txt": Vim(close):E814: Cannot close window, only autocmd window would remain',
pcall_err(command, 'doautoall BufAdd'))
end)
end)
+ it('closing `aucmd_win` using API gives E813', function()
+ exec_lua([[
+ vim.cmd('tabnew')
+ _G.buf = vim.api.nvim_create_buf(true, true)
+ ]])
+ matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[
+ vim.api.nvim_buf_call(_G.buf, function()
+ local win = vim.api.nvim_get_current_win()
+ vim.api.nvim_win_close(win, true)
+ end)
+ ]]))
+ matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[
+ vim.api.nvim_buf_call(_G.buf, function()
+ local win = vim.api.nvim_get_current_win()
+ vim.cmd('tabnext')
+ vim.api.nvim_win_close(win, true)
+ end)
+ ]]))
+ matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[
+ vim.api.nvim_buf_call(_G.buf, function()
+ local win = vim.api.nvim_get_current_win()
+ vim.api.nvim_win_hide(win)
+ end)
+ ]]))
+ matches('Vim:E813: Cannot close autocmd window$', pcall_err(exec_lua, [[
+ vim.api.nvim_buf_call(_G.buf, function()
+ local win = vim.api.nvim_get_current_win()
+ vim.cmd('tabnext')
+ vim.api.nvim_win_hide(win)
+ end)
+ ]]))
+ end)
+
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
screen:attach()
@@ -476,14 +510,14 @@ describe('autocmd', function()
it('during RecordingLeave event', function()
command([[autocmd RecordingLeave * let v:event.regname = '']])
- eq('Vim(let):E46: Cannot change read-only variable "v:event.regname"',
+ eq('RecordingLeave Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.regname"',
pcall_err(command, 'normal! qqq'))
end)
it('during TermClose event', function()
command('autocmd TermClose * let v:event.status = 0')
command('terminal')
- eq('Vim(let):E46: Cannot change read-only variable "v:event.status"',
+ eq('TermClose Autocommands for "*": Vim(let):E46: Cannot change read-only variable "v:event.status"',
pcall_err(command, 'bdelete!'))
end)
end)
diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua
index 8ec06dc148..82fb9b9444 100644
--- a/test/functional/autocmd/cmdline_spec.lua
+++ b/test/functional/autocmd/cmdline_spec.lua
@@ -73,7 +73,7 @@ describe('cmdline autocommands', function()
{1:~ }|
{4: }|
: |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
+ {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:^ |
]])
@@ -82,9 +82,9 @@ describe('cmdline autocommands', function()
|
{4: }|
: |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
+ {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):very error} |
+ {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
|
{3:Press ENTER or type command to continue}^ |
]])
@@ -111,9 +111,9 @@ describe('cmdline autocommands', function()
lorem ipsum |
{4: }|
: |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
+ {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
+ {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum'^ |
]])
@@ -123,9 +123,9 @@ describe('cmdline autocommands', function()
lorem ipsum |
{4: }|
: |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
+ {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
+ {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum^' |
]])
@@ -134,22 +134,22 @@ describe('cmdline autocommands', function()
screen:expect([[
{4: }|
: |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):FAIL} |
+ {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
+ {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
+ {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.^' |
]])
feed('<cr>')
screen:expect([[
:put ='lorem ipsum' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
+ {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):change erreor} |
+ {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
- {2:E5500: autocmd has thrown an exception: Vim(echoerr):very error} |
+ {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
|
{3:Press ENTER or type command to continue}^ |
]])
@@ -185,6 +185,14 @@ describe('cmdline autocommands', function()
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg())
end)
+ it('no crash with recursive use of v:event #19484', function()
+ command('autocmd CmdlineEnter * normal :')
+ feed(':')
+ eq({'notification', 'CmdlineEnter', {{cmdtype=':', cmdlevel=1}}}, next_msg())
+ feed('<CR>')
+ eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg())
+ end)
+
it('supports CmdlineChanged' ,function()
command("autocmd CmdlineChanged * call rpcnotify(g:channel, 'CmdlineChanged', v:event, getcmdline())")
feed(':')
@@ -215,7 +223,6 @@ describe('cmdline autocommands', function()
eq({'notification', 'CmdlineChanged', {{cmdtype='=', cmdlevel=2}, "1+1"}}, next_msg())
feed('<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype='=', cmdlevel=2, abort=false}}}, next_msg())
- eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = "}}, next_msg())
eq({'notification', 'CmdlineChanged', {{cmdtype=':', cmdlevel=1}, "let x = 2"}}, next_msg())
feed('<cr>')
eq({'notification', 'CmdlineLeave', {{cmdtype=':', cmdlevel=1, abort=false}}}, next_msg())
diff --git a/test/functional/autocmd/cursorhold_spec.lua b/test/functional/autocmd/cursorhold_spec.lua
index 506b688853..b04bd5233a 100644
--- a/test/functional/autocmd/cursorhold_spec.lua
+++ b/test/functional/autocmd/cursorhold_spec.lua
@@ -2,30 +2,82 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
-local eval = helpers.eval
local feed = helpers.feed
local retry = helpers.retry
-local source = helpers.source
+local exec = helpers.source
local sleep = helpers.sleep
+local meths = helpers.meths
-describe('CursorHoldI', function()
- before_each(clear)
+before_each(clear)
+
+describe('CursorHold', function()
+ before_each(function()
+ exec([[
+ let g:cursorhold = 0
+ augroup test
+ au CursorHold * let g:cursorhold += 1
+ augroup END
+ ]])
+ end)
+
+ it('is triggered correctly #12587', function()
+ local function test_cursorhold(fn, early)
+ local ut = 2
+ -- if testing with small 'updatetime' fails, double its value and test again
+ retry(10, nil, function()
+ ut = ut * 2
+ meths.set_option('updatetime', ut)
+ feed('0') -- reset did_cursorhold
+ meths.set_var('cursorhold', 0)
+ sleep(ut / 4)
+ fn()
+ eq(0, meths.get_var('cursorhold'))
+ sleep(ut / 2)
+ fn()
+ eq(0, meths.get_var('cursorhold'))
+ sleep(ut / 2)
+ eq(early, meths.get_var('cursorhold'))
+ sleep(ut / 4 * 3)
+ eq(1, meths.get_var('cursorhold'))
+ end)
+ end
+ local ignore_key = meths.replace_termcodes('<Ignore>', true, true, true)
+ test_cursorhold(function() end, 1)
+ test_cursorhold(function() feed('') end, 1)
+ test_cursorhold(function() meths.feedkeys('', 'n', true) end, 1)
+ test_cursorhold(function() feed('<Ignore>') end, 0)
+ test_cursorhold(function() meths.feedkeys(ignore_key, 'n', true) end, 0)
+ end)
+
+ it("reducing 'updatetime' while waiting for CursorHold #20241", function()
+ meths.set_option('updatetime', 10000)
+ feed('0') -- reset did_cursorhold
+ meths.set_var('cursorhold', 0)
+ sleep(50)
+ eq(0, meths.get_var('cursorhold'))
+ meths.set_option('updatetime', 20)
+ sleep(10)
+ eq(1, meths.get_var('cursorhold'))
+ end)
+end)
+
+describe('CursorHoldI', function()
-- NOTE: since this test uses RPC it is not necessary to trigger the initial
-- issue (#3757) via timer's or RPC callbacks in the first place.
it('is triggered after input', function()
- source([[
- set updatetime=1
+ exec([[
+ set updatetime=1
- let g:cursorhold = 0
- augroup test
- au CursorHoldI * let g:cursorhold += 1
- augroup END
+ let g:cursorhold = 0
+ augroup test
+ au CursorHoldI * let g:cursorhold += 1
+ augroup END
]])
feed('ifoo')
retry(5, nil, function()
sleep(1)
- eq(1, eval('g:cursorhold'))
+ eq(1, meths.get_var('cursorhold'))
end)
end)
end)
diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua
index 45dc06b39b..828cffa460 100644
--- a/test/functional/autocmd/dirchanged_spec.lua
+++ b/test/functional/autocmd/dirchanged_spec.lua
@@ -1,12 +1,12 @@
local lfs = require('lfs')
-local h = require('test.functional.helpers')(after_each)
+local helpers = require('test.functional.helpers')(after_each)
-local clear = h.clear
-local command = h.command
-local eq = h.eq
-local eval = h.eval
-local request = h.request
-local iswin = h.iswin
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local eval = helpers.eval
+local request = helpers.request
+local is_os = helpers.is_os
describe('autocmd DirChanged and DirChangedPre', function()
local curdir = string.gsub(lfs.currentdir(), '\\', '/')
@@ -21,8 +21,8 @@ describe('autocmd DirChanged and DirChangedPre', function()
curdir .. '\\XTEST-FUNCTIONAL-AUTOCMD-DIRCHANGED.DIR3',
}
- setup(function() for _, dir in pairs(dirs) do h.mkdir(dir) end end)
- teardown(function() for _, dir in pairs(dirs) do h.rmdir(dir) end end)
+ setup(function() for _, dir in pairs(dirs) do helpers.mkdir(dir) end end)
+ teardown(function() for _, dir in pairs(dirs) do helpers.rmdir(dir) end end)
before_each(function()
clear()
@@ -159,7 +159,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
- if iswin() then
+ if is_os('win') then
command('lcd '..win_dirs[1])
eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
@@ -182,7 +182,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
- if iswin() then
+ if is_os('win') then
command('tcd '..win_dirs[2])
eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
@@ -204,7 +204,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
- if iswin() then
+ if is_os('win') then
command('cd '..win_dirs[3])
eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
@@ -229,7 +229,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
- if iswin() then
+ if is_os('win') then
command('split '..win_dirs[1]..'/baz')
eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
@@ -278,7 +278,7 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
- if iswin() then
+ if is_os('win') then
command('tabnew') -- tab 3
eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index e3c9e1f9ee..d7a87e17ed 100644
--- a/test/functional/autocmd/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
@@ -6,7 +6,7 @@ local nvim_prog = helpers.nvim_prog
local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
-if helpers.pending_win32(pending) then return end
+if helpers.skip(helpers.is_os('win')) then return end
describe('autoread TUI FocusGained/FocusLost', function()
local f1 = 'xtest-foo'
@@ -33,18 +33,37 @@ describe('autoread TUI FocusGained/FocusLost', function()
helpers.write_file(path, '')
lfs.touch(path, os.time() - 10)
- feed_command('edit '..path)
- feed_data('\027[O')
screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+ feed_command('edit '..path)
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
{5:xtest-foo }|
:edit xtest-foo |
{3:-- TERMINAL --} |
]]}
+ feed_data('\027[O')
+ feed_data('\027[O')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:xtest-foo }|
+ :edit xtest-foo |
+ {3:-- TERMINAL --} |
+ ]], unchanged=true}
helpers.write_file(path, expected_addition)
diff --git a/test/functional/autocmd/signal_spec.lua b/test/functional/autocmd/signal_spec.lua
index d4f65cc61d..738064090a 100644
--- a/test/functional/autocmd/signal_spec.lua
+++ b/test/functional/autocmd/signal_spec.lua
@@ -5,11 +5,10 @@ local command = helpers.command
local eq = helpers.eq
local funcs = helpers.funcs
local next_msg = helpers.next_msg
+local is_os = helpers.is_os
+local skip = helpers.skip
-if helpers.pending_win32(pending) then
- -- Only applies to POSIX systems.
- return
-end
+if skip(is_os('win'), 'Only applies to POSIX systems') then return end
local function posix_kill(signame, pid)
os.execute('kill -s '..signame..' -- '..pid..' >/dev/null')
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index 859c2ebf44..0a33f1b2ac 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -5,11 +5,13 @@ local clear, command, nvim, testprg =
helpers.clear, helpers.command, helpers.nvim, helpers.testprg
local eval, eq, neq, retry =
helpers.eval, helpers.eq, helpers.neq, helpers.retry
+local matches = helpers.matches
local ok = helpers.ok
local feed = helpers.feed
local pcall_err = helpers.pcall_err
local assert_alive = helpers.assert_alive
-local iswin = helpers.iswin
+local skip = helpers.skip
+local is_os = helpers.is_os
describe('autocmd TermClose', function()
before_each(function()
@@ -22,7 +24,8 @@ describe('autocmd TermClose', function()
local function test_termclose_delete_own_buf()
command('autocmd TermClose * bdelete!')
command('terminal')
- eq('Vim(bdelete):E937: Attempt to delete a buffer that is in use', pcall_err(command, 'bdelete!'))
+ matches('^TermClose Autocommands for "%*": Vim%(bdelete%):E937: Attempt to delete a buffer that is in use: term://',
+ pcall_err(command, 'bdelete!'))
assert_alive()
end
@@ -45,7 +48,7 @@ describe('autocmd TermClose', function()
end)
it('triggers when long-running terminal job gets stopped', function()
- nvim('set_option', 'shell', iswin() and 'cmd.exe' or 'sh')
+ nvim('set_option', 'shell', is_os('win') and 'cmd.exe' or 'sh')
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
command('call jobstop(b:terminal_job_id)')
@@ -53,7 +56,7 @@ describe('autocmd TermClose', function()
end)
it('kills job trapping SIGTERM', function()
- if iswin() then return end
+ skip(is_os('win'))
nvim('set_option', 'shell', 'sh')
nvim('set_option', 'shellcmdflag', '-c')
command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]]
@@ -73,7 +76,7 @@ describe('autocmd TermClose', function()
end)
it('kills PTY job trapping SIGHUP and SIGTERM', function()
- if iswin() then return end
+ skip(is_os('win'))
nvim('set_option', 'shell', 'sh')
nvim('set_option', 'shellcmdflag', '-c')
command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]]
diff --git a/test/functional/autocmd/win_scrolled_resized_spec.lua b/test/functional/autocmd/win_scrolled_resized_spec.lua
new file mode 100644
index 0000000000..4957f56dd4
--- /dev/null
+++ b/test/functional/autocmd/win_scrolled_resized_spec.lua
@@ -0,0 +1,329 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local exec = helpers.exec
+local command = helpers.command
+local feed = helpers.feed
+local meths = helpers.meths
+local assert_alive = helpers.assert_alive
+
+before_each(clear)
+
+describe('WinResized', function()
+ -- oldtest: Test_WinResized()
+ it('works', function()
+ exec([[
+ set scrolloff=0
+ call setline(1, ['111', '222'])
+ vnew
+ call setline(1, ['aaa', 'bbb'])
+ new
+ call setline(1, ['foo', 'bar'])
+
+ let g:resized = 0
+ au WinResized * let g:resized += 1
+ au WinResized * let g:v_event = deepcopy(v:event)
+ ]])
+ eq(0, eval('g:resized'))
+
+ -- increase window height, two windows will be reported
+ feed('<C-W>+')
+ eq(1, eval('g:resized'))
+ eq({windows = {1002, 1001}}, eval('g:v_event'))
+
+ -- increase window width, three windows will be reported
+ feed('<C-W>>')
+ eq(2, eval('g:resized'))
+ eq({windows = {1002, 1001, 1000}}, eval('g:v_event'))
+ end)
+end)
+
+describe('WinScrolled', function()
+ local win_id
+
+ before_each(function()
+ win_id = meths.get_current_win().id
+ command(string.format('autocmd WinScrolled %d let g:matched = v:true', win_id))
+ exec([[
+ let g:scrolled = 0
+ au WinScrolled * let g:scrolled += 1
+ au WinScrolled * let g:amatch = str2nr(expand('<amatch>'))
+ au WinScrolled * let g:afile = str2nr(expand('<afile>'))
+ au WinScrolled * let g:v_event = deepcopy(v:event)
+ ]])
+ end)
+
+ after_each(function()
+ eq(true, eval('g:matched'))
+ eq(win_id, eval('g:amatch'))
+ eq(win_id, eval('g:afile'))
+ end)
+
+ it('is triggered by scrolling vertically', function()
+ local lines = {'123', '123'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ eq(0, eval('g:scrolled'))
+
+ feed('<C-E>')
+ eq(1, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('<C-Y>')
+ eq(2, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = -1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+ end)
+
+ it('is triggered by scrolling horizontally', function()
+ command('set nowrap')
+ local width = meths.win_get_width(0)
+ local line = '123' .. ('*'):rep(width * 2)
+ local lines = {line, line}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ eq(0, eval('g:scrolled'))
+
+ feed('zl')
+ eq(1, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('zh')
+ eq(2, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+ end)
+
+ it('is triggered by horizontal scrolling from cursor move', function()
+ command('set nowrap')
+ local lines = {'', '', 'Foo'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ meths.win_set_cursor(0, {3, 0})
+ eq(0, eval('g:scrolled'))
+
+ feed('zl')
+ eq(1, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('zl')
+ eq(2, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('h')
+ eq(3, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('zh')
+ eq(4, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = -1, topline = 0, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+ end)
+
+ -- oldtest: Test_WinScrolled_long_wrapped()
+ it('is triggered by scrolling on a long wrapped line #19968', function()
+ local height = meths.win_get_height(0)
+ local width = meths.win_get_width(0)
+ meths.buf_set_lines(0, 0, -1, true, {('foo'):rep(height * width)})
+ meths.win_set_cursor(0, {1, height * width - 1})
+ eq(0, eval('g:scrolled'))
+
+ feed('gj')
+ eq(1, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width},
+ ['1000'] = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width},
+ }, eval('g:v_event'))
+
+ feed('0')
+ eq(2, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = width},
+ ['1000'] = {leftcol = 0, topline = 0, topfill = 0, width = 0, height = 0, skipcol = -width},
+ }, eval('g:v_event'))
+
+ feed('$')
+ eq(3, eval('g:scrolled'))
+ end)
+
+ it('is triggered when the window scrolls in Insert mode', function()
+ local height = meths.win_get_height(0)
+ local lines = {}
+ for i = 1, height * 2 do
+ lines[i] = tostring(i)
+ end
+ meths.buf_set_lines(0, 0, -1, true, lines)
+
+ feed('M')
+ eq(0, eval('g:scrolled'))
+
+ feed('i<C-X><C-E><Esc>')
+ eq(1, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('i<C-X><C-Y><Esc>')
+ eq(2, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = -1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('L')
+ eq(2, eval('g:scrolled'))
+
+ feed('A<CR><Esc>')
+ eq(3, eval('g:scrolled'))
+ eq({
+ all = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+ end)
+end)
+
+describe('WinScrolled', function()
+ -- oldtest: Test_WinScrolled_mouse()
+ it('is triggered by mouse scrolling in another window', function()
+ local screen = Screen.new(75, 10)
+ screen:attach()
+ exec([[
+ set nowrap scrolloff=0
+ set mouse=a
+ call setline(1, ['foo']->repeat(32))
+ split
+ let g:scrolled = 0
+ au WinScrolled * let g:scrolled += 1
+ ]])
+ eq(0, eval('g:scrolled'))
+
+ -- With the upper split focused, send a scroll-down event to the unfocused one.
+ meths.input_mouse('wheel', 'down', '', 0, 6, 0)
+ eq(1, eval('g:scrolled'))
+
+ -- Again, but this time while we're in insert mode.
+ feed('i')
+ meths.input_mouse('wheel', 'down', '', 0, 6, 0)
+ feed('<Esc>')
+ eq(2, eval('g:scrolled'))
+ end)
+
+ -- oldtest: Test_WinScrolled_close_curwin()
+ it('closing window does not cause use-after-free #13265', function()
+ exec([[
+ set nowrap scrolloff=0
+ call setline(1, ['aaa', 'bbb'])
+ vsplit
+ au WinScrolled * close
+ ]])
+
+ -- This was using freed memory
+ feed('<C-E>')
+ assert_alive()
+ end)
+
+ -- oldtest: Test_WinScrolled_diff()
+ it('is triggered for both windows when scrolling in diff mode', function()
+ exec([[
+ set diffopt+=foldcolumn:0
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ vnew
+ call setline(1, ['d', 'e', 'f', 'g', 'h', 'i'])
+ windo diffthis
+ au WinScrolled * let g:v_event = deepcopy(v:event)
+ ]])
+
+ feed('<C-E>')
+ eq({
+ all = {leftcol = 0, topline = 1, topfill = 1, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1001'] = {leftcol = 0, topline = 0, topfill = -1, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('2<C-E>')
+ eq({
+ all = {leftcol = 0, topline = 2, topfill = 2, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = 2, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1001'] = {leftcol = 0, topline = 0, topfill = -2, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('<C-E>')
+ eq({
+ all = {leftcol = 0, topline = 2, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1001'] = {leftcol = 0, topline = 1, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ feed('2<C-Y>')
+ eq({
+ all = {leftcol = 0, topline = 3, topfill = 1, width = 0, height = 0, skipcol = 0},
+ ['1000'] = {leftcol = 0, topline = -2, topfill = 0, width = 0, height = 0, skipcol = 0},
+ ['1001'] = {leftcol = 0, topline = -1, topfill = 1, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+ end)
+
+ it('is triggered by mouse scrolling in unfocused floating window #18222', function()
+ local screen = Screen.new(80, 24)
+ screen:attach()
+
+ exec([[
+ let g:scrolled = 0
+ autocmd WinScrolled * let g:scrolled += 1
+ autocmd WinScrolled * let g:amatch = expand('<amatch>')
+ autocmd WinScrolled * let g:v_event = deepcopy(v:event)
+ ]])
+ eq(0, eval('g:scrolled'))
+
+ local buf = meths.create_buf(true, true)
+ meths.buf_set_lines(buf, 0, -1, false, {'a', 'b', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n'})
+ local win = meths.open_win(buf, false, {
+ height = 5,
+ width = 10,
+ col = 0,
+ row = 1,
+ relative = 'editor',
+ style = 'minimal'
+ })
+ local winid_str = tostring(win.id)
+ -- WinScrolled should not be triggered when creating a new floating window
+ eq(0, eval('g:scrolled'))
+
+ meths.input_mouse('wheel', 'down', '', 0, 3, 3)
+ eq(1, eval('g:scrolled'))
+ eq(winid_str, eval('g:amatch'))
+ eq({
+ all = {leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0},
+ [winid_str] = {leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+
+ meths.input_mouse('wheel', 'up', '', 0, 3, 3)
+ eq(2, eval('g:scrolled'))
+ eq(tostring(win.id), eval('g:amatch'))
+ eq({
+ all = {leftcol = 0, topline = 3, topfill = 0, width = 0, height = 0, skipcol = 0},
+ [winid_str] = {leftcol = 0, topline = -3, topfill = 0, width = 0, height = 0, skipcol = 0},
+ }, eval('g:v_event'))
+ end)
+end)
diff --git a/test/functional/autocmd/winscrolled_spec.lua b/test/functional/autocmd/winscrolled_spec.lua
deleted file mode 100644
index 5c1b758961..0000000000
--- a/test/functional/autocmd/winscrolled_spec.lua
+++ /dev/null
@@ -1,85 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local clear = helpers.clear
-local eq = helpers.eq
-local eval = helpers.eval
-local command = helpers.command
-local feed = helpers.feed
-local meths = helpers.meths
-local assert_alive = helpers.assert_alive
-
-before_each(clear)
-
-describe('WinScrolled', function()
- local win_id
-
- before_each(function()
- win_id = meths.get_current_win().id
- command(string.format('autocmd WinScrolled %d let g:matched = v:true', win_id))
- command('let g:scrolled = 0')
- command('autocmd WinScrolled * let g:scrolled += 1')
- command([[autocmd WinScrolled * let g:amatch = str2nr(expand('<amatch>'))]])
- command([[autocmd WinScrolled * let g:afile = str2nr(expand('<afile>'))]])
- end)
-
- after_each(function()
- eq(true, eval('g:matched'))
- eq(win_id, eval('g:amatch'))
- eq(win_id, eval('g:afile'))
- end)
-
- it('is triggered by scrolling vertically', function()
- local lines = {'123', '123'}
- meths.buf_set_lines(0, 0, -1, true, lines)
- eq(0, eval('g:scrolled'))
- feed('<C-E>')
- eq(1, eval('g:scrolled'))
- end)
-
- it('is triggered by scrolling horizontally', function()
- command('set nowrap')
- local width = meths.win_get_width(0)
- local line = '123' .. ('*'):rep(width * 2)
- local lines = {line, line}
- meths.buf_set_lines(0, 0, -1, true, lines)
- eq(0, eval('g:scrolled'))
- feed('zl')
- eq(1, eval('g:scrolled'))
- end)
-
- it('is triggered by horizontal scrolling from cursor move', function()
- command('set nowrap')
- local lines = {'', '', 'Foo'}
- meths.buf_set_lines(0, 0, -1, true, lines)
- meths.win_set_cursor(0, {3, 0})
- eq(0, eval('g:scrolled'))
- feed('zl')
- eq(1, eval('g:scrolled'))
- feed('zl')
- eq(2, eval('g:scrolled'))
- feed('h')
- eq(3, eval('g:scrolled'))
- end)
-
- it('is triggered when the window scrolls in Insert mode', function()
- local height = meths.win_get_height(0)
- local lines = {}
- for i = 1, height * 2 do
- lines[i] = tostring(i)
- end
- meths.buf_set_lines(0, 0, -1, true, lines)
- feed('L')
- eq(0, eval('g:scrolled'))
- feed('A<CR><Esc>')
- eq(1, eval('g:scrolled'))
- end)
-end)
-
-it('closing window in WinScrolled does not cause use-after-free #13265', function()
- local lines = {'aaa', 'bbb'}
- meths.buf_set_lines(0, 0, -1, true, lines)
- command('vsplit')
- command('autocmd WinScrolled * close')
- feed('<C-E>')
- assert_alive()
-end)
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index ca52404d3b..8275575c24 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -1,5 +1,4 @@
local helpers = require('test.functional.helpers')(after_each)
-local uname = helpers.uname
local clear, eq, eval, next_msg, ok, source = helpers.clear, helpers.eq,
helpers.eval, helpers.next_msg, helpers.ok, helpers.source
local command, funcs, meths = helpers.command, helpers.funcs, helpers.meths
@@ -12,6 +11,7 @@ local retry = helpers.retry
local expect_twostreams = helpers.expect_twostreams
local assert_alive = helpers.assert_alive
local pcall_err = helpers.pcall_err
+local skip = helpers.skip
describe('channels', function()
local init = [[
@@ -145,7 +145,7 @@ describe('channels', function()
end
it('can use stdio channel with pty', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
source([[
let g:job_opts = {
\ 'on_stdout': function('OnEvent'),
@@ -178,8 +178,7 @@ describe('channels', function()
command("call chansend(id, 'incomplet\004')")
- local is_bsd = not not string.find(uname(), 'bsd')
- local bsdlike = is_bsd or is_os('mac')
+ local bsdlike = is_os('bsd') or is_os('mac')
local extra = bsdlike and "^D\008\008" or ""
expect_twoline(id, "stdout",
"incomplet"..extra, "[1, ['incomplet'], 'stdin']", true)
@@ -199,7 +198,7 @@ describe('channels', function()
it('stdio channel can use rpc and stderr simultaneously', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
source([[
let g:job_opts = {
\ 'on_stderr': function('OnEvent'),
diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua
index 8cad7adfa6..05a69e1992 100644
--- a/test/functional/core/exit_spec.lua
+++ b/test/functional/core/exit_spec.lua
@@ -89,14 +89,14 @@ describe(':cquit', function()
end)
it('exits with redir msg for multiple exit codes after :cquit 1 2', function()
- test_cq('cquit 1 2', nil, 'Vim(cquit):E488: Trailing characters: 2: cquit 1 2')
+ test_cq('cquit 1 2', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: 2: cquit 1 2')
end)
it('exits with redir msg for non-number exit code after :cquit X', function()
- test_cq('cquit X', nil, 'Vim(cquit):E488: Trailing characters: X: cquit X')
+ test_cq('cquit X', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: X: cquit X')
end)
it('exits with redir msg for negative exit code after :cquit -1', function()
- test_cq('cquit -1', nil, 'Vim(cquit):E488: Trailing characters: -1: cquit -1')
+ test_cq('cquit -1', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: -1: cquit -1')
end)
end)
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index a4d22685e8..4e9891a4de 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -1,3 +1,4 @@
+local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local assert_log = helpers.assert_log
@@ -5,6 +6,7 @@ local assert_nolog = helpers.assert_nolog
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local neq = helpers.neq
local ok = helpers.ok
local feed = helpers.feed
local funcs = helpers.funcs
@@ -19,22 +21,28 @@ local read_file = helpers.read_file
local tmpname = helpers.tmpname
local trim = helpers.trim
local currentdir = helpers.funcs.getcwd
-local iswin = helpers.iswin
local assert_alive = helpers.assert_alive
+local check_close = helpers.check_close
local expect_exit = helpers.expect_exit
local write_file = helpers.write_file
+local Screen = require('test.functional.ui.screen')
+local feed_command = helpers.feed_command
+local skip = helpers.skip
+local is_os = helpers.is_os
+local is_ci = helpers.is_ci
describe('fileio', function()
before_each(function()
end)
after_each(function()
- expect_exit(command, ':qall!')
+ check_close()
os.remove('Xtest_startup_shada')
os.remove('Xtest_startup_file1')
os.remove('Xtest_startup_file1~')
os.remove('Xtest_startup_file2')
os.remove('Xtest_тест.md')
os.remove('Xtest-u8-int-max')
+ os.remove('Xtest-overwrite-forced')
rmdir('Xtest_startup_swapdir')
rmdir('Xtest_backupdir')
end)
@@ -83,6 +91,7 @@ describe('fileio', function()
end)
it('backup #9709', function()
+ skip(is_ci('cirrus'))
clear({ args={ '-i', 'Xtest_startup_shada',
'--cmd', 'set directory=Xtest_startup_swapdir' } })
@@ -102,6 +111,7 @@ describe('fileio', function()
end)
it('backup with full path #11214', function()
+ skip(is_ci('cirrus'))
clear()
mkdir('Xtest_backupdir')
command('set backup')
@@ -114,7 +124,7 @@ describe('fileio', function()
-- Backup filename = fullpath, separators replaced with "%".
local backup_file_name = string.gsub(currentdir()..'/Xtest_startup_file1',
- iswin() and '[:/\\]' or '/', '%%') .. '~'
+ is_os('win') and '[:/\\]' or '/', '%%') .. '~'
local foo_contents = trim(read_file('Xtest_backupdir/'..backup_file_name))
local foobar_contents = trim(read_file('Xtest_startup_file1'))
@@ -122,6 +132,53 @@ describe('fileio', function()
eq('foo', foo_contents);
end)
+ it('backup symlinked files #11349', function()
+ skip(is_ci('cirrus'))
+ clear()
+
+ local initial_content = 'foo'
+ local link_file_name = 'Xtest_startup_file2'
+ local backup_file_name = link_file_name .. '~'
+
+ write_file('Xtest_startup_file1', initial_content, false)
+ lfs.link('Xtest_startup_file1', link_file_name, true)
+ command('set backup')
+ command('set backupcopy=yes')
+ command('edit ' .. link_file_name)
+ feed('Abar<esc>')
+ command('write')
+
+ local backup_raw = read_file(backup_file_name)
+ neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. "to exist but did not")
+ eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents')
+ end)
+
+
+ it('backup symlinked files in first available backupdir #11349', function()
+ skip(is_ci('cirrus'))
+ clear()
+
+ local initial_content = 'foo'
+ local backup_dir = 'Xtest_backupdir'
+ local sep = helpers.get_pathsep()
+ local link_file_name = 'Xtest_startup_file2'
+ local backup_file_name = backup_dir .. sep .. link_file_name .. '~'
+
+ write_file('Xtest_startup_file1', initial_content, false)
+ lfs.link('Xtest_startup_file1', link_file_name, true)
+ mkdir(backup_dir)
+ command('set backup')
+ command('set backupcopy=yes')
+ command('set backupdir=.__this_does_not_exist__,' .. backup_dir)
+ command('edit ' .. link_file_name)
+ feed('Abar<esc>')
+ command('write')
+
+ local backup_raw = read_file(backup_file_name)
+ neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. " to exist but did not")
+ eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents')
+ end)
+
it('readfile() on multibyte filename #10586', function()
clear()
local text = {
@@ -144,6 +201,61 @@ describe('fileio', function()
command('edit ++enc=utf32 Xtest-u8-int-max')
assert_alive()
end)
+
+ it(':w! does not show "file has been changed" warning', function()
+ clear()
+ write_file("Xtest-overwrite-forced", 'foobar')
+ command('set nofixendofline')
+ local screen = Screen.new(40,4)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4}
+ })
+ screen:attach()
+ command("set shortmess-=F")
+
+ command("e Xtest-overwrite-forced")
+ screen:expect([[
+ ^foobar |
+ {1:~ }|
+ {1:~ }|
+ "Xtest-overwrite-forced" [noeol] 1L, 6B |
+ ]])
+
+ -- Get current unix time.
+ local cur_unix_time = os.time(os.date("!*t"))
+ local future_time = cur_unix_time + 999999
+ -- Set the file's access/update time to be
+ -- greater than the time at which it was created.
+ local uv = require("luv")
+ uv.fs_utime('Xtest-overwrite-forced', future_time, future_time)
+ -- use async feed_command because nvim basically hangs on the prompt
+ feed_command("w")
+ screen:expect([[
+ {2:WARNING: The file has been changed since}|
+ {2: reading it!!!} |
+ {3:Do you really want to write to it (y/n)^?}|
+ |
+ ]])
+
+ feed("n")
+ feed("<cr>")
+ screen:expect([[
+ ^foobar |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ -- Use a screen test because the warning does not set v:errmsg.
+ command("w!")
+ screen:expect([[
+ ^foobar |
+ {1:~ }|
+ {1:~ }|
+ <erwrite-forced" [noeol] 1L, 6B written |
+ ]])
+ end)
end)
describe('tmpdir', function()
@@ -159,7 +271,7 @@ describe('tmpdir', function()
end)
after_each(function()
- expect_exit(command, ':qall!')
+ check_close()
os.remove(testlog)
end)
@@ -183,14 +295,10 @@ describe('tmpdir', function()
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
-- Assert that broken tmpdir root was handled.
- retry(nil, 1000, function()
- assert_log('tempdir root not a directory', testlog, 100)
- end)
+ assert_log('tempdir root not a directory', testlog, 100)
-- "…/nvim.<user>/" has wrong permissions:
- if iswin() then
- return -- TODO(justinmk): need setfperm/getfperm on Windows. #8244
- end
+ skip(is_os('win'), 'TODO(justinmk): need setfperm/getfperm on Windows. #8244')
os.remove(testlog)
os.remove(tmproot)
mkdir(tmproot)
@@ -198,9 +306,7 @@ describe('tmpdir', function()
clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } })
matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
-- Assert that broken tmpdir root was handled.
- retry(nil, 1000, function()
- assert_log('tempdir root has invalid permissions', testlog, 100)
- end)
+ assert_log('tempdir root has invalid permissions', testlog, 100)
end)
it('too long', function()
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 02ff18bdda..1bae626b98 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -13,7 +13,6 @@ local retry = helpers.retry
local meths = helpers.meths
local NIL = helpers.NIL
local poke_eventloop = helpers.poke_eventloop
-local iswin = helpers.iswin
local get_pathsep = helpers.get_pathsep
local pathroot = helpers.pathroot
local exec_lua = helpers.exec_lua
@@ -23,6 +22,8 @@ local expect_msg_seq = helpers.expect_msg_seq
local pcall_err = helpers.pcall_err
local matches = helpers.matches
local Screen = require('test.functional.ui.screen')
+local skip = helpers.skip
+local is_os = helpers.is_os
describe('jobs', function()
local channel
@@ -55,7 +56,7 @@ describe('jobs', function()
it('must specify env option as a dict', function()
command("let g:job_opts.env = v:true")
local _, err = pcall(function()
- if iswin() then
+ if is_os('win') then
nvim('command', "let j = jobstart('set', g:job_opts)")
else
nvim('command', "let j = jobstart('env', g:job_opts)")
@@ -68,7 +69,7 @@ describe('jobs', function()
nvim('command', "let $VAR = 'abc'")
nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
- if iswin() then
+ if is_os('win') then
nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
else
nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
@@ -87,12 +88,12 @@ describe('jobs', function()
end)
it('append environment with pty #env', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
nvim('command', "let $VAR = 'abc'")
nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.pty = v:true")
nvim('command', "let g:job_opts.env = {'TOTO': 'hello world'}")
- if iswin() then
+ if is_os('win') then
nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
else
nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
@@ -122,7 +123,7 @@ describe('jobs', function()
--
-- Rather than expecting a completely empty environment, ensure that $VAR
-- is *not* in the environment but $TOTO is.
- if iswin() then
+ if is_os('win') then
nvim('command', [[call jobstart('echo %TOTO% %VAR%', g:job_opts)]])
expect_msg_seq({
{'notification', 'stdout', {0, {'hello world %VAR%', ''}}}
@@ -141,7 +142,7 @@ describe('jobs', function()
-- Since $Toto is being set in the job, it should take precedence over the
-- global $TOTO on Windows
nvim('command', "let g:job_opts = {'env': {'Toto': 'def'}, 'stdout_buffered': v:true}")
- if iswin() then
+ if is_os('win') then
nvim('command', [[let j = jobstart('set | find /I "toto="', g:job_opts)]])
else
nvim('command', [[let j = jobstart('env | grep -i toto=', g:job_opts)]])
@@ -150,7 +151,7 @@ describe('jobs', function()
nvim('command', "let g:output = Normalize(g:job_opts.stdout)")
local actual = eval('g:output')
local expected
- if iswin() then
+ if is_os('win') then
-- Toto is normalized to TOTO so we can detect duplicates, and because
-- Windows doesn't care about case
expected = {'TOTO=def', ''}
@@ -164,7 +165,7 @@ describe('jobs', function()
it('uses &shell and &shellcmdflag if passed a string', function()
nvim('command', "let $VAR = 'abc'")
- if iswin() then
+ if is_os('win') then
nvim('command', "let j = jobstart('echo %VAR%', g:job_opts)")
else
nvim('command', "let j = jobstart('echo $VAR', g:job_opts)")
@@ -176,7 +177,7 @@ describe('jobs', function()
it('changes to given / directory', function()
nvim('command', "let g:job_opts.cwd = '/'")
- if iswin() then
+ if is_os('win') then
nvim('command', "let j = jobstart('cd', g:job_opts)")
else
nvim('command', "let j = jobstart('pwd', g:job_opts)")
@@ -191,7 +192,7 @@ describe('jobs', function()
local dir = eval("resolve(tempname())"):gsub("/", get_pathsep())
mkdir(dir)
nvim('command', "let g:job_opts.cwd = '" .. dir .. "'")
- if iswin() then
+ if is_os('win') then
nvim('command', "let j = jobstart('cd', g:job_opts)")
else
nvim('command', "let j = jobstart('pwd', g:job_opts)")
@@ -215,7 +216,7 @@ describe('jobs', function()
local dir = eval('resolve(tempname())."-bogus"')
local _, err = pcall(function()
nvim('command', "let g:job_opts.cwd = '" .. dir .. "'")
- if iswin() then
+ if is_os('win') then
nvim('command', "let j = jobstart('cd', g:job_opts)")
else
nvim('command', "let j = jobstart('pwd', g:job_opts)")
@@ -225,7 +226,7 @@ describe('jobs', function()
end)
it('error on non-executable `cwd`', function()
- if iswin() then return end -- N/A for Windows
+ skip(is_os('win'), 'Not applicable for Windows')
local dir = 'Xtest_not_executable_dir'
mkdir(dir)
@@ -248,7 +249,7 @@ describe('jobs', function()
end
local executable_jobid = new_job()
- local exe = iswin() and './test/functional/fixtures' or './test/functional/fixtures/non_executable.txt'
+ local exe = is_os('win') and './test/functional/fixtures' or './test/functional/fixtures/non_executable.txt'
eq("Vim:E475: Invalid value for argument cmd: '"..exe.."' is not executable",
pcall_err(eval, "jobstart(['"..exe.."'])"))
eq("", eval("v:errmsg"))
@@ -702,7 +703,7 @@ describe('jobs', function()
describe('jobwait', function()
before_each(function()
- if iswin() then
+ if is_os('win') then
helpers.set_shell_powershell()
end
end)
@@ -786,7 +787,7 @@ describe('jobs', function()
feed_command('call rpcnotify(g:channel, "ready") | '..
'call rpcnotify(g:channel, "wait", '..
'jobwait([jobstart("'..
- (iswin() and 'Start-Sleep 10' or 'sleep 10')..
+ (is_os('win') and 'Start-Sleep 10' or 'sleep 10')..
'; exit 55")]))')
eq({'notification', 'ready', {}}, next_msg())
feed('<c-c>')
@@ -797,7 +798,7 @@ describe('jobs', function()
feed_command('call rpcnotify(g:channel, "ready") | '..
'call rpcnotify(g:channel, "wait", '..
'jobwait([jobstart("'..
- (iswin() and 'Start-Sleep 10' or 'sleep 10')..
+ (is_os('win') and 'Start-Sleep 10' or 'sleep 10')..
'; exit 55")], 10000))')
eq({'notification', 'ready', {}}, next_msg())
feed('<c-c>')
@@ -805,7 +806,7 @@ describe('jobs', function()
end)
it('can be called recursively', function()
- if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
+ skip(is_os('win'), "TODO: Need `cat`")
source([[
let g:opts = {}
let g:counter = 0
@@ -930,7 +931,7 @@ describe('jobs', function()
-- ..c.."', '-c', '"..c.."'])")
-- Create child with several descendants.
- if iswin() then
+ if is_os('win') then
source([[
function! s:formatprocs(pid, prefix)
let result = ''
@@ -979,13 +980,13 @@ describe('jobs', function()
endfunction
]])
end
- local sleep_cmd = (iswin()
+ local sleep_cmd = (is_os('win')
and 'ping -n 31 127.0.0.1'
or 'sleep 30')
local j = eval("jobstart('"..sleep_cmd..' | '..sleep_cmd..' | '..sleep_cmd.."')")
local ppid = funcs.jobpid(j)
local children
- if iswin() then
+ if is_os('win') then
local status, result = pcall(retry, nil, nil, function()
children = meths.get_proc_children(ppid)
-- On Windows conhost.exe may exist, and
@@ -1006,7 +1007,7 @@ describe('jobs', function()
-- Assert that nvim_get_proc() sees the children.
for _, child_pid in ipairs(children) do
local info = meths.get_proc(child_pid)
- -- eq((iswin() and 'nvim.exe' or 'nvim'), info.name)
+ -- eq((is_os('win') and 'nvim.exe' or 'nvim'), info.name)
eq(ppid, info.ppid)
end
-- Kill the root of the tree.
@@ -1027,7 +1028,7 @@ describe('jobs', function()
end)
describe('running tty-test program', function()
- if helpers.pending_win32(pending) then return end
+ if skip(is_os('win')) then return end
local function next_chunk()
local rv
while true do
@@ -1124,7 +1125,7 @@ describe("pty process teardown", function()
end)
it("does not prevent/delay exit. #4798 #4900", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
-- Use a nested nvim (in :term) to test without --headless.
feed_command(":terminal '"..helpers.nvim_prog
.."' -u NONE -i NONE --cmd '"..nvim_set.."' "
diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua
index 3b1ccd9559..f682df4155 100644
--- a/test/functional/core/log_spec.lua
+++ b/test/functional/core/log_spec.lua
@@ -6,7 +6,6 @@ local eq = helpers.eq
local exec_lua = helpers.exec_lua
local expect_exit = helpers.expect_exit
local request = helpers.request
-local retry = helpers.retry
describe('log', function()
local testlog = 'Xtest_logging'
@@ -40,9 +39,7 @@ describe('log', function()
}})
local tid = _G._nvim_test_id
- retry(nil, 1000, function()
- assert_log(tid..'%.%d+%.%d +server_init:%d+: test log message', testlog, 100)
- end)
+ assert_log(tid..'%.%d+%.%d +server_init:%d+: test log message', testlog, 100)
exec_lua([[
local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict())
@@ -50,8 +47,6 @@ describe('log', function()
]])
-- Child Nvim spawned by jobstart() appends "/c" to parent name.
- retry(nil, 1000, function()
- assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100)
- end)
+ assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100)
end)
end)
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index f6fb859ccc..ab11e14a67 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -9,6 +9,8 @@ local clear = helpers.clear
local funcs = helpers.funcs
local nvim_prog_abs = helpers.nvim_prog_abs
local write_file = helpers.write_file
+local is_os = helpers.is_os
+local skip = helpers.skip
describe('Command-line option', function()
describe('-s', function()
@@ -49,12 +51,12 @@ describe('Command-line option', function()
eq(#('100500\n'), attrs.size)
end)
it('does not crash after reading from stdin in non-headless mode', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
local screen = Screen.new(40, 8)
screen:attach()
local args = {
nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE',
- '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
+ '--cmd', '"set noswapfile shortmess+=IFW fileformats=unix"',
'-s', '-'
}
diff --git a/test/functional/core/path_spec.lua b/test/functional/core/path_spec.lua
index 669bc99136..a786887bbd 100644
--- a/test/functional/core/path_spec.lua
+++ b/test/functional/core/path_spec.lua
@@ -3,14 +3,16 @@ local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local command = helpers.command
-local iswin = helpers.iswin
+local insert = helpers.insert
+local feed = helpers.feed
+local is_os = helpers.is_os
describe('path collapse', function()
local targetdir
local expected_path
local function join_path(...)
- local pathsep = (iswin() and '\\' or '/')
+ local pathsep = (is_os('win') and '\\' or '/')
return table.concat({...}, pathsep)
end
@@ -54,3 +56,15 @@ describe('path collapse', function()
eq(expected_path, eval('expand("%:p")'))
end)
end)
+
+describe('file search', function()
+ before_each(clear)
+
+ it('find multibyte file name in line #20517', function()
+ command('cd test/functional/fixtures')
+ insert('filename_with_unicode_ααα')
+ eq('', eval('expand("%")'))
+ feed('gf')
+ eq('filename_with_unicode_ααα', eval('expand("%:t")'))
+ end)
+end)
diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua
index d7bd075eb2..846d79abf3 100644
--- a/test/functional/core/remote_spec.lua
+++ b/test/functional/core/remote_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local exec_lua = helpers.exec_lua
local expect = helpers.expect
local funcs = helpers.funcs
local insert = helpers.insert
@@ -48,8 +49,8 @@ describe('Remote', function()
-- our incoming --remote calls.
local client_starter = spawn(new_argv(), false, nil, true)
set_session(client_starter)
- local client_job_id = funcs.jobstart(client_argv)
- eq({ 0 }, funcs.jobwait({client_job_id}))
+ -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
+ eq({ 0 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], client_argv))
client_starter:close()
set_session(server)
end
@@ -121,8 +122,8 @@ describe('Remote', function()
-- the event loop. If the server event loop is blocked, it can't process
-- our incoming --remote calls.
clear()
- local bogus_job_id = funcs.jobstart(bogus_argv)
- eq({2}, funcs.jobwait({bogus_job_id}))
+ -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
+ eq({ 2 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], bogus_argv))
end
it('bogus subcommand', function()
run_and_check_exit_code('--remote-bogus')
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 4f9df4010e..1be5de6488 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -12,6 +12,7 @@ local eval = helpers.eval
local exec_lua = helpers.exec_lua
local feed = helpers.feed
local funcs = helpers.funcs
+local pesc = helpers.pesc
local mkdir = helpers.mkdir
local mkdir_p = helpers.mkdir_p
local nvim_prog = helpers.nvim_prog
@@ -20,11 +21,12 @@ local read_file = helpers.read_file
local retry = helpers.retry
local rmdir = helpers.rmdir
local sleep = helpers.sleep
-local iswin = helpers.iswin
local startswith = helpers.startswith
local write_file = helpers.write_file
local meths = helpers.meths
local alter_slashes = helpers.alter_slashes
+local is_os = helpers.is_os
+local dedent = helpers.dedent
local testfile = 'Xtest_startuptime'
after_each(function()
@@ -41,10 +43,36 @@ describe('startup', function()
it('--startuptime', function()
clear({ args = {'--startuptime', testfile}})
- retry(nil, 1000, function()
- assert_log('sourcing', testfile, 100)
- assert_log("require%('vim%._editor'%)", testfile, 100)
- end)
+ assert_log('sourcing', testfile, 100)
+ assert_log("require%('vim%._editor'%)", testfile, 100)
+ end)
+
+ it('-D does not hang #12647', function()
+ clear()
+ local screen
+ screen = Screen.new(60, 7)
+ screen:attach()
+ command([[let g:id = termopen('"]]..nvim_prog..
+ [[" -u NONE -i NONE --cmd "set noruler" -D')]])
+ screen:expect([[
+ ^ |
+ |
+ Entering Debug mode. Type "cont" to continue. |
+ nvim_exec() |
+ cmd: aunmenu * |
+ > |
+ |
+ ]])
+ command([[call chansend(g:id, "cont\n")]])
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] |
+ |
+ |
+ ]])
end)
end)
@@ -57,6 +85,124 @@ describe('startup', function()
os.remove('Xtest_startup_ttyout')
end)
+ describe('-l Lua', function()
+ local function assert_l_out(expected, nvim_args, lua_args, script, input)
+ local args = { nvim_prog }
+ vim.list_extend(args, nvim_args or {})
+ vim.list_extend(args, { '-l', (script or 'test/functional/fixtures/startup.lua') })
+ vim.list_extend(args, lua_args or {})
+ local out = funcs.system(args, input):gsub('\r\n', '\n')
+ return eq(dedent(expected), out)
+ end
+
+ it('failure modes', function()
+ -- nvim -l <empty>
+ matches('nvim%.?e?x?e?: Argument missing after: "%-l"', funcs.system({ nvim_prog, '-l' }))
+ eq(1, eval('v:shell_error'))
+ end)
+
+ it('os.exit() sets Nvim exitcode', function()
+ -- nvim -l foo.lua -arg1 -- a b c
+ assert_l_out([[
+ bufs:
+ nvim args: 7
+ lua args: { "-arg1", "--exitcode", "73", "--arg2",
+ [0] = "test/functional/fixtures/startup.lua"
+ }]],
+ {},
+ { '-arg1', "--exitcode", "73", '--arg2' }
+ )
+ eq(73, eval('v:shell_error'))
+ end)
+
+ it('Lua-error sets Nvim exitcode', function()
+ eq(0, eval('v:shell_error'))
+ matches('E5113: .* my pearls!!',
+ funcs.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' }))
+ eq(1, eval('v:shell_error'))
+ matches('E5113: .* %[string "error%("whoa"%)"%]:1: whoa',
+ funcs.system({ nvim_prog, '-l', '-' }, 'error("whoa")'))
+ eq(1, eval('v:shell_error'))
+ end)
+
+ it('executes stdin "-"', function()
+ assert_l_out('arg0=- args=2 whoa',
+ nil,
+ { 'arg1', 'arg 2' },
+ '-',
+ "print(('arg0=%s args=%d %s'):format(_G.arg[0], #_G.arg, 'whoa'))")
+ assert_l_out('biiig input: 1000042',
+ nil,
+ nil,
+ '-',
+ ('print("biiig input: "..("%s"):len())'):format(string.rep('x', (1000 * 1000) + 42)))
+ eq(0, eval('v:shell_error'))
+ end)
+
+ it('sets _G.arg', function()
+ -- nvim -l foo.lua [args]
+ assert_l_out([[
+ bufs:
+ nvim args: 7
+ lua args: { "-arg1", "--arg2", "--", "arg3",
+ [0] = "test/functional/fixtures/startup.lua"
+ }]],
+ {},
+ { '-arg1', '--arg2', '--', 'arg3' }
+ )
+ eq(0, eval('v:shell_error'))
+
+ -- nvim file1 file2 -l foo.lua -arg1 -- file3 file4
+ assert_l_out([[
+ bufs: file1 file2
+ nvim args: 10
+ lua args: { "-arg1", "arg 2", "--", "file3", "file4",
+ [0] = "test/functional/fixtures/startup.lua"
+ }]],
+ { 'file1', 'file2', },
+ { '-arg1', 'arg 2', '--', 'file3', 'file4' }
+ )
+ eq(0, eval('v:shell_error'))
+
+ -- nvim -l foo.lua <vim args>
+ assert_l_out([[
+ bufs:
+ nvim args: 5
+ lua args: { "-c", "set wrap?",
+ [0] = "test/functional/fixtures/startup.lua"
+ }]],
+ {},
+ { '-c', 'set wrap?' }
+ )
+ eq(0, eval('v:shell_error'))
+
+ -- nvim <vim args> -l foo.lua <vim args>
+ assert_l_out(
+ -- luacheck: ignore 611 (Line contains only whitespaces)
+ [[
+ wrap
+
+ bufs:
+ nvim args: 7
+ lua args: { "-c", "set wrap?",
+ [0] = "test/functional/fixtures/startup.lua"
+ }]],
+ { '-c', 'set wrap?' },
+ { '-c', 'set wrap?' }
+ )
+ eq(0, eval('v:shell_error'))
+ end)
+
+ it('disables swapfile/shada/config/plugins', function()
+ assert_l_out('updatecount=0 shadafile=NONE loadplugins=false scriptnames=1',
+ nil,
+ nil,
+ '-',
+ [[print(('updatecount=%d shadafile=%s loadplugins=%s scriptnames=%d'):format(
+ vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.split(vim.fn.execute('scriptnames'),'\n'))))]])
+ end)
+ end)
+
it('pipe at both ends: has("ttyin")==0 has("ttyout")==0', function()
-- system() puts a pipe at both ends.
local out = funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless',
@@ -65,6 +211,7 @@ describe('startup', function()
'+q' })
eq('0 0', out)
end)
+
it('with --embed: has("ttyin")==0 has("ttyout")==0', function()
local screen = Screen.new(25, 3)
-- Remote UI connected by --embed.
@@ -76,10 +223,11 @@ describe('startup', function()
0 0 |
]])
end)
+
it('in a TTY: has("ttyin")==1 has("ttyout")==1', function()
local screen = Screen.new(25, 4)
screen:attach()
- if iswin() then
+ if is_os('win') then
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end
-- Running in :terminal
@@ -94,8 +242,9 @@ describe('startup', function()
|
]])
end)
+
it('output to pipe: has("ttyin")==1 has("ttyout")==0', function()
- if iswin() then
+ if is_os('win') then
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end
-- Running in :terminal
@@ -110,8 +259,9 @@ describe('startup', function()
read_file('Xtest_startup_ttyout'))
end)
end)
+
it('input from pipe: has("ttyin")==0 has("ttyout")==1', function()
- if iswin() then
+ if is_os('win') then
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end
-- Running in :terminal
@@ -127,10 +277,11 @@ describe('startup', function()
read_file('Xtest_startup_ttyout'))
end)
end)
+
it('input from pipe (implicit) #7679', function()
local screen = Screen.new(25, 4)
screen:attach()
- if iswin() then
+ if is_os('win') then
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end
-- Running in :terminal
@@ -146,6 +297,7 @@ describe('startup', function()
|
]])
end)
+
it('input from pipe + file args #7679', function()
eq('ohyeah\r\n0 0 bufs=3',
funcs.system({nvim_prog, '-n', '-u', 'NONE', '-i', 'NONE', '--headless',
@@ -237,11 +389,11 @@ describe('startup', function()
it('-es/-Es disables swapfile, user config #8540', function()
for _,arg in ipairs({'-es', '-Es'}) do
local out = funcs.system({nvim_prog, arg,
- '+set swapfile? updatecount? shada?',
+ '+set swapfile? updatecount? shadafile?',
"+put =execute('scriptnames')", '+%print'})
local line1 = string.match(out, '^.-\n')
-- updatecount=0 means swapfile was disabled.
- eq(" swapfile updatecount=0 shada=!,'100,<50,s10,h\n", line1)
+ eq(" swapfile updatecount=0 shadafile=\n", line1)
-- Standard plugins were loaded, but not user config.
eq('health.vim', string.match(out, 'health.vim'))
eq(nil, string.match(out, 'init.vim'))
@@ -265,11 +417,13 @@ describe('startup', function()
{ 'put =mode(1)', 'print', '' }))
end)
- it('fails on --embed with -es/-Es', function()
- matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es',
+ it('fails on --embed with -es/-Es/-l', function()
+ matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l',
funcs.system({nvim_prog, '--embed', '-es' }))
- matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es',
+ matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l',
funcs.system({nvim_prog, '--embed', '-Es' }))
+ matches('nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l',
+ funcs.system({nvim_prog, '--embed', '-l', 'foo.lua' }))
end)
it('does not crash if --embed is given twice', function()
@@ -354,7 +508,9 @@ describe('startup', function()
local function pack_clear(cmd)
-- add packages after config dir in rtp but before config/after
- clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
+ clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'},
+ args_rm={'runtimepath'},
+ }
end
@@ -462,6 +618,19 @@ describe('startup', function()
clear{args={'--cmd', 'set packpath^=test/functional/fixtures', '--cmd', [[ lua _G.test_loadorder = {} vim.cmd "runtime! filen.lua" ]]}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
eq({'ordinary', 'FANCY', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
end)
+
+ it('window widths are correct when modelines set &columns with tabpages', function()
+ write_file('tab1.noft', 'vim: columns=81')
+ write_file('tab2.noft', 'vim: columns=81')
+ finally(function()
+ os.remove('tab1.noft')
+ os.remove('tab2.noft')
+ end)
+ clear({args = {'-p', 'tab1.noft', 'tab2.noft'}})
+ eq(81, meths.win_get_width(0))
+ command('tabnext')
+ eq(81, meths.win_get_width(0))
+ end)
end)
describe('sysinit', function()
@@ -516,32 +685,6 @@ describe('sysinit', function()
eval('printf("loaded %d xdg %d vim %d", g:loaded, get(g:, "xdg", 0), get(g:, "vim", 0))'))
end)
- it('fixed hang issue with -D (#12647)', function()
- local screen
- screen = Screen.new(60, 7)
- screen:attach()
- command([[let g:id = termopen('"]]..nvim_prog..
- [[" -u NONE -i NONE --cmd "set noruler" -D')]])
- screen:expect([[
- ^ |
- Entering Debug mode. Type "cont" to continue. |
- nvim_exec() |
- cmd: aunmenu * |
- > |
- <" -u NONE -i NONE --cmd "set noruler" -D 1,1 All|
- |
- ]])
- command([[call chansend(g:id, "cont\n")]])
- screen:expect([[
- ^ |
- ~ |
- ~ |
- [No Name] |
- |
- <" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All|
- |
- ]])
- end)
end)
describe('user config init', function()
@@ -574,7 +717,81 @@ describe('user config init', function()
eq(funcs.fnamemodify(init_lua_path, ':p'), eval('$MYVIMRC'))
end)
- describe 'with explicitly provided config'(function()
+ describe('with existing .exrc in cwd', function()
+ local exrc_path = '.exrc'
+ local xstate = 'Xstate'
+
+ local function setup_exrc_file(filename)
+ exrc_path = filename
+
+ if string.find(exrc_path, "%.lua$") then
+ write_file(exrc_path, string.format([[
+ vim.g.exrc_file = "%s"
+ ]], exrc_path))
+ else
+ write_file(exrc_path, string.format([[
+ let g:exrc_file = "%s"
+ ]], exrc_path))
+ end
+ end
+
+ before_each(function()
+ write_file(init_lua_path, [[
+ vim.o.exrc = true
+ vim.g.exrc_file = '---'
+ ]])
+ mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim'))
+ end)
+
+ after_each(function()
+ os.remove(exrc_path)
+ rmdir(xstate)
+ end)
+
+ for _, filename in ipairs({ '.exrc', '.nvimrc', '.nvim.lua' }) do
+ it('loads ' .. filename, function ()
+ setup_exrc_file(filename)
+
+ clear{ args_rm = {'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_STATE_HOME=xstate } }
+ -- The 'exrc' file is not trusted, and the prompt is skipped because there is no UI.
+ eq('---', eval('g:exrc_file'))
+
+ local screen = Screen.new(50, 8)
+ screen:attach()
+ funcs.termopen({nvim_prog})
+ screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny, (a)llow:') })
+ -- `i` to enter Terminal mode, `a` to allow
+ feed('ia')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] 0,0-1 All|
+ |
+ -- TERMINAL -- |
+ ]])
+ feed(':echo g:exrc_file<CR>')
+ screen:expect(string.format([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] 0,0-1 All|
+ %s%s|
+ -- TERMINAL -- |
+ ]], filename, string.rep(' ', 50 - #filename)))
+
+ clear{ args_rm = {'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_STATE_HOME=xstate } }
+ -- The 'exrc' file is now trusted.
+ eq(filename, eval('g:exrc_file'))
+ end)
+ end
+ end)
+
+ describe('with explicitly provided config', function()
local custom_lua_path = table.concat({xhome, 'custom.lua'}, pathsep)
before_each(function()
write_file(custom_lua_path, [[
@@ -589,7 +806,7 @@ describe('user config init', function()
end)
end)
- describe 'VIMRC also exists'(function()
+ describe('VIMRC also exists', function()
before_each(function()
write_file(table.concat({xconfig, 'nvim', 'init.vim'}, pathsep), [[
let g:vim_rc = 1
@@ -635,7 +852,7 @@ describe('runtime:', function()
end)
it('loads plugin/*.lua from start packages', function()
- local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'catagory',
+ local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'category',
'start', 'test_plugin'}, pathsep)
local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep)
local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'},
@@ -663,7 +880,7 @@ describe('runtime:', function()
end)
it('loads plugin/*.lua from site packages', function()
- local nvimdata = iswin() and "nvim-data" or "nvim"
+ local nvimdata = is_os('win') and "nvim-data" or "nvim"
local plugin_path = table.concat({xdata, nvimdata, 'site', 'pack', 'xa', 'start', 'yb'}, pathsep)
local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep)
local plugin_after_path = table.concat({plugin_path, 'after', 'plugin'}, pathsep)
diff --git a/test/functional/editor/K_spec.lua b/test/functional/editor/K_spec.lua
index 8ad81ac3d6..3b5580540f 100644
--- a/test/functional/editor/K_spec.lua
+++ b/test/functional/editor/K_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
-local eq, clear, eval, feed, retry =
- helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.retry
+local eq, clear, eval, feed, meths, retry =
+ helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.meths, helpers.retry
describe('K', function()
local test_file = 'K_spec_out'
@@ -58,4 +58,11 @@ describe('K', function()
helpers.neq(bufnr, eval('bufnr()'))
end)
+ it('empty string falls back to :help #19298', function()
+ meths.set_option('keywordprg', '')
+ meths.buf_set_lines(0, 0, -1, true, {'doesnotexist'})
+ feed('K')
+ eq('E149: Sorry, no help for doesnotexist', meths.get_vvar('errmsg'))
+ end)
+
end)
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index 6cdac3c079..22857efe5b 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -935,6 +935,9 @@ describe('completion', function()
eq({'api'}, funcs.getcompletion('vim.ap', 'lua'))
eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua'))
eq({'vim'}, funcs.getcompletion('print(vi', 'lua'))
+ -- fuzzy completion is not supported, so the result should be the same
+ command('set wildoptions+=fuzzy')
+ eq({'vim'}, funcs.getcompletion('vi', 'lua'))
end)
end)
@@ -1029,7 +1032,8 @@ describe('completion', function()
]])
end)
- it('TextChangedP autocommand', function()
+ -- oldtest: Test_ChangedP()
+ it('TextChangedI and TextChangedP autocommands', function()
curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar'})
source([[
set complete=. completeopt=menuone
@@ -1128,6 +1132,49 @@ describe('completion', function()
call cursor(4, 1)
]])
+ -- v:event.size should be set with ext_popupmenu #20646
+ screen:set_option('ext_popupmenu', true)
+ feed('Sf<C-N>')
+ screen:expect({grid = [[
+ foo |
+ bar |
+ foobar |
+ f^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{5:Back at original} |
+ ]], popupmenu = {
+ anchor = { 1, 3, 0 },
+ items = { { "foo", "", "", "" }, { "foobar", "", "", "" } },
+ pos = -1
+ }})
+ eq({completed_item = {}, width = 0,
+ height = 2, size = 2,
+ col = 0, row = 4, scrollbar = false},
+ eval('g:event'))
+ feed('oob')
+ screen:expect({grid = [[
+ foo |
+ bar |
+ foobar |
+ foob^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:-- Keyword completion (^N^P) }{5:Back at original} |
+ ]], popupmenu = {
+ anchor = { 1, 3, 0 },
+ items = { { "foobar", "", "", "" } },
+ pos = -1
+ }})
+ eq({completed_item = {}, width = 0,
+ height = 1, size = 1,
+ col = 0, row = 4, scrollbar = false},
+ eval('g:event'))
+ feed('<Esc>')
+ screen:set_option('ext_popupmenu', false)
+
feed('Sf<C-N>')
screen:expect([[
foo |
diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua
index 2440867c6e..b3b190ef79 100644
--- a/test/functional/editor/mark_spec.lua
+++ b/test/functional/editor/mark_spec.lua
@@ -40,59 +40,59 @@ describe('named marks', function()
it("errors when set out of range with :mark", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "1000mark x")
- eq("Vim(mark):E16: Invalid range: 1000mark x", err)
+ eq("nvim_exec(): Vim(mark):E16: Invalid range: 1000mark x", err)
end)
it("errors when set out of range with :k", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "1000kx")
- eq("Vim(k):E16: Invalid range: 1000kx", err)
+ eq("nvim_exec(): Vim(k):E16: Invalid range: 1000kx", err)
end)
it("errors on unknown mark name with :mark", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "mark #")
- eq("Vim(mark):E191: Argument must be a letter or forward/backward quote", err)
+ eq("nvim_exec(): Vim(mark):E191: Argument must be a letter or forward/backward quote", err)
end)
it("errors on unknown mark name with '", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "normal! '#")
- eq("Vim(normal):E78: Unknown mark", err)
+ eq("nvim_exec(): Vim(normal):E78: Unknown mark", err)
end)
it("errors on unknown mark name with `", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "normal! `#")
- eq("Vim(normal):E78: Unknown mark", err)
+ eq("nvim_exec(): Vim(normal):E78: Unknown mark", err)
end)
it("errors when moving to a mark that is not set with '", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "normal! 'z")
- eq("Vim(normal):E20: Mark not set", err)
+ eq("nvim_exec(): Vim(normal):E20: Mark not set", err)
err = pcall_err(helpers.exec_capture, "normal! '.")
- eq("Vim(normal):E20: Mark not set", err)
+ eq("nvim_exec(): Vim(normal):E20: Mark not set", err)
end)
it("errors when moving to a mark that is not set with `", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "normal! `z")
- eq("Vim(normal):E20: Mark not set", err)
+ eq("nvim_exec(): Vim(normal):E20: Mark not set", err)
err = pcall_err(helpers.exec_capture, "normal! `>")
- eq("Vim(normal):E20: Mark not set", err)
+ eq("nvim_exec(): Vim(normal):E20: Mark not set", err)
end)
it("errors when moving to a global mark that is not set with '", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "normal! 'Z")
- eq("Vim(normal):E20: Mark not set", err)
+ eq("nvim_exec(): Vim(normal):E20: Mark not set", err)
end)
it("errors when moving to a global mark that is not set with `", function()
command("edit " .. file1)
local err = pcall_err(helpers.exec_capture, "normal! `Z")
- eq("Vim(normal):E20: Mark not set", err)
+ eq("nvim_exec(): Vim(normal):E20: Mark not set", err)
end)
it("can move to them using '", function()
@@ -153,7 +153,7 @@ describe('named marks', function()
command("next")
command("bw! " .. file1 )
local err = pcall_err(helpers.exec_capture, "normal! 'A")
- eq("Vim(normal):E92: Buffer 1 not found", err)
+ eq("nvim_exec(): Vim(normal):E92: Buffer 1 not found", err)
os.remove(file1)
end)
@@ -330,7 +330,7 @@ describe('named marks view', function()
os.remove(file2)
end)
- it('is restored', function()
+ it('is restored in normal mode but not op-pending mode', function()
local screen = Screen.new(5, 8)
screen:attach()
command("edit " .. file1)
@@ -358,6 +358,18 @@ describe('named marks view', function()
8 line |
|
]])
+ -- not in op-pending mode #20886
+ feed("ggj=`a")
+ screen:expect([[
+ 1 line |
+ ^2 line |
+ 3 line |
+ 4 line |
+ 5 line |
+ 6 line |
+ 7 line |
+ |
+ ]])
end)
it('is restored across files', function()
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index e3d3cdbd85..cd51a65be3 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -6,12 +6,20 @@ local expect = helpers.expect
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
+local curbuf_contents = helpers.curbuf_contents
describe('insert-mode', function()
before_each(function()
clear()
end)
+ it('indents only once after "!" keys #12894', function()
+ command('let counter = []')
+ command('set indentexpr=len(add(counter,0))')
+ feed('i<C-F>x')
+ eq(' x', curbuf_contents())
+ end)
+
it('CTRL-@', function()
-- Inserts last-inserted text, leaves insert-mode.
insert('hello')
diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index 849a02c28b..a7f629a76b 100644
--- a/test/functional/editor/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
@@ -9,6 +9,9 @@ local feed = helpers.feed
local eval = helpers.eval
local exec = helpers.exec
local funcs = helpers.funcs
+local meths = helpers.meths
+local curwin = helpers.curwin
+local assert_alive = helpers.assert_alive
describe('tabpage', function()
before_each(clear)
@@ -54,6 +57,45 @@ describe('tabpage', function()
neq(999, eval('g:win_closed'))
end)
+ it('no segfault with strange WinClosed autocommand #20290', function()
+ pcall(exec, [[
+ set nohidden
+ edit Xa
+ split Xb
+ tab split
+ new
+ autocmd WinClosed * tabprev | bwipe!
+ close
+ ]])
+ assert_alive()
+ end)
+
+ it('nvim_win_close and nvim_win_hide update tabline #20285', function()
+ eq(1, #meths.list_tabpages())
+ eq({1, 1}, funcs.win_screenpos(0))
+ local win1 = curwin().id
+
+ command('tabnew')
+ eq(2, #meths.list_tabpages())
+ eq({2, 1}, funcs.win_screenpos(0))
+ local win2 = curwin().id
+
+ meths.win_close(win1, true)
+ eq(win2, curwin().id)
+ eq(1, #meths.list_tabpages())
+ eq({1, 1}, funcs.win_screenpos(0))
+
+ command('tabnew')
+ eq(2, #meths.list_tabpages())
+ eq({2, 1}, funcs.win_screenpos(0))
+ local win3 = curwin().id
+
+ meths.win_hide(win2)
+ eq(win3, curwin().id)
+ eq(1, #meths.list_tabpages())
+ eq({1, 1}, funcs.win_screenpos(0))
+ end)
+
it('switching tabpage after setting laststatus=3 #19591', function()
local screen = Screen.new(40, 8)
screen:set_default_attr_ids({
@@ -102,4 +144,10 @@ describe('tabpage', function()
command(' silent :keepalt :: ::: silent! -2 tabmove')
eq(1, funcs.nvim_tabpage_get_number(0))
end)
+
+ it(':tabs does not overflow IObuff with long path with comma #20850', function()
+ meths.buf_set_name(0, ('x'):rep(1024) .. ',' .. ('x'):rep(1024))
+ command('tabs')
+ assert_alive()
+ end)
end)
diff --git a/test/functional/editor/undo_spec.lua b/test/functional/editor/undo_spec.lua
index a041428cdc..d66ab352ef 100644
--- a/test/functional/editor/undo_spec.lua
+++ b/test/functional/editor/undo_spec.lua
@@ -9,6 +9,8 @@ local feed = helpers.feed
local feed_command = helpers.feed_command
local insert = helpers.insert
local funcs = helpers.funcs
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
local function lastmessage()
local messages = funcs.split(funcs.execute('messages'), '\n')
@@ -67,6 +69,79 @@ describe('u CTRL-R g- g+', function()
undo_and_redo(4, 'u', '<C-r>', '1')
undo_and_redo(4, 'g-', 'g+', '1')
end)
+
+ describe('undo works correctly when writing in Insert mode', function()
+ before_each(function()
+ exec([[
+ edit Xtestfile.txt
+ set undolevels=100 undofile
+ write
+ ]])
+ end)
+
+ after_each(function()
+ command('bwipe!')
+ os.remove('Xtestfile.txt')
+ os.remove('Xtestfile.txt.un~')
+ end)
+
+ -- oldtest: Test_undo_after_write()
+ it('using <Cmd> mapping', function()
+ command('imap . <Cmd>write<CR>')
+ feed('Otest.<CR>boo!!!<Esc>')
+ expect([[
+ test
+ boo!!!
+ ]])
+
+ feed('u')
+ expect([[
+ test
+ ]])
+
+ feed('u')
+ expect('')
+ end)
+
+ it('using Lua mapping', function()
+ exec_lua([[
+ vim.api.nvim_set_keymap('i', '.', '', {callback = function()
+ vim.cmd('write')
+ end})
+ ]])
+ feed('Otest.<CR>boo!!!<Esc>')
+ expect([[
+ test
+ boo!!!
+ ]])
+
+ feed('u')
+ expect([[
+ test
+ ]])
+
+ feed('u')
+ expect('')
+ end)
+
+ it('using RPC call', function()
+ feed('Otest')
+ command('write')
+ feed('<CR>boo!!!<Esc>')
+ expect([[
+ test
+ boo!!!
+ ]])
+
+ feed('u')
+ expect([[
+ test
+ ]])
+
+ feed('u')
+ expect('')
+ end)
+ end)
end)
describe(':undo! command', function()
diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua
index 42a811f5da..5ed71651c7 100644
--- a/test/functional/ex_cmds/cd_spec.lua
+++ b/test/functional/ex_cmds/cd_spec.lua
@@ -9,6 +9,8 @@ local clear = helpers.clear
local command = helpers.command
local exc_exec = helpers.exc_exec
local pathsep = helpers.get_pathsep()
+local skip = helpers.skip
+local is_os = helpers.is_os
-- These directories will be created for testing
local directories = {
@@ -279,9 +281,7 @@ describe("getcwd()", function ()
end)
it("returns empty string if working directory does not exist", function()
- if helpers.iswin() then
- return
- end
+ skip(is_os('win'))
command("cd "..directories.global)
command("call delete('../"..directories.global.."', 'd')")
eq("", helpers.eval("getcwd()"))
diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua
index 21adcf37da..afa6b519d5 100644
--- a/test/functional/ex_cmds/dict_notifications_spec.lua
+++ b/test/functional/ex_cmds/dict_notifications_spec.lua
@@ -4,6 +4,7 @@ local clear, nvim, source = helpers.clear, helpers.nvim, helpers.source
local insert = helpers.insert
local eq, next_msg = helpers.eq, helpers.next_msg
local exc_exec = helpers.exc_exec
+local exec_lua = helpers.exec_lua
local command = helpers.command
local eval = helpers.eval
@@ -21,6 +22,8 @@ describe('VimL dictionary notifications', function()
-- t:) and a dictionary variable, so we generate them in the following
-- function.
local function gentests(dict_expr, dict_init)
+ local is_g = dict_expr == 'g:'
+
local function update(opval, key)
if not key then
key = 'watched'
@@ -32,6 +35,28 @@ describe('VimL dictionary notifications', function()
end
end
+ local function update_with_api(opval, key)
+ if not key then
+ key = 'watched'
+ end
+ if opval == '' then
+ exec_lua(('vim.api.nvim_del_var(\'%s\')'):format(key))
+ else
+ exec_lua(('vim.api.nvim_set_var(\'%s\', %s)'):format(key, opval))
+ end
+ end
+
+ local function update_with_vim_g(opval, key)
+ if not key then
+ key = 'watched'
+ end
+ if opval == '' then
+ exec_lua(('vim.g.%s = nil'):format(key))
+ else
+ exec_lua(('vim.g.%s %s'):format(key, opval))
+ end
+ end
+
local function verify_echo()
-- helper to verify that no notifications are sent after certain change
-- to a dict
@@ -76,6 +101,18 @@ describe('VimL dictionary notifications', function()
update('', 'watched2')
update('')
verify_echo()
+ if is_g then
+ update_with_api('"test"')
+ update_with_api('"test2"', 'watched2')
+ update_with_api('', 'watched2')
+ update_with_api('')
+ verify_echo()
+ update_with_vim_g('= "test"')
+ update_with_vim_g('= "test2"', 'watched2')
+ update_with_vim_g('', 'watched2')
+ update_with_vim_g('')
+ verify_echo()
+ end
end)
it('is not triggered when unwatched keys are updated', function()
@@ -83,6 +120,16 @@ describe('VimL dictionary notifications', function()
update('.= "noop2"', 'unwatched')
update('', 'unwatched')
verify_echo()
+ if is_g then
+ update_with_api('"noop"', 'unwatched')
+ update_with_api('vim.g.unwatched .. "noop2"', 'unwatched')
+ update_with_api('', 'unwatched')
+ verify_echo()
+ update_with_vim_g('= "noop"', 'unwatched')
+ update_with_vim_g('= vim.g.unwatched .. "noop2"', 'unwatched')
+ update_with_vim_g('', 'unwatched')
+ verify_echo()
+ end
end)
it('is triggered by remove()', function()
@@ -92,6 +139,22 @@ describe('VimL dictionary notifications', function()
verify_value({old = 'test'})
end)
+ if is_g then
+ it('is triggered by remove() when updated with nvim_*_var', function()
+ update_with_api('"test"')
+ verify_value({new = 'test'})
+ nvim('command', 'call remove('..dict_expr..', "watched")')
+ verify_value({old = 'test'})
+ end)
+
+ it('is triggered by remove() when updated with vim.g', function()
+ update_with_vim_g('= "test"')
+ verify_value({new = 'test'})
+ nvim('command', 'call remove('..dict_expr..', "watched")')
+ verify_value({old = 'test'})
+ end)
+ end
+
it('is triggered by extend()', function()
update('= "xtend"')
verify_value({new = 'xtend'})
diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua
index c6bdd017bd..ec912053b2 100644
--- a/test/functional/ex_cmds/map_spec.lua
+++ b/test/functional/ex_cmds/map_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
local exec = helpers.exec
+local exec_capture = helpers.exec_capture
local feed = helpers.feed
local meths = helpers.meths
local clear = helpers.clear
@@ -30,12 +31,12 @@ describe(':*map', function()
expect('-foo-')
end)
- it('shows <nop> as mapping rhs', function()
+ it('shows <Nop> as mapping rhs', function()
command('nmap asdf <Nop>')
eq([[
n asdf <Nop>]],
- helpers.exec_capture('nmap asdf'))
+ exec_capture('nmap asdf'))
end)
it('mappings with description can be filtered', function()
@@ -48,7 +49,7 @@ n asdf3 qwert
do the other thing
n asdf1 qwert
do the one thing]],
- helpers.exec_capture('filter the nmap'))
+ exec_capture('filter the nmap'))
end)
it('<Plug> mappings ignore nore', function()
@@ -84,6 +85,12 @@ n asdf1 qwert
eq(2, meths.eval('x'))
eq('Some te', eval("getline('.')"))
end)
+
+ it(':unmap with rhs works when lhs is in another bucket #21530', function()
+ command('map F <Plug>Foo')
+ command('unmap <Plug>Foo')
+ eq('\nNo mapping found', exec_capture('map F'))
+ end)
end)
describe('Screen', function()
@@ -161,6 +168,7 @@ describe('Screen', function()
]])
end)
+ -- oldtest: Test_expr_map_restore_cursor()
it('cursor is restored after :map <expr> which redraws statusline vim-patch:8.1.2336', function()
exec([[
call setline(1, ['one', 'two', 'three'])
@@ -246,6 +254,7 @@ describe('Screen', function()
]])
end)
+ -- oldtest: Test_map_listing()
it('listing mappings clears command line vim-patch:8.2.4401', function()
screen:try_resize(40, 5)
command('nmap a b')
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index ee8da2932d..0a0c7ca410 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -5,7 +5,6 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local get_pathsep = helpers.get_pathsep
-local iswin = helpers.iswin
local eq = helpers.eq
local neq = helpers.neq
local funcs = helpers.funcs
@@ -14,6 +13,8 @@ local pesc = helpers.pesc
local rmdir = helpers.rmdir
local sleep = helpers.sleep
local meths = helpers.meths
+local skip = helpers.skip
+local is_os = helpers.is_os
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
@@ -177,7 +178,7 @@ describe(':mksession', function()
command('cd ' .. cwd_dir)
command('mksession ' .. session_path)
command('%bwipeout!')
- if iswin() then
+ if is_os('win') then
sleep(100) -- Make sure all child processes have exited.
end
@@ -188,16 +189,13 @@ describe(':mksession', function()
local expected_cwd = cwd_dir .. '/' .. tab_dir
matches('^term://' .. pesc(expected_cwd) .. '//%d+:', funcs.expand('%'))
command('%bwipeout!')
- if iswin() then
+ if is_os('win') then
sleep(100) -- Make sure all child processes have exited.
end
end)
it('restores CWD for :terminal buffer at root directory #16988', function()
- if iswin() then
- pending('N/A for Windows')
- return
- end
+ skip(is_os('win'), 'N/A for Windows')
local screen
local cwd_dir = funcs.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
diff --git a/test/functional/ex_cmds/normal_spec.lua b/test/functional/ex_cmds/normal_spec.lua
index f6e7dd2b3a..009f1d6516 100644
--- a/test/functional/ex_cmds/normal_spec.lua
+++ b/test/functional/ex_cmds/normal_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local command = helpers.command
+local funcs = helpers.funcs
local feed = helpers.feed
local expect = helpers.expect
local eq = helpers.eq
@@ -8,20 +9,30 @@ local eval = helpers.eval
before_each(clear)
-describe(':normal', function()
+describe(':normal!', function()
it('can get out of Insert mode if called from Ex mode #17924', function()
feed('gQnormal! Ifoo<CR>')
expect('foo')
end)
- it('normal! does not execute command in Ex mode when running out of characters', function()
+ it('does not execute command in Ex mode when running out of characters', function()
command('let g:var = 0')
command('normal! gQlet g:var = 1')
eq(0, eval('g:var'))
end)
- it('normal! gQinsert does not hang #17980', function()
+ it('gQinsert does not hang #17980', function()
command('normal! gQinsert')
expect('')
end)
+
+ it('can stop Visual mode without closing cmdwin vim-patch:9.0.0234', function()
+ feed('q:')
+ feed('v')
+ eq('v', funcs.mode(1))
+ eq(':', funcs.getcmdwintype())
+ command('normal! \027')
+ eq('n', funcs.mode(1))
+ eq(':', funcs.getcmdwintype())
+ end)
end)
diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua
index 94b7fa1a84..4d9d8eeb90 100644
--- a/test/functional/ex_cmds/quickfix_commands_spec.lua
+++ b/test/functional/ex_cmds/quickfix_commands_spec.lua
@@ -1,5 +1,7 @@
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 funcs = helpers.funcs
@@ -123,3 +125,22 @@ describe('quickfix', function()
os.remove(file)
end)
end)
+
+it(':vimgrep can specify Unicode pattern without delimiters', function()
+ eq('Vim(vimgrep):E480: No match: →', exc_exec('vimgrep → test/functional/fixtures/tty-test.c'))
+ local screen = Screen.new(40, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {reverse = true}, -- IncSearch
+ })
+ screen:attach()
+ feed('i→<Esc>:vimgrep →')
+ screen:expect([[
+ {1:→} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :vimgrep →^ |
+ ]])
+end)
diff --git a/test/functional/ex_cmds/quit_spec.lua b/test/functional/ex_cmds/quit_spec.lua
index fe138a24c8..3680801dae 100644
--- a/test/functional/ex_cmds/quit_spec.lua
+++ b/test/functional/ex_cmds/quit_spec.lua
@@ -7,7 +7,7 @@ describe(':qa', function()
end)
it('verify #3334', function()
- -- just testing if 'qa' passed as a program argument wont result in memory
+ -- just testing if 'qa' passed as a program argument won't result in memory
-- errors
end)
end)
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 163ded43f9..64c3464be7 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -14,9 +14,9 @@ local eval = helpers.eval
local exec_capture = helpers.exec_capture
local neq = helpers.neq
local matches = helpers.matches
-local iswin = helpers.iswin
local mkdir = helpers.mkdir
local rmdir = helpers.rmdir
+local is_os = helpers.is_os
describe(':source', function()
before_each(function()
@@ -44,7 +44,7 @@ describe(':source', function()
end)
it("changing 'shellslash' changes the result of expand()", function()
- if not iswin() then
+ if not is_os('win') then
pending("'shellslash' only works on Windows")
return
end
@@ -104,7 +104,7 @@ describe(':source', function()
eq("0zBEEFCAFE", meths.exec('echo d', true))
exec('set cpoptions+=C')
- eq('Vim(let):E15: Invalid expression: #{', exc_exec('source'))
+ eq('Vim(let):E723: Missing end of Dictionary \'}\': ', exc_exec('source'))
end)
it('selection in current buffer', function()
@@ -138,7 +138,7 @@ describe(':source', function()
eq('Vim(echo):E117: Unknown function: s:C', exc_exec('echo D()'))
exec('set cpoptions+=C')
- eq('Vim(let):E15: Invalid expression: #{', exc_exec("'<,'>source"))
+ eq('Vim(let):E723: Missing end of Dictionary \'}\': ', exc_exec("'<,'>source"))
end)
it('does not break if current buffer is modified while sourced', function()
@@ -166,6 +166,7 @@ describe(':source', function()
vim.g.sourced_lua = 1
vim.g.sfile_value = vim.fn.expand('<sfile>')
vim.g.stack_value = vim.fn.expand('<stack>')
+ vim.g.script_value = vim.fn.expand('<script>')
]])
command('set shellslash')
@@ -173,6 +174,7 @@ describe(':source', function()
eq(1, eval('g:sourced_lua'))
matches([[/test%.lua$]], meths.get_var('sfile_value'))
matches([[/test%.lua$]], meths.get_var('stack_value'))
+ matches([[/test%.lua$]], meths.get_var('script_value'))
os.remove(test_file)
end)
@@ -214,6 +216,7 @@ describe(':source', function()
"\ 2]=]
vim.g.sfile_value = vim.fn.expand('<sfile>')
vim.g.stack_value = vim.fn.expand('<stack>')
+ vim.g.script_value = vim.fn.expand('<script>')
]])
command('edit '..test_file)
@@ -223,6 +226,7 @@ describe(':source', function()
eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
eq(':source (no file)', meths.get_var('sfile_value'))
eq(':source (no file)', meths.get_var('stack_value'))
+ eq(':source (no file)', meths.get_var('script_value'))
os.remove(test_file)
end)
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index 4d984af41e..8eed00c973 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -1,15 +1,19 @@
local Screen = require('test.functional.ui.screen')
local helpers = require('test.functional.helpers')(after_each)
local lfs = require('lfs')
-local eq, eval, expect, source =
- helpers.eq, helpers.eval, helpers.expect, helpers.source
+local luv = require('luv')
+local eq, eval, expect, exec =
+ helpers.eq, helpers.eval, helpers.expect, helpers.exec
local assert_alive = helpers.assert_alive
local clear = helpers.clear
local command = helpers.command
local feed = helpers.feed
+local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
local ok = helpers.ok
local rmdir = helpers.rmdir
+local new_argv = helpers.new_argv
+local pesc = helpers.pesc
local os_kill = helpers.os_kill
local set_session = helpers.set_session
local spawn = helpers.spawn
@@ -55,11 +59,11 @@ describe(':preserve', function()
set swapfile fileformat=unix undolevels=-1
]]
- source(init)
+ exec(init)
command('edit! '..testfile)
feed('isometext<esc>')
command('preserve')
- source('redir => g:swapname | silent swapname | redir END')
+ exec('redir => g:swapname | silent swapname | redir END')
local swappath1 = eval('g:swapname')
@@ -69,12 +73,12 @@ describe(':preserve', function()
true)
set_session(nvim2)
- source(init)
+ exec(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')
+ exec('redir => g:swapname | silent swapname | redir END')
local swappath2 = eval('g:swapname')
@@ -92,25 +96,28 @@ end)
describe('swapfile detection', function()
local swapdir = lfs.currentdir()..'/Xtest_swapdialog_dir'
+ local nvim0
+ -- 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 nomodified undolevels=-1 nohidden
+ ]]
before_each(function()
- clear()
+ nvim0 = spawn(new_argv())
+ set_session(nvim0)
rmdir(swapdir)
lfs.mkdir(swapdir)
end)
after_each(function()
+ set_session(nvim0)
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
@@ -119,19 +126,17 @@ describe('swapfile detection', function()
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)
+ exec(init)
command('edit! '..testfile)
feed('isometext<esc>')
command('preserve')
- os_kill(eval('getpid()'))
-- Start another Nvim instance.
- local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
- true)
+ local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, true, nil, true)
set_session(nvim2)
local screen2 = Screen.new(256, 40)
screen2:attach()
- source(init)
+ exec(init)
-- With shortmess+=F
command('set shortmess+=F')
@@ -176,5 +181,163 @@ describe('swapfile detection', function()
}
})
feed('<cr>')
+
+ nvim2:close()
+ end)
+
+ -- oldtest: Test_swap_prompt_splitwin()
+ it('selecting "q" in the attention prompt', function()
+ exec(init)
+ command('edit Xfile1')
+ command('preserve') -- should help to make sure the swap file exists
+
+ local screen = Screen.new(75, 18)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ })
+
+ local nvim1 = spawn(new_argv(), true, nil, true)
+ set_session(nvim1)
+ screen:attach()
+ exec(init)
+ feed(':split Xfile1\n')
+ screen:expect({
+ any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^')
+ })
+ feed('q')
+ feed(':<CR>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ : |
+ ]])
+ nvim1:close()
+
+ local nvim2 = spawn(new_argv(), true, nil, true)
+ set_session(nvim2)
+ screen:attach()
+ exec(init)
+ command('set more')
+ command('au bufadd * let foo_w = wincol()')
+ feed(':e Xfile1<CR>')
+ screen:expect({any = pesc('{1:-- More --}^')})
+ feed('<Space>')
+ screen:expect({
+ any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^')
+ })
+ feed('q')
+ command([[echo 'hello']])
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ hello |
+ ]])
+ nvim2:close()
+ end)
+
+ -- oldtest: Test_nocatch_process_still_running()
+ it('allows deleting swapfile created before boot vim-patch:8.2.2586', function()
+ local screen = Screen.new(75, 30)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [2] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
+ })
+ screen:attach()
+
+ exec(init)
+ command('set nohidden')
+
+ exec([=[
+ " Make a copy of the current swap file to "Xswap".
+ " Return the name of the swap file.
+ func CopySwapfile()
+ preserve
+ " get the name of the swap file
+ let swname = split(execute("swapname"))[0]
+ let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
+ " make a copy of the swap file in Xswap
+ set binary
+ exe 'sp ' . fnameescape(swname)
+ w! Xswap
+ set nobinary
+ return swname
+ endfunc
+ ]=])
+
+ -- Edit a file and grab its swapfile.
+ exec([[
+ edit Xswaptest
+ call setline(1, ['a', 'b', 'c'])
+ ]])
+ local swname = funcs.CopySwapfile()
+
+ -- Forget we edited this file
+ exec([[
+ new
+ only!
+ bwipe! Xswaptest
+ ]])
+
+ os.rename('Xswap', swname)
+
+ feed(':edit Xswaptest<CR>')
+ screen:expect({any = table.concat({
+ pesc('{2:E325: ATTENTION}'),
+ 'file name: .*Xswaptest',
+ 'process ID: %d* %(STILL RUNNING%)',
+ pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^'),
+ }, '.*')})
+
+ feed('e')
+
+ -- Forget we edited this file
+ exec([[
+ new
+ only!
+ bwipe! Xswaptest
+ ]])
+
+ -- pretend that the swapfile was created before boot
+ lfs.touch(swname, os.time() - luv.uptime() - 10)
+
+ feed(':edit Xswaptest<CR>')
+ screen:expect({any = table.concat({
+ pesc('{2:E325: ATTENTION}'),
+ pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: }^'),
+ }, '.*')})
+
+ feed('e')
end)
end)
diff --git a/test/functional/ex_cmds/trust_spec.lua b/test/functional/ex_cmds/trust_spec.lua
new file mode 100644
index 0000000000..10ee02a790
--- /dev/null
+++ b/test/functional/ex_cmds/trust_spec.lua
@@ -0,0 +1,176 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local eq = helpers.eq
+local clear = helpers.clear
+local command = helpers.command
+local pathsep = helpers.get_pathsep()
+local is_os = helpers.is_os
+local funcs = helpers.funcs
+
+describe(':trust', function()
+ local xstate = 'Xstate'
+
+ setup(function()
+ helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim'))
+ end)
+
+ teardown(function()
+ helpers.rmdir(xstate)
+ end)
+
+ before_each(function()
+ helpers.write_file('test_file', 'test')
+ clear{env={XDG_STATE_HOME=xstate}}
+ end)
+
+ after_each(function()
+ os.remove('test_file')
+ end)
+
+ it('trust then deny then remove a file using current buffer', function()
+ local screen = Screen.new(80, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ })
+
+ local cwd = funcs.getcwd()
+ local hash = funcs.sha256(helpers.read_file('test_file'))
+
+ command('edit test_file')
+ command('trust')
+ screen:expect([[
+ ^test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" trusted.{MATCH:%s+}|
+ ]])
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, cwd .. pathsep .. 'test_file'), vim.trim(trust))
+
+ command('trust ++deny')
+ screen:expect([[
+ ^test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}|
+ ]])
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
+
+ command('trust ++remove')
+ screen:expect([[
+ ^test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}|
+ ]])
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format(''), vim.trim(trust))
+ end)
+
+ it('deny then trust then remove a file using current buffer', function()
+ local screen = Screen.new(80, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ })
+
+ local cwd = funcs.getcwd()
+ local hash = funcs.sha256(helpers.read_file('test_file'))
+
+ command('edit test_file')
+ command('trust ++deny')
+ screen:expect([[
+ ^test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}|
+ ]])
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
+
+ command('trust')
+ screen:expect([[
+ ^test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" trusted.{MATCH:%s+}|
+ ]])
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, cwd .. pathsep .. 'test_file'), vim.trim(trust))
+
+ command('trust ++remove')
+ screen:expect([[
+ ^test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}|
+ ]])
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format(''), vim.trim(trust))
+ end)
+
+ it('deny then remove a file using file path', function()
+ local screen = Screen.new(80, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ })
+
+ local cwd = funcs.getcwd()
+
+ command('trust ++deny test_file')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}|
+ ]])
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
+
+ command('trust ++remove test_file')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ "]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}|
+ ]])
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format(''), vim.trim(trust))
+ end)
+end)
diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua
index e6f67ef18e..000e746f1c 100644
--- a/test/functional/ex_cmds/verbose_spec.lua
+++ b/test/functional/ex_cmds/verbose_spec.lua
@@ -77,7 +77,7 @@ nohlsearch
script_location), result)
end)
- it('"Last set" for keymap set by Lua', function()
+ it('"Last set" for mapping set by Lua', function()
local result = exec_capture(':verbose map <leader>key1')
eq(string.format([[
@@ -86,7 +86,7 @@ n \key1 * :echo "test"<CR>
script_location), result)
end)
- it('"Last set" for keymap set by vim.keymap', function()
+ it('"Last set" for mapping set by vim.keymap', function()
local result = exec_capture(':verbose map <leader>key2')
eq(string.format([[
diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua
index 32fe397c03..1ccd27875e 100644
--- a/test/functional/ex_cmds/write_spec.lua
+++ b/test/functional/ex_cmds/write_spec.lua
@@ -8,7 +8,9 @@ local command = helpers.command
local feed_command = helpers.feed_command
local funcs = helpers.funcs
local meths = helpers.meths
-local iswin = helpers.iswin
+local skip = helpers.skip
+local is_os = helpers.is_os
+local is_ci = helpers.is_ci
local fname = 'Xtest-functional-ex_cmds-write'
local fname_bak = fname .. '~'
@@ -19,6 +21,9 @@ describe(':write', function()
os.remove('test_bkc_file.txt')
os.remove('test_bkc_link.txt')
os.remove('test_fifo')
+ os.remove('test/write/p_opt.txt')
+ os.remove('test/write')
+ os.remove('test')
os.remove(fname)
os.remove(fname_bak)
os.remove(fname_broken)
@@ -34,7 +39,7 @@ describe(':write', function()
it('&backupcopy=auto preserves symlinks', function()
command('set backupcopy=auto')
write_file('test_bkc_file.txt', 'content0')
- if iswin() then
+ if is_os('win') then
command("silent !mklink test_bkc_link.txt test_bkc_file.txt")
else
command("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
@@ -52,9 +57,10 @@ describe(':write', function()
end)
it('&backupcopy=no replaces symlink with new file', function()
+ skip(is_ci('cirrus'))
command('set backupcopy=no')
write_file('test_bkc_file.txt', 'content0')
- if iswin() then
+ if is_os('win') then
command("silent !mklink test_bkc_link.txt test_bkc_file.txt")
else
command("silent !ln -s test_bkc_file.txt test_bkc_link.txt")
@@ -73,7 +79,7 @@ describe(':write', function()
it("appends FIFO file", function()
-- mkfifo creates read-only .lnk files on Windows
- if iswin() or eval("executable('mkfifo')") == 0 then
+ if is_os('win') or eval("executable('mkfifo')") == 0 then
pending('missing "mkfifo" command')
end
@@ -90,11 +96,36 @@ describe(':write', function()
fifo:close()
end)
+ it("++p creates missing parent directories", function()
+ eq(0, eval("filereadable('p_opt.txt')"))
+ command("write ++p p_opt.txt")
+ eq(1, eval("filereadable('p_opt.txt')"))
+ os.remove("p_opt.txt")
+
+ eq(0, eval("filereadable('p_opt.txt')"))
+ command("write ++p ./p_opt.txt")
+ eq(1, eval("filereadable('p_opt.txt')"))
+ os.remove("p_opt.txt")
+
+ eq(0, eval("filereadable('test/write/p_opt.txt')"))
+ command("write ++p test/write/p_opt.txt")
+ eq(1, eval("filereadable('test/write/p_opt.txt')"))
+
+ eq(('Vim(write):E32: No file name'), pcall_err(command, 'write ++p test_write/'))
+ if not is_os('win') then
+ eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
+ pcall_err(command, 'write ++p .'))
+ eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
+ pcall_err(command, 'write ++p ./'))
+ end
+ end)
+
it('errors out correctly', function()
+ skip(is_ci('cirrus'))
command('let $HOME=""')
eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~'))
-- Message from check_overwrite
- if not iswin() then
+ if not is_os('win') then
eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
pcall_err(command, 'write .'))
end
@@ -113,7 +144,7 @@ describe(':write', function()
funcs.setfperm(fname, 'r--------')
eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)',
pcall_err(command, 'write'))
- if iswin() then
+ if is_os('win') then
eq(0, os.execute('del /q/f ' .. fname))
eq(0, os.execute('rd /q/s ' .. fname_bak))
else
@@ -121,8 +152,7 @@ describe(':write', function()
eq(true, os.remove(fname_bak))
end
write_file(fname_bak, 'TTYX')
- -- FIXME: exc_exec('write!') outputs 0 in Windows
- if iswin() then return end
+ skip(is_os('win'), [[FIXME: exc_exec('write!') outputs 0 in Windows]])
lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true)
eq('Vim(write):E166: Can\'t open linked file for writing',
pcall_err(command, 'write!'))
diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua
index 7c00daf1d7..861a977ea6 100644
--- a/test/functional/ex_cmds/wviminfo_spec.lua
+++ b/test/functional/ex_cmds/wviminfo_spec.lua
@@ -3,14 +3,14 @@ local lfs = require('lfs')
local clear = helpers.clear
local command, eq, neq, write_file =
helpers.command, helpers.eq, helpers.neq, helpers.write_file
-local iswin = helpers.iswin
local read_file = helpers.read_file
+local is_os = helpers.is_os
describe(':wshada', function()
local shada_file = 'wshada_test'
before_each(function()
- clear{args={'-i', iswin() and 'nul' or '/dev/null',
+ clear{args={'-i', is_os('win') and 'nul' or '/dev/null',
-- Need 'swapfile' for these tests.
'--cmd', 'set swapfile undodir=. directory=. viewdir=. backupdir=. belloff= noshowcmd noruler'},
args_rm={'-n', '-i', '--cmd'}}
diff --git a/test/functional/fixtures/CMakeLists.txt b/test/functional/fixtures/CMakeLists.txt
index a5410c2f8c..6e64b1e4dc 100644
--- a/test/functional/fixtures/CMakeLists.txt
+++ b/test/functional/fixtures/CMakeLists.txt
@@ -1,14 +1,23 @@
-add_executable(tty-test EXCLUDE_FROM_ALL tty-test.c)
-target_link_libraries(tty-test ${LIBUV_LIBRARIES})
+add_library(test_lib INTERFACE)
+if(MINGW)
+ target_link_libraries(test_lib INTERFACE -municode)
+endif()
+if(WIN32)
+ target_compile_definitions(test_lib INTERFACE MSWIN)
+endif()
+target_link_libraries(test_lib INTERFACE nvim)
+add_executable(tty-test EXCLUDE_FROM_ALL tty-test.c)
add_executable(shell-test EXCLUDE_FROM_ALL shell-test.c)
# Fake pwsh (powershell) for testing make_filter_cmd(). #16271
add_executable(pwsh-test EXCLUDE_FROM_ALL shell-test.c)
add_executable(printargs-test EXCLUDE_FROM_ALL printargs-test.c)
add_executable(printenv-test EXCLUDE_FROM_ALL printenv-test.c)
-if(MINGW)
- set_target_properties(printenv-test PROPERTIES LINK_FLAGS -municode)
-endif()
-
add_executable(streams-test EXCLUDE_FROM_ALL streams-test.c)
-target_link_libraries(streams-test ${LIBUV_LIBRARIES})
+
+target_link_libraries(tty-test PRIVATE test_lib)
+target_link_libraries(shell-test PRIVATE test_lib)
+target_link_libraries(pwsh-test PRIVATE test_lib)
+target_link_libraries(printargs-test PRIVATE test_lib)
+target_link_libraries(printenv-test PRIVATE test_lib)
+target_link_libraries(streams-test PRIVATE test_lib)
diff --git a/test/functional/fixtures/api_level_10.mpack b/test/functional/fixtures/api_level_10.mpack
new file mode 100644
index 0000000000..2a1f51045d
--- /dev/null
+++ b/test/functional/fixtures/api_level_10.mpack
Binary files differ
diff --git a/test/functional/fixtures/filename_with_unicode_ααα b/test/functional/fixtures/filename_with_unicode_ααα
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/filename_with_unicode_ααα
diff --git a/test/functional/fixtures/printenv-test.c b/test/functional/fixtures/printenv-test.c
index 0e68129543..295b4f04c3 100644
--- a/test/functional/fixtures/printenv-test.c
+++ b/test/functional/fixtures/printenv-test.c
@@ -3,13 +3,13 @@
#include <stdio.h>
-#ifdef WIN32
+#ifdef MSWIN
# include <windows.h>
#else
# include <stdlib.h>
#endif
-#ifdef WIN32
+#ifdef MSWIN
int wmain(int argc, wchar_t **argv)
#else
int main(int argc, char **argv)
@@ -19,7 +19,7 @@ int main(int argc, char **argv)
return 1;
}
-#ifdef WIN32
+#ifdef MSWIN
wchar_t *value = _wgetenv(argv[1]);
if (value == NULL) {
return 1;
diff --git a/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua b/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua
index a312572c5b..45226ce24b 100644
--- a/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua
+++ b/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua
@@ -1,3 +1,5 @@
return function (val, res)
- vim.loop.new_async(function() _G[res] = require'leftpad'(val) end):send()
+ local handle
+ handle = vim.loop.new_async(function() _G[res] = require'leftpad'(val) handle:close() end)
+ handle:send()
end
diff --git a/test/functional/fixtures/startup-fail.lua b/test/functional/fixtures/startup-fail.lua
new file mode 100644
index 0000000000..adcfe2a201
--- /dev/null
+++ b/test/functional/fixtures/startup-fail.lua
@@ -0,0 +1,7 @@
+-- Test "nvim -l foo.lua …" with a Lua error.
+
+local function main()
+ error('my pearls!!')
+end
+
+main()
diff --git a/test/functional/fixtures/startup.lua b/test/functional/fixtures/startup.lua
new file mode 100644
index 0000000000..d0e60309bd
--- /dev/null
+++ b/test/functional/fixtures/startup.lua
@@ -0,0 +1,35 @@
+-- Test "nvim -l foo.lua …"
+
+local function printbufs()
+ local bufs = ''
+ for _, v in ipairs(vim.api.nvim_list_bufs()) do
+ local b = vim.fn.bufname(v)
+ if b:len() > 0 then
+ bufs = ('%s %s'):format(bufs, b)
+ end
+ end
+ print(('bufs:%s'):format(bufs))
+end
+
+local function parseargs(args)
+ local exitcode = nil
+ for i = 1, #args do
+ if args[i] == '--exitcode' then
+ exitcode = tonumber(args[i + 1])
+ end
+ end
+ return exitcode
+end
+
+local function main()
+ printbufs()
+ print('nvim args:', #vim.v.argv)
+ print('lua args:', vim.inspect(_G.arg))
+
+ local exitcode = parseargs(_G.arg)
+ if type(exitcode) == 'number' then
+ os.exit(exitcode)
+ end
+end
+
+main()
diff --git a/test/functional/fixtures/tty-test.c b/test/functional/fixtures/tty-test.c
index 4438b73a22..6ee7715021 100644
--- a/test/functional/fixtures/tty-test.c
+++ b/test/functional/fixtures/tty-test.c
@@ -5,7 +5,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
-#ifdef _WIN32
+#ifdef MSWIN
# include <windows.h>
#else
# include <unistd.h>
@@ -23,7 +23,7 @@ uv_tty_t tty_out;
bool owns_tty(void); // silence -Wmissing-prototypes
bool owns_tty(void)
{
-#ifdef _WIN32
+#ifdef MSWIN
// XXX: We need to make proper detect owns tty
// HWND consoleWnd = GetConsoleWindow();
// DWORD dwProcessId;
@@ -38,14 +38,14 @@ bool owns_tty(void)
static void walk_cb(uv_handle_t *handle, void *arg)
{
if (!uv_is_closing(handle)) {
-#ifdef WIN32
+#ifdef MSWIN
uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);
#endif
uv_close(handle, NULL);
}
}
-#ifndef WIN32
+#ifndef MSWIN
static void sig_handler(int signum)
{
switch (signum) {
@@ -64,7 +64,7 @@ static void sig_handler(int signum)
}
#endif
-#ifdef WIN32
+#ifdef MSWIN
static void sigwinch_cb(uv_signal_t *handle, int signum)
{
int width, height;
@@ -102,7 +102,7 @@ static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf)
uv_write_t req;
uv_buf_t b = {
.base = buf->base,
-#ifdef WIN32
+#ifdef MSWIN
.len = (ULONG)cnt
#else
.len = (size_t)cnt
@@ -171,7 +171,7 @@ int main(int argc, char **argv)
uv_prepare_t prepare;
uv_prepare_init(uv_default_loop(), &prepare);
uv_prepare_start(&prepare, prepare_cb);
-#ifndef WIN32
+#ifndef MSWIN
uv_tty_init(uv_default_loop(), &tty, fileno(stderr), 1);
#else
uv_tty_init(uv_default_loop(), &tty, fileno(stdin), 1);
@@ -182,7 +182,7 @@ int main(int argc, char **argv)
uv_tty_set_mode(&tty, UV_TTY_MODE_RAW);
tty.data = &interrupted;
uv_read_start(STRUCT_CAST(uv_stream_t, &tty), alloc_cb, read_cb);
-#ifndef WIN32
+#ifndef MSWIN
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
@@ -196,7 +196,7 @@ int main(int argc, char **argv)
#endif
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
-#ifndef WIN32
+#ifndef MSWIN
// XXX: Without this the SIGHUP handler is skipped on some systems.
sleep(100);
#endif
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 981cfc306e..6400db9f87 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -1,5 +1,4 @@
require('coxpcall')
-local busted = require('busted')
local luv = require('luv')
local lfs = require('lfs')
local mpack = require('mpack')
@@ -29,6 +28,7 @@ local module = {
}
local start_dir = lfs.currentdir()
+local runtime_set = 'set runtimepath^=./build/lib/nvim/'
module.nvim_prog = (
os.getenv('NVIM_PRG')
or global_helpers.test_build_dir .. '/bin/nvim'
@@ -40,6 +40,8 @@ module.nvim_set = (
..' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid')
module.nvim_argv = {
module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
+ -- XXX: find treesitter parsers.
+ '--cmd', runtime_set,
'--cmd', module.nvim_set,
'--cmd', 'mapclear',
'--cmd', 'mapclear!',
@@ -51,7 +53,6 @@ if module.nvim_dir == module.nvim_prog then
module.nvim_dir = "."
end
-local iswin = global_helpers.iswin
local prepend_argv
if os.getenv('VALGRIND') then
@@ -109,6 +110,10 @@ function module.request(method, ...)
return rv
end
+function module.request_lua(method, ...)
+ return module.exec_lua([[return vim.api[...](select(2, ...))]], method, ...)
+end
+
function module.next_msg(timeout)
return session:next_message(timeout and timeout or 10000)
end
@@ -237,7 +242,7 @@ function module.run_session(lsession, request_cb, notification_cb, setup_cb, tim
end
loop_running = true
- session:run(on_request, on_notification, on_setup, timeout)
+ lsession:run(on_request, on_notification, on_setup, timeout)
loop_running = false
if last_error then
local err = last_error
@@ -245,7 +250,7 @@ function module.run_session(lsession, request_cb, notification_cb, setup_cb, tim
error(err)
end
- return session.eof_err
+ return lsession.eof_err
end
function module.run(request_cb, notification_cb, setup_cb, timeout)
@@ -272,7 +277,6 @@ function module.command(cmd)
module.request('nvim_command', cmd)
end
-
-- Use for commands which expect nvim to quit.
-- The first argument can also be a timeout.
function module.expect_exit(fn_or_timeout, ...)
@@ -297,12 +301,18 @@ function module.eval(expr)
return module.request('nvim_eval', expr)
end
--- Executes a VimL function.
+-- Executes a VimL function via RPC.
-- Fails on VimL error, but does not update v:errmsg.
function module.call(name, ...)
return module.request('nvim_call_function', name, {...})
end
+-- Executes a VimL function via Lua.
+-- Fails on VimL error, but does not update v:errmsg.
+function module.call_lua(name, ...)
+ return module.exec_lua([[return vim.call(...)]], name, ...)
+end
+
-- Sends user input to Nvim.
-- Does not fail on VimL error, but v:errmsg will be updated.
local function nvim_feed(input)
@@ -345,14 +355,17 @@ end
-- Removes Nvim startup args from `args` matching items in `args_rm`.
--
--- "-u", "-i", "--cmd" are treated specially: their "values" are also removed.
+-- - Special case: "-u", "-i", "--cmd" are treated specially: their "values" are also removed.
+-- - Special case: "runtimepath" will remove only { '--cmd', 'set runtimepath^=…', }
+--
-- Example:
-- args={'--headless', '-u', 'NONE'}
-- args_rm={'--cmd', '-u'}
-- Result:
-- {'--headless'}
--
--- All cases are removed.
+-- All matching cases are removed.
+--
-- Example:
-- args={'--cmd', 'foo', '-N', '--cmd', 'bar'}
-- args_rm={'--cmd', '-u'}
@@ -373,6 +386,9 @@ local function remove_args(args, args_rm)
last = ''
elseif tbl_contains(args_rm, arg) then
last = arg
+ elseif arg == runtime_set and tbl_contains(args_rm, 'runtimepath') then
+ table.remove(new_args) -- Remove the preceding "--cmd".
+ last = ''
else
table.insert(new_args, arg)
end
@@ -380,10 +396,27 @@ local function remove_args(args, args_rm)
return new_args
end
+function module.check_close()
+ if not session then
+ return
+ end
+ local start_time = luv.now()
+ session:close()
+ luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
+ local end_time = luv.now()
+ local delta = end_time - start_time
+ if delta > 500 then
+ print("nvim took " .. delta .. " milliseconds to exit after last test\n"..
+ "This indicates a likely problem with the test even if it passed!\n")
+ io.stdout:flush()
+ end
+ session = nil
+end
+
--- @param io_extra used for stdin_fd, see :help ui-option
function module.spawn(argv, merge, env, keep, io_extra)
- if session and not keep then
- session:close()
+ if not keep then
+ module.check_close()
end
local child_stream = ChildProcessStream.spawn(
@@ -400,28 +433,6 @@ function module.connect(file_or_address)
return Session.new(stream)
end
--- Calls fn() until it succeeds, up to `max` times or until `max_ms`
--- milliseconds have passed.
-function module.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 or 10000)
- local start_time = luv.now()
- while true do
- local status, result = pcall(fn)
- if status then
- return result
- end
- luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()).
- if (max and tries >= max) or (luv.now() - start_time > timeout) then
- busted.fail(string.format("retry() attempts: %d\n%s", tries, tostring(result)), 2)
- end
- tries = tries + 1
- luv.sleep(20) -- Avoid hot loop...
- end
-end
-
-- Starts a new global Nvim session.
--
-- Parameters are interpreted as startup args, OR a map with these keys:
@@ -435,8 +446,14 @@ end
-- clear('-e')
-- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}}
function module.clear(...)
+ module.set_session(module.spawn_argv(false, ...))
+end
+
+-- same params as clear, but does returns the session instead
+-- of replacing the default session
+function module.spawn_argv(keep, ...)
local argv, env, io_extra = module.new_argv(...)
- module.set_session(module.spawn(argv, nil, env, nil, io_extra))
+ return module.spawn(argv, nil, env, keep, io_extra)
end
-- Builds an argument list for use in clear().
@@ -526,7 +543,7 @@ function module.source(code)
end
function module.has_powershell()
- return module.eval('executable("'..(iswin() and 'powershell' or 'pwsh')..'")') == 1
+ return module.eval('executable("'..(is_os('win') and 'powershell' or 'pwsh')..'")') == 1
end
--- Sets Nvim shell to powershell.
@@ -539,23 +556,31 @@ function module.set_shell_powershell(fake)
if not fake then
assert(found)
end
- local shell = found and (iswin() and 'powershell' or 'pwsh') or module.testprg('pwsh-test')
- local set_encoding = '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;'
- local cmd = set_encoding..'Remove-Item -Force '..table.concat(iswin()
- and {'alias:cat', 'alias:echo', 'alias:sleep'}
+ local shell = found and (is_os('win') and 'powershell' or 'pwsh') or module.testprg('pwsh-test')
+ local set_encoding = '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();'
+ local cmd = set_encoding..'Remove-Item -Force '..table.concat(is_os('win')
+ and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort'}
or {'alias:echo'}, ',')..';'
module.exec([[
let &shell = ']]..shell..[['
set shellquote= shellxquote=
let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ]]..cmd..[['
let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
- let &shellredir = '-RedirectStandardOutput %s -NoNewWindow -Wait'
+ let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
]])
return found
end
-function module.nvim(method, ...)
- return module.request('nvim_'..method, ...)
+function module.create_callindex(func)
+ local table = {}
+ setmetatable(table, {
+ __index = function(tbl, arg1)
+ local ret = function(...) return func(arg1, ...) end
+ tbl[arg1] = ret
+ return ret
+ end,
+ })
+ return table
end
local function ui(method, ...)
@@ -566,23 +591,83 @@ function module.nvim_async(method, ...)
session:notify('nvim_'..method, ...)
end
-function module.buffer(method, ...)
- return module.request('nvim_buf_'..method, ...)
-end
+module.async_meths = module.create_callindex(module.nvim_async)
+module.uimeths = module.create_callindex(ui)
-function module.window(method, ...)
- return module.request('nvim_win_'..method, ...)
-end
+local function create_api(request, call)
+ local m = {}
+ function m.nvim(method, ...)
+ return request('nvim_'..method, ...)
+ end
+
+ function m.buffer(method, ...)
+ return request('nvim_buf_'..method, ...)
+ end
+
+ function m.window(method, ...)
+ return request('nvim_win_'..method, ...)
+ end
+
+ function m.tabpage(method, ...)
+ return request('nvim_tabpage_'..method, ...)
+ end
+
+ function m.curbuf(method, ...)
+ if not method then
+ return m.nvim('get_current_buf')
+ end
+ return m.buffer(method, 0, ...)
+ end
+
+ function m.curwin(method, ...)
+ if not method then
+ return m.nvim('get_current_win')
+ end
+ return m.window(method, 0, ...)
+ end
+
+ function m.curtab(method, ...)
+ if not method then
+ return m.nvim('get_current_tabpage')
+ end
+ return m.tabpage(method, 0, ...)
+ end
+
+ m.funcs = module.create_callindex(call)
+ m.meths = module.create_callindex(m.nvim)
+ m.bufmeths = module.create_callindex(m.buffer)
+ m.winmeths = module.create_callindex(m.window)
+ m.tabmeths = module.create_callindex(m.tabpage)
+ m.curbufmeths = module.create_callindex(m.curbuf)
+ m.curwinmeths = module.create_callindex(m.curwin)
+ m.curtabmeths = module.create_callindex(m.curtab)
-function module.tabpage(method, ...)
- return module.request('nvim_tabpage_'..method, ...)
+ return m
end
-function module.curbuf(method, ...)
- if not method then
- return module.nvim('get_current_buf')
+module.rpc = {
+ api = create_api(module.request, module.call),
+}
+
+module.lua = {
+ api = create_api(module.request_lua, module.call_lua),
+}
+
+module.describe_lua_and_rpc = function(describe)
+ return function(what, tests)
+ local function d(flavour)
+ describe(string.format('%s (%s)', what, flavour), function(...)
+ return tests(module[flavour].api, ...)
+ end)
+ end
+
+ d('rpc')
+ d('lua')
end
- return module.buffer(method, 0, ...)
+end
+
+for name, fn in pairs(module.rpc.api) do
+ module[name] = fn
end
function module.poke_eventloop()
@@ -601,20 +686,6 @@ function module.curbuf_contents()
return table.concat(module.curbuf('get_lines', 0, -1, true), '\n')
end
-function module.curwin(method, ...)
- if not method then
- return module.nvim('get_current_win')
- end
- return module.window(method, 0, ...)
-end
-
-function module.curtab(method, ...)
- if not method then
- return module.nvim('get_current_tabpage')
- end
- return module.tabpage(method, 0, ...)
-end
-
function module.expect(contents)
return eq(dedent(contents), module.curbuf_contents())
end
@@ -730,40 +801,16 @@ function module.exc_exec(cmd)
return ret
end
-function module.create_callindex(func)
- local table = {}
- setmetatable(table, {
- __index = function(tbl, arg1)
- local ret = function(...) return func(arg1, ...) end
- tbl[arg1] = ret
- return ret
- end,
- })
- return table
-end
-
--- Helper to skip tests. Returns true in Windows systems.
--- pending_fn is pending() from busted
-function module.pending_win32(pending_fn)
- if iswin() then
- if pending_fn ~= nil then
- pending_fn('FIXME: Windows', function() end)
- end
+function module.skip(cond, reason)
+ if cond then
+ local pending = getfenv(2).pending
+ pending(reason or 'FIXME')
return true
else
return false
end
end
-function module.pending_c_parser(pending_fn)
- local status, _ = unpack(module.exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]]))
- if not status then
- pending_fn 'no C parser, skipping'
- return true
- end
- return false
-end
-
-- Calls pending() and returns `true` if the system is too slow to
-- run fragile or expensive tests. Else returns `false`.
function module.skip_fragile(pending_fn, cond)
@@ -780,17 +827,6 @@ function module.skip_fragile(pending_fn, cond)
return false
end
-module.funcs = module.create_callindex(module.call)
-module.meths = module.create_callindex(module.nvim)
-module.async_meths = module.create_callindex(module.nvim_async)
-module.uimeths = module.create_callindex(ui)
-module.bufmeths = module.create_callindex(module.buffer)
-module.winmeths = module.create_callindex(module.window)
-module.tabmeths = module.create_callindex(module.tabpage)
-module.curbufmeths = module.create_callindex(module.curbuf)
-module.curwinmeths = module.create_callindex(module.curwin)
-module.curtabmeths = module.create_callindex(module.curtab)
-
function module.exec(code)
return module.meths.exec(code, false)
end
@@ -804,13 +840,13 @@ function module.exec_lua(code, ...)
end
function module.get_pathsep()
- return iswin() and '\\' or '/'
+ return is_os('win') and '\\' or '/'
end
--- Gets the filesystem root dir, namely "/" or "C:/".
function module.pathroot()
local pathsep = package.config:sub(1,1)
- return iswin() and (module.nvim_dir:sub(1,2)..pathsep) or '/'
+ return is_os('win') and (module.nvim_dir:sub(1,2)..pathsep) or '/'
end
--- Gets the full `…/build/bin/{name}` path of a test program produced by
@@ -818,7 +854,7 @@ end
---
--- @param name (string) Name of the test program.
function module.testprg(name)
- local ext = module.iswin() and '.exe' or ''
+ local ext = module.is_os('win') and '.exe' or ''
return ('%s/%s%s'):format(module.nvim_dir, name, ext)
end
@@ -845,7 +881,7 @@ function module.missing_provider(provider)
end
function module.alter_slashes(obj)
- if not iswin() then
+ if not is_os('win') then
return obj
end
if type(obj) == 'string' then
@@ -863,7 +899,7 @@ function module.alter_slashes(obj)
end
local load_factor = 1
-if global_helpers.isCI() then
+if global_helpers.is_ci() then
-- Compute load factor only once (but outside of any tests).
module.clear()
module.request('nvim_command', 'source src/nvim/testdir/load.vim')
@@ -896,14 +932,14 @@ end
-- Kill process with given pid
function module.os_kill(pid)
- return os.execute((iswin()
+ return os.execute((is_os('win')
and 'taskkill /f /t /pid '..pid..' > nul'
or 'kill -9 '..pid..' > /dev/null'))
end
-- Create folder with non existing parents
function module.mkdir_p(path)
- return os.execute((iswin()
+ return os.execute((is_os('win')
and 'mkdir '..path
or 'mkdir -p '..path))
end
diff --git a/test/functional/legacy/006_argument_list_spec.lua b/test/functional/legacy/006_argument_list_spec.lua
deleted file mode 100644
index d269bf8ec9..0000000000
--- a/test/functional/legacy/006_argument_list_spec.lua
+++ /dev/null
@@ -1,85 +0,0 @@
--- Test for autocommand that redefines the argument list, when doing ":all".
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local command, dedent, eq = helpers.command, helpers.dedent, helpers.eq
-local curbuf_contents = helpers.curbuf_contents
-local poke_eventloop = helpers.poke_eventloop
-
-describe('argument list', function()
- setup(clear)
-
- it('is working', function()
- insert([[
- start of test file Xxx
- this is a test
- this is a test
- this is a test
- this is a test
- end of test file Xxx]])
- poke_eventloop()
-
- command('au BufReadPost Xxx2 next Xxx2 Xxx1')
- command('/^start of')
-
- -- Write test file Xxx1
- feed('A1<Esc>:.,/end of/w! Xxx1<cr>')
-
- -- Write test file Xxx2
- feed('$r2:.,/end of/w! Xxx2<cr>')
-
- -- Write test file Xxx3
- feed('$r3:.,/end of/w! Xxx3<cr>')
- poke_eventloop()
-
- -- Redefine arglist; go to Xxx1
- command('next! Xxx1 Xxx2 Xxx3')
-
- -- Open window for all args
- command('all')
-
- -- Write contents of Xxx1
- command('%yank A')
-
- -- Append contents of last window (Xxx1)
- feed('')
- poke_eventloop()
- command('%yank A')
-
- -- should now be in Xxx2
- command('rew')
-
- -- Append contents of Xxx2
- command('%yank A')
-
- command('%d')
- command('0put=@a')
- command('$d')
-
- eq(dedent([[
- start of test file Xxx1
- this is a test
- this is a test
- this is a test
- this is a test
- end of test file Xxx
- start of test file Xxx1
- this is a test
- this is a test
- this is a test
- this is a test
- end of test file Xxx
- start of test file Xxx2
- this is a test
- this is a test
- this is a test
- this is a test
- end of test file Xxx]]), curbuf_contents())
- end)
-
- teardown(function()
- os.remove('Xxx1')
- os.remove('Xxx2')
- os.remove('Xxx3')
- end)
-end)
diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua
index 0fa9290f3c..7ae851467f 100644
--- a/test/functional/legacy/011_autocommands_spec.lua
+++ b/test/functional/legacy/011_autocommands_spec.lua
@@ -18,11 +18,11 @@ 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 command = helpers.command
-local iswin = helpers.iswin
local read_file = helpers.read_file
+local is_os = helpers.is_os
local function has_gzip()
- local null = iswin() and 'nul' or '/dev/null'
+ local null = is_os('win') and 'nul' or '/dev/null'
return os.execute('gzip --help >' .. null .. ' 2>&1') == 0
end
diff --git a/test/functional/legacy/025_jump_tag_hidden_spec.lua b/test/functional/legacy/025_jump_tag_hidden_spec.lua
index dd89a3680e..15bd56a601 100644
--- a/test/functional/legacy/025_jump_tag_hidden_spec.lua
+++ b/test/functional/legacy/025_jump_tag_hidden_spec.lua
@@ -23,7 +23,7 @@ describe('jump to a tag with hidden set', function()
feed_command('set hidden')
-- Create a link from test25.dir to the current directory.
- if helpers.iswin() then
+ if helpers.is_os('win') then
feed_command('!rd /q/s test25.dir')
feed_command('!mklink /j test25.dir .')
else
@@ -33,7 +33,7 @@ describe('jump to a tag with hidden set', function()
-- Create tags.text, with the current directory name inserted.
feed_command('/tags line')
- feed_command('r !' .. (helpers.iswin() and 'cd' or 'pwd'))
+ feed_command('r !' .. (helpers.is_os('win') and 'cd' or 'pwd'))
feed('d$/test<cr>')
feed('hP:.w! tags.test<cr>')
@@ -44,7 +44,7 @@ describe('jump to a tag with hidden set', function()
feed('G<C-]> x:yank a<cr>')
feed_command("call delete('tags.test')")
feed_command("call delete('Xxx')")
- if helpers.iswin() then
+ if helpers.is_os('win') then
feed_command('!rd /q test25.dir')
else
feed_command('!rm -f test25.dir')
diff --git a/test/functional/legacy/030_fileformats_spec.lua b/test/functional/legacy/030_fileformats_spec.lua
index 15dbd05cf5..e88afd9c47 100644
--- a/test/functional/legacy/030_fileformats_spec.lua
+++ b/test/functional/legacy/030_fileformats_spec.lua
@@ -255,7 +255,7 @@ describe('fileformats option', function()
-- Assert buffer contents. This has to be done manually as
-- helpers.expect() calls helpers.dedent() which messes up the white space
- -- and carrige returns.
+ -- and carriage returns.
eq(
'unix\n'..
'unix\n'..
diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua
deleted file mode 100644
index 7d7856fd37..0000000000
--- a/test/functional/legacy/045_folding_spec.lua
+++ /dev/null
@@ -1,214 +0,0 @@
--- Tests for folding.
-local Screen = require('test.functional.ui.screen')
-
-local helpers = require('test.functional.helpers')(after_each)
-local feed, insert, feed_command, expect_any =
- helpers.feed, helpers.insert, helpers.feed_command, helpers.expect_any
-
-describe('folding', function()
- local screen
-
- before_each(function()
- helpers.clear()
-
- screen = Screen.new(20, 8)
- screen:attach()
- end)
-
- it('creation, opening, moving (to the end) and closing', function()
- insert([[
- 1 aa
- 2 bb
- 3 cc
- last
- ]])
-
- -- Basic test if a fold can be created, opened, moving to the end and
- -- closed.
- feed_command('1')
- feed('zf2j')
- feed_command('call append("$", "manual " . getline(foldclosed(".")))')
- feed('zo')
- feed_command('call append("$", foldclosed("."))')
- feed(']z')
- feed_command('call append("$", getline("."))')
- feed('zc')
- feed_command('call append("$", getline(foldclosed(".")))')
-
- expect_any([[
- manual 1 aa
- -1
- 3 cc
- 1 aa]])
- end)
-
- it("foldmethod=marker", function()
- screen:try_resize(20, 10)
- insert([[
- dd {{{
- ee {{{ }}}
- ff }}}
- ]])
- feed_command('set fdm=marker fdl=1')
- feed_command('2')
- feed_command('call append("$", "line 2 foldlevel=" . foldlevel("."))')
- feed('[z')
- feed_command('call append("$", foldlevel("."))')
- feed('jo{{ <esc>r{jj') -- writes '{{{' and moves 2 lines bot
- feed_command('call append("$", foldlevel("."))')
- feed('kYpj')
- feed_command('call append("$", foldlevel("."))')
-
- helpers.poke_eventloop()
- screen:expect([[
- dd {{{ |
- ee {{{ }}} |
- {{{ |
- ff }}} |
- ff }}} |
- ^ |
- line 2 foldlevel=2 |
- 1 |
- 1 |
- |
- ]])
-
- end)
-
- it("foldmethod=indent", function()
- screen:try_resize(20, 8)
- feed_command('set fdm=indent sw=2')
- insert([[
- aa
- bb
- cc
- last
- ]])
- feed_command('call append("$", "foldlevel line3=" . foldlevel(3))')
- feed_command('call append("$", foldlevel(2))')
- feed('zR')
-
- helpers.poke_eventloop()
- screen:expect([[
- aa |
- bb |
- cc |
- last |
- ^ |
- foldlevel line3=2 |
- 1 |
- |
- ]])
- end)
-
- it("foldmethod=syntax", function()
- screen:try_resize(35, 15)
- insert([[
- 1 aa
- 2 bb
- 3 cc
- 4 dd {{{
- 5 ee {{{ }}}
- 6 ff }}}
- 7 gg
- 8 hh
- 9 ii
- a jj
- b kk
- last]])
- feed_command('set fdm=syntax fdl=0')
- feed_command('syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3')
- feed_command('syn region Fd1 start="ee" end="ff" fold contained')
- feed_command('syn region Fd2 start="gg" end="hh" fold contained')
- feed_command('syn region Fd3 start="commentstart" end="commentend" fold contained')
- feed('Gzk')
- feed_command('call append("$", "folding " . getline("."))')
- feed('k')
- feed_command('call append("$", getline("."))')
- feed('jAcommentstart <esc>Acommentend<esc>')
- feed_command('set fdl=1')
- feed('3j')
- feed_command('call append("$", getline("."))')
- feed_command('set fdl=0')
- feed('zO<C-L>j') -- <C-L> redraws screen
- feed_command('call append("$", getline("."))')
- feed_command('set fdl=0')
- expect_any([[
- folding 9 ii
- 3 cc
- 9 ii
- a jj]])
- end)
-
- it("foldmethod=expression", function()
- insert([[
- 1 aa
- 2 bb
- 3 cc
- 4 dd {{{
- 5 ee {{{ }}}
- 6 ff }}}
- 7 gg
- 8 hh
- 9 ii
- a jj
- b kk
- last ]])
-
- feed_command([[
- fun Flvl()
- let l = getline(v:lnum)
- if l =~ "bb$"
- return 2
- elseif l =~ "gg$"
- return "s1"
- elseif l =~ "ii$"
- return ">2"
- elseif l =~ "kk$"
- return "0"
- endif
- return "="
- endfun
- ]])
- feed_command('set fdm=expr fde=Flvl()')
- feed_command('/bb$')
- feed_command('call append("$", "expr " . foldlevel("."))')
- feed_command('/hh$')
- feed_command('call append("$", foldlevel("."))')
- feed_command('/ii$')
- feed_command('call append("$", foldlevel("."))')
- feed_command('/kk$')
- feed_command('call append("$", foldlevel("."))')
-
- expect_any([[
- expr 2
- 1
- 2
- 0]])
- end)
-
- it('can be opened after :move', function()
- -- luacheck: ignore
- screen:try_resize(35, 8)
- insert([[
- Test fdm=indent and :move bug END
- line2
- Test fdm=indent START
- line3
- line4]])
- feed_command('set noai nosta ')
- feed_command('set fdm=indent')
- feed_command('1m1')
- feed('2jzc')
- feed_command('m0')
- feed('zR')
-
- expect_any([[
- Test fdm=indent START
- line3
- line4
- Test fdm=indent and :move bug END
- line2]])
- end)
-end)
-
diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua
index 4d71a526c1..75294b3786 100644
--- a/test/functional/legacy/055_list_and_dict_types_spec.lua
+++ b/test/functional/legacy/055_list_and_dict_types_spec.lua
@@ -330,214 +330,6 @@ describe('list and dictionary types', function()
same list: 1]])
end)
- it('locked variables (part 1)', function()
- source([=[
- let l = []
- for depth in range(5)
- $put ='depth is ' . depth
- for u in range(3)
- unlet l
- let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
- exe "lockvar " . depth . " l"
- if u == 1
- exe "unlockvar l"
- elseif u == 2
- exe "unlockvar " . depth . " l"
- endif
- let ps = islocked("l") . islocked("l[1]") . islocked("l[1][1]") .
- \ islocked("l[1][1][0]") . '-' . islocked("l[2]") .
- \ islocked("l[2]['6']") . islocked("l[2]['6'][7]")
- $put =ps
- let ps = ''
- try
- let l[1][1][0] = 99
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- let l[1][1] = [99]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- let l[1] = [99]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- let l[2]['6'][7] = 99
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- let l[2][6] = {99: 99}
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- let l[2] = {99: 99}
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- let l = [99]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- $put =ps
- endfor
- endfor]=])
- expect([[
-
- depth is 0
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- depth is 1
- 1000-000
- ppppppF
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- depth is 2
- 1100-100
- ppFppFF
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- depth is 3
- 1110-110
- pFFpFFF
- 0010-010
- pFppFpp
- 0000-000
- ppppppp
- depth is 4
- 1111-111
- FFFFFFF
- 0011-011
- FFpFFpp
- 0000-000
- ppppppp]])
- end)
-
- -- TODO In the original test the 5th line of this source() call was used.
- -- But now the test only passes if I comment it.
- it('unletting locked variables', function()
- source([=[
- let l = []
- for depth in range(5)
- $put ='depth is ' . depth
- for u in range(3)
- "unlet l
- let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
- exe "lockvar " . depth . " l"
- if u == 1
- exe "unlockvar l"
- elseif u == 2
- exe "unlockvar " . depth . " l"
- endif
- let ps = islocked("l") . islocked("l[1]") . islocked("l[1][1]") .
- \ islocked("l[1][1][0]") . '-' . islocked("l[2]") .
- \ islocked("l[2]['6']") . islocked("l[2]['6'][7]")
- $put =ps
- let ps = ''
- try
- unlet l[2]['6'][7]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- unlet l[2][6]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- unlet l[2]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- unlet l[1][1][0]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- unlet l[1][1]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- unlet l[1]
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- try
- unlet l
- let ps .= 'p'
- catch
- let ps .= 'F'
- endtry
- $put =ps
- endfor
- endfor]=])
- expect([[
-
- depth is 0
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- depth is 1
- 1000-000
- ppFppFp
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- depth is 2
- 1100-100
- pFFpFFp
- 0000-000
- ppppppp
- 0000-000
- ppppppp
- depth is 3
- 1110-110
- FFFFFFp
- 0010-010
- FppFppp
- 0000-000
- ppppppp
- depth is 4
- 1111-111
- FFFFFFp
- 0011-011
- FppFppp
- 0000-000
- ppppppp]])
- end)
-
it('locked variables and :unlet or list / dict functions', function()
source([[
$put ='Locks and commands or functions:'
@@ -676,30 +468,6 @@ describe('list and dictionary types', function()
['a', 'b', 3]]=])
end)
- it('locked variables (part 2)', function()
- feed_command(
- 'let l = [1, 2, 3, 4]',
- 'lockvar! l',
- '$put =string(l)',
- 'unlockvar l[1]',
- 'unlet l[0:1]',
- '$put =string(l)',
- 'unlet l[1:2]',
- '$put =string(l)',
- 'unlockvar l[1]',
- 'let l[0:1] = [0, 1]',
- '$put =string(l)',
- 'let l[1:2] = [0, 1]',
- '$put =string(l)')
- expect([=[
-
- [1, 2, 3, 4]
- [1, 2, 3, 4]
- [1, 2, 3, 4]
- [1, 2, 3, 4]
- [1, 2, 3, 4]]=])
- end)
-
it(':lockvar/islocked() triggering script autoloading.', function()
source([[
set rtp+=test/functional/fixtures
@@ -907,7 +675,7 @@ describe('list and dictionary types', function()
feed('o<C-R>=a<CR><esc>')
feed_command('lang C')
feed_command('redir => a')
- -- The test failes if this is not in one line.
+ -- The test fails if this is not in one line.
feed_command("try|foobar|catch|let a = matchstr(v:exception,'^[^ ]*')|endtry")
feed_command('redir END')
feed('o<C-R>=a<CR><esc>')
diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua
index d164d9c02f..235a826640 100644
--- a/test/functional/legacy/063_match_and_matchadd_spec.lua
+++ b/test/functional/legacy/063_match_and_matchadd_spec.lua
@@ -3,10 +3,8 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local eval, clear, command = helpers.eval, helpers.clear, helpers.command
-local eq, neq = helpers.eq, helpers.neq
+local clear, command = helpers.clear, helpers.command
local insert = helpers.insert
-local pcall_err = helpers.pcall_err
describe('063: Test for ":match", "matchadd()" and related functions', function()
setup(clear)
@@ -19,105 +17,9 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
[1] = {background = Screen.colors.Red},
})
- -- Check that "matcharg()" returns the correct group and pattern if a match
- -- is defined.
command("highlight MyGroup1 term=bold ctermbg=red guibg=red")
command("highlight MyGroup2 term=italic ctermbg=green guibg=green")
command("highlight MyGroup3 term=underline ctermbg=blue guibg=blue")
- command("match MyGroup1 /TODO/")
- command("2match MyGroup2 /FIXME/")
- command("3match MyGroup3 /XXX/")
- eq({'MyGroup1', 'TODO'}, eval('matcharg(1)'))
- eq({'MyGroup2', 'FIXME'}, eval('matcharg(2)'))
- eq({'MyGroup3', 'XXX'}, eval('matcharg(3)'))
-
- -- Check that "matcharg()" returns an empty list if the argument is not 1,
- -- 2 or 3 (only 0 and 4 are tested).
- eq({}, eval('matcharg(0)'))
- eq({}, eval('matcharg(4)'))
-
- -- Check that "matcharg()" returns ['', ''] if a match is not defined.
- command("match")
- command("2match")
- command("3match")
- eq({'', ''}, eval('matcharg(1)'))
- eq({'', ''}, eval('matcharg(2)'))
- eq({'', ''}, eval('matcharg(3)'))
-
- -- Check that "matchadd()" and "getmatches()" agree on added matches and
- -- that default values apply.
- command("let m1 = matchadd('MyGroup1', 'TODO')")
- command("let m2 = matchadd('MyGroup2', 'FIXME', 42)")
- command("let m3 = matchadd('MyGroup3', 'XXX', 60, 17)")
- eq({{group = 'MyGroup1', pattern = 'TODO', priority = 10, id = 4},
- {group = 'MyGroup2', pattern = 'FIXME', priority = 42, id = 5},
- {group = 'MyGroup3', pattern = 'XXX', priority = 60, id = 17}},
- eval('getmatches()'))
-
- -- Check that "matchdelete()" deletes the matches defined in the previous
- -- test correctly.
- command("call matchdelete(m1)")
- command("call matchdelete(m2)")
- command("call matchdelete(m3)")
- eq({}, eval('getmatches()'))
-
- --- Check that "matchdelete()" returns 0 if successful and otherwise -1.
- command("let m = matchadd('MyGroup1', 'TODO')")
- eq(0, eval('matchdelete(m)'))
-
- -- matchdelete throws error and returns -1 on failure
- neq(true, pcall(function() eval('matchdelete(42)') end))
- eq('Vim(let):E803: ID not found: 42', pcall_err(command, 'let r2 = matchdelete(42)'))
-
- -- Check that "clearmatches()" clears all matches defined by ":match" and
- -- "matchadd()".
- command("let m1 = matchadd('MyGroup1', 'TODO')")
- command("let m2 = matchadd('MyGroup2', 'FIXME', 42)")
- command("let m3 = matchadd('MyGroup3', 'XXX', 60, 17)")
- command("match MyGroup1 /COFFEE/")
- command("2match MyGroup2 /HUMPPA/")
- command("3match MyGroup3 /VIM/")
- command("call clearmatches()")
- eq({}, eval('getmatches()'))
-
- -- Check that "setmatches()" restores a list of matches saved by
- -- "getmatches()" without changes. (Matches with equal priority must also
- -- remain in the same order.)
- command("let m1 = matchadd('MyGroup1', 'TODO')")
- command("let m2 = matchadd('MyGroup2', 'FIXME', 42)")
- command("let m3 = matchadd('MyGroup3', 'XXX', 60, 17)")
- command("match MyGroup1 /COFFEE/")
- command("2match MyGroup2 /HUMPPA/")
- command("3match MyGroup3 /VIM/")
- command("let ml = getmatches()")
- local ml = eval("ml")
- command("call clearmatches()")
- command("call setmatches(ml)")
- eq(ml, eval('getmatches()'))
-
- -- Check that "setmatches()" can correctly restore the matches from matchaddpos()
- command("call clearmatches()")
- command("call setmatches(ml)")
- eq(ml, eval('getmatches()'))
-
- -- Check that "setmatches()" will not add two matches with the same ID. The
- -- expected behaviour (for now) is to add the first match but not the
- -- second and to return -1.
- eq('Vim(let):E801: ID already taken: 1',
- pcall_err(command, "let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])"))
- eq({{group = 'MyGroup1', pattern = 'TODO', priority = 10, id = 1}}, eval('getmatches()'))
-
- -- Check that "setmatches()" returns 0 if successful and otherwise -1.
- -- (A range of valid and invalid input values are tried out to generate the
- -- return values.)
- eq(0,eval("setmatches([])"))
- eq(0,eval("setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}])"))
- command("call clearmatches()")
- eq('Vim(let):E714: List required', pcall_err(command, 'let rf1 = setmatches(0)'))
- eq('Vim(let):E474: List item 0 is either not a dictionary or an empty one',
- pcall_err(command, 'let rf2 = setmatches([0])'))
- eq('Vim(let):E474: List item 0 is missing one of the required keys',
- pcall_err(command, "let rf3 = setmatches([{'wrong key': 'wrong value'}])"))
-- Check that "matchaddpos()" positions matches correctly
insert('abcdefghijklmnopq')
diff --git a/test/functional/legacy/072_undo_file_spec.lua b/test/functional/legacy/072_undo_file_spec.lua
index b4927e779e..80665027c3 100644
--- a/test/functional/legacy/072_undo_file_spec.lua
+++ b/test/functional/legacy/072_undo_file_spec.lua
@@ -69,7 +69,7 @@ describe('72', function()
feed_command('set undofile ul=100')
feed('uuuuuu:w >>test.out<cr>')
- ---- Open the output to see if it meets the expections
+ ---- Open the output to see if it meets the expectations
feed_command('e! test.out')
-- Assert buffer contents.
diff --git a/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua b/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua
index e94b46ca66..54620c7104 100644
--- a/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua
+++ b/test/functional/legacy/083_tag_search_with_file_encoding_spec.lua
@@ -26,7 +26,7 @@ describe('tag search with !_TAG_FILE_ENCODING', function()
'!_TAG_FILE_ENCODING cp932 //\n' ..
'\130`\130a\130b Xtags2.txt /\130`\130a\130b\n'
)
- -- The last file is very long but repetetive and can be generated on the
+ -- The last file is very long but repetitive and can be generated on the
-- fly.
local text = helpers.dedent([[
!_TAG_FILE_SORTED 1 //
diff --git a/test/functional/legacy/097_glob_path_spec.lua b/test/functional/legacy/097_glob_path_spec.lua
index dd5a26ad3b..a62dc4d4c8 100644
--- a/test/functional/legacy/097_glob_path_spec.lua
+++ b/test/functional/legacy/097_glob_path_spec.lua
@@ -10,7 +10,7 @@ describe('glob() and globpath()', function()
setup(clear)
setup(function()
- if helpers.iswin() then
+ if helpers.is_os('win') then
os.execute("md sautest\\autoload")
os.execute(".>sautest\\autoload\\Test104.vim 2>nul")
os.execute(".>sautest\\autoload\\footest.vim 2>nul")
@@ -28,7 +28,7 @@ describe('glob() and globpath()', function()
-- Consistent sorting of file names
command('set nofileignorecase')
- if helpers.iswin() then
+ if helpers.is_os('win') then
command([[$put =glob('Xxx{')]])
command([[$put =glob('Xxx$')]])
@@ -72,7 +72,7 @@ describe('glob() and globpath()', function()
end)
teardown(function()
- if helpers.iswin() then
+ if helpers.is_os('win') then
os.execute('del /q/f Xxx{ Xxx$')
os.execute('rd /q /s sautest')
else
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index 4d9e88c446..a15809907b 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -3,7 +3,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, command, eq = helpers.clear, helpers.command, helpers.eq
-local eval, exc_exec, neq = helpers.eval, helpers.exc_exec, helpers.neq
local expect_exit = helpers.expect_exit
local feed = helpers.feed
local pcall_err = helpers.pcall_err
@@ -11,233 +10,6 @@ local pcall_err = helpers.pcall_err
describe('argument list commands', function()
before_each(clear)
- local function init_abc()
- command('args a b c')
- command('next')
- end
-
- local function reset_arglist()
- command('arga a | %argd')
- end
-
- local function assert_fails(cmd, err)
- neq(nil, exc_exec(cmd):find(err))
- end
-
- it('test that argidx() works', function()
- command('args a b c')
- command('last')
- eq(2, eval('argidx()'))
- command('%argdelete')
- eq(0, eval('argidx()'))
-
- command('args a b c')
- eq(0, eval('argidx()'))
- command('next')
- eq(1, eval('argidx()'))
- command('next')
- eq(2, eval('argidx()'))
- command('1argdelete')
- eq(1, eval('argidx()'))
- command('1argdelete')
- eq(0, eval('argidx()'))
- command('1argdelete')
- eq(0, eval('argidx()'))
- end)
-
- it('test that argadd() works', function()
- command('%argdelete')
- command('argadd a b c')
- eq(0, eval('argidx()'))
-
- command('%argdelete')
- command('argadd a')
- eq(0, eval('argidx()'))
- command('argadd b c d')
- eq(0, eval('argidx()'))
-
- init_abc()
- command('argadd x')
- eq({'a', 'b', 'x', 'c'}, eval('argv()'))
- eq(1, eval('argidx()'))
-
- init_abc()
- command('0argadd x')
- eq({'x', 'a', 'b', 'c'}, eval('argv()'))
- eq(2, eval('argidx()'))
-
- init_abc()
- command('1argadd x')
- eq({'a', 'x', 'b', 'c'}, eval('argv()'))
- eq(2, eval('argidx()'))
-
- init_abc()
- command('$argadd x')
- eq({'a', 'b', 'c', 'x'}, eval('argv()'))
- eq(1, eval('argidx()'))
-
- init_abc()
- command('$argadd x')
- command('+2argadd y')
- eq({'a', 'b', 'c', 'x', 'y'}, eval('argv()'))
- eq(1, eval('argidx()'))
-
- command('%argd')
- command('edit d')
- command('arga')
- eq(1, eval('len(argv())'))
- eq('d', eval('get(argv(), 0, "")'))
-
- command('%argd')
- command('new')
- command('arga')
- eq(0, eval('len(argv())'))
- end)
-
- it('test for 0argadd and 0argedit', function()
- reset_arglist()
-
- command('arga a b c d')
- command('2argu')
- command('0arga added')
- eq({'added', 'a', 'b', 'c', 'd'}, eval('argv()'))
-
- command('%argd')
- command('arga a b c d')
- command('2argu')
- command('0arge edited')
- eq({'edited', 'a', 'b', 'c', 'd'}, eval('argv()'))
-
- command('2argu')
- command('arga third')
- eq({'edited', 'a', 'third', 'b', 'c', 'd'}, eval('argv()'))
- end)
-
- it('test for argc()', function()
- reset_arglist()
- eq(0, eval('argc()'))
- command('argadd a b')
- eq(2, eval('argc()'))
- end)
-
- it('test for arglistid()', function()
- reset_arglist()
- command('arga a b')
- eq(0, eval('arglistid()'))
- command('split')
- command('arglocal')
- eq(1, eval('arglistid()'))
- command('tabnew | tabfirst')
- eq(0, eval('arglistid(2)'))
- eq(1, eval('arglistid(1, 1)'))
- eq(0, eval('arglistid(2, 1)'))
- eq(1, eval('arglistid(1, 2)'))
- command('tabonly | only | enew!')
- command('argglobal')
- eq(0, eval('arglistid()'))
- end)
-
- it('test for argv()', function()
- reset_arglist()
- eq({}, eval('argv()'))
- eq('', eval('argv(2)'))
- command('argadd a b c d')
- eq('c', eval('argv(2)'))
- end)
-
- it('test for :argedit command', function()
- reset_arglist()
- command('argedit a')
- eq({'a'}, eval('argv()'))
- eq('a', eval('expand("%:t")'))
- command('argedit b')
- eq({'a', 'b'}, eval('argv()'))
- eq('b', eval('expand("%:t")'))
- command('argedit a')
- eq({'a', 'b', 'a'}, eval('argv()'))
- eq('a', eval('expand("%:t")'))
- command('argedit c')
- eq({'a', 'b', 'a', 'c'}, eval('argv()'))
- command('0argedit x')
- eq({'x', 'a', 'b', 'a', 'c'}, eval('argv()'))
- command('set nohidden')
- command('enew! | set modified')
- assert_fails('argedit y', 'E37:')
- command('argedit! y')
- eq({'x', 'y', 'y', 'a', 'b', 'a', 'c'}, eval('argv()'))
- command('set hidden')
- command('%argd')
- command('argedit a b')
- eq({'a', 'b'}, eval('argv()'))
- end)
-
- it('test for :argdelete command', function()
- reset_arglist()
- command('args aa a aaa b bb')
- command('argdelete a*')
- eq({'b', 'bb'}, eval('argv()'))
- eq('aa', eval('expand("%:t")'))
- command('last')
- command('argdelete %')
- eq({'b'}, eval('argv()'))
- assert_fails('argdelete', 'E610:')
- assert_fails('1,100argdelete', 'E16:')
- reset_arglist()
- command('args a b c d')
- command('next')
- command('argdel')
- eq({'a', 'c', 'd'}, eval('argv()'))
- command('%argdel')
- end)
-
- it('test for the :next, :prev, :first, :last, :rewind commands', function()
- reset_arglist()
- command('args a b c d')
- command('last')
- eq(3, eval('argidx()'))
- assert_fails('next', 'E165:')
- command('prev')
- eq(2, eval('argidx()'))
- command('Next')
- eq(1, eval('argidx()'))
- command('first')
- eq(0, eval('argidx()'))
- assert_fails('prev', 'E164:')
- command('3next')
- eq(3, eval('argidx()'))
- command('rewind')
- eq(0, eval('argidx()'))
- command('%argd')
- end)
-
- it('test for autocommand that redefines the argument list, when doing ":all"', function()
- command('autocmd BufReadPost Xxx2 next Xxx2 Xxx1')
- command("call writefile(['test file Xxx1'], 'Xxx1')")
- command("call writefile(['test file Xxx2'], 'Xxx2')")
- command("call writefile(['test file Xxx3'], 'Xxx3')")
-
- command('new')
- -- redefine arglist; go to Xxx1
- command('next! Xxx1 Xxx2 Xxx3')
- -- open window for all args
- command('all')
- eq('test file Xxx1', eval('getline(1)'))
- command('wincmd w')
- command('wincmd w')
- eq('test file Xxx1', eval('getline(1)'))
- -- should now be in Xxx2
- command('rewind')
- eq('test file Xxx2', eval('getline(1)'))
-
- command('autocmd! BufReadPost Xxx2')
- command('enew! | only')
- command("call delete('Xxx1')")
- command("call delete('Xxx2')")
- command("call delete('Xxx3')")
- command('argdelete Xxx*')
- command('bwipe! Xxx1 Xxx2 Xxx3')
- end)
-
it('quitting Vim with unedited files in the argument list throws E173', function()
command('set nomore')
command('args a b c')
diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua
index 5e586d3a6a..e00b468c16 100644
--- a/test/functional/legacy/autocmd_option_spec.lua
+++ b/test/functional/legacy/autocmd_option_spec.lua
@@ -211,7 +211,7 @@ describe('au OptionSet', function()
expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
end)
- it('should trigger if the current buffer is different from the targetted buffer', function()
+ it('should trigger if the current buffer is different from the targeted buffer', function()
local new_buffer = make_buffer()
local new_bufnr = buf.get_number(new_buffer)
@@ -590,7 +590,7 @@ describe('au OptionSet', function()
expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
end)
- it('should trigger if the current buffer is different from the targetted buffer', function()
+ it('should trigger if the current buffer is different from the targeted buffer', function()
set_hook('buftype')
local new_buffer = make_buffer()
@@ -616,7 +616,7 @@ describe('au OptionSet', function()
expected_combination({'backup', 0, 0, '', 1, 'local', 'setlocal'})
end)
- it('should not trigger if the current window is different from the targetted window', function()
+ it('should not trigger if the current window is different from the targeted window', function()
set_hook('cursorcolumn')
local new_winnr = get_new_window_number()
diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua
new file mode 100644
index 0000000000..d7779684a4
--- /dev/null
+++ b/test/functional/legacy/breakindent_spec.lua
@@ -0,0 +1,44 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('breakindent', function()
+ -- oldtest: Test_cursor_position_with_showbreak()
+ it('cursor shown at correct position with showbreak', function()
+ local screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue}, -- SignColumn
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ exec([[
+ let &signcolumn = 'yes'
+ let &showbreak = '+'
+ let leftcol = win_getid()->getwininfo()->get(0, {})->get('textoff')
+ eval repeat('x', &columns - leftcol - 1)->setline(1)
+ eval 'second line'->setline(2)
+ ]])
+ screen:expect([[
+ {1: }^xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+ {1: }second line |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('AX')
+ screen:expect([[
+ {1: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX|
+ {1: }^second line |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/buffer_spec.lua b/test/functional/legacy/buffer_spec.lua
new file mode 100644
index 0000000000..acaa9a51f1
--- /dev/null
+++ b/test/functional/legacy/buffer_spec.lua
@@ -0,0 +1,59 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, source = helpers.clear, helpers.source
+local call, eq, meths = helpers.call, helpers.eq, helpers.meths
+
+local function expected_empty()
+ eq({}, meths.get_vvar('errors'))
+end
+
+describe('buffer', function()
+ before_each(function()
+ clear()
+ meths.ui_attach(80, 24, {})
+ meths.set_option('hidden', false)
+ end)
+
+ it('deleting a modified buffer with :confirm', function()
+ source([[
+ func Test_bdel_with_confirm()
+ new
+ call setline(1, 'test')
+ call assert_fails('bdel', 'E89:')
+ call nvim_input('c')
+ confirm bdel
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, &modified)
+ call nvim_input('n')
+ confirm bdel
+ call assert_equal(1, winnr('$'))
+ endfunc
+ ]])
+ call('Test_bdel_with_confirm')
+ expected_empty()
+ end)
+
+ it('editing another buffer from a modified buffer with :confirm', function()
+ source([[
+ func Test_goto_buf_with_confirm()
+ new Xfile
+ enew
+ call setline(1, 'test')
+ call assert_fails('b Xfile', 'E37:')
+ call nvim_input('c')
+ call assert_fails('confirm b Xfile', 'E37:')
+ call assert_equal(1, &modified)
+ call assert_equal('', @%)
+ call nvim_input('y')
+ call assert_fails('confirm b Xfile', 'E37:')
+ call assert_equal(1, &modified)
+ call assert_equal('', @%)
+ call nvim_input('n')
+ confirm b Xfile
+ call assert_equal('Xfile', @%)
+ close!
+ endfunc
+ ]])
+ call('Test_goto_buf_with_confirm')
+ expected_empty()
+ end)
+end)
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
index cf02636890..2fceb6a132 100644
--- a/test/functional/legacy/cmdline_spec.lua
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -1,9 +1,12 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
+local command = helpers.command
local feed = helpers.feed
local feed_command = helpers.feed_command
local exec = helpers.exec
+local meths = helpers.meths
+local pesc = helpers.pesc
describe('cmdline', function()
before_each(clear)
@@ -18,8 +21,6 @@ describe('cmdline', function()
[3] = {reverse = true};
[4] = {bold = true, foreground = Screen.colors.Blue1};
}
- -- TODO(bfredl): redraw with tabs is severly broken. fix it
- feed_command [[ set display-=msgsep ]]
feed_command([[call setline(1, range(30))]])
screen:expect([[
@@ -60,7 +61,7 @@ describe('cmdline', function()
{4:~ }|
|
|
- :tabnew |
+ |
]]}
feed [[gt]]
@@ -140,4 +141,180 @@ describe('cmdline', function()
:^ |
]])
end)
+
+ -- oldtest: Test_redraw_in_autocmd()
+ it('cmdline cursor position is correct after :redraw with cmdheight=2', function()
+ local screen = Screen.new(30, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ set cmdheight=2
+ autocmd CmdlineChanged * redraw
+ ]])
+ feed(':for i in range(3)<CR>')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ :for i in range(3) |
+ : ^ |
+ ]])
+ feed(':let i =')
+ -- Note: this may still be considered broken, ref #18140
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ : :let i =^ |
+ |
+ ]])
+ end)
+
+ it("setting 'cmdheight' works after outputting two messages vim-patch:9.0.0665", function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, reverse = true}, -- StatusLine
+ })
+ screen:attach()
+ exec([[
+ set cmdheight=1 laststatus=2
+ func EchoTwo()
+ set laststatus=2
+ set cmdheight=5
+ echo 'foo'
+ echo 'bar'
+ set cmdheight=1
+ endfunc
+ ]])
+ feed(':call EchoTwo()')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
+ :call EchoTwo()^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
+ |
+ ]])
+ end)
+
+ -- oldtest: Test_cmdheight_tabline()
+ it("changing 'cmdheight' when there is a tabline", function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, reverse = true}, -- StatusLine
+ [2] = {bold = true}, -- TabLineSel
+ [3] = {reverse = true}, -- TabLineFill
+ })
+ screen:attach()
+ meths.set_option('laststatus', 2)
+ meths.set_option('showtabline', 2)
+ meths.set_option('cmdheight', 1)
+ screen:expect([[
+ {2: [No Name] }{3: }|
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
+ |
+ ]])
+ end)
+end)
+
+describe('cmdwin', function()
+ before_each(clear)
+
+ -- oldtest: Test_cmdwin_interrupted()
+ it('still uses a new buffer when interrupting more prompt on open', function()
+ local screen = Screen.new(30, 16)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, reverse = true}, -- StatusLine
+ [2] = {reverse = true}, -- StatusLineNC
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [4] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ command('set more')
+ command('autocmd WinNew * highlight')
+ feed('q:')
+ screen:expect({any = pesc('{3:-- More --}^')})
+ feed('q')
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:[No Name] }|
+ {0::}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[Command Line] }|
+ |
+ ]])
+ feed([[aecho 'done']])
+ screen:expect([[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:[No Name] }|
+ {0::}echo 'done'^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:[Command Line] }|
+ {4:-- INSERT --} |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ done |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua
index 4ba4c8d356..cefcd6c6c4 100644
--- a/test/functional/legacy/delete_spec.lua
+++ b/test/functional/legacy/delete_spec.lua
@@ -48,7 +48,7 @@ describe('Test for delete()', function()
it('symlink directory delete', function()
command("call mkdir('Xdir1')")
- if helpers.iswin() then
+ if helpers.is_os('win') then
command("silent !mklink /j Xlink Xdir1")
else
command("silent !ln -s Xdir1 Xlink")
diff --git a/test/functional/legacy/digraph_spec.lua b/test/functional/legacy/digraph_spec.lua
new file mode 100644
index 0000000000..0cb0bb84be
--- /dev/null
+++ b/test/functional/legacy/digraph_spec.lua
@@ -0,0 +1,46 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('digraph', function()
+ -- oldtest: Test_entering_digraph()
+ it('characters displayed on the screen', function()
+ local screen = Screen.new(10, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ feed('i<C-K>')
+ screen:expect([[
+ {1:^?} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ feed('1')
+ screen:expect([[
+ {1:^1} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ feed('2')
+ screen:expect([[
+ ½^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index f0ffaf2c48..f9b78f5dcd 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -9,6 +9,7 @@ local command = helpers.command
describe('display', function()
before_each(clear)
+ -- oldtest: Test_display_scroll_at_topline()
it('scroll when modified at topline vim-patch:8.2.1488', function()
local screen = Screen.new(20, 4)
screen:attach()
@@ -26,6 +27,7 @@ describe('display', function()
]])
end)
+ -- oldtest: Test_display_scroll_update_visual()
it('scrolling when modified at topline in Visual mode vim-patch:8.2.4626', function()
local screen = Screen.new(60, 8)
screen:attach()
@@ -56,8 +58,53 @@ describe('display', function()
]])
end)
- it('@@@ in the last line shows correctly in a narrow window vim-patch:8.2.4718', function()
- local screen = Screen.new(60, 10)
+ -- oldtest: Test_matchparen_clear_highlight()
+ it('matchparen highlight is cleared when switching buffer', function()
+ local screen = Screen.new(20, 5)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue},
+ [1] = {background = Screen.colors.Cyan},
+ })
+ screen:attach()
+
+ local screen1 = [[
+ {1:^()} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]
+ local screen2 = [[
+ ^aa |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]
+
+ exec([[
+ source $VIMRUNTIME/plugin/matchparen.vim
+ set hidden
+ call setline(1, ['()'])
+ normal 0
+ ]])
+ screen:expect(screen1)
+
+ exec([[
+ enew
+ exe "normal iaa\<Esc>0"
+ ]])
+ screen:expect(screen2)
+
+ feed('<C-^>')
+ screen:expect(screen1)
+
+ feed('<C-^>')
+ screen:expect(screen2)
+ end)
+
+ local function run_test_display_lastline(euro)
+ local screen = Screen.new(75, 10)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
[2] = {bold = true, reverse = true}, -- StatusLine
@@ -65,39 +112,86 @@ describe('display', function()
})
screen:attach()
exec([[
- call setline(1, ['aaa', 'b'->repeat(100)])
+ call setline(1, ['aaa', 'b'->repeat(200)])
set display=truncate
+
vsplit
100wincmd <
]])
- screen:expect([[
- ^a│aaa |
- a│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
- a│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
- b│{1:~ }|
- b│{1:~ }|
- b│{1:~ }|
- b│{1:~ }|
- {1:@}│{1:~ }|
- {2:< }{3:[No Name] [+] }|
- |
- ]])
+ local fillchar = '@'
+ if euro then
+ command('set fillchars=lastline:€')
+ fillchar = '€'
+ end
+ screen:expect((([[
+ ^a│aaa |
+ a│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ a│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ b│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ b│{1:~ }|
+ b│{1:~ }|
+ b│{1:~ }|
+ {1:@}│{1:~ }|
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]]):gsub('@', fillchar)))
+
command('set display=lastline')
screen:expect_unchanged()
+
command('100wincmd >')
- screen:expect([[
- ^aaa │a|
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│a|
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb │a|
- {1:~ }│b|
- {1:~ }│b|
- {1:~ }│b|
- {1:~ }│b|
- {1:~ }│{1:@}|
- {2:[No Name] [+] }{3:<}|
- |
- ]])
+ screen:expect((([[
+ ^aaa │a|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│a|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│a|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb │b|
+ {1:~ }│b|
+ {1:~ }│b|
+ {1:~ }│b|
+ {1:~ }│{1:@}|
+ {2:[No Name] [+] }{3:<}|
+ |
+ ]]):gsub('@', fillchar)))
+
command('set display=truncate')
screen:expect_unchanged()
+
+ command('close')
+ command('3split')
+ screen:expect((([[
+ ^aaa |
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ {1:@@@ }|
+ {2:[No Name] [+] }|
+ aaa |
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ {3:[No Name] [+] }|
+ |
+ ]]):gsub('@', fillchar)))
+
+ command('close')
+ command('2vsplit')
+ screen:expect((([[
+ ^aa│aaa |
+ a │bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ bb│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ bb│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ bb│{1:~ }|
+ bb│{1:~ }|
+ bb│{1:~ }|
+ {1:@@}│{1:~ }|
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]]):gsub('@', fillchar)))
+ end
+
+ -- oldtest: Test_display_lastline()
+ it('display "lastline" works correctly', function()
+ run_test_display_lastline()
+ end)
+ it('display "lastline" works correctly with multibyte fillchar', function()
+ run_test_display_lastline(true)
end)
end)
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
index 7fc5f11a79..362d33a0fd 100644
--- a/test/functional/legacy/edit_spec.lua
+++ b/test/functional/legacy/edit_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local expect = helpers.expect
@@ -7,20 +8,51 @@ local sleep = helpers.sleep
before_each(clear)
--- oldtest: Test_autoindent_remove_indent()
-it('autoindent removes indent when Insert mode is stopped', function()
- command('set autoindent')
- -- leaving insert mode in a new line with indent added by autoindent, should
- -- remove the indent.
- feed('i<Tab>foo<CR><Esc>')
- -- Need to delay for sometime, otherwise the code in getchar.c will not be
- -- exercised.
- sleep(50)
- -- when a line is wrapped and the cursor is at the start of the second line,
- -- leaving insert mode, should move the cursor back to the first line.
- feed('o' .. ('x'):rep(20) .. '<Esc>')
- -- Need to delay for sometime, otherwise the code in getchar.c will not be
- -- exercised.
- sleep(50)
- expect('\tfoo\n\n' .. ('x'):rep(20))
+describe('edit', function()
+ -- oldtest: Test_autoindent_remove_indent()
+ it('autoindent removes indent when Insert mode is stopped', function()
+ command('set autoindent')
+ -- leaving insert mode in a new line with indent added by autoindent, should
+ -- remove the indent.
+ feed('i<Tab>foo<CR><Esc>')
+ -- Need to delay for sometime, otherwise the code in getchar.c will not be
+ -- exercised.
+ sleep(50)
+ -- when a line is wrapped and the cursor is at the start of the second line,
+ -- leaving insert mode, should move the cursor back to the first line.
+ feed('o' .. ('x'):rep(20) .. '<Esc>')
+ -- Need to delay for sometime, otherwise the code in getchar.c will not be
+ -- exercised.
+ sleep(50)
+ expect('\tfoo\n\n' .. ('x'):rep(20))
+ end)
+
+ -- oldtest: Test_edit_insert_reg()
+ it('inserting a register using CTRL-R', function()
+ local screen = Screen.new(10, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ feed('a<C-R>')
+ screen:expect([[
+ {1:^"} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ feed('=')
+ screen:expect([[
+ {1:"} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ =^ |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index 05d853622e..b5e45a86c1 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -639,7 +639,7 @@ describe('eval', function()
end)
it('function name includes a colon', function()
- eq('Vim(function):E128: Function name must start with a capital or "s:": b:test()\\nendfunction',
+ eq('Vim(function):E884: Function name cannot contain a colon: b:test()\\nendfunction',
exc_exec(dedent([[
function! b:test()
endfunction]])))
diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua
index ece88d26bd..eb480a6689 100644
--- a/test/functional/legacy/excmd_spec.lua
+++ b/test/functional/legacy/excmd_spec.lua
@@ -7,12 +7,12 @@ local exec_lua = helpers.exec_lua
local expect_exit = helpers.expect_exit
local feed = helpers.feed
local funcs = helpers.funcs
-local iswin = helpers.iswin
local meths = helpers.meths
local read_file = helpers.read_file
local source = helpers.source
local eq = helpers.eq
local write_file = helpers.write_file
+local is_os = helpers.is_os
local function sizeoflong()
if not exec_lua('return pcall(require, "ffi")') then
@@ -376,7 +376,7 @@ describe(':confirm command dialog', function()
{3:(Y)es, [N]o: }^ |
]])
feed('Y')
- if iswin() then
+ if is_os('win') then
screen:expect([[
foobar |
{0:~ }|
@@ -416,7 +416,7 @@ describe(':confirm command dialog', function()
{3:(Y)es, [N]o: }^ |
]])
feed('Y')
- if iswin() then
+ if is_os('win') then
screen:expect([[
foobar |
{1: }|
@@ -493,7 +493,7 @@ describe(':confirm command dialog', function()
{3:(Y)es, [N]o: }^ |
]])
feed('Y')
- if iswin() then
+ if is_os('win') then
screen:expect([[
a |
b |
diff --git a/test/functional/legacy/filechanged_spec.lua b/test/functional/legacy/filechanged_spec.lua
index 1f23528d61..cea1d6ac30 100644
--- a/test/functional/legacy/filechanged_spec.lua
+++ b/test/functional/legacy/filechanged_spec.lua
@@ -1,6 +1,8 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, source = helpers.clear, helpers.source
local call, eq, meths = helpers.call, helpers.eq, helpers.meths
+local is_os = helpers.is_os
+local skip = helpers.skip
local function expected_empty()
eq({}, meths.get_vvar('errors'))
@@ -15,7 +17,7 @@ describe('file changed dialog', function()
end)
it('works', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
source([[
func Test_file_changed_dialog()
au! FileChangedShell
diff --git a/test/functional/legacy/fold_spec.lua b/test/functional/legacy/fold_spec.lua
new file mode 100644
index 0000000000..83513a3f94
--- /dev/null
+++ b/test/functional/legacy/fold_spec.lua
@@ -0,0 +1,335 @@
+-- Tests for folding.
+local Screen = require('test.functional.ui.screen')
+
+local helpers = require('test.functional.helpers')(after_each)
+local feed, insert, feed_command, expect_any =
+ helpers.feed, helpers.insert, helpers.feed_command, helpers.expect_any
+local command = helpers.command
+local exec = helpers.exec
+
+describe('folding', function()
+ local screen
+
+ before_each(function()
+ helpers.clear()
+
+ screen = Screen.new(45, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey}, -- Folded
+ [3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey}, -- FoldColumn
+ [4] = {foreground = Screen.colors.Brown}, -- LineNr
+ })
+ screen:attach()
+ end)
+
+ it('creation, opening, moving (to the end) and closing', function()
+ insert([[
+ 1 aa
+ 2 bb
+ 3 cc
+ last
+ ]])
+
+ -- Basic test if a fold can be created, opened, moving to the end and
+ -- closed.
+ feed_command('1')
+ feed('zf2j')
+ feed_command('call append("$", "manual " . getline(foldclosed(".")))')
+ feed('zo')
+ feed_command('call append("$", foldclosed("."))')
+ feed(']z')
+ feed_command('call append("$", getline("."))')
+ feed('zc')
+ feed_command('call append("$", getline(foldclosed(".")))')
+
+ expect_any([[
+ manual 1 aa
+ -1
+ 3 cc
+ 1 aa]])
+ end)
+
+ it("foldmethod=marker", function()
+ screen:try_resize(20, 10)
+ insert([[
+ dd {{{
+ ee {{{ }}}
+ ff }}}
+ ]])
+ feed_command('set fdm=marker fdl=1')
+ feed_command('2')
+ feed_command('call append("$", "line 2 foldlevel=" . foldlevel("."))')
+ feed('[z')
+ feed_command('call append("$", foldlevel("."))')
+ feed('jo{{ <esc>r{jj') -- writes '{{{' and moves 2 lines bot
+ feed_command('call append("$", foldlevel("."))')
+ feed('kYpj')
+ feed_command('call append("$", foldlevel("."))')
+
+ helpers.poke_eventloop()
+ screen:expect([[
+ dd {{{ |
+ ee {{{ }}} |
+ {{{ |
+ ff }}} |
+ ff }}} |
+ ^ |
+ line 2 foldlevel=2 |
+ 1 |
+ 1 |
+ |
+ ]])
+
+ end)
+
+ it("foldmethod=indent", function()
+ screen:try_resize(20, 8)
+ feed_command('set fdm=indent sw=2')
+ insert([[
+ aa
+ bb
+ cc
+ last
+ ]])
+ feed_command('call append("$", "foldlevel line3=" . foldlevel(3))')
+ feed_command('call append("$", foldlevel(2))')
+ feed('zR')
+
+ helpers.poke_eventloop()
+ screen:expect([[
+ aa |
+ bb |
+ cc |
+ last |
+ ^ |
+ foldlevel line3=2 |
+ 1 |
+ |
+ ]])
+ end)
+
+ it("foldmethod=syntax", function()
+ screen:try_resize(35, 15)
+ insert([[
+ 1 aa
+ 2 bb
+ 3 cc
+ 4 dd {{{
+ 5 ee {{{ }}}
+ 6 ff }}}
+ 7 gg
+ 8 hh
+ 9 ii
+ a jj
+ b kk
+ last]])
+ feed_command('set fdm=syntax fdl=0')
+ feed_command('syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3')
+ feed_command('syn region Fd1 start="ee" end="ff" fold contained')
+ feed_command('syn region Fd2 start="gg" end="hh" fold contained')
+ feed_command('syn region Fd3 start="commentstart" end="commentend" fold contained')
+ feed('Gzk')
+ feed_command('call append("$", "folding " . getline("."))')
+ feed('k')
+ feed_command('call append("$", getline("."))')
+ feed('jAcommentstart <esc>Acommentend<esc>')
+ feed_command('set fdl=1')
+ feed('3j')
+ feed_command('call append("$", getline("."))')
+ feed_command('set fdl=0')
+ feed('zO<C-L>j') -- <C-L> redraws screen
+ feed_command('call append("$", getline("."))')
+ feed_command('set fdl=0')
+ expect_any([[
+ folding 9 ii
+ 3 cc
+ 9 ii
+ a jj]])
+ end)
+
+ it("foldmethod=expression", function()
+ insert([[
+ 1 aa
+ 2 bb
+ 3 cc
+ 4 dd {{{
+ 5 ee {{{ }}}
+ 6 ff }}}
+ 7 gg
+ 8 hh
+ 9 ii
+ a jj
+ b kk
+ last ]])
+
+ feed_command([[
+ fun Flvl()
+ let l = getline(v:lnum)
+ if l =~ "bb$"
+ return 2
+ elseif l =~ "gg$"
+ return "s1"
+ elseif l =~ "ii$"
+ return ">2"
+ elseif l =~ "kk$"
+ return "0"
+ endif
+ return "="
+ endfun
+ ]])
+ feed_command('set fdm=expr fde=Flvl()')
+ feed_command('/bb$')
+ feed_command('call append("$", "expr " . foldlevel("."))')
+ feed_command('/hh$')
+ feed_command('call append("$", foldlevel("."))')
+ feed_command('/ii$')
+ feed_command('call append("$", foldlevel("."))')
+ feed_command('/kk$')
+ feed_command('call append("$", foldlevel("."))')
+
+ expect_any([[
+ expr 2
+ 1
+ 2
+ 0]])
+ end)
+
+ it('can be opened after :move', function()
+ -- luacheck: ignore
+ screen:try_resize(35, 8)
+ insert([[
+ Test fdm=indent and :move bug END
+ line2
+ Test fdm=indent START
+ line3
+ line4]])
+ feed_command('set noai nosta ')
+ feed_command('set fdm=indent')
+ feed_command('1m1')
+ feed('2jzc')
+ feed_command('m0')
+ feed('zR')
+
+ expect_any([[
+ Test fdm=indent START
+ line3
+ line4
+ Test fdm=indent and :move bug END
+ line2]])
+ end)
+
+ -- oldtest: Test_folds_with_rnu()
+ it('with relative line numbers', function()
+ command('set fdm=marker rnu foldcolumn=2')
+ command('call setline(1, ["{{{1", "nline 1", "{{{1", "line 2"])')
+
+ screen:expect([[
+ {3:+ }{4: 0 }{2:^+-- 2 lines: ·························}|
+ {3:+ }{4: 1 }{2:+-- 2 lines: ·························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed("j")
+ screen:expect([[
+ {3:+ }{4: 1 }{2:+-- 2 lines: ·························}|
+ {3:+ }{4: 0 }{2:^+-- 2 lines: ·························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ -- oldtest: Test_foldclose_opt()
+ it('foldclose=all', function()
+ exec([[
+ set foldmethod=manual foldclose=all foldopen=all
+ call setline(1, ['one', 'two', 'three', 'four'])
+ 2,3fold
+ ]])
+
+ screen:expect([[
+ ^one |
+ {2:+-- 2 lines: two····························}|
+ four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('2G')
+ screen:expect([[
+ one |
+ ^two |
+ three |
+ four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('4G')
+ screen:expect([[
+ one |
+ {2:+-- 2 lines: two····························}|
+ ^four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('3G')
+ screen:expect([[
+ one |
+ two |
+ ^three |
+ four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('1G')
+ screen:expect([[
+ ^one |
+ {2:+-- 2 lines: two····························}|
+ four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('2G')
+ screen:expect([[
+ one |
+ ^two |
+ three |
+ four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('k')
+ screen:expect([[
+ ^one |
+ {2:+-- 2 lines: two····························}|
+ four |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/gf_spec.lua b/test/functional/legacy/gf_spec.lua
index f1b1790ba1..9f725446be 100644
--- a/test/functional/legacy/gf_spec.lua
+++ b/test/functional/legacy/gf_spec.lua
@@ -10,6 +10,7 @@ describe('gf', function()
it('is not allowed when buffer is locked', function()
command('au OptionSet diff norm! gf')
command([[call setline(1, ['Xfile1', 'line2', 'line3', 'line4'])]])
- eq('Vim(normal):E788: Not allowed to edit another buffer now', pcall_err(command, 'diffthis'))
+ eq('OptionSet Autocommands for "diff": Vim(normal):E788: Not allowed to edit another buffer now',
+ pcall_err(command, 'diffthis'))
end)
end)
diff --git a/test/functional/legacy/increment_spec.lua b/test/functional/legacy/increment_spec.lua
index d51f9a2e02..d35f4bdae6 100644
--- a/test/functional/legacy/increment_spec.lua
+++ b/test/functional/legacy/increment_spec.lua
@@ -285,7 +285,7 @@ describe('Ctrl-A/Ctrl-X on visual selections', function()
" 1
" 1
" 1
- " Expexted:
+ " Expected:
" 1) g Ctrl-A on block selected indented lines
" 2
" 1
diff --git a/test/functional/legacy/listlbr_spec.lua b/test/functional/legacy/listlbr_spec.lua
index f70d55f4a3..d4f11a61c2 100644
--- a/test/functional/legacy/listlbr_spec.lua
+++ b/test/functional/legacy/listlbr_spec.lua
@@ -1,11 +1,12 @@
-- Test for linebreak and list option (non-utf8)
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
describe('listlbr', function()
- setup(clear)
+ before_each(clear)
-- luacheck: ignore 621 (Indentation)
-- luacheck: ignore 611 (Line contains only whitespaces)
@@ -195,4 +196,97 @@ describe('listlbr', function()
aa>-----a-$
~ ]])
end)
+
+ -- oldtest: Test_linebreak_reset_restore()
+ it('cursor position is drawn correctly after operator', function()
+ local screen = Screen.new(60, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.LightGrey}, -- Visual
+ [2] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
+ })
+ screen:attach()
+
+ -- f_wincol() calls validate_cursor()
+ source([[
+ set linebreak showcmd noshowmode formatexpr=wincol()-wincol()
+ call setline(1, repeat('a', &columns - 10) .. ' bbbbbbbbbb c')
+ ]])
+
+ feed('$v$')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb {1:c}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ 2 |
+ ]])
+ feed('zo')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb ^c |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} |
+ ]])
+
+ feed('$v$')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb {1:c}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} 2 |
+ ]])
+ feed('gq')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb ^c |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} |
+ ]])
+
+ feed('$<C-V>$')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb {1:c}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} 1x2 |
+ ]])
+ feed('I')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb ^c |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} |
+ ]])
+
+ feed('<Esc>$v$')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb {1:c}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} 2 |
+ ]])
+ feed('s')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ bbbbbbbbbb ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:E490: No fold found} |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/match_spec.lua b/test/functional/legacy/match_spec.lua
new file mode 100644
index 0000000000..b6e45c396c
--- /dev/null
+++ b/test/functional/legacy/match_spec.lua
@@ -0,0 +1,126 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('matchaddpos()', function()
+ -- oldtest: Test_matchaddpos_dump()
+ it('can add more than 8 match positions vim-patch:9.0.0620', function()
+ local screen = Screen.new(60, 14)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Yellow}, -- Search
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['1234567890123']->repeat(14))
+ call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]}))
+ ]])
+ screen:expect([[
+ {1:^1}234567890123 |
+ 1{1:2}34567890123 |
+ 12{1:3}4567890123 |
+ 123{1:4}567890123 |
+ 1234{1:5}67890123 |
+ 12345{1:6}7890123 |
+ 123456{1:7}890123 |
+ 1234567{1:8}90123 |
+ 12345678{1:9}0123 |
+ 123456789{1:0}123 |
+ 1234567890{1:1}23 |
+ 12345678901{1:2}3 |
+ 1234567890123 |
+ |
+ ]])
+ end)
+end)
+
+describe('match highlighting', function()
+ -- oldtest: Test_match_in_linebreak()
+ it('does not continue in linebreak vim-patch:8.2.3698', function()
+ local screen = Screen.new(75, 10)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
+ })
+ screen:attach()
+ exec([=[
+ set breakindent linebreak breakat+=]
+ call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1)
+ call matchaddpos('ErrorMsg', [[1, 51]])
+ ]=])
+ screen:expect([[
+ ^xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx{1:]} |
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('is shown with incsearch vim-patch:8.2.3940', function()
+ local screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Yellow}, -- Search
+ [2] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
+ })
+ screen:attach()
+ exec([[
+ set incsearch
+ call setline(1, range(20))
+ call matchaddpos('ErrorMsg', [3])
+ ]])
+ screen:expect([[
+ ^0 |
+ 1 |
+ {2:2} |
+ 3 |
+ 4 |
+ |
+ ]])
+ feed(':s/0')
+ screen:expect([[
+ {1:0} |
+ 1 |
+ {2:2} |
+ 3 |
+ 4 |
+ :s/0^ |
+ ]])
+ end)
+
+ it('on a Tab vim-patch:8.2.4062', function()
+ local screen = Screen.new(75, 10)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
+ })
+ screen:attach()
+ exec([[
+ set linebreak
+ call setline(1, "\tix")
+ call matchadd('ErrorMsg', '\t')
+ ]])
+ screen:expect([[
+ {1: ^ }ix |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index eec89aa919..59839157ea 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -3,15 +3,14 @@ local clear = helpers.clear
local eval = helpers.eval
local eq = helpers.eq
local feed_command = helpers.feed_command
-local iswin = helpers.iswin
local retry = helpers.retry
local ok = helpers.ok
local source = helpers.source
local poke_eventloop = helpers.poke_eventloop
-local uname = helpers.uname
local load_adjust = helpers.load_adjust
local write_file = helpers.write_file
-local isCI = helpers.isCI
+local is_os = helpers.is_os
+local is_ci = helpers.is_ci
local function isasan()
local version = eval('execute("version")')
@@ -22,8 +21,8 @@ clear()
if isasan() then
pending('ASAN build is difficult to estimate memory usage', function() end)
return
-elseif iswin() then
- if isCI('github') then
+elseif is_os('win') then
+ if is_ci('github') then
pending('Windows runners in Github Actions do not have a stable environment to estimate memory usage', function() end)
return
elseif eval("executable('wmic')") == 0 then
@@ -38,7 +37,7 @@ end
local monitor_memory_usage = {
memory_usage = function(self)
local handle
- if iswin() then
+ if is_os('win') then
handle = io.popen('wmic process where processid=' ..self.pid..' get WorkingSetSize')
else
handle = io.popen('ps -o rss= -p '..self.pid)
@@ -167,9 +166,9 @@ describe('memory usage', function()
local last = monitor_memory_usage(pid)
-- The usage may be a bit less than the last value, use 80%.
-- Allow for 20% tolerance at the upper limit. That's very permissive, but
- -- otherwise the test fails sometimes. On Sourcehut CI with FreeBSD we need to
- -- be even much more permissive.
- local upper_multiplier = uname() == 'freebsd' and 19 or 12
+ -- otherwise the test fails sometimes. On FreeBSD we need to be even much
+ -- more permissive.
+ local upper_multiplier = is_os('freebsd') and 19 or 12
local lower = before.last * 8 / 10
local upper = load_adjust((after.max + (after.last - before.last)) * upper_multiplier / 10)
check_result({before=before, after=after, last=last},
@@ -179,7 +178,7 @@ describe('memory usage', function()
end)
it('releases memory when closing windows when folds exist', function()
- if helpers.is_os('mac') then
+ if is_os('mac') then
pending('macOS memory compression causes flakiness')
end
local pid = eval('getpid()')
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
index 159cf7a551..71a53c8381 100644
--- a/test/functional/legacy/messages_spec.lua
+++ b/test/functional/legacy/messages_spec.lua
@@ -4,27 +4,65 @@ local clear = helpers.clear
local command = helpers.command
local exec = helpers.exec
local feed = helpers.feed
+local meths = helpers.meths
+local nvim_dir = helpers.nvim_dir
before_each(clear)
describe('messages', function()
local screen
+ -- oldtest: Test_warning_scroll()
+ it('a warning causes scrolling if and only if it has a stacktrace', function()
+ screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [2] = {bold = true, reverse = true}, -- MsgSeparator
+ [3] = {foreground = Screen.colors.Red}, -- WarningMsg
+ })
+ screen:attach()
+
+ -- When the warning comes from a script, messages are scrolled so that the
+ -- stacktrace is visible.
+ -- It is a bit hard to assert the screen when sourcing a script, so skip this part.
+
+ -- When the warning does not come from a script, messages are not scrolled.
+ command('enew')
+ command('set readonly')
+ feed('u')
+ screen:expect({grid = [[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:W10: Warning: Changing a readonly file}^ |
+ ]], timeout = 500})
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ Already at oldest change |
+ ]])
+ end)
+
describe('more prompt', function()
before_each(function()
+ command('set more')
+ end)
+
+ -- oldtest: Test_message_more()
+ it('works', function()
screen = Screen.new(75, 6)
screen:set_default_attr_ids({
- [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
[1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
[2] = {foreground = Screen.colors.Brown}, -- LineNr
- [3] = {foreground = Screen.colors.Blue}, -- SpecialKey
})
screen:attach()
- command('set more')
- end)
- -- oldtest: Test_message_more()
- it('works', function()
command('call setline(1, range(1, 100))')
feed(':%pfoo<C-H><C-H><C-H>#')
@@ -313,16 +351,139 @@ describe('messages', function()
]])
end)
+ -- oldtest: Test_echo_verbose_system()
+ it('verbose message before echo command', function()
+ screen = Screen.new(60, 10)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ })
+ screen:attach()
+
+ command('cd '..nvim_dir)
+ meths.set_option('shell', './shell-test')
+ meths.set_option('shellcmdflag', 'REP 20')
+ meths.set_option('shellxquote', '') -- win: avoid extra quotes
+
+ -- display a page and go back, results in exactly the same view
+ feed([[:4 verbose echo system('foo')<CR>]])
+ screen:expect([[
+ Executing command: "'./shell-test' 'REP' '20' 'foo'" |
+ |
+ 0: foo |
+ 1: foo |
+ 2: foo |
+ 3: foo |
+ 4: foo |
+ 5: foo |
+ 6: foo |
+ {1:-- More --}^ |
+ ]])
+ feed('<Space>')
+ screen:expect([[
+ 7: foo |
+ 8: foo |
+ 9: foo |
+ 10: foo |
+ 11: foo |
+ 12: foo |
+ 13: foo |
+ 14: foo |
+ 15: foo |
+ {1:-- More --}^ |
+ ]])
+ feed('b')
+ screen:expect([[
+ Executing command: "'./shell-test' 'REP' '20' 'foo'" |
+ |
+ 0: foo |
+ 1: foo |
+ 2: foo |
+ 3: foo |
+ 4: foo |
+ 5: foo |
+ 6: foo |
+ {1:-- More --}^ |
+ ]])
+
+ -- do the same with 'cmdheight' set to 2
+ feed('q')
+ command('set ch=2')
+ command('mode') -- FIXME: bottom is invalid after scrolling
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ |
+ ]])
+ feed([[:4 verbose echo system('foo')<CR>]])
+ screen:expect([[
+ Executing command: "'./shell-test' 'REP' '20' 'foo'" |
+ |
+ 0: foo |
+ 1: foo |
+ 2: foo |
+ 3: foo |
+ 4: foo |
+ 5: foo |
+ 6: foo |
+ {1:-- More --}^ |
+ ]])
+ feed('<Space>')
+ screen:expect([[
+ 7: foo |
+ 8: foo |
+ 9: foo |
+ 10: foo |
+ 11: foo |
+ 12: foo |
+ 13: foo |
+ 14: foo |
+ 15: foo |
+ {1:-- More --}^ |
+ ]])
+ feed('b')
+ screen:expect([[
+ Executing command: "'./shell-test' 'REP' '20' 'foo'" |
+ |
+ 0: foo |
+ 1: foo |
+ 2: foo |
+ 3: foo |
+ 4: foo |
+ 5: foo |
+ 6: foo |
+ {1:-- More --}^ |
+ ]])
+ end)
+
-- oldtest: Test_quit_long_message()
it('with control characters can be quit vim-patch:8.2.1844', function()
- screen:try_resize(40, 6)
+ screen = Screen.new(40, 10)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [2] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ })
+ screen:attach()
+
feed([[:echom range(9999)->join("\x01")<CR>]])
screen:expect([[
- 0{3:^A}1{3:^A}2{3:^A}3{3:^A}4{3:^A}5{3:^A}6{3:^A}7{3:^A}8{3:^A}9{3:^A}10{3:^A}11{3:^A}12|
- {3:^A}13{3:^A}14{3:^A}15{3:^A}16{3:^A}17{3:^A}18{3:^A}19{3:^A}20{3:^A}21{3:^A}22|
- {3:^A}23{3:^A}24{3:^A}25{3:^A}26{3:^A}27{3:^A}28{3:^A}29{3:^A}30{3:^A}31{3:^A}32|
- {3:^A}33{3:^A}34{3:^A}35{3:^A}36{3:^A}37{3:^A}38{3:^A}39{3:^A}40{3:^A}41{3:^A}42|
- {3:^A}43{3:^A}44{3:^A}45{3:^A}46{3:^A}47{3:^A}48{3:^A}49{3:^A}50{3:^A}51{3:^A}52|
+ 0{2:^A}1{2:^A}2{2:^A}3{2:^A}4{2:^A}5{2:^A}6{2:^A}7{2:^A}8{2:^A}9{2:^A}10{2:^A}11{2:^A}12|
+ {2:^A}13{2:^A}14{2:^A}15{2:^A}16{2:^A}17{2:^A}18{2:^A}19{2:^A}20{2:^A}21{2:^A}22|
+ {2:^A}23{2:^A}24{2:^A}25{2:^A}26{2:^A}27{2:^A}28{2:^A}29{2:^A}30{2:^A}31{2:^A}32|
+ {2:^A}33{2:^A}34{2:^A}35{2:^A}36{2:^A}37{2:^A}38{2:^A}39{2:^A}40{2:^A}41{2:^A}42|
+ {2:^A}43{2:^A}44{2:^A}45{2:^A}46{2:^A}47{2:^A}48{2:^A}49{2:^A}50{2:^A}51{2:^A}52|
+ {2:^A}53{2:^A}54{2:^A}55{2:^A}56{2:^A}57{2:^A}58{2:^A}59{2:^A}60{2:^A}61{2:^A}62|
+ {2:^A}63{2:^A}64{2:^A}65{2:^A}66{2:^A}67{2:^A}68{2:^A}69{2:^A}70{2:^A}71{2:^A}72|
+ {2:^A}73{2:^A}74{2:^A}75{2:^A}76{2:^A}77{2:^A}78{2:^A}79{2:^A}80{2:^A}81{2:^A}82|
+ {2:^A}83{2:^A}84{2:^A}85{2:^A}86{2:^A}87{2:^A}88{2:^A}89{2:^A}90{2:^A}91{2:^A}92|
{1:-- More --}^ |
]])
feed('q')
@@ -332,6 +493,10 @@ describe('messages', function()
{0:~ }|
{0:~ }|
{0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
|
]])
end)
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index 67991f5d48..3f1f85cf28 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -14,7 +14,7 @@ describe('search cmdline', function()
before_each(function()
clear()
- command('set nohlsearch')
+ command('set nohlsearch inccommand=')
screen = Screen.new(20, 3)
screen:attach()
screen:set_default_attr_ids({
@@ -472,8 +472,8 @@ describe('search cmdline', function()
funcs.winsaveview())
end)
+ -- oldtest: Test_search_cmdline4().
it("CTRL-G with 'incsearch' and ? goes in the right direction", function()
- -- oldtest: Test_search_cmdline4().
screen:try_resize(40, 4)
command('enew!')
funcs.setline(1, {' 1 the first', ' 2 the second', ' 3 the third'})
@@ -573,8 +573,8 @@ describe('search cmdline', function()
]])
end)
+ -- oldtest: Test_incsearch_sort_dump().
it('incsearch works with :sort', function()
- -- oldtest: Test_incsearch_sort_dump().
screen:try_resize(20, 4)
command('set incsearch hlsearch scrolloff=0')
funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
@@ -589,8 +589,8 @@ describe('search cmdline', function()
feed('<esc>')
end)
+ -- oldtest: Test_incsearch_vimgrep_dump().
it('incsearch works with :vimgrep family', function()
- -- oldtest: Test_incsearch_vimgrep_dump().
screen:try_resize(30, 4)
command('set incsearch hlsearch scrolloff=0')
funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
@@ -640,11 +640,74 @@ describe('search cmdline', function()
]])
feed('<esc>')
end)
+
+ -- oldtest: Test_incsearch_substitute_dump2()
+ it('detects empty pattern properly vim-patch:8.2.2295', function()
+ screen:try_resize(70, 6)
+ exec([[
+ set incsearch hlsearch scrolloff=0
+ for n in range(1, 4)
+ call setline(n, "foo " . n)
+ endfor
+ call setline(5, "abc|def")
+ 3
+ ]])
+
+ feed([[:%s/\vabc|]])
+ screen:expect([[
+ foo 1 |
+ foo 2 |
+ foo 3 |
+ foo 4 |
+ abc|def |
+ :%s/\vabc|^ |
+ ]])
+ feed('<Esc>')
+
+ -- The following should not be highlighted
+ feed([[:1,5s/\v|]])
+ screen:expect([[
+ foo 1 |
+ foo 2 |
+ foo 3 |
+ foo 4 |
+ abc|def |
+ :1,5s/\v|^ |
+ ]])
+ end)
end)
describe('Search highlight', function()
before_each(clear)
- it('Search highlight is combined with Visual highlight vim-patch:8.2.2797', function()
+
+ -- oldtest: Test_hlsearch_dump()
+ it('beyond line end vim-patch:8.2.2542', function()
+ local screen = Screen.new(50, 6)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {background = Screen.colors.Yellow}, -- Search
+ [3] = {background = Screen.colors.Grey90}, -- CursorLine
+ })
+ screen:attach()
+ exec([[
+ set hlsearch noincsearch cursorline
+ call setline(1, ["xxx", "xxx", "xxx"])
+ /.*
+ 2
+ ]])
+ feed([[/\_.*<CR>]])
+ screen:expect([[
+ {2:xxx } |
+ {2:xxx } |
+ {2:^xxx }{3: }|
+ {1:~ }|
+ {1:~ }|
+ /\_.* |
+ ]])
+ end)
+
+ -- oldtest: Test_hlsearch_and_visual()
+ it('is combined with Visual highlight vim-patch:8.2.2797', function()
local screen = Screen.new(40, 6)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
diff --git a/test/functional/legacy/search_stat_spec.lua b/test/functional/legacy/search_stat_spec.lua
index c2ca393a56..9fcf798836 100644
--- a/test/functional/legacy/search_stat_spec.lua
+++ b/test/functional/legacy/search_stat_spec.lua
@@ -17,6 +17,7 @@ describe('search stat', function()
screen:attach()
end)
+ -- oldtest: Test_search_stat_screendump()
it('right spacing with silent mapping vim-patch:8.1.1970', function()
exec([[
set shortmess-=S
@@ -57,6 +58,7 @@ describe('search stat', function()
]])
end)
+ -- oldtest: Test_search_stat_foldopen()
it('when only match is in fold vim-patch:8.2.0840', function()
exec([[
set shortmess-=S
@@ -86,6 +88,7 @@ describe('search stat', function()
screen:expect_unchanged()
end)
+ -- oldtest: Test_search_stat_then_gd()
it('is cleared by gd and gD vim-patch:8.2.3583', function()
exec([[
call setline(1, ['int cat;', 'int dog;', 'cat = dog;'])
@@ -120,6 +123,7 @@ describe('search stat', function()
]])
end)
+ -- oldtest: Test_search_stat_and_incsearch()
it('is not broken by calling searchcount() in tabline vim-patch:8.2.4378', function()
exec([[
call setline(1, ['abc--c', '--------abc', '--abc'])
diff --git a/test/functional/legacy/source_spec.lua b/test/functional/legacy/source_spec.lua
new file mode 100644
index 0000000000..f31521607d
--- /dev/null
+++ b/test/functional/legacy/source_spec.lua
@@ -0,0 +1,32 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+local write_file = helpers.write_file
+
+before_each(clear)
+
+describe(':source!', function()
+ -- oldtest: Test_nested_script()
+ it('gives E22 when scripts nested too deep', function()
+ write_file('Xscript.vim', [[
+ :source! Xscript.vim
+ ]])
+ local screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg
+ })
+ screen:attach()
+ feed(':source! Xscript.vim\n')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:E22: Scripts nested too deep} |
+ ]])
+ os.remove('Xscript.vim')
+ end)
+end)
diff --git a/test/functional/legacy/statusline_spec.lua b/test/functional/legacy/statusline_spec.lua
index e2b30a7c82..c5b17f8749 100644
--- a/test/functional/legacy/statusline_spec.lua
+++ b/test/functional/legacy/statusline_spec.lua
@@ -68,4 +68,87 @@ describe('statusline', function()
|
]])
end)
+
+ -- oldtest: Test_statusline_showcmd()
+ it('showcmdloc=statusline works', function()
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.LightGrey}, -- Visual
+ [2] = {bold = true}, -- MoreMsg
+ [3] = {bold = true, reverse = true}, -- StatusLine
+ [5] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue}, -- Folded
+ })
+ exec([[
+ func MyStatusLine()
+ return '%S'
+ endfunc
+
+ set showcmd
+ set laststatus=2
+ set statusline=%S
+ set showcmdloc=statusline
+ call setline(1, ['a', 'b', 'c'])
+ set foldopen+=jump
+ 1,2fold
+ 3
+ ]])
+
+ feed('g')
+ screen:expect([[
+ {5:+-- 2 lines: a···································}|
+ ^c |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:g }|
+ |
+ ]])
+
+ -- typing "gg" should open the fold
+ feed('g')
+ screen:expect([[
+ ^a |
+ b |
+ c |
+ {0:~ }|
+ {0:~ }|
+ {3: }|
+ |
+ ]])
+
+ feed('<C-V>Gl')
+ screen:expect([[
+ {1:a} |
+ {1:b} |
+ {1:c}^ |
+ {0:~ }|
+ {0:~ }|
+ {3:3x2 }|
+ {2:-- VISUAL BLOCK --} |
+ ]])
+
+ feed('<Esc>1234')
+ screen:expect([[
+ a |
+ b |
+ ^c |
+ {0:~ }|
+ {0:~ }|
+ {3:1234 }|
+ |
+ ]])
+
+ feed('<Esc>:set statusline=<CR>')
+ feed(':<CR>')
+ feed('1234')
+ screen:expect([[
+ a |
+ b |
+ ^c |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] [+] 1234 }|
+ : |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/080_substitute_spec.lua b/test/functional/legacy/substitute_spec.lua
index faeb61e3af..f3ce343680 100644
--- a/test/functional/legacy/080_substitute_spec.lua
+++ b/test/functional/legacy/substitute_spec.lua
@@ -3,11 +3,13 @@
-- Test for *:s%* on :substitute.
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local feed, insert = helpers.feed, helpers.insert
+local exec = helpers.exec
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
local eq, eval = helpers.eq, helpers.eval
-describe('substitue()', function()
+describe('substitute()', function()
before_each(clear)
-- The original test contained several TEST_X lines to delimit different
@@ -132,7 +134,7 @@ describe('substitue()', function()
end)
end)
-describe(':substitue', function()
+describe(':substitute', function()
before_each(clear)
it('with \\ze and \\zs and confirmation dialog (TEST_8)', function()
@@ -159,4 +161,29 @@ describe(':substitue', function()
feed('yyq') -- For the dialog of the previous :s command.
expect('XXx')
end)
+
+ it('first char is highlighted with confirmation dialog and empty match', function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {reverse = true}, -- IncSearch
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ })
+ screen:attach()
+ exec([[
+ set nohlsearch noincsearch
+ call setline(1, ['one', 'two', 'three'])
+ ]])
+ feed(':%s/^/ /c<CR>')
+ screen:expect([[
+ {1:o}ne |
+ two |
+ three |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:replace with (y/n/a/q/l/^E/^Y)?}^ |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/syn_attr_spec.lua b/test/functional/legacy/syn_attr_spec.lua
index 06e8427e27..e6573da5d3 100644
--- a/test/functional/legacy/syn_attr_spec.lua
+++ b/test/functional/legacy/syn_attr_spec.lua
@@ -4,10 +4,10 @@ local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
-before_each(clear)
-
-- oldtest: Test_missing_attr()
-it('synIDattr() works', function()
+describe('synIDattr()', function()
+ setup(clear)
+
local bool_attrs = {
'bold',
'italic',
@@ -22,39 +22,55 @@ it('synIDattr() works', function()
'nocombine',
}
- command('hi Mine cterm=NONE gui=NONE')
- eq('Mine', eval([[synIDattr(hlID("Mine"), "name")]]))
- for _, mode in ipairs({'cterm', 'gui'}) do
- eq('', eval(([[synIDattr("Mine"->hlID(), "bg", '%s')]]):format(mode)))
- eq('', eval(([[synIDattr("Mine"->hlID(), "fg", '%s')]]):format(mode)))
- eq('', eval(([[synIDattr("Mine"->hlID(), "sp", '%s')]]):format(mode)))
- for _, attr in ipairs(bool_attrs) do
- eq('', eval(([[synIDattr(hlID("Mine"), "%s", '%s')]]):format(attr, mode)))
- eq('', eval(([[synIDattr(hlID("Mine"), "%s", '%s')]]):format(attr, mode)))
- eq('', eval(([[synIDattr(hlID("Mine"), "%s", '%s')]]):format(attr, mode)))
+ describe(':hi Mine cterm=NONE gui=NONE', function()
+ setup(function()
+ command(':hi Mine cterm=NONE gui=NONE')
+ end)
+
+ it('"name"', function()
+ eq('Mine', eval([[synIDattr(hlID("Mine"), "name")]]))
+ end)
+
+ local function none_test(attr, mode)
+ it(('"%s"'):format(attr), function()
+ eq('', eval(([[synIDattr(hlID("Mine"), "%s", '%s')]]):format(attr, mode)))
+ end)
end
- eq('', eval(([[synIDattr(hlID("Mine"), "inverse", '%s')]]):format(mode)))
+
+ for _, mode in ipairs({'cterm', 'gui'}) do
+ describe(('"%s"'):format(mode), function()
+ for _, attr in ipairs(bool_attrs) do
+ none_test(attr, mode)
+ end
+ for _, attr in ipairs({'inverse', 'bg', 'fg', 'sp'}) do
+ none_test(attr, mode)
+ end
+ end)
+ end
+ end)
+
+ local function attr_test(attr1, attr2)
+ local cmd = (':hi Mine cterm=%s gui=%s'):format(attr1, attr2)
+ it(cmd, function()
+ command(cmd)
+ eq('1', eval(([[synIDattr("Mine"->hlID(), "%s", 'cterm')]]):format(attr1)))
+ eq('', eval(([[synIDattr(hlID("Mine"), "%s", 'cterm')]]):format(attr2)))
+ eq('', eval(([[synIDattr("Mine"->hlID(), "%s", 'gui')]]):format(attr1)))
+ eq('1', eval(([[synIDattr(hlID("Mine"), "%s", 'gui')]]):format(attr2)))
+ end)
end
for i, attr1 in ipairs(bool_attrs) do
local attr2 = bool_attrs[i - 1] or bool_attrs[#bool_attrs]
-
- command(('hi Mine cterm=%s gui=%s'):format(attr1, attr2))
- eq('1', eval(([[synIDattr(hlID("Mine"), "%s", 'cterm')]]):format(attr1)))
- eq('', eval(([[synIDattr(hlID("Mine"), "%s", 'cterm')]]):format(attr2)))
- eq('', eval(([[synIDattr("Mine"->hlID(), "%s", 'gui')]]):format(attr1)))
- eq('1', eval(([[synIDattr("Mine"->hlID(), "%s", 'gui')]]):format(attr2)))
-
- command(('hi Mine cterm=%s gui=%s'):format(attr2, attr1))
- eq('', eval(([[synIDattr("Mine"->hlID(), "%s", 'cterm')]]):format(attr1)))
- eq('1', eval(([[synIDattr("Mine"->hlID(), "%s", 'cterm')]]):format(attr2)))
- eq('1', eval(([[synIDattr(hlID("Mine"), "%s", 'gui')]]):format(attr1)))
- eq('', eval(([[synIDattr(hlID("Mine"), "%s", 'gui')]]):format(attr2)))
+ attr_test(attr1, attr2)
+ attr_test(attr2, attr1)
end
- command('hi Mine cterm=reverse gui=inverse')
- eq('1', eval([[synIDattr(hlID("Mine"), "reverse", 'cterm')]]))
- eq('1', eval([[synIDattr(hlID("Mine"), "inverse", 'cterm')]]))
- eq('1', eval([[synIDattr(hlID("Mine"), "reverse", 'gui')]]))
- eq('1', eval([[synIDattr(hlID("Mine"), "inverse", 'gui')]]))
+ it(':hi Mine cterm=reverse gui=inverse', function()
+ command(':hi Mine cterm=reverse gui=inverse')
+ eq('1', eval([[synIDattr(hlID("Mine"), "reverse", 'cterm')]]))
+ eq('1', eval([[synIDattr(hlID("Mine"), "inverse", 'cterm')]]))
+ eq('1', eval([[synIDattr(hlID("Mine"), "reverse", 'gui')]]))
+ eq('1', eval([[synIDattr(hlID("Mine"), "inverse", 'gui')]]))
+ end)
end)
diff --git a/test/functional/legacy/tabline_spec.lua b/test/functional/legacy/tabline_spec.lua
new file mode 100644
index 0000000000..6b368d1857
--- /dev/null
+++ b/test/functional/legacy/tabline_spec.lua
@@ -0,0 +1,100 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('tabline', function()
+ local screen
+
+ before_each(function()
+ screen = Screen.new(50, 7)
+ screen:attach()
+ end)
+
+ -- oldtest: Test_tabline_showcmd()
+ it('showcmdloc=tabline works', function()
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.LightGrey}, -- Visual
+ [2] = {bold = true}, -- MoreMsg, TabLineSel
+ [3] = {reverse = true}, -- TabLineFill
+ [4] = {background = Screen.colors.LightGrey, underline = true}, -- TabLine
+ [5] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue}, -- Folded
+ })
+ exec([[
+ func MyTabLine()
+ return '%S'
+ endfunc
+
+ set showcmd
+ set showtabline=2
+ set tabline=%!MyTabLine()
+ set showcmdloc=tabline
+ call setline(1, ['a', 'b', 'c'])
+ set foldopen+=jump
+ 1,2fold
+ 3
+ ]])
+
+ feed('g')
+ screen:expect([[
+ {3:g }|
+ {5:+-- 2 lines: a···································}|
+ ^c |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ -- typing "gg" should open the fold
+ feed('g')
+ screen:expect([[
+ {3: }|
+ ^a |
+ b |
+ c |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<C-V>Gl')
+ screen:expect([[
+ {3:3x2 }|
+ {1:a} |
+ {1:b} |
+ {1:c}^ |
+ {0:~ }|
+ {0:~ }|
+ {2:-- VISUAL BLOCK --} |
+ ]])
+
+ feed('<Esc>1234')
+ screen:expect([[
+ {3:1234 }|
+ a |
+ b |
+ ^c |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+
+ feed('<Esc>:set tabline=<CR>')
+ feed(':<CR>')
+ feed('1234')
+ screen:expect([[
+ {2: + [No Name] }{3: }{4:1234}{3: }|
+ a |
+ b |
+ ^c |
+ {0:~ }|
+ {0:~ }|
+ : |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/vimscript_spec.lua b/test/functional/legacy/vimscript_spec.lua
new file mode 100644
index 0000000000..f59a87f824
--- /dev/null
+++ b/test/functional/legacy/vimscript_spec.lua
@@ -0,0 +1,90 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+local meths = helpers.meths
+
+before_each(clear)
+
+describe('Vim script', function()
+ -- oldtest: Test_deep_nest()
+ it('Error when if/for/while/try/function is nested too deep',function()
+ local screen = Screen.new(80, 24)
+ screen:attach()
+ meths.set_option('laststatus', 2)
+ exec([[
+ " Deep nesting of if ... endif
+ func Test1()
+ let @a = join(repeat(['if v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endif'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of for ... endfor
+ func Test2()
+ let @a = join(repeat(['for i in [1]'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endfor'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of while ... endwhile
+ func Test3()
+ let @a = join(repeat(['while v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endwhile'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of try ... endtry
+ func Test4()
+ let @a = join(repeat(['try'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endtry'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of function ... endfunction
+ func Test5()
+ let @a = join(repeat(['function X()'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endfunction'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+ ]])
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test1()<CR>')
+ screen:expect({any = 'E579: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test2()<CR>')
+ screen:expect({any = 'E585: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test3()<CR>')
+ screen:expect({any = 'E585: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test4()<CR>')
+ screen:expect({any = 'E601: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test5()<CR>')
+ screen:expect({any = 'E1058: '})
+ end)
+
+ -- oldtest: Test_typed_script_var()
+ it('using s: with a typed command', function()
+ local screen = Screen.new(80, 24)
+ screen:attach()
+ feed(":echo get(s:, 'foo', 'x')\n")
+ screen:expect({any = 'E116: '})
+ end)
+end)
diff --git a/test/functional/legacy/visual_mode_spec.lua b/test/functional/legacy/visual_mode_spec.lua
index 8b5dd0c2dc..1a08fb4c0e 100644
--- a/test/functional/legacy/visual_mode_spec.lua
+++ b/test/functional/legacy/visual_mode_spec.lua
@@ -1,31 +1,28 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local call = helpers.call
local clear = helpers.clear
local feed = helpers.feed
-local feed_command = helpers.feed_command
-local funcs = helpers.funcs
-local meths = helpers.meths
-local eq = helpers.eq
local exec = helpers.exec
-describe('visual line mode', function()
- local screen
+before_each(clear)
+describe('visual line mode', function()
+ -- oldtest: Test_visual_block_scroll()
it('redraws properly after scrolling with matchparen loaded and scrolloff=1', function()
- clear{args={'-u', 'NORC'}}
- screen = Screen.new(30, 7)
+ local screen = Screen.new(30, 7)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true},
[2] = {background = Screen.colors.LightGrey},
})
- eq(1, meths.get_var('loaded_matchparen'))
- feed_command('set scrolloff=1')
- funcs.setline(1, {'a', 'b', 'c', 'd', 'e', '', '{', '}', '{', 'f', 'g', '}'})
- call('cursor', 5, 1)
+ exec([[
+ source $VIMRUNTIME/plugin/matchparen.vim
+ set scrolloff=1
+ call setline(1, ['a', 'b', 'c', 'd', 'e', '', '{', '}', '{', 'f', 'g', '}'])
+ call cursor(5, 1)
+ ]])
feed('V<c-d><c-d>')
screen:expect([[
@@ -41,8 +38,8 @@ describe('visual line mode', function()
end)
describe('visual block mode', function()
+ -- oldtest: Test_visual_block_with_virtualedit()
it('shows selection correctly with virtualedit=block', function()
- clear()
local screen = Screen.new(30, 7)
screen:set_default_attr_ids({
[1] = {bold = true}, -- ModeMsg
diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua
new file mode 100644
index 0000000000..0e9775060d
--- /dev/null
+++ b/test/functional/legacy/window_cmd_spec.lua
@@ -0,0 +1,227 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+
+describe('splitkeep', function()
+ local screen
+
+ before_each(function()
+ clear('--cmd', 'set splitkeep=screen')
+ screen = Screen.new()
+ screen:attach()
+ end)
+
+ -- oldtest: Test_splitkeep_callback()
+ it('does not scroll when split in callback', function()
+ exec([[
+ call setline(1, range(&lines))
+ function C1(a, b, c)
+ split | wincmd p
+ endfunction
+ function C2(a, b, c)
+ close | split
+ endfunction
+ ]])
+ exec_lua([[
+ vim.api.nvim_set_keymap("n", "j", "", { callback = function()
+ vim.cmd("call jobstart([&sh, &shcf, 'true'], { 'on_exit': 'C1' })")
+ end
+ })]])
+ exec_lua([[
+ vim.api.nvim_set_keymap("n", "t", "", { callback = function()
+ vim.api.nvim_set_current_win(
+ vim.api.nvim_open_win(vim.api.nvim_create_buf(false, {}), false, {
+ width = 10,
+ relative = "cursor",
+ height = 4,
+ row = 0,
+ col = 0,
+ }))
+ vim.cmd("call termopen([&sh, &shcf, 'true'], { 'on_exit': 'C2' })")
+ end
+ })]])
+ feed('j')
+ screen:expect([[
+ 0 |
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ [No Name] [+] |
+ ^7 |
+ 8 |
+ 9 |
+ 10 |
+ 11 |
+ [No Name] [+] |
+ |
+ ]])
+ feed(':quit<CR>Ht')
+ screen:expect([[
+ ^0 |
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ [No Name] [+] |
+ 7 |
+ 8 |
+ 9 |
+ 10 |
+ 11 |
+ [No Name] [+] |
+ :quit |
+ ]])
+ feed(':set sb<CR>:quit<CR>Gj')
+ screen:expect([[
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ ^5 |
+ [No Name] [+] |
+ 7 |
+ 8 |
+ 9 |
+ 10 |
+ 11 |
+ 12 |
+ [No Name] [+] |
+ :quit |
+ ]])
+ feed(':quit<CR>Gt')
+ screen:expect([[
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
+ [No Name] [+] |
+ 7 |
+ 8 |
+ 9 |
+ 10 |
+ 11 |
+ ^12 |
+ [No Name] [+] |
+ :quit |
+ ]])
+ end)
+
+ -- oldtest: Test_splitkeep_fold()
+ it('does not scroll when window has closed folds', function()
+ exec([[
+ set splitkeep=screen
+ set foldmethod=marker
+ set number
+ let line = 1
+ for n in range(1, &lines)
+ call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
+ \ 'after fold'])
+ let line += 8
+ endfor
+ ]])
+ feed('L:wincmd s<CR>')
+ screen:expect([[
+ 1 +-- 7 lines: int FuncName() {···················|
+ 8 after fold |
+ 9 +-- 7 lines: int FuncName() {···················|
+ 16 after fold |
+ 17 +-- 7 lines: int FuncName() {···················|
+ 24 ^after fold |
+ [No Name] [+] |
+ 32 after fold |
+ 33 +-- 7 lines: int FuncName() {···················|
+ 40 after fold |
+ 41 +-- 7 lines: int FuncName() {···················|
+ 48 after fold |
+ [No Name] [+] |
+ :wincmd s |
+ ]])
+ feed(':quit<CR>')
+ screen:expect([[
+ 1 +-- 7 lines: int FuncName() {···················|
+ 8 after fold |
+ 9 +-- 7 lines: int FuncName() {···················|
+ 16 after fold |
+ 17 +-- 7 lines: int FuncName() {···················|
+ 24 after fold |
+ 25 +-- 7 lines: int FuncName() {···················|
+ 32 after fold |
+ 33 +-- 7 lines: int FuncName() {···················|
+ 40 after fold |
+ 41 +-- 7 lines: int FuncName() {···················|
+ 48 after fold |
+ 49 ^+-- 7 lines: int FuncName() {···················|
+ :quit |
+ ]])
+ feed('H:below split<CR>')
+ screen:expect([[
+ 1 +-- 7 lines: int FuncName() {···················|
+ 8 after fold |
+ 9 +-- 7 lines: int FuncName() {···················|
+ 16 after fold |
+ 17 +-- 7 lines: int FuncName() {···················|
+ [No Name] [+] |
+ 25 ^+-- 7 lines: int FuncName() {···················|
+ 32 after fold |
+ 33 +-- 7 lines: int FuncName() {···················|
+ 40 after fold |
+ 41 +-- 7 lines: int FuncName() {···················|
+ 48 after fold |
+ [No Name] [+] |
+ :below split |
+ ]])
+ feed(':wincmd k<CR>:quit<CR>')
+ screen:expect([[
+ 1 +-- 7 lines: int FuncName() {···················|
+ 8 after fold |
+ 9 +-- 7 lines: int FuncName() {···················|
+ 16 after fold |
+ 17 +-- 7 lines: int FuncName() {···················|
+ 24 after fold |
+ 25 ^+-- 7 lines: int FuncName() {···················|
+ 32 after fold |
+ 33 +-- 7 lines: int FuncName() {···················|
+ 40 after fold |
+ 41 +-- 7 lines: int FuncName() {···················|
+ 48 after fold |
+ 49 +-- 7 lines: int FuncName() {···················|
+ :quit |
+ ]])
+ end)
+
+ -- oldtest: Test_splitkeep_status()
+ it('does not scroll when split in callback', function()
+ exec([[
+ call setline(1, ['a', 'b', 'c'])
+ set nomodified
+ set splitkeep=screen
+ let win = winnr()
+ wincmd s
+ wincmd j
+ ]])
+ feed(':call win_move_statusline(win, 1)<CR>')
+ screen:expect([[
+ a |
+ b |
+ c |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] |
+ ^a |
+ b |
+ c |
+ ~ |
+ [No Name] |
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index f173a15d32..03832978a4 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -166,7 +166,7 @@ describe('luaeval(vim.api.…)', function()
eq({v={}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})'))
-- If API requests dictionary, then empty table will be the one. This is not
- -- the case normally because empty table is an empty arrray.
+ -- the case normally because empty table is an empty array.
eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({})'))
eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]]))
end)
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 10de45274c..2fd44b8b5f 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -118,6 +118,24 @@ describe('lua buffer event callbacks: on_lines', function()
}
tick = tick + 1
+ tick = tick + 1
+ command('redo')
+ check_events {
+ { "test1", "lines", 1, tick, 3, 5, 4, 32 };
+ { "test2", "lines", 1, tick, 3, 5, 4, 32 };
+ { "test2", "changedtick", 1, tick+1 };
+ }
+ tick = tick + 1
+
+ tick = tick + 1
+ command('undo!')
+ check_events {
+ { "test1", "lines", 1, tick, 3, 4, 5, 13 };
+ { "test2", "lines", 1, tick, 3, 4, 5, 13 };
+ { "test2", "changedtick", 1, tick+1 };
+ }
+ tick = tick + 1
+
-- simulate next callback returning true
exec_lua("test_unreg = 'test1'")
@@ -315,7 +333,7 @@ describe('lua: nvim_buf_attach on_bytes', function()
start_txt = meths.buf_get_lines(0, 0, -1, true)
end
local shadowbytes = table.concat(start_txt, '\n') .. '\n'
- -- TODO: while we are brewing the real strong coffe,
+ -- TODO: while we are brewing the real strong coffee,
-- verify should check buf_get_offset after every check_events
if verify then
local len = meths.buf_get_offset(0, meths.buf_line_count(0))
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index f9647f5b6a..d364986ad7 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -16,7 +16,7 @@ describe('vim.diagnostic', function()
exec_lua [[
require('vim.diagnostic')
- function make_diagnostic(msg, x1, y1, x2, y2, severity, source)
+ function make_diagnostic(msg, x1, y1, x2, y2, severity, source, code)
return {
lnum = x1,
col = y1,
@@ -25,23 +25,24 @@ describe('vim.diagnostic', function()
message = msg,
severity = severity,
source = source,
+ code = code,
}
end
- function make_error(msg, x1, y1, x2, y2, source)
- return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.ERROR, source)
+ function make_error(msg, x1, y1, x2, y2, source, code)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.ERROR, source, code)
end
- function make_warning(msg, x1, y1, x2, y2, source)
- return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.WARN, source)
+ function make_warning(msg, x1, y1, x2, y2, source, code)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.WARN, source, code)
end
- function make_info(msg, x1, y1, x2, y2, source)
- return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.INFO, source)
+ function make_info(msg, x1, y1, x2, y2, source, code)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.INFO, source, code)
end
- function make_hint(msg, x1, y1, x2, y2, source)
- return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.HINT, source)
+ function make_hint(msg, x1, y1, x2, y2, source, code)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.HINT, source, code)
end
function count_diagnostics(bufnr, severity, namespace)
@@ -89,20 +90,25 @@ describe('vim.diagnostic', function()
'DiagnosticFloatingError',
'DiagnosticFloatingHint',
'DiagnosticFloatingInfo',
+ 'DiagnosticFloatingOk',
'DiagnosticFloatingWarn',
'DiagnosticHint',
'DiagnosticInfo',
+ 'DiagnosticOk',
'DiagnosticSignError',
'DiagnosticSignHint',
'DiagnosticSignInfo',
+ 'DiagnosticSignOk',
'DiagnosticSignWarn',
'DiagnosticUnderlineError',
'DiagnosticUnderlineHint',
'DiagnosticUnderlineInfo',
+ 'DiagnosticUnderlineOk',
'DiagnosticUnderlineWarn',
'DiagnosticVirtualTextError',
'DiagnosticVirtualTextHint',
'DiagnosticVirtualTextInfo',
+ 'DiagnosticVirtualTextOk',
'DiagnosticVirtualTextWarn',
'DiagnosticWarn',
}, exec_lua([[return vim.fn.getcompletion('Diagnostic', 'highlight')]]))
@@ -128,6 +134,55 @@ describe('vim.diagnostic', function()
eq('Diagnostic #1', result[1].message)
end)
+ it('removes diagnostics from the cache when a buffer is removed', function()
+ eq(2, exec_lua [[
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ local other_bufnr = vim.fn.bufadd('test | test')
+ local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true)
+ vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines)
+ vim.cmd('bunload! ' .. other_bufnr)
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ vim.diagnostic.set(diagnostic_ns, other_bufnr, {
+ make_error('Diagnostic #3', 3, 1, 3, 1),
+ })
+ vim.api.nvim_set_current_buf(other_bufnr)
+ vim.opt_local.buflisted = true
+ vim.cmd('bwipeout!')
+ return #vim.diagnostic.get()
+ ]])
+ eq(2, exec_lua [[
+ vim.api.nvim_set_current_buf(diagnostic_bufnr)
+ vim.opt_local.buflisted = false
+ return #vim.diagnostic.get()
+ ]])
+ eq(0, exec_lua [[
+ vim.cmd('bwipeout!')
+ return #vim.diagnostic.get()
+ ]])
+ end)
+
+ it('removes diagnostic from stale cache on reset', function()
+ local diagnostics = exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ local other_bufnr = vim.fn.bufadd('test | test')
+ vim.cmd('noautocmd bwipeout! ' .. diagnostic_bufnr)
+ return vim.diagnostic.get(diagnostic_bufnr)
+ ]]
+ eq(2, #diagnostics)
+ diagnostics = exec_lua [[
+ vim.diagnostic.reset()
+ return vim.diagnostic.get()
+ ]]
+ eq(0, #diagnostics)
+ end)
+
it('resolves buffer number 0 to the current buffer', function()
eq(2, exec_lua [[
vim.api.nvim_set_current_buf(diagnostic_bufnr)
@@ -1129,6 +1184,44 @@ end)
eq(" some_linter: 👀 Warning", result[1][2][1])
eq(" another_linter: 🔥 Error", result[2][2][1])
end)
+
+ it('can add a suffix to virtual text', function()
+ eq(' Some error ✘', exec_lua [[
+ local diagnostics = {
+ make_error('Some error', 0, 0, 0, 0),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ suffix = ' ✘',
+ }
+ })
+
+ local extmarks = get_virt_text_extmarks(diagnostic_ns)
+ local virt_text = extmarks[1][4].virt_text[2][1]
+ return virt_text
+ ]])
+
+ eq(' Some error [err-code]', exec_lua [[
+ local diagnostics = {
+ make_error('Some error', 0, 0, 0, 0, nil, 'err-code'),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ suffix = function(diag) return string.format(' [%s]', diag.code) end,
+ }
+ })
+
+ local extmarks = get_virt_text_extmarks(diagnostic_ns)
+ local virt_text = extmarks[1][4].virt_text[2][1]
+ return virt_text
+ ]])
+ end)
end)
describe('set()', function()
@@ -1745,10 +1838,55 @@ end)
return lines
]])
- eq("Error executing lua: .../diagnostic.lua:0: prefix: expected 'string' or 'table' or 'function', got 42",
+ eq(".../diagnostic.lua:0: prefix: expected string|table|function, got number",
pcall_err(exec_lua, [[ vim.diagnostic.open_float({ prefix = 42 }) ]]))
end)
+ it('can add a suffix to diagnostics', function()
+ -- Default is to render the diagnostic error code
+ eq({'1. Syntax error [code-x]', '2. Some warning [code-y]'}, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"),
+ make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"})
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]])
+
+ eq({'1. Syntax error', '2. Some warning'}, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"),
+ make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer", suffix = ""})
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]])
+
+ -- Suffix is rendered on the last line of a multiline diagnostic
+ eq({'1. Syntax error', ' More context [code-x]'}, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error\nMore context", 0, 1, 0, 3, nil, "code-x"),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float({header = false, scope = "buffer"})
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]])
+
+ eq(".../diagnostic.lua:0: suffix: expected string|table|function, got number",
+ pcall_err(exec_lua, [[ vim.diagnostic.open_float({ suffix = 42 }) ]]))
+ end)
+
it('works with the old signature', function()
eq({'1. Syntax error'}, exec_lua [[
local diagnostics = {
@@ -1952,19 +2090,26 @@ end)
end)
it('triggers the autocommand when diagnostics are set', function()
- eq(true, exec_lua [[
+ eq({true, true}, exec_lua [[
-- Set a different buffer as current to test that <abuf> is being set properly in
-- DiagnosticChanged callbacks
local tmp = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_current_buf(tmp)
- vim.g.diagnostic_autocmd_triggered = 0
- vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")')
+ local triggered = {}
+ vim.api.nvim_create_autocmd('DiagnosticChanged', {
+ callback = function(args)
+ triggered = {args.buf, #args.data.diagnostics}
+ end,
+ })
vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test")
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error('Diagnostic', 0, 0, 0, 0)
})
- return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr
+ return {
+ triggered[1] == diagnostic_bufnr,
+ triggered[2] == 1,
+ }
]])
end)
@@ -1979,5 +2124,31 @@ end)
return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr
]])
end)
+
+ it("checks if diagnostics are disabled in a buffer", function()
+ eq({true, true, true , true}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_set_current_buf(diagnostic_bufnr)
+ vim.diagnostic.disable()
+ return {
+ vim.diagnostic.is_disabled(),
+ vim.diagnostic.is_disabled(diagnostic_bufnr),
+ vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns),
+ vim.diagnostic.is_disabled(_, diagnostic_ns),
+ }
+ ]])
+
+ eq({false, false, false , false}, exec_lua [[
+ vim.diagnostic.enable()
+ return {
+ vim.diagnostic.is_disabled(),
+ vim.diagnostic.is_disabled(diagnostic_bufnr),
+ vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns),
+ vim.diagnostic.is_disabled(_, diagnostic_ns),
+ }
+ ]])
+ end)
end)
end)
diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua
index 80c01a2b8c..18b13a8959 100644
--- a/test/functional/lua/ffi_spec.lua
+++ b/test/functional/lua/ffi_spec.lua
@@ -29,32 +29,37 @@ describe('ffi.cdef', function()
typedef struct window_S win_T;
typedef struct {} stl_hlrec_t;
typedef struct {} StlClickRecord;
+ typedef struct {} statuscol_T;
typedef struct {} Error;
win_T *find_window_by_handle(int Window, Error *err);
int build_stl_str_hl(
win_T *wp,
- char_u *out,
+ char *out,
size_t outlen,
- char_u *fmt,
- int use_sandbox,
- char_u fillchar,
+ char *fmt,
+ char *opt_name,
+ int opt_scope,
+ int fillchar,
int maxwidth,
stl_hlrec_t **hltab,
- StlClickRecord **tabtab
+ StlClickRecord **tabtab,
+ statuscol_T *scp
);
]]
return ffi.C.build_stl_str_hl(
ffi.C.find_window_by_handle(0, ffi.new('Error')),
- ffi.new('char_u[1024]'),
+ ffi.new('char[1024]'),
1024,
- ffi.cast('char_u*', 'StatusLineOfLength20'),
+ ffi.cast('char*', 'StatusLineOfLength20'),
+ nil,
0,
0,
0,
nil,
+ nil,
nil
)
]=])
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index be57b2db31..2a7be53164 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local exec_lua = helpers.exec_lua
local eq = helpers.eq
+local meths = helpers.meths
local clear = helpers.clear
local pathroot = helpers.pathroot
local command = helpers.command
@@ -94,3 +95,10 @@ describe('vim.filetype', function()
]])
end)
end)
+
+describe('filetype.lua', function()
+ it('does not override user autocommands that set filetype #20333', function()
+ clear({args={'--clean', '--cmd', 'autocmd BufRead *.md set filetype=notmarkdown', 'README.md'}})
+ eq('notmarkdown', meths.buf_get_option(0, 'filetype'))
+ end)
+end)
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index 2bcc84db0f..642d36f63a 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local lfs = require('lfs')
local clear = helpers.clear
local exec_lua = helpers.exec_lua
@@ -7,10 +8,43 @@ local mkdir_p = helpers.mkdir_p
local rmdir = helpers.rmdir
local nvim_dir = helpers.nvim_dir
local test_build_dir = helpers.test_build_dir
-local iswin = helpers.iswin
local nvim_prog = helpers.nvim_prog
+local is_os = helpers.is_os
-local nvim_prog_basename = iswin() and 'nvim.exe' or 'nvim'
+local nvim_prog_basename = is_os('win') and 'nvim.exe' or 'nvim'
+
+local test_basename_dirname_eq = {
+ '~/foo/',
+ '~/foo',
+ '~/foo/bar.lua',
+ 'foo.lua',
+ ' ',
+ '',
+ '.',
+ '..',
+ '../',
+ '~',
+ '/usr/bin',
+ '/usr/bin/gcc',
+ '/',
+ '/usr/',
+ '/usr',
+ 'c:/usr',
+ 'c:/',
+ 'c:',
+ 'c:/users/foo',
+ 'c:/users/foo/bar.lua',
+ 'c:/users/foo/bar/../',
+}
+
+local tests_windows_paths = {
+ 'c:\\usr',
+ 'c:\\',
+ 'c:',
+ 'c:\\users\\foo',
+ 'c:\\users\\foo\\bar.lua',
+ 'c:\\users\\foo\\bar\\..\\',
+}
before_each(clear)
@@ -41,19 +75,73 @@ describe('vim.fs', function()
local nvim_dir = ...
return vim.fs.dirname(nvim_dir)
]], nvim_dir))
+
+ local function test_paths(paths)
+ for _, path in ipairs(paths) do
+ eq(
+ exec_lua([[
+ local path = ...
+ return vim.fn.fnamemodify(path,':h'):gsub('\\', '/')
+ ]], path),
+ exec_lua([[
+ local path = ...
+ return vim.fs.dirname(path)
+ ]], path),
+ path
+ )
+ end
+ end
+
+ test_paths(test_basename_dirname_eq)
+ if is_os('win') then
+ test_paths(tests_windows_paths)
+ end
end)
end)
describe('basename()', function()
it('works', function()
+
eq(nvim_prog_basename, exec_lua([[
local nvim_prog = ...
return vim.fs.basename(nvim_prog)
]], nvim_prog))
+
+ local function test_paths(paths)
+ for _, path in ipairs(paths) do
+ eq(
+ exec_lua([[
+ local path = ...
+ return vim.fn.fnamemodify(path,':t'):gsub('\\', '/')
+ ]], path),
+ exec_lua([[
+ local path = ...
+ return vim.fs.basename(path)
+ ]], path),
+ path
+ )
+ end
+ end
+
+ test_paths(test_basename_dirname_eq)
+ if is_os('win') then
+ test_paths(tests_windows_paths)
+ end
end)
end)
describe('dir()', function()
+ before_each(function()
+ lfs.mkdir('testd')
+ lfs.mkdir('testd/a')
+ lfs.mkdir('testd/a/b')
+ lfs.mkdir('testd/a/b/c')
+ end)
+
+ after_each(function()
+ rmdir('testd')
+ end)
+
it('works', function()
eq(true, exec_lua([[
local dir, nvim = ...
@@ -65,6 +153,71 @@ describe('vim.fs', function()
return false
]], nvim_dir, nvim_prog_basename))
end)
+
+ it('works with opts.depth and opts.skip', function()
+ io.open('testd/a1', 'w'):close()
+ io.open('testd/b1', 'w'):close()
+ io.open('testd/c1', 'w'):close()
+ io.open('testd/a/a2', 'w'):close()
+ io.open('testd/a/b2', 'w'):close()
+ io.open('testd/a/c2', 'w'):close()
+ io.open('testd/a/b/a3', 'w'):close()
+ io.open('testd/a/b/b3', 'w'):close()
+ io.open('testd/a/b/c3', 'w'):close()
+ io.open('testd/a/b/c/a4', 'w'):close()
+ io.open('testd/a/b/c/b4', 'w'):close()
+ io.open('testd/a/b/c/c4', 'w'):close()
+
+ local function run(dir, depth, skip)
+ local r = exec_lua([[
+ local dir, depth, skip = ...
+ local r = {}
+ local skip_f
+ if skip then
+ skip_f = function(n)
+ if vim.tbl_contains(skip or {}, n) then
+ return false
+ end
+ end
+ end
+ for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do
+ r[name] = type_
+ end
+ return r
+ ]], dir, depth, skip)
+ return r
+ end
+
+ local exp = {}
+
+ exp['a1'] = 'file'
+ exp['b1'] = 'file'
+ exp['c1'] = 'file'
+ exp['a'] = 'directory'
+
+ eq(exp, run('testd', 1))
+
+ exp['a/a2'] = 'file'
+ exp['a/b2'] = 'file'
+ exp['a/c2'] = 'file'
+ exp['a/b'] = 'directory'
+
+ eq(exp, run('testd', 2))
+
+ exp['a/b/a3'] = 'file'
+ exp['a/b/b3'] = 'file'
+ exp['a/b/c3'] = 'file'
+ exp['a/b/c'] = 'directory'
+
+ eq(exp, run('testd', 3))
+ eq(exp, run('testd', 999, {'a/b/c'}))
+
+ exp['a/b/c/a4'] = 'file'
+ exp['a/b/c/b4'] = 'file'
+ exp['a/b/c/c4'] = 'file'
+
+ eq(exp, run('testd', 999))
+ end)
end)
describe('find()', function()
@@ -77,6 +230,28 @@ describe('vim.fs', function()
local dir, nvim = ...
return vim.fs.find(nvim, { path = dir, type = 'file' })
]], test_build_dir, nvim_prog_basename))
+ eq({nvim_dir}, exec_lua([[
+ local dir = ...
+ local parent, name = dir:match('^(.*/)([^/]+)$')
+ return vim.fs.find(name, { path = parent, upward = true, type = 'directory' })
+ ]], nvim_dir))
+ end)
+
+ it('accepts predicate as names', function()
+ eq({test_build_dir}, exec_lua([[
+ local dir = ...
+ local opts = { path = dir, upward = true, type = 'directory' }
+ return vim.fs.find(function(x) return x == 'build' end, opts)
+ ]], nvim_dir))
+ eq({nvim_prog}, exec_lua([[
+ local dir, nvim = ...
+ return vim.fs.find(function(x) return x == nvim end, { path = dir, type = 'file' })
+ ]], test_build_dir, nvim_prog_basename))
+ eq({}, exec_lua([[
+ local dir = ...
+ local opts = { path = dir, upward = true, type = 'directory' }
+ return vim.fs.find(function(x) return x == 'no-match' end, opts)
+ ]], nvim_dir))
end)
end)
@@ -85,7 +260,7 @@ describe('vim.fs', function()
eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]])
end)
it('works with ~', function()
- if iswin() then
+ if is_os('win') then
pending([[$HOME does not exist on Windows ¯\_(ツ)_/¯]])
end
eq(os.getenv('HOME') .. '/src/foo', exec_lua [[ return vim.fs.normalize('~/src/foo') ]])
diff --git a/test/functional/lua/help_spec.lua b/test/functional/lua/help_spec.lua
new file mode 100644
index 0000000000..b396e2ba30
--- /dev/null
+++ b/test/functional/lua/help_spec.lua
@@ -0,0 +1,50 @@
+-- Tests for gen_help_html.lua. Validates :help tags/links and HTML doc generation.
+--
+-- TODO: extract parts of gen_help_html.lua into Nvim stdlib?
+
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local ok = helpers.ok
+
+describe(':help docs', function()
+ before_each(clear)
+ it('validate', function()
+ -- If this test fails, try these steps (in order):
+ -- 1. Fix/cleanup the :help docs.
+ -- 2. Fix the parser: https://github.com/neovim/tree-sitter-vimdoc
+ -- 3. File a parser bug, and adjust the tolerance of this test in the meantime.
+
+ local rv = exec_lua([[return require('scripts.gen_help_html').validate('./build/runtime/doc')]])
+ -- Check that we actually found helpfiles.
+ ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles)
+ eq({}, rv.invalid_links, 'invalid tags in :help docs')
+ eq({}, rv.invalid_urls, 'invalid URLs in :help docs')
+ -- Check that parse errors did not increase wildly.
+ -- TODO: Fix all parse errors in :help files.
+ ok(rv.err_count < 250, '<250 parse errors', rv.err_count)
+ end)
+
+ it('gen_help_html.lua generates HTML', function()
+ -- 1. Test that gen_help_html.lua actually works.
+ -- 2. Test that parse errors did not increase wildly. Because we explicitly test only a few
+ -- :help files, we can be precise about the tolerances here.
+
+ local tmpdir = exec_lua('return vim.fs.dirname(vim.fn.tempname())')
+ -- Because gen() is slow (~30s), this test is limited to a few files.
+ local rv = exec_lua([[
+ local to_dir = ...
+ return require('scripts.gen_help_html').gen(
+ './build/runtime/doc',
+ to_dir,
+ { 'pi_health.txt', 'help.txt', 'index.txt', 'nvim.txt', }
+ )
+ ]],
+ tmpdir
+ )
+ eq(4, #rv.helpfiles)
+ eq(0, rv.err_count, 'parse errors in :help docs')
+ eq({}, rv.invalid_links, 'invalid tags in :help docs')
+ end)
+end)
diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua
new file mode 100644
index 0000000000..5e488bb082
--- /dev/null
+++ b/test/functional/lua/inspector_spec.lua
@@ -0,0 +1,56 @@
+local helpers = require('test.functional.helpers')(after_each)
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local eval = helpers.eval
+local clear = helpers.clear
+
+describe('vim.inspect_pos', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('it returns items', function()
+ local ret = exec_lua([[
+ local buf = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(buf)
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"})
+ vim.api.nvim_buf_set_option(buf, "filetype", "lua")
+ vim.cmd("syntax on")
+ return {buf, vim.inspect_pos(0, 0, 10)}
+ ]])
+ local buf, items = unpack(ret)
+ eq('', eval('v:errmsg'))
+ eq({
+ buffer = buf,
+ col = 10,
+ row = 0,
+ extmarks = {},
+ treesitter = {},
+ semantic_tokens = {},
+ syntax = {
+ {
+ hl_group = 'luaNumber',
+ hl_group_link = 'Constant',
+ },
+ },
+ }, items)
+ end)
+end)
+
+describe('vim.show_pos', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('it does not error', function()
+ exec_lua([[
+ local buf = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(buf)
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"})
+ vim.api.nvim_buf_set_option(buf, "filetype", "lua")
+ vim.cmd("syntax on")
+ return {buf, vim.show_pos(0, 0, 10)}
+ ]])
+ eq('', eval('v:errmsg'))
+ end)
+end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 32c1615a45..3f107811ae 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -8,12 +8,12 @@ local feed = helpers.feed
local clear = helpers.clear
local funcs = helpers.funcs
local meths = helpers.meths
-local iswin = helpers.iswin
local command = helpers.command
local write_file = helpers.write_file
local exec_capture = helpers.exec_capture
local exec_lua = helpers.exec_lua
local pcall_err = helpers.pcall_err
+local is_os = helpers.is_os
local screen
@@ -135,7 +135,7 @@ describe('print', function()
print("very slow")
vim.api.nvim_command("sleep 1m") -- force deferred event processing
end
- ]], (iswin() and "timeout 1") or "sleep 0.1")
+ ]], (is_os('win') and "timeout 1") or "sleep 0.1")
eq('very slow\nvery fast', exec_capture('lua test()'))
end)
end)
diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua
index e9c34c9228..b659f2eacb 100644
--- a/test/functional/lua/runtime_spec.lua
+++ b/test/functional/lua/runtime_spec.lua
@@ -4,6 +4,7 @@ local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local exec = helpers.exec
+local funcs = helpers.funcs
local mkdir_p = helpers.mkdir_p
local rmdir = helpers.rmdir
local write_file = helpers.write_file
@@ -29,6 +30,7 @@ describe('runtime:', function()
after_each(function()
rmdir(plug_dir)
+ exec('bwipe!')
end)
describe('colors', function()
@@ -39,6 +41,8 @@ describe('runtime:', function()
mkdir_p(colorscheme_folder)
write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]])
+ eq({'new_colorscheme'}, funcs.getcompletion('new_c', 'color'))
+
exec('colorscheme new_colorscheme')
eq(1, eval('g:lua_colorscheme'))
@@ -64,23 +68,25 @@ describe('runtime:', function()
it('loads lua compilers', function()
local compiler_file = compiler_folder .. sep .. 'new_compiler.lua'
mkdir_p(compiler_folder)
- write_file(compiler_file, [[vim.g.lua_compiler = 1]])
+ write_file(compiler_file, [[vim.b.lua_compiler = 1]])
+
+ eq({'new_compiler'}, funcs.getcompletion('new_c', 'compiler'))
exec('compiler new_compiler')
- eq(1, eval('g:lua_compiler'))
+ eq(1, eval('b:lua_compiler'))
rmdir(compiler_folder)
end)
it('loads vim compilers when both lua and vim version exist', function()
local compiler_file = compiler_folder .. sep .. 'new_compiler'
mkdir_p(compiler_folder)
- write_file(compiler_file..'.vim', [[let g:compiler = 'vim']])
- write_file(compiler_file..'.lua', [[vim.g.compiler = 'lua']])
+ write_file(compiler_file..'.vim', [[let b:compiler = 'vim']])
+ write_file(compiler_file..'.lua', [[vim.b.compiler = 'lua']])
exec('compiler new_compiler')
- eq('vim', eval('g:compiler'))
+ eq('vim', eval('b:compiler'))
rmdir(compiler_folder)
end)
end)
@@ -91,10 +97,12 @@ describe('runtime:', function()
it('loads lua ftplugins', function()
local ftplugin_file = table.concat({ftplugin_folder , 'new-ft.lua'}, sep)
mkdir_p(ftplugin_folder)
- write_file(ftplugin_file , [[vim.g.lua_ftplugin = 1]])
+ write_file(ftplugin_file , [[vim.b.lua_ftplugin = 1]])
+
+ eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype'))
exec [[set filetype=new-ft]]
- eq(1, eval('g:lua_ftplugin'))
+ eq(1, eval('b:lua_ftplugin'))
rmdir(ftplugin_folder)
end)
end)
@@ -105,10 +113,12 @@ describe('runtime:', function()
it('loads lua indents', function()
local indent_file = table.concat({indent_folder , 'new-ft.lua'}, sep)
mkdir_p(indent_folder)
- write_file(indent_file , [[vim.g.lua_indent = 1]])
+ write_file(indent_file , [[vim.b.lua_indent = 1]])
+
+ eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype'))
exec [[set filetype=new-ft]]
- eq(1, eval('g:lua_indent'))
+ eq(1, eval('b:lua_indent'))
rmdir(indent_folder)
end)
end)
@@ -116,24 +126,32 @@ describe('runtime:', function()
describe('syntax', function()
local syntax_folder = table.concat({plug_dir, 'syntax'}, sep)
- it('loads lua syntaxes on filetype change', function()
+ before_each(function()
local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep)
mkdir_p(syntax_folder)
- write_file(syntax_file , [[vim.g.lua_syntax = 1]])
+ write_file(syntax_file , [[vim.b.current_syntax = 'my-lang']])
+ exec([[let b:current_syntax = '']])
+ end)
+ it('loads lua syntaxes on filetype change', function()
exec('set filetype=my-lang')
- eq(1, eval('g:lua_syntax'))
- rmdir(syntax_folder)
+ eq('my-lang', eval('b:current_syntax'))
end)
it('loads lua syntaxes on syntax change', function()
- local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep)
- mkdir_p(syntax_folder)
- write_file(syntax_file , [[vim.g.lua_syntax = 5]])
-
exec('set syntax=my-lang')
- eq(5, eval('g:lua_syntax'))
- rmdir(syntax_folder)
+ eq('my-lang', eval('b:current_syntax'))
+ end)
+
+ it('loads lua syntaxes for :ownsyntax', function()
+ exec('ownsyntax my-lang')
+ eq('my-lang', eval('w:current_syntax'))
+ eq('', eval('b:current_syntax'))
+ end)
+
+ it('lua syntaxes are included in cmdline completion', function()
+ eq({'my-lang'}, funcs.getcompletion('my-l', 'filetype'))
+ eq({'my-lang'}, funcs.getcompletion('my-l', 'syntax'))
end)
end)
diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua
new file mode 100644
index 0000000000..2647b2be46
--- /dev/null
+++ b/test/functional/lua/secure_spec.lua
@@ -0,0 +1,284 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local eq = helpers.eq
+local clear = helpers.clear
+local command = helpers.command
+local pathsep = helpers.get_pathsep()
+local is_os = helpers.is_os
+local curbufmeths = helpers.curbufmeths
+local exec_lua = helpers.exec_lua
+local feed_command = helpers.feed_command
+local feed = helpers.feed
+local funcs = helpers.funcs
+local pcall_err = helpers.pcall_err
+local matches = helpers.matches
+
+describe('vim.secure', function()
+ describe('read()', function()
+ local xstate = 'Xstate'
+
+ setup(function()
+ helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim'))
+ end)
+
+ teardown(function()
+ helpers.rmdir(xstate)
+ end)
+
+ before_each(function()
+ helpers.write_file('Xfile', [[
+ let g:foobar = 42
+ ]])
+ clear{env={XDG_STATE_HOME=xstate}}
+ end)
+
+ after_each(function()
+ os.remove('Xfile')
+ helpers.rmdir(xstate)
+ end)
+
+ it('works', function()
+ local screen = Screen.new(80, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [4] = {reverse = true},
+ })
+
+ local cwd = funcs.getcwd()
+
+ -- Need to use feed_command instead of exec_lua because of the confirmation prompt
+ feed_command([[lua vim.secure.read('Xfile')]])
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ :lua vim.secure.read('Xfile') |
+ {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}|
+ {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ |
+ ]]}
+ feed('d')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', cwd .. pathsep .. 'Xfile'), vim.trim(trust))
+ eq(helpers.NIL, exec_lua([[return vim.secure.read('Xfile')]]))
+
+ os.remove(funcs.stdpath('state') .. pathsep .. 'trust')
+
+ feed_command([[lua vim.secure.read('Xfile')]])
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ :lua vim.secure.read('Xfile') |
+ {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}|
+ {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ |
+ ]]}
+ feed('a')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ local hash = funcs.sha256(helpers.read_file('Xfile'))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, cwd .. pathsep .. 'Xfile'), vim.trim(trust))
+ eq(helpers.NIL, exec_lua([[vim.secure.read('Xfile')]]))
+
+ os.remove(funcs.stdpath('state') .. pathsep .. 'trust')
+
+ feed_command([[lua vim.secure.read('Xfile')]])
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ :lua vim.secure.read('Xfile') |
+ {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}|
+ {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ |
+ ]]}
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ -- Trust database is not updated
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(nil, trust)
+
+ feed_command([[lua vim.secure.read('Xfile')]])
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ :lua vim.secure.read('Xfile') |
+ {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}|
+ {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ |
+ ]]}
+ feed('v')
+ screen:expect{grid=[[
+ ^let g:foobar = 42 |
+ {1:~ }|
+ {1:~ }|
+ {2:]] .. funcs.fnamemodify(cwd, ':~') .. pathsep .. [[Xfile [RO]{MATCH:%s+}|
+ |
+ {1:~ }|
+ {4:[No Name] }|
+ |
+ ]]}
+
+ -- Trust database is not updated
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(nil, trust)
+
+ -- Cannot write file
+ pcall_err(command, 'write')
+ eq(true, curbufmeths.get_option('readonly'))
+ end)
+ end)
+
+ describe('trust()', function()
+ local xstate = 'Xstate'
+
+ setup(function()
+ helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim'))
+ end)
+
+ teardown(function()
+ helpers.rmdir(xstate)
+ end)
+
+ before_each(function()
+ helpers.write_file('test_file', 'test')
+ end)
+
+ after_each(function()
+ os.remove('test_file')
+ end)
+
+ it('returns error when passing both path and bufnr', function()
+ matches('"path" and "bufnr" are mutually exclusive',
+ pcall_err(exec_lua, [[vim.secure.trust({action='deny', bufnr=0, path='test_file'})]]))
+ end)
+
+ it('returns error when passing neither path or bufnr', function()
+ matches('one of "path" or "bufnr" is required',
+ pcall_err(exec_lua, [[vim.secure.trust({action='deny'})]]))
+ end)
+
+ it('trust then deny then remove a file using bufnr', function()
+ local cwd = funcs.getcwd()
+ local hash = funcs.sha256(helpers.read_file('test_file'))
+ local full_path = cwd .. pathsep .. 'test_file'
+
+ command('edit test_file')
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq('', vim.trim(trust))
+ end)
+
+ it('deny then trust then remove a file using bufnr', function()
+ local cwd = funcs.getcwd()
+ local hash = funcs.sha256(helpers.read_file('test_file'))
+ local full_path = cwd .. pathsep .. 'test_file'
+
+ command('edit test_file')
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]]))
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq('', vim.trim(trust))
+ end)
+
+ it('trust using bufnr then deny then remove a file using path', function()
+ local cwd = funcs.getcwd()
+ local hash = funcs.sha256(helpers.read_file('test_file'))
+ local full_path = cwd .. pathsep .. 'test_file'
+
+ command('edit test_file')
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq('', vim.trim(trust))
+ end)
+
+ it('deny then trust then remove a file using bufnr', function()
+ local cwd = funcs.getcwd()
+ local hash = funcs.sha256(helpers.read_file('test_file'))
+ local full_path = cwd .. pathsep .. 'test_file'
+
+ command('edit test_file')
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]))
+ local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('! %s', full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq(string.format('%s %s', hash, full_path), vim.trim(trust))
+
+ eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]))
+ trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
+ eq('', vim.trim(trust))
+ end)
+
+ it('trust returns error when buffer not associated to file', function()
+ command('new')
+ eq({false, 'buffer is not associated with a file'},
+ exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
+ end)
+ end)
+end)
diff --git a/test/functional/lua/spell_spec.lua b/test/functional/lua/spell_spec.lua
index 7e831f16a7..b3de6a0912 100644
--- a/test/functional/lua/spell_spec.lua
+++ b/test/functional/lua/spell_spec.lua
@@ -15,7 +15,7 @@ describe('vim.spell', function()
end
it('can handle nil', function()
- eq([[Error executing lua: [string "<nvim>"]:0: bad argument #1 to 'check' (expected string)]],
+ eq([[bad argument #1 to 'check' (expected string)]],
pcall_err(exec_lua, [[vim.spell.check(nil)]]))
end)
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
index e183ce3a57..c7f2783cf3 100644
--- a/test/functional/lua/thread_spec.lua
+++ b/test/functional/lua/thread_spec.lua
@@ -272,7 +272,7 @@ describe('threadpool', function()
work:queue({})
]])
- eq([[Error executing lua: [string "<nvim>"]:0: Error: thread arg not support type 'function' at 1]],
+ eq([[Error: thread arg not support type 'function' at 1]],
status)
end)
diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua
new file mode 100644
index 0000000000..6481da900e
--- /dev/null
+++ b/test/functional/lua/ui_event_spec.lua
@@ -0,0 +1,147 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local clear = helpers.clear
+local feed = helpers.feed
+local funcs = helpers.funcs
+local inspect = require'vim.inspect'
+
+describe('vim.ui_attach', function()
+ local screen
+ before_each(function()
+ clear()
+ exec_lua [[
+ ns = vim.api.nvim_create_namespace 'testspace'
+ events = {}
+ function on_event(event, ...)
+ events[#events+1] = {event, ...}
+ return true
+ end
+
+ function get_events()
+ local ret_events = events
+ events = {}
+ return ret_events
+ end
+ ]]
+
+ screen = Screen.new(40,5)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {bold = true};
+ [3] = {background = Screen.colors.Grey};
+ [4] = {background = Screen.colors.LightMagenta};
+ })
+ screen:attach()
+ end)
+
+ local function expect_events(expected)
+ local evs = exec_lua "return get_events(...)"
+ eq(expected, evs, inspect(evs))
+ end
+
+ it('can receive popupmenu events', function()
+ exec_lua [[ vim.ui_attach(ns, {ext_popupmenu=true}, on_event) ]]
+ feed('ifo')
+ screen:expect{grid=[[
+ fo^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]]}
+
+ funcs.complete(1, {'food', 'foobar', 'foo'})
+ screen:expect{grid=[[
+ food^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]]}
+ expect_events {
+ { "popupmenu_show", { { "food", "", "", "" }, { "foobar", "", "", "" }, { "foo", "", "", "" } }, 0, 0, 0, 1 };
+ }
+
+ feed '<c-n>'
+ screen:expect{grid=[[
+ foobar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]]}
+ expect_events {
+ { "popupmenu_select", 1 };
+ }
+
+ feed '<c-y>'
+ screen:expect{grid=[[
+ foobar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], intermediate=true}
+ expect_events {
+ { "popupmenu_hide" };
+ }
+
+ -- vim.ui_detach() stops events, and reenables builtin pum immediately
+ exec_lua [[
+ vim.ui_detach(ns)
+ vim.fn.complete(1, {'food', 'foobar', 'foo'})
+ ]]
+
+ screen:expect{grid=[[
+ food^ |
+ {3:food }{1: }|
+ {4:foobar }{1: }|
+ {4:foo }{1: }|
+ {2:-- INSERT --} |
+ ]]}
+ expect_events {
+ }
+
+ end)
+
+ it('does not crash on exit', function()
+ helpers.funcs.system({
+ helpers.nvim_prog,
+ '-u', 'NONE',
+ '-i', 'NONE',
+ '--cmd', [[ lua ns = vim.api.nvim_create_namespace 'testspace' ]],
+ '--cmd', [[ lua vim.ui_attach(ns, {ext_popupmenu=true}, function() end) ]],
+ '--cmd', 'quitall!',
+ })
+ eq(0, helpers.eval('v:shell_error'))
+ end)
+
+ it('can receive accurate message kinds even if they are history', function()
+ exec_lua([[
+ vim.cmd.echomsg("'message1'")
+ print('message2')
+ vim.ui_attach(ns, { ext_messages = true }, on_event)
+ vim.cmd.echomsg("'message3'")
+ ]])
+ feed(':messages<cr>')
+ feed('<cr>')
+
+ local actual = exec_lua([[
+ return vim.tbl_filter(function (event)
+ return event[1] == "msg_history_show"
+ end, events)
+ ]])
+ eq({
+ {
+ 'msg_history_show',
+ {
+ { 'echomsg', { { 0, 'message1' } } },
+ { '', { { 0, 'message2' } } },
+ { 'echomsg', { { 0, 'message3' } } },
+ },
+ },
+ }, actual, inspect(actual))
+ end)
+end)
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
index 3fcb2dec8d..9ee99b4905 100644
--- a/test/functional/lua/ui_spec.lua
+++ b/test/functional/lua/ui_spec.lua
@@ -4,6 +4,7 @@ local exec_lua = helpers.exec_lua
local clear = helpers.clear
local feed = helpers.feed
local eval = helpers.eval
+local poke_eventloop = helpers.poke_eventloop
describe('vim.ui', function()
before_each(function()
@@ -83,5 +84,50 @@ describe('vim.ui', function()
feed('abcdefg<cr>')
eq('abcdefg', exec_lua('return result'))
end)
+
+ it('can input empty text #18144', function()
+ feed(':lua vim.ui.input({}, function(input) result = input end)<cr>')
+ feed('<cr>')
+ eq('', exec_lua('return result'))
+ end)
+
+ it('can input empty text with cancelreturn opt #18144', function()
+ feed(':lua vim.ui.input({ cancelreturn = "CANCEL" }, function(input) result = input end)<cr>')
+ feed('<cr>')
+ eq('', exec_lua('return result'))
+ end)
+
+ it('can return nil when aborted with ESC #18144', function()
+ feed(':lua result = "on_confirm not called"<cr>')
+ feed(':lua vim.ui.input({}, function(input) result = input end)<cr>')
+ feed('Inputted Text<esc>')
+ -- Note: When `result == nil`, exec_lua('returns result') returns vim.NIL
+ eq(true, exec_lua('return (nil == result)'))
+ end)
+
+ it('can return opts.cacelreturn when aborted with ESC with cancelreturn opt #18144', function()
+ feed(':lua result = "on_confirm not called"<cr>')
+ feed(':lua vim.ui.input({ cancelreturn = "CANCEL" }, function(input) result = input end)<cr>')
+ feed('Inputted Text<esc>')
+ eq('CANCEL', exec_lua('return result'))
+ end)
+
+ it('can return nil when interrupted with Ctrl-C #18144', function()
+ feed(':lua result = "on_confirm not called"<cr>')
+ feed(':lua vim.ui.input({}, function(input) result = input end)<cr>')
+ poke_eventloop() -- This is needed because Ctrl-C flushes input
+ feed('Inputted Text<c-c>')
+ eq(true, exec_lua('return (nil == result)'))
+ end)
+
+ it('can return the identical object when an arbitrary opts.cancelreturn object is given', function()
+ feed(':lua fn = function() return 42 end<CR>')
+ eq(42, exec_lua('return fn()'))
+ feed(':lua vim.ui.input({ cancelreturn = fn }, function(input) result = input end)<cr>')
+ feed('cancel<esc>')
+ eq(true, exec_lua('return (result == fn)'))
+ eq(42, exec_lua('return result()'))
+ end)
+
end)
end)
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index 4635f17557..416e9e1f02 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local exec_lua = helpers.exec_lua
local eq = helpers.eq
+local is_os = helpers.is_os
+local skip = helpers.skip
local write_file = require('test.helpers').write_file
describe('URI methods', function()
@@ -11,7 +13,7 @@ describe('URI methods', function()
describe('file path to uri', function()
describe('encode Unix file path', function()
- it('file path includes only ascii charactors', function()
+ it('file path includes only ascii characters', function()
exec_lua("filepath = '/Foo/Bar/Baz.txt'")
eq('file:///Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)"))
@@ -23,7 +25,7 @@ describe('URI methods', function()
eq('file:///Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)"))
end)
- it('file path including Unicode charactors', function()
+ it('file path including Unicode characters', function()
exec_lua("filepath = '/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt'")
-- The URI encoding should be case-insensitive
@@ -32,7 +34,7 @@ describe('URI methods', function()
end)
describe('encode Windows filepath', function()
- it('file path includes only ascii charactors', function()
+ it('file path includes only ascii characters', function()
exec_lua([[filepath = 'C:\\Foo\\Bar\\Baz.txt']])
eq('file:///C:/Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)"))
@@ -44,7 +46,7 @@ describe('URI methods', function()
eq('file:///C:/Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)"))
end)
- it('file path including Unicode charactors', function()
+ it('file path including Unicode characters', function()
exec_lua([[filepath = 'C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt']])
eq('file:///C:/xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)"))
@@ -72,7 +74,7 @@ describe('URI methods', function()
eq('/Foo /Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)"))
end)
- it('file path including Unicode charactors', function()
+ it('file path including Unicode characters', function()
local test_case = [[
local uri = 'file:///xy/%C3%A5%C3%A4%C3%B6/%C9%A7/%E6%B1%89%E8%AF%AD/%E2%86%A5/%F0%9F%A4%A6/%F0%9F%A6%84/a%CC%8A/%D8%A8%D9%90%D9%8A%D9%8E%D9%91.txt'
return vim.uri_to_fname(uri)
@@ -83,7 +85,7 @@ describe('URI methods', function()
end)
describe('decode Windows filepath', function()
- it('file path includes only ascii charactors', function()
+ it('file path includes only ascii characters', function()
local test_case = [[
local uri = 'file:///C:/Foo/Bar/Baz.txt'
return vim.uri_to_fname(uri)
@@ -119,7 +121,7 @@ describe('URI methods', function()
eq('C:\\Foo \\Bar\\Baz.txt', exec_lua(test_case))
end)
- it('file path including Unicode charactors', function()
+ it('file path including Unicode characters', function()
local test_case = [[
local uri = 'file:///C:/xy/%C3%A5%C3%A4%C3%B6/%C9%A7/%E6%B1%89%E8%AF%AD/%E2%86%A5/%F0%9F%A4%A6/%F0%9F%A6%84/a%CC%8A/%D8%A8%D9%90%D9%8A%D9%8E%D9%91.txt'
return vim.uri_to_fname(uri)
@@ -167,7 +169,7 @@ describe('URI methods', function()
describe('uri from bufnr', function()
it('Windows paths should not be treated as uris', function()
- if not helpers.iswin() then return end
+ skip(not is_os('win'), "Not applicable on non-Windows")
local file = helpers.tmpname()
write_file(file, 'Test content')
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 2b249b7a69..867f366d06 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -2,6 +2,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local nvim_prog = helpers.nvim_prog
local funcs = helpers.funcs
local meths = helpers.meths
local command = helpers.command
@@ -22,8 +23,8 @@ local remove_trace = helpers.remove_trace
local mkdir_p = helpers.mkdir_p
local rmdir = helpers.rmdir
local write_file = helpers.write_file
-local expect_exit = helpers.expect_exit
local poke_eventloop = helpers.poke_eventloop
+local assert_alive = helpers.assert_alive
describe('lua stdlib', function()
before_each(clear)
@@ -158,28 +159,32 @@ describe('lua stdlib', function()
end)
it("vim.str_utfindex/str_byteindex", function()
- exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]])
- local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48}
- local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48}
- for i,k in pairs(indicies32) do
+ exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ\000ъ"]])
+ local indices32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48,49,51}
+ local indices16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48,49,51}
+ for i,k in pairs(indices32) do
eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i)
end
- for i,k in pairs(indicies16) do
+ for i,k in pairs(indices16) do
eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i)
end
+ eq("index out of range", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ...)", #indices32 + 1))
+ eq("index out of range", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ..., true)", #indices16 + 1))
local i32, i16 = 0, 0
- for k = 0,48 do
- if indicies32[i32] < k then
+ local len = 51
+ for k = 0,len do
+ if indices32[i32] < k then
i32 = i32 + 1
end
- if indicies16[i16] < k then
+ if indices16[i16] < k then
i16 = i16 + 1
- if indicies16[i16+1] == indicies16[i16] then
+ if indices16[i16+1] == indices16[i16] then
i16 = i16 + 1
end
end
eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k)
end
+ eq("index out of range", pcall_err(exec_lua, "return vim.str_utfindex(_G.test_text, ...)", len + 1))
end)
it("vim.str_utf_start", function()
@@ -414,6 +419,12 @@ describe('lua stdlib', function()
return getmetatable(t2) == mt
]]))
+ ok(exec_lua([[
+ local t1 = {a = vim.NIL}
+ local t2 = vim.deepcopy(t1)
+ return t2.a == vim.NIL
+ ]]))
+
matches('Cannot deepcopy object of type thread',
pcall_err(exec_lua, [[
local thread = coroutine.create(function () return 0 end)
@@ -425,6 +436,8 @@ describe('lua stdlib', function()
it('vim.pesc', function()
eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]]))
eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]]))
+ -- pesc() returns one result. #20751
+ eq({'x'}, exec_lua([[return {vim.pesc('x')}]]))
-- Validates args.
matches('s: expected string, got number',
@@ -499,6 +512,8 @@ describe('lua stdlib', function()
eq(NIL, exec_lua("return vim.tbl_get({ unindexable = function () end }, 'unindexable', 'missing_key')"))
eq(NIL, exec_lua("return vim.tbl_get({}, 'missing_key')"))
eq(NIL, exec_lua("return vim.tbl_get({})"))
+ eq(1, exec_lua("return select('#', vim.tbl_get({}))"))
+ eq(1, exec_lua("return select('#', vim.tbl_get({ nested = {} }, 'nested', 'missing_key'))"))
end)
it('vim.tbl_extend', function()
@@ -748,6 +763,20 @@ describe('lua stdlib', function()
pcall_err(exec_lua, code))
end)
+ it('vim.spairs', function()
+ local res = ''
+ local table = {
+ ccc=1,
+ bbb=2,
+ ddd=3,
+ aaa=4
+ }
+ for key, _ in vim.spairs(table) do
+ res = res .. key
+ end
+ matches('aaabbbcccddd', res)
+ end)
+
it('vim.call, vim.fn', function()
eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]]))
eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]]))
@@ -788,6 +817,11 @@ describe('lua stdlib', function()
local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end)
return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar'
]]))
+
+ -- Test for #20211
+ eq('a (b) c', exec_lua([[
+ return vim.fn.substitute('a b c', 'b', function(m) return '(' .. m[1] .. ')' end, 'g')
+ ]]))
end)
it('vim.fn should error when calling API function', function()
@@ -896,7 +930,7 @@ describe('lua stdlib', function()
]]))
-- vim.empty_dict() gives new value each time
- -- equality is not overriden (still by ref)
+ -- equality is not overridden (still by ref)
-- non-empty table uses the usual heuristics (ignores the tag)
eq({false, {"foo"}, {namey="bar"}}, exec_lua([[
local aa = vim.empty_dict()
@@ -1006,11 +1040,11 @@ describe('lua stdlib', function()
eq('hi', funcs.luaeval "vim.g.testing")
eq(123, funcs.luaeval "vim.g.other")
eq(5120.1, funcs.luaeval "vim.g.floaty")
- eq(NIL, funcs.luaeval "vim.g.nonexistant")
+ eq(NIL, funcs.luaeval "vim.g.nonexistent")
eq(NIL, funcs.luaeval "vim.g.nullvar")
-- lost over RPC, so test locally:
eq({false, true}, exec_lua [[
- return {vim.g.nonexistant == vim.NIL, vim.g.nullvar == vim.NIL}
+ return {vim.g.nonexistent == vim.NIL, vim.g.nullvar == vim.NIL}
]])
eq({hello="world"}, funcs.luaeval "vim.g.to_delete")
@@ -1029,6 +1063,7 @@ describe('lua stdlib', function()
vim.g.AddCounter = add_counter
vim.g.GetCounter = get_counter
vim.g.funcs = {add = add_counter, get = get_counter}
+ vim.g.AddParens = function(s) return '(' .. s .. ')' end
]]
eq(0, eval('g:GetCounter()'))
@@ -1044,6 +1079,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.g.funcs.get()]]))
exec_lua([[vim.api.nvim_get_var('funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
+ eq('((foo))', eval([['foo'->AddParens()->AddParens()]]))
exec_lua [[
local counter = 0
@@ -1052,6 +1088,7 @@ describe('lua stdlib', function()
vim.api.nvim_set_var('AddCounter', add_counter)
vim.api.nvim_set_var('GetCounter', get_counter)
vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter})
+ vim.api.nvim_set_var('AddParens', function(s) return '(' .. s .. ')' end)
]]
eq(0, eval('g:GetCounter()'))
@@ -1067,6 +1104,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.g.funcs.get()]]))
exec_lua([[vim.api.nvim_get_var('funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
+ eq('((foo))', eval([['foo'->AddParens()->AddParens()]]))
exec([[
function Test()
@@ -1109,12 +1147,12 @@ describe('lua stdlib', function()
eq('bye', funcs.luaeval "vim.b[BUF].testing")
eq(123, funcs.luaeval "vim.b.other")
eq(5120.1, funcs.luaeval "vim.b.floaty")
- eq(NIL, funcs.luaeval "vim.b.nonexistant")
- eq(NIL, funcs.luaeval "vim.b[BUF].nonexistant")
+ eq(NIL, funcs.luaeval "vim.b.nonexistent")
+ eq(NIL, funcs.luaeval "vim.b[BUF].nonexistent")
eq(NIL, funcs.luaeval "vim.b.nullvar")
-- lost over RPC, so test locally:
eq({false, true}, exec_lua [[
- return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL}
+ return {vim.b.nonexistent == vim.NIL, vim.b.nullvar == vim.NIL}
]])
matches([[attempt to index .* nil value]],
@@ -1133,6 +1171,7 @@ describe('lua stdlib', function()
vim.b.AddCounter = add_counter
vim.b.GetCounter = get_counter
vim.b.funcs = {add = add_counter, get = get_counter}
+ vim.b.AddParens = function(s) return '(' .. s .. ')' end
]]
eq(0, eval('b:GetCounter()'))
@@ -1148,6 +1187,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.b.funcs.get()]]))
exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
+ eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]]))
exec_lua [[
local counter = 0
@@ -1156,6 +1196,7 @@ describe('lua stdlib', function()
vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter)
vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter)
vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter})
+ vim.api.nvim_buf_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end)
]]
eq(0, eval('b:GetCounter()'))
@@ -1171,6 +1212,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.b.funcs.get()]]))
exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
+ eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]]))
exec([[
function Test()
@@ -1189,7 +1231,7 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.b.testing")
eq(NIL, funcs.luaeval "vim.b.other")
- eq(NIL, funcs.luaeval "vim.b.nonexistant")
+ eq(NIL, funcs.luaeval "vim.b.nonexistent")
end)
it('vim.w', function()
@@ -1208,8 +1250,8 @@ describe('lua stdlib', function()
eq('hi', funcs.luaeval "vim.w.testing")
eq('bye', funcs.luaeval "vim.w[WIN].testing")
eq(123, funcs.luaeval "vim.w.other")
- eq(NIL, funcs.luaeval "vim.w.nonexistant")
- eq(NIL, funcs.luaeval "vim.w[WIN].nonexistant")
+ eq(NIL, funcs.luaeval "vim.w.nonexistent")
+ eq(NIL, funcs.luaeval "vim.w[WIN].nonexistent")
matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.w[WIN][0].testing'))
@@ -1227,6 +1269,7 @@ describe('lua stdlib', function()
vim.w.AddCounter = add_counter
vim.w.GetCounter = get_counter
vim.w.funcs = {add = add_counter, get = get_counter}
+ vim.w.AddParens = function(s) return '(' .. s .. ')' end
]]
eq(0, eval('w:GetCounter()'))
@@ -1242,6 +1285,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.w.funcs.get()]]))
exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
+ eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]]))
exec_lua [[
local counter = 0
@@ -1250,6 +1294,7 @@ describe('lua stdlib', function()
vim.api.nvim_win_set_var(0, 'AddCounter', add_counter)
vim.api.nvim_win_set_var(0, 'GetCounter', get_counter)
vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter})
+ vim.api.nvim_win_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end)
]]
eq(0, eval('w:GetCounter()'))
@@ -1265,6 +1310,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.w.funcs.get()]]))
exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
+ eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]]))
exec([[
function Test()
@@ -1283,7 +1329,7 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.w.testing")
eq(NIL, funcs.luaeval "vim.w.other")
- eq(NIL, funcs.luaeval "vim.w.nonexistant")
+ eq(NIL, funcs.luaeval "vim.w.nonexistent")
end)
it('vim.t', function()
@@ -1295,10 +1341,10 @@ describe('lua stdlib', function()
eq('hi', funcs.luaeval "vim.t.testing")
eq(123, funcs.luaeval "vim.t.other")
- eq(NIL, funcs.luaeval "vim.t.nonexistant")
+ eq(NIL, funcs.luaeval "vim.t.nonexistent")
eq('hi', funcs.luaeval "vim.t[0].testing")
eq(123, funcs.luaeval "vim.t[0].other")
- eq(NIL, funcs.luaeval "vim.t[0].nonexistant")
+ eq(NIL, funcs.luaeval "vim.t[0].nonexistent")
matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.t[0][0].testing'))
@@ -1316,6 +1362,7 @@ describe('lua stdlib', function()
vim.t.AddCounter = add_counter
vim.t.GetCounter = get_counter
vim.t.funcs = {add = add_counter, get = get_counter}
+ vim.t.AddParens = function(s) return '(' .. s .. ')' end
]]
eq(0, eval('t:GetCounter()'))
@@ -1331,6 +1378,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.t.funcs.get()]]))
exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
+ eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]]))
exec_lua [[
local counter = 0
@@ -1339,6 +1387,7 @@ describe('lua stdlib', function()
vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter)
vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter)
vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter})
+ vim.api.nvim_tabpage_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end)
]]
eq(0, eval('t:GetCounter()'))
@@ -1354,6 +1403,7 @@ describe('lua stdlib', function()
eq(5, exec_lua([[return vim.t.funcs.get()]]))
exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
+ eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]]))
exec_lua [[
vim.cmd "tabnew"
@@ -1361,15 +1411,27 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.t.testing")
eq(NIL, funcs.luaeval "vim.t.other")
- eq(NIL, funcs.luaeval "vim.t.nonexistant")
+ eq(NIL, funcs.luaeval "vim.t.nonexistent")
end)
it('vim.env', function()
- exec_lua [[
- vim.fn.setenv("A", 123)
- ]]
- eq('123', funcs.luaeval "vim.env.A")
- eq(true, funcs.luaeval "vim.env.B == nil")
+ exec_lua([[vim.fn.setenv('A', 123)]])
+ eq('123', funcs.luaeval('vim.env.A'))
+ exec_lua([[vim.env.A = 456]])
+ eq('456', funcs.luaeval('vim.env.A'))
+ exec_lua([[vim.env.A = nil]])
+ eq(NIL, funcs.luaeval('vim.env.A'))
+
+ eq(true, funcs.luaeval('vim.env.B == nil'))
+
+ command([[let $HOME = 'foo']])
+ eq('foo', funcs.expand('~'))
+ eq('foo', funcs.luaeval('vim.env.HOME'))
+ exec_lua([[vim.env.HOME = nil]])
+ eq('foo', funcs.expand('~'))
+ exec_lua([[vim.env.HOME = 'bar']])
+ eq('bar', funcs.expand('~'))
+ eq('bar', funcs.luaeval('vim.env.HOME'))
end)
it('vim.v', function()
@@ -1396,7 +1458,7 @@ describe('lua stdlib', function()
]]
eq('', funcs.luaeval "vim.bo.filetype")
eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
- matches("unknown option 'nosuchopt'$",
+ matches("no such option: 'nosuchopt'$",
pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
@@ -1417,7 +1479,7 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo.cole")
eq(0, funcs.luaeval "vim.wo[0].cole")
eq(0, funcs.luaeval "vim.wo[1001].cole")
- matches("unknown option 'notanopt'$",
+ matches("no such option: 'notanopt'$",
pcall_err(exec_lua, 'return vim.wo.notanopt'))
matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.wo[0][0].list'))
@@ -2141,6 +2203,22 @@ describe('lua stdlib', function()
end)
end) -- vim.opt
+ describe('opt_local', function()
+ it('should be able to append to an array list type option', function()
+ eq({ "foo,bar,baz,qux" }, exec_lua [[
+ local result = {}
+
+ vim.opt.tags = "foo,bar"
+ vim.opt_local.tags:append("baz")
+ vim.opt_local.tags:append("qux")
+
+ table.insert(result, vim.bo.tags)
+
+ return result
+ ]])
+ end)
+ end)
+
it('vim.cmd', function()
exec_lua [[
vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')"
@@ -2173,6 +2251,10 @@ describe('lua stdlib', function()
eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]])
eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]])
eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]])
+
+ -- vim.regex() error inside :silent! should not crash. #20546
+ command([[silent! lua vim.regex('\\z')]])
+ assert_alive()
end)
it('vim.defer_fn', function()
@@ -2185,13 +2267,19 @@ describe('lua stdlib', function()
eq(true, exec_lua[[return vim.g.test]])
end)
- it('vim.region', function()
- insert(helpers.dedent( [[
- text tααt tααt text
- text tαxt txtα tex
- text tαxt tαxt
- ]]))
- eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
+ describe('vim.region', function()
+ it('charwise', function()
+ insert(helpers.dedent( [[
+ text tααt tααt text
+ text tαxt txtα tex
+ text tαxt tαxt
+ ]]))
+ eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
+ end)
+ it('blockwise', function()
+ insert([[αα]])
+ eq({0,5}, exec_lua[[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]])
+ end)
end)
describe('vim.on_key', function()
@@ -2623,6 +2711,46 @@ describe('lua stdlib', function()
a.nvim_buf_call(a.nvim_create_buf(false, true), function() vim.cmd "redraw" end)
]]
end)
+
+ it('can be nested crazily with hidden buffers', function()
+ eq(true, exec_lua([[
+ local function scratch_buf_call(fn)
+ local buf = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_option(buf, 'cindent', true)
+ return vim.api.nvim_buf_call(buf, function()
+ return vim.api.nvim_get_current_buf() == buf
+ and vim.api.nvim_buf_get_option(buf, 'cindent')
+ and fn()
+ end) and vim.api.nvim_buf_delete(buf, {}) == nil
+ end
+
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return scratch_buf_call(function()
+ return true
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ end)
+ ]]))
+ end)
end)
describe('vim.api.nvim_win_call', function()
@@ -2721,6 +2849,57 @@ describe('lua stdlib', function()
]]
end)
end)
+
+ describe('vim.iconv', function()
+ it('can convert strings', function()
+ eq('hello', exec_lua[[
+ return vim.iconv('hello', 'latin1', 'utf-8')
+ ]])
+ end)
+
+ it('can validate arguments', function()
+ eq({false, 'Expected at least 3 arguments'}, exec_lua[[
+ return {pcall(vim.iconv, 'hello')}
+ ]])
+
+ eq({false, 'bad argument #3 to \'?\' (expected string)'}, exec_lua[[
+ return {pcall(vim.iconv, 'hello', 'utf-8', true)}
+ ]])
+ end)
+
+ it('can handle bad encodings', function()
+ eq(NIL, exec_lua[[
+ return vim.iconv('hello', 'foo', 'bar')
+ ]])
+ end)
+
+ it('can handle strings with NUL bytes', function()
+ eq(7, exec_lua[[
+ local a = string.char(97, 98, 99, 0, 100, 101, 102) -- abc\0def
+ return string.len(vim.iconv(a, 'latin1', 'utf-8'))
+ ]])
+ end)
+
+ end)
+
+ describe("vim.defaulttable", function()
+ it("creates nested table by default", function()
+ eq({ b = {c = 1 } }, exec_lua[[
+ local a = vim.defaulttable()
+ a.b.c = 1
+ return a
+ ]])
+ end)
+
+ it("allows to create default objects", function()
+ eq({ b = 1 }, exec_lua[[
+ local a = vim.defaulttable(function() return 0 end)
+ a.b = a.b + 1
+ return a
+ ]])
+ end)
+ end)
+
end)
describe('lua: builtin modules', function()
@@ -2745,9 +2924,14 @@ describe('lua: builtin modules', function()
end)
- it('does not work when disabled without runtime', function()
- clear{args={'--luamod-dev'}, env={VIMRUNTIME='fixtures/a'}}
- expect_exit(exec_lua, [[return vim.tbl_count {x=1,y=2}]])
+ it('fails when disabled without runtime', function()
+ clear()
+ command("let $VIMRUNTIME='fixtures/a'")
+ -- Use system([nvim,…]) instead of clear() to avoid stderr noise. #21844
+ local out = funcs.system({nvim_prog, '--clean', '--luamod-dev',
+ [[+call nvim_exec_lua('return vim.tbl_count {x=1,y=2}')]], '+qa!'}):gsub('\r\n', '\n')
+ eq(1, eval('v:shell_error'))
+ matches("'vim%.shared' not found", out)
end)
end)
diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua
index d55268fc78..3121ac051f 100644
--- a/test/functional/lua/xdiff_spec.lua
+++ b/test/functional/lua/xdiff_spec.lua
@@ -74,11 +74,13 @@ describe('xdiff bindings', function()
end)
it('with error callback', function()
- exec_lua([[on_hunk = function(sa, ca, sb, cb)
+ exec_lua[[
+ on_hunk = function(sa, ca, sb, cb)
error('ERROR1')
- end]])
+ end
+ ]]
- eq([[Error executing lua: [string "<nvim>"]:0: error running function on_hunk: [string "<nvim>"]:0: ERROR1]],
+ eq([[error running function on_hunk: [string "<nvim>"]:0: ERROR1]],
pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]]))
end)
@@ -135,19 +137,19 @@ describe('xdiff bindings', function()
end)
it('can handle bad args', function()
- eq([[Error executing lua: [string "<nvim>"]:0: Expected at least 2 arguments]],
+ eq([[Expected at least 2 arguments]],
pcall_err(exec_lua, [[vim.diff('a')]]))
- eq([[Error executing lua: [string "<nvim>"]:0: bad argument #1 to 'diff' (expected string)]],
+ eq([[bad argument #1 to 'diff' (expected string)]],
pcall_err(exec_lua, [[vim.diff(1, 2)]]))
- eq([[Error executing lua: [string "<nvim>"]:0: bad argument #3 to 'diff' (expected table)]],
+ eq([[bad argument #3 to 'diff' (expected table)]],
pcall_err(exec_lua, [[vim.diff('a', 'b', true)]]))
- eq([[Error executing lua: [string "<nvim>"]:0: unexpected key: bad_key]],
+ eq([[unexpected key: bad_key]],
pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]]))
- eq([[Error executing lua: [string "<nvim>"]:0: on_hunk is not a function]],
+ eq([[on_hunk is not a function]],
pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]]))
end)
diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua
index 74959a8e76..0b6fe9533c 100644
--- a/test/functional/options/autochdir_spec.lua
+++ b/test/functional/options/autochdir_spec.lua
@@ -16,7 +16,7 @@ describe("'autochdir'", function()
-- With 'autochdir' on, we should get the directory of tty-test.c.
clear('--cmd', 'set autochdir', targetdir..'/tty-test.c')
- eq(helpers.iswin() and expected:gsub('/', '\\') or expected, funcs.getcwd())
+ eq(helpers.is_os('win') and expected:gsub('/', '\\') or expected, funcs.getcwd())
end)
it('is not overwritten by getwinvar() call #17609',function()
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 4e2f2ab63e..84ec43f4cb 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_alive = helpers.assert_alive
+local assert_log = helpers.assert_log
local meths = helpers.meths
local command = helpers.command
local clear = helpers.clear
@@ -12,13 +13,15 @@ local eq = helpers.eq
local ok = helpers.ok
local funcs = helpers.funcs
local insert = helpers.insert
-local iswin = helpers.iswin
local neq = helpers.neq
local mkdir = helpers.mkdir
local rmdir = helpers.rmdir
local alter_slashes = helpers.alter_slashes
local tbl_contains = helpers.tbl_contains
local expect_exit = helpers.expect_exit
+local is_os = helpers.is_os
+
+local testlog = 'Xtest-defaults-log'
describe('startup defaults', function()
describe(':filetype', function()
@@ -220,7 +223,9 @@ describe('startup defaults', function()
end)
it("'packpath'", function()
- clear()
+ clear{
+ args_rm={'runtimepath'},
+ }
-- Defaults to &runtimepath.
eq(meths.get_option('runtimepath'), meths.get_option('packpath'))
@@ -238,7 +243,7 @@ describe('startup defaults', function()
describe('$NVIM_LOG_FILE', function()
local xdgdir = 'Xtest-startup-xdg-logpath'
- local xdgstatedir = iswin() and xdgdir..'/nvim-data' or xdgdir..'/nvim'
+ local xdgstatedir = is_os('win') and xdgdir..'/nvim-data' or xdgdir..'/nvim'
after_each(function()
os.remove('Xtest-logpath')
rmdir(xdgdir)
@@ -273,11 +278,15 @@ describe('XDG defaults', function()
-- Need separate describe() blocks to not run clear() twice.
-- Do not put before_each() here for the same reasons.
+ after_each(function()
+ os.remove(testlog)
+ end)
+
it("&runtimepath data-dir matches stdpath('data') #9910", function()
clear()
local rtp = eval('split(&runtimepath, ",")')
local rv = {}
- local expected = (iswin()
+ local expected = (is_os('win')
and { [[\nvim-data\site]], [[\nvim-data\site\after]], }
or { '/nvim/site', '/nvim/site/after', })
@@ -325,28 +334,35 @@ describe('XDG defaults', function()
return vimruntime, libdir
end
- local env_sep = iswin() and ';' or ':'
- local data_dir = iswin() and 'nvim-data' or 'nvim'
- local state_dir = iswin() and 'nvim-data' or 'nvim'
- local root_path = iswin() and 'C:' or ''
+ local env_sep = is_os('win') and ';' or ':'
+ local data_dir = is_os('win') and 'nvim-data' or 'nvim'
+ local state_dir = is_os('win') and 'nvim-data' or 'nvim'
+ local root_path = is_os('win') and 'C:' or ''
describe('with too long XDG variables', function()
before_each(function()
- clear({env={
- XDG_CONFIG_HOME=(root_path .. ('/x'):rep(4096)),
- XDG_CONFIG_DIRS=(root_path .. ('/a'):rep(2048)
- .. env_sep.. root_path .. ('/b'):rep(2048)
- .. (env_sep .. root_path .. '/c'):rep(512)),
- XDG_DATA_HOME=(root_path .. ('/X'):rep(4096)),
- XDG_RUNTIME_DIR=(root_path .. ('/X'):rep(4096)),
- XDG_STATE_HOME=(root_path .. ('/X'):rep(4096)),
- XDG_DATA_DIRS=(root_path .. ('/A'):rep(2048)
- .. env_sep .. root_path .. ('/B'):rep(2048)
- .. (env_sep .. root_path .. '/C'):rep(512)),
+ clear({
+ args_rm={'runtimepath'},
+ env={
+ NVIM_LOG_FILE=testlog,
+ XDG_CONFIG_HOME=(root_path .. ('/x'):rep(4096)),
+ XDG_CONFIG_DIRS=(root_path .. ('/a'):rep(2048)
+ .. env_sep.. root_path .. ('/b'):rep(2048)
+ .. (env_sep .. root_path .. '/c'):rep(512)),
+ XDG_DATA_HOME=(root_path .. ('/X'):rep(4096)),
+ XDG_RUNTIME_DIR=(root_path .. ('/X'):rep(4096)),
+ XDG_STATE_HOME=(root_path .. ('/X'):rep(4096)),
+ XDG_DATA_DIRS=(root_path .. ('/A'):rep(2048)
+ .. env_sep .. root_path .. ('/B'):rep(2048)
+ .. (env_sep .. root_path .. '/C'):rep(512)),
}})
end)
it('are correctly set', function()
+ if not is_os('win') then
+ assert_log('Failed to start server: no such file or directory: /X/X/X', testlog, 10)
+ end
+
local vimruntime, libdir = vimruntime_and_libdir()
eq(((root_path .. ('/x'):rep(4096) .. '/nvim'
@@ -405,17 +421,24 @@ describe('XDG defaults', function()
describe('with XDG variables that can be expanded', function()
before_each(function()
- clear({env={
- XDG_CONFIG_HOME='$XDG_DATA_HOME',
- XDG_CONFIG_DIRS='$XDG_DATA_DIRS',
- XDG_DATA_HOME='$XDG_CONFIG_HOME',
- XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR',
- XDG_STATE_HOME='$XDG_CONFIG_HOME',
- XDG_DATA_DIRS='$XDG_CONFIG_DIRS',
+ clear({
+ args_rm={'runtimepath'},
+ env={
+ NVIM_LOG_FILE=testlog,
+ XDG_CONFIG_HOME='$XDG_DATA_HOME',
+ XDG_CONFIG_DIRS='$XDG_DATA_DIRS',
+ XDG_DATA_HOME='$XDG_CONFIG_HOME',
+ XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR',
+ XDG_STATE_HOME='$XDG_CONFIG_HOME',
+ XDG_DATA_DIRS='$XDG_CONFIG_DIRS',
}})
end)
it('are not expanded', function()
+ if not is_os('win') then
+ assert_log('Failed to start server: no such file or directory: %$XDG_RUNTIME_DIR%/', testlog, 10)
+ end
+
local vimruntime, libdir = vimruntime_and_libdir()
eq((('$XDG_DATA_HOME/nvim'
.. ',$XDG_DATA_DIRS/nvim'
@@ -478,18 +501,20 @@ describe('XDG defaults', function()
describe('with commas', function()
before_each(function()
- clear({env={
- XDG_CONFIG_HOME=', , ,',
- XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-',
- XDG_DATA_HOME=',=,=,',
- XDG_STATE_HOME=',=,=,',
- XDG_DATA_DIRS=',≡,≡,' .. env_sep .. '≡,≡,≡',
+ clear({
+ args_rm={'runtimepath'},
+ env={
+ XDG_CONFIG_HOME=', , ,',
+ XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-',
+ XDG_DATA_HOME=',=,=,',
+ XDG_STATE_HOME=',=,=,',
+ XDG_DATA_DIRS=',≡,≡,' .. env_sep .. '≡,≡,≡',
}})
end)
it('are escaped properly', function()
local vimruntime, libdir = vimruntime_and_libdir()
- local path_sep = iswin() and '\\' or '/'
+ local path_sep = is_os('win') and '\\' or '/'
eq(('\\, \\, \\,' .. path_sep .. 'nvim'
.. ',\\,-\\,-\\,' .. path_sep .. 'nvim'
.. ',-\\,-\\,-' .. path_sep .. 'nvim'
@@ -541,9 +566,9 @@ end)
describe('stdpath()', function()
-- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions
-- due to XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_STATE_HOME being the same.
- local datadir = iswin() and 'nvim-data' or 'nvim'
- local statedir = iswin() and 'nvim-data' or 'nvim'
- local env_sep = iswin() and ';' or ':'
+ local datadir = is_os('win') and 'nvim-data' or 'nvim'
+ local statedir = is_os('win') and 'nvim-data' or 'nvim'
+ local env_sep = is_os('win') and ';' or ':'
it('acceptance', function()
clear() -- Do not explicitly set any env vars.
@@ -696,7 +721,7 @@ describe('stdpath()', function()
context('returns a List', function()
-- Some OS specific variables the system would have set.
local function base_env()
- if iswin() then
+ if is_os('win') then
return {
HOME='C:\\Users\\docwhat', -- technically, is not a usual PATH
HOMEDRIVE='C:',
diff --git a/test/functional/options/keymap_spec.lua b/test/functional/options/keymap_spec.lua
index a814c35a39..4fdc6ef4be 100644
--- a/test/functional/options/keymap_spec.lua
+++ b/test/functional/options/keymap_spec.lua
@@ -184,7 +184,7 @@ describe("'keymap' / :lmap", function()
feed('il<esc>')
expect('alllaaa')
end)
- -- This is a problem introduced when introducting :lmap and macro
+ -- This is a problem introduced when introducing :lmap and macro
-- compatibility. There are no plans to fix this as the complexity involved
-- seems too great.
pending('mappings not applied to macro replay of :lnoremap', function()
diff --git a/test/functional/options/mousescroll_spec.lua b/test/functional/options/mousescroll_spec.lua
index 2c9b2d175e..5bff45a836 100644
--- a/test/functional/options/mousescroll_spec.lua
+++ b/test/functional/options/mousescroll_spec.lua
@@ -97,6 +97,24 @@ describe("'mousescroll'", function()
eq(10, screencol())
scroll('left')
eq(10, screencol())
+
+ -- vertical scrolling is still disabled with non-zero 'scrolloff' value
+ command('set scrolloff=1')
+
+ eq(10, screenrow())
+ scroll('up')
+ eq(10, screenrow())
+ scroll('down')
+ eq(10, screenrow())
+
+ -- also in insert mode
+ feed('i')
+
+ eq(10, screenrow())
+ scroll('up')
+ eq(10, screenrow())
+ scroll('down')
+ eq(10, screenrow())
end)
local test_vertical_scrolling = function()
diff --git a/test/functional/plugin/ccomplete_spec.lua b/test/functional/plugin/ccomplete_spec.lua
new file mode 100644
index 0000000000..903f16fc73
--- /dev/null
+++ b/test/functional/plugin/ccomplete_spec.lua
@@ -0,0 +1,61 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local write_file = helpers.write_file
+
+describe('ccomplete#Complete', function()
+ setup(function()
+ -- Realistic tags generated from neovim source tree using `ctags -R *`
+ write_file(
+ 'Xtags',
+ [[
+augroup_del src/nvim/autocmd.c /^void augroup_del(char *name, bool stupid_legacy_mode)$/;" f typeref:typename:void
+augroup_exists src/nvim/autocmd.c /^bool augroup_exists(const char *name)$/;" f typeref:typename:bool
+augroup_find src/nvim/autocmd.c /^int augroup_find(const char *name)$/;" f typeref:typename:int
+aupat_get_buflocal_nr src/nvim/autocmd.c /^int aupat_get_buflocal_nr(char *pat, int patlen)$/;" f typeref:typename:int
+aupat_is_buflocal src/nvim/autocmd.c /^bool aupat_is_buflocal(char *pat, int patlen)$/;" f typeref:typename:bool
+expand_get_augroup_name src/nvim/autocmd.c /^char *expand_get_augroup_name(expand_T *xp, int idx)$/;" f typeref:typename:char *
+expand_get_event_name src/nvim/autocmd.c /^char *expand_get_event_name(expand_T *xp, int idx)$/;" f typeref:typename:char *
+]]
+ )
+ end)
+
+ before_each(function()
+ clear()
+ command('set tags=Xtags')
+ end)
+
+ teardown(function()
+ os.remove('Xtags')
+ end)
+
+ it('can complete from Xtags', function()
+ local completed = eval('ccomplete#Complete(0, "a")')
+ eq(5, #completed)
+ eq('augroup_del(', completed[1].word)
+ eq('f', completed[1].kind)
+
+ local aupat = eval('ccomplete#Complete(0, "aupat")')
+ eq(2, #aupat)
+ eq('aupat_get_buflocal_nr(', aupat[1].word)
+ eq('f', aupat[1].kind)
+ end)
+
+ it('does not error when returning no matches', function()
+ local completed = eval('ccomplete#Complete(0, "doesnotmatch")')
+ eq({}, completed)
+ end)
+
+ it('can find the beginning of a word for C', function()
+ command('set filetype=c')
+ feed('i int something = augroup')
+ local result = eval('ccomplete#Complete(1, "")')
+ eq(#' int something = ', result)
+
+ local completed = eval('ccomplete#Complete(0, "augroup")')
+ eq(3, #completed)
+ end)
+end)
diff --git a/test/functional/plugin/cfilter_spec.lua b/test/functional/plugin/cfilter_spec.lua
new file mode 100644
index 0000000000..8b1e75b495
--- /dev/null
+++ b/test/functional/plugin/cfilter_spec.lua
@@ -0,0 +1,106 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local funcs = helpers.funcs
+
+describe('cfilter.lua', function()
+ before_each(function()
+ clear()
+ command('packadd cfilter')
+ end)
+
+ for _, list in ipairs({
+ {
+ name = 'Cfilter',
+ get = funcs.getqflist,
+ set = funcs.setqflist,
+ },
+ {
+ name = 'Lfilter',
+ get = function()
+ return funcs.getloclist(0)
+ end,
+ set = function(items)
+ return funcs.setloclist(0, items)
+ end,
+ },
+ }) do
+ local filter = function(s, bang)
+ if not bang then
+ bang = ''
+ else
+ bang = '!'
+ end
+
+ command(string.format('%s%s %s', list.name, bang, s))
+ end
+
+ describe((':%s'):format(list.name), function()
+ it('does not error on empty list', function()
+ filter('nothing')
+ eq({}, funcs.getqflist())
+ end)
+
+ it('requires an argument', function()
+ local ok = pcall(filter, '')
+ eq(false, ok)
+ end)
+
+ local test = function(name, s, res, map, bang)
+ it(('%s (%s)'):format(name, s), function()
+ list.set({
+ { filename = 'foo', lnum = 1, text = 'bar' },
+ { filename = 'foo', lnum = 2, text = 'baz' },
+ { filename = 'foo', lnum = 3, text = 'zed' },
+ })
+
+ filter(s, bang)
+
+ local got = list.get()
+ if map then
+ got = map(got)
+ end
+ eq(res, got)
+ end)
+ end
+
+ local toname = function(qflist)
+ return funcs.map(qflist, 'v:val.text')
+ end
+
+ test('filters with no matches', 'does not match', {})
+
+ test('filters with matches', 'ba', { 'bar', 'baz' }, toname)
+ test('filters with matches', 'z', { 'baz', 'zed' }, toname)
+ test('filters with matches', '^z', { 'zed' }, toname)
+ test('filters with not matches', '^z', { 'bar', 'baz' }, toname, true)
+
+ it('also supports using the / register', function()
+ list.set({
+ { filename = 'foo', lnum = 1, text = 'bar' },
+ { filename = 'foo', lnum = 2, text = 'baz' },
+ { filename = 'foo', lnum = 3, text = 'zed' },
+ })
+
+ funcs.setreg('/', 'ba')
+ filter('/')
+
+ eq({ 'bar', 'baz' }, toname(list.get()))
+ end)
+
+ it('also supports using the / register with bang', function()
+ list.set({
+ { filename = 'foo', lnum = 1, text = 'bar' },
+ { filename = 'foo', lnum = 2, text = 'baz' },
+ { filename = 'foo', lnum = 3, text = 'zed' },
+ })
+
+ funcs.setreg('/', 'ba')
+ filter('/', true)
+
+ eq({ 'zed' }, toname(list.get()))
+ end)
+ end)
+ end
+end)
diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua
new file mode 100644
index 0000000000..e6a2550aba
--- /dev/null
+++ b/test/functional/plugin/editorconfig_spec.lua
@@ -0,0 +1,210 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local pathsep = helpers.get_pathsep()
+local curbufmeths = helpers.curbufmeths
+local funcs = helpers.funcs
+local meths = helpers.meths
+
+local testdir = 'Xtest-editorconfig'
+
+local function test_case(name, expected)
+ local filename = testdir .. pathsep .. name
+ command('edit ' .. filename)
+ for opt, val in pairs(expected) do
+ eq(val, curbufmeths.get_option(opt), name)
+ end
+end
+
+setup(function()
+ helpers.mkdir_p(testdir)
+ helpers.write_file(
+ testdir .. pathsep .. '.editorconfig',
+ [[
+ root = true
+
+ [3_space.txt]
+ indent_style = space
+ indent_size = 3
+ tab_width = 3
+
+ [4_space.py]
+ indent_style = space
+ indent_size = 4
+ tab_width = 8
+
+ [space.txt]
+ indent_style = space
+ indent_size = tab
+
+ [tab.txt]
+ indent_style = tab
+
+ [4_tab.txt]
+ indent_style = tab
+ indent_size = 4
+ tab_width = 4
+
+ [4_tab_width_of_8.txt]
+ indent_style = tab
+ indent_size = 4
+ tab_width = 8
+
+ [lf.txt]
+ end_of_line = lf
+
+ [crlf.txt]
+ end_of_line = crlf
+
+ [cr.txt]
+ end_of_line = cr
+
+ [utf-8.txt]
+ charset = utf-8
+
+ [utf-8-bom.txt]
+ charset = utf-8-bom
+
+ [utf-16be.txt]
+ charset = utf-16be
+
+ [utf-16le.txt]
+ charset = utf-16le
+
+ [latin1.txt]
+ charset = latin1
+
+ [with_newline.txt]
+ insert_final_newline = true
+
+ [without_newline.txt]
+ insert_final_newline = false
+
+ [trim.txt]
+ trim_trailing_whitespace = true
+
+ [no_trim.txt]
+ trim_trailing_whitespace = false
+
+ [max_line_length.txt]
+ max_line_length = 42
+ ]]
+ )
+end)
+
+teardown(function()
+ helpers.rmdir(testdir)
+end)
+
+describe('editorconfig', function()
+ before_each(function()
+ -- Remove -u NONE so that plugins (i.e. editorconfig.lua) are loaded
+ clear({ args_rm = { '-u' } })
+ end)
+
+ it('sets indent options', function()
+ test_case('3_space.txt', {
+ expandtab = true,
+ shiftwidth = 3,
+ softtabstop = -1,
+ tabstop = 3,
+ })
+
+ test_case('4_space.py', {
+ expandtab = true,
+ shiftwidth = 4,
+ softtabstop = -1,
+ tabstop = 8,
+ })
+
+ test_case('space.txt', {
+ expandtab = true,
+ shiftwidth = 0,
+ softtabstop = 0,
+ })
+
+ test_case('tab.txt', {
+ expandtab = false,
+ shiftwidth = 0,
+ softtabstop = 0,
+ })
+
+ test_case('4_tab.txt', {
+ expandtab = false,
+ shiftwidth = 4,
+ softtabstop = -1,
+ tabstop = 4,
+ })
+
+ test_case('4_tab_width_of_8.txt', {
+ expandtab = false,
+ shiftwidth = 4,
+ softtabstop = -1,
+ tabstop = 8,
+ })
+ end)
+
+ it('sets end-of-line options', function()
+ test_case('lf.txt', { fileformat = 'unix' })
+ test_case('crlf.txt', { fileformat = 'dos' })
+ test_case('cr.txt', { fileformat = 'mac' })
+ end)
+
+ it('sets encoding options', function()
+ test_case('utf-8.txt', { fileencoding = 'utf-8', bomb = false })
+ test_case('utf-8-bom.txt', { fileencoding = 'utf-8', bomb = true })
+ test_case('utf-16be.txt', { fileencoding = 'utf-16', bomb = false })
+ test_case('utf-16le.txt', { fileencoding = 'utf-16le', bomb = false })
+ test_case('latin1.txt', { fileencoding = 'latin1', bomb = false })
+ end)
+
+ it('sets newline options', function()
+ test_case('with_newline.txt', { fixendofline = true, endofline = true })
+ test_case('without_newline.txt', { fixendofline = false, endofline = false })
+ end)
+
+ it('respects trim_trailing_whitespace', function()
+ local filename = testdir .. pathsep .. 'trim.txt'
+ -- luacheck: push ignore 613
+ local untrimmed = [[
+This line ends in whitespace
+So does this one
+And this one
+But not this one
+]]
+ -- luacheck: pop
+ local trimmed = untrimmed:gsub('%s+\n', '\n')
+
+ helpers.write_file(filename, untrimmed)
+ command('edit ' .. filename)
+ command('write')
+ command('bdelete')
+ eq(trimmed, helpers.read_file(filename))
+
+ filename = testdir .. pathsep .. 'no_trim.txt'
+ helpers.write_file(filename, untrimmed)
+ command('edit ' .. filename)
+ command('write')
+ command('bdelete')
+ eq(untrimmed, helpers.read_file(filename))
+ end)
+
+ it('sets textwidth', function()
+ test_case('max_line_length.txt', { textwidth = 42 })
+ end)
+
+ it('can be disabled globally', function()
+ meths.set_var('editorconfig', false)
+ meths.set_option_value('shiftwidth', 42, {})
+ test_case('3_space.txt', { shiftwidth = 42 })
+ end)
+
+ it('can be disabled per-buffer', function()
+ meths.set_option_value('shiftwidth', 42, {})
+ local bufnr = funcs.bufadd(testdir .. pathsep .. '3_space.txt')
+ meths.buf_set_var(bufnr, 'editorconfig', false)
+ test_case('3_space.txt', { shiftwidth = 42 })
+ test_case('4_space.py', { shiftwidth = 4 })
+ end)
+end)
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index ba66117fb1..97d32313e5 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -5,7 +5,7 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local curbuf_contents = helpers.curbuf_contents
local command = helpers.command
-local eq, neq = helpers.eq, helpers.neq
+local eq, neq, matches = helpers.eq, helpers.neq, helpers.matches
local getcompletion = helpers.funcs.getcompletion
describe(':checkhealth', function()
@@ -29,8 +29,7 @@ describe(':checkhealth', function()
-- Do this after startup, otherwise it just breaks $VIMRUNTIME.
command("let $VIM='zub'")
command("checkhealth nvim")
- eq("ERROR: $VIM is invalid: zub",
- string.match(curbuf_contents(), "ERROR: $VIM .* zub"))
+ matches('ERROR $VIM .* zub', curbuf_contents())
end)
it('completions can be listed via getcompletion()', function()
clear()
@@ -56,21 +55,22 @@ describe('health.vim', function()
command("checkhealth full_render")
helpers.expect([[
+ ==============================================================================
full_render: health#full_render#check
- ========================================================================
- ## report 1
- - OK: life is fine
- - WARNING: no what installed
- - ADVICE:
- - pip what
- - make what
-
- ## report 2
- - INFO: stuff is stable
- - ERROR: why no hardcopy
- - ADVICE:
- - :help |:hardcopy|
- - :help |:TOhtml|
+
+ report 1 ~
+ - OK life is fine
+ - WARNING no what installed
+ - ADVICE:
+ - pip what
+ - make what
+
+ report 2 ~
+ - stuff is stable
+ - ERROR why no hardcopy
+ - ADVICE:
+ - :help |:hardcopy|
+ - :help |:TOhtml|
]])
end)
@@ -78,26 +78,29 @@ describe('health.vim', function()
command("checkhealth success1 success2 test_plug")
helpers.expect([[
+ ==============================================================================
success1: health#success1#check
- ========================================================================
- ## report 1
- - OK: everything is fine
- ## report 2
- - OK: nothing to see here
+ report 1 ~
+ - OK everything is fine
+
+ report 2 ~
+ - OK nothing to see here
+ ==============================================================================
success2: health#success2#check
- ========================================================================
- ## another 1
- - OK: ok
+ another 1 ~
+ - OK ok
+
+ ==============================================================================
test_plug: require("test_plug.health").check()
- ========================================================================
- ## report 1
- - OK: everything is fine
- ## report 2
- - OK: nothing to see here
+ report 1 ~
+ - OK everything is fine
+
+ report 2 ~
+ - OK nothing to see here
]])
end)
@@ -107,13 +110,14 @@ describe('health.vim', function()
-- and the Lua healthcheck is used instead.
helpers.expect([[
+ ==============================================================================
test_plug: require("test_plug.health").check()
- ========================================================================
- ## report 1
- - OK: everything is fine
- ## report 2
- - OK: nothing to see here
+ report 1 ~
+ - OK everything is fine
+
+ report 2 ~
+ - OK nothing to see here
]])
end)
@@ -121,13 +125,14 @@ describe('health.vim', function()
command("checkhealth test_plug.submodule")
helpers.expect([[
+ ==============================================================================
test_plug.submodule: require("test_plug.submodule.health").check()
- ========================================================================
- ## report 1
- - OK: everything is fine
- ## report 2
- - OK: nothing to see here
+ report 1 ~
+ - OK everything is fine
+
+ report 2 ~
+ - OK nothing to see here
]])
end)
@@ -138,30 +143,34 @@ describe('health.vim', function()
local received = table.concat(buf_lines, '\n', 1, #buf_lines - 5)
local expected = helpers.dedent([[
+ ==============================================================================
test_plug: require("test_plug.health").check()
- ========================================================================
- ## report 1
- - OK: everything is fine
- ## report 2
- - OK: nothing to see here
+ report 1 ~
+ - OK everything is fine
+
+ report 2 ~
+ - OK nothing to see here
+ ==============================================================================
test_plug.submodule: require("test_plug.submodule.health").check()
- ========================================================================
- ## report 1
- - OK: everything is fine
- ## report 2
- - OK: nothing to see here
+ report 1 ~
+ - OK everything is fine
+ report 2 ~
+ - OK nothing to see here
+
+ ==============================================================================
test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
- ========================================================================
- - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+ - ERROR The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+
+ ==============================================================================
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
- ========================================================================
- - ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
- function health#check, line 20]])
+
+ - ERROR Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
+ function health#check, line 25]])
eq(expected, received)
end)
@@ -169,11 +178,12 @@ describe('health.vim', function()
command("checkhealth broken")
helpers.expect([[
+ ==============================================================================
broken: health#broken#check
- ========================================================================
- - ERROR: Failed to run healthcheck for "broken" plugin. Exception:
- function health#check[20]..health#broken#check, line 1
- caused an error
+
+ - ERROR Failed to run healthcheck for "broken" plugin. Exception:
+ function health#check[25]..health#broken#check, line 1
+ caused an error
]])
end)
@@ -181,9 +191,10 @@ describe('health.vim', function()
command("checkhealth test_plug.submodule_empty")
helpers.expect([[
+ ==============================================================================
test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
- ========================================================================
- - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+
+ - ERROR The healthcheck report for "test_plug.submodule_empty" plugin is empty.
]])
end)
@@ -198,38 +209,38 @@ describe('health.vim', function()
local expected = global_helpers.dedent([[
+ ==============================================================================
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
- ========================================================================
- - ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
- function health#check, line 20]])
+
+ - ERROR Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
+ function health#check, line 25]])
eq(expected, received)
end)
it("highlights OK, ERROR", function()
- local screen = Screen.new(72, 10)
+ local screen = Screen.new(50, 12)
screen:attach()
screen:set_default_attr_ids({
Ok = { foreground = Screen.colors.Grey3, background = 6291200 },
Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- Heading = { bold=true, foreground=Screen.colors.Magenta },
- Heading2 = { foreground = Screen.colors.SlateBlue },
- Bar = { foreground = 0x6a0dad },
- Bullet = { bold=true, foreground=Screen.colors.Brown },
+ Heading = { foreground = tonumber('0x6a0dad') },
+ Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey },
})
command("checkhealth foo success1")
- command("1tabclose")
- command("set laststatus=0")
+ command("set nowrap laststatus=0")
screen:expect{grid=[[
- ^ |
- {Heading:foo: } |
- {Bar:========================================================================}|
- {Bullet: -} {Error:ERROR}: No healthcheck found for "foo" plugin. |
- |
- {Heading:success1: health#success1#check} |
- {Bar:========================================================================}|
- {Heading2:##}{Heading: report 1} |
- {Bullet: -} {Ok:OK}: everything is fine |
- |
+ ^ |
+ {Bar:──────────────────────────────────────────────────}|
+ {Heading:foo: } |
+ |
+ - {Error:ERROR} No healthcheck found for "foo" plugin. |
+ |
+ {Bar:──────────────────────────────────────────────────}|
+ {Heading:success1: health#success1#check} |
+ |
+ {Heading:report 1} |
+ - {Ok:OK} everything is fine |
+ |
]]}
end)
@@ -238,9 +249,10 @@ describe('health.vim', function()
-- luacheck: ignore 613
helpers.expect([[
+ ==============================================================================
non_existent_healthcheck:
- ========================================================================
- - ERROR: No healthcheck found for "non_existent_healthcheck" plugin.
+
+ - ERROR No healthcheck found for "non_existent_healthcheck" plugin.
]])
end)
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
index ecc2f579b8..3d7a15a191 100644
--- a/test/functional/plugin/lsp/codelens_spec.lua
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -58,6 +58,41 @@ describe('vim.lsp.codelens', function()
]], bufnr)
eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks)
+ end)
+
+ it('can clear all lens', function()
+ local fake_uri = "file:///fake/uri"
+ local bufnr = exec_lua([[
+ fake_uri = ...
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ local lines = {'So', 'many', 'lines'}
+ vim.fn.bufload(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
+ return bufnr
+ ]], fake_uri)
+
+ exec_lua([[
+ local bufnr = ...
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 0 }
+ },
+ command = { title = 'Lens1', command = 'Dummy' }
+ },
+ }
+ vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ ]], bufnr)
+
+ local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ eq(1, #stored_lenses)
+
+ exec_lua([[
+ vim.lsp.codelens.clear()
+ ]])
+ stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ eq(0, #stored_lenses)
end)
end)
diff --git a/test/functional/plugin/lsp/helpers.lua b/test/functional/plugin/lsp/helpers.lua
new file mode 100644
index 0000000000..028ccb9e2c
--- /dev/null
+++ b/test/functional/plugin/lsp/helpers.lua
@@ -0,0 +1,176 @@
+local helpers = require('test.functional.helpers')(nil)
+
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local run = helpers.run
+local stop = helpers.stop
+local NIL = helpers.NIL
+
+local M = {}
+
+function M.clear_notrace()
+ -- problem: here be dragons
+ -- solution: don't look too closely for dragons
+ clear {env={
+ NVIM_LUA_NOTRACK="1";
+ VIMRUNTIME=os.getenv"VIMRUNTIME";
+ }}
+end
+
+M.create_server_definition = [[
+ function _create_server(opts)
+ opts = opts or {}
+ local server = {}
+ server.messages = {}
+
+ function server.cmd(dispatchers)
+ local closing = false
+ local handlers = opts.handlers or {}
+ local srv = {}
+
+ function srv.request(method, params, callback)
+ table.insert(server.messages, {
+ method = method,
+ params = params,
+ })
+ local handler = handlers[method]
+ if handler then
+ local response, err = handler(method, params)
+ callback(err, response)
+ elseif method == 'initialize' then
+ callback(nil, {
+ capabilities = opts.capabilities or {}
+ })
+ elseif method == 'shutdown' then
+ callback(nil, nil)
+ end
+ local request_id = #server.messages
+ return true, request_id
+ end
+
+ function srv.notify(method, params)
+ table.insert(server.messages, {
+ method = method,
+ params = params
+ })
+ if method == 'exit' then
+ dispatchers.on_exit(0, 15)
+ end
+ end
+
+ function srv.is_closing()
+ return closing
+ end
+
+ function srv.terminate()
+ closing = true
+ end
+
+ return srv
+ end
+
+ return server
+ end
+]]
+
+-- Fake LSP server.
+M.fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
+M.fake_lsp_logfile = 'Xtest-fake-lsp.log'
+
+local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
+ exec_lua([=[
+ lsp = require('vim.lsp')
+ local test_name, fixture_filename, logfile, timeout, options, settings = ...
+ TEST_RPC_CLIENT_ID = lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = logfile;
+ NVIM_LUA_NOTRACK = "1";
+ };
+ cmd = {
+ vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
+ "-c", string.format("lua TEST_NAME = %q", test_name),
+ "-c", string.format("lua TIMEOUT = %d", timeout),
+ "-c", "luafile "..fixture_filename,
+ };
+ handlers = setmetatable({}, {
+ __index = function(t, method)
+ return function(...)
+ return vim.rpcrequest(1, 'handler', ...)
+ end
+ end;
+ });
+ workspace_folders = {{
+ uri = 'file://' .. vim.loop.cwd(),
+ name = 'test_folder',
+ }};
+ on_init = function(client, result)
+ TEST_RPC_CLIENT = client
+ vim.rpcrequest(1, "init", result)
+ end;
+ flags = {
+ allow_incremental_sync = options.allow_incremental_sync or false;
+ debounce_text_changes = options.debounce_text_changes or 0;
+ };
+ settings = settings;
+ on_exit = function(...)
+ vim.rpcnotify(1, "exit", ...)
+ end;
+ }
+ ]=], test_name, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3, options or {}, settings or {})
+end
+
+function M.test_rpc_server(config)
+ if config.test_name then
+ M.clear_notrace()
+ fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options, config.settings)
+ end
+ local client = setmetatable({}, {
+ __index = function(_, name)
+ -- Workaround for not being able to yield() inside __index for Lua 5.1 :(
+ -- Otherwise I would just return the value here.
+ return function(...)
+ return exec_lua([=[
+ local name = ...
+ if type(TEST_RPC_CLIENT[name]) == 'function' then
+ return TEST_RPC_CLIENT[name](select(2, ...))
+ else
+ return TEST_RPC_CLIENT[name]
+ end
+ ]=], name, ...)
+ end
+ end;
+ })
+ local code, signal
+ local function on_request(method, args)
+ if method == "init" then
+ if config.on_init then
+ config.on_init(client, unpack(args))
+ end
+ return NIL
+ end
+ if method == 'handler' then
+ if config.on_handler then
+ config.on_handler(unpack(args))
+ end
+ end
+ return NIL
+ end
+ local function on_notify(method, args)
+ if method == 'exit' then
+ code, signal = unpack(args)
+ return stop()
+ end
+ end
+ -- TODO specify timeout?
+ -- run(on_request, on_notify, config.on_setup, 1000)
+ run(on_request, on_notify, config.on_setup)
+ if config.on_exit then
+ config.on_exit(code, signal)
+ end
+ stop()
+ if config.test_name then
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
+ end
+end
+
+return M
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
new file mode 100644
index 0000000000..9c1ba86fe1
--- /dev/null
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -0,0 +1,1219 @@
+local helpers = require('test.functional.helpers')(after_each)
+local lsp_helpers = require('test.functional.plugin.lsp.helpers')
+local Screen = require('test.functional.ui.screen')
+
+local command = helpers.command
+local dedent = helpers.dedent
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+local insert = helpers.insert
+local matches = helpers.matches
+
+local clear_notrace = lsp_helpers.clear_notrace
+local create_server_definition = lsp_helpers.create_server_definition
+
+before_each(function()
+ clear_notrace()
+end)
+
+after_each(function()
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
+end)
+
+describe('semantic token highlighting', function()
+
+ describe('general', function()
+ local text = dedent([[
+ #include <iostream>
+
+ int main()
+ {
+ int x;
+ #ifdef __cplusplus
+ std::cout << x << "\n";
+ #else
+ printf("%d\n", x);
+ #endif
+ }
+ }]])
+
+ local legend = [[{
+ "tokenTypes": [
+ "variable", "variable", "parameter", "function", "method", "function", "property", "variable", "class", "interface", "enum", "enumMember", "type", "type", "unknown", "namespace", "typeParameter", "concept", "type", "macro", "comment"
+ ],
+ "tokenModifiers": [
+ "declaration", "deprecated", "deduced", "readonly", "static", "abstract", "virtual", "dependentName", "defaultLibrary", "usedAsMutableReference", "functionScope", "classScope", "fileScope", "globalScope"
+ ]
+ }]]
+
+ local response = [[{
+ "data": [ 2, 4, 4, 3, 8193, 2, 8, 1, 1, 1025, 1, 7, 11, 19, 8192, 1, 4, 3, 15, 8448, 0, 5, 4, 0, 8448, 0, 8, 1, 1, 1024, 1, 0, 5, 20, 0, 1, 0, 22, 20, 0, 1, 0, 6, 20, 0 ],
+ "resultId": 1
+ }]]
+
+ local edit_response = [[{
+ "edits": [ {"data": [ 2, 8, 1, 3, 8193, 1, 7, 11, 19, 8192, 1, 4, 3, 15, 8448, 0, 5, 4, 0, 8448, 0, 8, 1, 3, 8192 ], "deleteCount": 25, "start": 5 } ],
+ "resultId":"2"
+ }]]
+
+ local screen
+ before_each(function()
+ screen = Screen.new(40, 16)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = { bold = true, foreground = Screen.colors.Blue1 };
+ [2] = { foreground = Screen.colors.DarkCyan };
+ [3] = { foreground = Screen.colors.SlateBlue };
+ [4] = { bold = true, foreground = Screen.colors.SeaGreen };
+ [5] = { foreground = tonumber('0x6a0dad') };
+ [6] = { foreground = Screen.colors.Blue1 };
+ [7] = { bold = true, foreground = Screen.colors.DarkCyan };
+ [8] = { bold = true, foreground = Screen.colors.SlateBlue };
+ }
+ command([[ hi link @namespace Type ]])
+ command([[ hi link @function Special ]])
+ command([[ hi @declaration gui=bold ]])
+
+ exec_lua(create_server_definition)
+ exec_lua([[
+ local legend, response, edit_response = ...
+ server = _create_server({
+ capabilities = {
+ semanticTokensProvider = {
+ full = { delta = true },
+ legend = vim.fn.json_decode(legend),
+ },
+ },
+ handlers = {
+ ['textDocument/semanticTokens/full'] = function()
+ return vim.fn.json_decode(response)
+ end,
+ ['textDocument/semanticTokens/full/delta'] = function()
+ return vim.fn.json_decode(edit_response)
+ end,
+ }
+ })
+ ]], legend, response, edit_response)
+ end)
+
+ it('buffer is highlighted when attached', function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]])
+
+ insert(text)
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ int {7:x}; |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+ end)
+
+ it('buffer is unhighlighted when client is detached', function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]])
+
+ insert(text)
+
+ exec_lua([[
+ vim.notify = function() end
+ vim.lsp.buf_detach_client(bufnr, client_id)
+ ]])
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int main() |
+ { |
+ int x; |
+ #ifdef __cplusplus |
+ std::cout << x << "\n"; |
+ #else |
+ printf("%d\n", x); |
+ #endif |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+ end)
+
+ it('buffer is highlighted and unhighlighted when semantic token highlighting is started and stopped'
+ , function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]])
+
+ insert(text)
+
+ exec_lua([[
+ vim.notify = function() end
+ vim.lsp.semantic_tokens.stop(bufnr, client_id)
+ ]])
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int main() |
+ { |
+ int x; |
+ #ifdef __cplusplus |
+ std::cout << x << "\n"; |
+ #else |
+ printf("%d\n", x); |
+ #endif |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+
+ exec_lua([[
+ vim.lsp.semantic_tokens.start(bufnr, client_id)
+ ]])
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ int {7:x}; |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+ end)
+
+ it('buffer is re-highlighted when force refreshed', function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]])
+
+ insert(text)
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ int {7:x}; |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+
+ exec_lua([[
+ vim.lsp.semantic_tokens.force_refresh(bufnr)
+ ]])
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ int {7:x}; |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], unchanged = true }
+
+ local messages = exec_lua('return server.messages')
+ local token_request_count = 0
+ for _, message in ipairs(messages) do
+ assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
+ if message.method == 'textDocument/semanticTokens/full' then
+ token_request_count = token_request_count + 1
+ end
+ end
+ eq(2, token_request_count)
+ end)
+
+ it('destroys the highlighter if the buffer is deleted', function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]])
+
+ insert(text)
+
+ local highlighters = exec_lua([[
+ vim.api.nvim_buf_delete(bufnr, { force = true })
+ local semantic_tokens = vim.lsp.semantic_tokens
+ return semantic_tokens.__STHighlighter.active
+ ]])
+
+ eq({}, highlighters)
+ end)
+
+ it('updates highlights with delta request on buffer change', function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]])
+
+ insert(text)
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ int {7:x}; |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+ feed_command('%s/int x/int x()/')
+ feed_command('noh')
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ ^int {8:x}(); |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {3:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :noh |
+ ]] }
+ end)
+
+ it('prevents starting semantic token highlighting with invalid conditions', function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start_client({ name = 'dummy', cmd = server.cmd })
+ notifications = {}
+ vim.notify = function(...) table.insert(notifications, 1, {...}) end
+ ]])
+ eq(false, exec_lua("return vim.lsp.buf_is_attached(bufnr, client_id)"))
+
+ insert(text)
+
+ local notifications = exec_lua([[
+ vim.lsp.semantic_tokens.start(bufnr, client_id)
+ return notifications
+ ]])
+ matches('%[LSP%] Client with id %d not attached to buffer %d', notifications[1][1])
+
+ notifications = exec_lua([[
+ vim.lsp.semantic_tokens.start(bufnr, client_id + 1)
+ return notifications
+ ]])
+ matches('%[LSP%] No client with id %d', notifications[1][1])
+ end)
+
+ it('opt-out: does not activate semantic token highlighting if disabled in client attach',
+ function()
+ exec_lua([[
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ on_attach = vim.schedule_wrap(function(client, bufnr)
+ client.server_capabilities.semanticTokensProvider = nil
+ end),
+ })
+ ]])
+ eq(true, exec_lua("return vim.lsp.buf_is_attached(bufnr, client_id)"))
+
+ insert(text)
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int main() |
+ { |
+ int x; |
+ #ifdef __cplusplus |
+ std::cout << x << "\n"; |
+ #else |
+ printf("%d\n", x); |
+ #endif |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+
+ local notifications = exec_lua([[
+ local notifications = {}
+ vim.notify = function(...) table.insert(notifications, 1, {...}) end
+ vim.lsp.semantic_tokens.start(bufnr, client_id)
+ return notifications
+ ]])
+ eq('[LSP] Server does not support semantic tokens', notifications[1][1])
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int main() |
+ { |
+ int x; |
+ #ifdef __cplusplus |
+ std::cout << x << "\n"; |
+ #else |
+ printf("%d\n", x); |
+ #endif |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], unchanged = true }
+ end)
+
+ it('ignores null responses from the server', function()
+ exec_lua([[
+ local legend, response, edit_response = ...
+ server2 = _create_server({
+ capabilities = {
+ semanticTokensProvider = {
+ full = { delta = false },
+ },
+ },
+ handlers = {
+ ['textDocument/semanticTokens/full'] = function()
+ return nil
+ end,
+ ['textDocument/semanticTokens/full/delta'] = function()
+ return nil
+ end,
+ }
+ })
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
+ ]])
+ eq(true, exec_lua("return vim.lsp.buf_is_attached(bufnr, client_id)"))
+
+ insert(text)
+
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int main() |
+ { |
+ int x; |
+ #ifdef __cplusplus |
+ std::cout << x << "\n"; |
+ #else |
+ printf("%d\n", x); |
+ #endif |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+ end)
+
+ it('does not send delta requests if not supported by server', function()
+ exec_lua([[
+ local legend, response, edit_response = ...
+ server2 = _create_server({
+ capabilities = {
+ semanticTokensProvider = {
+ full = { delta = false },
+ legend = vim.fn.json_decode(legend),
+ },
+ },
+ handlers = {
+ ['textDocument/semanticTokens/full'] = function()
+ return vim.fn.json_decode(response)
+ end,
+ ['textDocument/semanticTokens/full/delta'] = function()
+ return vim.fn.json_decode(edit_response)
+ end,
+ }
+ })
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server2.cmd })
+ ]], legend, response, edit_response)
+
+ insert(text)
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ int {7:x}; |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]] }
+ feed_command('%s/int x/int x()/')
+ feed_command('noh')
+
+ -- the highlights don't change because our fake server sent the exact
+ -- same result for the same method (the full request). "x" would have
+ -- changed to highlight index 3 had we sent a delta request
+ screen:expect { grid = [[
+ #include <iostream> |
+ |
+ int {8:main}() |
+ { |
+ ^int {7:x}(); |
+ #ifdef {5:__cplusplus} |
+ {4:std}::{2:cout} << {2:x} << "\n"; |
+ {6:#else} |
+ {6: printf("%d\n", x);} |
+ {6:#endif} |
+ } |
+ } |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :noh |
+ ]] }
+ local messages = exec_lua('return server2.messages')
+ local token_request_count = 0
+ for _, message in ipairs(messages) do
+ assert(message.method ~= 'textDocument/semanticTokens/full/delta', 'delta request received')
+ if message.method == 'textDocument/semanticTokens/full' then
+ token_request_count = token_request_count + 1
+ end
+ end
+ eq(2, token_request_count)
+ end)
+ end)
+
+ describe('token array decoding', function()
+ for _, test in ipairs({
+ {
+ it = 'clangd-15 on C',
+ text = [[char* foo = "\n";]],
+ response = [[{"data": [0, 6, 3, 0, 8193], "resultId": "1"}]],
+ legend = [[{
+ "tokenTypes": [
+ "variable", "variable", "parameter", "function", "method", "function", "property", "variable", "class", "interface", "enum", "enumMember", "type", "type", "unknown", "namespace", "typeParameter", "concept", "type", "macro", "comment"
+ ],
+ "tokenModifiers": [
+ "declaration", "deprecated", "deduced", "readonly", "static", "abstract", "virtual", "dependentName", "defaultLibrary", "usedAsMutableReference", "functionScope", "classScope", "fileScope", "globalScope"
+ ]
+ }]],
+ expected = {
+ {
+ line = 0,
+ modifiers = {
+ 'declaration',
+ 'globalScope',
+ },
+ start_col = 6,
+ end_col = 9,
+ type = 'variable',
+ extmark_added = true,
+ },
+ },
+ },
+ {
+ it = 'clangd-15 on C++',
+ text = [[#include <iostream>
+int main()
+{
+ #ifdef __cplusplus
+ const int x = 1;
+ std::cout << x << std::endl;
+ #else
+ comment
+ #endif
+}]],
+ response = [[{"data": [1, 4, 4, 3, 8193, 2, 9, 11, 19, 8192, 1, 12, 1, 1, 1033, 1, 2, 3, 15, 8448, 0, 5, 4, 0, 8448, 0, 8, 1, 1, 1032, 0, 5, 3, 15, 8448, 0, 5, 4, 3, 8448, 1, 0, 7, 20, 0, 1, 0, 11, 20, 0, 1, 0, 8, 20, 0], "resultId": "1"}]],
+ legend = [[{
+ "tokenTypes": [
+ "variable", "variable", "parameter", "function", "method", "function", "property", "variable", "class", "interface", "enum", "enumMember", "type", "type", "unknown", "namespace", "typeParameter", "concept", "type", "macro", "comment"
+ ],
+ "tokenModifiers": [
+ "declaration", "deprecated", "deduced", "readonly", "static", "abstract", "virtual", "dependentName", "defaultLibrary", "usedAsMutableReference", "functionScope", "classScope", "fileScope", "globalScope"
+ ]
+ }]],
+ expected = {
+ { -- main
+ line = 1,
+ modifiers = { 'declaration', 'globalScope' },
+ start_col = 4,
+ end_col = 8,
+ type = 'function',
+ extmark_added = true,
+ },
+ { -- __cplusplus
+ line = 3,
+ modifiers = { 'globalScope' },
+ start_col = 9,
+ end_col = 20,
+ type = 'macro',
+ extmark_added = true,
+ },
+ { -- x
+ line = 4,
+ modifiers = { 'declaration', 'readonly', 'functionScope' },
+ start_col = 12,
+ end_col = 13,
+ type = 'variable',
+ extmark_added = true,
+ },
+ { -- std
+ line = 5,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ start_col = 2,
+ end_col = 5,
+ type = 'namespace',
+ extmark_added = true,
+ },
+ { -- cout
+ line = 5,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ start_col = 7,
+ end_col = 11,
+ type = 'variable',
+ extmark_added = true,
+ },
+ { -- x
+ line = 5,
+ modifiers = { 'readonly', 'functionScope' },
+ start_col = 15,
+ end_col = 16,
+ type = 'variable',
+ extmark_added = true,
+ },
+ { -- std
+ line = 5,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ start_col = 20,
+ end_col = 23,
+ type = 'namespace',
+ extmark_added = true,
+ },
+ { -- endl
+ line = 5,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ start_col = 25,
+ end_col = 29,
+ type = 'function',
+ extmark_added = true,
+ },
+ { -- #else comment #endif
+ line = 6,
+ modifiers = {},
+ start_col = 0,
+ end_col = 7,
+ type = 'comment',
+ extmark_added = true,
+ },
+ {
+ line = 7,
+ modifiers = {},
+ start_col = 0,
+ end_col = 11,
+ type = 'comment',
+ extmark_added = true,
+ },
+ {
+ line = 8,
+ modifiers = {},
+ start_col = 0,
+ end_col = 8,
+ type = 'comment',
+ extmark_added = true,
+ },
+ },
+ },
+ {
+ it = 'sumneko_lua',
+ text = [[-- comment
+local a = 1
+b = "as"]],
+ response = [[{"data": [0, 0, 10, 17, 0, 1, 6, 1, 8, 1, 1, 0, 1, 8, 8]}]],
+ legend = [[{
+ "tokenTypes": [
+ "namespace", "type", "class", "enum", "interface", "struct", "typeParameter", "parameter", "variable", "property", "enumMember", "event", "function", "method", "macro", "keyword", "modifier", "comment", "string", "number", "regexp", "operator"
+ ],
+ "tokenModifiers": [
+ "declaration", "definition", "readonly", "static", "deprecated", "abstract", "async", "modification", "documentation", "defaultLibrary"
+ ]
+ }]],
+ expected = {
+ {
+ line = 0,
+ modifiers = {},
+ start_col = 0,
+ end_col = 10,
+ type = 'comment', -- comment
+ extmark_added = true,
+ },
+ {
+ line = 1,
+ modifiers = { 'declaration' }, -- a
+ start_col = 6,
+ end_col = 7,
+ type = 'variable',
+ extmark_added = true,
+ },
+ {
+ line = 2,
+ modifiers = { 'static' }, -- b (global)
+ start_col = 0,
+ end_col = 1,
+ type = 'variable',
+ extmark_added = true,
+ },
+ },
+ },
+ {
+ it = 'rust-analyzer',
+ text = [[pub fn main() {
+ break rust;
+ /// what?
+}
+]],
+ response = [[{"data": [0, 0, 3, 1, 0, 0, 4, 2, 1, 0, 0, 3, 4, 14, 524290, 0, 4, 1, 45, 0, 0, 1, 1, 45, 0, 0, 2, 1, 26, 0, 1, 4, 5, 1, 8192, 0, 6, 4, 52, 0, 0, 4, 1, 48, 0, 1, 4, 9, 0, 1, 1, 0, 1, 26, 0], "resultId": "1"}]],
+ legend = [[{
+ "tokenTypes": [
+ "comment", "keyword", "string", "number", "regexp", "operator", "namespace", "type", "struct", "class", "interface", "enum", "enumMember", "typeParameter", "function", "method", "property", "macro", "variable",
+ "parameter", "angle", "arithmetic", "attribute", "attributeBracket", "bitwise", "boolean", "brace", "bracket", "builtinAttribute", "builtinType", "character", "colon", "comma", "comparison", "constParameter", "derive",
+ "dot", "escapeSequence", "formatSpecifier", "generic", "label", "lifetime", "logical", "macroBang", "operator", "parenthesis", "punctuation", "selfKeyword", "semicolon", "typeAlias", "toolModule", "union", "unresolvedReference"
+ ],
+ "tokenModifiers": [
+ "documentation", "declaration", "definition", "static", "abstract", "deprecated", "readonly", "defaultLibrary", "async", "attribute", "callable", "constant", "consuming", "controlFlow", "crateRoot", "injected", "intraDocLink",
+ "library", "mutable", "public", "reference", "trait", "unsafe"
+ ]
+ }]],
+ expected = {
+ {
+ line = 0,
+ modifiers = {},
+ start_col = 0,
+ end_col = 3, -- pub
+ type = 'keyword',
+ extmark_added = true,
+ },
+ {
+ line = 0,
+ modifiers = {},
+ start_col = 4,
+ end_col = 6, -- fn
+ type = 'keyword',
+ extmark_added = true,
+ },
+ {
+ line = 0,
+ modifiers = { 'declaration', 'public' },
+ start_col = 7,
+ end_col = 11, -- main
+ type = 'function',
+ extmark_added = true,
+ },
+ {
+ line = 0,
+ modifiers = {},
+ start_col = 11,
+ end_col = 12,
+ type = 'parenthesis',
+ extmark_added = true,
+ },
+ {
+ line = 0,
+ modifiers = {},
+ start_col = 12,
+ end_col = 13,
+ type = 'parenthesis',
+ extmark_added = true,
+ },
+ {
+ line = 0,
+ modifiers = {},
+ start_col = 14,
+ end_col = 15,
+ type = 'brace',
+ extmark_added = true,
+ },
+ {
+ line = 1,
+ modifiers = { 'controlFlow' },
+ start_col = 4,
+ end_col = 9, -- break
+ type = 'keyword',
+ extmark_added = true,
+ },
+ {
+ line = 1,
+ modifiers = {},
+ start_col = 10,
+ end_col = 13, -- rust
+ type = 'unresolvedReference',
+ extmark_added = true,
+ },
+ {
+ line = 1,
+ modifiers = {},
+ start_col = 13,
+ end_col = 13,
+ type = 'semicolon',
+ extmark_added = true,
+ },
+ {
+ line = 2,
+ modifiers = { 'documentation' },
+ start_col = 4,
+ end_col = 11,
+ type = 'comment', -- /// what?
+ extmark_added = true,
+ },
+ {
+ line = 3,
+ modifiers = {},
+ start_col = 0,
+ end_col = 1,
+ type = 'brace',
+ extmark_added = true,
+ },
+ },
+ },
+ }) do
+ it(test.it, function()
+ exec_lua(create_server_definition)
+ exec_lua([[
+ local legend, resp = ...
+ server = _create_server({
+ capabilities = {
+ semanticTokensProvider = {
+ full = { delta = false },
+ legend = vim.fn.json_decode(legend),
+ },
+ },
+ handlers = {
+ ['textDocument/semanticTokens/full'] = function()
+ return vim.fn.json_decode(resp)
+ end,
+ }
+ })
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ ]], test.legend, test.response)
+
+ insert(test.text)
+
+ local highlights = exec_lua([[
+ local semantic_tokens = vim.lsp.semantic_tokens
+ return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ ]])
+ eq(test.expected, highlights)
+ end)
+ end
+ end)
+
+ describe('token decoding with deltas', function()
+ for _, test in ipairs({
+ {
+ it = 'semantic_tokens_delta: clangd-15 on C',
+ legend = [[{
+ "tokenTypes": [
+ "variable", "variable", "parameter", "function", "method", "function", "property", "variable", "class", "interface", "enum", "enumMember", "type", "type", "unknown", "namespace", "typeParameter", "concept", "type", "macro", "comment"
+ ],
+ "tokenModifiers": [
+ "declaration", "deprecated", "deduced", "readonly", "static", "abstract", "virtual", "dependentName", "defaultLibrary", "usedAsMutableReference", "functionScope", "classScope", "fileScope", "globalScope"
+ ]
+ }]],
+ text1 = [[char* foo = "\n";]],
+ edit = [[ggO<Esc>]],
+ response1 = [[{"data": [0, 6, 3, 0, 8193], "resultId": "1"}]],
+ response2 = [[{"edits": [{ "start": 0, "deleteCount": 1, "data": [1] }], "resultId": "2"}]],
+ expected1 = {
+ {
+ line = 0,
+ modifiers = {
+ 'declaration',
+ 'globalScope',
+ },
+ start_col = 6,
+ end_col = 9,
+ type = 'variable',
+ extmark_added = true,
+ }
+ },
+ expected2 = {
+ {
+ line = 1,
+ modifiers = {
+ 'declaration',
+ 'globalScope',
+ },
+ start_col = 6,
+ end_col = 9,
+ type = 'variable',
+ extmark_added = true,
+ }
+ },
+ },
+ {
+ it = 'response with multiple delta edits',
+ legend = [[{
+ "tokenTypes": [
+ "variable", "variable", "parameter", "function", "method", "function", "property", "variable", "class", "interface", "enum", "enumMember", "type", "type", "unknown", "namespace", "typeParameter", "concept", "type", "macro", "comment"
+ ],
+ "tokenModifiers": [
+ "declaration", "deprecated", "deduced", "readonly", "static", "abstract", "virtual", "dependentName", "defaultLibrary", "usedAsMutableReference", "functionScope", "classScope", "fileScope", "globalScope"
+ ]
+ }]],
+ text1 = dedent([[
+ #include <iostream>
+
+ int main()
+ {
+ int x;
+ #ifdef __cplusplus
+ std::cout << x << "\n";
+ #else
+ printf("%d\n", x);
+ #endif
+ }]]),
+ text2 = [[#include <iostream>
+
+int main()
+{
+ int x();
+ double y;
+#ifdef __cplusplus
+ std::cout << x << "\n";
+#else
+ printf("%d\n", x);
+#endif
+}]],
+ response1 = [[{
+ "data": [ 2, 4, 4, 3, 8193, 2, 8, 1, 1, 1025, 1, 7, 11, 19, 8192, 1, 4, 3, 15, 8448, 0, 5, 4, 0, 8448, 0, 8, 1, 1, 1024, 1, 0, 5, 20, 0, 1, 0, 22, 20, 0, 1, 0, 6, 20, 0 ],
+ "resultId": 1
+ }]],
+ response2 = [[{
+ "edits": [ {"data": [ 2, 8, 1, 3, 8193, 1, 11, 1, 1, 1025 ], "deleteCount": 5, "start": 5}, {"data": [ 0, 8, 1, 3, 8192 ], "deleteCount": 5, "start": 25 } ],
+ "resultId":"2"
+ }]],
+ expected1 = {
+ {
+ line = 2,
+ start_col = 4,
+ end_col = 8,
+ modifiers = { 'declaration', 'globalScope' },
+ type = 'function',
+ extmark_added = true,
+ },
+ {
+ line = 4,
+ start_col = 8,
+ end_col = 9,
+ modifiers = { 'declaration', 'functionScope' },
+ type = 'variable',
+ extmark_added = true,
+ },
+ {
+ line = 5,
+ start_col = 7,
+ end_col = 18,
+ modifiers = { 'globalScope' },
+ type = 'macro',
+ extmark_added = true,
+ },
+ {
+ line = 6,
+ start_col = 4,
+ end_col = 7,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ type = 'namespace',
+ extmark_added = true,
+ },
+ {
+ line = 6,
+ start_col = 9,
+ end_col = 13,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ type = 'variable',
+ extmark_added = true,
+ },
+ {
+ line = 6,
+ start_col = 17,
+ end_col = 18,
+ extmark_added = true,
+ modifiers = { 'functionScope' },
+ type = 'variable',
+ },
+ {
+ line = 7,
+ start_col = 0,
+ end_col = 5,
+ extmark_added = true,
+ modifiers = {},
+ type = 'comment',
+ },
+ {
+ line = 8,
+ end_col = 22,
+ modifiers = {},
+ start_col = 0,
+ type = 'comment',
+ extmark_added = true,
+ },
+ {
+ line = 9,
+ start_col = 0,
+ end_col = 6,
+ modifiers = {},
+ type = 'comment',
+ extmark_added = true,
+ }
+ },
+ expected2 = {
+ {
+ line = 2,
+ start_col = 4,
+ end_col = 8,
+ modifiers = { 'declaration', 'globalScope' },
+ type = 'function',
+ extmark_added = true,
+ },
+ {
+ line = 4,
+ start_col = 8,
+ end_col = 9,
+ modifiers = { 'declaration', 'globalScope' },
+ type = 'function',
+ extmark_added = true,
+ },
+ {
+ line = 5,
+ end_col = 12,
+ start_col = 11,
+ modifiers = { 'declaration', 'functionScope' },
+ type = 'variable',
+ extmark_added = true,
+ },
+ {
+ line = 6,
+ start_col = 7,
+ end_col = 18,
+ modifiers = { 'globalScope' },
+ type = 'macro',
+ extmark_added = true,
+ },
+ {
+ line = 7,
+ start_col = 4,
+ end_col = 7,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ type = 'namespace',
+ extmark_added = true,
+ },
+ {
+ line = 7,
+ start_col = 9,
+ end_col = 13,
+ modifiers = { 'defaultLibrary', 'globalScope' },
+ type = 'variable',
+ extmark_added = true,
+ },
+ {
+ line = 7,
+ start_col = 17,
+ end_col = 18,
+ extmark_added = true,
+ modifiers = { 'globalScope' },
+ type = 'function',
+ },
+ {
+ line = 8,
+ start_col = 0,
+ end_col = 5,
+ extmark_added = true,
+ modifiers = {},
+ type = 'comment',
+ },
+ {
+ line = 9,
+ end_col = 22,
+ modifiers = {},
+ start_col = 0,
+ type = 'comment',
+ extmark_added = true,
+ },
+ {
+ line = 10,
+ start_col = 0,
+ end_col = 6,
+ modifiers = {},
+ type = 'comment',
+ extmark_added = true,
+ }
+ },
+ },
+ {
+ it = 'optional token_edit.data on deletion',
+ legend = [[{
+ "tokenTypes": [
+ "comment", "keyword", "operator", "string", "number", "regexp", "type", "class", "interface", "enum", "enumMember", "typeParameter", "function", "method", "property", "variable", "parameter", "module", "intrinsic", "selfParameter", "clsParameter", "magicFunction", "builtinConstant", "parenthesis", "curlybrace", "bracket", "colon", "semicolon", "arrow"
+ ],
+ "tokenModifiers": [
+ "declaration", "static", "abstract", "async", "documentation", "typeHint", "typeHintComment", "readonly", "decorator", "builtin"
+ ]
+ }]],
+ text1 = [[string = "test"]],
+ text2 = [[]],
+ response1 = [[{"data": [0, 0, 6, 15, 1], "resultId": "1"}]],
+ response2 = [[{"edits": [{ "start": 0, "deleteCount": 5 }], "resultId": "2"}]],
+ expected1 = {
+ {
+ line = 0,
+ modifiers = {
+ 'declaration',
+ },
+ start_col = 0,
+ end_col = 6,
+ type = 'variable',
+ extmark_added = true,
+ }
+ },
+ expected2 = {
+ },
+ },
+ }) do
+ it(test.it, function()
+ exec_lua(create_server_definition)
+ exec_lua([[
+ local legend, resp1, resp2 = ...
+ server = _create_server({
+ capabilities = {
+ semanticTokensProvider = {
+ full = { delta = true },
+ legend = vim.fn.json_decode(legend),
+ },
+ },
+ handlers = {
+ ['textDocument/semanticTokens/full'] = function()
+ return vim.fn.json_decode(resp1)
+ end,
+ ['textDocument/semanticTokens/full/delta'] = function()
+ return vim.fn.json_decode(resp2)
+ end,
+ }
+ })
+ bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+
+ -- speed up vim.api.nvim_buf_set_lines calls by changing debounce to 10 for these tests
+ semantic_tokens = vim.lsp.semantic_tokens
+ vim.schedule(function()
+ semantic_tokens.stop(bufnr, client_id)
+ semantic_tokens.start(bufnr, client_id, { debounce = 10 })
+ end)
+ ]], test.legend, test.response1, test.response2)
+
+ insert(test.text1)
+
+ local highlights = exec_lua([[
+ return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ ]])
+
+ eq(test.expected1, highlights)
+
+ if test.edit then
+ feed(test.edit)
+ else
+ exec_lua([[
+ local text = ...
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n"))
+ vim.wait(15) -- wait fot debounce
+ ]], test.text2)
+ end
+
+ highlights = exec_lua([[
+ return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ ]])
+
+ eq(test.expected2, highlights)
+ end)
+ end
+ end)
+end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index cd7415de90..5229022564 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -1,8 +1,9 @@
local helpers = require('test.functional.helpers')(after_each)
+local lsp_helpers = require('test.functional.plugin.lsp.helpers')
local assert_log = helpers.assert_log
-local clear = helpers.clear
local buf_lines = helpers.buf_lines
+local clear = helpers.clear
local command = helpers.command
local dedent = helpers.dedent
local exec_lua = helpers.exec_lua
@@ -14,133 +15,28 @@ local pesc = helpers.pesc
local insert = helpers.insert
local funcs = helpers.funcs
local retry = helpers.retry
+local stop = helpers.stop
local NIL = helpers.NIL
local read_file = require('test.helpers').read_file
local write_file = require('test.helpers').write_file
-local isCI = helpers.isCI
+local is_ci = helpers.is_ci
local meths = helpers.meths
+local is_os = helpers.is_os
+local skip = helpers.skip
--- Use these to get access to a coroutine so that I can run async tests and use
--- yield.
-local run, stop = helpers.run, helpers.stop
+local clear_notrace = lsp_helpers.clear_notrace
+local create_server_definition = lsp_helpers.create_server_definition
+local fake_lsp_code = lsp_helpers.fake_lsp_code
+local fake_lsp_logfile = lsp_helpers.fake_lsp_logfile
+local test_rpc_server = lsp_helpers.test_rpc_server
-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
-if helpers.pending_win32(pending) then return end
-
--- Fake LSP server.
-local fake_lsp_code = 'test/functional/fixtures/fake-lsp-server.lua'
-local fake_lsp_logfile = 'Xtest-fake-lsp.log'
+if skip(is_os('win')) then return end
teardown(function()
os.remove(fake_lsp_logfile)
end)
-local function clear_notrace()
- -- problem: here be dragons
- -- solution: don't look for dragons to closely
- clear {env={
- NVIM_LUA_NOTRACK="1";
- VIMRUNTIME=os.getenv"VIMRUNTIME";
- }}
-end
-
-
-local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
- exec_lua([=[
- lsp = require('vim.lsp')
- local test_name, fixture_filename, logfile, timeout, options, settings = ...
- TEST_RPC_CLIENT_ID = lsp.start_client {
- cmd_env = {
- NVIM_LOG_FILE = logfile;
- NVIM_LUA_NOTRACK = "1";
- };
- cmd = {
- vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
- "-c", string.format("lua TEST_NAME = %q", test_name),
- "-c", string.format("lua TIMEOUT = %d", timeout),
- "-c", "luafile "..fixture_filename,
- };
- handlers = setmetatable({}, {
- __index = function(t, method)
- return function(...)
- return vim.rpcrequest(1, 'handler', ...)
- end
- end;
- });
- workspace_folders = {{
- uri = 'file://' .. vim.loop.cwd(),
- name = 'test_folder',
- }};
- on_init = function(client, result)
- TEST_RPC_CLIENT = client
- vim.rpcrequest(1, "init", result)
- end;
- flags = {
- allow_incremental_sync = options.allow_incremental_sync or false;
- debounce_text_changes = options.debounce_text_changes or 0;
- };
- settings = settings;
- on_exit = function(...)
- vim.rpcnotify(1, "exit", ...)
- end;
- }
- ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {}, settings or {})
-end
-
-local function test_rpc_server(config)
- if config.test_name then
- clear_notrace()
- fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options, config.settings)
- end
- local client = setmetatable({}, {
- __index = function(_, name)
- -- Workaround for not being able to yield() inside __index for Lua 5.1 :(
- -- Otherwise I would just return the value here.
- return function(...)
- return exec_lua([=[
- local name = ...
- if type(TEST_RPC_CLIENT[name]) == 'function' then
- return TEST_RPC_CLIENT[name](select(2, ...))
- else
- return TEST_RPC_CLIENT[name]
- end
- ]=], name, ...)
- end
- end;
- })
- local code, signal
- local function on_request(method, args)
- if method == "init" then
- if config.on_init then
- config.on_init(client, unpack(args))
- end
- return NIL
- end
- if method == 'handler' then
- if config.on_handler then
- config.on_handler(unpack(args))
- end
- end
- return NIL
- end
- local function on_notify(method, args)
- if method == 'exit' then
- code, signal = unpack(args)
- return stop()
- end
- end
- -- TODO specify timeout?
- -- run(on_request, on_notify, config.on_setup, 1000)
- run(on_request, on_notify, config.on_setup)
- if config.on_exit then
- config.on_exit(code, signal)
- end
- stop()
- if config.test_name then
- exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
- end
-end
-
describe('LSP', function()
before_each(function()
clear_notrace()
@@ -236,9 +132,9 @@ describe('LSP', function()
end)
it('should invalid cmd argument', function()
- eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
+ eq('.../lsp.lua:0: cmd: expected list, got nvim',
pcall_err(_cmd_parts, 'nvim'))
- eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
+ eq('.../lsp.lua:0: cmd argument: expected string, got number',
pcall_err(_cmd_parts, {'nvim', 1}))
end)
end)
@@ -316,7 +212,7 @@ describe('LSP', function()
end)
it('should succeed with manual shutdown', function()
- if isCI() then
+ if is_ci() then
pending('hangs the build on CI #14028, re-enable with freeze timeout #14204')
return
elseif helpers.skip_fragile(pending) then
@@ -418,6 +314,31 @@ describe('LSP', function()
}
end)
+ it('should detach buffer on bufwipe', function()
+ clear()
+ exec_lua(create_server_definition)
+ local result = exec_lua([[
+ local server = _create_server()
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server.cmd })
+ assert(client_id, "lsp.start must return client_id")
+ local client = vim.lsp.get_client_by_id(client_id)
+ local num_attached_before = vim.tbl_count(client.attached_buffers)
+ vim.api.nvim_buf_delete(bufnr, { force = true })
+ local num_attached_after = vim.tbl_count(client.attached_buffers)
+ return {
+ bufnr = bufnr,
+ client_id = client_id,
+ num_attached_before = num_attached_before,
+ num_attached_after = num_attached_after,
+ }
+ ]])
+ eq(true, result ~= nil, "exec_lua must return result")
+ eq(1, result.num_attached_before)
+ eq(0, result.num_attached_after)
+ end)
+
it('client should return settings via workspace/configuration handler', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
@@ -535,6 +456,70 @@ describe('LSP', function()
}
end)
+ it('BufWritePre does not send notifications if server lacks willSave capabilities', function()
+ clear()
+ exec_lua(create_server_definition)
+ local messages = exec_lua([[
+ local server = _create_server({
+ capabilities = {
+ textDocumentSync = {
+ willSave = false,
+ willSaveWaitUntil = false,
+ }
+ },
+ })
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local buf = vim.api.nvim_get_current_buf()
+ vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false })
+ vim.lsp.stop_client(client_id)
+ return server.messages
+ ]])
+ eq(#messages, 4)
+ eq(messages[1].method, 'initialize')
+ eq(messages[2].method, 'initialized')
+ eq(messages[3].method, 'shutdown')
+ eq(messages[4].method, 'exit')
+ end)
+
+ it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function()
+ clear()
+ exec_lua(create_server_definition)
+ local result = exec_lua([[
+ local server = _create_server({
+ capabilities = {
+ textDocumentSync = {
+ willSave = true,
+ willSaveWaitUntil = true,
+ }
+ },
+ handlers = {
+ ['textDocument/willSaveWaitUntil'] = function()
+ local text_edit = {
+ range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ },
+ newText = 'Hello'
+ }
+ return { text_edit, }
+ end
+ },
+ })
+ local buf = vim.api.nvim_get_current_buf()
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ vim.api.nvim_exec_autocmds('BufWritePre', { buffer = buf, modeline = false })
+ vim.lsp.stop_client(client_id)
+ return {
+ messages = server.messages,
+ lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true)
+ }
+ ]])
+ local messages = result.messages
+ eq('textDocument/willSave', messages[3].method)
+ eq('textDocument/willSaveWaitUntil', messages[4].method)
+ eq({'Hello'}, result.lines)
+ end)
+
it('saveas sends didOpen if filename changed', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -1682,6 +1667,46 @@ describe('LSP', function()
end)
end)
+ describe('apply_text_edits regression tests for #20116', function()
+ before_each(function()
+ insert(dedent([[
+ Test line one
+ Test line two 21 char]]))
+ end)
+ describe('with LSP end column out of bounds and start column at 0', function()
+ it('applies edits at the end of the buffer', function()
+ local edits = {
+ make_edit(0, 0, 1, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'});
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8")
+ eq({'#include "whatever.h"', '#include <algorithm>'}, buf_lines(1))
+ end)
+ it('applies edits in the middle of the buffer', function()
+ local edits = {
+ make_edit(0, 0, 0, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'});
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8")
+ eq({'#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char'}, buf_lines(1))
+ end)
+ end)
+ describe('with LSP end column out of bounds and start column NOT at 0', function()
+ it('applies edits at the end of the buffer', function()
+ local edits = {
+ make_edit(0, 2, 1, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'});
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8")
+ eq({'Te#include "whatever.h"', '#include <algorithm>'}, buf_lines(1))
+ end)
+ it('applies edits in the middle of the buffer', function()
+ local edits = {
+ make_edit(0, 2, 0, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'});
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8")
+ eq({'Te#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char'}, buf_lines(1))
+ end)
+ end)
+ end)
+
describe('apply_text_document_edit', function()
local target_bufnr
local text_document_edit = function(editVersion)
@@ -1900,6 +1925,22 @@ describe('LSP', function()
exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
end)
+ it('Supports file creation in folder that needs to be created with CreateFile payload', function()
+ local tmpfile = helpers.tmpname()
+ os.remove(tmpfile) -- Should not exist, only interested in a tmpname
+ tmpfile = tmpfile .. '/dummy/x/'
+ local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
+ local edit = {
+ documentChanges = {
+ {
+ kind = 'create',
+ uri = uri,
+ },
+ }
+ }
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
+ end)
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
local tmpfile = helpers.tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2377,7 +2418,7 @@ describe('LSP', function()
},
uri = "file:///test_a"
},
- contanerName = "TestAContainer"
+ containerName = "TestAContainer"
},
{
deprecated = false,
@@ -2396,7 +2437,7 @@ describe('LSP', function()
},
uri = "file:///test_b"
},
- contanerName = "TestBContainer"
+ containerName = "TestBContainer"
}
}
return vim.lsp.util.symbols_to_items(sym_info, nil)
@@ -2493,7 +2534,7 @@ describe('LSP', function()
local mark = funcs.nvim_buf_get_mark(target_bufnr, "'")
eq({ 1, 0 }, mark)
- funcs.nvim_win_set_cursor(0, {2, 3})
+ funcs.nvim_win_set_cursor(0, { 2, 3 })
jump(location(0, 9, 0, 9))
mark = funcs.nvim_buf_get_mark(target_bufnr, "'")
@@ -2501,6 +2542,193 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.show_document', function()
+ local target_bufnr
+ local target_bufnr2
+
+ before_each(function()
+ target_bufnr = exec_lua([[
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
+ return bufnr
+ ]])
+
+ target_bufnr2 = exec_lua([[
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri2")
+ local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
+ return bufnr
+ ]])
+ end)
+
+ local location = function(start_line, start_char, end_line, end_char, second_uri)
+ return {
+ uri = second_uri and 'file:///fake/uri2' or 'file:///fake/uri',
+ range = {
+ start = { line = start_line, character = start_char },
+ ['end'] = { line = end_line, character = end_char },
+ },
+ }
+ end
+
+ local show_document = function(msg, focus, reuse_win)
+ eq(
+ true,
+ exec_lua(
+ 'return vim.lsp.util.show_document(...)',
+ msg,
+ 'utf-16',
+ { reuse_win = reuse_win, focus = focus }
+ )
+ )
+ if focus == true or focus == nil then
+ eq(target_bufnr, exec_lua([[return vim.fn.bufnr('%')]]))
+ end
+ return {
+ line = exec_lua([[return vim.fn.line('.')]]),
+ col = exec_lua([[return vim.fn.col('.')]]),
+ }
+ end
+
+ it('jumps to a Location if focus is true', function()
+ local pos = show_document(location(0, 9, 0, 9), true, true)
+ eq(1, pos.line)
+ eq(10, pos.col)
+ end)
+
+ it('jumps to a Location if focus is true via handler', function()
+ exec_lua(create_server_definition)
+ local result = exec_lua([[
+ local server = _create_server()
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local result = {
+ uri = 'file:///fake/uri',
+ selection = {
+ start = { line = 0, character = 9 },
+ ['end'] = { line = 0, character = 9 }
+ },
+ takeFocus = true,
+ }
+ local ctx = {
+ client_id = client_id,
+ method = 'window/showDocument',
+ }
+ vim.lsp.handlers['window/showDocument'](nil, result, ctx)
+ vim.lsp.stop_client(client_id)
+ return {
+ cursor = vim.api.nvim_win_get_cursor(0)
+ }
+ ]])
+ eq(1, result.cursor[1])
+ eq(9, result.cursor[2])
+ end)
+
+ it('jumps to a Location if focus not set', function()
+ local pos = show_document(location(0, 9, 0, 9), nil, true)
+ eq(1, pos.line)
+ eq(10, pos.col)
+ end)
+
+ it('does not add current position to jumplist if not focus', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+ local mark = funcs.nvim_buf_get_mark(target_bufnr, "'")
+ eq({ 1, 0 }, mark)
+
+ funcs.nvim_win_set_cursor(0, { 2, 3 })
+ show_document(location(0, 9, 0, 9), false, true)
+ show_document(location(0, 9, 0, 9, true), false, true)
+
+ mark = funcs.nvim_buf_get_mark(target_bufnr, "'")
+ eq({ 1, 0 }, mark)
+ end)
+
+ it('does not change cursor position if not focus and not reuse_win', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+ local cursor = funcs.nvim_win_get_cursor(0)
+
+ show_document(location(0, 9, 0, 9), false, false)
+ eq(cursor, funcs.nvim_win_get_cursor(0))
+ end)
+
+ it('does not change window if not focus', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+ local win = funcs.nvim_get_current_win()
+
+ -- same document/bufnr
+ show_document(location(0, 9, 0, 9), false, true)
+ eq(win, funcs.nvim_get_current_win())
+
+ -- different document/bufnr, new window/split
+ show_document(location(0, 9, 0, 9, true), false, true)
+ eq(2, #funcs.nvim_list_wins())
+ eq(win, funcs.nvim_get_current_win())
+ end)
+
+ it("respects 'reuse_win' parameter", function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+
+ -- does not create a new window if the buffer is already open
+ show_document(location(0, 9, 0, 9), false, true)
+ eq(1, #funcs.nvim_list_wins())
+
+ -- creates a new window even if the buffer is already open
+ show_document(location(0, 9, 0, 9), false, false)
+ eq(2, #funcs.nvim_list_wins())
+ end)
+
+ it('correctly sets the cursor of the split if range is given without focus', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+
+ show_document(location(0, 9, 0, 9, true), false, true)
+
+ local wins = funcs.nvim_list_wins()
+ eq(2, #wins)
+ table.sort(wins)
+
+ eq({ 1, 0 }, funcs.nvim_win_get_cursor(wins[1]))
+ eq({ 1, 9 }, funcs.nvim_win_get_cursor(wins[2]))
+ end)
+
+ it('does not change cursor of the split if not range and not focus', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+ funcs.nvim_win_set_cursor(0, { 2, 3 })
+
+ exec_lua([[vim.cmd.new()]])
+ funcs.nvim_win_set_buf(0, target_bufnr2)
+ funcs.nvim_win_set_cursor(0, { 2, 3 })
+
+ show_document({ uri = 'file:///fake/uri2' }, false, true)
+
+ local wins = funcs.nvim_list_wins()
+ eq(2, #wins)
+ eq({ 2, 3 }, funcs.nvim_win_get_cursor(wins[1]))
+ eq({ 2, 3 }, funcs.nvim_win_get_cursor(wins[2]))
+ end)
+
+ it('respects existing buffers', function()
+ funcs.nvim_win_set_buf(0, target_bufnr)
+ local win = funcs.nvim_get_current_win()
+
+ exec_lua([[vim.cmd.new()]])
+ funcs.nvim_win_set_buf(0, target_bufnr2)
+ funcs.nvim_win_set_cursor(0, { 2, 3 })
+ local split = funcs.nvim_get_current_win()
+
+ -- reuse win for open document/bufnr if called from split
+ show_document(location(0, 9, 0, 9, true), false, true)
+ eq({ 1, 9 }, funcs.nvim_win_get_cursor(split))
+ eq(2, #funcs.nvim_list_wins())
+
+ funcs.nvim_set_current_win(win)
+
+ -- reuse win for open document/bufnr if called outside the split
+ show_document(location(0, 9, 0, 9, true), false, true)
+ eq({ 1, 9 }, funcs.nvim_win_get_cursor(split))
+ eq(2, #funcs.nvim_list_wins())
+ end)
+ end)
+
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
exec_lua [[ contents =
@@ -3180,5 +3408,159 @@ describe('LSP', function()
end,
}
end)
+ it('format formats range in visual mode', function()
+ exec_lua(create_server_definition)
+ local result = exec_lua([[
+ local server = _create_server({ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = true,
+ }})
+ local bufnr = vim.api.nvim_get_current_buf()
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ vim.api.nvim_win_set_buf(0, bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar'})
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.cmd.normal('v')
+ vim.api.nvim_win_set_cursor(0, { 2, 3 })
+ vim.lsp.buf.format({ bufnr = bufnr, false })
+ return server.messages
+ ]])
+ eq("textDocument/rangeFormatting", result[3].method)
+ local expected_range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 1, character = 4 },
+ }
+ eq(expected_range, result[3].params.range)
+ end)
+ it('Aborts with notify if no clients support requested method', function()
+ exec_lua(create_server_definition)
+ exec_lua([[
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ ]])
+ local fail_msg = "[LSP] Format request failed, no matching language servers."
+ local function check_notify(name, formatting, range_formatting)
+ local timeout_msg = "[LSP][" .. name .. "] timeout"
+ exec_lua([[
+ local formatting, range_formatting, name = ...
+ local server = _create_server({ capabilities = {
+ documentFormattingProvider = formatting,
+ documentRangeFormattingProvider = range_formatting,
+ }})
+ vim.lsp.start({ name = name, cmd = server.cmd })
+ notify_msg = nil
+ vim.lsp.buf.format({ name = name, timeout_ms = 1 })
+ ]], formatting, range_formatting, name)
+ eq(formatting and timeout_msg or fail_msg, exec_lua('return notify_msg'))
+ exec_lua([[
+ notify_msg = nil
+ vim.lsp.buf.format({ name = name, timeout_ms = 1, range = {start={1, 0}, ['end']={1, 0}}})
+ ]])
+ eq(range_formatting and timeout_msg or fail_msg, exec_lua('return notify_msg'))
+ end
+ check_notify("none", false, false)
+ check_notify("formatting", true, false)
+ check_notify("rangeFormatting", false, true)
+ check_notify("both", true, true)
+ end)
+ end)
+ describe('cmd', function()
+ it('can connect to lsp server via rpc.connect', function()
+ local result = exec_lua [[
+ local uv = vim.loop
+ local server = uv.new_tcp()
+ local init = nil
+ server:bind('127.0.0.1', 0)
+ server:listen(127, function(err)
+ assert(not err, err)
+ local socket = uv.new_tcp()
+ server:accept(socket)
+ socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
+ init = body
+ socket:close()
+ end))
+ end)
+ local port = server:getsockname().port
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })
+ vim.wait(1000, function() return init ~= nil end)
+ assert(init, "server must receive `initialize` request")
+ server:close()
+ server:shutdown()
+ return vim.json.decode(init)
+ ]]
+ eq(result.method, "initialize")
+ end)
+ end)
+
+ describe('handlers', function()
+ it('handler can return false as response', function()
+ local result = exec_lua [[
+ local uv = vim.loop
+ local server = uv.new_tcp()
+ local messages = {}
+ local responses = {}
+ server:bind('127.0.0.1', 0)
+ server:listen(127, function(err)
+ assert(not err, err)
+ local socket = uv.new_tcp()
+ server:accept(socket)
+ socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
+ local payload = vim.json.decode(body)
+ if payload.method then
+ table.insert(messages, payload.method)
+ if payload.method == 'initialize' then
+ local msg = vim.json.encode({
+ id = payload.id,
+ jsonrpc = '2.0',
+ result = {
+ capabilities = {}
+ },
+ })
+ socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ elseif payload.method == 'initialized' then
+ local msg = vim.json.encode({
+ id = 10,
+ jsonrpc = '2.0',
+ method = 'dummy',
+ params = {},
+ })
+ socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ end
+ else
+ table.insert(responses, payload)
+ socket:close()
+ end
+ end))
+ end)
+ local port = server:getsockname().port
+ local handler_called = false
+ vim.lsp.handlers['dummy'] = function(err, result)
+ handler_called = true
+ return false
+ end
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) })
+ local client = vim.lsp.get_client_by_id(client_id)
+ vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 end)
+ server:close()
+ server:shutdown()
+ return {
+ messages = messages,
+ handler_called = handler_called,
+ responses = responses }
+ ]]
+ local expected = {
+ messages = { 'initialize', 'initialized' },
+ handler_called = true,
+ responses = {
+ {
+ id = 10,
+ jsonrpc = '2.0',
+ result = false
+ }
+ }
+ }
+ eq(expected, result)
+ end)
end)
end)
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index c8da5a711f..c6c7d2b03d 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -1,10 +1,21 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local command, eval, rawfeed = helpers.command, helpers.eval, helpers.rawfeed
+local command, rawfeed = helpers.command, helpers.rawfeed
local clear = helpers.clear
+local exec_lua = helpers.exec_lua
local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
local matches = helpers.matches
+local write_file = helpers.write_file
+local tmpname = helpers.tmpname
+local skip = helpers.skip
+local is_ci = helpers.is_ci
+
+clear()
+if funcs.executable('man') == 0 then
+ pending('missing "man" command', function() end)
+ return
+end
describe(':Man', function()
before_each(function()
@@ -44,7 +55,7 @@ describe(':Man', function()
|
]]}
- eval('man#init_pager()')
+ exec_lua[[require'man'.init_pager()]]
screen:expect([[
^this {b:is} {b:a} test |
@@ -68,7 +79,7 @@ describe(':Man', function()
|
]=]}
- eval('man#init_pager()')
+ exec_lua[[require'man'.init_pager()]]
screen:expect([[
^this {b:is }{bi:a }{biu:test} |
@@ -83,7 +94,7 @@ describe(':Man', function()
rawfeed([[
ithis i<C-v><C-h>is<C-v><C-h>s あ<C-v><C-h>あ test
with _<C-v><C-h>ö_<C-v><C-h>v_<C-v><C-h>e_<C-v><C-h>r_<C-v><C-h>s_<C-v><C-h>t_<C-v><C-h>r_<C-v><C-h>u_<C-v><C-h>̃_<C-v><C-h>c_<C-v><C-h>k te<C-v><ESC>[3mxt¶<C-v><ESC>[0m<ESC>]])
- eval('man#init_pager()')
+ exec_lua[[require'man'.init_pager()]]
screen:expect([[
^this {b:is} {b:あ} test |
@@ -99,7 +110,7 @@ describe(':Man', function()
i_<C-v><C-h>_b<C-v><C-h>be<C-v><C-h>eg<C-v><C-h>gi<C-v><C-h>in<C-v><C-h>ns<C-v><C-h>s
m<C-v><C-h>mi<C-v><C-h>id<C-v><C-h>d_<C-v><C-h>_d<C-v><C-h>dl<C-v><C-h>le<C-v><C-h>e
_<C-v><C-h>m_<C-v><C-h>i_<C-v><C-h>d_<C-v><C-h>__<C-v><C-h>d_<C-v><C-h>l_<C-v><C-h>e<ESC>]])
- eval('man#init_pager()')
+ exec_lua[[require'man'.init_pager()]]
screen:expect([[
{b:^_begins} |
@@ -115,7 +126,7 @@ describe(':Man', function()
i· ·<C-v><C-h>·
+<C-v><C-h>o
+<C-v><C-h>+<C-v><C-h>o<C-v><C-h>o double<ESC>]])
- eval('man#init_pager()')
+ exec_lua[[require'man'.init_pager()]]
screen:expect([[
^· {b:·} |
@@ -132,7 +143,7 @@ describe(':Man', function()
<C-v><C-[>[44m 4 <C-v><C-[>[45m 5 <C-v><C-[>[46m 6 <C-v><C-[>[47m 7 <C-v><C-[>[100m 8 <C-v><C-[>[101m 9
<C-v><C-[>[102m 10 <C-v><C-[>[103m 11 <C-v><C-[>[104m 12 <C-v><C-[>[105m 13 <C-v><C-[>[106m 14 <C-v><C-[>[107m 15
<C-v><C-[>[48:5:16m 16 <ESC>]])
- eval('man#init_pager()')
+ exec_lua[[require'man'.init_pager()]]
screen:expect([[
^ 0 1 2 3 |
@@ -149,4 +160,17 @@ describe(':Man', function()
local args = {nvim_prog, '--headless', '+autocmd VimLeave * echo "quit works!!"', '+Man!', '+call nvim_input("q")'}
matches('quit works!!', funcs.system(args, {'manpage contents'}))
end)
+
+ it('reports non-existent man pages for absolute paths', function()
+ skip(is_ci('cirrus'))
+ local actual_file = tmpname()
+ -- actual_file must be an absolute path to an existent file for us to test against it
+ matches('^/.+', actual_file)
+ write_file(actual_file, '')
+ local args = {nvim_prog, '--headless', '+:Man ' .. actual_file, '+q'}
+ matches(('Error detected while processing command line:\r\n' ..
+ 'man.lua: "no manual entry for %s"'):format(actual_file),
+ funcs.system(args, {''}))
+ os.remove(actual_file)
+ end)
end)
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 6f22f865e6..93cf6d2b77 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local eq, meths, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
helpers.eq, helpers.meths, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
@@ -2139,7 +2140,7 @@ end)
describe('plugin/shada.vim', function()
local epoch = os.date('%Y-%m-%dT%H:%M:%S', 0)
- local eol = helpers.iswin() and '\r\n' or '\n'
+ local eol = helpers.is_os('win') and '\r\n' or '\n'
before_each(function()
-- Note: reset() is called explicitly in each test.
os.remove(fname)
@@ -2538,13 +2539,26 @@ describe('ftplugin/shada.vim', function()
end)
describe('syntax/shada.vim', function()
- local epoch = os.date('%Y-%m-%dT%H:%M:%S', 0)
+ local epoch = os.date('!%Y-%m-%dT%H:%M:%S', 0)
before_each(reset)
it('works', function()
nvim_command('syntax on')
nvim_command('setlocal syntax=shada')
nvim_command('set laststatus&')
+ local screen = Screen.new(60, 37)
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Brown};
+ [2] = {foreground = tonumber('0x6a0dad')};
+ [3] = {foreground = Screen.colors.Fuchsia};
+ [4] = {foreground = Screen.colors.Blue1};
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen4};
+ [6] = {foreground = Screen.colors.SlateBlue};
+ [7] = {bold = true, reverse = true};
+ [8] = {bold = true, foreground = Screen.colors.Blue};
+ }
+ screen:attach()
+
curbuf('set_lines', 0, 1, true, {
'Header with timestamp ' .. epoch .. ':',
' % Key Value',
@@ -2580,6 +2594,46 @@ describe('syntax/shada.vim', function()
' % Key Description________ Value',
' + se place cursor at end TRUE',
})
+ screen:expect{grid=[=[
+ {1:^Header} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {2: % Key Value} |
+ {1: +} {3:t } {1:"}{3:test}{1:"} |
+ {1:Jump} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {2: % Key________ Description Value} |
+ {1: +} {3:n } {4:name } {3:'A'} |
+ {1: +} {3:f } {4:file name } {1:["}{3:foo}{1:"]} |
+ {1: +} {3:l } {4:line number} {3:2} |
+ {1: +} {3:c } {4:column } {3:-200} |
+ {1:Register} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {2: % Key Description Value} |
+ {1: +} {3:rc } {4:contents } {1:@} |
+ {1: | -} {1:{"}{3:abcdefghijklmnopqrstuvwxyz}{1:":} {3:1.0}{1:}} |
+ {1: +} {3:rt } {4:type } {1:CHARACTERWISE} |
+ {1: +} {3:rt } {4:type } {1:LINEWISE} |
+ {1: +} {3:rt } {4:type } {1:BLOCKWISE} |
+ {1:Replacement string} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {2: @ Description__________ Value} |
+ {1: -} {4::s replacement string} {1:CMD} |
+ {1: -} {4::s replacement string} {1:SEARCH} |
+ {1: -} {4::s replacement string} {1:EXPR} |
+ {1: -} {4::s replacement string} {1:INPUT} |
+ {1: -} {4::s replacement string} {1:DEBUG} |
+ {1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {4: # Expected array of maps} |
+ = {1:[{="}{3:a}{1:":} {1:+(}{5:10}{1:)"}{3:ac}{6:\0}{3:df}{6:\n}{3:gi}{6:\"}{3:tt\.}{1:",} {1:TRUE:} {1:FALSE},} {1:[NIL,} {1:+(}{5:-}|
+ {5:10}{1:)""]]} |
+ {1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {2: % Key Description Value} |
+ |
+ {2: % Key Description Value} |
+ {1:Header} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
+ {2: % Key Description________ Value} |
+ {1: +} {3:se } {4:place cursor at end} {1:TRUE} |
+ {8:~ }|
+ {7:[No Name] [+] }|
+ |
+ ]=]}
+
nvim_command([[
function GetSyntax()
let lines = []
@@ -2613,7 +2667,7 @@ describe('syntax/shada.vim', function()
year = htsnum(os.date('%Y', 0)),
month = htsnum(os.date('%m', 0)),
day = htsnum(os.date('%d', 0)),
- hour = htsnum(os.date('%H', 0)),
+ hour = htsnum(os.date('!%H', 0)),
minute = htsnum(os.date('%M', 0)),
second = htsnum(os.date('%S', 0)),
}
@@ -2768,9 +2822,8 @@ describe('syntax/shada.vim', function()
{{'ShaDaEntryArray', 'ShaDaMsgpackShaDaKeyword'}, 'INPUT'},
},
{
- {{'ShaDaEntryArrayEntryStart'}, ' - '},
- {{'ShaDaEntryArrayDescription'}, ':s replacement string '},
- {{'ShaDaMsgpackShaDaKeyword'}, 'DEBUG'},
+ as(), ad(':s replacement string '),
+ {{'ShaDaEntryArray', 'ShaDaMsgpackShaDaKeyword'}, 'DEBUG'},
},
{
hname('Buffer list'), h(' with timestamp '),
@@ -2872,10 +2925,10 @@ describe('syntax/shada.vim', function()
mlh(' % Key Description________ Value'),
},
{
- {{'ShaDaEntryMapLongEntryStart'}, ' + '},
- {{'ShaDaEntryMapLongKey'}, 'se '},
- {{'ShaDaEntryMapLongDescription'}, 'place cursor at end '},
- {{'ShaDaMsgpackKeyword'}, 'TRUE'},
+ mles(' + '),
+ mlk('se '),
+ mld('place cursor at end '),
+ {{'ShaDaEntryMapLong', 'ShaDaMsgpackKeyword'}, 'TRUE'},
},
}
eq(exp, act)
diff --git a/test/functional/preload.lua b/test/functional/preload.lua
index 74f03eaecf..6a5a2e907e 100644
--- a/test/functional/preload.lua
+++ b/test/functional/preload.lua
@@ -2,10 +2,11 @@
-- Busted started doing this to help provide more isolation. See issue #62
-- for more information about this.
local helpers = require('test.functional.helpers')(nil)
-local iswin = helpers.iswin
+require('test.functional.ui.screen')
local busted = require("busted")
+local is_os = helpers.is_os
-if iswin() then
+if is_os('win') then
local ffi = require('ffi')
ffi.cdef[[
typedef int errno_t;
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index fbaef3ae00..2c5185a974 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -106,8 +106,53 @@ describe('clipboard', function()
basic_register_test()
end)
- it('`:redir @+>` with invalid g:clipboard shows exactly one error #7184',
- function()
+ it('using "+ in Normal mode with invalid g:clipboard always shows error', function()
+ insert('a')
+ command("let g:clipboard = 'bogus'")
+ feed('"+yl')
+ screen:expect([[
+ ^a |
+ {0:~ }|
+ {0:~ }|
+ clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
+ ]])
+ feed('"+p')
+ screen:expect([[
+ a^a |
+ {0:~ }|
+ {0:~ }|
+ clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
+ ]])
+ end)
+
+ it('using clipboard=unnamedplus with invalid g:clipboard shows error once', function()
+ insert('a')
+ command("let g:clipboard = 'bogus'")
+ command('set clipboard=unnamedplus')
+ feed('yl')
+ screen:expect([[
+ ^a |
+ {0:~ }|
+ {0:~ }|
+ clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
+ ]])
+ feed(':<CR>')
+ screen:expect([[
+ ^a |
+ {0:~ }|
+ {0:~ }|
+ : |
+ ]])
+ feed('p')
+ screen:expect([[
+ a^a |
+ {0:~ }|
+ {0:~ }|
+ : |
+ ]])
+ end)
+
+ it('`:redir @+>` with invalid g:clipboard shows exactly one error #7184', function()
command("let g:clipboard = 'bogus'")
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
screen:expect([[
@@ -118,8 +163,7 @@ describe('clipboard', function()
]])
end)
- it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184',
- function()
+ it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184', function()
command("let g:clipboard = 'bogus'")
feed_command('redir @+> | bogus_cmd | redir END')
screen:expect{grid=[[
@@ -310,18 +354,18 @@ describe('clipboard (with fake clipboard.vim)', function()
insert([[
text:
first line
- secound line
+ second line
third line]])
feed('G"+dd"*dddd"+p"*pp')
expect([[
text:
third line
- secound line
+ second line
first line]])
-- linewise selection should be encoded as an extra newline
eq({{'third line', ''}, 'V'}, eval("g:test_clip['+']"))
- eq({{'secound line', ''}, 'V'}, eval("g:test_clip['*']"))
+ eq({{'second line', ''}, 'V'}, eval("g:test_clip['*']"))
end)
it('handles null bytes when pasting and in getreg', function()
@@ -477,7 +521,7 @@ describe('clipboard (with fake clipboard.vim)', function()
expect("indeed star")
end)
- it('unamed operations work even if the provider fails', function()
+ it('unnamed operations work even if the provider fails', function()
insert('the text')
feed('yy')
feed_command("let g:cliperror = 1")
@@ -511,7 +555,7 @@ describe('clipboard (with fake clipboard.vim)', function()
eq('textstar', meths.get_current_line())
end)
- it('Block paste works currectly', function()
+ it('Block paste works correctly', function()
insert([[
aabbcc
ddeeff
@@ -559,7 +603,7 @@ describe('clipboard (with fake clipboard.vim)', function()
eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['+']"))
eq({{'really unnamed', ''}, 'V'}, eval("g:test_clip['*']"))
- -- unnamedplus takes predecence when pasting
+ -- unnamedplus takes precedence when pasting
eq('+', eval('v:register'))
feed_command("let g:test_clip['+'] = ['the plus','']")
feed_command("let g:test_clip['*'] = ['the star','']")
diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua
index aff5e36e24..ce92831f4c 100644
--- a/test/functional/provider/perl_spec.lua
+++ b/test/functional/provider/perl_spec.lua
@@ -9,6 +9,8 @@ local curbufmeths = helpers.curbufmeths
local insert = helpers.insert
local expect = helpers.expect
local feed = helpers.feed
+local is_os = helpers.is_os
+local skip = helpers.skip
do
clear()
@@ -24,7 +26,7 @@ before_each(function()
end)
describe('legacy perl provider', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
it('feature test', function()
eq(1, eval('has("perl")'))
@@ -68,7 +70,7 @@ describe('legacy perl provider', function()
end)
describe('perl provider', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
teardown(function ()
os.remove('Xtest-perl-hello.pl')
os.remove('Xtest-perl-hello-plugin.pl')
diff --git a/test/functional/shada/compatibility_spec.lua b/test/functional/shada/compatibility_spec.lua
index a5ef60d91f..fb656735dd 100644
--- a/test/functional/shada/compatibility_spec.lua
+++ b/test/functional/shada/compatibility_spec.lua
@@ -12,7 +12,7 @@ local wshada, sdrcmd, shada_fname = get_shada_rw('Xtest-functional-shada-compati
local mock_file_path = '/a/b/'
local mock_file_path2 = '/d/e/'
-if helpers.iswin() then
+if helpers.is_os('win') then
mock_file_path = 'C:/a/'
mock_file_path2 = 'C:/d/'
end
diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index 2d44b0a950..da2fbbe029 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -14,7 +14,7 @@ local wshada, sdrcmd, shada_fname =
get_shada_rw('Xtest-functional-shada-merging.shada')
local mock_file_path = '/a/b/'
-if helpers.iswin() then
+if helpers.is_os('win') then
mock_file_path = 'C:/a/'
end
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index d10a2facbb..88a99d9b55 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -5,6 +5,8 @@ local meths, nvim_command, funcs, eq =
local write_file, spawn, set_session, nvim_prog, exc_exec =
helpers.write_file, helpers.spawn, helpers.set_session, helpers.nvim_prog,
helpers.exc_exec
+local is_os = helpers.is_os
+local skip = helpers.skip
local lfs = require('lfs')
local paths = require('test.cmakeconfig.paths')
@@ -238,8 +240,17 @@ describe('ShaDa support code', function()
eq('', meths.get_option('shada'))
end)
+ it('setting &shada gives proper error message on missing number', function()
+ eq([[Vim(set):E526: Missing number after <">: shada="]],
+ exc_exec([[set shada=\"]]))
+ for _, c in ipairs({"'", "/", ":", "<", "@", "s"}) do
+ eq(([[Vim(set):E526: Missing number after <%s>: shada=%s]]):format(c, c),
+ exc_exec(([[set shada=%s]]):format(c)))
+ end
+ end)
+
it('does not crash when ShaDa file directory is not writable', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
funcs.mkdir(dirname, '', 0)
eq(0, funcs.filewritable(dirname))
diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua
index 155a156d15..cbe5e06005 100644
--- a/test/functional/terminal/altscreen_spec.lua
+++ b/test/functional/terminal/altscreen_spec.lua
@@ -6,7 +6,7 @@ local feed_data = thelpers.feed_data
local enter_altscreen = thelpers.enter_altscreen
local exit_altscreen = thelpers.exit_altscreen
-if helpers.pending_win32(pending) then return end
+if helpers.skip(helpers.is_os('win')) then return end
describe(':terminal altscreen', function()
local screen
@@ -126,13 +126,13 @@ describe(':terminal altscreen', function()
wait_removal()
feed('<c-\\><c-n>4k')
screen:expect([[
- ^line3 |
+ ^ |
|
|
rows: 4, cols: 50 |
|
]])
- eq(8, curbuf('line_count'))
+ eq(9, curbuf('line_count'))
end)
describe('and after exit', function()
@@ -142,15 +142,11 @@ describe(':terminal altscreen', function()
end)
it('restore buffer state', function()
- -- FIXME(tarruda): Note that the last line was lost after restoring the
- -- screen. This is a libvterm bug: When the main screen is restored it
- -- seems to "cut" lines that would have been left below the new visible
- -- screen.
screen:expect([[
- line4 |
line5 |
line6 |
line7 |
+ line8 |
{3:-- TERMINAL --} |
]])
end)
diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index 5305b8af9c..724791343d 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local child_session = require('test.functional.terminal.helpers')
local ok = helpers.ok
-if helpers.pending_win32(pending) then return end
+if helpers.skip(helpers.is_os('win')) then return end
describe('api', function()
local screen
@@ -19,6 +19,16 @@ describe('api', function()
end)
it("qa! RPC request during insert-mode", function()
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
-- Start the socket from the child nvim.
child_session.feed_data(":echo serverstart('"..socket_name.."')\n")
@@ -67,4 +77,3 @@ describe('api', function()
socket_session1:request("nvim_command", "qa!")
end)
end)
-
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 23430a620b..9c8b983ff7 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -4,6 +4,7 @@ local assert_alive = helpers.assert_alive
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
local poke_eventloop = helpers.poke_eventloop
local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.source
+local pcall_err = helpers.pcall_err
local eq, neq = helpers.eq, helpers.neq
local meths = helpers.meths
local retry = helpers.retry
@@ -14,6 +15,8 @@ local matches = helpers.matches
local exec_lua = helpers.exec_lua
local sleep = helpers.sleep
local funcs = helpers.funcs
+local is_os = helpers.is_os
+local skip = helpers.skip
describe(':terminal buffer', function()
local screen
@@ -199,7 +202,7 @@ describe(':terminal buffer', function()
-- Save the buffer number of the terminal for later testing.
local tbuf = eval('bufnr("%")')
- local exitcmd = helpers.iswin()
+ local exitcmd = helpers.is_os('win')
and "['cmd', '/c', 'exit']"
or "['sh', '-c', 'exit']"
source([[
@@ -261,7 +264,7 @@ describe(':terminal buffer', function()
end)
it('it works with set rightleft #11438', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
local columns = eval('&columns')
feed(string.rep('a', columns))
command('set rightleft')
@@ -339,6 +342,11 @@ describe(':terminal buffer', function()
]]}
eq('t', funcs.mode(1))
end)
+
+ it('writing to an existing file with :w fails #13549', function()
+ eq('Vim(write):E13: File exists (add ! to override)',
+ pcall_err(command, 'write test/functional/fixtures/tty-test.c'))
+ end)
end)
describe('No heap-buffer-overflow when using', function()
@@ -404,6 +412,14 @@ describe('on_lines does not emit out-of-bounds line indexes when', function()
feed_command('bdelete!')
eq('', exec_lua([[return _G.cb_error]]))
end)
+
+ it('runs TextChangedT event', function()
+ meths.set_var('called', 0)
+ command('autocmd TextChangedT * ++once let g:called = 1')
+ feed_command('terminal')
+ feed('iaa')
+ eq(1, meths.get_var('called'))
+ end)
end)
it('terminal truncates number of composing characters to 5', function()
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index b5f3c2bd31..2ca7cdb0a2 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -7,6 +7,7 @@ local command = helpers.command
local pcall_err = helpers.pcall_err
local feed = helpers.feed
local poke_eventloop = helpers.poke_eventloop
+local is_os = helpers.is_os
describe('terminal channel is closed and later released if', function()
local screen
@@ -92,3 +93,17 @@ describe('terminal channel is closed and later released if', function()
eq(chans - 1, eval('len(nvim_list_chans())'))
end)
end)
+
+it('chansend sends lines to terminal channel in proper order', function()
+ clear()
+ local screen = Screen.new(100, 20)
+ screen:attach()
+ local shells = is_os('win') and {'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop'} or {'sh'}
+ for _, sh in ipairs(shells) do
+ command([[bdelete! | let id = termopen(']] .. sh .. [[')]])
+ command([[call chansend(id, ['echo "hello"', 'echo "world"', ''])]])
+ screen:expect{
+ any=[[echo "hello".*echo "world"]]
+ }
+ end
+end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index 2d1c790d2f..98ac03211a 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -9,6 +9,8 @@ local matches = helpers.matches
local feed_command = helpers.feed_command
local hide_cursor = thelpers.hide_cursor
local show_cursor = thelpers.show_cursor
+local is_os = helpers.is_os
+local skip = helpers.skip
describe(':terminal cursor', function()
local screen
@@ -88,7 +90,7 @@ describe(':terminal cursor', function()
describe('when invisible', function()
it('is not highlighted and is detached from screen cursor', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
hide_cursor()
screen:expect([[
tty ready |
@@ -361,7 +363,7 @@ describe('buffer cursor position is correct in terminal without number column',
end)
describe('in a line with single-cell composed multibyte characters and no trailing spaces,', function()
- if helpers.pending_win32(pending) then return end -- These tests fail on Windows. Encoding problem?
+ if skip(is_os('win'), "Encoding problem?") then return end
before_each(function()
setup_ex_register('µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳')
@@ -444,7 +446,7 @@ describe('buffer cursor position is correct in terminal without number column',
end)
describe('in a line with double-cell multibyte characters and no trailing spaces,', function()
- if helpers.pending_win32(pending) then return end -- These tests fail on Windows. Encoding problem?
+ skip(is_os('win'), "Encoding problem?")
before_each(function()
setup_ex_register('哦哦哦哦哦哦哦哦')
@@ -741,7 +743,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
end)
describe('in a line with single-cell composed multibyte characters and no trailing spaces,', function()
- if helpers.pending_win32(pending) then return end -- These tests fail on Windows. Encoding problem?
+ if skip(is_os('win'), "Encoding problem?") then return end
before_each(function()
setup_ex_register('µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳')
@@ -824,7 +826,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
end)
describe('in a line with double-cell multibyte characters and no trailing spaces,', function()
- if helpers.pending_win32(pending) then return end -- These tests fail on Windows. Encoding problem?
+ skip(is_os('win'), "Encoding problem?")
before_each(function()
setup_ex_register('哦哦哦哦哦哦哦哦')
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index aeb4b7cc2e..80287bb3d0 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -36,7 +36,7 @@ describe(':edit term://*', function()
end)
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
- if helpers.pending_win32(pending) then return end
+ if helpers.skip(helpers.is_os('win')) then return end
local columns, lines = 20, 4
local scr = get_screen(columns, lines)
local rep = 97
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 23b69319f0..6b7e93a864 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -8,8 +8,10 @@ local feed_command, eval = helpers.feed_command, helpers.eval
local funcs = helpers.funcs
local retry = helpers.retry
local ok = helpers.ok
-local iswin = helpers.iswin
local command = helpers.command
+local skip = helpers.skip
+local is_os = helpers.is_os
+local is_ci = helpers.is_ci
describe(':terminal', function()
local screen
@@ -45,8 +47,8 @@ describe(':terminal', function()
end)
it("reads output buffer on terminal reporting #4151", function()
- if helpers.pending_win32(pending) then return end
- if iswin() then
+ skip(is_ci('cirrus') or is_os('win'))
+ if is_os('win') then
feed_command([[terminal powershell -NoProfile -NoLogo -Command Write-Host -NoNewline "\"$([char]27)[6n\""; Start-Sleep -Milliseconds 500 ]])
else
feed_command([[terminal printf '\e[6n'; sleep 0.5 ]])
@@ -55,7 +57,7 @@ describe(':terminal', function()
end)
it("in normal-mode :split does not move cursor", function()
- if iswin() then
+ if is_os('win') then
feed_command([[terminal for /L \\%I in (1,0,2) do ( echo foo & ping -w 100 -n 1 127.0.0.1 > nul )]])
else
feed_command([[terminal while true; do echo foo; sleep .1; done]])
@@ -142,7 +144,7 @@ describe(':terminal (with fake shell)', function()
end
it('with no argument, acts like termopen()', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
terminal_with_fake_shell()
retry(nil, 4 * screen.timeout, function()
screen:expect([[
@@ -166,7 +168,7 @@ describe(':terminal (with fake shell)', function()
end)
it("with no argument, but 'shell' has arguments, acts like termopen()", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
terminal_with_fake_shell()
screen:expect([[
@@ -178,7 +180,7 @@ describe(':terminal (with fake shell)', function()
end)
it('executes a given command through the shell', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
screen:expect([[
@@ -190,7 +192,7 @@ describe(':terminal (with fake shell)', function()
end)
it("executes a given command through the shell, when 'shell' has arguments", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
@@ -203,7 +205,7 @@ describe(':terminal (with fake shell)', function()
end)
it('allows quotes and slashes', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo 'hello' \ "world"]])
screen:expect([[
@@ -240,7 +242,7 @@ describe(':terminal (with fake shell)', function()
end)
it('works with :find', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
terminal_with_fake_shell()
screen:expect([[
^ready $ |
@@ -251,7 +253,7 @@ describe(':terminal (with fake shell)', function()
eq('term://', string.match(eval('bufname("%")'), "^term://"))
feed([[<C-\><C-N>]])
feed_command([[find */shadacat.py]])
- if iswin() then
+ if is_os('win') then
eq('scripts\\shadacat.py', eval('bufname("%")'))
else
eq('scripts/shadacat.py', eval('bufname("%")'))
@@ -259,7 +261,7 @@ describe(':terminal (with fake shell)', function()
end)
it('works with gf', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo "scripts/shadacat.py"]])
retry(nil, 4 * screen.timeout, function()
diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua
index bcfd3559e6..7247361649 100644
--- a/test/functional/terminal/helpers.lua
+++ b/test/functional/terminal/helpers.lua
@@ -4,19 +4,31 @@
local helpers = require('test.functional.helpers')(nil)
local Screen = require('test.functional.ui.screen')
local testprg = helpers.testprg
+local exec_lua = helpers.exec_lua
local feed_command, nvim = helpers.feed_command, helpers.nvim
local function feed_data(data)
- -- A string containing NUL bytes is not converted to a Blob when
- -- calling nvim_set_var() API, so convert it using Lua instead.
- nvim('exec_lua', 'vim.g.term_data = ...', {data})
- nvim('command', 'call jobsend(b:terminal_job_id, term_data)')
+ if type(data) == 'table' then
+ data = table.concat(data, '\n')
+ end
+ exec_lua('vim.api.nvim_chan_send(vim.b.terminal_job_id, ...)', data)
end
local function feed_termcode(data)
- -- feed with the job API
- nvim('command', 'call jobsend(b:terminal_job_id, "\\x1b'..data..'")')
+ feed_data('\027' .. data)
+end
+
+local function make_lua_executor(session)
+ return function(code, ...)
+ local status, rv = session:request('nvim_exec_lua', code, {...})
+ if not status then
+ session:stop()
+ error(rv[2])
+ end
+ return rv
+ end
end
+
-- some helpers for controlling the terminal. the codes were taken from
-- infocmp xterm-256color which is less what libvterm understands
-- civis/cnorm
@@ -31,6 +43,8 @@ local function set_bg(num) feed_termcode('[48;5;'..num..'m') end
local function set_bold() feed_termcode('[1m') end
local function set_italic() feed_termcode('[3m') end
local function set_underline() feed_termcode('[4m') end
+local function set_underdouble() feed_termcode('[4:2m') end
+local function set_undercurl() feed_termcode('[4:3m') end
local function set_strikethrough() feed_termcode('[9m') end
local function clear_attrs() feed_termcode('[0;10m') end
-- mouse
@@ -60,7 +74,10 @@ local function screen_setup(extra_rows, command, cols, opts)
[9] = {foreground = 4},
[10] = {foreground = 121}, -- "Press ENTER" in embedded :terminal session.
[11] = {foreground = tonumber('0x00000b')},
- [12] = {reverse = true, foreground = tonumber('0x000079')},
+ [12] = {underline = true},
+ [13] = {underline = true, reverse = true},
+ [14] = {underline = true, reverse = true, bold = true},
+ [15] = {underline = true, foreground = 12},
})
screen:attach(opts or {rgb=false})
@@ -107,6 +124,7 @@ end
return {
feed_data = feed_data,
feed_termcode = feed_termcode,
+ make_lua_executor = make_lua_executor,
hide_cursor = hide_cursor,
show_cursor = show_cursor,
enter_altscreen = enter_altscreen,
@@ -116,6 +134,8 @@ return {
set_bold = set_bold,
set_italic = set_italic,
set_underline = set_underline,
+ set_underdouble = set_underdouble,
+ set_undercurl = set_undercurl,
set_strikethrough = set_strikethrough,
clear_attrs = clear_attrs,
enable_mouse = enable_mouse,
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 28ca07d815..2ac45771d4 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -7,6 +7,8 @@ local nvim_prog_abs = helpers.nvim_prog_abs
local eq, eval = helpers.eq, helpers.eval
local funcs = helpers.funcs
local nvim_set = helpers.nvim_set
+local is_os = helpers.is_os
+local skip = helpers.skip
describe(':terminal highlight', function()
local screen
@@ -26,6 +28,8 @@ describe(':terminal highlight', function()
[9] = {foreground = 130},
[10] = {reverse = true},
[11] = {background = 11},
+ [12] = {bold = true, underdouble = true},
+ [13] = {italic = true, undercurl = true},
})
screen:attach({rgb=false})
command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
@@ -56,7 +60,7 @@ describe(':terminal highlight', function()
end)
local function pass_attrs()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
screen:expect(sub([[
tty ready |
{NUM:text}text{10: } |
@@ -71,7 +75,7 @@ describe(':terminal highlight', function()
it('will pass the corresponding attributes', pass_attrs)
it('will pass the corresponding attributes on scrollback', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
pass_attrs()
local lines = {}
for i = 1, 8 do
@@ -114,6 +118,14 @@ describe(':terminal highlight', function()
thelpers.set_underline()
thelpers.set_strikethrough()
end)
+ descr('bold and underdouble', 12, function()
+ thelpers.set_bold()
+ thelpers.set_underdouble()
+ end)
+ descr('italics and undercurl', 13, function()
+ thelpers.set_italic()
+ thelpers.set_undercurl()
+ end)
end)
it(':terminal highlight has lower precedence than editor #9964', function()
@@ -187,7 +199,7 @@ describe(':terminal highlight forwarding', function()
end)
it('will handle cterm and rgb attributes', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
thelpers.set_fg(3)
thelpers.feed_data('text')
thelpers.feed_termcode('[38:2:255:128:0m')
@@ -239,7 +251,7 @@ describe(':terminal highlight with custom palette', function()
end)
it('will use the custom color', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
thelpers.set_fg(3)
thelpers.feed_data('text')
thelpers.clear_attrs()
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index 6e2c851df7..50c8f5e7df 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -3,6 +3,8 @@ local thelpers = require('test.functional.terminal.helpers')
local clear, eq, eval = helpers.clear, helpers.eq, helpers.eval
local feed, nvim, command = helpers.feed, helpers.nvim, helpers.command
local feed_data = thelpers.feed_data
+local is_os = helpers.is_os
+local skip = helpers.skip
describe(':terminal mouse', function()
local screen
@@ -66,7 +68,7 @@ describe(':terminal mouse', function()
end)
it('does not leave terminal mode on left-release', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
feed('<LeftRelease>')
eq('t', eval('mode(1)'))
end)
@@ -87,7 +89,7 @@ describe(':terminal mouse', function()
end)
it('will forward mouse press, drag and release to the program', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
feed('<LeftMouse><1,2>')
screen:expect([[
line27 |
@@ -131,7 +133,7 @@ describe(':terminal mouse', function()
end)
it('will forward mouse scroll to the program', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
feed('<ScrollWheelUp><0,0>')
screen:expect([[
line27 |
@@ -145,7 +147,7 @@ describe(':terminal mouse', function()
end)
it('dragging and scrolling do not interfere with each other', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
feed('<LeftMouse><1,2>')
screen:expect([[
line27 |
@@ -199,7 +201,7 @@ describe(':terminal mouse', function()
end)
it('will forward mouse clicks to the program with the correct even if set nu', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
command('set number')
-- When the display area such as a number is clicked, it returns to the
-- normal mode.
@@ -230,7 +232,7 @@ describe(':terminal mouse', function()
end)
describe('with a split window and other buffer', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
before_each(function()
feed('<c-\\><c-n>:vsp<cr>')
screen:expect([[
@@ -287,7 +289,7 @@ describe(':terminal mouse', function()
]])
end)
- it('wont lose focus if another window is scrolled', function()
+ it("won't lose focus if another window is scrolled", function()
feed('<ScrollWheelUp><4,0><ScrollWheelUp><4,0>')
screen:expect([[
{7: 21 }line │line30 |
@@ -310,6 +312,34 @@ describe(':terminal mouse', function()
]])
end)
+ it("scrolling another window respects 'mousescroll'", function()
+ command('set mousescroll=ver:1')
+ feed('<ScrollWheelUp><4,0>')
+ screen:expect([[
+ {7: 26 }line │line30 |
+ {7: 27 }line │rows: 5, cols: 25 |
+ {7: 28 }line │rows: 5, cols: 24 |
+ {7: 29 }line │mouse enabled |
+ {7: 30 }line │{1: } |
+ ========== ========== |
+ {3:-- TERMINAL --} |
+ ]])
+ command('set mousescroll=ver:10')
+ feed('<ScrollWheelUp><4,0>')
+ screen:expect([[
+ {7: 16 }line │line30 |
+ {7: 17 }line │rows: 5, cols: 25 |
+ {7: 18 }line │rows: 5, cols: 24 |
+ {7: 19 }line │mouse enabled |
+ {7: 20 }line │{1: } |
+ ========== ========== |
+ {3:-- TERMINAL --} |
+ ]])
+ command('set mousescroll=ver:0')
+ feed('<ScrollWheelUp><4,0>')
+ screen:expect_unchanged()
+ end)
+
it('will lose focus if another window is clicked', function()
feed('<LeftMouse><5,1>')
screen:expect([[
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index b491cb2735..a4899c8219 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -3,7 +3,6 @@ local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local clear, eq, curbuf = helpers.clear, helpers.eq, helpers.curbuf
local feed, testprg, feed_command = helpers.feed, helpers.testprg, helpers.feed_command
-local iswin = helpers.iswin
local eval = helpers.eval
local command = helpers.command
local matches = helpers.matches
@@ -15,6 +14,8 @@ local feed_data = thelpers.feed_data
local pcall_err = helpers.pcall_err
local exec_lua = helpers.exec_lua
local assert_alive = helpers.assert_alive
+local skip = helpers.skip
+local is_os = helpers.is_os
describe(':terminal scrollback', function()
local screen
@@ -139,7 +140,7 @@ describe(':terminal scrollback', function()
describe('and height decreased by 1', function()
- if helpers.pending_win32(pending) then return end
+ if skip(is_os('win')) then return end
local function will_hide_top_line()
feed([[<C-\><C-N>]])
screen:try_resize(screen._width - 2, screen._height - 1)
@@ -185,7 +186,7 @@ describe(':terminal scrollback', function()
-- XXX: Can't test this reliably on Windows unless the cursor is _moved_
-- by the resize. http://docs.libuv.org/en/v1.x/signal.html
-- See also: https://github.com/rprichard/winpty/issues/110
- if helpers.pending_win32(pending) then return end
+ if skip(is_os('win')) then return end
describe('and the height is decreased by 2', function()
before_each(function()
@@ -264,7 +265,7 @@ describe(':terminal scrollback', function()
-- XXX: Can't test this reliably on Windows unless the cursor is _moved_
-- by the resize. http://docs.libuv.org/en/v1.x/signal.html
-- See also: https://github.com/rprichard/winpty/issues/110
- if helpers.pending_win32(pending) then return end
+ if skip(is_os('win')) then return end
local function pop_then_push()
screen:try_resize(screen._width, screen._height + 1)
screen:expect([[
@@ -346,7 +347,7 @@ end)
describe(':terminal prints more lines than the screen height and exits', function()
it('will push extra lines to scrollback', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
clear()
local screen = Screen.new(30, 7)
screen:attach({rgb=false})
@@ -396,21 +397,21 @@ describe("'scrollback' option", function()
it('set to 0 behaves as 1', function()
local screen
- if iswin() then
+ if is_os('win') then
screen = thelpers.screen_setup(nil, "['cmd.exe']", 30)
else
screen = thelpers.screen_setup(nil, "['sh']", 30)
end
curbufmeths.set_option('scrollback', 0)
- feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), iswin() and '\r' or '\n'))
+ feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), is_os('win') and '\r' or '\n'))
screen:expect{any='30: line '}
retry(nil, nil, function() expect_lines(7) end)
end)
it('deletes lines (only) if necessary', function()
local screen
- if iswin() then
+ if is_os('win') then
command([[let $PROMPT='$$']])
screen = thelpers.screen_setup(nil, "['cmd.exe']", 30)
else
@@ -423,7 +424,7 @@ describe("'scrollback' option", function()
-- Wait for prompt.
screen:expect{any='%$'}
- feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), iswin() and '\r' or '\n'))
+ feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), is_os('win') and '\r' or '\n'))
screen:expect{any='30: line '}
retry(nil, nil, function() expect_lines(33, 2) end)
@@ -436,8 +437,8 @@ describe("'scrollback' option", function()
-- 'scrollback' option is synchronized with the internal sb_buffer.
command('sleep 100m')
- feed_data(('%s REP 41 line%s'):format(testprg('shell-test'), iswin() and '\r' or '\n'))
- if iswin() then
+ feed_data(('%s REP 41 line%s'):format(testprg('shell-test'), is_os('win') and '\r' or '\n'))
+ if is_os('win') then
screen:expect{grid=[[
37: line |
38: line |
@@ -461,8 +462,8 @@ describe("'scrollback' option", function()
expect_lines(58)
-- Verify off-screen state
- matches((iswin() and '^36: line[ ]*$' or '^35: line[ ]*$'), eval("getline(line('w0') - 1)"))
- matches((iswin() and '^27: line[ ]*$' or '^26: line[ ]*$'), eval("getline(line('w0') - 10)"))
+ matches((is_os('win') and '^36: line[ ]*$' or '^35: line[ ]*$'), eval("getline(line('w0') - 1)"))
+ matches((is_os('win') and '^27: line[ ]*$' or '^26: line[ ]*$'), eval("getline(line('w0') - 10)"))
end)
it('deletes extra lines immediately', function()
@@ -606,7 +607,7 @@ describe("pending scrollback line handling", function()
end)
it("does not crash after nvim_buf_call #14891", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
exec_lua [[
local a = vim.api
local bufnr = a.nvim_create_buf(false, true)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 99f69ef556..b28728057f 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -5,15 +5,15 @@
-- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Bracketed-Paste-Mode
local helpers = require('test.functional.helpers')(after_each)
-local uname = helpers.uname
local thelpers = require('test.functional.terminal.helpers')
local Screen = require('test.functional.ui.screen')
-local assert_alive = helpers.assert_alive
local eq = helpers.eq
local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
local clear = helpers.clear
local command = helpers.command
+local dedent = helpers.dedent
+local exec = helpers.exec
local testprg = helpers.testprg
local retry = helpers.retry
local nvim_prog = helpers.nvim_prog
@@ -21,16 +21,25 @@ local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
local funcs = helpers.funcs
+local meths = helpers.meths
+local is_ci = helpers.is_ci
+local is_os = helpers.is_os
+local new_pipename = helpers.new_pipename
+local spawn_argv = helpers.spawn_argv
+local set_session = helpers.set_session
+local feed = helpers.feed
+local eval = helpers.eval
-if helpers.pending_win32(pending) then return end
+if helpers.skip(helpers.is_os('win')) then return end
describe('TUI', function()
local screen
local child_session
+ local child_exec_lua
before_each(function()
clear()
- local child_server = helpers.new_pipename()
+ local child_server = new_pipename()
screen = thelpers.screen_setup(0,
string.format([=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark"]]=],
nvim_prog, child_server, nvim_set))
@@ -44,6 +53,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
child_session = helpers.connect(child_server)
+ child_exec_lua = thelpers.make_lua_executor(child_session)
end)
-- Wait for mode in the child Nvim (avoid "typeahead race" #10826).
@@ -66,7 +76,16 @@ describe('TUI', function()
it('rapid resize #7572 #7628', function()
-- Need buffer rows to provoke the behavior.
- feed_data(":edit test/functional/fixtures/bigfile.txt:")
+ feed_data(":edit test/functional/fixtures/bigfile.txt\n")
+ screen:expect([[
+ {1:0}000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
+ 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ {5:test/functional/fixtures/bigfile.txt }|
+ :edit test/functional/fixtures/bigfile.txt |
+ {3:-- TERMINAL --} |
+ ]])
command('call jobresize(b:terminal_job_id, 58, 9)')
command('call jobresize(b:terminal_job_id, 62, 13)')
command('call jobresize(b:terminal_job_id, 100, 42)')
@@ -83,25 +102,9 @@ describe('TUI', function()
command('call jobresize(b:terminal_job_id, 1, 4)')
screen:try_resize(57, 17)
command('call jobresize(b:terminal_job_id, 57, 17)')
- assert_alive()
- end)
-
- it('resize at startup', function()
- -- Issues: #17285 #15044 #11330
- screen:try_resize(50, 10)
- feed_command([[call termopen([v:progpath, '--clean', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile']) | sleep 500m | vs new]])
- screen:expect([[
- {1: } │ |
- {4:~ }│{4:~ }|
- {4:~ }│{4:~ }|
- {4:~ }│{4:~ }|
- {4:~ }│{4:~ }|
- {4:~ }│{5:[No Name] 0,0-1 All}|
- {4:~ }│ |
- {5:new }{MATCH:<.*[/\]nvim }|
- |
- {3:-- TERMINAL --} |
- ]])
+ retry(nil, nil, function()
+ eq({true, 57}, {child_session:request('nvim_win_get_width', 0)})
+ end)
end)
it('accepts resize while pager is active', function()
@@ -297,6 +300,199 @@ describe('TUI', function()
]], attrs)
end)
+ it('accepts mouse wheel events #19992', function()
+ child_session:request('nvim_command', [[
+ set number nostartofline nowrap mousescroll=hor:1,ver:1
+ call setline(1, repeat([join(range(10), '----')], 10))
+ vsplit
+ ]])
+ screen:expect([[
+ {11: 1 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelDown> in active window
+ feed_data('\027[<65;8;1M')
+ screen:expect([[
+ {11: 2 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 4 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 5 }0----1----2----3----4│{11: 4 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelDown> in inactive window
+ feed_data('\027[<65;48;1M')
+ screen:expect([[
+ {11: 2 }{1:0}----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
+ {11: 5 }0----1----2----3----4│{11: 5 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelRight> in active window
+ feed_data('\027[<67;8;1M')
+ screen:expect([[
+ {11: 2 }{1:-}---1----2----3----4-│{11: 2 }0----1----2----3----|
+ {11: 3 }----1----2----3----4-│{11: 3 }0----1----2----3----|
+ {11: 4 }----1----2----3----4-│{11: 4 }0----1----2----3----|
+ {11: 5 }----1----2----3----4-│{11: 5 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelRight> in inactive window
+ feed_data('\027[<67;48;1M')
+ screen:expect([[
+ {11: 2 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
+ {11: 3 }----1----2----3----4-│{11: 3 }----1----2----3----4|
+ {11: 4 }----1----2----3----4-│{11: 4 }----1----2----3----4|
+ {11: 5 }----1----2----3----4-│{11: 5 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelDown> in active window
+ feed_data('\027[<69;8;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
+ {11: 6 }----1----2----3----4-│{11: 3 }----1----2----3----4|
+ {11: 7 }----1----2----3----4-│{11: 4 }----1----2----3----4|
+ {11: 8 }----1----2----3----4-│{11: 5 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelDown> in inactive window
+ feed_data('\027[<69;48;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---1----2----3----4-│{11: 5 }----1----2----3----4|
+ {11: 6 }----1----2----3----4-│{11: 6 }----1----2----3----4|
+ {11: 7 }----1----2----3----4-│{11: 7 }----1----2----3----4|
+ {11: 8 }----1----2----3----4-│{11: 8 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelRight> in active window
+ feed_data('\027[<71;8;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---6----7----8----9 │{11: 5 }----1----2----3----4|
+ {11: 6 }----6----7----8----9 │{11: 6 }----1----2----3----4|
+ {11: 7 }----6----7----8----9 │{11: 7 }----1----2----3----4|
+ {11: 8 }----6----7----8----9 │{11: 8 }----1----2----3----4|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelRight> in inactive window
+ feed_data('\027[<71;48;1M')
+ screen:expect([[
+ {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
+ {11: 8 }----6----7----8----9 │{11: 8 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelUp> in active window
+ feed_data('\027[<64;8;1M')
+ screen:expect([[
+ {11: 4 }----6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 5 }{1:-}---6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 6 }----6----7----8----9 │{11: 7 }5----6----7----8----|
+ {11: 7 }----6----7----8----9 │{11: 8 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelUp> in inactive window
+ feed_data('\027[<64;48;1M')
+ screen:expect([[
+ {11: 4 }----6----7----8----9 │{11: 4 }5----6----7----8----|
+ {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelLeft> in active window
+ feed_data('\027[<66;8;1M')
+ screen:expect([[
+ {11: 4 }5----6----7----8----9│{11: 4 }5----6----7----8----|
+ {11: 5 }5{1:-}---6----7----8----9│{11: 5 }5----6----7----8----|
+ {11: 6 }5----6----7----8----9│{11: 6 }5----6----7----8----|
+ {11: 7 }5----6----7----8----9│{11: 7 }5----6----7----8----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <ScrollWheelLeft> in inactive window
+ feed_data('\027[<66;48;1M')
+ screen:expect([[
+ {11: 4 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
+ {11: 5 }5{1:-}---6----7----8----9│{11: 5 }-5----6----7----8---|
+ {11: 6 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
+ {11: 7 }5----6----7----8----9│{11: 7 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelUp> in active window
+ feed_data('\027[<68;8;1M')
+ screen:expect([[
+ {11: 1 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
+ {11: 2 }5----6----7----8----9│{11: 5 }-5----6----7----8---|
+ {11: 3 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
+ {11: 4 }5{1:-}---6----7----8----9│{11: 7 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelUp> in inactive window
+ feed_data('\027[<68;48;1M')
+ screen:expect([[
+ {11: 1 }5----6----7----8----9│{11: 1 }-5----6----7----8---|
+ {11: 2 }5----6----7----8----9│{11: 2 }-5----6----7----8---|
+ {11: 3 }5----6----7----8----9│{11: 3 }-5----6----7----8---|
+ {11: 4 }5{1:-}---6----7----8----9│{11: 4 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelLeft> in active window
+ feed_data('\027[<70;8;1M')
+ screen:expect([[
+ {11: 1 }0----1----2----3----4│{11: 1 }-5----6----7----8---|
+ {11: 2 }0----1----2----3----4│{11: 2 }-5----6----7----8---|
+ {11: 3 }0----1----2----3----4│{11: 3 }-5----6----7----8---|
+ {11: 4 }0----1----2----3----{1:4}│{11: 4 }-5----6----7----8---|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <S-ScrollWheelLeft> in inactive window
+ feed_data('\027[<70;48;1M')
+ screen:expect([[
+ {11: 1 }0----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
+ {11: 4 }0----1----2----3----{1:4}│{11: 4 }0----1----2----3----|
+ {5:[No Name] [+] }{1:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('accepts keypad keys from kitty keyboard protocol #19180', function()
feed_data('i')
feed_data(funcs.nr2char(57399)) -- KP_0
@@ -440,37 +636,83 @@ describe('TUI', function()
tabnew
highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline
]])
- local attrs = screen:get_default_attr_ids()
- attrs[11] = {underline = true}
screen:expect([[
- {11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11:X}|
+ {12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}|
{1: } |
{4:~ }|
{4:~ }|
{5:[No Name] }|
|
{3:-- TERMINAL --} |
- ]], attrs)
+ ]])
feed_data('\027[57421;5u') -- CTRL + KP_PAGE_UP
screen:expect([[
- {11: + [No Name] }{3: + [No Name] }{11: [No Name] }{1: }{11:X}|
+ {12: + [No Name] }{3: + [No Name] }{12: [No Name] }{1: }{12:X}|
0123456789/*-{1:+} |
= |
{4:~ }|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
- ]], attrs)
+ ]])
feed_data('\027[57422;5u') -- CTRL + KP_PAGE_DOWN
screen:expect([[
- {11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11:X}|
+ {12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}|
{1: } |
{4:~ }|
{4:~ }|
{5:[No Name] }|
|
{3:-- TERMINAL --} |
- ]], attrs)
+ ]])
+ end)
+
+ it('mouse events work with right-click menu', function()
+ child_session:request('nvim_command', [[
+ call setline(1, 'popup menu test')
+ set mouse=a mousemodel=popup
+
+ aunmenu PopUp
+ menu PopUp.foo :let g:menustr = 'foo'<CR>
+ menu PopUp.bar :let g:menustr = 'bar'<CR>
+ menu PopUp.baz :let g:menustr = 'baz'<CR>
+ highlight Pmenu ctermbg=NONE ctermfg=NONE cterm=underline,reverse
+ highlight PmenuSel ctermbg=NONE ctermfg=NONE cterm=underline,reverse,bold
+ ]])
+ meths.input_mouse('right', 'press', '', 0, 0, 4)
+ screen:expect([[
+ {1:p}opup menu test |
+ {4:~ }{13: foo }{4: }|
+ {4:~ }{13: bar }{4: }|
+ {4:~ }{13: baz }{4: }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ meths.input_mouse('right', 'release', '', 0, 0, 4)
+ screen:expect_unchanged()
+ meths.input_mouse('move', '', '', 0, 3, 6)
+ screen:expect([[
+ {1:p}opup menu test |
+ {4:~ }{13: foo }{4: }|
+ {4:~ }{13: bar }{4: }|
+ {4:~ }{14: baz }{4: }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 2, 6)
+ screen:expect([[
+ {1:p}opup menu test |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ :let g:menustr = 'bar' |
+ {3:-- TERMINAL --} |
+ ]])
+ meths.input_mouse('left', 'release', '', 0, 2, 6)
+ screen:expect_unchanged()
end)
it('paste: Insert mode', function()
@@ -574,12 +816,11 @@ describe('TUI', function()
end)
it('paste: terminal mode', function()
- if os.getenv('GITHUB_ACTIONS') ~= nil then
+ if is_ci('github') then
pending("tty-test complains about not owning the terminal -- actions/runner#241")
- return
end
- feed_data(':set statusline=^^^^^^^\n')
- feed_data(':terminal '..testprg('tty-test')..'\n')
+ child_exec_lua('vim.o.statusline="^^^^^^^"')
+ child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
feed_data('i')
screen:expect{grid=[[
tty ready |
@@ -841,8 +1082,7 @@ describe('TUI', function()
wait_for_mode('i')
-- "bracketed paste"
feed_data('\027[200~'..expected..'\027[201~')
- -- FIXME: Data race between the two feeds
- if uname() == 'freebsd' then screen:sleep(1) end
+ expect_child_buf_lines({expected})
feed_data(' end')
expected = expected..' end'
screen:expect([[
@@ -961,6 +1201,15 @@ describe('TUI', function()
it('paste: split "start paste" code', function()
feed_data('i')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
-- Send split "start paste" sequence.
feed_data('\027[2')
feed_data('00~pasted from terminal\027[201~')
@@ -977,6 +1226,15 @@ describe('TUI', function()
it('paste: split "stop paste" code', function()
feed_data('i')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
-- Send split "stop paste" sequence.
feed_data('\027[200~pasted from terminal\027[20')
feed_data('1~')
@@ -1002,6 +1260,15 @@ describe('TUI', function()
end)(vim.paste)
]], {})
feed_data('i')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data('\027[200~pasted') -- phase 1
screen:expect([[
pasted{1: } |
@@ -1041,6 +1308,7 @@ describe('TUI', function()
[7] = {reverse = true, foreground = Screen.colors.SeaGreen4},
[8] = {foreground = Screen.colors.SeaGreen4},
[9] = {bold = true, foreground = Screen.colors.Blue1},
+ [10] = {foreground = Screen.colors.Blue},
})
feed_data(':hi SpecialKey ctermfg=3 guifg=SeaGreen\n')
@@ -1061,9 +1329,9 @@ describe('TUI', function()
feed_data(':set termguicolors\n')
screen:expect([[
{7:^}{8:G} |
- {9:~ }|
- {9:~ }|
- {9:~ }|
+ {9:~}{10: }|
+ {9:~}{10: }|
+ {9:~}{10: }|
{3:[No Name] [+] }|
:set termguicolors |
{4:-- TERMINAL --} |
@@ -1082,9 +1350,8 @@ describe('TUI', function()
end)
it('forwards :term palette colors with termguicolors', function()
- if os.getenv('GITHUB_ACTIONS') ~= nil then
+ if is_ci('github') then
pending("tty-test complains about not owning the terminal -- actions/runner#241")
- return
end
screen:set_rgb_cterm(true)
screen:set_default_attr_ids({
@@ -1095,12 +1362,9 @@ describe('TUI', function()
[5] = {{foreground = tonumber('0xff8000')}, {}},
})
- feed_data(':set statusline=^^^^^^^\n')
- feed_data(':set termguicolors\n')
- feed_data(':terminal '..testprg('tty-test')..'\n')
- -- Depending on platform the above might or might not fit in the cmdline
- -- so clear it for consistent behavior.
- feed_data(':\027')
+ child_exec_lua('vim.o.statusline="^^^^^^^"')
+ child_exec_lua('vim.o.termguicolors=true')
+ child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
screen:expect{grid=[[
{1:t}ty ready |
|
@@ -1139,7 +1403,7 @@ describe('TUI', function()
|
{4:~ }|
{5: }|
- [[['chan', 0], ['height', 6], ['override', v:false|
+ [[['chan', 1], ['height', 6], ['override', v:false|
], ['rgb', v:false], ['width', 50]]] |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
@@ -1147,18 +1411,14 @@ describe('TUI', function()
end)
it('allows grid to assume wider ambiguous-width characters than host terminal #19686', function()
- child_session:request('nvim_buf_set_lines', 0, 0, 0, true, { ('℃'):rep(60), ('℃'):rep(60) })
+ child_session:request('nvim_buf_set_lines', 0, 0, -1, true, { ('℃'):rep(60), ('℃'):rep(60) })
child_session:request('nvim_win_set_option', 0, 'cursorline', true)
child_session:request('nvim_win_set_option', 0, 'list', true)
child_session:request('nvim_win_set_option', 0, 'listchars', 'eol:$')
- local attrs = screen:get_default_attr_ids()
- attrs[11] = {underline = true} -- CursorLine
- attrs[12] = {underline = true, reverse = true} -- CursorLine and TermCursor
- attrs[13] = {underline = true, foreground = 12} -- CursorLine and NonText
feed_data('gg')
local singlewidth_screen = [[
- {12:℃}{11:℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
- {11:℃℃℃℃℃℃℃℃℃℃}{13:$}{11: }|
+ {13:℃}{12:℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
+ {12:℃℃℃℃℃℃℃℃℃℃}{15:$}{12: }|
℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃|
℃℃℃℃℃℃℃℃℃℃{4:$} |
{5:[No Name] [+] }|
@@ -1168,23 +1428,83 @@ describe('TUI', function()
-- When grid assumes "℃" to be double-width but host terminal assumes it to be single-width, the
-- second cell of "℃" is a space and the attributes of the "℃" are applied to it.
local doublewidth_screen = [[
- {12:℃}{11: ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
- {11:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
- {11:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }{13:$}{11: }|
+ {13:℃}{12: ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
+ {12:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
+ {12:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }{15:$}{12: }|
℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ >{4:@@@}|
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]]
- screen:expect(singlewidth_screen, attrs)
+ screen:expect(singlewidth_screen)
child_session:request('nvim_set_option', 'ambiwidth', 'double')
- screen:expect(doublewidth_screen, attrs)
+ screen:expect(doublewidth_screen)
child_session:request('nvim_set_option', 'ambiwidth', 'single')
- screen:expect(singlewidth_screen, attrs)
+ screen:expect(singlewidth_screen)
child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 2}}})
- screen:expect(doublewidth_screen, attrs)
+ screen:expect(doublewidth_screen)
child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 1}}})
- screen:expect(singlewidth_screen, attrs)
+ screen:expect(singlewidth_screen)
+ end)
+
+ it('draws correctly when cursor_address overflows #21643', function()
+ helpers.skip(helpers.is_os('mac'), 'FIXME: crashes/errors on macOS')
+ screen:try_resize(77, 834)
+ retry(nil, nil, function()
+ eq({true, 831}, {child_session:request('nvim_win_get_height', 0)})
+ end)
+ -- Use full screen message so that redrawing afterwards is more deterministic.
+ child_session:notify('nvim_command', 'intro')
+ screen:expect({any = 'Nvim'})
+ -- Going to top-left corner needs 3 bytes.
+ -- Setting underline attribute needs 9 bytes.
+ -- With screen width 77, 63857 characters need 829 full screen lines.
+ -- Drawing each full screen line needs 77 + 2 = 79 bytes (2 bytes for CR LF).
+ -- The incomplete screen line needs 24 + 3 = 27 bytes.
+ -- The whole line needs 3 + 9 + 79 * 829 + 27 = 65530 bytes.
+ -- The cursor_address that comes after will overflow the 65535-byte buffer.
+ local line = ('a'):rep(63857) .. '℃'
+ child_session:notify('nvim_exec_lua', [[
+ vim.api.nvim_buf_set_lines(0, 0, -1, true, {...})
+ vim.o.cursorline = true
+ ]], {line, 'b'})
+ -- Close the :intro message and redraw the lines.
+ feed_data('\n')
+ screen:expect(
+ '{13:a}{12:' .. ('a'):rep(76) .. '}|\n'
+ .. ('{12:' .. ('a'):rep(77) .. '}|\n'):rep(828)
+ .. '{12:' .. ('a'):rep(24) .. '℃' .. (' '):rep(52) .. '}|\n' .. dedent([[
+ b |
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |]]))
+ end)
+
+ it('visual bell (padding) does not crash #21610', function()
+ feed_data ':set visualbell\n'
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ :set visualbell |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ -- move left is enough to invoke the bell
+ feed_data 'h'
+ -- visual change to show we process events after this
+ feed_data 'i'
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
end)
end)
@@ -1194,6 +1514,35 @@ describe('TUI', function()
os.remove('testF')
end)
+ it('resize at startup #17285 #15044 #11330', function()
+ local screen = Screen.new(50, 10)
+ screen:set_default_attr_ids({
+ [1] = {reverse = true},
+ [2] = {bold = true, foreground = Screen.colors.Blue},
+ [3] = {bold = true},
+ [4] = {foreground = tonumber('0x4040ff'), fg_indexed = true},
+ [5] = {bold = true, reverse = true},
+ })
+ screen:attach()
+ exec([[
+ call termopen([v:progpath, '--clean', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile'])
+ sleep 500m
+ vs new
+ ]])
+ screen:expect([[
+ ^ │ |
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{4:~ }|
+ {2:~ }│{5:[No Name] 0,0-1 All}|
+ {2:~ }│ |
+ {5:new }{MATCH:<.*[/\]nvim }|
+ |
+ ]])
+ end)
+
it('with non-tty (pipe) stdout/stderr', function()
local screen = thelpers.screen_setup(0, '"'..nvim_prog
..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"')
@@ -1212,6 +1561,15 @@ describe('TUI', function()
it('<C-h> #10134', function()
local screen = thelpers.screen_setup(0, '["'..nvim_prog
..[[", "-u", "NONE", "-i", "NONE", "--cmd", "set noruler", "--cmd", ':nnoremap <C-h> :echomsg "\<C-h\>"<CR>']]..']')
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
command([[call chansend(b:terminal_job_id, "\<C-h>")]])
screen:expect([[
@@ -1238,6 +1596,15 @@ describe('TUI UIEnter/UILeave', function()
..[[, "--cmd", "autocmd VimEnter * :call add(g:evs, 'VimEnter')"]]
..']'
)
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data(":echo g:evs\n")
screen:expect{grid=[[
{1: } |
@@ -1258,61 +1625,88 @@ describe('TUI FocusGained/FocusLost', function()
clear()
screen = thelpers.screen_setup(0, '["'..nvim_prog
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]')
- feed_data(":autocmd FocusGained * echo 'gained'\n")
- feed_data(":autocmd FocusLost * echo 'lost'\n")
- feed_data("\034\016") -- CTRL-\ CTRL-N
- end)
-
- it('in normal-mode', function()
- retry(2, 3 * screen.timeout, function()
- feed_data('\027[I')
- screen:expect([[
+ screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
- gained |
+ |
{3:-- TERMINAL --} |
- ]])
+ ]]}
+ feed_data(":autocmd FocusGained * echo 'gained'\n")
+ feed_data(":autocmd FocusLost * echo 'lost'\n")
+ feed_data("\034\016") -- CTRL-\ CTRL-N
+ end)
- feed_data('\027[O')
- screen:expect([[
+ it('in normal-mode', function()
+ screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
- lost |
+ :autocmd FocusLost * echo 'lost' |
{3:-- TERMINAL --} |
- ]])
+ ]]}
+ retry(2, 3 * screen.timeout, function()
+ feed_data('\027[I')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ gained |
+ {3:-- TERMINAL --} |
+ ]])
+
+ feed_data('\027[O')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ lost |
+ {3:-- TERMINAL --} |
+ ]])
end)
end)
it('in insert-mode', function()
feed_command('set noshowmode')
feed_data('i')
- retry(2, 3 * screen.timeout, function()
- feed_data('\027[I')
- screen:expect([[
- {1: } |
- {4:~ }|
- {4:~ }|
- {4:~ }|
- {5:[No Name] }|
- gained |
- {3:-- TERMINAL --} |
- ]])
- feed_data('\027[O')
- screen:expect([[
+ screen:expect{grid=[[
{1: } |
{4:~ }|
{4:~ }|
{4:~ }|
{5:[No Name] }|
- lost |
+ :set noshowmode |
{3:-- TERMINAL --} |
- ]])
+ ]]}
+ retry(2, 3 * screen.timeout, function()
+ feed_data('\027[I')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ gained |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data('\027[O')
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ lost |
+ {3:-- TERMINAL --} |
+ ]])
end)
end)
@@ -1349,6 +1743,15 @@ describe('TUI FocusGained/FocusLost', function()
feed_data(":autocmd!\n")
feed_data(":autocmd FocusLost * call append(line('$'), 'lost')\n")
feed_data(":autocmd FocusGained * call append(line('$'), 'gained')\n")
+ screen:expect{grid=[[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
retry(2, 3 * screen.timeout, function()
-- Enter cmdline-mode.
feed_data(':')
@@ -1407,9 +1810,18 @@ describe('TUI FocusGained/FocusLost', function()
feed_data(":echom 'msg1'|echom 'msg2'|echom 'msg3'|echom 'msg4'|echom 'msg5'\n")
-- Execute :messages to provoke the press-enter prompt.
feed_data(":messages\n")
+ screen:expect{grid=[[
+ msg1 |
+ msg2 |
+ msg3 |
+ msg4 |
+ msg5 |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data('\027[I')
feed_data('\027[I')
- screen:expect([[
+ screen:expect{grid=[[
msg1 |
msg2 |
msg3 |
@@ -1417,7 +1829,7 @@ describe('TUI FocusGained/FocusLost', function()
msg5 |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
- ]])
+ ]], unchanged=true}
end)
end)
@@ -1425,7 +1837,6 @@ end)
-- does not initialize the TUI.
describe("TUI 't_Co' (terminal colors)", function()
local screen
- local is_freebsd = (uname() == 'freebsd')
local function assert_term_colors(term, colorterm, maxcolors)
helpers.clear({env={TERM=term}, args={}})
@@ -1528,7 +1939,7 @@ describe("TUI 't_Co' (terminal colors)", function()
-- which is raised to 16 by COLORTERM.
it("TERM=screen no COLORTERM uses 8/256 colors", function()
- if is_freebsd then
+ if is_os('freebsd') then
assert_term_colors("screen", nil, 256)
else
assert_term_colors("screen", nil, 8)
@@ -1536,7 +1947,7 @@ describe("TUI 't_Co' (terminal colors)", function()
end)
it("TERM=screen COLORTERM=screen uses 16/256 colors", function()
- if is_freebsd then
+ if is_os('freebsd') then
assert_term_colors("screen", "screen", 256)
else
assert_term_colors("screen", "screen", 16)
@@ -1699,8 +2110,6 @@ end)
-- does not initialize the TUI.
describe("TUI 'term' option", function()
local screen
- local is_bsd = not not string.find(uname(), 'bsd')
- local is_macos = not not string.find(uname(), 'darwin')
local function assert_term(term_envvar, term_expected)
clear()
@@ -1726,11 +2135,11 @@ describe("TUI 'term' option", function()
end)
it('gets system-provided term if $TERM is valid', function()
- if uname() == "openbsd" then
+ if is_os('openbsd') then
assert_term("xterm", "xterm")
- elseif is_bsd then -- BSD lacks terminfo, builtin is always used.
+ elseif is_os('bsd') then -- BSD lacks terminfo, builtin is always used.
assert_term("xterm", "builtin_xterm")
- elseif is_macos then
+ elseif is_os('mac') then
local status, _ = pcall(assert_term, "xterm", "xterm")
if not status then
pending("macOS: unibilium could not find terminfo")
@@ -1788,7 +2197,7 @@ describe("TUI", function()
retry(nil, 3000, function() -- Wait for log file to be flushed.
local log = read_file('Xtest_tui_verbose_log') or ''
- eq('--- Terminal info --- {{{\n', string.match(log, '%-%-%- Terminal.-\n'))
+ eq('--- Terminal info --- {{{\n', string.match(log, '%-%-%- Terminal.-\n')) -- }}}
ok(#log > 50)
end)
end)
@@ -1912,3 +2321,163 @@ describe('TUI bg color', function()
screen:expect{any='new_bg=dark'}
end)
end)
+
+-- These tests require `thelpers` because --headless/--embed
+-- does not initialize the TUI.
+describe("TUI as a client", function()
+
+ it("connects to remote instance (with its own TUI)", function()
+ local server_super = spawn_argv(false) -- equivalent to clear()
+ local client_super = spawn_argv(true)
+
+ set_session(server_super)
+ local server_pipe = new_pipename()
+ local screen_server = thelpers.screen_setup(0,
+ string.format([=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark"]]=],
+ nvim_prog, server_pipe, nvim_set))
+
+ feed_data("iHello, World")
+ screen_server:expect{grid=[[
+ Hello, World{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
+ feed_data("\027")
+ screen_server:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ set_session(client_super)
+ local screen_client = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ nvim_prog, server_pipe))
+
+ screen_client:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ feed_data(":q!\n")
+
+ server_super:close()
+ client_super:close()
+ end)
+
+ it("connects to remote instance (--headless)", function()
+ local server = helpers.spawn_argv(false) -- equivalent to clear()
+ local client_super = spawn_argv(true)
+
+ set_session(server)
+ local server_pipe = eval'v:servername'
+ feed'iHalloj!<esc>'
+
+ set_session(client_super)
+ local screen = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ nvim_prog, server_pipe))
+
+ screen:expect{grid=[[
+ Halloj{1:!} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ client_super:close()
+ server:close()
+ end)
+
+
+ it("throws error when no server exists", function()
+ clear()
+ local screen = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "127.0.0.1:2436546", "--remote-ui"]]=],
+ nvim_prog), 60)
+
+ screen:expect([[
+ Remote ui failed to start: {MATCH:.*}|
+ |
+ [Process exited 1]{1: } |
+ |
+ |
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
+ it("exits when server quits", function()
+ local server_super = spawn_argv(false) -- equivalent to clear()
+ local client_super = spawn_argv(true)
+
+ set_session(server_super)
+ local server_pipe = new_pipename()
+ local screen_server = thelpers.screen_setup(0,
+ string.format([=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "%s laststatus=2 background=dark"]]=],
+ nvim_prog, server_pipe, nvim_set))
+
+ feed_data("iHello, World")
+ screen_server:expect{grid=[[
+ Hello, World{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]]}
+ feed_data("\027")
+ screen_server:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ set_session(client_super)
+ local screen_client = thelpers.screen_setup(0,
+ string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=],
+ nvim_prog, server_pipe))
+
+ screen_client:expect{grid=[[
+ Hello, Worl{1:d} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ -- quitting the server
+ set_session(server_super)
+ feed_data(":q!\n")
+ screen_server:expect({any="Process exited 0"})
+
+ -- assert that client has exited
+ screen_client:expect({any="Process exited 0"})
+
+ server_super:close()
+ client_super:close()
+ end)
+end)
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index 0d3295cf32..80e9d78400 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -3,11 +3,12 @@ local thelpers = require('test.functional.terminal.helpers')
local feed_data = thelpers.feed_data
local feed, clear = helpers.feed, helpers.clear
local poke_eventloop = helpers.poke_eventloop
-local iswin = helpers.iswin
local command = helpers.command
local retry = helpers.retry
local eq = helpers.eq
local eval = helpers.eval
+local skip = helpers.skip
+local is_os = helpers.is_os
describe(':terminal window', function()
local screen
@@ -18,7 +19,7 @@ describe(':terminal window', function()
end)
it('sets topline correctly #8556', function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
-- Test has hardcoded assumptions of dimensions.
eq(7, eval('&lines'))
feed_data('\n\n\n') -- Add blank lines.
@@ -54,9 +55,7 @@ describe(':terminal window', function()
{3:-- TERMINAL --} |
]])
- if iswin() then
- return -- win: :terminal resize is unreliable #7007
- end
+ skip(is_os('win'), 'win: :terminal resize is unreliable #7007')
-- numberwidth=9
feed([[<C-\><C-N>]])
@@ -172,7 +171,7 @@ describe(':terminal with multigrid', function()
]])
screen:try_resize_grid(2, 20, 10)
- if iswin() then
+ if is_os('win') then
screen:expect{any="rows: 10, cols: 20"}
else
screen:expect([[
@@ -201,7 +200,7 @@ describe(':terminal with multigrid', function()
end
screen:try_resize_grid(2, 70, 3)
- if iswin() then
+ if is_os('win') then
screen:expect{any="rows: 3, cols: 70"}
else
screen:expect([[
@@ -223,7 +222,7 @@ describe(':terminal with multigrid', function()
end
screen:try_resize_grid(2, 0, 0)
- if iswin() then
+ if is_os('win') then
screen:expect{any="rows: 6, cols: 50"}
else
screen:expect([[
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index b62d173cea..1d77e1e92e 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -8,9 +8,9 @@ local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
local meths = helpers.meths
-local iswin = helpers.iswin
local sleep = helpers.sleep
local retry = helpers.retry
+local is_os = helpers.is_os
describe(':terminal', function()
local screen
@@ -96,7 +96,7 @@ describe(':terminal', function()
local w1, h1 = screen._width - 3, screen._height - 2
local w2, h2 = w1 - 6, h1 - 3
- if iswin() then
+ if is_os('win') then
-- win: SIGWINCH is unreliable, use a weaker test. #7506
retry(3, 30000, function()
screen:try_resize(w1, h1)
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 5ec0a8a060..2a2311c0fa 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -5,12 +5,14 @@ local clear = helpers.clear
local insert = helpers.insert
local exec_lua = helpers.exec_lua
local feed = helpers.feed
-local pending_c_parser = helpers.pending_c_parser
+local command = helpers.command
+local meths = helpers.meths
+local eq = helpers.eq
before_each(clear)
local hl_query = [[
- (ERROR) @ErrorMsg
+ (ERROR) @error
"if" @keyword
"else" @keyword
@@ -23,23 +25,24 @@ local hl_query = [[
"enum" @type
"extern" @type
- (string_literal) @string.nonexistent-specializer-for-string.should-fallback-to-string
+ ; nonexistent specializer for string should fallback to string
+ (string_literal) @string.nonexistent_specializer
(number_literal) @number
(char_literal) @string
(type_identifier) @type
- ((type_identifier) @Special (#eq? @Special "LuaRef"))
+ ((type_identifier) @constant.builtin (#eq? @constant.builtin "LuaRef"))
(primitive_type) @type
(sized_type_specifier) @type
; Use lua regexes
- ((identifier) @Identifier (#contains? @Identifier "lua_"))
+ ((identifier) @function (#contains? @function "lua_"))
((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$"))
- ((identifier) @Normal (#vim-match? @Constant "^lstate$"))
+ ((identifier) @Normal (#vim-match? @Normal "^lstate$"))
- ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right))
+ ((binary_expression left: (identifier) @warning.left right: (identifier) @warning.right) (#eq? @warning.left @warning.right))
(comment) @comment
]]
@@ -103,11 +106,11 @@ describe('treesitter highlighting', function()
}
exec_lua([[ hl_query = ... ]], hl_query)
+ command [[ hi link @error ErrorMsg ]]
+ command [[ hi link @warning WarningMsg ]]
end)
it('is updated with edits', function()
- if pending_c_parser(pending) then return end
-
insert(hl_text)
screen:expect{grid=[[
/// Schedule Lua callback on main loop's event queue |
@@ -271,8 +274,6 @@ describe('treesitter highlighting', function()
end)
it('is updated with :sort', function()
- if pending_c_parser(pending) then return end
-
insert(test_text)
exec_lua [[
local parser = vim.treesitter.get_parser(0, "c")
@@ -346,8 +347,6 @@ describe('treesitter highlighting', function()
end)
it("supports with custom parser", function()
- if pending_c_parser(pending) then return end
-
screen:set_default_attr_ids {
[1] = {bold = true, foreground = Screen.colors.SeaGreen4};
}
@@ -412,8 +411,6 @@ describe('treesitter highlighting', function()
end)
it("supports injected languages", function()
- if pending_c_parser(pending) then return end
-
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
@@ -474,8 +471,6 @@ describe('treesitter highlighting', function()
end)
it("supports overriding queries, like ", function()
- if pending_c_parser(pending) then return end
-
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
@@ -515,8 +510,6 @@ describe('treesitter highlighting', function()
end)
it("supports highlighting with custom highlight groups", function()
- if pending_c_parser(pending) then return end
-
insert(hl_text)
exec_lua [[
@@ -547,7 +540,7 @@ describe('treesitter highlighting', function()
-- This will change ONLY the literal strings to look like comments
-- The only literal string is the "vim.schedule: expected function" in this test.
- exec_lua [[vim.cmd("highlight link cString comment")]]
+ exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]]
screen:expect{grid=[[
{2:/// Schedule Lua callback on main loop's event queue} |
{3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
@@ -572,8 +565,6 @@ describe('treesitter highlighting', function()
end)
it("supports highlighting with priority", function()
- if pending_c_parser(pending) then return end
-
insert([[
int x = INT_MAX;
#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
@@ -589,9 +580,9 @@ describe('treesitter highlighting', function()
-- expect everything to have Error highlight
screen:expect{grid=[[
{12:int}{8: x = INT_MAX;} |
- {8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}|
- {8:#define foo void main() { \} |
- {8: return 42; \} |
+ {8:#define READ_STRING(x, y) (}{12:char_u}{8: *)read_string((x), (}{12:size_t}{8:)(y))}|
+ {8:#define foo }{12:void}{8: main() { \} |
+ {8: }{12:return}{8: 42; \} |
{8: }} |
^ |
{1:~ }|
@@ -612,11 +603,14 @@ describe('treesitter highlighting', function()
-- bold will not be overwritten at the moment
[12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Grey100};
}}
+
+ eq({
+ {capture='Error', metadata = { priority='101' }, lang='c' };
+ {capture='type', metadata = { }, lang='c' };
+ }, exec_lua [[ return vim.treesitter.get_captures_at_pos(0, 0, 2) ]])
end)
it("allows to use captures with dots (don't use fallback when specialization of foo exists)", function()
- if pending_c_parser(pending) then return end
-
insert([[
char* x = "Will somebody ever read this?";
]])
@@ -642,11 +636,13 @@ describe('treesitter highlighting', function()
|
]]}
+ command [[
+ hi link @foo.bar Type
+ hi link @foo String
+ ]]
exec_lua [[
local parser = vim.treesitter.get_parser(0, "c", {})
local highlighter = vim.treesitter.highlighter
- highlighter.hl_map['foo.bar'] = 'Type'
- highlighter.hl_map['foo'] = 'String'
test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}})
]]
@@ -670,10 +666,32 @@ describe('treesitter highlighting', function()
{1:~ }|
|
]]}
+
+ -- clearing specialization reactivates fallback
+ command [[ hi clear @foo.bar ]]
+ screen:expect{grid=[[
+ {5:char}* x = {5:"Will somebody ever read this?"}; |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
end)
it("supports conceal attribute", function()
- if pending_c_parser(pending) then return end
insert(hl_text)
-- conceal can be empty or a single cchar.
@@ -712,32 +730,26 @@ describe('treesitter highlighting', function()
]]}
end)
- it("hl_map has the correct fallback behavior", function()
- exec_lua [[
- local hl_map = vim.treesitter.highlighter.hl_map
- hl_map["foo"] = 1
- hl_map["foo.bar"] = 2
- hl_map["foo.bar.baz"] = 3
-
- assert(hl_map["foo"] == 1)
- assert(hl_map["foo.a.b.c.d"] == 1)
- assert(hl_map["foo.bar"] == 2)
- assert(hl_map["foo.bar.a.b.c.d"] == 2)
- assert(hl_map["foo.bar.baz"] == 3)
- assert(hl_map["foo.bar.baz.d"] == 3)
-
- hl_map["FOO"] = 1
- hl_map["FOO.BAR"] = 2
- assert(hl_map["FOO.BAR.BAZ"] == 2)
-
- hl_map["foo.missing.exists"] = 3
- assert(hl_map["foo.missing"] == 1)
- assert(hl_map["foo.missing.exists"] == 3)
- assert(hl_map["foo.missing.exists.bar"] == 3)
- assert(hl_map["total.nonsense.but.a.lot.of.dots"] == nil)
- -- It will not perform a second look up of this variable but return a sentinel value
- assert(hl_map["total.nonsense.but.a.lot.of.dots"] == "__notfound")
- ]]
-
+ it("@foo.bar groups has the correct fallback behavior", function()
+ local get_hl = function(name) return meths.get_hl_by_name(name,1).foreground end
+ meths.set_hl(0, "@foo", {fg = 1})
+ meths.set_hl(0, "@foo.bar", {fg = 2})
+ meths.set_hl(0, "@foo.bar.baz", {fg = 3})
+
+ eq(1, get_hl"@foo")
+ eq(1, get_hl"@foo.a.b.c.d")
+ eq(2, get_hl"@foo.bar")
+ eq(2, get_hl"@foo.bar.a.b.c.d")
+ eq(3, get_hl"@foo.bar.baz")
+ eq(3, get_hl"@foo.bar.baz.d")
+
+ -- lookup is case insensitive
+ eq(2, get_hl"@FOO.BAR.SPAM")
+
+ meths.set_hl(0, "@foo.missing.exists", {fg = 3})
+ eq(1, get_hl"@foo.missing")
+ eq(3, get_hl"@foo.missing.exists")
+ eq(3, get_hl"@foo.missing.exists.bar")
+ eq(nil, get_hl"@total.nonsense.but.a.lot.of.dots")
end)
end)
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index 30585be328..f95b05a1cc 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -6,31 +6,32 @@ local command = helpers.command
local exec_lua = helpers.exec_lua
local pcall_err = helpers.pcall_err
local matches = helpers.matches
-local pending_c_parser = helpers.pending_c_parser
+local insert = helpers.insert
before_each(clear)
-describe('treesitter API', function()
+describe('treesitter language API', function()
-- error tests not requiring a parser library
it('handles missing language', function()
- eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')"))
-- actual message depends on platform
- matches("Error executing lua: Failed to load parser: uv_dlopen: .+",
+ matches("Failed to load parser for language 'borklang': uv_dlopen: .+",
pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')"))
-- Should not throw an error when silent
eq(false, exec_lua("return vim.treesitter.require_language('borklang', nil, true)"))
eq(false, exec_lua("return vim.treesitter.require_language('borklang', 'borkbork.so', true)"))
- eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')"))
+
+ matches("Failed to load parser: uv_dlsym: .+",
+ pcall_err(exec_lua, 'vim.treesitter.require_language("c", nil, false, "borklang")'))
end)
it('inspects language', function()
- if pending_c_parser(pending) then return end
-
local keys, fields, symbols = unpack(exec_lua([[
local lang = vim.treesitter.inspect_language('c')
local keys, symbols = {}, {}
@@ -70,14 +71,41 @@ describe('treesitter API', function()
end)
it('checks if vim.treesitter.get_parser tries to create a new parser on filetype change', function ()
- if pending_c_parser(pending) then return end
command("set filetype=c")
-- Should not throw an error when filetype is c
eq('c', exec_lua("return vim.treesitter.get_parser(0):lang()"))
command("set filetype=borklang")
-- Should throw an error when filetype changes to borklang
- eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0)"))
end)
+
+ it('retrieve the tree given a range', function ()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua([[
+ langtree = vim.treesitter.get_parser(0, "c")
+ tree = langtree:tree_for_range({1, 3, 1, 3})
+ ]])
+
+ eq('<node translation_unit>', exec_lua('return tostring(tree:root())'))
+ end)
+
+ it('retrieve the node given a range', function ()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua([[
+ langtree = vim.treesitter.get_parser(0, "c")
+ node = langtree:named_node_for_range({1, 3, 1, 3})
+ ]])
+
+ eq('<node primitive_type>', exec_lua('return tostring(node)'))
+ end)
end)
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index 21c287644e..a82dce47b7 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -4,7 +4,6 @@ local clear = helpers.clear
local eq = helpers.eq
local exec_lua = helpers.exec_lua
local insert = helpers.insert
-local pending_c_parser = helpers.pending_c_parser
before_each(clear)
@@ -15,10 +14,6 @@ end
describe('treesitter node API', function()
clear()
- if pending_c_parser(pending) then
- return
- end
-
it('can move between siblings', function()
insert([[
int main(int x, int y, int z) {
@@ -59,4 +54,53 @@ describe('treesitter node API', function()
exec_lua 'node = node:prev_named_sibling()'
eq('int x', lua_eval('node_text(node)'))
end)
+
+ it('can retrieve the children of a node', function()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ local len = exec_lua([[
+ tree = vim.treesitter.get_parser(0, "c"):parse()[1]
+ node = tree:root():child(0)
+ children = node:named_children()
+
+ return #children
+ ]])
+
+ eq(3, len)
+ eq('<node compound_statement>', lua_eval('tostring(children[3])'))
+ end)
+
+ it('can retrieve the tree root given a node', function()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua([[
+ tree = vim.treesitter.get_parser(0, "c"):parse()[1]
+ root = tree:root()
+ node = root:child(0):child(2)
+ ]])
+
+ eq(lua_eval('tostring(root)'), lua_eval('tostring(node:root())'))
+ end)
+
+ it('can compute the byte length of a node', function()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua([[
+ tree = vim.treesitter.get_parser(0, "c"):parse()[1]
+ root = tree:root()
+ child = root:child(0):child(0)
+ ]])
+
+ eq(28, lua_eval('root:byte_length()'))
+ eq(3, lua_eval('child:byte_length()'))
+ end)
end)
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 7f3b0e770a..f006ad4539 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -5,17 +5,15 @@ local eq = helpers.eq
local insert = helpers.insert
local exec_lua = helpers.exec_lua
local feed = helpers.feed
-local pending_c_parser = helpers.pending_c_parser
+local is_os = helpers.is_os
+local skip = helpers.skip
before_each(clear)
describe('treesitter parser API', function()
clear()
- if pending_c_parser(pending) then return end
it('parses buffer', function()
- if helpers.pending_win32(pending) then return end
-
insert([[
int main() {
int x = 3;
@@ -249,7 +247,6 @@ void ui_refresh(void)
end)
it('supports getting text of multiline node', function()
- if pending_c_parser(pending) then return end
insert(test_text)
local res = exec_lua([[
local parser = vim.treesitter.get_parser(0, "c")
@@ -687,7 +684,7 @@ int x = INT_MAX;
end)
it("should not inject bad languages", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
exec_lua([=[
vim.treesitter.add_directive("inject-bad!", function(match, _, _, pred, metadata)
metadata.language = "{"
diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua
new file mode 100644
index 0000000000..7f5a864c3d
--- /dev/null
+++ b/test/functional/treesitter/utils_spec.lua
@@ -0,0 +1,31 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local insert = helpers.insert
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+
+before_each(clear)
+
+describe('treesitter utils', function()
+ before_each(clear)
+
+ it('can find an ancestor', function()
+
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua([[
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ root = tree:root()
+ ancestor = root:child(0)
+ child = ancestor:child(0)
+ ]])
+
+ eq(true, exec_lua('return vim.treesitter.is_ancestor(ancestor, child)'))
+ eq(false, exec_lua('return vim.treesitter.is_ancestor(child, ancestor)'))
+ end)
+end)
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 7c0831bd09..46bfae8de2 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -762,7 +762,7 @@ describe('Buffer highlighting', function()
local s1 = {{'Köttbullar', 'Comment'}, {'Kräuterbutter'}}
local s2 = {{'こんにちは', 'Comment'}}
- -- TODO: only a virtual text from the same ns curretly overrides
+ -- TODO: only a virtual text from the same ns currently overrides
-- an existing virtual text. We might add a prioritation system.
set_virtual_text(id1, 0, s1, {})
eq({{1, 0, 0, {
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index fa5771a8b3..eb5de693bd 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -61,7 +61,7 @@ before_each(function()
endwhile
return ret
endfunction
- function SplittedMultibyteStart(cmdline)
+ function SplitMultibyteStart(cmdline)
let ret = []
let i = 0
while i < len(a:cmdline)
@@ -77,7 +77,7 @@ before_each(function()
endwhile
return ret
endfunction
- function SplittedMultibyteEnd(cmdline)
+ function SplitMultibyteEnd(cmdline)
let ret = []
let i = 0
while i < len(a:cmdline)
@@ -296,7 +296,7 @@ describe('Command-line coloring', function()
end
it('does the right thing when hl start appears to split multibyte char',
function()
- set_color_cb('SplittedMultibyteStart')
+ set_color_cb('SplitMultibyteStart')
start_prompt('echo "«')
screen:expect{grid=[[
|
@@ -322,7 +322,7 @@ describe('Command-line coloring', function()
end)
it('does the right thing when hl end appears to split multibyte char',
function()
- set_color_cb('SplittedMultibyteEnd')
+ set_color_cb('SplitMultibyteEnd')
start_prompt('echo "«')
screen:expect([[
|
@@ -335,17 +335,17 @@ describe('Command-line coloring', function()
:echo "«^ |
]])
end)
- it('does the right thing when errorring', function()
+ it('does the right thing when erroring', function()
set_color_cb('Echoerring')
start_prompt('e')
screen:expect([[
|
{EOB:~ }|
- {EOB:~ }|
{MSEP: }|
: |
{ERR:E5407: Callback has thrown an exception:}|
- {ERR: Vim(echoerr):HERE} |
+ {ERR: function DoPrompt[3]..Echoerring, line }|
+ {ERR:1: Vim(echoerr):HERE} |
:e^ |
]])
end)
@@ -400,16 +400,16 @@ describe('Command-line coloring', function()
screen:expect([[
|
{EOB:~ }|
- {EOB:~ }|
{MSEP: }|
: |
{ERR:E5407: Callback has thrown an exception:}|
+ {ERR: function DoPrompt[3]..Throwing, line 1:}|
{ERR: ABC} |
:e^ |
]])
end)
it('stops executing callback after a number of errors', function()
- set_color_cb('SplittedMultibyteStart')
+ set_color_cb('SplitMultibyteStart')
start_prompt('let x = "«»«»«»«»«»"')
screen:expect([[
|
@@ -772,7 +772,7 @@ describe('Ex commands coloring', function()
]])
end)
it('still executes command-line even if errored out', function()
- meths.set_var('Nvim_color_cmdline', 'SplittedMultibyteStart')
+ meths.set_var('Nvim_color_cmdline', 'SplitMultibyteStart')
feed(':let x = "«"\n')
eq('«', meths.get_var('x'))
local msg = 'E5405: Chunk 0 start 10 splits multibyte character'
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index db13647cc6..1c9ac7f7ba 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -4,9 +4,12 @@ local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local command = helpers.command
local assert_alive = helpers.assert_alive
-local uname = helpers.uname
+local poke_eventloop = helpers.poke_eventloop
+local exec = helpers.exec
local eval = helpers.eval
local eq = helpers.eq
+local is_os = helpers.is_os
+local meths = helpers.meths
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -716,7 +719,7 @@ describe('cmdline redraw', function()
end)
it('with <Cmd>', function()
- if string.find(uname(), 'bsd') then
+ if is_os('bsd') then
pending('FIXME #10804')
end
command('cmap a <Cmd>call sin(0)<CR>') -- no-op
@@ -821,16 +824,27 @@ describe('statusline is redrawn on entering cmdline', function()
]]}
end)
- it('but not with scrolled messages', function()
- command('set statusline=%{mode()}')
- screen:try_resize(35,10)
+ it('with scrolled messages', function()
+ screen:try_resize(35,14)
+ exec([[
+ let g:count = 0
+ autocmd CmdlineEnter * let g:count += 1
+ split
+ resize 1
+ setlocal statusline=%{mode()}%{g:count}
+ setlocal winbar=%{mode()}%{g:count}
+ ]])
feed(':echoerr doesnotexist<cr>')
screen:expect{grid=[[
+ {9:c1 }|
+ |
+ {3:c1 }|
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
+ {1:~ }|
{3: }|
{4:E121: Undefined variable: doesnotex}|
{4:ist} |
@@ -839,8 +853,12 @@ describe('statusline is redrawn on entering cmdline', function()
]]}
feed(':echoerr doesnotexist<cr>')
screen:expect{grid=[[
+ {9:c2 }|
+ |
+ {3:c2 }|
|
{1:~ }|
+ {1:~ }|
{3: }|
{4:E121: Undefined variable: doesnotex}|
{4:ist} |
@@ -853,6 +871,10 @@ describe('statusline is redrawn on entering cmdline', function()
feed(':echoerr doesnotexist<cr>')
screen:expect{grid=[[
+ {9:c3 }|
+ |
+ {3:c3 }|
+ {3: }|
{4:E121: Undefined variable: doesnotex}|
{4:ist} |
{5:Press ENTER or type command to cont}|
@@ -867,7 +889,10 @@ describe('statusline is redrawn on entering cmdline', function()
feed('<cr>')
screen:expect{grid=[[
+ {9:n3 }|
^ |
+ {3:n3 }|
+ |
{1:~ }|
{1:~ }|
{1:~ }|
@@ -875,7 +900,8 @@ describe('statusline is redrawn on entering cmdline', function()
{1:~ }|
{1:~ }|
{1:~ }|
- {3:n }|
+ {1:~ }|
+ {2:[No Name] }|
|
]]}
end)
@@ -934,6 +960,15 @@ describe('cmdheight=0', function()
before_each(function()
clear()
screen = Screen.new(25, 5)
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue};
+ [2] = {bold = true, reverse = true};
+ [3] = {bold = true};
+ [4] = {foreground = Screen.colors.White, background = Screen.colors.Red};
+ [5] = {foreground = Screen.colors.SeaGreen4, bold = true};
+ [6] = {reverse = true};
+ [7] = {background = Screen.colors.Yellow};
+ }
screen:attach()
end)
@@ -941,9 +976,9 @@ describe('cmdheight=0', function()
command("set cmdheight=1 noruler laststatus=2")
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- [No Name] |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
|
]]}
end)
@@ -952,10 +987,10 @@ describe('cmdheight=0', function()
command("set cmdheight=0 noruler laststatus=2")
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- [No Name] |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
]]}
end)
@@ -963,10 +998,10 @@ describe('cmdheight=0', function()
command("set cmdheight=0 ruler laststatus=0")
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
]]}
end)
@@ -975,10 +1010,10 @@ describe('cmdheight=0', function()
feed('i')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
]], showmode={}}
feed('<Esc>')
eq(0, eval('&cmdheight'))
@@ -989,10 +1024,10 @@ describe('cmdheight=0', function()
feed('i')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
]], showmode={}}
feed('<Esc>')
eq(0, eval('&cmdheight'))
@@ -1003,10 +1038,10 @@ describe('cmdheight=0', function()
feed('i')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- -- INSERT -- |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:-- INSERT --} |
]]}
feed('<Esc>')
eq(1, eval('&cmdheight'))
@@ -1017,19 +1052,19 @@ describe('cmdheight=0', function()
feed(':')
screen:expect{grid=[[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
:^ |
]]}
- eq(1, eval('&cmdheight'))
+ eq(0, eval('&cmdheight'))
feed('<cr>')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
]], showmode={}}
eq(0, eval('&cmdheight'))
end)
@@ -1039,19 +1074,19 @@ describe('cmdheight=0', function()
feed(':call input("foo >")<cr>')
screen:expect{grid=[[
|
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {2: }|
+ :call input("foo >") |
foo >^ |
]]}
- eq(1, eval('&cmdheight'))
+ eq(0, eval('&cmdheight'))
feed('<cr>')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
]], showmode={}}
eq(0, eval('&cmdheight'))
end)
@@ -1060,35 +1095,35 @@ describe('cmdheight=0', function()
command("set cmdheight=0 noruler laststatus=3 winbar=foo")
feed(':split<CR>')
screen:expect{grid=[[
- foo |
- |
- E36: Not enough room |
- Press ENTER or type comma|
- nd to continue^ |
+ {2: }|
+ :split |
+ {4:E36: Not enough room} |
+ {5:Press ENTER or type comma}|
+ {5:nd to continue}^ |
]]}
feed('<CR>')
screen:expect{grid=[[
- foo |
+ {3:foo }|
^ |
- ~ |
- ~ |
- [No Name] |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
]]}
feed(':')
screen:expect{grid=[[
- foo |
+ {3:foo }|
|
- ~ |
- [No Name] |
+ {1:~ }|
+ {1:~ }|
:^ |
]]}
feed('<Esc>')
screen:expect{grid=[[
- foo |
+ {3:foo }|
^ |
- ~ |
- ~ |
- [No Name] |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
]], showmode={}}
eq(0, eval('&cmdheight'))
@@ -1100,19 +1135,19 @@ describe('cmdheight=0', function()
feed('qq')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- recording @q |
- ]], showmode={}}
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
feed('q')
screen:expect{grid=[[
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ]], showmode={}}
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], unchanged=true}
end)
it("when substitute text", function()
@@ -1120,28 +1155,28 @@ describe('cmdheight=0', function()
feed('ifoo<ESC>')
screen:expect{grid=[[
fo^o |
- ~ |
- ~ |
- ~ |
- [No Name] [+] |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] }|
]]}
feed(':%s/foo/bar/gc<CR>')
screen:expect{grid=[[
- foo |
- ~ |
- ~ |
- [No Name] [+] |
- replace wi...q/l/^E/^Y)?^ |
+ {6:foo} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {5:replace wi...q/l/^E/^Y)?}^ |
]]}
feed('y')
screen:expect{grid=[[
^bar |
- ~ |
- ~ |
- ~ |
- [No Name] [+] |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] }|
]]}
assert_alive()
@@ -1152,4 +1187,223 @@ describe('cmdheight=0', function()
feed('<C-w>+')
eq(0, eval('&cmdheight'))
end)
+
+ it("with non-silent mappings with cmdline", function()
+ command("set cmdheight=0")
+ command("map <f3> :nohlsearch<cr>")
+ feed('iaabbaa<esc>/aa<cr>')
+ screen:expect{grid=[[
+ {7:^aa}bb{7:aa} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+
+ feed('<f3>')
+ screen:expect{grid=[[
+ ^aabbaa |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+ end)
+
+ it('with silent! at startup', function()
+ clear{args={'-c', 'set cmdheight=0', '-c', 'autocmd VimEnter * silent! call Foo()'}}
+ screen:attach()
+ -- doesn't crash while not displaying silent! error message
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+ end)
+
+ it('with multigrid', function()
+ clear{args={'--cmd', 'set cmdheight=0'}}
+ screen:attach{ext_multigrid=true}
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+
+ feed '/p'
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ /p^ |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ end)
+
+ it('winbar is redrawn on entering cmdline and :redrawstatus #20336', function()
+ exec([[
+ set cmdheight=0
+ set winbar=%{mode()}%=:%{getcmdline()}
+ ]])
+ feed(':')
+ screen:expect([[
+ {3:c :}|
+ |
+ {1:~ }|
+ {1:~ }|
+ :^ |
+ ]])
+ feed('echo')
+ -- not redrawn yet
+ screen:expect([[
+ {3:c :}|
+ |
+ {1:~ }|
+ {1:~ }|
+ :echo^ |
+ ]])
+ command('redrawstatus')
+ screen:expect([[
+ {3:c :echo}|
+ |
+ {1:~ }|
+ {1:~ }|
+ :echo^ |
+ ]])
+ end)
+
+ it('window equalization with laststatus=0 #20367', function()
+ screen:try_resize(60, 9)
+ command('set cmdheight=0 laststatus=0')
+ command('vsplit')
+ screen:expect([[
+ ^ │ |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ ]])
+ feed(':')
+ command('split')
+ feed('<Esc>')
+ screen:expect([[
+ ^ │ |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] }│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ ]])
+ command('resize 2')
+ screen:expect([[
+ ^ │ |
+ {1:~ }│{1:~ }|
+ {2:[No Name] }│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ ]])
+ feed(':')
+ command('wincmd =')
+ feed('<Esc>')
+ screen:expect([[
+ ^ │ |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] }│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ ]])
+ end)
+
+ it('no assert failure with showcmd', function()
+ command('set showcmd cmdheight=0')
+ feed('d')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+ assert_alive()
+ end)
+
+ it('can only be resized to 0 if set explicitly', function()
+ command('set laststatus=2')
+ command('resize +1')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+ command('set cmdheight=0')
+ command('resize -1')
+ command('resize +1')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ ]])
+ end)
+
+ it("cannot be resized at all with external messages", function()
+ clear()
+ screen = new_screen({rgb=true, ext_messages=true})
+ command('set laststatus=2 mouse=a')
+ command('resize -1')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 6, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 0, 5, 10)
+ screen:expect_unchanged()
+ end)
end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 03cd4bfd06..e261f0dfab 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -215,7 +215,7 @@ describe('ui/cursor', function()
m.hl_id = 60
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 61 end
+ if m.id_lm then m.id_lm = 62 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 789f1c6487..489c33d8b1 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -31,6 +31,8 @@ describe('decorations providers', function()
[12] = {foreground = tonumber('0x990000')};
[13] = {background = Screen.colors.LightBlue};
[14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
+ [15] = {special = Screen.colors.Blue1, undercurl = true},
+ [16] = {special = Screen.colors.Red, undercurl = true},
}
end)
@@ -56,7 +58,7 @@ describe('decorations providers', function()
a.nvim_set_decoration_provider(_G.ns1, {
on_start = on_do; on_buf = on_do;
on_win = on_do; on_line = on_do;
- on_end = on_do;
+ on_end = on_do; _on_spell_nav = on_do;
})
return _G.ns1
]])
@@ -95,7 +97,7 @@ describe('decorations providers', function()
|
]]}
check_trace {
- { "start", 4, 40 };
+ { "start", 4 };
{ "win", 1000, 1, 0, 8 };
{ "line", 1000, 1, 0 };
{ "line", 1000, 1, 1 };
@@ -119,7 +121,7 @@ describe('decorations providers', function()
|
]]}
check_trace {
- { "start", 5, 10 };
+ { "start", 5 };
{ "buf", 1 };
{ "win", 1000, 1, 0, 8 };
{ "line", 1000, 1, 6 };
@@ -156,6 +158,120 @@ describe('decorations providers', function()
]]}
end)
+ it('can indicate spellchecked points', function()
+ exec [[
+ set spell
+ set spelloptions=noplainbuffer
+ syntax off
+ ]]
+
+ insert [[
+ I am well written text.
+ i am not capitalized.
+ I am a speling mistakke.
+ ]]
+
+ setup_provider [[
+ local ns = a.nvim_create_namespace "spell"
+ beamtrace = {}
+ local function on_do(kind, ...)
+ if kind == 'win' or kind == 'spell' then
+ a.nvim_buf_set_extmark(0, ns, 0, 0, {
+ end_row = 2,
+ end_col = 23,
+ spell = true,
+ priority = 20,
+ ephemeral = true
+ })
+ end
+ table.insert(beamtrace, {kind, ...})
+ end
+ ]]
+
+ check_trace {
+ { "start", 5 };
+ { "win", 1000, 1, 0, 5 };
+ { "line", 1000, 1, 0 };
+ { "line", 1000, 1, 1 };
+ { "line", 1000, 1, 2 };
+ { "line", 1000, 1, 3 };
+ { "end", 5 };
+ }
+
+ feed "gg0"
+
+ screen:expect{grid=[[
+ ^I am well written text. |
+ {15:i} am not capitalized. |
+ I am a {16:speling} {16:mistakke}. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed "]s"
+ check_trace {
+ { "spell", 1000, 1, 1, 0, 1, -1 };
+ }
+ screen:expect{grid=[[
+ I am well written text. |
+ {15:^i} am not capitalized. |
+ I am a {16:speling} {16:mistakke}. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed "]s"
+ check_trace {
+ { "spell", 1000, 1, 2, 7, 2, -1 };
+ }
+ screen:expect{grid=[[
+ I am well written text. |
+ {15:i} am not capitalized. |
+ I am a {16:^speling} {16:mistakke}. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ -- spell=false with lower priority doesn't disable spell
+ local ns = meths.create_namespace "spell"
+ local id = helpers.curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false })
+
+ screen:expect{grid=[[
+ I am well written text. |
+ i am not capitalized. |
+ I am a ^speling mistakke. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ -- spell=false with higher priority does disable spell
+ helpers.curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false })
+
+ screen:expect{grid=[[
+ I am well written text. |
+ {15:i} am not capitalized. |
+ I am a {16:^speling} {16:mistakke}. |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ end)
+
it('can predefine highlights', function()
screen:try_resize(40, 16)
insert(mulholland)
@@ -484,6 +600,7 @@ describe('extmark decorations', function()
[24] = {bold = true};
[25] = {background = Screen.colors.LightRed};
[26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
+ [27] = {background = Screen.colors.Plum1};
}
ns = meths.create_namespace 'test'
@@ -606,15 +723,15 @@ end]]
screen:expect{grid=[[
{5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
- {5:local} text, hl_id_cell, count = unpack(item) |
- {5:if} hl_id_cell ~= {13:nil} {5:then} |
- hl_id = hl_id_cell |
+ {5:local} text, hl_id_cell, count {5:=} unpack(item) |
+ {5:if} hl_id_cell {5:~=} {13:nil} {5:then} |
+ hl_id {5:=} hl_id_cell |
{5:end} |
- {5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do} |
- {5:local} cell = line[colpos] |
- cell.text = text |
- cell.hl_id = hl_id |
- colpos = colpos+{13:1} |
+ {5:for} _ {5:=} {13:1}, (count {5:or} {13:1}) {5:do} |
+ {5:local} cell {5:=} line[colpos] |
+ cell.text {5:=} text |
+ cell.hl_id {5:=} hl_id |
+ colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|
@@ -633,15 +750,15 @@ end]]
screen:expect{grid=[[
{5:^for} _,item {5:in} {6:ipairs}(items) {5:do} |
- {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) |
- {5:i}{12:c}{11:ombining color} {13:nil} {5:then} |
+ {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count {5:=} unpack(item) |
+ {5:i}{12:c}{11:ombining col}{12:or} {13:nil} {5:then} |
{11:replacing color}d_cell |
{5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} |
- {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
+ {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
- cell.text = text |
- cell.hl_id = hl_id |
- colpos = colpos+{13:1} |
+ cell.text {5:=} text |
+ cell.hl_id {5:=} hl_id |
+ colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|
@@ -652,15 +769,15 @@ end]]
feed 'V5G'
screen:expect{grid=[[
{17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
- {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
- {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
+ {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} |
+ {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} |
{18: }{11:replacing color}{18:d_cell} |
{18: }{5:^e}{17:nd} |
- {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
+ {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
- cell.text = text |
- cell.hl_id = hl_id |
- colpos = colpos+{13:1} |
+ cell.text {5:=} text |
+ cell.hl_id {5:=} hl_id |
+ colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|
@@ -671,15 +788,15 @@ end]]
feed 'jj'
screen:expect{grid=[[
{17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} |
- {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} |
- {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} |
+ {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} |
+ {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} |
{18: }{11:replacing color}{18:d_cell} |
{18: }{17:end} |
- {18: }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} |
- {18: }^ {18: }{17:local}{18: cell = line[colpos]} |
- cell.text = text |
- cell.hl_id = hl_id |
- colpos = colpos+{13:1} |
+ {18: }{17:for}{18: _ }{17:=}{18: }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} |
+ {18: }^ {18: }{17:local}{18: cell }{17:=}{18: line[colpos]} |
+ cell.text {5:=} text |
+ cell.hl_id {5:=} hl_id |
+ colpos {5:=} colpos{5:+}{13:1} |
{5:end} |
{5:end} |
{1:~ }|
@@ -879,6 +996,55 @@ end]]
|
]])
end)
+
+ it('avoids redraw issue #20651', function()
+ exec_lua[[
+ vim.cmd.normal'10oXXX'
+ vim.cmd.normal'gg'
+ local ns = vim.api.nvim_create_namespace('ns')
+
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_open_win(bufnr, false, { relative = 'win', height = 1, width = 1, row = 0, col = 0 })
+
+ vim.api.nvim_create_autocmd('CursorMoved', { callback = function()
+ local row = vim.api.nvim_win_get_cursor(0)[1] - 1
+ vim.api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1 })
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {})
+ vim.schedule(function()
+ vim.api.nvim_buf_set_extmark(0, ns, row, 0, {
+ id = 1,
+ virt_text = {{'HELLO', 'Normal'}},
+ })
+ end)
+ end
+ })
+ ]]
+
+ for _ = 1, 3 do
+ helpers.sleep(10)
+ feed 'j'
+ end
+
+ screen:expect{grid=[[
+ {27: } |
+ XXX |
+ XXX |
+ ^XXX HELLO |
+ XXX |
+ XXX |
+ XXX |
+ XXX |
+ XXX |
+ XXX |
+ XXX |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ end)
+
end)
describe('decorations: virtual lines', function()
@@ -985,7 +1151,7 @@ if (h->n_buckets < new_n_buckets) { // expand
]]}
meths.buf_set_extmark(0, ns, 5, 0, {
- virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unneccesary?", "Comment"}} };
+ virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unnecessary?", "Comment"}} };
})
-- TODO: what about the cursor??
screen:expect{grid=[[
@@ -998,7 +1164,7 @@ if (h->n_buckets < new_n_buckets) { // expand
if (kh_is_map && val_size) { |
^char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
buckets * val_size); |
- {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} |
+ {5:^^ REVIEW:}{6: new_vals variable seems unnecessary?} |
h->vals_buf = new_vals; |
|
]]}
@@ -1201,6 +1367,110 @@ if (h->n_buckets < new_n_buckets) { // expand
]]}
end)
+ it('works beyond end of the buffer with virt_lines_above', function()
+ insert(example_text)
+ feed 'G'
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+
+ local id = meths.buf_set_extmark(0, ns, 8, 0, {
+ virt_lines={{{"Grugg"}}};
+ virt_lines_above = true,
+ })
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ Grugg |
+ |
+ ]]}
+
+ feed('dd')
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ ^} |
+ Grugg |
+ {1:~ }|
+ |
+ ]]}
+
+ feed('dk')
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ ^char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ Grugg |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed('dgg')
+ screen:expect{grid=[[
+ ^ |
+ Grugg |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ --No lines in buffer-- |
+ ]]}
+
+ meths.buf_del_extmark(0, ns, id)
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ --No lines in buffer-- |
+ ]]}
+ end)
+
it('does not cause syntax ml_get error at the end of a buffer #17816', function()
command([[syntax region foo keepend start='^foo' end='^$']])
command('syntax sync minlines=100')
@@ -1470,6 +1740,38 @@ if (h->n_buckets < new_n_buckets) { // expand
} |
|
]]}
+
+ command 'set number'
+ screen:expect{grid=[[
+ {9: 1 }^if (h->n_buckets < new_n_buckets) { // expand |
+ {9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi|
+ {9: }d *)h->keys, new_n_buckets * sizeof(khkey_t));|
+ {9: }{1:>>}{2: very tabby}text with tabs |
+ {9: 3 } h->keys = new_keys; |
+ {9: 4 } if (kh_is_map && val_size) { |
+ {9: 5 } char *new_vals = krealloc( h->vals_buf, ne|
+ {9: }w_n_buckets * val_size); |
+ {9: 6 } h->vals_buf = new_vals; |
+ {9: 7 } } |
+ {9: 8 }} |
+ |
+ ]]}
+
+ command 'set tabstop&'
+ screen:expect{grid=[[
+ {9: 1 }^if (h->n_buckets < new_n_buckets) { // expand |
+ {9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi|
+ {9: }d *)h->keys, new_n_buckets * sizeof(khkey_t));|
+ {9: }{1:>>}{2: very tabby}text with tabs |
+ {9: 3 } h->keys = new_keys; |
+ {9: 4 } if (kh_is_map && val_size) { |
+ {9: 5 } char *new_vals = krealloc( h->vals_buf, ne|
+ {9: }w_n_buckets * val_size); |
+ {9: 6 } h->vals_buf = new_vals; |
+ {9: 7 } } |
+ {9: 8 }} |
+ |
+ ]]}
end)
end)
@@ -1869,4 +2171,39 @@ describe('decorations: virt_text', function()
]]}
end)
+ it('redraws correctly when re-using extmark ids', function()
+ command 'normal 5ohello'
+
+ screen:expect{grid=[[
+ |
+ hello |
+ hello |
+ hello |
+ hello |
+ hell^o |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+
+ local ns = meths.create_namespace('ns')
+ for row = 1, 5 do
+ meths.buf_set_extmark(0, ns, row, 0, { id = 1, virt_text = {{'world', 'Normal'}} })
+ end
+
+ screen:expect{grid=[[
+ |
+ hello |
+ hello |
+ hello |
+ hello |
+ hell^o world |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ end)
+
end)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index 36dc5addcd..dbdf3823ec 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -8,6 +8,8 @@ local insert = helpers.insert
local write_file = helpers.write_file
local dedent = helpers.dedent
local exec = helpers.exec
+local eq = helpers.eq
+local meths = helpers.meths
describe('Diff mode screen', function()
local fname = 'Xtest-functional-diff-screen-1'
@@ -1073,6 +1075,182 @@ int main(int argc, char **argv)
:e |
]])
end)
+
+ describe('line matching diff algorithm', function()
+ setup(function()
+ local f1 = [[if __name__ == "__main__":
+ import sys
+ app = QWidgets.QApplication(sys.args)
+ MainWindow = QtWidgets.QMainWindow()
+ ui = UI_MainWindow()
+ ui.setupUI(MainWindow)
+ MainWindow.show()
+ sys.exit(app.exec_())]]
+ write_file(fname, f1, false)
+ local f2 = [[if __name__ == "__main__":
+ import sys
+ comment these things
+ #app = QWidgets.QApplication(sys.args)
+ #MainWindow = QtWidgets.QMainWindow()
+ add a completely different line here
+ #ui = UI_MainWindow()
+ add another new line
+ ui.setupUI(MainWindow)
+ MainWindow.show()
+ sys.exit(app.exec_())]]
+ write_file(fname_2, f2, false)
+ end)
+
+ it('diffopt+=linematch:20', function()
+ reread()
+ feed(':set diffopt=internal,filler<cr>')
+ screen:expect([[
+ {1: }^if __name__ == "__│{1: }if __name__ == "_|
+ {1: } import sys │{1: } import sys |
+ {1: }{9: }{8:app = QWidgets}│{1: }{9: }{8:comment these}|
+ {1: }{9: }{8:MainWindow = Q}│{1: }{9: }{8:#app = QWidge}|
+ {1: }{9: }{8:ui = UI_}{9:MainWi}│{1: }{9: }{8:#MainWindow =}|
+ {1: }{2:------------------}│{1: }{4: add a complet}|
+ {1: }{2:------------------}│{1: }{4: #ui = UI_Main}|
+ {1: }{2:------------------}│{1: }{4: add another n}|
+ {1: } ui.setupUI(Mai│{1: } ui.setupUI(Ma|
+ {1: } MainWindow.sho│{1: } MainWindow.sh|
+ {1: } sys.exit(app.e│{1: } sys.exit(app.|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt=internal,filler |
+ ]])
+
+ feed('G')
+ feed(':set diffopt+=linematch:20<cr>')
+ screen:expect([[
+ {1: }if __name__ == "__│{1: }if __name__ == "_|
+ {1: } import sys │{1: } import sys |
+ {1: }{2:------------------}│{1: }{4: comment these}|
+ {1: }{9: app = QWidgets}│{1: }{9: }{8:#}{9:app = QWidge}|
+ {1: }{9: MainWindow = Q}│{1: }{9: }{8:#}{9:MainWindow =}|
+ {1: }{2:------------------}│{1: }{4: add a complet}|
+ {1: }{9: ui = UI_MainWi}│{1: }{9: }{8:#}{9:ui = UI_Main}|
+ {1: }{2:------------------}│{1: }{4: add another n}|
+ {1: } ui.setupUI(Mai│{1: } ui.setupUI(Ma|
+ {1: } MainWindow.sho│{1: } MainWindow.sh|
+ {1: } ^sys.exit(app.e│{1: } sys.exit(app.|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt+=linematch:20 |
+ ]])
+ end)
+ end)
+
+ describe('line matching diff algorithm with icase', function()
+ setup(function()
+ local f1 = [[DDD
+_aa]]
+ write_file(fname, f1, false)
+ local f2 = [[DDD
+AAA
+ccca]]
+ write_file(fname_2, f2, false)
+ end)
+ it('diffopt+=linematch:20,icase', function()
+ reread()
+ feed(':set diffopt=internal,filler,linematch:20<cr>')
+ screen:expect([[
+ {1: }^DDD │{1: }DDD |
+ {1: }{2:------------------}│{1: }{4:AAA }|
+ {1: }{8:_a}{9:a }│{1: }{8:ccc}{9:a }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ |
+ ]])
+ feed(':set diffopt+=icase<cr>')
+ screen:expect([[
+ {1: }^DDD │{1: }DDD |
+ {1: }{8:_}{9:aa }│{1: }{8:A}{9:AA }|
+ {1: }{2:------------------}│{1: }{4:ccca }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt+=icase |
+ ]])
+ end)
+ end)
+
+ describe('line matching diff algorithm with iwhiteall', function()
+ setup(function()
+ local f1 = [[BB
+ AAA]]
+ write_file(fname, f1, false)
+ local f2 = [[BB
+ AAB
+AAAB]]
+ write_file(fname_2, f2, false)
+ end)
+ it('diffopt+=linematch:20,iwhiteall', function()
+ reread()
+ feed(':set diffopt=internal,filler,linematch:20<cr>')
+ screen:expect{grid=[[
+ {1: }^BB │{1: }BB |
+ {1: }{9: AA}{8:A}{9: }│{1: }{9: AA}{8:B}{9: }|
+ {1: }{2:------------------}│{1: }{4:AAAB }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ |
+ ]]}
+ feed(':set diffopt+=iwhiteall<cr>')
+ screen:expect{grid=[[
+ {1: }^BB │{1: }BB |
+ {1: }{2:------------------}│{1: }{4: AAB }|
+ {1: }{9: AAA }│{1: }{9:AAA}{8:B}{9: }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt+=iwhiteall |
+ ]]}
+ end)
+ end)
end)
it('win_update redraws lines properly', function()
@@ -1315,6 +1493,26 @@ it('Align the filler lines when changing text in diff mode', function()
]]}
end)
+it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function()
+ clear()
+ local screen = Screen.new(60, 6)
+ screen:set_default_attr_ids({
+ [0] = {foreground = Screen.colors.Blue, bold = true};
+ })
+ screen:attach()
+ eq('0', meths.get_option_value('foldcolumn', {}))
+ command('diffsplit | bd')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ eq('0', meths.get_option_value('foldcolumn', {}))
+end)
+
-- oldtest: Test_diff_binary()
it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function()
clear()
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
index 92f5beebf5..cd2b48213d 100644
--- a/test/functional/ui/embed_spec.lua
+++ b/test/functional/ui/embed_spec.lua
@@ -51,7 +51,7 @@ local function test_embed(ext_linegrid)
end)
it("doesn't erase output when setting color scheme", function()
- if 'openbsd' == helpers.uname() then
+ if helpers.is_os('openbsd') then
pending('FIXME #10804')
end
startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"')
@@ -82,20 +82,6 @@ local function test_embed(ext_linegrid)
eq(Screen.colors.Green, screen.default_colors.rgb_bg)
end}
end)
-
- it("set display-=msgsep before first redraw", function()
- startup('--cmd', 'set display-=msgsep')
- screen:expect{grid=[[
- ^ |
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
- {3:~ }|
- |
- ]]}
- end)
end
describe('--embed UI on startup (ext_linegrid=true)', function() test_embed(true) end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 5967b630f6..6759510ad1 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -25,36 +25,6 @@ describe('float window', function()
clear()
command('hi VertSplit gui=reverse')
end)
- local attrs = {
- [0] = {bold=true, foreground=Screen.colors.Blue},
- [1] = {background = Screen.colors.LightMagenta},
- [2] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1},
- [3] = {bold = true},
- [4] = {bold = true, reverse = true},
- [5] = {reverse = true},
- [6] = {background = Screen.colors.LightMagenta, bold = true, reverse = true},
- [7] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- [8] = {bold = true, foreground = Screen.colors.SeaGreen4},
- [9] = {background = Screen.colors.LightGrey, underline = true},
- [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta},
- [11] = {bold = true, foreground = Screen.colors.Magenta},
- [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue1},
- [13] = {background = Screen.colors.WebGray},
- [14] = {foreground = Screen.colors.Brown},
- [15] = {background = Screen.colors.Grey20},
- [16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1},
- [17] = {background = Screen.colors.Yellow},
- [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20},
- [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
- [20] = {bold = true, foreground = Screen.colors.Brown},
- [21] = {background = Screen.colors.Gray90},
- [22] = {background = Screen.colors.LightRed},
- [23] = {foreground = Screen.colors.Black, background = Screen.colors.White};
- [24] = {foreground = Screen.colors.Black, background = Screen.colors.Grey80};
- [25] = {blend = 100, background = Screen.colors.Gray0};
- [26] = {blend = 80, background = Screen.colors.Gray0};
- [27] = {background = Screen.colors.LightGray};
- }
it('behavior', function()
-- Create three windows and test that ":wincmd <direction>" changes to the
@@ -93,7 +63,7 @@ describe('float window', function()
end)
it('closed immediately by autocmd #11383', function()
- eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
+ eq('Window was closed immediately',
pcall_err(exec_lua, [[
local a = vim.api
local function crashes(contents)
@@ -118,7 +88,7 @@ describe('float window', function()
end)
it('closed immediately by autocmd after win_enter #15548', function()
- eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
+ eq('Window was closed immediately',
pcall_err(exec_lua, [[
vim.cmd "autocmd BufLeave * ++once quit!"
local buf = vim.api.nvim_create_buf(true, true)
@@ -198,6 +168,29 @@ describe('float window', function()
eq(7, pos[2])
end)
+ it('opened with correct position relative to the mouse', function()
+ meths.input_mouse('left', 'press', '', 0, 10, 10)
+ local pos = exec_lua([[
+ local bufnr = vim.api.nvim_create_buf(false, true)
+
+ local opts = {
+ width = 10,
+ height = 10,
+ col = 1,
+ row = 2,
+ relative = 'mouse',
+ style = 'minimal'
+ }
+
+ local win_id = vim.api.nvim_open_win(bufnr, false, opts)
+
+ return vim.api.nvim_win_get_position(win_id)
+ ]])
+
+ eq(12, pos[1])
+ eq(11, pos[2])
+ end)
+
it('opened with correct position relative to the cursor', function()
local pos = exec_lua([[
local bufnr = vim.api.nvim_create_buf(false, true)
@@ -421,6 +414,15 @@ describe('float window', function()
eq(winids, eval('winids'))
end)
+ it('no crash with bufpos and non-existent window', function()
+ command('new')
+ local closed_win = meths.get_current_win().id
+ command('close')
+ local buf = meths.create_buf(false,false)
+ meths.open_win(buf, true, {relative='win', win=closed_win, width=1, height=1, bufpos={0,0}})
+ assert_alive()
+ end)
+
it("no segfault when setting minimal style after clearing local 'fillchars' #19510", function()
local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
local float_win = meths.open_win(0, true, float_opts)
@@ -430,6 +432,13 @@ describe('float window', function()
assert_alive()
end)
+ it("'scroll' is computed correctly when opening float with splitkeep=screen #20684", function()
+ meths.set_option('splitkeep', 'screen')
+ local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10}
+ local float_win = meths.open_win(0, true, float_opts)
+ eq(5, meths.win_get_option(float_win, 'scroll'))
+ end)
+
describe('with only one tabpage,', function()
local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
local old_buf, old_win
@@ -569,7 +578,7 @@ describe('float window', function()
end)
end)
- describe('with mulitple tabpages but only one listed buffer,', function()
+ describe('with multiple tabpages but only one listed buffer,', function()
local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
local unlisted_buf, old_buf, old_win
before_each(function()
@@ -596,6 +605,11 @@ describe('float window', function()
meths.buf_delete(old_buf, {force = true})
eq(old_win, curwin().id)
end)
+ it('if called from non-floating window in another tabpage', function()
+ command('tab split')
+ eq(3, #meths.list_tabpages())
+ meths.buf_delete(old_buf, {force = true})
+ end)
it('if called from floating window with the same buffer', function()
meths.set_current_win(same_buf_float)
command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()')
@@ -712,10 +726,41 @@ describe('float window', function()
end)
local function with_ext_multigrid(multigrid)
- local screen
+ local screen, attrs
before_each(function()
screen = Screen.new(40,7)
screen:attach {ext_multigrid=multigrid}
+ attrs = {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {background = Screen.colors.LightMagenta},
+ [2] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1},
+ [3] = {bold = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {reverse = true},
+ [6] = {background = Screen.colors.LightMagenta, bold = true, reverse = true},
+ [7] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [8] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [9] = {background = Screen.colors.LightGrey, underline = true},
+ [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta},
+ [11] = {bold = true, foreground = Screen.colors.Magenta},
+ [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue1},
+ [13] = {background = Screen.colors.WebGray},
+ [14] = {foreground = Screen.colors.Brown},
+ [15] = {background = Screen.colors.Grey20},
+ [16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1},
+ [17] = {background = Screen.colors.Yellow},
+ [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20},
+ [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [20] = {bold = true, foreground = Screen.colors.Brown},
+ [21] = {background = Screen.colors.Gray90},
+ [22] = {background = Screen.colors.LightRed},
+ [23] = {foreground = Screen.colors.Black, background = Screen.colors.White};
+ [24] = {foreground = Screen.colors.Black, background = Screen.colors.Grey80};
+ [25] = {blend = 100, background = Screen.colors.Gray0};
+ [26] = {blend = 80, background = Screen.colors.Gray0};
+ [27] = {background = Screen.colors.LightGray};
+ [28] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
+ }
screen:set_default_attr_ids(attrs)
end)
@@ -1307,6 +1352,54 @@ describe('float window', function()
end
end)
+ it("would not break 'minimal' style with statuscolumn set", function()
+ command('set number')
+ command('set signcolumn=yes')
+ command('set colorcolumn=1')
+ command('set cursorline')
+ command('set foldcolumn=1')
+ command('set statuscolumn=%l%s%C')
+ command('hi NormalFloat guibg=#333333')
+ feed('ix<cr>y<cr><esc>gg')
+ meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ {20:1}{19: }{20: }{22:^x}{21: }|
+ {14:2}{19: }{14: }{22:y} |
+ {14:3}{19: }{14: }{22: } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {15:x }|
+ {15:y }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect{grid=[[
+ {20:1}{19: }{20: }{22:^x}{21: }|
+ {14:2}{19: }{14: }{22:y} |
+ {14:3}{19: }{14: }{22: } {15:x } |
+ {0:~ }{15:y }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]]}
+ end
+ end)
+
it('can have border', function()
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',
@@ -1704,6 +1797,222 @@ describe('float window', function()
end
end)
+ it('validates title title_pos', function()
+ local buf = meths.create_buf(false,false)
+ eq("title requires border to be set",
+ pcall_err(meths.open_win,buf, false, {
+ relative='editor', width=9, height=2, row=2, col=5, title='Title',
+ }))
+ eq("title_pos requires title to be set",
+ pcall_err(meths.open_win,buf, false, {
+ relative='editor', width=9, height=2, row=2, col=5,
+ border='single', title_pos='left',
+ }))
+ end)
+
+ it('validate title_pos in nvim_win_get_config', function()
+ local title_pos = exec_lua([[
+ local bufnr = vim.api.nvim_create_buf(false, false)
+ local opts = {
+ relative = 'editor',
+ col = 2,
+ row = 5,
+ height = 2,
+ width = 9,
+ border = 'double',
+ title = 'Test',
+ title_pos = 'center'
+ }
+
+ local win_id = vim.api.nvim_open_win(bufnr, true, opts)
+ return vim.api.nvim_win_get_config(win_id).title_pos
+ ]])
+
+ eq('center', title_pos)
+ end)
+
+
+ it('border with title', function()
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',
+ ' BORDAA '})
+ local win = meths.open_win(buf, false, {
+ relative='editor', width=9, height=2, row=2, col=5, border="double",
+ title = "Left",title_pos = "left",
+ })
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔}{11:Left}{5:═════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔}{11:Left}{5:═════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {title= "Center",title_pos="center"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔═}{11:Center}{5:══╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔═}{11:Center}{5:══╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {title= "Right",title_pos="right"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔════}{11:Right}{5:╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔════}{11:Right}{5:╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ |
+ ]]}
+ end
+
+ meths.win_set_config(win, {title= { {"🦄"},{"BB"}},title_pos="right"})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:╔═════}🦄BB{5:╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [5] = { { id = 1002 }, "NW", 1, 2, 5, true }
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔═════}🦄BB{5:╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ |
+ ]]}
+ end
+ end)
+
it('terminates border on edge of viewport when window extends past viewport', function()
local buf = meths.create_buf(false, false)
meths.open_win(buf, false, {relative='editor', width=40, height=7, row=0, col=0, border="single"})
@@ -2756,7 +3065,7 @@ describe('float window', function()
}, "NW", 2, 1, 32, true }
}}
else
- -- note: appears misalinged due to cursor
+ -- note: appears misaligned due to cursor
screen:expect{grid=[[
^example text that is wider than the window |
{1:some info! } |
@@ -2862,6 +3171,66 @@ describe('float window', function()
]]}
end
+ command('set laststatus=0')
+ command('botright vnew')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [2:----]{5:│}[6:--------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ exam|
+ ple |
+ text|
+ tha|
+ t is|
+ wid|
+ er t|
+ han |
+ the |
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ## grid 6
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "SW", 2, 8, 0, true }
+ }}
+ else
+ screen:expect{grid=[[
+ exam{5:│}^ |
+ ple {5:│}{0:~ }|
+ text{5:│}{0:~ }|
+ tha{5:│}{0:~ }|
+ t is{5:│}{0:~ }|
+ wid{5:│}{0:~ }|
+ er t{5:│}{0:~ }|
+ {1:some info! }{0: }|
+ the {5:│}{0:~ }|
+ |
+ ]]}
+ end
+ command('close')
+
meths.win_set_config(win, {relative='win', bufpos={1,32}, anchor='NW', col=-2})
if multigrid then
screen:expect{grid=[[
@@ -2957,6 +3326,54 @@ describe('float window', function()
|
]]}
end
+
+ command('%fold')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [2:-------------------------]|
+ [3:-------------------------]|
+ ## grid 2
+ {28:^+-- 5 lines: just some··}|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {1:some info! }|
+ ]], float_pos={
+ [5] = { {
+ id = 1002
+ }, "NW", 2, 2, 0, true }
+ }}
+ else
+ screen:expect{grid=[[
+ {28:^+-- 5 lines: just some··}|
+ {0:~ }|
+ {1:some info! }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
end)
it('validates cursor even when window is not entered', function()
@@ -8147,6 +8564,394 @@ describe('float window', function()
]]}
end
end)
+
+ it('it can be resized with messages and cmdheight=0 #20106', function()
+ screen:try_resize(40,9)
+ command 'set cmdheight=0'
+ local buf = meths.create_buf(false,true)
+ local win = meths.open_win(buf, false, {relative='editor', width=40, height=4, anchor='SW', row=9, col=0, style='minimal', border="single", noautocmd=true})
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ ## grid 5
+ {5:┌────────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└────────────────────────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {5:┌──────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└──────────────────────────────────────┘}|
+ ]]}
+ end
+
+ exec_lua([[
+ local win = ...
+ vim.api.nvim_win_set_height(win, 2)
+ vim.api.nvim_echo({ { "" } }, false, {})
+ ]], win)
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ ## grid 5
+ {5:┌────────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└────────────────────────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:┌──────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└──────────────────────────────────────┘}|
+ ]]}
+
+ end
+
+ meths.win_close(win, true)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]]}
+ end
+ end)
+
+ it('it can be resized with messages and cmdheight=1', function()
+ screen:try_resize(40,9)
+ local buf = meths.create_buf(false,true)
+ local win = meths.open_win(buf, false, {relative='editor', width=40, height=4, anchor='SW', row=8, col=0, style='minimal', border="single", noautocmd=true})
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌────────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└────────────────────────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {5:┌──────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└──────────────────────────────────────┘}|
+ |
+ ]]}
+ end
+
+ exec_lua([[
+ -- echo prompt is blocking, so schedule
+ local win = ...
+ vim.schedule(function()
+ vim.api.nvim_win_set_height(win, 2)
+ vim.api.nvim_echo({ { "\n" } }, false, {})
+ end)
+ ]], win)
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ {8:Press ENTER or type command to continue}^ |
+ ## grid 5
+ {5:┌────────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└────────────────────────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {5:┌──────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {4: }|
+ |
+ {8:Press ENTER or type command to continue}^ |
+ ]]}
+ end
+
+ feed('<cr>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌────────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└────────────────────────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:┌──────────────────────────────────────┐}|
+ {5:│}{1: }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:└──────────────────────────────────────┘}|
+ |
+ ]]}
+ end
+
+ meths.win_close(win, true)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+ end)
+
+ describe('no crash after moving and closing float window #21547', function()
+ local function test_float_move_close(cmd)
+ local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10}
+ meths.open_win(meths.create_buf(false, false), true, float_opts)
+ if multigrid then
+ screen:expect({float_pos = {[4] = {{id = 1001}, 'NW', 1, 1, 1, true}}})
+ end
+ command(cmd)
+ exec_lua([[
+ vim.api.nvim_win_set_config(0, {relative = 'editor', row = 2, col = 2})
+ vim.api.nvim_win_close(0, {})
+ vim.api.nvim_echo({{''}}, false, {})
+ ]])
+ if multigrid then
+ screen:expect({float_pos = {}})
+ end
+ assert_alive()
+ end
+
+ it('if WinClosed autocommand flushes UI', function()
+ test_float_move_close('autocmd WinClosed * ++once redraw')
+ end)
+
+ it('if closing buffer flushes UI', function()
+ test_float_move_close('autocmd BufWinLeave * ++once redraw')
+ end)
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 6bb8bb81c6..46a478c1ea 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -4,9 +4,11 @@ local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq
local command = helpers.command
local feed_command = helpers.feed_command
local insert = helpers.insert
+local expect = helpers.expect
local funcs = helpers.funcs
local meths = helpers.meths
-local source = helpers.source
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
local assert_alive = helpers.assert_alive
@@ -198,50 +200,6 @@ describe("folded lines", function()
end
end)
- it("highlighting with relative line numbers", function()
- command("set relativenumber cursorline cursorlineopt=number foldmethod=marker")
- feed_command("set foldcolumn=2")
- funcs.setline(1, '{{{1')
- funcs.setline(2, 'line 1')
- funcs.setline(3, '{{{1')
- funcs.setline(4, 'line 2')
- feed("j")
- if multigrid then
- screen:expect([[
- ## grid 1
- [2:---------------------------------------------]|
- [2:---------------------------------------------]|
- [2:---------------------------------------------]|
- [2:---------------------------------------------]|
- [2:---------------------------------------------]|
- [2:---------------------------------------------]|
- [2:---------------------------------------------]|
- [3:---------------------------------------------]|
- ## grid 2
- {7:+ }{8: 1 }{5:+-- 2 lines: ·························}|
- {7:+ }{9: 0 }{5:^+-- 2 lines: ·························}|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- ## grid 3
- :set foldcolumn=2 |
- ]])
- else
- screen:expect([[
- {7:+ }{8: 1 }{5:+-- 2 lines: ·························}|
- {7:+ }{9: 0 }{5:^+-- 2 lines: ·························}|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- :set foldcolumn=2 |
- ]])
- end
- end)
-
it("work with spell", function()
command("set spell")
insert(content1)
@@ -1713,7 +1671,7 @@ describe("folded lines", function()
end)
it('does not crash when foldtext is longer than columns #12988', function()
- source([[
+ exec([[
function! MyFoldText() abort
return repeat('-', &columns + 100)
endfunction
@@ -1760,7 +1718,7 @@ describe("folded lines", function()
it('work correctly with :move #18668', function()
screen:try_resize(45, 12)
- source([[
+ exec([[
set foldmethod=expr foldexpr=indent(v:lnum)
let content = ['', '', 'Line1', ' Line2', ' Line3',
\ 'Line4', ' Line5', ' Line6',
@@ -1895,6 +1853,128 @@ describe("folded lines", function()
]])
end
end)
+
+ it('fold attached virtual lines are drawn correctly #21837', function()
+ funcs.setline(1, 'line 1')
+ funcs.setline(2, 'line 2')
+ funcs.setline(3, 'line 3')
+ funcs.setline(4, 'line 4')
+ feed("zfj")
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace("ns")
+ vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines_above = true, virt_lines = {{{"virt_line above line 1", ""}}} })
+ vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_lines = {{{"virt_line below line 2", ""}}} })
+ vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_lines_above = true, virt_lines = {{{"virt_line above line 3", ""}}} })
+ vim.api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = {{{"virt_line below line 4", ""}}} })
+ ]])
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {5:^+-- 2 lines: line 1·························}|
+ virt_line above line 3 |
+ line 3 |
+ line 4 |
+ virt_line below line 4 |
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]])
+ else
+ screen:expect([[
+ {5:^+-- 2 lines: line 1·························}|
+ virt_line above line 3 |
+ line 3 |
+ line 4 |
+ virt_line below line 4 |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end
+
+ feed('jzfj')
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ {5:+-- 2 lines: line 1·························}|
+ {5:^+-- 2 lines: line 3·························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]])
+ else
+ screen:expect([[
+ {5:+-- 2 lines: line 1·························}|
+ {5:^+-- 2 lines: line 3·························}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end
+
+ feed('kzo<C-Y>')
+ funcs.setline(5, 'line 5')
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ virt_line above line 1 |
+ ^line 1 |
+ line 2 |
+ virt_line below line 2 |
+ {5:+-- 2 lines: line 3·························}|
+ line 5 |
+ {1:~ }|
+ ## grid 3
+ |
+ ]])
+ else
+ screen:expect([[
+ virt_line above line 1 |
+ ^line 1 |
+ line 2 |
+ virt_line below line 2 |
+ {5:+-- 2 lines: line 3·························}|
+ line 5 |
+ {1:~ }|
+ |
+ ]])
+ end
+ end)
end
describe("with ext_multigrid", function()
@@ -1911,4 +1991,19 @@ describe("folded lines", function()
command('%delete')
eq(0, funcs.foldlevel(1))
end)
+
+ it('multibyte fold markers work #20438', function()
+ meths.win_set_option(0, 'foldmethod', 'marker')
+ meths.win_set_option(0, 'foldmarker', '«,»')
+ insert([[
+ bbbbb
+ bbbbb
+ bbbbb]])
+ feed('zfgg')
+ expect([[
+ bbbbb/*«*/
+ bbbbb
+ bbbbb/*»*/]])
+ eq(1, funcs.foldlevel(1))
+ end)
end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 4e3d62509c..288c2a214f 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -6,6 +6,7 @@ local command, exec = helpers.command, helpers.exec
local eval = helpers.eval
local feed_command, eq = helpers.feed_command, helpers.eq
local curbufmeths = helpers.curbufmeths
+local funcs = helpers.funcs
local meths = helpers.meths
describe('colorscheme compatibility', function()
@@ -13,7 +14,9 @@ describe('colorscheme compatibility', function()
clear()
end)
- it('t_Co is set to 256 by default', function()
+ it('&t_Co exists and is set to 256 by default', function()
+ eq(1, funcs.exists('&t_Co'))
+ eq(1, funcs.exists('+t_Co'))
eq('256', eval('&t_Co'))
end)
end)
@@ -1048,6 +1051,7 @@ describe('CursorLine and CursorLineNr highlights', function()
]])
end)
+ -- oldtest: Test_cursorline_after_yank()
it('always updated. vim-patch:8.1.0849', function()
local screen = Screen.new(50,5)
screen:set_default_attr_ids({
@@ -1081,6 +1085,7 @@ describe('CursorLine and CursorLineNr highlights', function()
]])
end)
+ -- oldtest: Test_cursorline_with_visualmode()
it('with visual area. vim-patch:8.1.1001', function()
local screen = Screen.new(50,5)
screen:set_default_attr_ids({
@@ -1108,6 +1113,7 @@ describe('CursorLine and CursorLineNr highlights', function()
]])
end)
+ -- oldtest: Test_cursorline_callback()
it('is updated if cursor is moved up from timer vim-patch:8.2.4591', function()
local screen = Screen.new(50, 8)
screen:set_default_attr_ids({
@@ -1237,6 +1243,7 @@ describe('CursorLine and CursorLineNr highlights', function()
})
end)
+ -- oldtest: Test_diff_with_cursorline_number()
it('CursorLineNr shows correctly just below filler lines', function()
local screen = Screen.new(50,12)
screen:set_default_attr_ids({
@@ -1357,6 +1364,7 @@ describe('CursorColumn highlight', function()
]])
end)
+ -- oldtest: Test_cursorcolumn_callback()
it('is updated if cursor is moved from timer', function()
exec([[
call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
@@ -1398,7 +1406,7 @@ describe('ColorColumn highlight', function()
before_each(function()
clear()
screen = Screen.new(40, 15)
- Screen:set_default_attr_ids({
+ screen:set_default_attr_ids({
[1] = {background = Screen.colors.LightRed}, -- ColorColumn
[2] = {background = Screen.colors.Grey90}, -- CursorLine
[3] = {foreground = Screen.colors.Brown}, -- LineNr
@@ -1412,6 +1420,7 @@ describe('ColorColumn highlight', function()
screen:attach()
end)
+ -- oldtest: Test_colorcolumn()
it('when entering a buffer vim-patch:8.1.2073', function()
exec([[
set nohidden
@@ -1443,6 +1452,7 @@ describe('ColorColumn highlight', function()
]])
end)
+ -- oldtest: Test_colorcolumn_bri()
it("in 'breakindent' vim-patch:8.2.1689", function()
exec([[
call setline(1, 'The quick brown fox jumped over the lazy dogs')
@@ -1467,6 +1477,7 @@ describe('ColorColumn highlight', function()
]])
end)
+ -- oldtest: Test_colorcolumn_sbr()
it("in 'showbreak' vim-patch:8.2.1689", function()
exec([[
call setline(1, 'The quick brown fox jumped over the lazy dogs')
@@ -1560,17 +1571,6 @@ describe("MsgSeparator highlight and msgsep fillchar", function()
1 %a "[No Name]" line 1 |
{3:Press ENTER or type command to continue}^ |
]])
-
- -- when display doesn't contain msgsep, these options have no effect
- feed_command("set display-=msgsep")
- feed_command("ls")
- screen:expect([[
- {1:~ }|
- {1:~ }|
- :ls |
- 1 %a "[No Name]" line 1 |
- {3:Press ENTER or type command to continue}^ |
- ]])
end)
it("and MsgArea", function()
@@ -1697,6 +1697,7 @@ describe("'number' and 'relativenumber' highlight", function()
]])
end)
+ -- oldtest: Test_relativenumber_callback()
it('relative number highlight is updated if cursor is moved from timer', function()
local screen = Screen.new(50, 8)
screen:set_default_attr_ids({
@@ -1745,38 +1746,40 @@ describe("'winhighlight' highlight", function()
clear()
screen = Screen.new(20,8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- [1] = {background = Screen.colors.DarkBlue},
- [2] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Blue1},
- [3] = {bold = true, reverse = true},
- [4] = {reverse = true},
- [5] = {background = Screen.colors.DarkGreen},
- [6] = {background = Screen.colors.DarkGreen, bold = true, foreground = Screen.colors.Blue1},
- [7] = {background = Screen.colors.DarkMagenta},
- [8] = {background = Screen.colors.DarkMagenta, bold = true, foreground = Screen.colors.Blue1},
- [9] = {foreground = Screen.colors.Brown},
- [10] = {foreground = Screen.colors.Brown, background = Screen.colors.DarkBlue},
- [11] = {background = Screen.colors.DarkBlue, bold = true, reverse = true},
- [12] = {background = Screen.colors.DarkGreen, reverse = true},
- [13] = {background = Screen.colors.Magenta4, reverse = true},
- [14] = {background = Screen.colors.DarkBlue, reverse = true},
- [15] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- [16] = {foreground = Screen.colors.Blue1},
- [17] = {background = Screen.colors.LightRed},
- [18] = {background = Screen.colors.Gray90},
- [19] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray},
- [20] = {background = Screen.colors.LightGrey, underline = true},
- [21] = {bold = true},
- [22] = {bold = true, foreground = Screen.colors.SeaGreen4},
- [23] = {background = Screen.colors.LightMagenta},
- [24] = {background = Screen.colors.WebGray},
- [25] = {bold = true, foreground = Screen.colors.Green1},
- [26] = {background = Screen.colors.Red},
- [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1},
- [28] = {bold = true, foreground = Screen.colors.Brown},
+ screen:set_default_attr_ids {
+ [0] = {bold=true, foreground=Screen.colors.Blue};
+ [1] = {background = Screen.colors.DarkBlue};
+ [2] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Blue1};
+ [3] = {bold = true, reverse = true};
+ [4] = {reverse = true};
+ [5] = {background = Screen.colors.DarkGreen};
+ [6] = {background = Screen.colors.DarkGreen, bold = true, foreground = Screen.colors.Blue1};
+ [7] = {background = Screen.colors.DarkMagenta};
+ [8] = {background = Screen.colors.DarkMagenta, bold = true, foreground = Screen.colors.Blue1};
+ [9] = {foreground = Screen.colors.Brown};
+ [10] = {foreground = Screen.colors.Brown, background = Screen.colors.DarkBlue};
+ [11] = {background = Screen.colors.DarkBlue, bold = true, reverse = true};
+ [12] = {background = Screen.colors.DarkGreen, reverse = true};
+ [13] = {background = Screen.colors.Magenta4, reverse = true};
+ [14] = {background = Screen.colors.DarkBlue, reverse = true};
+ [15] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
+ [16] = {foreground = Screen.colors.Blue1};
+ [17] = {background = Screen.colors.LightRed};
+ [18] = {background = Screen.colors.Gray90};
+ [19] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray};
+ [20] = {background = Screen.colors.LightGrey, underline = true};
+ [21] = {bold = true};
+ [22] = {bold = true, foreground = Screen.colors.SeaGreen4};
+ [23] = {background = Screen.colors.LightMagenta};
+ [24] = {background = Screen.colors.WebGray};
+ [25] = {bold = true, foreground = Screen.colors.Green1};
+ [26] = {background = Screen.colors.Red};
+ [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1};
+ [28] = {bold = true, foreground = Screen.colors.Brown};
[29] = {foreground = Screen.colors.Blue1, background = Screen.colors.Red, bold = true};
- })
+ [30] = {background = tonumber('0xff8800')};
+ [31] = {background = tonumber('0xff8800'), bold = true, foreground = Screen.colors.Blue};
+ }
command("hi Background1 guibg=DarkBlue")
command("hi Background2 guibg=DarkGreen")
end)
@@ -2021,6 +2024,33 @@ describe("'winhighlight' highlight", function()
]])
end)
+ it('updates background to changed linked group', function()
+ command("split")
+ command("setlocal winhl=Normal:FancyGroup") -- does not yet exist
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {3:[No Name] }|
+ |
+ {0:~ }|
+ {4:[No Name] }|
+ |
+ ]]}
+
+ command("hi FancyGroup guibg=#FF8800") -- nice orange
+ screen:expect{grid=[[
+ {30:^ }|
+ {31:~ }|
+ {31:~ }|
+ {3:[No Name] }|
+ |
+ {0:~ }|
+ {4:[No Name] }|
+ |
+ ]]}
+ end)
+
it('background applies also to non-text', function()
command('set sidescroll=0')
insert('Lorem ipsum dolor sit amet ')
@@ -2333,6 +2363,51 @@ describe("'winhighlight' highlight", function()
helpers.assert_alive()
end)
+
+ it('can redraw statusline on cursor movement', function()
+ screen:try_resize(40, 8)
+ exec [[
+ set statusline=%f%=%#Background1#%l,%c%V\ %P
+ split
+ ]]
+ insert [[
+ some text
+ more text]]
+ screen:expect{grid=[[
+ some text |
+ more tex^t |
+ {0:~ }|
+ {3:[No Name] }{1:2,9 All}|
+ some text |
+ more text |
+ {4:[No Name] }{1:1,1 All}|
+ |
+ ]]}
+
+ command 'set winhl=Background1:Background2'
+ screen:expect{grid=[[
+ some text |
+ more tex^t |
+ {0:~ }|
+ {3:[No Name] }{5:2,9 All}|
+ some text |
+ more text |
+ {4:[No Name] }{1:1,1 All}|
+ |
+ ]]}
+
+ feed 'k'
+ screen:expect{grid=[[
+ some tex^t |
+ more text |
+ {0:~ }|
+ {3:[No Name] }{5:1,9 All}|
+ some text |
+ more text |
+ {4:[No Name] }{1:1,1 All}|
+ |
+ ]]}
+ end)
end)
describe('highlight namespaces', function()
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index dc74d6d401..55f873e827 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -4,9 +4,10 @@ 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 testprg = helpers.testprg
local thelpers = require('test.functional.terminal.helpers')
+local skip = helpers.skip
+local is_os = helpers.is_os
describe('ext_hlstate detailed highlights', function()
local screen
@@ -182,7 +183,7 @@ describe('ext_hlstate detailed highlights', function()
end)
it("work with :terminal", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
screen:set_default_attr_ids({
[1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}},
@@ -211,7 +212,7 @@ describe('ext_hlstate detailed highlights', function()
thelpers.set_bold()
thelpers.feed_data('z\n')
-- TODO(bfredl): check if this distinction makes sense
- if iswin() then
+ if is_os('win') then
screen:expect([[
^tty ready |
x {5:y z} |
@@ -237,7 +238,7 @@ describe('ext_hlstate detailed highlights', function()
thelpers.feed_termcode("[A")
thelpers.feed_termcode("[2C")
- if iswin() then
+ if is_os('win') then
screen:expect([[
^tty ready |
x {6:y}{5: z} |
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 9ca4673efe..6fbf9b72c8 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -1190,6 +1190,8 @@ describe(":substitute, inccommand=split", function()
end)
it("deactivates if 'redrawtime' is exceeded #5602", function()
+ -- prevent redraws from 'incsearch'
+ meths.set_option('incsearch', false)
-- Assert that 'inccommand' is ENABLED initially.
eq("split", eval("&inccommand"))
-- Set 'redrawtime' to minimal value, to ensure timeout is triggered.
@@ -2972,6 +2974,59 @@ it(':substitute with inccommand, does not crash if range contains invalid marks'
]])
end)
+it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function()
+ local screen = Screen.new(60, 6)
+ clear()
+ common_setup(screen, 'split', 'test')
+ feed(':ls<CR>')
+ screen:expect([[
+ test |
+ {15:~ }|
+ {11: }|
+ :ls |
+ 1 %a + "[No Name]" line 1 |
+ {13:Press ENTER or type command to continue}^ |
+ ]])
+ feed(':s')
+ -- no unnecessary redraw, so messages are still shown
+ screen:expect([[
+ test |
+ {15:~ }|
+ {11: }|
+ :ls |
+ 1 %a + "[No Name]" line 1 |
+ :s^ |
+ ]])
+ feed('o')
+ screen:expect([[
+ test |
+ {15:~ }|
+ {11: }|
+ :ls |
+ 1 %a + "[No Name]" line 1 |
+ :so^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ test |
+ {15:~ }|
+ {11: }|
+ :ls |
+ 1 %a + "[No Name]" line 1 |
+ :s^ |
+ ]])
+ feed('/test')
+ -- now inccommand is shown, so screen is redrawn
+ screen:expect([[
+ {12:test} |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :s/test^ |
+ ]])
+end)
+
it(":substitute doesn't crash with inccommand, if undo is empty #12932", function()
local screen = Screen.new(10,5)
clear()
@@ -2992,6 +3047,43 @@ it(":substitute doesn't crash with inccommand, if undo is empty #12932", functio
assert_alive()
end)
+it(':substitute with inccommand works properly if undo is not synced #20029', function()
+ local screen = Screen.new(30, 6)
+ clear()
+ common_setup(screen, 'nosplit', 'foo\nbar\nbaz')
+ meths.set_keymap('x', '<F2>', '<Esc>`<Oaaaaa asdf<Esc>`>obbbbb asdf<Esc>V`<k:s/asdf/', {})
+ feed('gg0<C-V>lljj<F2>')
+ screen:expect([[
+ aaaaa |
+ foo |
+ bar |
+ baz |
+ bbbbb |
+ :'<,'>s/asdf/^ |
+ ]])
+ feed('hjkl')
+ screen:expect([[
+ aaaaa {12:hjkl} |
+ foo |
+ bar |
+ baz |
+ bbbbb {12:hjkl} |
+ :'<,'>s/asdf/hjkl^ |
+ ]])
+ feed('<CR>')
+ expect([[
+ aaaaa hjkl
+ foo
+ bar
+ baz
+ bbbbb hjkl]])
+ feed('u')
+ expect([[
+ foo
+ bar
+ baz]])
+end)
+
it('long :%s/ with inccommand does not collapse cmdline', function()
local screen = Screen.new(10,5)
clear()
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index 0b25d4f8d2..43e9b94feb 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -220,7 +220,7 @@ local setup_replace_cmd = [[
end
-- ":<range>Replace <pat1> <pat2>"
- -- Replaces all occurences of <pat1> in <range> with <pat2>
+ -- Replaces all occurrences of <pat1> in <range> with <pat2>
vim.api.nvim_create_user_command(
'Replace',
replace,
diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua
new file mode 100644
index 0000000000..697677aa67
--- /dev/null
+++ b/test/functional/ui/linematch_spec.lua
@@ -0,0 +1,995 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local feed = helpers.feed
+local clear = helpers.clear
+local write_file = helpers.write_file
+
+describe('Diff mode screen with 3 diffs open', function()
+ local fname = 'Xtest-functional-diff-screen-1'
+ local fname_2 = fname .. '.2'
+ local fname_3 = fname .. '.3'
+ local screen
+
+ local reread = function()
+ feed(':e<cr><c-w>w:e<cr><c-w>w:e<cr><c-w>w')
+ end
+
+ setup(function()
+ clear()
+ os.remove(fname)
+ os.remove(fname_2)
+ os.remove(fname_3)
+ end)
+
+ teardown(function()
+ os.remove(fname)
+ os.remove(fname_2)
+ os.remove(fname_3)
+ end)
+
+ before_each(function()
+ clear()
+ feed(':set diffopt+=linematch:30<cr>')
+ feed(':e ' .. fname .. '<cr>')
+ feed(':vnew ' .. fname_2 .. '<cr>')
+ feed(':vnew ' .. fname_3 .. '<cr>')
+ feed(':windo diffthis<cr>')
+
+ screen = Screen.new(100, 16)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightCyan1};
+ [3] = {reverse = true};
+ [4] = {background = Screen.colors.LightBlue};
+ [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
+ [6] = {foreground = Screen.colors.Blue1, bold = true};
+ [7] = {reverse = true, bold = true};
+ [8] = {background = Screen.colors.Red1, bold = true};
+ [10] = {foreground = Screen.colors.Brown};
+ [9] = {background = Screen.colors.Plum1};
+ })
+ feed('<c-w>=')
+ feed(':windo set nu!<cr>')
+ end)
+
+ describe('setup the diff screen to look like a merge conflict with 3 files in diff mode', function()
+ before_each(function()
+
+ local f1 = [[
+
+ common line
+ AAA
+ AAA
+ AAA
+ ]]
+ local f2 = [[
+
+ common line
+ <<<<<<< HEAD
+ AAA
+ AAA
+ AAA
+ =======
+ BBB
+ BBB
+ BBB
+ >>>>>>> branch1
+ ]]
+ local f3 = [[
+
+ common line
+ BBB
+ BBB
+ BBB
+ ]]
+
+ write_file(fname, f1, false)
+ write_file(fname_2, f2, false)
+ write_file(fname_3, f3, false)
+ reread()
+ end)
+
+ it('get from window 1', function()
+ feed('1<c-w>w')
+ feed(':2,6diffget screen-1.2<cr>')
+ screen:expect([[
+ {1: }{10: 1 }^ │{1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }{9:<<<<<<< HEAD }│{1: }{10: 3 }{9:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 4 } AAA │{1: }{10: 4 } AAA │{1: }{10: 3 } AAA |
+ {1: }{10: 5 } AAA │{1: }{10: 5 } AAA │{1: }{10: 4 } AAA |
+ {1: }{10: 6 } AAA │{1: }{10: 6 } AAA │{1: }{10: 5 } AAA |
+ {1: }{10: 7 }{9:======= }│{1: }{10: 7 }{9:======= }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 8 }{9: BBB }│{1: }{10: 8 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 9 }{9: BBB }│{1: }{10: 9 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 10 }{9: BBB }│{1: }{10: 10 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 12 } │{1: }{10: 12 } │{1: }{10: 6 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {7:<-functional-diff-screen-1.3 [+] }{3:<est-functional-diff-screen-1.2 Xtest-functional-diff-screen-1 }|
+ :2,6diffget screen-1.2 |
+ ]])
+ end)
+
+ it('get from window 2', function()
+ feed('2<c-w>w')
+ feed(':5,7diffget screen-1.3<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: 3 }{9: BBB }│{1: }{10: 5 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 4 }{9: }{8:BBB}{9: }│{1: }{10: 6 }{9: }{8:BBB}{9: }│{1: }{10: 4 }{9: }{8:AAA}{9: }|
+ {1: }{10: 5 }{9: }{8:BBB}{9: }│{1: }{10: 7 }{9: }{8:BBB}{9: }│{1: }{10: 5 }{9: }{8:AAA}{9: }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 8 }{4:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 6 } │{1: }{10: 9 } │{1: }{10: 6 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 }{7:<functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :5,7diffget screen-1.3 |
+ ]])
+ end)
+
+ it('get from window 3', function()
+ feed('3<c-w>w')
+ feed(':5,6diffget screen-1.2<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } │{1: }{10: 1 }^ |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }|
+ {1: }{10: 3 } BBB │{1: }{10: 8 } BBB │{1: }{10: 7 } BBB |
+ {1: }{10: 4 } BBB │{1: }{10: 9 } BBB │{1: }{10: 8 } BBB |
+ {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 9 } BBB |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 10 }{9:>>>>>>> branch1 }|
+ {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 11 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 <est-functional-diff-screen-1.2 }{7:<st-functional-diff-screen-1 [+] }|
+ :5,6diffget screen-1.2 |
+ ]])
+ end)
+
+ it('put from window 2 - part', function()
+ feed('2<c-w>w')
+ feed(':6,8diffput screen-1<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }|
+ {1: }{10: 3 }{9: BBB }│{1: }{10: 8 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 4 }{9: BBB }│{1: }{10: 9 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 7 } BBB |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{4:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 8 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 }{7:<est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }|
+ :6,8diffput screen-1 |
+ ]])
+
+ end)
+ it('put from window 2 - part to end', function()
+ feed('2<c-w>w')
+ feed(':6,11diffput screen-1<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }|
+ {1: }{10: 3 } BBB │{1: }{10: 8 } BBB │{1: }{10: 7 } BBB |
+ {1: }{10: 4 } BBB │{1: }{10: 9 } BBB │{1: }{10: 8 } BBB |
+ {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 9 } BBB |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 10 }{9:>>>>>>> branch1 }|
+ {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 11 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 }{7:<est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }|
+ :6,11diffput screen-1 |
+ ]])
+
+ end)
+ end)
+end)
+
+describe('Diff mode screen with 2 diffs open', function()
+ local fname = 'Xtest-functional-diff-screen-1'
+ local fname_2 = fname .. '.2'
+ local screen
+
+ local reread = function()
+ feed(':e<cr><c-w>w:e<cr><c-w>w:e<cr><c-w>w')
+ end
+
+ setup(function()
+ clear()
+ os.remove(fname)
+ os.remove(fname_2)
+ end)
+
+ teardown(function()
+ os.remove(fname)
+ os.remove(fname_2)
+ end)
+
+ before_each(function()
+ clear()
+ feed(':e ' .. fname .. '<cr>')
+ feed(':vnew ' .. fname_2 .. '<cr>')
+ feed(':windo diffthis<cr>')
+
+ screen = Screen.new(100, 20)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightCyan1};
+ [3] = {reverse = true};
+ [4] = {background = Screen.colors.LightBlue};
+ [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
+ [6] = {foreground = Screen.colors.Blue1, bold = true};
+ [7] = {reverse = true, bold = true};
+ [8] = {background = Screen.colors.Red1, bold = true};
+ [10] = {foreground = Screen.colors.Brown};
+ [9] = {background = Screen.colors.Plum1};
+ })
+ feed('<c-w>=')
+ feed(':windo set nu!<cr>')
+ end)
+
+ describe('setup a diff with 2 files and set linematch:30', function()
+ before_each(function()
+ feed(':set diffopt+=linematch:30<cr>')
+ local f1 = [[
+
+common line
+common line
+
+DEFabc
+xyz
+xyz
+xyz
+DEFabc
+DEFabc
+DEFabc
+common line
+common line
+DEF
+common line
+DEF
+something
+ ]]
+ local f2 = [[
+
+common line
+common line
+
+ABCabc
+ABCabc
+ABCabc
+ABCabc
+common line
+common line
+common line
+something
+ ]]
+ write_file(fname, f1, false)
+ write_file(fname_2, f2, false)
+ reread()
+ end)
+
+ it('get from window 1 from line 5 to 9', function()
+ feed('1<c-w>w')
+ feed(':5,9diffget<cr>')
+ screen:expect([[
+ {1:+ }{10: 1 }{5:^+-- 7 lines: common line··················}│{1:+ }{10: 1 }{5:+-- 7 lines: common line···················}|
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 10 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 11 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 14 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 15 }something │{1: }{10: 17 }something |
+ {1: }{10: 16 } │{1: }{10: 18 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :5,9diffget |
+ ]])
+ end)
+ it('get from window 2 from line 5 to 10', function()
+ feed('2<c-w>w')
+ feed(':5,10diffget<cr>')
+ screen:expect([[
+ {1:- }{10: 1 } │{1:- }{10: 1 }^ |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }ABCabc │{1: }{10: 5 }ABCabc |
+ {1: }{10: 6 }ABCabc │{1: }{10: 6 }ABCabc |
+ {1: }{10: 7 }ABCabc │{1: }{10: 7 }ABCabc |
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 8 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 9 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 10 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 11 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 12 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 13 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 14 }something |
+ {1: }{10: 13 } │{1: }{10: 15 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :5,10diffget |
+ ]])
+ end)
+ it('get all from window 2', function()
+ feed('2<c-w>w')
+ feed(':4,17diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }ABCabc │{1: }{10: 5 }ABCabc |
+ {1: }{10: 6 }ABCabc │{1: }{10: 6 }ABCabc |
+ {1: }{10: 7 }ABCabc │{1: }{10: 7 }ABCabc |
+ {1: }{10: 8 }ABCabc │{1: }{10: 8 }ABCabc |
+ {1: }{10: 9 }common line │{1: }{10: 9 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 11 }common line │{1: }{10: 11 }common line |
+ {1: }{10: 12 }something │{1: }{10: 12 }something |
+ {1: }{10: 13 } │{1: }{10: 13 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :4,17diffget |
+ ]])
+
+ end)
+ it('get all from window 1', function()
+ feed('1<c-w>w')
+ feed(':4,12diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }DEFabc │{1: }{10: 5 }DEFabc |
+ {1: }{10: 6 }xyz │{1: }{10: 6 }xyz |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 10 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 11 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 14 }DEF │{1: }{10: 14 }DEF |
+ {1: }{10: 15 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 16 }DEF │{1: }{10: 16 }DEF |
+ {1: }{10: 17 }something │{1: }{10: 17 }something |
+ {1: }{10: 18 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :4,12diffget |
+ ]])
+ end)
+ it('get from window 1 using do 1 line 5', function()
+ feed('1<c-w>w')
+ feed('5gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }^DEFabc │{1: }{10: 5 }DEFabc |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 6', function()
+ feed('1<c-w>w')
+ feed('6gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }^DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 7 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 7', function()
+ feed('1<c-w>w')
+ feed('7gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 7 }^DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 11', function()
+ feed('1<c-w>w')
+ feed('11gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 11 }DEF │{1: }{10: 14 }DEF |
+ {1: }{10: 12 }^common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 13 }something │{1: }{10: 17 }something |
+ {1: }{10: 14 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 12', function()
+ feed('1<c-w>w')
+ feed('12gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 12 }DEF │{1: }{10: 16 }DEF |
+ {1: }{10: 13 }^something │{1: }{10: 17 }something |
+ {1: }{10: 14 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 1 line 5', function()
+ feed('1<c-w>w')
+ feed('5gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }^ABCabc │{1: }{10: 5 }ABCabc |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 6', function()
+ feed('1<c-w>w')
+ feed('6gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }^ABCabc │{1: }{10: 9 }ABCabc |
+ {1: }{10: 7 }ABCabc │{1: }{10: 10 }ABCabc |
+ {1: }{10: 8 }ABCabc │{1: }{10: 11 }ABCabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 7', function()
+ feed('1<c-w>w')
+ feed('7gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }ABCabc │{1: }{10: 9 }ABCabc |
+ {1: }{10: 7 }^ABCabc │{1: }{10: 10 }ABCabc |
+ {1: }{10: 8 }ABCabc │{1: }{10: 11 }ABCabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 11', function()
+ feed('1<c-w>w')
+ feed('11gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 11 }^common line │{1: }{10: 14 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 15 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 16 }something |
+ {1: }{10: 13 } │{1: }{10: 17 } |
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 12', function()
+ feed('1<c-w>w')
+ feed('12gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 12 }^something │{1: }{10: 16 }something |
+ {1: }{10: 13 } │{1: }{10: 17 } |
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 6', function()
+ feed('2<c-w>w')
+ feed('6gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: 6 }xyz │{1: }{10: 6 }^xyz |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 10 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 11 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 14 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 15 }something │{1: }{10: 17 }something |
+ {1: }{10: 16 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 8', function()
+ feed('2<c-w>w')
+ feed('8gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: 6 }xyz │{1: }{10: 6 }xyz |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }^xyz |
+ {1: }{10: 9 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 10 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 11 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 14 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 15 }something │{1: }{10: 17 }something |
+ {1: }{10: 16 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 9', function()
+ feed('2<c-w>w')
+ feed('9gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }DEFabc │{1: }{10: 9 }^DEFabc |
+ {1: }{10: 7 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 17', function()
+ feed('2<c-w>w')
+ feed('17gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 12 }DEF │{1: }{10: 16 }DEF |
+ {1: }{10: 13 }something │{1: }{10: 17 }^something |
+ {1: }{10: 14 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+
+ end)
+ end)
+ describe('setup a diff with 2 files and set linematch:10', function()
+ before_each(function()
+ feed(':set diffopt+=linematch:10<cr>')
+ local f1 = [[
+common line
+HIL
+
+aABCabc
+aABCabc
+aABCabc
+aABCabc
+common line
+HIL
+common line
+something
+ ]]
+ local f2 = [[
+common line
+DEF
+GHI
+something
+
+aDEFabc
+xyz
+xyz
+xyz
+aDEFabc
+aDEFabc
+aDEFabc
+common line
+DEF
+GHI
+something else
+common line
+something
+ ]]
+ write_file(fname, f1, false)
+ write_file(fname_2, f2, false)
+ reread()
+ end)
+
+ it('enable linematch for the longest diff block by increasing the number argument passed to linematch', function()
+ feed('1<c-w>w')
+ -- linematch is disabled for the longest diff because it's combined line length is over 10
+ screen:expect([[
+ {1: }{10: 1 }^common line │{1: }{10: 1 }common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }|
+ {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }|
+ {1: }{10: 9 }{8:xyz}{9: }│{1: }{10: 7 }{8:aABCabc}{9: }|
+ {1: }{10: 10 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 11 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 12 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 13 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 9 }{8:HIL}{9: }|
+ {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 17 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 18 }something │{1: }{10: 11 }something |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ -- enable it by increasing the number
+ feed(":set diffopt-=linematch:10<cr>")
+ feed(":set diffopt+=linematch:30<cr>")
+ screen:expect([[
+ {1: }{10: 1 }^common line │{1: }{10: 1 }common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 8 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 9 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 10 }{9:a}{8:DEF}{9:abc }│{1: }{10: 5 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 11 }{9:a}{8:DEF}{9:abc }│{1: }{10: 6 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 12 }{9:a}{8:DEF}{9:abc }│{1: }{10: 7 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 13 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 9 }{8:HIL}{9: }|
+ {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 17 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 18 }something │{1: }{10: 11 }something |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 }|
+ :set diffopt+=linematch:30 |
+ ]])
+ end)
+ it('get all from second window', function()
+ feed('2<c-w>w')
+ feed(':1,12diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }common line │{1: }{10: 1 }^common line |
+ {1: }{10: 2 }DEF │{1: }{10: 2 }DEF |
+ {1: }{10: 3 }GHI │{1: }{10: 3 }GHI |
+ {1: }{10: 4 }something │{1: }{10: 4 }something |
+ {1: }{10: 5 } │{1: }{10: 5 } |
+ {1: }{10: 6 }aDEFabc │{1: }{10: 6 }aDEFabc |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }xyz │{1: }{10: 9 }xyz |
+ {1: }{10: 10 }aDEFabc │{1: }{10: 10 }aDEFabc |
+ {1: }{10: 11 }aDEFabc │{1: }{10: 11 }aDEFabc |
+ {1: }{10: 12 }aDEFabc │{1: }{10: 12 }aDEFabc |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 14 }DEF │{1: }{10: 14 }DEF |
+ {1: }{10: 15 }GHI │{1: }{10: 15 }GHI |
+ {1: }{10: 16 }something else │{1: }{10: 16 }something else |
+ {1: }{10: 17 }common line │{1: }{10: 17 }common line |
+ {1: }{10: 18 }something │{1: }{10: 18 }something |
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :1,12diffget |
+ ]])
+ end)
+ it('get all from first window', function()
+ feed('1<c-w>w')
+ feed(':1,19diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }^common line │{1: }{10: 1 }common line |
+ {1: }{10: 2 }HIL │{1: }{10: 2 }HIL |
+ {1: }{10: 3 } │{1: }{10: 3 } |
+ {1: }{10: 4 }aABCabc │{1: }{10: 4 }aABCabc |
+ {1: }{10: 5 }aABCabc │{1: }{10: 5 }aABCabc |
+ {1: }{10: 6 }aABCabc │{1: }{10: 6 }aABCabc |
+ {1: }{10: 7 }aABCabc │{1: }{10: 7 }aABCabc |
+ {1: }{10: 8 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 9 }HIL │{1: }{10: 9 }HIL |
+ {1: }{10: 10 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 11 }something │{1: }{10: 11 }something |
+ {1: }{10: 12 } │{1: }{10: 12 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :1,19diffget |
+ ]])
+ end)
+ it('get part of the non linematched diff block in window 2 line 7 - 8 (non line matched block)', function()
+ feed('2<c-w>w')
+ feed(':7,8diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }common line │{1: }{10: 1 }^common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }|
+ {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }|
+ {1: }{10: 9 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 10 }aDEFabc │{1: }{10: 8 }aDEFabc |
+ {1: }{10: 11 }aDEFabc │{1: }{10: 9 }aDEFabc |
+ {1: }{10: 12 }aDEFabc │{1: }{10: 10 }aDEFabc |
+ {1: }{10: 13 }common line │{1: }{10: 11 }common line |
+ {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 12 }{8:HIL}{9: }|
+ {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 17 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 18 }something │{1: }{10: 14 }something |
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :7,8diffget |
+ ]])
+ end)
+ it('get part of the non linematched diff block in window 2 line 8 - 10 (line matched block)', function()
+ feed('2<c-w>w')
+ feed(':8,10diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }common line │{1: }{10: 1 }^common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }|
+ {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }|
+ {1: }{10: 9 }{8:xyz}{9: }│{1: }{10: 7 }{8:aABCabc}{9: }|
+ {1: }{10: 10 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 11 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 12 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 13 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 14 }DEF │{1: }{10: 9 }DEF |
+ {1: }{10: 15 }GHI │{1: }{10: 10 }GHI |
+ {1: }{10: 16 }something else │{1: }{10: 11 }something else |
+ {1: }{10: 17 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 18 }something │{1: }{10: 13 }something |
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :8,10diffget |
+ ]])
+ end)
+ end)
+end)
+
+describe('regressions', function()
+ local screen
+
+ it("doesn't crash with long lines", function()
+ clear()
+ feed(':set diffopt+=linematch:30<cr>')
+ screen = Screen.new(100, 20)
+ screen:attach()
+ -- line must be greater than MATCH_CHAR_MAX_LEN
+ helpers.curbufmeths.set_lines(0, -1, false, { string.rep('a', 1000)..'hello' })
+ helpers.exec 'vnew'
+ helpers.curbufmeths.set_lines(0, -1, false, { string.rep('a', 1010)..'world' })
+ helpers.exec 'windo diffthis'
+ end)
+end)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 2cff7c1cf4..3052a74f38 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -9,10 +9,13 @@ local meths = helpers.meths
local async_meths = helpers.async_meths
local test_build_dir = helpers.test_build_dir
local nvim_prog = helpers.nvim_prog
-local iswin = helpers.iswin
+local exec = helpers.exec
local exc_exec = helpers.exc_exec
local exec_lua = helpers.exec_lua
local poke_eventloop = helpers.poke_eventloop
+local assert_alive = helpers.assert_alive
+local is_os = helpers.is_os
+local is_ci = helpers.is_ci
describe('ui/ext_messages', function()
local screen
@@ -869,7 +872,7 @@ stack traceback:
{1:~ }|
{1:~ }|
]], messages={
- { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "" }
+ { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "echomsg" }
}}
feed ':ls<cr>'
@@ -880,7 +883,7 @@ stack traceback:
{1:~ }|
{1:~ }|
]], messages={
- { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = "echomsg" }
+ { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = "" }
}}
feed ':messages<cr>'
@@ -905,6 +908,13 @@ stack traceback:
{1:~ }|
]]}
end)
+
+ it('does not truncate messages', function()
+ command('write Xtest')
+ screen:expect({messages={
+ {content = { { '"Xtest" [New] 0L, 0B written' } }, kind = "" }
+ }})
+ end)
end)
describe('ui/builtin messages', function()
@@ -1077,10 +1087,10 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
]]}
end)
- it('redraws NOT_VALID correctly after message', function()
- -- edge case: only one window was set NOT_VALID. Original report
+ it('redraws UPD_NOT_VALID correctly after message', function()
+ -- edge case: only one window was set UPD_NOT_VALID. Original report
-- used :make, but fake it using one command to set the current
- -- window NOT_VALID and another to show a long message.
+ -- window UPD_NOT_VALID and another to show a long message.
command("set more")
feed(':new<cr><c-w><c-w>')
screen:expect{grid=[[
@@ -1200,28 +1210,6 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
it('prints lines in Ex mode correctly with a burst of carriage returns #19341', function()
command('set number')
meths.buf_set_lines(0, 0, 0, true, {'aaa', 'bbb', 'ccc'})
- command('set display-=msgsep')
- feed('gggQ<CR><CR>1<CR><CR>vi')
- screen:expect([[
- Entering Ex mode. Type "visual" to go to Normal mode. |
- {11: 2 }bbb |
- {11: 3 }ccc |
- :1 |
- {11: 1 }aaa |
- {11: 2 }bbb |
- :vi^ |
- ]])
- feed('<CR>')
- screen:expect([[
- {11: 1 }aaa |
- {11: 2 }^bbb |
- {11: 3 }ccc |
- {11: 4 } |
- {1:~ }|
- {1:~ }|
- |
- ]])
- command('set display+=msgsep')
feed('gggQ<CR><CR>1<CR><CR>vi')
screen:expect([[
Entering Ex mode. Type "visual" to go to Normal mode. |
@@ -1256,6 +1244,45 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
bar^ |
]])
end)
+
+ it('consecutive calls to win_move_statusline() work after multiline message #21014',function()
+ async_meths.exec([[
+ echo "\n"
+ call win_move_statusline(0, -4)
+ call win_move_statusline(0, 4)
+ ]], false)
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3: }|
+ |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ eq(1, meths.get_option('cmdheight'))
+ end)
+end)
+
+it('calling screenstring() after redrawing between messages without UI #20999', function()
+ clear()
+ exec([[
+ echo repeat('a', 100)
+ redraw
+ echo "\n"
+ call screenstring(1, 1)
+ ]])
+ assert_alive()
end)
describe('ui/ext_messages', function()
@@ -1285,7 +1312,6 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
{1:~ }|
- {1:~ }|
{MATCH:.*}|
{1:~ }|
{1:~ }Nvim is open source and freely distributable{1: }|
@@ -1296,6 +1322,8 @@ describe('ui/ext_messages', function()
{1:~ }type :q{5:<Enter>} to exit {1: }|
{1:~ }type :help{5:<Enter>} for help {1: }|
{1:~ }|
+ {1:~ }type :help news{5:<Enter>} to see changes in v{MATCH:%d+%.%d+}|
+ {1:~ }|
{MATCH:.*}|
{MATCH:.*}|
{1:~ }|
@@ -1303,7 +1331,6 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
{1:~ }|
- {1:~ }|
]])
feed("<c-l>")
@@ -1341,7 +1368,6 @@ describe('ui/ext_messages', function()
|
|
|
- |
{MATCH:.*}|
|
Nvim is open source and freely distributable |
@@ -1352,6 +1378,8 @@ describe('ui/ext_messages', function()
type :q{5:<Enter>} to exit |
type :help{5:<Enter>} for help |
|
+ type :help news{5:<Enter>} to see changes in v{MATCH:%d+%.%d+}|
+ |
{MATCH:.*}|
{MATCH:.*}|
|
@@ -1359,7 +1387,6 @@ describe('ui/ext_messages', function()
|
|
|
- |
]], messages={
{content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" }
}}
@@ -1432,7 +1459,6 @@ describe('ui/ext_messages', function()
feed(":set mouse=a<cr>")
meths.input_mouse('left', 'press', '', 0, 12, 10)
poke_eventloop()
- meths.input_mouse('left', 'drag', '', 0, 12, 10)
meths.input_mouse('left', 'drag', '', 0, 11, 10)
feed("<c-l>")
feed(":set cmdheight<cr>")
@@ -1477,7 +1503,7 @@ describe('ui/msg_puts_printf', function()
screen = Screen.new(25, 5)
screen:attach()
- if iswin() then
+ if is_os('win') then
if os.execute('chcp 932 > NUL 2>&1') ~= 0 then
pending('missing japanese language features', function() end)
return
@@ -1488,7 +1514,7 @@ describe('ui/msg_puts_printf', function()
if (exc_exec('lang ja_JP.UTF-8') ~= 0) then
pending('Locale ja_JP.UTF-8 not supported', function() end)
return
- elseif helpers.isCI() then
+ elseif is_ci() then
-- Fails non--Windows CI. Message catalog directory issue?
pending('fails on unix CI', function() end)
return
@@ -2020,4 +2046,55 @@ aliquip ex ea commodo consequat.]])
|
]]}
end)
+
+ it('with cmdheight=0 does not crash with g<', function()
+ command('set cmdheight=0')
+ feed(':ls<cr>')
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {12: }|
+ :ls |
+ 1 %a "[No Name]" |
+ line 1 |
+ {4:Press ENTER or type command to cont}|
+ {4:inue}^ |
+ ]]}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+
+ feed('g<lt>')
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {12: }|
+ :ls |
+ 1 %a "[No Name]" |
+ line 1 |
+ {4:Press ENTER or type command to cont}|
+ {4:inue}^ |
+ ]]}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+ end)
end)
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index 9390f268b3..cf4eb034e0 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -17,6 +17,7 @@ describe('ui mode_change event', function()
[1] = {bold=true, reverse=true},
[2] = {bold=true},
[3] = {reverse=true},
+ [4] = {background=Screen.colors.Red, foreground=Screen.colors.White}, -- ErrorMsg
})
end)
@@ -43,6 +44,25 @@ describe('ui mode_change event', function()
{0:~ }|
|
]], mode="normal"}
+
+ screen:try_resize(50, 4)
+ command('set nomodifiable')
+
+ feed('c')
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]], mode="operator"}
+
+ feed('c')
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {4:E21: Cannot make changes, 'modifiable' is off} |
+ ]], mode="normal"}
end)
it('works in insert mode', function()
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 9896b11218..f705678bd5 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -4,6 +4,7 @@ local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
local insert, feed_command = helpers.insert, helpers.feed_command
local eq, funcs = helpers.eq, helpers.funcs
local command = helpers.command
+local exec = helpers.exec
describe('ui/mouse/input', function()
local screen
@@ -648,8 +649,10 @@ describe('ui/mouse/input', function()
]]}
end)
- it('two clicks will select the word and enter VISUAL', function()
- feed('<LeftMouse><2,2><LeftMouse><2,2>')
+ it('two clicks will enter VISUAL and dragging selects words', function()
+ feed('<LeftMouse><2,2>')
+ feed('<LeftRelease><2,2>')
+ feed('<LeftMouse><2,2>')
screen:expect([[
testing |
mouse |
@@ -657,10 +660,38 @@ describe('ui/mouse/input', function()
{0:~ }|
{2:-- VISUAL --} |
]])
+ feed('<LeftDrag><0,1>')
+ screen:expect([[
+ testing |
+ ^m{1:ouse} |
+ {1:support} and selection |
+ {0:~ }|
+ {2:-- VISUAL --} |
+ ]])
+ feed('<LeftDrag><4,0>')
+ screen:expect([[
+ ^t{1:esting} |
+ {1:mouse} |
+ {1:support} and selection |
+ {0:~ }|
+ {2:-- VISUAL --} |
+ ]])
+ feed('<LeftDrag><14,2>')
+ screen:expect([[
+ testing |
+ mouse |
+ {1:support and selectio}^n |
+ {0:~ }|
+ {2:-- VISUAL --} |
+ ]])
end)
- it('three clicks will select the line and enter VISUAL LINE', function()
- feed('<LeftMouse><2,2><LeftMouse><2,2><LeftMouse><2,2>')
+ it('three clicks will enter VISUAL LINE and dragging selects lines', function()
+ feed('<LeftMouse><2,2>')
+ feed('<LeftRelease><2,2>')
+ feed('<LeftMouse><2,2>')
+ feed('<LeftRelease><2,2>')
+ feed('<LeftMouse><2,2>')
screen:expect([[
testing |
mouse |
@@ -668,10 +699,40 @@ describe('ui/mouse/input', function()
{0:~ }|
{2:-- VISUAL LINE --} |
]])
+ feed('<LeftDrag><0,1>')
+ screen:expect([[
+ testing |
+ ^m{1:ouse} |
+ {1:support and selection} |
+ {0:~ }|
+ {2:-- VISUAL LINE --} |
+ ]])
+ feed('<LeftDrag><4,0>')
+ screen:expect([[
+ {1:test}^i{1:ng} |
+ {1:mouse} |
+ {1:support and selection} |
+ {0:~ }|
+ {2:-- VISUAL LINE --} |
+ ]])
+ feed('<LeftDrag><14,2>')
+ screen:expect([[
+ testing |
+ mouse |
+ {1:support and se}^l{1:ection} |
+ {0:~ }|
+ {2:-- VISUAL LINE --} |
+ ]])
end)
- it('four clicks will enter VISUAL BLOCK', function()
- feed('<LeftMouse><2,2><LeftMouse><2,2><LeftMouse><2,2><LeftMouse><2,2>')
+ it('four clicks will enter VISUAL BLOCK and dragging selects blockwise', function()
+ feed('<LeftMouse><2,2>')
+ feed('<LeftRelease><2,2>')
+ feed('<LeftMouse><2,2>')
+ feed('<LeftRelease><2,2>')
+ feed('<LeftMouse><2,2>')
+ feed('<LeftRelease><2,2>')
+ feed('<LeftMouse><2,2>')
screen:expect([[
testing |
mouse |
@@ -679,6 +740,30 @@ describe('ui/mouse/input', function()
{0:~ }|
{2:-- VISUAL BLOCK --} |
]])
+ feed('<LeftDrag><0,1>')
+ screen:expect([[
+ testing |
+ ^m{1:ou}se |
+ {1:sup}port and selection |
+ {0:~ }|
+ {2:-- VISUAL BLOCK --} |
+ ]])
+ feed('<LeftDrag><4,0>')
+ screen:expect([[
+ te{1:st}^ing |
+ mo{1:use} |
+ su{1:ppo}rt and selection |
+ {0:~ }|
+ {2:-- VISUAL BLOCK --} |
+ ]])
+ feed('<LeftDrag><14,2>')
+ screen:expect([[
+ testing |
+ mouse |
+ su{1:pport and se}^lection |
+ {0:~ }|
+ {2:-- VISUAL BLOCK --} |
+ ]])
end)
it('right click extends visual selection to the clicked location', function()
@@ -883,6 +968,49 @@ describe('ui/mouse/input', function()
]])
end)
+ it("'sidescrolloff' applies to horizontal scrolling", function()
+ command('set nowrap')
+ command('set sidescrolloff=4')
+
+ feed("I <esc>020ib<esc>0")
+ screen:expect([[
+ testing |
+ mouse |
+ ^bbbbbbbbbbbbbbbbbbbb supp|
+ {0:~ }|
+ |
+ ]])
+
+ meths.input_mouse('wheel', 'right', '', 0, 0, 27)
+ screen:expect([[
+ g |
+ |
+ bbbb^bbbbbbbbbb support an|
+ {0:~ }|
+ |
+ ]])
+
+ -- window-local 'sidescrolloff' should override global value. #21162
+ command('setlocal sidescrolloff=2')
+ feed('0')
+ screen:expect([[
+ testing |
+ mouse |
+ ^bbbbbbbbbbbbbbbbbbbb supp|
+ {0:~ }|
+ |
+ ]])
+
+ meths.input_mouse('wheel', 'right', '', 0, 0, 27)
+ screen:expect([[
+ g |
+ |
+ bb^bbbbbbbbbbbb support an|
+ {0:~ }|
+ |
+ ]])
+ end)
+
describe('on concealed text', function()
-- Helpful for reading the test expectations:
-- :match Error /\^/
@@ -1585,9 +1713,151 @@ describe('ui/mouse/input', function()
eq(0, meths.get_var('mouse_up2'))
end)
- it('feeding <MouseMove> does not use uninitialized memory #19480', function()
+ it('<MouseMove> is not translated into multiclicks and can be mapped', function()
+ meths.set_var('mouse_move', 0)
+ meths.set_var('mouse_move2', 0)
+ command('nnoremap <MouseMove> <Cmd>let g:mouse_move += 1<CR>')
+ command('nnoremap <2-MouseMove> <Cmd>let g:mouse_move2 += 1<CR>')
+ feed('<MouseMove><0,0>')
+ feed('<MouseMove><0,0>')
+ meths.input_mouse('move', '', '', 0, 0, 0)
+ meths.input_mouse('move', '', '', 0, 0, 0)
+ eq(4, meths.get_var('mouse_move'))
+ eq(0, meths.get_var('mouse_move2'))
+ end)
+
+ it('feeding <MouseMove> in Normal mode does not use uninitialized memory #19480', function()
feed('<MouseMove>')
helpers.poke_eventloop()
helpers.assert_alive()
end)
+
+ it('mousemodel=popup_setpos', function()
+ screen:try_resize(80, 24)
+ exec([[
+ 5new
+ call setline(1, ['the dish ran away with the spoon',
+ \ 'the cow jumped over the moon' ])
+
+ set mouse=a mousemodel=popup_setpos
+
+ aunmenu PopUp
+ nmenu PopUp.foo :let g:menustr = 'foo'<CR>
+ nmenu PopUp.bar :let g:menustr = 'bar'<CR>
+ nmenu PopUp.baz :let g:menustr = 'baz'<CR>
+ vmenu PopUp.foo y:<C-U>let g:menustr = 'foo'<CR>
+ vmenu PopUp.bar y:<C-U>let g:menustr = 'bar'<CR>
+ vmenu PopUp.baz y:<C-U>let g:menustr = 'baz'<CR>
+ ]])
+
+ meths.win_set_cursor(0, {1, 0})
+ meths.input_mouse('right', 'press', '', 0, 0, 4)
+ meths.input_mouse('right', 'release', '', 0, 0, 4)
+ feed('<Down><Down><CR>')
+ eq('bar', meths.get_var('menustr'))
+ eq({1, 4}, meths.win_get_cursor(0))
+
+ -- Test for right click in visual mode inside the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 9})
+ feed('vee')
+ meths.input_mouse('right', 'press', '', 0, 0, 11)
+ meths.input_mouse('right', 'release', '', 0, 0, 11)
+ feed('<Down><CR>')
+ eq({1, 9}, meths.win_get_cursor(0))
+ eq('ran away', funcs.getreg('"'))
+
+ -- Test for right click in visual mode right before the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 9})
+ feed('vee')
+ meths.input_mouse('right', 'press', '', 0, 0, 8)
+ meths.input_mouse('right', 'release', '', 0, 0, 8)
+ feed('<Down><CR>')
+ eq({1, 8}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('"'))
+
+ -- Test for right click in visual mode right after the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 9})
+ feed('vee')
+ meths.input_mouse('right', 'press', '', 0, 0, 17)
+ meths.input_mouse('right', 'release', '', 0, 0, 17)
+ feed('<Down><CR>')
+ eq({1, 17}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('"'))
+
+ -- Test for right click in block-wise visual mode inside the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 15})
+ feed('<C-V>j3l')
+ meths.input_mouse('right', 'press', '', 0, 1, 16)
+ meths.input_mouse('right', 'release', '', 0, 1, 16)
+ feed('<Down><CR>')
+ eq({1, 15}, meths.win_get_cursor(0))
+ eq('\0224', funcs.getregtype('"'))
+
+ -- Test for right click in block-wise visual mode outside the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 15})
+ feed('<C-V>j3l')
+ meths.input_mouse('right', 'press', '', 0, 1, 1)
+ meths.input_mouse('right', 'release', '', 0, 1, 1)
+ feed('<Down><CR>')
+ eq({2, 1}, meths.win_get_cursor(0))
+ eq('v', funcs.getregtype('"'))
+ eq('', funcs.getreg('"'))
+
+ -- Test for right click in line-wise visual mode inside the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 15})
+ feed('V')
+ meths.input_mouse('right', 'press', '', 0, 0, 9)
+ meths.input_mouse('right', 'release', '', 0, 0, 9)
+ feed('<Down><CR>')
+ eq({1, 0}, meths.win_get_cursor(0)) -- After yanking, the cursor goes to 1,1
+ eq('V', funcs.getregtype('"'))
+ eq(1, #funcs.getreg('"', 1, true))
+
+ -- Test for right click in multi-line line-wise visual mode inside the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 15})
+ feed('Vj')
+ meths.input_mouse('right', 'press', '', 0, 1, 19)
+ meths.input_mouse('right', 'release', '', 0, 1, 19)
+ feed('<Down><CR>')
+ eq({1, 0}, meths.win_get_cursor(0)) -- After yanking, the cursor goes to 1,1
+ eq('V', funcs.getregtype('"'))
+ eq(2, #funcs.getreg('"', 1, true))
+
+ -- Test for right click in line-wise visual mode outside the selection
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 15})
+ feed('V')
+ meths.input_mouse('right', 'press', '', 0, 1, 9)
+ meths.input_mouse('right', 'release', '', 0, 1, 9)
+ feed('<Down><CR>')
+ eq({2, 9}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('"'))
+
+ -- Try clicking on the status line
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {1, 9})
+ feed('vee')
+ meths.input_mouse('right', 'press', '', 0, 5, 1)
+ meths.input_mouse('right', 'release', '', 0, 5, 1)
+ feed('<Down><CR>')
+ eq({1, 9}, meths.win_get_cursor(0))
+ eq('ran away', funcs.getreg('"'))
+
+ -- Try clicking outside the window
+ funcs.setreg('"', '')
+ meths.win_set_cursor(0, {2, 1})
+ feed('vee')
+ meths.input_mouse('right', 'press', '', 0, 6, 1)
+ meths.input_mouse('right', 'release', '', 0, 6, 1)
+ feed('<Down><CR>')
+ eq(2, funcs.winnr())
+ eq('', funcs.getreg('"'))
+ end)
end)
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index b30aa67fd3..71adeb42a4 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -3,7 +3,9 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local feed, command, insert = helpers.feed, helpers.command, helpers.insert
local eq = helpers.eq
+local funcs = helpers.funcs
local meths = helpers.meths
+local curwin = helpers.curwin
local poke_eventloop = helpers.poke_eventloop
@@ -871,6 +873,15 @@ describe('ext_multigrid', function()
before_each(function()
screen:try_resize_grid(2, 60, 20)
end)
+
+ it('winwidth() winheight() getwininfo() return inner width and height #19743', function()
+ eq(60, funcs.winwidth(0))
+ eq(20, funcs.winheight(0))
+ local win_info = funcs.getwininfo(curwin().id)[1]
+ eq(60, win_info.width)
+ eq(20, win_info.height)
+ end)
+
it('gets written till grid width', function()
insert(('a'):rep(60).."\n")
@@ -2370,8 +2381,7 @@ describe('ext_multigrid', function()
end)
it('with winbar', function()
- command 'split'
- command 'setlocal winbar=very\\ bar'
+ command('split')
screen:expect{grid=[[
## grid 1
[4:-----------------------------------------------------]|
@@ -2397,16 +2407,100 @@ describe('ext_multigrid', function()
## grid 3
|
## grid 4
- {7:very bar }|
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
+ {1:~ }|
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+
+ -- XXX: hack to get notifications. Could use next_msg() also.
+ local orig_handle_win_pos = screen._handle_win_pos
+ local win_pos = {}
+ function screen._handle_win_pos(self, grid, win, startrow, startcol, width, height)
+ table.insert(win_pos, {grid, win, startrow, startcol, width, height})
+ orig_handle_win_pos(self, grid, win, startrow, startcol, width, height)
+ end
+
+ command('setlocal winbar=very%=bar')
+ screen:expect{grid=[[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:very bar}|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ eq({}, win_pos)
+
+ command('setlocal winbar=')
+ screen:expect{grid=[[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
]], win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
[4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
}}
+ eq({}, win_pos)
end)
it('with winbar dragging statusline with mouse works correctly', function()
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 8d7c404637..9d20229ce1 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -19,10 +19,12 @@ describe('UI receives option updates', function()
linespace=0,
pumblend=0,
mousefocus=false,
+ mousemoveevent=false,
showtabline=1,
termguicolors=false,
ttimeout=true,
ttimeoutlen=50,
+ verbose=0,
ext_cmdline=false,
ext_popupmenu=false,
ext_tabline=false,
@@ -131,6 +133,12 @@ describe('UI receives option updates', function()
eq(expected, screen.options)
end)
+ command("set mousemoveevent")
+ expected.mousemoveevent = true
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+
command("set nottimeout")
expected.ttimeout = false
screen:expect(function()
@@ -187,7 +195,7 @@ end)
describe('UI can set terminal option', function()
local screen
before_each(function()
- -- by default we implicity "--cmd 'set bg=light'" which ruins everything
+ -- by default we implicitly "--cmd 'set bg=light'" which ruins everything
clear{args_rm={'--cmd'}}
screen = Screen.new(20,5)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 9bb067ed8e..223844405e 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -6,13 +6,14 @@ local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdi
local eq = helpers.eq
local feed = helpers.feed
local feed_command = helpers.feed_command
-local iswin = helpers.iswin
local clear = helpers.clear
local command = helpers.command
local testprg = helpers.testprg
local nvim_dir = helpers.nvim_dir
local has_powershell = helpers.has_powershell
local set_shell_powershell = helpers.set_shell_powershell
+local skip = helpers.skip
+local is_os = helpers.is_os
describe("shell command :!", function()
local screen
@@ -36,7 +37,7 @@ describe("shell command :!", function()
end)
it("displays output without LF/EOF. #4646 #4569 #3772", function()
- if helpers.pending_win32(pending) then return end
+ skip(is_os('win'))
-- NOTE: We use a child nvim (within a :term buffer)
-- to avoid triggering a UI flush.
child_session.feed_data(":!printf foo; sleep 200\n")
@@ -52,9 +53,7 @@ describe("shell command :!", function()
end)
it("throttles shell-command output greater than ~10KB", function()
- if 'openbsd' == helpers.uname() then
- pending('FIXME #10804')
- end
+ skip(is_os('openbsd'), 'FIXME #10804')
child_session.feed_data((":!%s REP 30001 foo\n"):format(testprg('shell-test')))
-- If we observe any line starting with a dot, then throttling occurred.
@@ -96,9 +95,7 @@ describe("shell command :!", function()
end)
it('handles control codes', function()
- if iswin() then
- pending('missing printf')
- end
+ skip(is_os('win'), 'missing printf')
local screen = Screen.new(50, 4)
screen:set_default_attr_ids {
[1] = {bold = true, reverse = true};
@@ -173,10 +170,10 @@ describe("shell command :!", function()
end)
it("doesn't truncate Last line of shell output #3269", function()
- command(helpers.iswin()
+ command(is_os('win')
and [[nnoremap <silent>\l :!dir /b bang_filter_spec<cr>]]
or [[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
- local result = (helpers.iswin()
+ local result = (is_os('win')
and [[:!dir /b bang_filter_spec]]
or [[:!ls bang_filter_spec ]])
feed([[\l]])
@@ -215,7 +212,7 @@ describe("shell command :!", function()
it('handles multibyte sequences split over buffer boundaries', function()
command('cd '..nvim_dir)
- local cmd = iswin() and '!shell-test UTF-8 ' or '!./shell-test UTF-8'
+ local cmd = is_os('win') and '!shell-test UTF-8 ' or '!./shell-test UTF-8'
feed_command(cmd)
-- Note: only the first example of split composed char works
screen:expect([[
@@ -265,7 +262,7 @@ describe("shell command :!", function()
|
Press ENTER or type command to continue^ |
]])
- if iswin() then
+ if is_os('win') then
feed_command([[!& 'cmd.exe' /c 'echo $a']])
screen:expect([[
:!& 'cmd.exe' /c 'echo $a' |
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index e11cd1e859..c681453294 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -259,174 +259,339 @@ describe('ui/ext_popupmenu', function()
{2:-- INSERT --} |
]])
- command('imap <f1> <cmd>call nvim_select_popupmenu_item(2,v:true,v:false,{})<cr>')
- command('imap <f2> <cmd>call nvim_select_popupmenu_item(-1,v:false,v:false,{})<cr>')
- command('imap <f3> <cmd>call nvim_select_popupmenu_item(1,v:false,v:true,{})<cr>')
- feed('<C-r>=TestComplete()<CR>')
- screen:expect{grid=[[
+ command('set wildmenu')
+ command('set wildoptions=pum')
+ local expected_wildpum = {
+ { "define", "", "", "" },
+ { "jump", "", "", "" },
+ { "list", "", "", "" },
+ { "place", "", "", "" },
+ { "undefine", "", "", "" },
+ { "unplace", "", "", "" },
+ }
+ feed('<Esc>:sign <Tab>')
+ screen:expect({grid = [[
+ |
|
- foo^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]], popupmenu={
- items=expected,
- pos=0,
- anchor={1,1,0},
- }}
+ :sign define^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = 0,
+ anchor = { 1, 7, 6 },
+ }})
- feed('<f1>')
- screen:expect{grid=[[
+ meths.select_popupmenu_item(-1, true, false, {})
+ screen:expect({grid = [[
+ |
|
- spam^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]], popupmenu={
- items=expected,
- pos=2,
- anchor={1,1,0},
- }}
+ :sign ^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = -1,
+ anchor = { 1, 7, 6 },
+ }})
- feed('<f2>')
- screen:expect{grid=[[
+ meths.select_popupmenu_item(5, true, false, {})
+ screen:expect({grid = [[
+ |
|
- spam^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]], popupmenu={
- items=expected,
- pos=-1,
- anchor={1,1,0},
- }}
+ :sign unplace^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = 5,
+ anchor = { 1, 7, 6 },
+ }})
- feed('<f3>')
- screen:expect([[
+ meths.select_popupmenu_item(-1, true, true, {})
+ screen:expect({grid = [[
+ |
|
- bar^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]])
+ :sign ^ |
+ ]]})
- -- also should work for builtin popupmenu
- screen:set_option('ext_popupmenu', false)
- feed('<C-r>=TestComplete()<CR>')
- screen:expect([[
+ feed('<Tab>')
+ screen:expect({grid = [[
|
- foo^ |
- {6:fo x the foo }{1: }|
- {7:bar }{1: }|
- {7:spam }{1: }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]])
-
- feed('<f1>')
- screen:expect([[
|
- spam^ |
- {7:fo x the foo }{1: }|
- {7:bar }{1: }|
- {6:spam }{1: }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]])
-
- feed('<f2>')
- screen:expect([[
- |
- spam^ |
- {7:fo x the foo }{1: }|
- {7:bar }{1: }|
- {7:spam }{1: }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]])
+ {1:~ }|
+ :sign define^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = 0,
+ anchor = { 1, 7, 6 },
+ }})
- feed('<f3>')
- screen:expect([[
+ meths.select_popupmenu_item(5, true, true, {})
+ screen:expect({grid = [[
+ |
|
- bar^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- {2:-- INSERT --} |
- ]])
+ :sign unplace^ |
+ ]]})
- command('iunmap <f1>')
- command('iunmap <f2>')
- command('iunmap <f3>')
- exec_lua([[
- vim.keymap.set('i', '<f1>', function() vim.api.nvim_select_popupmenu_item(2, true, false, {}) end)
- vim.keymap.set('i', '<f2>', function() vim.api.nvim_select_popupmenu_item(-1, false, false, {}) end)
- vim.keymap.set('i', '<f3>', function() vim.api.nvim_select_popupmenu_item(1, false, true, {}) end)
- ]])
- feed('<C-r>=TestComplete()<CR>')
- screen:expect([[
- |
- foo^ |
- {6:fo x the foo }{1: }|
- {7:bar }{1: }|
- {7:spam }{1: }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]])
+ local function test_pum_select_mappings()
+ screen:set_option('ext_popupmenu', true)
+ feed('<Esc>A<C-r>=TestComplete()<CR>')
+ screen:expect{grid=[[
+ |
+ foo^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=0,
+ anchor={1,1,0},
+ }}
- feed('<f1>')
- screen:expect([[
- |
- spam^ |
- {7:fo x the foo }{1: }|
- {7:bar }{1: }|
- {6:spam }{1: }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]])
+ feed('<f1>')
+ screen:expect{grid=[[
+ |
+ spam^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=2,
+ anchor={1,1,0},
+ }}
- feed('<f2>')
- screen:expect([[
- |
- spam^ |
- {7:fo x the foo }{1: }|
- {7:bar }{1: }|
- {7:spam }{1: }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
- ]])
+ feed('<f2>')
+ screen:expect{grid=[[
+ |
+ spam^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=-1,
+ anchor={1,1,0},
+ }}
- feed('<f3>')
- screen:expect([[
- |
- bar^ |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {1:~ }|
- {2:-- INSERT --} |
+ feed('<f3>')
+ screen:expect([[
+ |
+ bar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<Esc>:sign <Tab>')
+ screen:expect({grid = [[
+ |
+ bar |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign define^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = 0,
+ anchor = { 1, 7, 6 },
+ }})
+
+ feed('<f1>')
+ screen:expect({grid = [[
+ |
+ bar |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign list^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = 2,
+ anchor = { 1, 7, 6 },
+ }})
+
+ feed('<f2>')
+ screen:expect({grid = [[
+ |
+ bar |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign ^ |
+ ]], popupmenu = {
+ items = expected_wildpum,
+ pos = -1,
+ anchor = { 1, 7, 6 },
+ }})
+
+ feed('<f3>')
+ screen:expect({grid = [[
+ |
+ bar |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign jump^ |
+ ]]})
+
+ -- also should work for builtin popupmenu
+ screen:set_option('ext_popupmenu', false)
+ feed('<Esc>A<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ |
+ foo^ |
+ {6:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {7:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f1>')
+ screen:expect([[
+ |
+ spam^ |
+ {7:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {6:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f2>')
+ screen:expect([[
+ |
+ spam^ |
+ {7:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {7:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f3>')
+ screen:expect([[
+ |
+ bar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<Esc>:sign <Tab>')
+ screen:expect([[
+ |
+ bar {6: define } |
+ {1:~ }{7: jump }{1: }|
+ {1:~ }{7: list }{1: }|
+ {1:~ }{7: place }{1: }|
+ {1:~ }{7: undefine }{1: }|
+ {1:~ }{7: unplace }{1: }|
+ :sign define^ |
+ ]])
+
+ feed('<f1>')
+ screen:expect([[
+ |
+ bar {7: define } |
+ {1:~ }{7: jump }{1: }|
+ {1:~ }{6: list }{1: }|
+ {1:~ }{7: place }{1: }|
+ {1:~ }{7: undefine }{1: }|
+ {1:~ }{7: unplace }{1: }|
+ :sign list^ |
+ ]])
+
+ feed('<f2>')
+ screen:expect([[
+ |
+ bar {7: define } |
+ {1:~ }{7: jump }{1: }|
+ {1:~ }{7: list }{1: }|
+ {1:~ }{7: place }{1: }|
+ {1:~ }{7: undefine }{1: }|
+ {1:~ }{7: unplace }{1: }|
+ :sign ^ |
+ ]])
+
+ feed('<f3>')
+ screen:expect([[
+ |
+ bar |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign jump^ |
+ ]])
+ end
+
+ command('map! <f1> <cmd>call nvim_select_popupmenu_item(2,v:true,v:false,{})<cr>')
+ command('map! <f2> <cmd>call nvim_select_popupmenu_item(-1,v:false,v:false,{})<cr>')
+ command('map! <f3> <cmd>call nvim_select_popupmenu_item(1,v:false,v:true,{})<cr>')
+ test_pum_select_mappings()
+
+ command('unmap! <f1>')
+ command('unmap! <f2>')
+ command('unmap! <f3>')
+ exec_lua([[
+ vim.keymap.set('!', '<f1>', function() vim.api.nvim_select_popupmenu_item(2, true, false, {}) end)
+ vim.keymap.set('!', '<f2>', function() vim.api.nvim_select_popupmenu_item(-1, false, false, {}) end)
+ vim.keymap.set('!', '<f3>', function() vim.api.nvim_select_popupmenu_item(1, false, true, {}) end)
]])
+ test_pum_select_mappings()
feed('<esc>ddiaa bb cc<cr>')
feed('<c-x><c-n>')
@@ -780,6 +945,82 @@ describe('ui/ext_popupmenu', function()
}}
end)
+
+ it('does not interfere with mousemodel=popup', function()
+ exec([[
+ set mouse=a mousemodel=popup
+
+ aunmenu PopUp
+ menu PopUp.foo :let g:menustr = 'foo'<CR>
+ menu PopUp.bar :let g:menustr = 'bar'<CR>
+ menu PopUp.baz :let g:menustr = 'baz'<CR>
+ ]])
+ feed('o<C-r>=TestComplete()<CR>')
+ screen:expect{grid=[[
+ |
+ foo^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=0,
+ anchor={1,1,0},
+ }}
+
+ feed('<c-p>')
+ screen:expect{grid=[[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]], popupmenu={
+ items=expected,
+ pos=-1,
+ anchor={1,1,0},
+ }}
+
+ feed('<esc>')
+ screen:expect{grid=[[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ feed('<RightMouse><0,0>')
+ screen:expect([[
+ |
+ {7:^foo } |
+ {7:bar }{1: }|
+ {7:baz }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ feed('<esc>')
+ screen:expect([[
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
end)
@@ -802,6 +1043,8 @@ describe('builtin popupmenu', function()
[4] = {bold = true, reverse = true},
[5] = {bold = true, foreground = Screen.colors.SeaGreen},
[6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [7] = {background = Screen.colors.Yellow}, -- Search
+ [8] = {foreground = Screen.colors.Red},
})
end)
@@ -949,6 +1192,66 @@ describe('builtin popupmenu', function()
]])
end)
+ -- oldtest: Test_pum_with_preview_win()
+ it('preview window opened during completion', function()
+ exec([[
+ funct Omni_test(findstart, base)
+ if a:findstart
+ return col(".") - 1
+ endif
+ return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}]
+ endfunc
+ set omnifunc=Omni_test
+ set completeopt+=longest
+ ]])
+ feed('Gi<C-X><C-O>')
+ screen:expect([[
+ ^ |
+ {n:one }{1: }|
+ {n:two }{1: }|
+ {n:three }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- }{8:Back at original} |
+ ]])
+ feed('<C-N>')
+ screen:expect([[
+ 1info |
+ |
+ {1:~ }|
+ {3:[Scratch] [Preview] }|
+ one^ |
+ {s:one }{1: }|
+ {n:two }{1: }|
+ {n:three }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ end)
+
it('with vsplits', function()
insert('aaa aab aac\n')
feed(':vsplit<cr>')
@@ -1990,6 +2293,22 @@ describe('builtin popupmenu', function()
efine unplace^ |
]])
+ -- Pressing <Left> after that should move the cursor
+ feed('<Left>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4: }|
+ :sign define jump list place und|
+ efine unplac^e |
+ ]])
+ feed('<End>')
+
-- Pressing <C-D> when the popup menu is displayed should remove the popup
-- menu
feed('<C-U>sign <Tab><C-D>')
@@ -2206,8 +2525,130 @@ describe('builtin popupmenu', function()
{1:~ }{n: xyz }{1: }|
:e あいう/123^ |
]])
+ feed('<Esc>')
- feed('<esc>')
+ -- Pressing <PageDown> should scroll the menu downward
+ feed(':sign <Tab><PageDown>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{s: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign undefine^ |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{s: unplace }{1: }|
+ :sign unplace^ |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign ^ |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{s: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign define^ |
+ ]])
+ feed('<C-U>sign <Tab><Right><Right><PageDown>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{s: unplace }{1: }|
+ :sign unplace^ |
+ ]])
+
+ -- Pressing <PageUp> should scroll the menu upward
+ feed('<C-U>sign <Tab><PageUp>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign ^ |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{s: unplace }{1: }|
+ :sign unplace^ |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: define }{1: }|
+ {1:~ }{s: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign jump^ |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{s: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign define^ |
+ ]])
+
+ feed('<Esc>')
-- check positioning with multibyte char in pattern
command("e långfile1")
@@ -2304,7 +2745,7 @@ describe('builtin popupmenu', function()
]])
end)
- it('wildoptions=pum with scrolled messages ', function()
+ it('wildoptions=pum with scrolled messages', function()
screen:try_resize(40,10)
command('set wildmenu')
command('set wildoptions=pum')
@@ -2401,6 +2842,49 @@ describe('builtin popupmenu', function()
]]}
end)
+ it('wildoptions=pum with a wrapped line in buffer vim-patch:8.2.4655', function()
+ screen:try_resize(32, 10)
+ meths.buf_set_lines(0, 0, -1, true, { ('a'):rep(100) })
+ command('set wildoptions+=pum')
+ feed('$')
+ feed(':sign <Tab>')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaa {s: define } |
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign define^ |
+ ]])
+ end)
+
+ -- oldtest: Test_wildmenu_pum_clear_entries()
+ it('wildoptions=pum when using Ctrl-E as wildchar vim-patch:9.0.1030', function()
+ screen:try_resize(30, 10)
+ exec([[
+ set wildoptions=pum
+ set wildchar=<C-E>
+ ]])
+ feed(':sign <C-E><C-E>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{s: define }{1: }|
+ {1:~ }{n: jump }{1: }|
+ {1:~ }{n: list }{1: }|
+ {1:~ }{n: place }{1: }|
+ {1:~ }{n: undefine }{1: }|
+ {1:~ }{n: unplace }{1: }|
+ :sign define^ |
+ ]])
+ assert_alive()
+ end)
+
it("'pumblend' RGB-color", function()
screen:try_resize(60,14)
screen:set_default_attr_ids({
@@ -2739,7 +3223,7 @@ describe('builtin popupmenu', function()
menu PopUp.bar :let g:menustr = 'bar'<CR>
menu PopUp.baz :let g:menustr = 'baz'<CR>
]])
- meths.input_mouse('right', 'press', '', 0, 0, 4)
+ feed('<RightMouse><4,0>')
screen:expect([[
^popup menu test |
{1:~ }{n: foo }{1: }|
@@ -2776,7 +3260,7 @@ describe('builtin popupmenu', function()
:let g:menustr = 'bar' |
]])
eq('bar', meths.get_var('menustr'))
- meths.input_mouse('right', 'press', '', 0, 1, 20)
+ feed('<RightMouse><20,1>')
screen:expect([[
^popup menu test |
{1:~ }|
@@ -2785,7 +3269,7 @@ describe('builtin popupmenu', function()
{1:~ }{n: baz }{1: }|
:let g:menustr = 'bar' |
]])
- meths.input_mouse('left', 'press', '', 0, 4, 22)
+ feed('<LeftMouse><22,4>')
screen:expect([[
^popup menu test |
{1:~ }|
@@ -2795,7 +3279,7 @@ describe('builtin popupmenu', function()
:let g:menustr = 'baz' |
]])
eq('baz', meths.get_var('menustr'))
- meths.input_mouse('right', 'press', '', 0, 0, 4)
+ feed('<RightMouse><4,0>')
screen:expect([[
^popup menu test |
{1:~ }{n: foo }{1: }|
@@ -2804,7 +3288,7 @@ describe('builtin popupmenu', function()
{1:~ }|
:let g:menustr = 'baz' |
]])
- meths.input_mouse('right', 'drag', '', 0, 3, 6)
+ feed('<RightDrag><6,3>')
screen:expect([[
^popup menu test |
{1:~ }{n: foo }{1: }|
@@ -2813,7 +3297,7 @@ describe('builtin popupmenu', function()
{1:~ }|
:let g:menustr = 'baz' |
]])
- meths.input_mouse('right', 'release', '', 0, 1, 6)
+ feed('<RightRelease><6,1>')
screen:expect([[
^popup menu test |
{1:~ }|
@@ -2823,6 +3307,188 @@ describe('builtin popupmenu', function()
:let g:menustr = 'foo' |
]])
eq('foo', meths.get_var('menustr'))
+ eq(false, screen.options.mousemoveevent)
+ feed('<RightMouse><4,0>')
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: baz }{1: }|
+ {1:~ }|
+ :let g:menustr = 'foo' |
+ ]])
+ eq(true, screen.options.mousemoveevent)
+ feed('<MouseMove><6,3>')
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{s: baz }{1: }|
+ {1:~ }|
+ :let g:menustr = 'foo' |
+ ]])
+ eq(true, screen.options.mousemoveevent)
+ feed('<LeftMouse><6,2>')
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :let g:menustr = 'bar' |
+ ]])
+ eq(false, screen.options.mousemoveevent)
+ eq('bar', meths.get_var('menustr'))
+ end)
+
+ -- oldtest: Test_popup_command_dump()
+ it(':popup command', function()
+ exec([[
+ func ChangeMenu()
+ aunmenu PopUp.&Paste
+ nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR>
+ echomsg 'changed'
+ return "\<Ignore>"
+ endfunc
+
+ let lines =<< trim END
+ one two three four five
+ and one two Xthree four five
+ one more two three four five
+ END
+ call setline(1, lines)
+
+ aunmenu *
+ source $VIMRUNTIME/menu.vim
+ ]])
+ feed('/X<CR>:popup PopUp<CR>')
+ screen:expect([[
+ one two three four five |
+ and one two {7:^X}three four five |
+ one more tw{n: Undo } |
+ {1:~ }{n: }{1: }|
+ {1:~ }{n: Paste }{1: }|
+ {1:~ }{n: }{1: }|
+ {1:~ }{n: Select Word }{1: }|
+ {1:~ }{n: Select Sentence }{1: }|
+ {1:~ }{n: Select Paragraph }{1: }|
+ {1:~ }{n: Select Line }{1: }|
+ {1:~ }{n: Select Block }{1: }|
+ {1:~ }{n: Select All }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :popup PopUp |
+ ]])
+
+ -- go to the Paste entry in the menu
+ feed('jj')
+ screen:expect([[
+ one two three four five |
+ and one two {7:^X}three four five |
+ one more tw{n: Undo } |
+ {1:~ }{n: }{1: }|
+ {1:~ }{s: Paste }{1: }|
+ {1:~ }{n: }{1: }|
+ {1:~ }{n: Select Word }{1: }|
+ {1:~ }{n: Select Sentence }{1: }|
+ {1:~ }{n: Select Paragraph }{1: }|
+ {1:~ }{n: Select Line }{1: }|
+ {1:~ }{n: Select Block }{1: }|
+ {1:~ }{n: Select All }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :popup PopUp |
+ ]])
+
+ -- Select a word
+ feed('j')
+ screen:expect([[
+ one two three four five |
+ and one two {7:^X}three four five |
+ one more tw{n: Undo } |
+ {1:~ }{n: }{1: }|
+ {1:~ }{n: Paste }{1: }|
+ {1:~ }{n: }{1: }|
+ {1:~ }{s: Select Word }{1: }|
+ {1:~ }{n: Select Sentence }{1: }|
+ {1:~ }{n: Select Paragraph }{1: }|
+ {1:~ }{n: Select Line }{1: }|
+ {1:~ }{n: Select Block }{1: }|
+ {1:~ }{n: Select All }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :popup PopUp |
+ ]])
+
+ feed('<Esc>')
+
+ -- Set an <expr> mapping to change a menu entry while it's displayed.
+ -- The text should not change but the command does.
+ -- Also verify that "changed" shows up, which means the mapping triggered.
+ command('nnoremap <expr> <F2> ChangeMenu()')
+ feed('/X<CR>:popup PopUp<CR><F2>')
+ screen:expect([[
+ one two three four five |
+ and one two {7:^X}three four five |
+ one more tw{n: Undo } |
+ {1:~ }{n: }{1: }|
+ {1:~ }{n: Paste }{1: }|
+ {1:~ }{n: }{1: }|
+ {1:~ }{n: Select Word }{1: }|
+ {1:~ }{n: Select Sentence }{1: }|
+ {1:~ }{n: Select Paragraph }{1: }|
+ {1:~ }{n: Select Line }{1: }|
+ {1:~ }{n: Select Block }{1: }|
+ {1:~ }{n: Select All }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ changed |
+ ]])
+
+ -- Select the Paste entry, executes the changed menu item.
+ feed('jj<CR>')
+ screen:expect([[
+ one two three four five |
+ and one two {7:^X}three four five |
+ one more two three four five |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ pasted |
+ ]])
end)
end)
@@ -3031,5 +3697,72 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
:let g:menustr = 'foo' |
]]})
eq('foo', meths.get_var('menustr'))
+ eq(false, screen.options.mousemoveevent)
+ meths.input_mouse('right', 'press', '', 2, 0, 4)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'foo' |
+ ## grid 4
+ {n: foo }|
+ {n: bar }|
+ {n: baz }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+ eq(true, screen.options.mousemoveevent)
+ meths.input_mouse('move', '', '', 2, 3, 6)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'foo' |
+ ## grid 4
+ {n: foo }|
+ {n: bar }|
+ {s: baz }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+ eq(true, screen.options.mousemoveevent)
+ meths.input_mouse('left', 'press', '', 2, 2, 6)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'bar' |
+ ]]})
+ eq(false, screen.options.mousemoveevent)
+ eq('bar', meths.get_var('menustr'))
end)
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 6ee9e7b393..3b9cce0e6f 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -101,13 +101,10 @@ 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'})
+function Screen._init_colors(session)
local status, rv = session:request('nvim_get_color_map')
if not status then
- print('failed to get color map')
- os.exit(1)
+ error('failed to get color map')
end
local colors = rv
local colornames = {}
@@ -116,12 +113,15 @@ do
-- this is just a helper to get any canonical name of a color
colornames[rgb] = name
end
- session:close()
Screen.colors = colors
Screen.colornames = colornames
end
function Screen.new(width, height)
+ if not Screen.colors then
+ Screen._init_colors(get_session())
+ end
+
if not width then
width = 53
end
@@ -519,7 +519,7 @@ function Screen:_wait(check, flags)
end
assert(timeout >= minimal_timeout)
- local did_miminal_timeout = false
+ local did_minimal_timeout = false
local function notification_cb(method, args)
assert(method == 'redraw', string.format(
@@ -536,7 +536,7 @@ function Screen:_wait(check, flags)
if not err then
success_seen = true
- if did_miminal_timeout then
+ if did_minimal_timeout then
self._session:stop()
end
elseif success_seen and #args > 0 then
@@ -558,7 +558,7 @@ function Screen:_wait(check, flags)
end
if not success_seen and not eof then
- did_miminal_timeout = true
+ did_minimal_timeout = true
eof = run_session(self._session, flags.request_cb, notification_cb, nil, timeout-minimal_timeout)
end
@@ -769,6 +769,7 @@ end
function Screen:_handle_grid_cursor_goto(grid, row, col)
self._cursor.grid = grid
+ assert(row >= 0 and col >= 0)
self._cursor.row = row + 1
self._cursor.col = col + 1
end
@@ -1549,7 +1550,8 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
attr_state.modified = true
return id
end
- return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
+ local kind = self._options.rgb and 1 or 2
+ return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][kind])
else
if self:_equal_attrs(attrs, {}) then
-- ignore this attrs
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 6c872e52d3..3bd2289a73 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -5,8 +5,8 @@ local feed, command = helpers.feed, helpers.command
local insert = helpers.insert
local eq = helpers.eq
local eval = helpers.eval
-local iswin = helpers.iswin
local funcs, meths, exec_lua = helpers.funcs, helpers.meths, helpers.exec_lua
+local is_os = helpers.is_os
describe('screen', function()
local screen
@@ -128,18 +128,18 @@ local function screen_tests(linegrid)
end)
it('has correct default title with named file', function()
- local expected = (iswin() and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
+ local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
command('set title')
- command(iswin() and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
+ command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
screen:expect(function()
eq(expected, screen.title)
end)
end)
describe('is not changed by', function()
- local file1 = iswin() and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
- local file2 = iswin() and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
- local expected = (iswin() and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
+ local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
+ local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
+ local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
local buf2
before_each(function()
@@ -682,30 +682,7 @@ local function screen_tests(linegrid)
]])
end)
- it('execute command with multi-line output without msgsep', function()
- command("set display-=msgsep")
- feed(':ls<cr>')
- screen:expect([[
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- :ls |
- 1 %a "[No Name]" line 1 |
- {7:Press ENTER or type command to continue}^ |
- ]])
- feed('<cr>') -- skip the "Press ENTER..." state or tests will hang
- end)
-
- it('execute command with multi-line output and with msgsep', function()
- command("set display+=msgsep")
+ it('execute command with multi-line output', function()
feed(':ls<cr>')
screen:expect([[
|
@@ -917,6 +894,31 @@ local function screen_tests(linegrid)
:ls^ |
]])
end)
+
+ it('VimResized autocommand does not cause invalid UI events #20692 #20759', function()
+ feed('<Esc>')
+ command([[autocmd VimResized * redrawtabline]])
+ command([[autocmd VimResized * lua vim.api.nvim_echo({ { 'Hello' } }, false, {})]])
+ command([[autocmd VimResized * let g:echospace = v:echospace]])
+ meths.set_option('showtabline', 2)
+ screen:expect([[
+ {2: + [No Name] }{3: }|
+ resiz^e |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ screen:try_resize(30, 6)
+ screen:expect([[
+ {2: + [No Name] }{3: }|
+ resiz^e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ eq(29, meths.get_var('echospace'))
+ end)
end)
describe('press enter', function()
@@ -1051,38 +1053,35 @@ describe('Screen default colors', function()
end)
end)
-
-describe('screen with msgsep deactivated on startup', function()
- local screen
-
- before_each(function()
- clear('--cmd', 'set display-=msgsep')
- screen = Screen.new()
- screen:attach()
- screen:set_default_attr_ids {
- [0] = {bold=true, foreground=255};
- [7] = {bold = true, foreground = Screen.colors.SeaGreen};
- }
- end)
-
- it('execute command with multi-line output', function()
- feed ':ls<cr>'
- screen:expect([[
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- :ls |
- 1 %a "[No Name]" line 1 |
- {7:Press ENTER or type command to continue}^ |
- ]])
- feed '<cr>' -- skip the "Press ENTER..." state or tests will hang
- end)
+it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function()
+ clear()
+ local screen = Screen.new(100, 100)
+ screen:attach()
+ eq(100, meths.get_option('lines'))
+ eq(99, meths.get_option('window'))
+ eq(99, meths.win_get_height(0))
+ feed('1000o<Esc>')
+ eq(903, funcs.line('w0'))
+ feed('<C-B>')
+ eq(806, funcs.line('w0'))
+ feed('<C-B>')
+ eq(709, funcs.line('w0'))
+ feed('<C-F>')
+ eq(806, funcs.line('w0'))
+ feed('<C-F>')
+ eq(903, funcs.line('w0'))
+ feed('G')
+ screen:try_resize(50, 50)
+ eq(50, meths.get_option('lines'))
+ eq(49, meths.get_option('window'))
+ eq(49, meths.win_get_height(0))
+ eq(953, funcs.line('w0'))
+ feed('<C-B>')
+ eq(906, funcs.line('w0'))
+ feed('<C-B>')
+ eq(859, funcs.line('w0'))
+ feed('<C-F>')
+ eq(906, funcs.line('w0'))
+ feed('<C-F>')
+ eq(953, funcs.line('w0'))
end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index c5c88323a2..18bbb56a61 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -221,10 +221,10 @@ describe('search highlighting', function()
feed('gg/foo\\nbar<CR>')
screen:expect([[
one |
- {2:^foo} |
+ {2:^foo } |
{2:bar} |
baz |
- {1:foo} |
+ {1:foo } |
{1:bar} |
/foo\nbar |
]])
@@ -232,20 +232,20 @@ describe('search highlighting', function()
feed('gg/efg\\nhij<CR>')
screen:expect([[
--- |
- abcd{2:^efg} |
+ abcd{2:^efg } |
{2:hij}kl |
--- |
- abcd{1:efg} |
+ abcd{1:efg } |
{1:hij}kl |
/efg\nhij |
]])
feed('n')
screen:expect([[
--- |
- abcd{1:efg} |
+ abcd{1:efg } |
{1:hij}kl |
--- |
- abcd{2:^efg} |
+ abcd{2:^efg } |
{2:hij}kl |
/efg\nhij |
]])
@@ -548,9 +548,9 @@ describe('search highlighting', function()
feed('/line\\na<cr>')
screen:expect([[
|
- a repeated {2:^line} |
- {2:a} repeated {2:line} |
- {2:a} repeated {2:line} |
+ a repeated {2:^line } |
+ {2:a} repeated {2:line } |
+ {2:a} repeated {2:line } |
{2:a} repeated line |
{1:~ }|
{4:search hit BOTTOM, continuing at TOP} |
@@ -560,9 +560,9 @@ describe('search highlighting', function()
feed('4Grb')
screen:expect([[
|
- a repeated {2:line} |
+ a repeated {2:line } |
{2:a} repeated line |
- ^b repeated {2:line} |
+ ^b repeated {2:line } |
{2:a} repeated line |
{1:~ }|
{4:search hit BOTTOM, continuing at TOP} |
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index dbc92ca222..7dcd4cff25 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -2,6 +2,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
+local meths = helpers.meths
describe('Signs', function()
local screen
@@ -155,9 +156,12 @@ describe('Signs', function()
{0:~ }|
|
]])
+ -- Check that 'statuscolumn' correctly applies numhl
+ command('set statuscolumn=%s%=%l\\ ')
+ screen:expect_unchanged()
end)
- it('higlights the cursorline sign with culhl', function()
+ it('highlights the cursorline sign with culhl', function()
feed('ia<cr>b<cr>c<esc>')
command('sign define piet text=>> texthl=Search culhl=ErrorMsg')
command('sign place 1 line=1 name=piet buffer=1')
@@ -232,11 +236,13 @@ describe('Signs', function()
|
]])
command('set cursorlineopt=number')
+ command('hi! link SignColumn IncSearch')
+ feed('Go<esc>2G')
screen:expect([[
{1:>>}a |
{8:>>}^b |
{1:>>}c |
- {0:~ }|
+ {5: } |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -248,6 +254,9 @@ describe('Signs', function()
{0:~ }|
|
]])
+ -- Check that 'statuscolumn' cursorline/signcolumn highlights are the same (#21726)
+ command('set statuscolumn=%s')
+ screen:expect_unchanged()
end)
it('multiple signs #9295', function()
@@ -592,4 +601,88 @@ describe('Signs', function()
]])
end)
end)
+
+ it('signcolumn width is updated when removing all signs after deleting lines', function()
+ meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'})
+ command('sign define piet text=>>')
+ command('sign place 10001 line=1 name=piet')
+ command('sign place 10002 line=5 name=piet')
+ command('2delete')
+ command('sign unplace 10001')
+ screen:expect([[
+ {2: }a |
+ {2: }^c |
+ {2: }d |
+ >>e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ command('sign unplace 10002')
+ screen:expect([[
+ a |
+ ^c |
+ d |
+ e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('signcolumn width is updated when removing all signs after inserting lines', function()
+ meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'})
+ command('sign define piet text=>>')
+ command('sign place 10001 line=1 name=piet')
+ command('sign place 10002 line=5 name=piet')
+ command('copy .')
+ command('sign unplace 10001')
+ screen:expect([[
+ {2: }a |
+ {2: }^a |
+ {2: }b |
+ {2: }c |
+ {2: }d |
+ >>e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ command('sign unplace 10002')
+ screen:expect([[
+ a |
+ ^a |
+ b |
+ c |
+ d |
+ e |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index de77100cc0..361f83d1ce 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -5,8 +5,8 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local feed = helpers.feed
local insert = helpers.insert
-local uname = helpers.uname
local command = helpers.command
+local is_os = helpers.is_os
describe("'spell'", function()
local screen
@@ -19,11 +19,15 @@ describe("'spell'", function()
[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {special = Screen.colors.Red, undercurl = true},
[2] = {special = Screen.colors.Blue1, undercurl = true},
+ [3] = {foreground = tonumber('0x6a0dad')},
+ [4] = {foreground = Screen.colors.Magenta},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [6] = {foreground = Screen.colors.Red},
})
end)
it('joins long lines #7937', function()
- if uname() == 'openbsd' then pending('FIXME #12104', function() end) return end
+ if is_os('openbsd') then pending('FIXME #12104', function() end) return end
command('set spell')
insert([[
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
@@ -47,6 +51,7 @@ describe("'spell'", function()
end)
+ -- oldtest: Test_spell_screendump()
it('has correct highlight at start of line', function()
insert([[
"This is some text without any spell errors. Everything",
@@ -66,6 +71,96 @@ describe("'spell'", function()
"with missing caps here.", |
^ |
|
- ]])
+ ]])
+ end)
+
+ it('"noplainbuffer" and syntax #20385', function()
+ command('set filetype=c')
+ command('syntax on')
+ command('set spell')
+ insert([[
+ #include <stdbool.h>
+ bool func(void);]])
+ screen:expect([[
+ {3:#include }{4:<stdbool.h>} |
+ {5:bool} func({5:void})^; |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('[s')
+ screen:expect([[
+ {3:#include }{4:<stdbool.h>} |
+ {5:bool} func({5:void})^; |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:search hit TOP, continuing at BOTTOM} |
+ ]])
+ -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled
+ command('set spelloptions+=noplainbuffer')
+ screen:expect_unchanged()
+ feed(']s')
+ screen:expect([[
+ {3:#include }{4:<stdbool.h>} |
+ {5:bool} func({5:void})^; |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:search hit BOTTOM, continuing at TOP} |
+ ]])
+ -- no spellchecking with "noplainbuffer" and syntax disabled
+ command('syntax off')
+ screen:expect([[
+ #include <stdbool.h> |
+ bool func(void)^; |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:search hit BOTTOM, continuing at TOP} |
+ ]])
+ feed('[s')
+ screen:expect([[
+ #include <stdbool.h> |
+ bool func(void)^; |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:search hit TOP, continuing at BOTTOM} |
+ ]])
+ -- everything is spellchecked without "noplainbuffer" with syntax disabled
+ command('set spelloptions&')
+ screen:expect([[
+ #include <{1:stdbool}.h> |
+ {1:bool} {1:func}(void)^; |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:search hit TOP, continuing at BOTTOM} |
+ ]])
+ feed(']s')
+ screen:expect([[
+ #include <{1:^stdbool}.h> |
+ {1:bool} {1:func}(void); |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:search hit BOTTOM, continuing at TOP} |
+ ]])
end)
end)
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
new file mode 100644
index 0000000000..ae3b95fb0f
--- /dev/null
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -0,0 +1,462 @@
+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 eval = helpers.eval
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+local meths = helpers.meths
+local pcall_err = helpers.pcall_err
+
+describe('statuscolumn', function()
+ local screen
+ before_each(function()
+ clear('--cmd', 'set number nuw=1 | call setline(1, repeat(["aaaaa"], 16)) | norm GM')
+ screen = Screen.new()
+ screen:attach()
+ end)
+
+ it("fails with invalid 'statuscolumn'", function()
+ command([[set stc=%{v:relnum?v:relnum:(v:lnum==5?invalid:v:lnum)}\ ]])
+ screen:expect([[
+ 4 aaaaa |
+ 3 aaaaa |
+ 2 aaaaa |
+ 1 aaaaa |
+ 8 ^aaaaa |
+ 1 aaaaa |
+ 2 aaaaa |
+ 3 aaaaa |
+ 4 aaaaa |
+ 5 aaaaa |
+ 6 aaaaa |
+ 7 aaaaa |
+ 8 aaaaa |
+ |
+ ]])
+ command('norm 5G')
+ eq('Vim(redraw):E121: Undefined variable: invalid', pcall_err(command, 'redraw!'))
+ eq('', eval('&statuscolumn'))
+ end)
+
+ it("widens with irregular 'statuscolumn' width", function()
+ command([[set stc=%{v:relnum?v:relnum:(v:lnum==5?'bbbbb':v:lnum)}]])
+ command('norm 5G | redraw!')
+ screen:expect([[
+ 1 aaaaa |
+ bbbbba^eaaa |
+ 1 aaaaa |
+ 2 aaaaa |
+ 3 aaaaa |
+ 4 aaaaa |
+ 5 aaaaa |
+ 6 aaaaa |
+ 7 aaaaa |
+ 8 aaaaa |
+ 9 aaaaa |
+ 10 aaaaa |
+ 11 aaaaa |
+ |
+ ]])
+ end)
+
+ it("works with 'number' and 'relativenumber'", function()
+ command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
+ screen:expect([[
+ 4 │aaaaa |
+ 5 │aaaaa |
+ 6 │aaaaa |
+ 7 │aaaaa |
+ 8 │^aaaaa |
+ 9 │aaaaa |
+ 10│aaaaa |
+ 11│aaaaa |
+ 12│aaaaa |
+ 13│aaaaa |
+ 14│aaaaa |
+ 15│aaaaa |
+ 16│aaaaa |
+ |
+ ]])
+ command([[set stc=%l%=%{&rnu?'\ ':''}%r│]])
+ screen:expect_unchanged()
+ command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
+ command('set relativenumber')
+ screen:expect([[
+ 4 4│aaaaa |
+ 5 3│aaaaa |
+ 6 2│aaaaa |
+ 7 1│aaaaa |
+ 8 0│^aaaaa |
+ 9 1│aaaaa |
+ 10 2│aaaaa |
+ 11 3│aaaaa |
+ 12 4│aaaaa |
+ 13 5│aaaaa |
+ 14 6│aaaaa |
+ 15 7│aaaaa |
+ 16 8│aaaaa |
+ |
+ ]])
+ command([[set stc=%l%=%{&rnu?'\ ':''}%r│]])
+ screen:expect_unchanged()
+ command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
+ command('norm 12GH')
+ screen:expect([[
+ 4 0│^aaaaa |
+ 5 1│aaaaa |
+ 6 2│aaaaa |
+ 7 3│aaaaa |
+ 8 4│aaaaa |
+ 9 5│aaaaa |
+ 10 6│aaaaa |
+ 11 7│aaaaa |
+ 12 8│aaaaa |
+ 13 9│aaaaa |
+ 14 10│aaaaa |
+ 15 11│aaaaa |
+ 16 12│aaaaa |
+ |
+ ]])
+ command([[set stc=%l%=%{&rnu?'\ ':''}%r│]])
+ screen:expect_unchanged()
+ command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
+ end)
+
+ it("works with highlighted 'statuscolumn'", function()
+ command([[set stc=%#NonText#%{&nu?v:lnum:''}]] ..
+ [[%=%{&rnu&&(v:lnum%2)?'\ '.v:relnum:''}]] ..
+ [[%#LineNr#%{&rnu&&!(v:lnum%2)?'\ '.v:relnum:''}│]])
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue},
+ [1] = {foreground = Screen.colors.Brown},
+ })
+ screen:expect([[
+ {0:4 }{1:│}aaaaa |
+ {0:5 }{1:│}aaaaa |
+ {0:6 }{1:│}aaaaa |
+ {0:7 }{1:│}aaaaa |
+ {0:8 }{1:│}^aaaaa |
+ {0:9 }{1:│}aaaaa |
+ {0:10}{1:│}aaaaa |
+ {0:11}{1:│}aaaaa |
+ {0:12}{1:│}aaaaa |
+ {0:13}{1:│}aaaaa |
+ {0:14}{1:│}aaaaa |
+ {0:15}{1:│}aaaaa |
+ {0:16}{1:│}aaaaa |
+ |
+ ]])
+ command('set relativenumber')
+ screen:expect([[
+ {0:4 }{1: 4│}aaaaa |
+ {0:5 3}{1:│}aaaaa |
+ {0:6 }{1: 2│}aaaaa |
+ {0:7 1}{1:│}aaaaa |
+ {0:8 }{1: 0│}^aaaaa |
+ {0:9 1}{1:│}aaaaa |
+ {0:10}{1: 2│}aaaaa |
+ {0:11 3}{1:│}aaaaa |
+ {0:12}{1: 4│}aaaaa |
+ {0:13 5}{1:│}aaaaa |
+ {0:14}{1: 6│}aaaaa |
+ {0:15 7}{1:│}aaaaa |
+ {0:16}{1: 8│}aaaaa |
+ |
+ ]])
+ command('set nonumber')
+ screen:expect([[
+ {1:4│}aaaaa |
+ {0:3}{1:│}aaaaa |
+ {1:2│}aaaaa |
+ {0:1}{1:│}aaaaa |
+ {1:0│}^aaaaa |
+ {0:1}{1:│}aaaaa |
+ {1:2│}aaaaa |
+ {0:3}{1:│}aaaaa |
+ {1:4│}aaaaa |
+ {0:5}{1:│}aaaaa |
+ {1:6│}aaaaa |
+ {0:7}{1:│}aaaaa |
+ {1:8│}aaaaa |
+ |
+ ]])
+ end)
+
+ it('works with wrapped lines, signs and folds', function()
+ command([[set stc=%C%s%=%{v:virtnum?'':v:lnum}│\ ]])
+ command("call setline(1,repeat([repeat('aaaaa',10)],16))")
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue},
+ [1] = {foreground = Screen.colors.Brown},
+ [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGrey},
+ [3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
+ [4] = {bold = true, foreground = Screen.colors.Brown},
+ [5] = {background = Screen.colors.Grey90},
+ })
+ screen:expect([[
+ {1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1: │ }a |
+ {1: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1: │ }a |
+ {1: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1: │ }a |
+ {1: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1: │ }a |
+ {1: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1: │ }a |
+ {1: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1: │ }a |
+ {1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
+ |
+ ]])
+ command("set stc=%C%s%=%l│\\ ")
+ screen:expect_unchanged()
+ command('set signcolumn=auto:2 foldcolumn=auto')
+ command('sign define piet1 text=>> texthl=LineNr')
+ command('sign define piet2 text=>! texthl=NonText')
+ command('sign place 1 line=4 name=piet1 buffer=1')
+ command('sign place 2 line=5 name=piet2 buffer=1')
+ command('sign place 3 line=6 name=piet1 buffer=1')
+ command('sign place 4 line=6 name=piet2 buffer=1')
+ screen:expect([[
+ {1:>>}{2: }{1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │ }aaaaa |
+ {0:>!}{2: }{1: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │ }aaaaa |
+ {1:>>}{0:>!}{1: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │ }aaaaa |
+ {2: }{1: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │ }aaaaa |
+ {2: }{1: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │ }aaaaa |
+ {2: }{1: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │ }aaaaa |
+ {2: }{1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
+ |
+ ]])
+ command('norm zf$')
+ -- Check that alignment works properly with signs after %=
+ command([[set stc=%C%=%{v:virtnum?'':v:lnum}│%s\ ]])
+ screen:expect([[
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 6│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2:+}{1: 8│}{2: }{1: }{3:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ |
+ ]])
+ command('set cursorline')
+ screen:expect([[
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 6│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2:+}{4: 8│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ |
+ ]])
+ -- v:lnum is the same value on wrapped lines
+ command([[set stc=%C%=%{v:lnum}│%s\ ]])
+ screen:expect([[
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 4│}{2: }{1: }aaaaaa |
+ {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 5│}{2: }{1: }aaaaaa |
+ {2: }{1: 6│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 6│}{2: }{1: }aaaaaa |
+ {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 7│}{2: }{1: }aaaaaa |
+ {2:+}{4: 8│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 9│}{2: }{1: }aaaaaa |
+ {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1:10│}{2: }{1: }aaaaaa |
+ |
+ ]])
+ -- v:relnum is the same value on wrapped lines
+ command([[set stc=%C%=\ %{v:relnum}│%s\ ]])
+ screen:expect([[
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 4│}{2: }{1: }aaaaaa |
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 3│}{2: }{1: }aaaaaa |
+ {2: }{1: 2│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 2│}{2: }{1: }aaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 1│}{2: }{1: }aaaaaa |
+ {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 1│}{2: }{1: }aaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 2│}{2: }{1: }aaaaaa |
+ |
+ ]])
+ command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]])
+ screen:expect([[
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 2│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaa |
+ |
+ ]])
+ -- Up to 9 signs in a line
+ command('set signcolumn=auto:9 foldcolumn=auto')
+ command('sign place 5 line=6 name=piet1 buffer=1')
+ command('sign place 6 line=6 name=piet2 buffer=1')
+ command('sign place 7 line=6 name=piet1 buffer=1')
+ command('sign place 8 line=6 name=piet2 buffer=1')
+ command('sign place 9 line=6 name=piet1 buffer=1')
+ command('sign place 10 line=6 name=piet2 buffer=1')
+ command('sign place 11 line=6 name=piet1 buffer=1')
+ screen:expect([[
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa |
+ {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa |
+ |
+ ]])
+ -- Status column is re-evaluated for virt_lines, buffer line, and wrapped line
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace("ns")
+ vim.api.nvim_buf_set_extmark(0, ns, 5, 0, {
+ virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}} })
+ vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_lines = {{{"virt_line", ""}}} })
+ ]])
+ command('set foldcolumn=0 signcolumn=no')
+ command([[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]])
+ screen:expect([[
+ {1:buffer 0 4}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1:wrapped 1 4}aaaaaaaa |
+ {1:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1:wrapped 1 5}aaaaaaaa |
+ {1:virtual-2 5}virt_line |
+ {1:virtual-2 5}virt_line above |
+ {1:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1:wrapped 1 6}aaaaaaaa |
+ {1:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1:wrapped 1 7}aaaaaaaa |
+ {4:buffer 0 8}{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {1:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1:wrapped 1 9}aaaaaaaa |
+ |
+ ]])
+ end)
+
+ it("works with 'statuscolumn' clicks", function()
+ command('set mousemodel=extend')
+ command([[
+ function! MyClickFunc(minwid, clicks, button, mods)
+ let g:testvar = printf("%d %d %s %d", a:minwid, a:clicks, a:button, getmousepos().line)
+ if a:mods !=# ' '
+ let g:testvar ..= '(' .. a:mods .. ')'
+ endif
+ endfunction
+ set stc=%0@MyClickFunc@%=%l%T
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ eq('0 2 l 4', eval("g:testvar"))
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ eq('0 3 l 4', eval("g:testvar"))
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ eq('0 4 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 0)
+ eq('0 1 r 7', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 0)
+ eq('0 2 r 7', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 0)
+ eq('0 3 r 7', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 0)
+ eq('0 4 r 7', eval("g:testvar"))
+ command('set laststatus=2 winbar=%f')
+ command('let g:testvar=""')
+ -- Check that winbar click doesn't register as statuscolumn click
+ meths.input_mouse('right', 'press', '', 0, 0, 0)
+ eq('', eval("g:testvar"))
+ -- Check that statusline click doesn't register as statuscolumn click
+ meths.input_mouse('right', 'press', '', 0, 12, 0)
+ eq('', eval("g:testvar"))
+ end)
+
+ it('click labels do not leak memory', function()
+ command([[
+ set laststatus=2
+ setlocal statuscolumn=%0@MyClickFunc@abcd%T
+ 4vsplit
+ setlocal statusline=abcd
+ redrawstatus
+ setlocal statusline=
+ only
+ redraw
+ ]])
+ end)
+
+ it('works with foldcolumn', function()
+ -- Fits maximum multibyte foldcolumn #21759
+ command([[set stc=%C%=%l\ fdc=9 fillchars=foldsep:𒀀]])
+ for _ = 0,8 do command('norm zfjzo') end
+ -- 'statuscolumn' is not drawn for `virt_lines_leftcol` lines
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace("ns")
+ vim.api.nvim_buf_set_extmark(0, ns, 6, 0, {
+ virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} })
+ vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {
+ virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} })
+ ]])
+ feed('lh') -- force update wcol/row
+ screen:expect([[
+ 4 aaaaa |
+ 5 aaaaa |
+ 6 aaaaa |
+ 7 aaaaa |
+ virt |
+ --------- 8 ^aaaaa |
+ virt |
+ 𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀 9 aaaaa |
+ 10 aaaaa |
+ 11 aaaaa |
+ 12 aaaaa |
+ 13 aaaaa |
+ 14 aaaaa |
+ |
+ ]])
+ command('set stc=') -- also for the default sign column
+ screen:expect_unchanged()
+ end)
+end)
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index add5144e1b..1c184ff27d 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -164,6 +164,24 @@ describe('statusline clicks', function()
meths.input_mouse('right', 'press', '', 0, 6, 5)
eq('0 1 r', eval("g:testvar"))
end)
+
+ it('no memory leak with zero-width click labels', function()
+ command([[
+ let &stl = '%@Test@%T%@MyClickFunc@%=%T%@Test@'
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 39)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('no memory leak with truncated click labels', function()
+ command([[
+ let &stl = '%@MyClickFunc@foo%X' .. repeat('a', 40) .. '%<t%@Test@bar%X%@Test@baz'
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 6, 2)
+ eq('0 1 l', eval("g:testvar"))
+ end)
end)
describe('global statusline', function()
@@ -178,6 +196,7 @@ describe('global statusline', function()
[2] = {bold = true, reverse = true};
[3] = {bold = true};
[4] = {reverse = true};
+ [5] = {bold = true, foreground = Screen.colors.Fuchsia};
})
command('set laststatus=3')
command('set ruler')
@@ -398,6 +417,106 @@ describe('global statusline', function()
meths.input_mouse('left', 'drag', '', 0, 14, 10)
eq(1, meths.get_option('cmdheight'))
end)
+
+ it('cmdline row is correct after setting cmdheight #20514', function()
+ command('botright split test/functional/fixtures/bigfile.txt')
+ meths.set_option('cmdheight', 1)
+ feed('L')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────|
+ 0000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
+ 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
+ 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
+ ^0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
+ {2:test/functional/fixtures/bigfile.txt 7,1 Top}|
+ |
+ ]])
+ feed('j')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────|
+ 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
+ 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
+ 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
+ ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
+ {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ |
+ ]])
+ meths.set_option('showtabline', 2)
+ screen:expect([[
+ {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────|
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
+ 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
+ 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
+ ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
+ {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ |
+ ]])
+ meths.set_option('cmdheight', 0)
+ screen:expect([[
+ {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────|
+ 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
+ 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
+ 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
+ ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
+ {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ ]])
+ meths.set_option('cmdheight', 1)
+ screen:expect([[
+ {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────|
+ 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
+ 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
+ 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; |
+ 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; |
+ 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; |
+ ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; |
+ {2:test/functional/fixtures/bigfile.txt 8,1 0%}|
+ |
+ ]])
+ end)
end)
it('statusline does not crash if it has Arabic characters #19447', function()
@@ -444,3 +563,29 @@ it('statusline is redrawn with :resize from <Cmd> mapping #19629', function()
|
]])
end)
+
+it('showcmdloc=statusline does not show if statusline is too narrow', function()
+ clear()
+ local screen = Screen.new(40, 8)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, reverse = true}, -- StatusLine
+ [2] = {reverse = true}, -- StatusLineNC
+ })
+ screen:attach()
+ command('set showcmd')
+ command('set showcmdloc=statusline')
+ command('1vsplit')
+ screen:expect([[
+ ^ │ |
+ {0:~}│{0:~ }|
+ {0:~}│{0:~ }|
+ {0:~}│{0:~ }|
+ {0:~}│{0:~ }|
+ {0:~}│{0:~ }|
+ {1:< }{2:[No Name] }|
+ |
+ ]])
+ feed('1234')
+ screen:expect_unchanged()
+end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index f790597140..1391985823 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -4,7 +4,7 @@ local clear, feed, command = helpers.clear, helpers.feed, helpers.command
local eq = helpers.eq
local insert = helpers.insert
local poke_eventloop = helpers.poke_eventloop
-local expect_exit = helpers.expect_exit
+local exec = helpers.exec
describe('Screen', function()
local screen
@@ -947,7 +947,7 @@ describe('Screen', function()
{0:~ }|
|
]]}
- eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ eq({{2, 0, {{'c', 0, 3}, {' ', 0, 50}}}, {3, 0, {{' ', 0, 53}}}}, grid_lines)
end)
it('K_EVENT should not cause extra redraws with concealcursor #13196', function()
@@ -994,31 +994,39 @@ describe('Screen', function()
{0:~ }|
|
]]}
- eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ eq({{2, 0, {{'c', 0, 3}, {' ', 0, 50}}}}, grid_lines)
+ grid_lines = {}
poke_eventloop() -- causes K_EVENT key
screen:expect_unchanged()
- eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ eq({}, grid_lines) -- no redraw was done
end)
- -- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in
- -- test/functional/ui/syntax_conceal_spec.lua.
- describe('concealed line after window scroll', function()
- after_each(function()
- expect_exit(command, ':qall!')
- os.remove('Xcolesearch')
- end)
-
- it('has the correct cursor column', function()
+ describe('concealed line has the correct cursor column', function()
+ -- oldtest: Test_cursor_column_in_concealed_line_after_window_scroll()
+ it('after window scroll', function()
insert([[
- 3split
- let m = matchadd('Conceal', '=')
- setl conceallevel=2 concealcursor=nc
- normal gg
- "==expr==
- ]])
+ 3split
+ let m = matchadd('Conceal', '=')
+ setl conceallevel=2 concealcursor=nc
+ normal gg
+ "==expr==]])
+ feed('gg')
+ command('file Xcolesearch')
+ command('set nomodified')
- command('write Xcolesearch')
- feed(":so %<CR>")
+ command('so')
+ screen:expect{grid=[[
+ ^3split |
+ let m matchadd('Conceal', '') |
+ setl conceallevel2 concealcursornc |
+ {2:Xcolesearch }|
+ 3split |
+ let m = matchadd('Conceal', '=') |
+ setl conceallevel=2 concealcursor=nc |
+ normal gg |
+ {3:Xcolesearch }|
+ |
+ ]]}
-- Jump to something that is beyond the bottom of the window,
-- so there's a scroll down.
@@ -1032,13 +1040,42 @@ describe('Screen', function()
normal gg |
"{5:^expr} |
{2:Xcolesearch }|
+ 3split |
+ let m = matchadd('Conceal', '=') |
+ setl conceallevel=2 concealcursor=nc |
normal gg |
- "=={5:expr}== |
- |
- {0:~ }|
{3:Xcolesearch }|
/expr |
]]}
end)
+
+ -- oldtest: Test_cursor_column_in_concealed_line_after_leftcol_change()
+ it('after leftcol change', function()
+ exec([[
+ 0put = 'ab' .. repeat('-', &columns) .. 'c'
+ call matchadd('Conceal', '-')
+ set nowrap ss=0 cole=3 cocu=n
+ ]])
+
+ -- Go to the end of the line (3 columns beyond the end of the screen).
+ -- Horizontal scroll would center the cursor in the screen line, but conceal
+ -- makes it go to screen column 1.
+ feed('$')
+
+ -- Are the concealed parts of the current line really hidden?
+ -- Is the window's cursor column properly updated for conceal?
+ screen:expect{grid=[[
+ ^c |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end)
end)
end)
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index 809486d4db..2cdec62d01 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -84,3 +84,45 @@ describe('ui/ext_tabline', function()
end}
end)
end)
+
+describe("tabline", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(42, 5)
+ screen:attach()
+ end)
+
+ it('redraws when tabline option is set', function()
+ command('set tabline=asdf')
+ command('set showtabline=2')
+ screen:expect{grid=[[
+ {1:asdf }|
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {bold = true, foreground = Screen.colors.Blue1};
+ }}
+ command('set tabline=jkl')
+ screen:expect{grid=[[
+ {1:jkl }|
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {bold = true, foreground = Screen.colors.Blue};
+ }}
+ end)
+
+ it('click definitions do not leak memory #21765', function()
+ command('set tabline=%@MyClickFunc@MyClickText%T')
+ command('set showtabline=2')
+ command('redrawtabline')
+ end)
+end)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 98398bc7a1..50466c9473 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -1,13 +1,13 @@
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 iswin = helpers.iswin
local funcs = helpers.funcs
local meths = helpers.meths
local eq = helpers.eq
local eval = helpers.eval
local retry = helpers.retry
local testprg = helpers.testprg
+local is_os = helpers.is_os
describe("'wildmenu'", function()
local screen
@@ -159,7 +159,7 @@ describe("'wildmenu'", function()
-- must wait the full timeout. So make it reasonable.
screen.timeout = 1000
- if not iswin() then
+ if not is_os('win') then
command('set shell=sh') -- Need a predictable "$" prompt.
command('let $PS1 = "$"')
end
@@ -169,7 +169,7 @@ describe("'wildmenu'", function()
-- Check for a shell prompt to verify that the terminal loaded.
retry(nil, nil, function()
- if iswin() then
+ if is_os('win') then
eq('Microsoft', eval("matchstr(join(getline(1, '$')), 'Microsoft')"))
else
eq('$', eval([[matchstr(getline(1), '\$')]]))
@@ -184,11 +184,10 @@ describe("'wildmenu'", function()
screen:expect_unchanged()
end)
- it('wildmode=list,full and display+=msgsep interaction #10092', function()
+ it('wildmode=list,full and messages interaction #10092', function()
-- Need more than 5 rows, else tabline is covered and will be redrawn.
screen:try_resize(25, 7)
- command('set display+=msgsep')
command('set wildmenu wildmode=list,full')
command('set showtabline=2')
feed(':set wildm<tab>')
@@ -223,44 +222,6 @@ describe("'wildmenu'", function()
]])
end)
- it('wildmode=list,full and display-=msgsep interaction', function()
- -- Need more than 5 rows, else tabline is covered and will be redrawn.
- screen:try_resize(25, 7)
-
- command('set display-=msgsep')
- command('set wildmenu wildmode=list,full')
- feed(':set wildm<tab>')
- screen:expect([[
- ~ |
- ~ |
- ~ |
- ~ |
- :set wildm |
- wildmenu wildmode |
- :set wildm^ |
- ]])
- feed('<tab>') -- trigger wildmode full
- screen:expect([[
- ~ |
- ~ |
- ~ |
- :set wildm |
- wildmenu wildmode |
- wildmenu wildmode |
- :set wildmenu^ |
- ]])
- feed('<Esc>')
- screen:expect([[
- ^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- |
- ]])
- end)
-
it('wildmode=longest,list', function()
-- Need more than 5 rows, else tabline is covered and will be redrawn.
screen:try_resize(25, 7)
@@ -365,7 +326,6 @@ describe("'wildmenu'", function()
screen:try_resize(25, 7)
command('set laststatus=2')
- command('set display+=msgsep')
feed(':set wildm')
feed('<c-d>')
screen:expect([[
@@ -461,20 +421,20 @@ end)
describe('command line completion', function()
local screen
before_each(function()
+ clear()
screen = Screen.new(40, 5)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow},
[3] = {bold = true, reverse = true},
})
+ screen:attach()
end)
after_each(function()
os.remove('Xtest-functional-viml-compl-dir')
end)
it('lists directories with empty PATH', function()
- clear()
- screen:attach()
local tmp = funcs.tempname()
command('e '.. tmp)
command('cd %:h')
@@ -491,8 +451,6 @@ describe('command line completion', function()
end)
it('completes env var names #9681', function()
- clear()
- screen:attach()
command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"')
command('set wildmenu wildmode=full')
feed(':!echo $XTEST_<tab>')
@@ -521,6 +479,58 @@ describe('command line completion', function()
:!echo $XTEST_1AaあB^ |
]])
end)
+
+ it('does not leak memory with <S-Tab> with wildmenu and only one match #19874', function()
+ meths.set_option('wildmenu', true)
+ meths.set_option('wildmode', 'full')
+ meths.set_option('wildoptions', 'pum')
+
+ feed(':sign unpla<S-Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign unplace^ |
+ ]])
+
+ feed('<Space>buff<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign unplace buffer=^ |
+ ]])
+ end)
+
+ it('does not show matches with <S-Tab> without wildmenu with wildmode=full', function()
+ meths.set_option('wildmenu', false)
+ meths.set_option('wildmode', 'full')
+
+ feed(':sign <S-Tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :sign unplace^ |
+ ]])
+ end)
+
+ it('shows matches with <S-Tab> without wildmenu with wildmode=list', function()
+ meths.set_option('wildmenu', false)
+ meths.set_option('wildmode', 'list')
+
+ feed(':sign <S-Tab>')
+ screen:expect([[
+ {3: }|
+ :sign define |
+ define list undefine |
+ jump place unplace |
+ :sign unplace^ |
+ ]])
+ end)
end)
describe('ui/ext_wildmenu', function()
diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
index 8976c4371f..ece27ec3ff 100644
--- a/test/functional/ui/winbar_spec.lua
+++ b/test/functional/ui/winbar_spec.lua
@@ -7,6 +7,8 @@ local meths = helpers.meths
local eq = helpers.eq
local poke_eventloop = helpers.poke_eventloop
local feed = helpers.feed
+local funcs = helpers.funcs
+local curwin = helpers.curwin
local pcall_err = helpers.pcall_err
describe('winbar', function()
@@ -48,6 +50,11 @@ describe('winbar', function()
{3:~ }|
|
]])
+ -- winbar is excluded from the heights returned by winheight() and getwininfo()
+ eq(11, funcs.winheight(0))
+ local win_info = funcs.getwininfo(curwin().id)[1]
+ eq(11, win_info.height)
+ eq(1, win_info.winbar)
end)
it('works with custom \'fillchars\' value', function()
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index 8ca245f61a..c032ac3030 100644
--- a/test/functional/vimscript/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -5,6 +5,7 @@ local neq, eq, command = helpers.neq, helpers.eq, helpers.command
local clear, curbufmeths = helpers.clear, helpers.curbufmeths
local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval
local insert, pcall_err = helpers.insert, helpers.pcall_err
+local matches = helpers.matches
local meths = helpers.meths
describe('eval-API', function()
@@ -49,7 +50,7 @@ describe('eval-API', function()
it('cannot change texts if textlocked', function()
command("autocmd TextYankPost <buffer> ++once call nvim_buf_set_lines(0, 0, -1, v:false, [])")
- eq('Vim(call):E5555: API call: E565: Not allowed to change text or change window',
+ matches('Vim%(call%):E5555: API call: E565: Not allowed to change text or change window$',
pcall_err(command, "normal! yy"))
end)
diff --git a/test/functional/vimscript/container_functions_spec.lua b/test/functional/vimscript/container_functions_spec.lua
index 04a3248c49..5bef3fce05 100644
--- a/test/functional/vimscript/container_functions_spec.lua
+++ b/test/functional/vimscript/container_functions_spec.lua
@@ -8,7 +8,7 @@ local clear = helpers.clear
before_each(clear)
describe('extend()', function()
- it('suceeds to extend list with itself', function()
+ it('succeeds to extend list with itself', function()
meths.set_var('l', {1, {}})
eq({1, {}, 1, {}}, eval('extend(l, l)'))
eq({1, {}, 1, {}}, meths.get_var('l'))
diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua
index d92a81c55b..5ee84a6d13 100644
--- a/test/functional/vimscript/ctx_functions_spec.lua
+++ b/test/functional/vimscript/ctx_functions_spec.lua
@@ -173,9 +173,9 @@ describe('context functions', function()
call('SaveSFuncs')
call('DeleteSFuncs')
- eq('Vim(call):E117: Unknown function: s:greet',
+ eq('function Greet, line 1: Vim(call):E117: Unknown function: s:greet',
pcall_err(command, [[call Greet('World')]]))
- eq('Vim(call):E117: Unknown function: s:greet_all',
+ eq('function GreetAll, line 1: Vim(call):E117: Unknown function: s:greet_all',
pcall_err(command, [[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('RestoreFuncs')
@@ -287,9 +287,11 @@ describe('context functions', function()
local with_jumps = {
['jumps'] = eval(([[
- filter(map(getjumplist()[0], 'filter(
- { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
- { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
+ filter(map(add(
+ getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
+ 'filter(
+ { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
+ { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
]]):gsub('\n', ''))
}
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index 0c2ca8de78..a8a901042b 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -10,16 +10,22 @@
-- test/functional/vimscript/functions_spec.lua
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local lfs = require('lfs')
local clear = helpers.clear
local eq = helpers.eq
local exc_exec = helpers.exc_exec
+local exec_lua = helpers.exec_lua
+local exec_capture = helpers.exec_capture
local eval = helpers.eval
local command = helpers.command
local write_file = helpers.write_file
local meths = helpers.meths
local sleep = helpers.sleep
+local matches = helpers.matches
+local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
local poke_eventloop = helpers.poke_eventloop
local feed = helpers.feed
@@ -65,13 +71,13 @@ describe("backtick expansion", function()
end)
it("with default 'shell'", function()
- if helpers.iswin() then
+ if helpers.is_os('win') then
command(":silent args `dir /b *2`")
else
command(":silent args `echo ***2`")
end
eq({ "file2", }, eval("argv()"))
- if helpers.iswin() then
+ if helpers.is_os('win') then
command(":silent args `dir /s/b *4`")
eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')"))
else
@@ -144,3 +150,73 @@ describe('List support code', function()
end
end)
end)
+
+describe("uncaught exception", function()
+ before_each(clear)
+ after_each(function()
+ os.remove('throw1.vim')
+ os.remove('throw2.vim')
+ os.remove('throw3.vim')
+ end)
+
+ it('is not forgotten #13490', function()
+ command('autocmd BufWinEnter * throw "i am error"')
+ eq('i am error', exc_exec('try | new | endtry'))
+
+ -- Like Vim, throwing here aborts the processing of the script, but does not stop :runtime!
+ -- from processing the others.
+ -- Only the first thrown exception should be rethrown from the :try below, though.
+ for i = 1, 3 do
+ write_file('throw' .. i .. '.vim', ([[
+ let result ..= '%d'
+ throw 'throw%d'
+ let result ..= 'X'
+ ]]):format(i, i))
+ end
+ command('set runtimepath+=. | let result = ""')
+ eq('throw1', exc_exec('try | runtime! throw*.vim | endtry'))
+ eq('123', eval('result'))
+ end)
+end)
+
+describe('listing functions using :function', function()
+ before_each(clear)
+
+ it('works for lambda functions with <lambda> #20466', function()
+ command('let A = {-> 1}')
+ local num = exec_capture('echo A'):match("function%('<lambda>(%d+)'%)")
+ eq(([[
+ function <lambda>%s(...)
+1 return 1
+ endfunction]]):format(num), exec_capture(('function <lambda>%s'):format(num)))
+ end)
+
+ -- FIXME: If the same function is deleted, the crash still happens. #20790
+ it('does not crash if another function is deleted while listing', function()
+ local screen = Screen.new(80, 24)
+ screen:attach()
+ matches('Vim%(function%):E454: function list was modified', pcall_err(exec_lua, [=[
+ vim.cmd([[
+ func Func1()
+ endfunc
+ func Func2()
+ endfunc
+ func Func3()
+ endfunc
+ ]])
+
+ local ns = vim.api.nvim_create_namespace('test')
+
+ vim.ui_attach(ns, { ext_messages = true }, function(event, _, content)
+ if event == 'msg_show' and content[1][2] == 'function Func1()' then
+ vim.cmd('delfunc Func3')
+ end
+ end)
+
+ vim.cmd('function')
+
+ vim.ui_detach(ns)
+ ]=]))
+ assert_alive()
+ end)
+end)
diff --git a/test/functional/vimscript/executable_spec.lua b/test/functional/vimscript/executable_spec.lua
index b4162b2336..43e4a29e1a 100644
--- a/test/functional/vimscript/executable_spec.lua
+++ b/test/functional/vimscript/executable_spec.lua
@@ -1,15 +1,16 @@
local helpers = require('test.functional.helpers')(after_each)
-local eq, clear, call, iswin, write_file, command =
- helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file,
+local eq, clear, call, write_file, command =
+ helpers.eq, helpers.clear, helpers.call, helpers.write_file,
helpers.command
local exc_exec = helpers.exc_exec
local eval = helpers.eval
+local is_os = helpers.is_os
describe('executable()', function()
before_each(clear)
it('returns 1 for commands in $PATH', function()
- local exe = iswin() and 'ping' or 'ls'
+ local exe = is_os('win') and 'ping' or 'ls'
eq(1, call('executable', exe))
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
eq(1, call('executable', 'null'))
@@ -17,7 +18,7 @@ describe('executable()', function()
eq(1, call('executable', 'false'))
end)
- if iswin() then
+ if is_os('win') then
it('exepath respects shellslash', function()
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
eq([[test\functional\fixtures\bin\null.CMD]], call('fnamemodify', call('exepath', 'null'), ':.'))
@@ -34,11 +35,13 @@ describe('executable()', function()
it('fails for invalid values', function()
for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
- eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
+ eq('Vim(call):E1174: String required for argument 1',
+ exc_exec('call executable('..input..')'))
end
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
- eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
+ eq('Vim(call):E1174: String required for argument 1',
+ exc_exec('call executable('..input..')'))
end
end)
@@ -54,8 +57,8 @@ describe('executable()', function()
-- Some executable in build/bin/, *not* in $PATH nor CWD.
local sibling_exe = 'printargs-test'
-- Windows: siblings are in Nvim's "pseudo-$PATH".
- local expected = iswin() and 1 or 0
- if iswin() then
+ local expected = is_os('win') and 1 or 0
+ if is_os('win') then
eq('arg1=lemon;arg2=sky;arg3=tree;',
call('system', sibling_exe..' lemon sky tree'))
end
@@ -67,7 +70,7 @@ describe('executable()', function()
clear()
write_file('Xtest_not_executable', 'non-executable file')
write_file('Xtest_executable', 'executable file (exec-bit set)')
- if not iswin() then -- N/A for Windows.
+ if not is_os('win') then -- N/A for Windows.
call('system', {'chmod', '-x', 'Xtest_not_executable'})
call('system', {'chmod', '+x', 'Xtest_executable'})
end
@@ -88,14 +91,17 @@ describe('executable()', function()
end)
it('set, qualified as a path', function()
- local expected = iswin() and 0 or 1
+ local expected = is_os('win') and 0 or 1
eq(expected, call('executable', './Xtest_executable'))
end)
end)
end)
describe('executable() (Windows)', function()
- if not iswin() then return end -- N/A for Unix.
+ if not is_os('win') then
+ pending('N/A for non-windows')
+ return
+ end
local exts = {'bat', 'exe', 'com', 'cmd'}
setup(function()
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index a733b098f5..5fe3d787cb 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -8,7 +8,7 @@ local funcs = helpers.funcs
local Screen = require('test.functional.ui.screen')
local command = helpers.command
local feed = helpers.feed
-local iswin = helpers.iswin
+local is_os = helpers.is_os
describe('execute()', function()
before_each(clear)
@@ -265,7 +265,7 @@ describe('execute()', function()
-- This deviates from vim behavior, but is consistent
-- with how nvim currently displays the output.
it('captures shell-command output', function()
- local win_lf = iswin() and '\13' or ''
+ local win_lf = is_os('win') and '\13' or ''
eq('\n:!echo foo\r\n\nfoo'..win_lf..'\n', funcs.execute('!echo foo'))
end)
diff --git a/test/functional/vimscript/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua
index bbca954511..056f67e0ad 100644
--- a/test/functional/vimscript/exepath_spec.lua
+++ b/test/functional/vimscript/exepath_spec.lua
@@ -1,19 +1,20 @@
local helpers = require('test.functional.helpers')(after_each)
-local eq, clear, call, iswin =
- helpers.eq, helpers.clear, helpers.call, helpers.iswin
+local eq, clear, call =
+ helpers.eq, helpers.clear, helpers.call
local command = helpers.command
local exc_exec = helpers.exc_exec
local matches = helpers.matches
+local is_os = helpers.is_os
describe('exepath()', function()
before_each(clear)
it('returns 1 for commands in $PATH', function()
- local exe = iswin() and 'ping' or 'ls'
- local ext_pat = iswin() and '%.EXE$' or '$'
+ local exe = is_os('win') and 'ping' or 'ls'
+ local ext_pat = is_os('win') and '%.EXE$' or '$'
matches(exe .. ext_pat, call('exepath', exe))
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
- ext_pat = iswin() and '%.CMD$' or '$'
+ ext_pat = is_os('win') and '%.CMD$' or '$'
matches('null' .. ext_pat, call('exepath', 'null'))
matches('true' .. ext_pat, call('exepath', 'true'))
matches('false' .. ext_pat, call('exepath', 'false'))
@@ -21,16 +22,16 @@ describe('exepath()', function()
it('fails for invalid values', function()
for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
- eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
+ eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')'))
end
- eq('Vim(call):E1142: Non-empty string required', exc_exec('call exepath("")'))
+ eq('Vim(call):E1175: Non-empty string required for argument 1', exc_exec('call exepath("")'))
command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do
- eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')'))
+ eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')'))
end
end)
- if iswin() then
+ if is_os('win') then
it('append extension if omitted', function()
local filename = 'cmd'
local pathext = '.exe'
diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua
index d54a6db417..c3ecdd853c 100644
--- a/test/functional/vimscript/fnamemodify_spec.lua
+++ b/test/functional/vimscript/fnamemodify_spec.lua
@@ -1,12 +1,12 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
-local iswin = helpers.iswin
local fnamemodify = helpers.funcs.fnamemodify
local getcwd = helpers.funcs.getcwd
local command = helpers.command
local write_file = helpers.write_file
local alter_slashes = helpers.alter_slashes
+local is_os = helpers.is_os
local function eq_slashconvert(expected, got)
eq(alter_slashes(expected), alter_slashes(got))
@@ -27,7 +27,7 @@ describe('fnamemodify()', function()
local root = helpers.pathroot()
eq(root, fnamemodify([[/]], ':p:h'))
eq(root, fnamemodify([[/]], ':p'))
- if iswin() then
+ if is_os('win') then
eq(root, fnamemodify([[\]], ':p:h'))
eq(root, fnamemodify([[\]], ':p'))
command('set shellslash')
@@ -114,7 +114,7 @@ describe('fnamemodify()', function()
it('handles shell escape', function()
local expected
- if iswin() then
+ if is_os('win') then
-- we expand with double-quotes on Windows
expected = [["hello there! quote ' newline]] .. '\n' .. [["]]
else
diff --git a/test/functional/vimscript/functions_spec.lua b/test/functional/vimscript/functions_spec.lua
index 20c1400030..09b3334989 100644
--- a/test/functional/vimscript/functions_spec.lua
+++ b/test/functional/vimscript/functions_spec.lua
@@ -9,12 +9,12 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eval = helpers.eval
-local iswin = helpers.iswin
local matches = helpers.matches
+local is_os = helpers.is_os
before_each(clear)
it('windowsversion()', function()
clear()
- matches(iswin() and '^%d+%.%d+$' or '^$', eval('windowsversion()'))
+ matches(is_os('win') and '^%d+%.%d+$' or '^$', eval('windowsversion()'))
end)
diff --git a/test/functional/vimscript/has_spec.lua b/test/functional/vimscript/has_spec.lua
index 4d9b226434..2e26d603b3 100644
--- a/test/functional/vimscript/has_spec.lua
+++ b/test/functional/vimscript/has_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local clear = helpers.clear
local funcs = helpers.funcs
-local iswin = helpers.iswin
+local is_os = helpers.is_os
describe('has()', function()
before_each(clear)
@@ -51,7 +51,7 @@ describe('has()', function()
end)
it('"unnamedplus"', function()
- if (not iswin()) and funcs.has("clipboard") == 1 then
+ if (not is_os('win')) and funcs.has("clipboard") == 1 then
eq(1, funcs.has("unnamedplus"))
else
eq(0, funcs.has("unnamedplus"))
diff --git a/test/functional/vimscript/hostname_spec.lua b/test/functional/vimscript/hostname_spec.lua
index 6112cf64e3..7d4baa7213 100644
--- a/test/functional/vimscript/hostname_spec.lua
+++ b/test/functional/vimscript/hostname_spec.lua
@@ -3,7 +3,7 @@ local eq = helpers.eq
local ok = helpers.ok
local call = helpers.call
local clear = helpers.clear
-local iswin = helpers.iswin
+local is_os = helpers.is_os
describe('hostname()', function()
before_each(clear)
@@ -13,8 +13,8 @@ describe('hostname()', function()
ok(string.len(actual) > 0)
if call('executable', 'hostname') == 1 then
local expected = string.gsub(call('system', 'hostname'), '[\n\r]', '')
- eq((iswin() and expected:upper() or expected),
- (iswin() and actual:upper() or actual))
+ eq((is_os('win') and expected:upper() or expected),
+ (is_os('win') and actual:upper() or actual))
end
end)
end)
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index 554d15e550..f50b39c2c5 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -8,7 +8,8 @@ local clear = helpers.clear
local source = helpers.source
local command = helpers.command
local exc_exec = helpers.exc_exec
-local nvim_async = helpers.nvim_async
+local pcall_err = helpers.pcall_err
+local async_meths = helpers.async_meths
local NIL = helpers.NIL
local screen
@@ -449,6 +450,78 @@ describe('inputdialog()', function()
end)
describe('confirm()', function()
+ -- oldtest: Test_confirm()
+ it('works', function()
+ meths.set_option('more', false) -- Avoid hit-enter prompt
+ meths.set_option('laststatus', 2)
+ -- screen:expect() calls are needed to avoid feeding input too early
+ screen:expect({any = '%[No Name%]'})
+
+ async_meths.command([[let a = confirm('Press O to proceed')]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('o')
+ screen:expect({any = '%[No Name%]'})
+ eq(1, meths.get_var('a'))
+
+ async_meths.command([[let a = 'Are you sure?'->confirm("&Yes\n&No")]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('y')
+ screen:expect({any = '%[No Name%]'})
+ eq(1, meths.get_var('a'))
+
+ async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('n')
+ screen:expect({any = '%[No Name%]'})
+ eq(2, meths.get_var('a'))
+
+ -- Not possible to match Vim's CTRL-C test here as CTRL-C always sets got_int in Nvim.
+
+ -- confirm() should return 0 when pressing ESC.
+ async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('<Esc>')
+ screen:expect({any = '%[No Name%]'})
+ eq(0, meths.get_var('a'))
+
+ -- Default choice is returned when pressing <CR>.
+ async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('<CR>')
+ screen:expect({any = '%[No Name%]'})
+ eq(1, meths.get_var('a'))
+
+ async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 2)]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('<CR>')
+ screen:expect({any = '%[No Name%]'})
+ eq(2, meths.get_var('a'))
+
+ async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 0)]])
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('<CR>')
+ screen:expect({any = '%[No Name%]'})
+ eq(0, meths.get_var('a'))
+
+ -- Test with the {type} 4th argument
+ for _, type in ipairs({'Error', 'Question', 'Info', 'Warning', 'Generic'}) do
+ async_meths.command(([[let a = confirm('Are you sure?', "&Yes\n&No", 1, '%s')]]):format(type))
+ screen:expect({any = '{CONFIRM:.+: }'})
+ feed('y')
+ screen:expect({any = '%[No Name%]'})
+ eq(1, meths.get_var('a'))
+ end
+
+ eq('Vim(call):E730: using List as a String',
+ pcall_err(command, 'call confirm([])'))
+ eq('Vim(call):E730: using List as a String',
+ pcall_err(command, 'call confirm("Are you sure?", [])'))
+ eq('Vim(call):E745: Using a List as a Number',
+ pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", [])'))
+ eq('Vim(call):E730: using List as a String',
+ pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", 0, [])'))
+ end)
+
it("shows dialog even if :silent #8788", function()
command("autocmd BufNewFile * call confirm('test')")
@@ -483,7 +556,7 @@ describe('confirm()', function()
feed(':call nvim_command("edit x")<cr>')
check_and_clear(':call nvim_command("edit |\n')
- nvim_async('command', 'edit x')
+ async_meths.command('edit x')
check_and_clear(' |\n')
end)
end)
diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua
index 5d1597f53d..70d0934756 100644
--- a/test/functional/vimscript/json_functions_spec.lua
+++ b/test/functional/vimscript/json_functions_spec.lua
@@ -343,7 +343,7 @@ describe('json_decode() function', function()
exc_exec('call json_decode("\\t\\"abc\\\\u0000")'))
end)
- it('fails to parse unknown escape sequnces', function()
+ it('fails to parse unknown escape sequences', function()
eq('Vim(call):E474: Unknown escape sequence: \\a"',
exc_exec('call json_decode("\\t\\"\\\\a\\"")'))
end)
diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua
index aa64006de0..ba1b4d7a76 100644
--- a/test/functional/vimscript/map_functions_spec.lua
+++ b/test/functional/vimscript/map_functions_spec.lua
@@ -3,6 +3,8 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
local expect = helpers.expect
local feed = helpers.feed
local funcs = helpers.funcs
@@ -10,6 +12,8 @@ local meths = helpers.meths
local nvim = helpers.nvim
local source = helpers.source
local command = helpers.command
+local exec_capture = helpers.exec_capture
+local pcall_err = helpers.pcall_err
describe('maparg()', function()
before_each(clear)
@@ -172,14 +176,12 @@ describe('mapset()', function()
it('can restore mapping description from the dict returned by maparg()', function()
meths.set_keymap('n', 'lhs', 'rhs', {desc = 'map description'})
- eq('\nn lhs rhs\n map description',
- helpers.exec_capture("nmap lhs"))
+ eq('\nn lhs rhs\n map description', exec_capture("nmap lhs"))
local mapargs = funcs.maparg('lhs', 'n', false, true)
- meths.del_keymap('n', 'lhs')
- eq('\nNo mapping found', helpers.exec_capture("nmap lhs"))
+ meths.set_keymap('n', 'lhs', 'rhs', {desc = 'MAP DESCRIPTION'})
+ eq('\nn lhs rhs\n MAP DESCRIPTION', exec_capture("nmap lhs"))
funcs.mapset('n', false, mapargs)
- eq('\nn lhs rhs\n map description',
- helpers.exec_capture("nmap lhs"))
+ eq('\nn lhs rhs\n map description', exec_capture("nmap lhs"))
end)
it('can restore "replace_keycodes" from the dict returned by maparg()', function()
@@ -194,4 +196,59 @@ describe('mapset()', function()
feed('foo')
expect('<<lt><')
end)
+
+ it('replaces an abbreviation of the same lhs #20320', function()
+ command('inoreabbr foo bar')
+ eq('\ni foo * bar', exec_capture('iabbr foo'))
+ feed('ifoo ')
+ expect('bar ')
+ local mapargs = funcs.maparg('foo', 'i', true, true)
+ command('inoreabbr foo BAR')
+ eq('\ni foo * BAR', exec_capture('iabbr foo'))
+ feed('foo ')
+ expect('bar BAR ')
+ funcs.mapset('i', true, mapargs)
+ eq('\ni foo * bar', exec_capture('iabbr foo'))
+ feed('foo<Esc>')
+ expect('bar BAR bar')
+ end)
+
+ it('can restore Lua callback from the dict returned by maparg()', function()
+ eq(0, exec_lua([[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]]))
+ feed('asdf')
+ eq(1, exec_lua([[return GlobalCount]]))
+
+ exec_lua([[
+ _G.saved_asdf_map = vim.fn.maparg('asdf', 'n', false, true)
+ vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 10 end })
+ ]])
+ feed('asdf')
+ eq(11, exec_lua([[return GlobalCount]]))
+
+ exec_lua([[vim.fn.mapset('n', false, _G.saved_asdf_map)]])
+ feed('asdf')
+ eq(12, exec_lua([[return GlobalCount]]))
+
+ exec([[
+ let g:saved_asdf_map = maparg('asdf', 'n', v:false, v:true)
+ lua vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 10 end })
+ ]])
+ feed('asdf')
+ eq(22, exec_lua([[return GlobalCount]]))
+
+ command([[call mapset('n', v:false, g:saved_asdf_map)]])
+ feed('asdf')
+ eq(23, exec_lua([[return GlobalCount]]))
+ end)
+
+ it('does not leak memory if lhs is missing', function()
+ eq('Vim:E460: entries missing in mapset() dict argument',
+ pcall_err(exec_lua, [[vim.fn.mapset('n', false, {rhs = 'foo'})]]))
+ eq('Vim:E460: entries missing in mapset() dict argument',
+ pcall_err(exec_lua, [[vim.fn.mapset('n', false, {callback = function() end})]]))
+ end)
end)
diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua
index cab67d77e4..de5a721efe 100644
--- a/test/functional/vimscript/msgpack_functions_spec.lua
+++ b/test/functional/vimscript/msgpack_functions_spec.lua
@@ -5,7 +5,7 @@ local eval, eq = helpers.eval, helpers.eq
local command = helpers.command
local nvim = helpers.nvim
local exc_exec = helpers.exc_exec
-local iswin = helpers.iswin
+local is_os = helpers.is_os
describe('msgpack*() functions', function()
before_each(clear)
@@ -467,7 +467,7 @@ describe('msgpackparse() function', function()
eval(cmd)
eval(cmd) -- do it again (try to force segfault)
local api_info = eval(cmd) -- do it again
- if iswin() then
+ if is_os('win') then
helpers.assert_alive()
pending('msgpackparse() has a bug on windows')
return
diff --git a/test/functional/vimscript/null_spec.lua b/test/functional/vimscript/null_spec.lua
index 2451da983e..1153baac46 100644
--- a/test/functional/vimscript/null_spec.lua
+++ b/test/functional/vimscript/null_spec.lua
@@ -69,7 +69,7 @@ describe('NULL', function()
null_expr_test('can be splice-indexed', 'L[:]', 0, {})
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
- null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function()
+ null_expr_test('does not crash append()', 'append(0, L)', 0, 0, function()
eq({''}, curbufmeths.get_lines(0, -1, false))
end)
null_expr_test('does not crash setline()', 'setline(1, L)', 0, 0, function()
diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua
index 6e95459630..c89a0c4e93 100644
--- a/test/functional/vimscript/server_spec.lua
+++ b/test/functional/vimscript/server_spec.lua
@@ -1,11 +1,14 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_log = helpers.assert_log
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
-local iswin = helpers.iswin
local ok = helpers.ok
local matches = helpers.matches
local pcall_err = helpers.pcall_err
local mkdir = helpers.mkdir
+local is_os = helpers.is_os
+
+local testlog = 'Xtest-server-log'
local function clear_serverlist()
for _, server in pairs(funcs.serverlist()) do
@@ -14,12 +17,16 @@ local function clear_serverlist()
end
describe('server', function()
+ after_each(function()
+ os.remove(testlog)
+ end)
+
it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function()
local dir = 'Xtest_xdg_run'
mkdir(dir)
clear({ env={ XDG_RUNTIME_DIR=dir } })
matches(dir, funcs.stdpath('run'))
- if not iswin() then
+ if not is_os('win') then
matches(dir, funcs.serverstart())
end
end)
@@ -65,7 +72,7 @@ describe('server', function()
eq('', meths.get_vvar('servername'))
-- v:servername and $NVIM take the next available server.
- local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]]
+ local servername = (is_os('win') and [[\\.\pipe\Xtest-functional-server-pipe]]
or './Xtest-functional-server-socket')
funcs.serverstart(servername)
eq(servername, meths.get_vvar('servername'))
@@ -74,13 +81,20 @@ describe('server', function()
end)
it('serverstop() returns false for invalid input', function()
- clear()
+ clear{env={
+ NVIM_LOG_FILE=testlog,
+ NVIM_LISTEN_ADDRESS='.',
+ }}
eq(0, eval("serverstop('')"))
eq(0, eval("serverstop('bogus-socket-name')"))
+ assert_log('Not listening on bogus%-socket%-name', testlog, 10)
end)
it('parses endpoints', function()
- clear()
+ clear{env={
+ NVIM_LOG_FILE=testlog,
+ NVIM_LISTEN_ADDRESS='.',
+ }}
clear_serverlist()
eq({}, funcs.serverlist())
@@ -104,6 +118,7 @@ describe('server', function()
if status then
table.insert(expected, v4)
pcall(funcs.serverstart, v4) -- exists already; ignore
+ assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10)
end
local v6 = '::1:12345'
@@ -111,6 +126,7 @@ describe('server', function()
if status then
table.insert(expected, v6)
pcall(funcs.serverstart, v6) -- exists already; ignore
+ assert_log('Failed to start server: address already in use: ::1', testlog, 10)
end
eq(expected, funcs.serverlist())
clear_serverlist()
@@ -130,7 +146,7 @@ describe('server', function()
local n = eval('len(serverlist())')
-- Add some servers.
- local servs = (iswin()
+ local servs = (is_os('win')
and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] }
or { [[./Xtest-pipe0934]], [[./Xtest-pipe4324]] })
for _, s in ipairs(servs) do
@@ -164,7 +180,7 @@ describe('startup --listen', function()
end)
it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
- local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]]
+ local addr = (is_os('win') and [[\\.\pipe\Xtest-listen-pipe]]
or './Xtest-listen-pipe')
clear({ env={ NVIM_LISTEN_ADDRESS='./Xtest-env-pipe' },
args={ '--listen', addr } })
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index a778e2f435..7ada1c4bea 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -1,3 +1,5 @@
+-- Tests for system() and :! shell.
+
local helpers = require('test.functional.helpers')(after_each)
local assert_alive = helpers.assert_alive
@@ -9,9 +11,9 @@ local command = helpers.command
local insert = helpers.insert
local expect = helpers.expect
local exc_exec = helpers.exc_exec
-local iswin = helpers.iswin
local os_kill = helpers.os_kill
local pcall_err = helpers.pcall_err
+local is_os = helpers.is_os
local Screen = require('test.functional.ui.screen')
@@ -85,7 +87,7 @@ describe('system()', function()
end)
it('does NOT run in shell', function()
- if iswin() then
+ if is_os('win') then
eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'Write-Output', '%PATH%'])"))
else
eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])"))
@@ -94,7 +96,7 @@ describe('system()', function()
end)
it('sets v:shell_error', function()
- if iswin() then
+ if is_os('win') then
eval([[system("cmd.exe /c exit")]])
eq(0, eval('v:shell_error'))
eval([[system("cmd.exe /c exit 1")]])
@@ -123,7 +125,7 @@ describe('system()', function()
screen:attach()
end)
- if iswin() then
+ if is_os('win') then
local function test_more()
eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]]))
end
@@ -184,7 +186,7 @@ describe('system()', function()
-- * on Windows, expected to default to Western European enc
-- * on Linux, expected to default to UTF8
command([[let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ']])
- eq(iswin() and '??\n' or 'ああ\n', eval([[system('Write-Output "ああ"')]]))
+ eq(is_os('win') and '??\n' or 'ああ\n', eval([[system('Write-Output "ああ"')]]))
end)
it('`echo` and waits for its return', function()
@@ -213,7 +215,7 @@ describe('system()', function()
screen:try_resize(72, 14)
feed(':4verbose echo system("echo hi")<cr>')
- if iswin() then
+ if is_os('win') then
screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' '"echo hi"'"]]}
else
screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' 'echo hi'"]]}
@@ -243,7 +245,7 @@ describe('system()', function()
end)
it('`yes` interrupted with CTRL-C', function()
- feed(':call system("' .. (iswin()
+ feed(':call system("' .. (is_os('win')
and 'for /L %I in (1,0,2) do @echo y'
or 'yes') .. '")<cr>')
screen:expect([[
@@ -260,7 +262,7 @@ describe('system()', function()
~ |
~ |
~ |
-]] .. (iswin()
+]] .. (is_os('win')
and [[
:call system("for /L %I in (1,0,2) do @echo y") |]]
or [[
@@ -286,7 +288,7 @@ describe('system()', function()
it('`yes` interrupted with mapped CTRL-C', function()
command('nnoremap <C-C> i')
- feed(':call system("' .. (iswin()
+ feed(':call system("' .. (is_os('win')
and 'for /L %I in (1,0,2) do @echo y'
or 'yes') .. '")<cr>')
screen:expect([[
@@ -303,7 +305,7 @@ describe('system()', function()
~ |
~ |
~ |
-]] .. (iswin()
+]] .. (is_os('win')
and [[
:call system("for /L %I in (1,0,2) do @echo y") |]]
or [[
@@ -330,7 +332,7 @@ describe('system()', function()
describe('passing no input', function()
it('returns the program output', function()
- if iswin() then
+ if is_os('win') then
eq("echoed\n", eval('system("echo echoed")'))
else
eq("echoed", eval('system("echo -n echoed")'))
@@ -438,7 +440,7 @@ describe('systemlist()', function()
before_each(clear)
it('sets v:shell_error', function()
- if iswin() then
+ if is_os('win') then
eval([[systemlist("cmd.exe /c exit")]])
eq(0, eval('v:shell_error'))
eval([[systemlist("cmd.exe /c exit 1")]])
@@ -617,12 +619,12 @@ describe('systemlist()', function()
return
end
helpers.set_shell_powershell()
- eq({iswin() and 'あ\r' or 'あ'}, eval([[systemlist('Write-Output あ')]]))
+ eq({is_os('win') and 'あ\r' or 'あ'}, eval([[systemlist('Write-Output あ')]]))
-- Sanity test w/ default encoding
-- * on Windows, expected to default to Western European enc
-- * on Linux, expected to default to UTF8
command([[let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ']])
- eq({iswin() and '?\r' or 'あ'}, eval([[systemlist('Write-Output あ')]]))
+ eq({is_os('win') and '?\r' or 'あ'}, eval([[systemlist('Write-Output あ')]]))
end)
end)
@@ -639,15 +641,15 @@ describe('shell :!', function()
1
4
2]])
- if iswin() then
+ if is_os('win') then
feed(':4verbose %!sort /R<cr>')
screen:expect{
- any=[[Executing command: .?Start%-Process sort %-ArgumentList "/R" %-RedirectStandardInput .* %-RedirectStandardOutput .* %-NoNewWindow %-Wait]]
+ any=[[Executing command: .?& { Get%-Content .* | & sort /R } 2>&1 | Out%-File %-Encoding UTF8 .*; exit $LastExitCode"]]
}
else
feed(':4verbose %!sort -r<cr>')
screen:expect{
- any=[[Executing command: .?Start%-Process sort %-ArgumentList "%-r" %-RedirectStandardInput .* %-RedirectStandardOutput .* %-NoNewWindow %-Wait]]
+ any=[[Executing command: .?& { Get%-Content .* | & sort %-r } 2>&1 | Out%-File %-Encoding UTF8 .*; exit $LastExitCode"]]
}
end
feed('<CR>')
@@ -660,4 +662,33 @@ describe('shell :!', function()
1]])
end
end)
+
+ it(':{range}! without redirecting to buffer', function()
+ local screen = Screen.new(500, 10)
+ screen:attach()
+ insert([[
+ 3
+ 1
+ 4
+ 2]])
+ feed(':4verbose %w !sort<cr>')
+ if is_os('win') then
+ screen:expect{
+ any=[[Executing command: .?sort %< .*]]
+ }
+ else
+ screen:expect{
+ any=[[Executing command: .?%(sort%) %< .*]]
+
+ }
+ end
+ feed('<CR>')
+ helpers.set_shell_powershell(true)
+ feed(':4verbose %w !sort<cr>')
+ screen:expect{
+ any=[[Executing command: .?& { Get%-Content .* | & sort }]]
+ }
+ feed('<CR>')
+ helpers.expect_exit(command, 'qall!')
+ end)
end)
diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index 5463cfb234..1818a71ea2 100644
--- a/test/functional/vimscript/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
@@ -131,34 +131,34 @@ describe('timers', function()
nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem', {'repeat': -1})")
screen:expect([[
- ITEM 1 |
+ ^ITEM 1 |
ITEM 2 |
{1:~ }|
{1:~ }|
{1:~ }|
- ^ |
+ |
]])
nvim_async("command", "let g:cont = 1")
screen:expect([[
- ITEM 1 |
+ ^ITEM 1 |
ITEM 2 |
ITEM 3 |
{1:~ }|
{1:~ }|
- ^ |
+ |
]])
feed("3")
eq(51, eval("g:c2"))
- screen:expect([[
+ screen:expect{grid=[[
^ITEM 1 |
ITEM 2 |
ITEM 3 |
{1:~ }|
{1:~ }|
|
- ]])
+ ]], unchanged=true}
end)
it('can be stopped', function()
diff --git a/test/functional/vimscript/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua
index 5f693249a9..8c8da9dc88 100644
--- a/test/functional/vimscript/writefile_spec.lua
+++ b/test/functional/vimscript/writefile_spec.lua
@@ -111,6 +111,26 @@ describe('writefile()', function()
pcall_err(command, ('call writefile([42], %s)'):format(ddname_tail)))
end)
+ it('writefile(..., "p") creates missing parent directories', function()
+ os.remove(dname)
+ eq(nil, read_file(dfname))
+ eq(0, funcs.writefile({'abc', 'def', 'ghi'}, dfname, 'p'))
+ eq('abc\ndef\nghi\n', read_file(dfname))
+ os.remove(dfname)
+ os.remove(dname)
+ eq(nil, read_file(dfname))
+ eq(0, funcs.writefile({'\na\nb\n'}, dfname, 'pb'))
+ eq('\0a\0b\0', read_file(dfname))
+ os.remove(dfname)
+ os.remove(dname)
+ eq('Vim(call):E32: No file name',
+ pcall_err(command, ('call writefile([], "%s", "p")'):format(dfname .. '.d/')))
+ eq(('Vim(call):E482: Can\'t open file ./ for writing: illegal operation on a directory'),
+ pcall_err(command, 'call writefile([], "./", "p")'))
+ eq(('Vim(call):E482: Can\'t open file . for writing: illegal operation on a directory'),
+ pcall_err(command, 'call writefile([], ".", "p")'))
+ end)
+
it('errors out with invalid arguments', function()
write_file(fname, 'TEST')
eq('Vim(call):E119: Not enough arguments for function: writefile',