aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
committerJosh Rahm <joshuarahm@gmail.com>2024-11-19 22:57:13 +0000
commit9be89f131f87608f224f0ee06d199fcd09d32176 (patch)
tree11022dcfa9e08cb4ac5581b16734196128688d48 /test/functional
parentff7ed8f586589d620a806c3758fac4a47a8e7e15 (diff)
parent88085c2e80a7e3ac29aabb6b5420377eed99b8b6 (diff)
downloadrneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.gz
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.tar.bz2
rneovim-9be89f131f87608f224f0ee06d199fcd09d32176.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/api/buffer_spec.lua117
-rw-r--r--test/functional/api/buffer_updates_spec.lua6
-rw-r--r--test/functional/api/extmark_spec.lua44
-rw-r--r--test/functional/api/version_spec.lua14
-rw-r--r--test/functional/api/vim_spec.lua515
-rw-r--r--test/functional/api/window_spec.lua281
-rw-r--r--test/functional/autocmd/autocmd_oldtest_spec.lua10
-rw-r--r--test/functional/autocmd/autocmd_spec.lua49
-rw-r--r--test/functional/autocmd/cmdline_spec.lua46
-rw-r--r--test/functional/autocmd/dirchanged_spec.lua2
-rw-r--r--test/functional/autocmd/focus_spec.lua2
-rw-r--r--test/functional/autocmd/show_spec.lua14
-rw-r--r--test/functional/autocmd/termxx_spec.lua4
-rw-r--r--test/functional/core/channels_spec.lua31
-rw-r--r--test/functional/core/fileio_spec.lua26
-rw-r--r--test/functional/core/job_spec.lua15
-rw-r--r--test/functional/core/log_spec.lua57
-rw-r--r--test/functional/core/main_spec.lua22
-rw-r--r--test/functional/core/server_spec.lua (renamed from test/functional/vimscript/server_spec.lua)151
-rw-r--r--test/functional/core/startup_spec.lua73
-rw-r--r--test/functional/editor/completion_spec.lua718
-rw-r--r--test/functional/editor/defaults_spec.lua100
-rw-r--r--test/functional/editor/jump_spec.lua46
-rw-r--r--test/functional/editor/macro_spec.lua17
-rw-r--r--test/functional/editor/meta_key_spec.lua15
-rw-r--r--test/functional/editor/mode_cmdline_spec.lua12
-rw-r--r--test/functional/editor/mode_insert_spec.lua113
-rw-r--r--test/functional/editor/tabpage_spec.lua23
-rw-r--r--test/functional/ex_cmds/append_spec.lua2
-rw-r--r--test/functional/ex_cmds/excmd_spec.lua8
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua2
-rw-r--r--test/functional/ex_cmds/profile_spec.lua9
-rw-r--r--test/functional/ex_cmds/quickfix_commands_spec.lua22
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua42
-rw-r--r--test/functional/legacy/crash_spec.lua31
-rw-r--r--test/functional/legacy/edit_spec.lua6
-rw-r--r--test/functional/legacy/ex_mode_spec.lua18
-rw-r--r--test/functional/legacy/excmd_spec.lua31
-rw-r--r--test/functional/legacy/matchparen_spec.lua79
-rw-r--r--test/functional/legacy/put_spec.lua41
-rw-r--r--test/functional/legacy/scroll_opt_spec.lua120
-rw-r--r--test/functional/legacy/signs_spec.lua63
-rw-r--r--test/functional/lua/api_spec.lua33
-rw-r--r--test/functional/lua/buffer_updates_spec.lua74
-rw-r--r--test/functional/lua/command_line_completion_spec.lua171
-rw-r--r--test/functional/lua/commands_spec.lua14
-rw-r--r--test/functional/lua/deprecated_spec.lua22
-rw-r--r--test/functional/lua/diagnostic_spec.lua3560
-rw-r--r--test/functional/lua/ffi_spec.lua56
-rw-r--r--test/functional/lua/filetype_spec.lua159
-rw-r--r--test/functional/lua/fs_spec.lua64
-rw-r--r--test/functional/lua/glob_spec.lua40
-rw-r--r--test/functional/lua/highlight_spec.lua161
-rw-r--r--test/functional/lua/inspector_spec.lua31
-rw-r--r--test/functional/lua/loader_spec.lua56
-rw-r--r--test/functional/lua/loop_spec.lua74
-rw-r--r--test/functional/lua/luaeval_spec.lua66
-rw-r--r--test/functional/lua/mpack_spec.lua16
-rw-r--r--test/functional/lua/overrides_spec.lua16
-rw-r--r--test/functional/lua/runtime_spec.lua8
-rw-r--r--test/functional/lua/snippet_spec.lua33
-rw-r--r--test/functional/lua/system_spec.lua32
-rw-r--r--test/functional/lua/text_spec.lua6
-rw-r--r--test/functional/lua/thread_spec.lua38
-rw-r--r--test/functional/lua/ui_event_spec.lua53
-rw-r--r--test/functional/lua/ui_spec.lua23
-rw-r--r--test/functional/lua/uri_spec.lua2
-rw-r--r--test/functional/lua/version_spec.lua4
-rw-r--r--test/functional/lua/vim_spec.lua402
-rw-r--r--test/functional/lua/watch_spec.lua97
-rw-r--r--test/functional/lua/with_spec.lua1626
-rw-r--r--test/functional/lua/xdiff_spec.lua112
-rw-r--r--test/functional/options/autochdir_spec.lua2
-rw-r--r--test/functional/options/defaults_spec.lua585
-rw-r--r--test/functional/plugin/editorconfig_spec.lua28
-rw-r--r--test/functional/plugin/health_spec.lua95
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua84
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua547
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua536
-rw-r--r--test/functional/plugin/lsp/handler_spec.lua23
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua91
-rw-r--r--test/functional/plugin/lsp/inlay_hint_spec.lua335
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua378
-rw-r--r--test/functional/plugin/lsp/testutil.lua125
-rw-r--r--test/functional/plugin/lsp/utils_spec.lua104
-rw-r--r--test/functional/plugin/lsp_spec.lua3807
-rw-r--r--test/functional/plugin/man_spec.lua42
-rw-r--r--test/functional/plugin/msgpack_spec.lua65
-rw-r--r--test/functional/plugin/shada_spec.lua77
-rw-r--r--test/functional/plugin/tohtml_spec.lua109
-rw-r--r--test/functional/provider/clipboard_spec.lua37
-rw-r--r--test/functional/script/luacats_grammar_spec.lua125
-rw-r--r--test/functional/script/text_utils_spec.lua4
-rw-r--r--test/functional/shada/errors_spec.lua105
-rw-r--r--test/functional/terminal/altscreen_spec.lua4
-rw-r--r--test/functional/terminal/api_spec.lua2
-rw-r--r--test/functional/terminal/buffer_spec.lua22
-rw-r--r--test/functional/terminal/clipboard_spec.lua65
-rw-r--r--test/functional/terminal/cursor_spec.lua4
-rw-r--r--test/functional/terminal/highlight_spec.lua22
-rw-r--r--test/functional/terminal/mouse_spec.lua12
-rw-r--r--test/functional/terminal/parser_spec.lua15
-rw-r--r--test/functional/terminal/scrollback_spec.lua16
-rw-r--r--test/functional/terminal/tui_spec.lua320
-rw-r--r--test/functional/terminal/window_spec.lua40
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua12
-rw-r--r--test/functional/testnvim.lua240
-rw-r--r--test/functional/testterm.lua (renamed from test/functional/terminal/testutil.lua)144
-rw-r--r--test/functional/treesitter/fold_spec.lua125
-rw-r--r--test/functional/treesitter/highlight_spec.lua429
-rw-r--r--test/functional/treesitter/inspect_tree_spec.lua81
-rw-r--r--test/functional/treesitter/language_spec.lua89
-rw-r--r--test/functional/treesitter/node_spec.lua103
-rw-r--r--test/functional/treesitter/parser_spec.lua487
-rw-r--r--test/functional/treesitter/query_spec.lua524
-rw-r--r--test/functional/treesitter/utils_spec.lua30
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/decorations_spec.lua391
-rw-r--r--test/functional/ui/diff_spec.lua607
-rw-r--r--test/functional/ui/float_spec.lua185
-rw-r--r--test/functional/ui/highlight_spec.lua44
-rw-r--r--test/functional/ui/hlstate_spec.lua2
-rw-r--r--test/functional/ui/messages_spec.lua58
-rw-r--r--test/functional/ui/mouse_spec.lua96
-rw-r--r--test/functional/ui/multibyte_spec.lua122
-rw-r--r--test/functional/ui/multigrid_spec.lua254
-rw-r--r--test/functional/ui/output_spec.lua2
-rw-r--r--test/functional/ui/popupmenu_spec.lua625
-rw-r--r--test/functional/ui/screen.lua67
-rw-r--r--test/functional/ui/screen_basic_spec.lua37
-rw-r--r--test/functional/ui/scrollbind_spec.lua442
-rw-r--r--test/functional/ui/searchhl_spec.lua34
-rw-r--r--test/functional/ui/sign_spec.lua42
-rw-r--r--test/functional/ui/statuscolumn_spec.lua361
-rw-r--r--test/functional/ui/statusline_spec.lua16
-rw-r--r--test/functional/ui/title_spec.lua10
-rw-r--r--test/functional/ui/wildmode_spec.lua94
-rw-r--r--test/functional/vimscript/api_functions_spec.lua2
-rw-r--r--test/functional/vimscript/changedtick_spec.lua4
-rw-r--r--test/functional/vimscript/ctx_functions_spec.lua6
-rw-r--r--test/functional/vimscript/fnamemodify_spec.lua3
-rw-r--r--test/functional/vimscript/input_spec.lua8
-rw-r--r--test/functional/vimscript/json_functions_spec.lua34
-rw-r--r--test/functional/vimscript/map_functions_spec.lua4
-rw-r--r--test/functional/vimscript/msgpack_functions_spec.lua41
-rw-r--r--test/functional/vimscript/printf_spec.lua3
-rw-r--r--test/functional/vimscript/string_spec.lua8
147 files changed, 16011 insertions, 7731 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index cf69958fd8..3775c8c7b7 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -125,11 +125,6 @@ describe('api/buf', function()
it('cursor position is maintained consistently with viewport', function()
local screen = Screen.new(20, 12)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { reverse = true, bold = true },
- [3] = { reverse = true },
- }
screen:attach()
local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' }
@@ -143,11 +138,11 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
line5 |
line6 |
{1:~ }|*2
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -158,11 +153,11 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
boogalo 5 |
line6 |
{1:~ }|*2
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -172,11 +167,11 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
boogalo 5 |
^line6 |
{1:~ }|*2
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
}
@@ -216,11 +211,6 @@ describe('api/buf', function()
local screen
before_each(function()
screen = Screen.new(20, 12)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { reverse = true, bold = true },
- [3] = { reverse = true },
- }
screen:attach()
api.nvim_buf_set_lines(
0,
@@ -243,12 +233,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
www |
xxx |
yyy |
^zzz |
- {2:[No Name] }|
+ {3:[No Name] }|
|
]],
}
@@ -258,12 +248,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
www |
xxx |
yyy |
^zzz |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
}
@@ -274,12 +264,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
wwweeee |
xxx |
yyy |
^zzz |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
}
@@ -290,12 +280,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
wwweeee |
xxx |
yyy |
^zzz |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
unchanged = true,
@@ -306,12 +296,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
wwweeee |
xxx |
^yyy |
zzz |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
}
@@ -321,12 +311,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
mmmeeeee |
wwweeee |
xxx |
^yyy |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
}
@@ -343,12 +333,12 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] }|
+ {2:[No Name] }|
|
]],
}
@@ -358,12 +348,12 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -374,12 +364,12 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
wwweeee |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -389,12 +379,12 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
wwweeee |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
unchanged = true,
@@ -416,12 +406,12 @@ describe('api/buf', function()
ccc |
ddd |
www |
- {2:[No Name] }|
+ {3:[No Name] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] }|
+ {2:[No Name] }|
|
]],
}
@@ -434,12 +424,12 @@ describe('api/buf', function()
ddd |
www |
xxx |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -453,12 +443,12 @@ describe('api/buf', function()
ddd |
wwweeee |
xxx |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
wwweeee |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -471,12 +461,12 @@ describe('api/buf', function()
ddd |
mmm |
wwweeee |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
wwweeee |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -745,10 +735,6 @@ describe('api/buf', function()
it("set_lines of invisible buffer doesn't move cursor in current window", function()
local screen = Screen.new(20, 5)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true },
- })
screen:attach()
insert([[
@@ -771,7 +757,7 @@ describe('api/buf', function()
A real window |
with proper tex^t |
{1:~ }|
- {2:-- INSERT --} |
+ {5:-- INSERT --} |
]])
end)
@@ -1756,11 +1742,6 @@ describe('api/buf', function()
local screen
before_each(function()
screen = Screen.new(20, 12)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { reverse = true, bold = true },
- [3] = { reverse = true },
- }
screen:attach()
api.nvim_buf_set_lines(
0,
@@ -1783,12 +1764,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
www |
xxx |
yyy |
^zzz |
- {2:[No Name] }|
+ {3:[No Name] }|
|
]],
}
@@ -1798,12 +1779,12 @@ describe('api/buf', function()
grid = [[
|
{1:~ }|*4
- {3:[No Name] }|
+ {2:[No Name] }|
www |
xxx |
yyy |
^zzz |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
|
]],
}
@@ -1820,12 +1801,12 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] }|
+ {2:[No Name] }|
|
]],
}
@@ -1835,12 +1816,12 @@ describe('api/buf', function()
grid = [[
^ |
{1:~ }|*4
- {2:[No Name] }|
+ {3:[No Name] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -1861,12 +1842,12 @@ describe('api/buf', function()
ccc |
ddd |
www |
- {2:[No Name] }|
+ {3:[No Name] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] }|
+ {2:[No Name] }|
|
]],
}
@@ -1879,12 +1860,12 @@ describe('api/buf', function()
ddd |
www |
xxx |
- {2:[No Name] [+] }|
+ {3:[No Name] [+] }|
www |
xxx |
yyy |
zzz |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -1910,6 +1891,8 @@ describe('api/buf', function()
eq({ '' }, get_text(0, 0, 18, 0, 20, {}))
eq({ 'ext' }, get_text(0, -2, 1, -2, 4, {}))
eq({ 'hello foo!', 'text', 'm' }, get_text(0, 0, 0, 2, 1, {}))
+ eq({ 'hello foo!' }, get_text(0, 0, -987654321, 0, 987654321, {}))
+ eq({ '' }, get_text(0, 0, -15, 0, -20, {}))
end)
it('errors on out-of-range', function()
@@ -1923,7 +1906,7 @@ describe('api/buf', function()
it('errors when start is greater than end', function()
eq("'start' is higher than 'end'", pcall_err(get_text, 0, 1, 0, 0, 0, {}))
- eq('start_col must be less than end_col', pcall_err(get_text, 0, 0, 1, 0, 0, {}))
+ eq('start_col must be less than or equal to end_col', pcall_err(get_text, 0, 0, 1, 0, 0, {}))
end)
end)
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index e030b45396..527394bfd1 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -27,12 +27,10 @@ end
local function sendkeys(keys)
api.nvim_input(keys)
- -- give nvim some time to process msgpack requests before possibly sending
+ -- Wait for Nvim to fully process pending input before possibly sending
-- more key presses - otherwise they all pile up in the queue and get
-- processed at once
- local ntime = os.clock() + 0.1
- repeat
- until os.clock() > ntime
+ n.poke_eventloop()
end
local function open(activate, lines)
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 7b2fe209ba..52d8fd5097 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -1758,13 +1758,13 @@ describe('API/extmarks', function()
command('1d 2')
eq(0, #get_extmarks(-1, 0, -1, {}))
-- mark is not removed when deleting bytes before the range
- set_extmark(
- ns,
- 3,
- 0,
- 4,
- { invalidate = true, undo_restore = false, hl_group = 'Error', end_col = 7 }
- )
+ set_extmark(ns, 3, 0, 4, {
+ invalidate = true,
+ undo_restore = true,
+ hl_group = 'Error',
+ end_col = 7,
+ right_gravity = false,
+ })
feed('dw')
eq(3, get_extmark_by_id(ns, 3, { details = true })[3].end_col)
-- mark is not removed when deleting bytes at the start of the range
@@ -1778,15 +1778,18 @@ describe('API/extmarks', function()
eq(1, get_extmark_by_id(ns, 3, { details = true })[3].end_col)
-- mark is removed when all bytes in the range are deleted
feed('hx')
- eq({}, get_extmark_by_id(ns, 3, {}))
+ eq(true, get_extmark_by_id(ns, 3, { details = true })[3].invalid)
+ -- mark is restored with undo_restore == true if pos did not change
+ command('undo')
+ eq(nil, get_extmark_by_id(ns, 3, { details = true })[3].invalid)
-- multiline mark is not removed when start of its range is deleted
- set_extmark(
- ns,
- 4,
- 1,
- 4,
- { undo_restore = false, invalidate = true, hl_group = 'Error', end_col = 7, end_row = 3 }
- )
+ set_extmark(ns, 4, 1, 4, {
+ undo_restore = false,
+ invalidate = true,
+ hl_group = 'Error',
+ end_col = 7,
+ end_row = 3,
+ })
feed('ddDdd')
eq({ 0, 0 }, get_extmark_by_id(ns, 4, {}))
-- multiline mark is removed when entirety of its range is deleted
@@ -1795,10 +1798,15 @@ describe('API/extmarks', function()
end)
it('can set a URL', function()
- set_extmark(ns, 1, 0, 0, { url = 'https://example.com', end_col = 3 })
+ local url1 = 'https://example.com'
+ local url2 = 'http://127.0.0.1'
+ set_extmark(ns, 1, 0, 0, { url = url1, end_col = 3 })
+ set_extmark(ns, 2, 0, 3, { url = url2, hl_group = 'Search', end_col = 5 })
local extmarks = get_extmarks(ns, 0, -1, { details = true })
- eq(1, #extmarks)
- eq('https://example.com', extmarks[1][4].url)
+ eq(2, #extmarks)
+ eq(url1, extmarks[1][4].url)
+ eq(url2, extmarks[2][4].url)
+ eq('Search', extmarks[2][4].hl_group)
end)
it('respects priority', function()
diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua
index 5dad9978b7..617786eb2d 100644
--- a/test/functional/api/version_spec.lua
+++ b/test/functional/api/version_spec.lua
@@ -58,10 +58,18 @@ describe('api metadata', function()
return by_name
end
- -- Remove metadata that is not essential to backwards-compatibility.
- local function filter_function_metadata(f)
+ -- Remove or patch metadata that is not essential to backwards-compatibility.
+ local function normalize_func_metadata(f)
+ -- Dictionary was renamed to Dict. That doesn't break back-compat because clients don't actually
+ -- use the `return_type` field (evidence: "ArrayOf(…)" didn't break clients).
+ f.return_type = f.return_type:gsub('Dictionary', 'Dict')
+
f.deprecated_since = nil
for idx, _ in ipairs(f.parameters) do
+ -- Dictionary was renamed to Dict. Doesn't break back-compat because clients don't actually
+ -- use the `parameters` field of API metadata (evidence: "ArrayOf(…)" didn't break clients).
+ f.parameters[idx][1] = f.parameters[idx][1]:gsub('Dictionary', 'Dict')
+
f.parameters[idx][2] = '' -- Remove parameter name.
end
@@ -141,7 +149,7 @@ describe('api metadata', function()
)
end
else
- eq(filter_function_metadata(f), filter_function_metadata(funcs_new[f.name]))
+ eq(normalize_func_metadata(f), normalize_func_metadata(funcs_new[f.name]))
end
end
funcs_compat[level] = name_table(old_api[level].functions)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index fd0535aa51..af4d4854f5 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -367,14 +367,11 @@ describe('API', function()
it('displays messages when opts.output=false', function()
local screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- })
api.nvim_exec2("echo 'hello'", { output = false })
screen:expect {
grid = [[
^ |
- {0:~ }|*6
+ {1:~ }|*6
hello |
]],
}
@@ -383,14 +380,11 @@ describe('API', function()
it("doesn't display messages when output=true", function()
local screen = Screen.new(40, 6)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- })
api.nvim_exec2("echo 'hello'", { output = true })
screen:expect {
grid = [[
^ |
- {0:~ }|*4
+ {1:~ }|*4
|
]],
}
@@ -403,7 +397,7 @@ describe('API', function()
screen:expect {
grid = [[
^ |
- {0:~ }|*4
+ {1:~ }|*4
15 |
]],
}
@@ -699,7 +693,7 @@ describe('API', function()
pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', { 1, 2 })
)
eq(
- 'dict argument type must be String or Dictionary',
+ 'dict argument type must be String or Dict',
pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 })
)
eq(
@@ -1307,12 +1301,136 @@ describe('API', function()
end)
it('crlf=false does not break lines at CR, CRLF', function()
api.nvim_paste('line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1)
- expect('line 1\r\n\r\rline 2\nline 3\rline 4\r')
+ local expected = 'line 1\r\n\r\rline 2\nline 3\rline 4\r'
+ expect(expected)
eq({ 0, 3, 14, 0 }, fn.getpos('.'))
+ feed('u') -- Undo.
+ expect('')
+ feed('.') -- Dot-repeat.
+ expect(expected)
+ end)
+ describe('repeating a paste via redo/recording', function()
+ -- Test with indent and control chars and multibyte chars containing 0x80 bytes
+ local text = dedent(([[
+ foo
+ bar
+ baz
+ !!!%s!!!%s!!!%s!!!
+ 最…倒…倀…
+ ]]):format('\0', '\2\3\6\21\22\23\24\27', '\127'))
+ before_each(function()
+ api.nvim_set_option_value('autoindent', true, {})
+ end)
+ local function test_paste_repeat_normal_insert(is_insert)
+ feed('qr' .. (is_insert and 'i' or ''))
+ eq('r', fn.reg_recording())
+ api.nvim_paste(text, true, -1)
+ feed(is_insert and '<Esc>' or '')
+ expect(text)
+ feed('.')
+ expect(text:rep(2))
+ feed('q')
+ eq('', fn.reg_recording())
+ feed('3.')
+ expect(text:rep(5))
+ feed('2@r')
+ expect(text:rep(9))
+ end
+ it('works in Normal mode', function()
+ test_paste_repeat_normal_insert(false)
+ end)
+ it('works in Insert mode', function()
+ test_paste_repeat_normal_insert(true)
+ end)
+ local function test_paste_repeat_visual_select(is_select)
+ insert(('xxx\n'):rep(5))
+ feed('ggqr' .. (is_select and 'gH' or 'V'))
+ api.nvim_paste(text, true, -1)
+ feed('q')
+ expect(text .. ('xxx\n'):rep(4))
+ feed('2@r')
+ expect(text:rep(3) .. ('xxx\n'):rep(2))
+ end
+ it('works in Visual mode (recording only)', function()
+ test_paste_repeat_visual_select(false)
+ end)
+ it('works in Select mode (recording only)', function()
+ test_paste_repeat_visual_select(true)
+ end)
+ end)
+ it('in a mapping recorded in a macro', function()
+ command([[nnoremap <F2> <Cmd>call nvim_paste('foo', v:false, -1)<CR>]])
+ feed('qr<F2>$q')
+ expect('foo')
+ feed('@r') -- repeating a macro containing the mapping should only paste once
+ expect('foofoo')
+ end)
+ local function test_paste_cancel_error(is_error)
+ before_each(function()
+ exec_lua(([[
+ vim.paste = (function(overridden)
+ return function(lines, phase)
+ for i, line in ipairs(lines) do
+ if line == 'CANCEL' then
+ %s
+ end
+ end
+ return overridden(lines, phase)
+ end
+ end)(vim.paste)
+ ]]):format(is_error and 'error("fake fail")' or 'return false'))
+ end)
+ local function check_paste_cancel_error(data, crlf, phase)
+ if is_error then
+ eq('fake fail', pcall_err(api.nvim_paste, data, crlf, phase))
+ else
+ eq(false, api.nvim_paste(data, crlf, phase))
+ end
+ end
+ it('in phase -1', function()
+ feed('A')
+ check_paste_cancel_error('CANCEL', true, -1)
+ feed('<Esc>')
+ expect('')
+ feed('.')
+ expect('')
+ end)
+ it('in phase 1', function()
+ feed('A')
+ check_paste_cancel_error('CANCEL', true, 1)
+ feed('<Esc>')
+ expect('')
+ feed('.')
+ expect('')
+ end)
+ it('in phase 2', function()
+ feed('A')
+ eq(true, api.nvim_paste('aaa', true, 1))
+ expect('aaa')
+ check_paste_cancel_error('CANCEL', true, 2)
+ feed('<Esc>')
+ expect('aaa')
+ feed('.')
+ expect('aaaaaa')
+ end)
+ it('in phase 3', function()
+ feed('A')
+ eq(true, api.nvim_paste('aaa', true, 1))
+ expect('aaa')
+ eq(true, api.nvim_paste('bbb', true, 2))
+ expect('aaabbb')
+ check_paste_cancel_error('CANCEL', true, 3)
+ feed('<Esc>')
+ expect('aaabbb')
+ feed('.')
+ expect('aaabbbaaabbb')
+ end)
+ end
+ describe('vim.paste() cancel', function()
+ test_paste_cancel_error(false)
end)
- it('vim.paste() failure', function()
- api.nvim_exec_lua('vim.paste = (function(lines, phase) error("fake fail") end)', {})
- eq('fake fail', pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1))
+ describe('vim.paste() error', function()
+ test_paste_cancel_error(true)
end)
end)
@@ -1441,6 +1559,28 @@ describe('API', function()
it('cannot handle NULs', function()
eq(0, api.nvim_strwidth('\0abc'))
end)
+
+ it('can handle emoji with variant selectors and ZWJ', function()
+ local selector = '❤️'
+ eq(2, fn.strchars(selector))
+ eq(1, fn.strcharlen(selector))
+ eq(2, api.nvim_strwidth(selector))
+
+ local no_selector = '❤'
+ eq(1, fn.strchars(no_selector))
+ eq(1, fn.strcharlen(no_selector))
+ eq(1, api.nvim_strwidth(no_selector))
+
+ local selector_zwj_selector = '🏳️‍⚧️'
+ eq(5, fn.strchars(selector_zwj_selector))
+ eq(1, fn.strcharlen(selector_zwj_selector))
+ eq(2, api.nvim_strwidth(selector_zwj_selector))
+
+ local emoji_zwj_emoji = '🧑‍🌾'
+ eq(3, fn.strchars(emoji_zwj_emoji))
+ eq(1, fn.strcharlen(emoji_zwj_emoji))
+ eq(2, api.nvim_strwidth(emoji_zwj_emoji))
+ end)
end)
describe('nvim_get_current_line, nvim_set_current_line', function()
@@ -1503,9 +1643,11 @@ describe('API', function()
it('nvim_get_vvar, nvim_set_vvar', function()
eq('Key is read-only: count', pcall_err(request, 'nvim_set_vvar', 'count', 42))
- eq('Dictionary is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42))
+ eq('Dict is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42))
api.nvim_set_vvar('errmsg', 'set by API')
eq('set by API', api.nvim_get_vvar('errmsg'))
+ api.nvim_set_vvar('completed_item', { word = 'a', user_data = vim.empty_dict() })
+ eq({}, api.nvim_get_vvar('completed_item')['user_data'])
api.nvim_set_vvar('errmsg', 42)
eq('42', eval('v:errmsg'))
api.nvim_set_vvar('oldfiles', { 'one', 'two' })
@@ -1533,16 +1675,12 @@ describe('API', function()
eq({ 1, 5 }, api.nvim_win_get_cursor(0))
local screen = Screen.new(60, 3)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.Yellow },
- })
screen:attach()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
- {1:foo} {1:^foo} {1:foo} |
- {0:~ }|
+ {10:foo} {10:^foo} {10:foo} |
+ {1:~ }|
|
]],
}
@@ -1551,7 +1689,7 @@ describe('API', function()
screen:expect {
grid = [[
foo ^foo foo |
- {0:~ }|
+ {1:~ }|
|
]],
}
@@ -1559,8 +1697,8 @@ describe('API', function()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
- {1:foo} {1:^foo} {1:foo} |
- {0:~ }|
+ {10:foo} {10:^foo} {10:foo} |
+ {1:~ }|
|
]],
}
@@ -1581,9 +1719,9 @@ describe('API', function()
eq(val2, request('vim_del_var', 'lua'))
end)
- it('truncates values with NULs in them', function()
+ it('preserves values with NULs in them', function()
api.nvim_set_var('xxx', 'ab\0cd')
- eq('ab', api.nvim_get_var('xxx'))
+ eq('ab\000cd', api.nvim_get_var('xxx'))
end)
end)
@@ -2144,7 +2282,7 @@ describe('API', function()
end)
describe('nvim_load_context', function()
- it('sets current editor state to given context dictionary', function()
+ it('sets current editor state to given context dict', function()
local opts = { types = { 'regs', 'jumps', 'bufs', 'gvars' } }
eq({}, parse_context(api.nvim_get_context(opts)))
@@ -2160,7 +2298,7 @@ describe('API', function()
eq({ 1, 2, 3 }, eval('[g:one, g:Two, g:THREE]'))
end)
- it('errors when context dictionary is invalid', function()
+ it('errors when context dict is invalid', function()
eq(
'E474: Failed to convert list to msgpack string buffer',
pcall_err(api.nvim_load_context, { regs = { {} }, jumps = { {} } })
@@ -2254,12 +2392,6 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { bold = true, foreground = Screen.colors.SeaGreen },
- [2] = { bold = true, reverse = true },
- [3] = { foreground = Screen.colors.Blue },
- })
end)
it('prints long messages correctly #20534', function()
@@ -2287,11 +2419,11 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~ }|*3
- {2: }|
+ {1:~ }|*3
+ {3: }|
|
a |
- {1:Press ENTER or type command to continue}^ |
+ {6:Press ENTER or type command to continue}^ |
]],
}
feed('<CR>')
@@ -2299,12 +2431,12 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~ }|*2
- {2: }|
+ {1:~ }|*2
+ {3: }|
b |
|
c |
- {1:Press ENTER or type command to continue}^ |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -2314,11 +2446,11 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~ }|*3
- {2: }|
- aaa{3:^@}bbb{3:^@^@}ccc |
- ddd{3:^@^@^@}eee |
- {1:Press ENTER or type command to continue}^ |
+ {1:~ }|*3
+ {3: }|
+ aaa{18:^@}bbb{18:^@^@}ccc |
+ ddd{18:^@^@^@}eee |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -2330,20 +2462,14 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { foreground = Screen.colors.White, background = Screen.colors.Red },
- [2] = { bold = true, foreground = Screen.colors.SeaGreen },
- [3] = { bold = true, reverse = true },
- })
end)
it('can show one line', function()
async_meths.nvim_err_write('has bork\n')
screen:expect([[
^ |
- {0:~ }|*6
- {1:has bork} |
+ {1:~ }|*6
+ {9:has bork} |
]])
end)
@@ -2351,11 +2477,11 @@ describe('API', function()
async_meths.nvim_err_write('something happened\nvery bad\n')
screen:expect([[
|
- {0:~ }|*3
+ {1:~ }|*3
{3: }|
- {1:something happened} |
- {1:very bad} |
- {2:Press ENTER or type command to continue}^ |
+ {9:something happened} |
+ {9:very bad} |
+ {6:Press ENTER or type command to continue}^ |
]])
end)
@@ -2363,13 +2489,13 @@ describe('API', function()
async_meths.nvim_err_write('FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n')
screen:expect([[
|
- {0:~ }|
+ {1:~ }|
{3: }|
- {1:FAILURE} |
- {1:ERROR} |
- {1:EXCEPTION} |
- {1:TRACEBACK} |
- {2:Press ENTER or type command to continue}^ |
+ {9:FAILURE} |
+ {9:ERROR} |
+ {9:EXCEPTION} |
+ {9:TRACEBACK} |
+ {6:Press ENTER or type command to continue}^ |
]])
end)
@@ -2379,8 +2505,8 @@ describe('API', function()
async_meths.nvim_err_write('fail\n')
screen:expect([[
^ |
- {0:~ }|*6
- {1:very fail} |
+ {1:~ }|*6
+ {9:very fail} |
]])
n.poke_eventloop()
@@ -2388,11 +2514,11 @@ describe('API', function()
async_meths.nvim_err_write('more fail\ntoo fail\n')
screen:expect([[
|
- {0:~ }|*3
+ {1:~ }|*3
{3: }|
- {1:more fail} |
- {1:too fail} |
- {2:Press ENTER or type command to continue}^ |
+ {9:more fail} |
+ {9:too fail} |
+ {6:Press ENTER or type command to continue}^ |
]])
feed('<cr>') -- exit the press ENTER screen
end)
@@ -2402,11 +2528,11 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~ }|*3
+ {1:~ }|*3
{3: }|
- {1:aaa^@bbb^@^@ccc} |
- {1:ddd^@^@^@eee} |
- {2:Press ENTER or type command to continue}^ |
+ {9:aaa^@bbb^@^@ccc} |
+ {9:ddd^@^@^@eee} |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -2418,30 +2544,24 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { foreground = Screen.colors.White, background = Screen.colors.Red },
- [2] = { bold = true, foreground = Screen.colors.SeaGreen },
- [3] = { bold = true, reverse = true },
- })
end)
it('shows only one return prompt after all lines are shown', function()
async_meths.nvim_err_writeln('FAILURE\nERROR\nEXCEPTION\nTRACEBACK')
screen:expect([[
|
- {0:~ }|
+ {1:~ }|
{3: }|
- {1:FAILURE} |
- {1:ERROR} |
- {1:EXCEPTION} |
- {1:TRACEBACK} |
- {2:Press ENTER or type command to continue}^ |
+ {9:FAILURE} |
+ {9:ERROR} |
+ {9:EXCEPTION} |
+ {9:TRACEBACK} |
+ {6:Press ENTER or type command to continue}^ |
]])
feed('<CR>')
screen:expect([[
^ |
- {0:~ }|*6
+ {1:~ }|*6
|
]])
end)
@@ -2964,6 +3084,13 @@ describe('API', function()
return ('%s(%s)%s'):format(typ, args, rest)
end
end
+
+ it('does not crash parsing invalid VimL expression #29648', function()
+ api.nvim_input(':<C-r>=')
+ api.nvim_input('1bork/')
+ assert_alive()
+ end)
+
require('test.unit.viml.expressions.parser_tests')(it, _check_parsing, hl, fmtn)
end)
@@ -3102,9 +3229,6 @@ describe('API', function()
eq(1, api.nvim_get_current_buf())
local screen = Screen.new(20, 4)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- })
screen:attach()
--
@@ -3201,7 +3325,7 @@ describe('API', function()
end)
describe('nvim_get_runtime_file', function()
- local p = n.alter_slashes
+ local p = t.fix_slashes
it('can find files', function()
eq({}, api.nvim_get_runtime_file('bork.borkbork', false))
eq({}, api.nvim_get_runtime_file('bork.borkbork', true))
@@ -3210,36 +3334,36 @@ describe('API', function()
local val = api.nvim_get_runtime_file('autoload/remote/*.vim', true)
eq(2, #val)
if endswith(val[1], 'define.vim') then
- ok(endswith(val[1], p 'autoload/remote/define.vim'))
- ok(endswith(val[2], p 'autoload/remote/host.vim'))
+ ok(endswith(p(val[1]), 'autoload/remote/define.vim'))
+ ok(endswith(p(val[2]), 'autoload/remote/host.vim'))
else
- ok(endswith(val[1], p 'autoload/remote/host.vim'))
- ok(endswith(val[2], p 'autoload/remote/define.vim'))
+ ok(endswith(p(val[1]), 'autoload/remote/host.vim'))
+ ok(endswith(p(val[2]), 'autoload/remote/define.vim'))
end
val = api.nvim_get_runtime_file('autoload/remote/*.vim', false)
eq(1, #val)
ok(
- endswith(val[1], p 'autoload/remote/define.vim')
- or endswith(val[1], p 'autoload/remote/host.vim')
+ endswith(p(val[1]), 'autoload/remote/define.vim')
+ or endswith(p(val[1]), 'autoload/remote/host.vim')
)
val = api.nvim_get_runtime_file('lua', true)
eq(1, #val)
- ok(endswith(val[1], p 'lua'))
+ ok(endswith(p(val[1]), 'lua'))
val = api.nvim_get_runtime_file('lua/vim', true)
eq(1, #val)
- ok(endswith(val[1], p 'lua/vim'))
+ ok(endswith(p(val[1]), 'lua/vim'))
end)
it('can find directories', function()
local val = api.nvim_get_runtime_file('lua/', true)
eq(1, #val)
- ok(endswith(val[1], p 'lua/'))
+ ok(endswith(p(val[1]), 'lua/'))
val = api.nvim_get_runtime_file('lua/vim/', true)
eq(1, #val)
- ok(endswith(val[1], p 'lua/vim/'))
+ ok(endswith(p(val[1]), 'lua/vim/'))
eq({}, api.nvim_get_runtime_file('foobarlang/', true))
end)
@@ -3253,6 +3377,16 @@ describe('API', function()
exc_exec("echo nvim_get_runtime_file('{', v:false)")
)
end)
+ it('preserves order of runtimepath', function()
+ local vimruntime = fn.getenv('VIMRUNTIME')
+ local rtp = string.format('%s/syntax,%s/ftplugin', vimruntime, vimruntime)
+ api.nvim_set_option_value('runtimepath', rtp, {})
+
+ local val = api.nvim_get_runtime_file('vim.vim', true)
+ eq(2, #val)
+ eq(p(val[1]), vimruntime .. '/syntax/vim.vim')
+ eq(p(val[2]), vimruntime .. '/ftplugin/vim.vim')
+ end)
end)
describe('nvim_get_all_options_info', function()
@@ -3458,13 +3592,6 @@ describe('API', function()
before_each(function()
screen = Screen.new(40, 8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { bold = true, foreground = Screen.colors.SeaGreen },
- [2] = { bold = true, reverse = true },
- [3] = { foreground = Screen.colors.Brown, bold = true }, -- Statement
- [4] = { foreground = Screen.colors.SlateBlue }, -- Special
- })
command('highlight Statement gui=bold guifg=Brown')
command('highlight Special guifg=SlateBlue')
end)
@@ -3474,7 +3601,7 @@ describe('API', function()
screen:expect {
grid = [[
^ |
- {0:~ }|*6
+ {1:~ }|*6
msg |
]],
}
@@ -3489,8 +3616,8 @@ describe('API', function()
screen:expect {
grid = [[
^ |
- {0:~ }|*6
- msg_a{3:msg_b}{4:msg_c} |
+ {1:~ }|*6
+ msg_a{15:msg_b}{16:msg_c} |
]],
}
end)
@@ -3500,11 +3627,11 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~ }|*3
- {2: }|
- {3:msg_a} |
- {3:msg_a}{4:msg_b} |
- {1:Press ENTER or type command to continue}^ |
+ {1:~ }|*3
+ {3: }|
+ {15:msg_a} |
+ {15:msg_a}{16:msg_b} |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -3528,24 +3655,16 @@ describe('API', function()
before_each(function()
screen = Screen.new(100, 35)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.Plum1 },
- [2] = { background = tonumber('0xffff40'), bg_indexed = true },
- [3] = {
- background = Screen.colors.Plum1,
- fg_indexed = true,
- foreground = tonumber('0x00e000'),
- },
- [4] = { bold = true, reverse = true, background = Screen.colors.Plum1 },
- [5] = {
- foreground = Screen.colors.Blue,
+ screen:add_extra_attr_ids {
+ [100] = { background = tonumber('0xffff40'), bg_indexed = true },
+ [101] = {
background = Screen.colors.LightMagenta,
- bold = true,
+ foreground = tonumber('0x00e000'),
+ fg_indexed = true,
},
- [6] = { bold = true },
- [7] = { reverse = true, background = Screen.colors.LightMagenta },
- })
+ [102] = { background = Screen.colors.LightMagenta, reverse = true },
+ [103] = { background = Screen.colors.LightMagenta, bold = true, reverse = true },
+ }
end)
it('can batch process sequences', function()
@@ -3561,38 +3680,38 @@ describe('API', function()
screen:expect {
grid = [[
^ |
- {0:~}{1::smile }{0: }|
- {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }|
- {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{0: }|
- {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:o$}{1: }{2:$$}{1: }{2:o$}{1: }{0: }|
- {0:~}{1: }{2:o}{1: }{2:$}{1: }{2:oo}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:$$}{1: }{2:$$}{1: }{2:$$o$}{1: }{0: }|
- {0:~}{1: }{2:oo}{1: }{2:$}{1: }{2:$}{1: "}{2:$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$o}{1: }{2:$$$o$$o$}{1: }{0: }|
- {0:~}{1: "}{2:$$$$$$o$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$o}{1: }{2:$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$}{1: """}{2:$$$}{1: }{0: }|
- {0:~}{1: "}{2:$$$}{1:""""}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$o}{1: }{0: }|
- {0:~}{1: }{2:o$$}{1:" }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$o}{1: }{0: }|
- {0:~}{1: }{2:$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" "}{2:$$$$$$ooooo$$$$o}{1: }{0: }|
- {0:~}{1: }{2:o$$$oooo$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:o$$$$$$$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$}{1:"}{2:$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$}{1:"""""""" }{0: }|
- {0:~}{1: """" }{2:$$$$}{1: "}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" }{2:o$$$}{1: }{0: }|
- {0:~}{1: "}{2:$$$o}{1: """}{2:$$$$$$$$$$$$$$$$$$}{1:"}{2:$$}{1:" }{2:$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$o}{1: "}{2:$$}{1:""}{2:$$$$$$}{1:"""" }{2:o$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$o}{1: }{2:o$$$}{1:" }{0: }|
- {0:~}{1: "}{2:$$$$o}{1: }{2:o$$$$$$o}{1:"}{2:$$$$o}{1: }{2:o$$$$}{1: }{0: }|
- {0:~}{1: "}{2:$$$$$oo}{1: ""}{2:$$$$o$$$$$o}{1: }{2:o$$$$}{1:"" }{0: }|
- {0:~}{1: ""}{2:$$$$$oooo}{1: "}{2:$$$o$$$$$$$$$}{1:""" }{0: }|
- {0:~}{1: ""}{2:$$$$$$$oo}{1: }{2:$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: """"}{2:$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$$$}{1:" }{0: }|
- {0:~}{1: "}{2:$$$}{1:"""" }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{3:Press ENTER or type command to continue}{1: }{0: }|
- {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }|
- {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }|
- {0:~ }|*2
+ {1:~}{4::smile }{1: }|
+ {1:~}{4: }{100:oooo$$$$$$$$$$$$oooo}{4: }{1: }|
+ {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{1: }|
+ {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:o$}{4: }{100:$$}{4: }{100:o$}{4: }{1: }|
+ {1:~}{4: }{100:o}{4: }{100:$}{4: }{100:oo}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:$$}{4: }{100:$$}{4: }{100:$$o$}{4: }{1: }|
+ {1:~}{4: }{100:oo}{4: }{100:$}{4: }{100:$}{4: "}{100:$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$o}{4: }{100:$$$o$$o$}{4: }{1: }|
+ {1:~}{4: "}{100:$$$$$$o$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$o}{4: }{100:$$$$$$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$}{4: """}{100:$$$}{4: }{1: }|
+ {1:~}{4: "}{100:$$$}{4:""""}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$o}{4: }{1: }|
+ {1:~}{4: }{100:o$$}{4:" }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$o}{4: }{1: }|
+ {1:~}{4: }{100:$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" "}{100:$$$$$$ooooo$$$$o}{4: }{1: }|
+ {1:~}{4: }{100:o$$$oooo$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:o$$$$$$$$$$$$$$$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$$$$$$}{4:"}{100:$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$}{4:"""""""" }{1: }|
+ {1:~}{4: """" }{100:$$$$}{4: "}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" }{100:o$$$}{4: }{1: }|
+ {1:~}{4: "}{100:$$$o}{4: """}{100:$$$$$$$$$$$$$$$$$$}{4:"}{100:$$}{4:" }{100:$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$o}{4: "}{100:$$}{4:""}{100:$$$$$$}{4:"""" }{100:o$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$$o}{4: }{100:o$$$}{4:" }{1: }|
+ {1:~}{4: "}{100:$$$$o}{4: }{100:o$$$$$$o}{4:"}{100:$$$$o}{4: }{100:o$$$$}{4: }{1: }|
+ {1:~}{4: "}{100:$$$$$oo}{4: ""}{100:$$$$o$$$$$o}{4: }{100:o$$$$}{4:"" }{1: }|
+ {1:~}{4: ""}{100:$$$$$oooo}{4: "}{100:$$$o$$$$$$$$$}{4:""" }{1: }|
+ {1:~}{4: ""}{100:$$$$$$$oo}{4: }{100:$$$$$$$$$$}{4: }{1: }|
+ {1:~}{4: """"}{100:$$$$$$$$$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$$$$$$$$$$}{4: }{1: }|
+ {1:~}{4: }{100:$$$$$$$$$$}{4:" }{1: }|
+ {1:~}{4: "}{100:$$$}{4:"""" }{1: }|
+ {1:~}{4: }{1: }|
+ {1:~}{101:Press ENTER or type command to continue}{4: }{1: }|
+ {1:~}{103:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{1: }|
+ {1:~}{4::call nvim__screenshot("smile2.cat") }{1: }|
+ {1:~ }|*2
|
]],
}
@@ -3624,9 +3743,9 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~}{1:^ }{0: }|
- {0:~}{1: }{0: }|*4
- {0:~ }|*3
+ {1:~}{4:^ }{1: }|
+ {1:~}{4: }{1: }|*4
+ {1:~ }|*3
|
]],
}
@@ -3635,10 +3754,10 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~}{7: }{1: }{0: }|
- {0:~}{1: }{0: }|*4
- {0:~ }|*3
- {6:-- TERMINAL --} |
+ {1:~}{102: }{4: }{1: }|
+ {1:~}{4: }{1: }|*4
+ {1:~ }|*3
+ {5:-- TERMINAL --} |
]],
}
@@ -3651,10 +3770,10 @@ describe('API', function()
screen:expect {
grid = [[
|
- {0:~}{1:herrejösses!}{7: }{1: }{0: }|
- {0:~}{1: }{0: }|*4
- {0:~ }|*3
- {6:-- TERMINAL --} |
+ {1:~}{4:herrejösses!}{102: }{4: }{1: }|
+ {1:~}{4: }{1: }|*4
+ {1:~ }|*3
+ {5:-- TERMINAL --} |
]],
}
eq('ba\024blaherrejösses!', exec_lua [[ return stream ]])
@@ -3933,11 +4052,11 @@ describe('API', function()
))
eq(
{
- str = '3 ',
- width = 2,
+ str = ' 3 ',
+ width = 9,
highlights = {
{ group = 'LineNr', start = 0 },
- { group = 'ErrorMsg', start = 1 },
+ { group = 'ErrorMsg', start = 8 },
},
},
api.nvim_eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true })
@@ -4472,10 +4591,6 @@ describe('API', function()
end)
it('does not interfere with printing line in Ex mode #19400', function()
local screen = Screen.new(60, 7)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { bold = true, reverse = true }, -- MsgSeparator
- })
screen:attach()
insert([[
foo
@@ -4484,8 +4599,8 @@ describe('API', function()
screen:expect([[
foo |
bar |
- {0:~ }|*2
- {1: }|
+ {1:~ }|*2
+ {3: }|
Entering Ex mode. Type "visual" to go to Normal mode. |
:1^ |
]])
@@ -4494,7 +4609,7 @@ describe('API', function()
screen:expect([[
foo |
bar |
- {1: }|
+ {3: }|
Entering Ex mode. Type "visual" to go to Normal mode. |
:1 |
foo |
@@ -4934,14 +5049,11 @@ describe('API', function()
it("doesn't display messages when output=true", function()
local screen = Screen.new(40, 6)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- })
api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true })
screen:expect {
grid = [[
^ |
- {0:~ }|*4
+ {1:~ }|*4
|
]],
}
@@ -4954,7 +5066,7 @@ describe('API', function()
screen:expect {
grid = [[
^ |
- {0:~ }|*4
+ {1:~ }|*4
15 |
]],
}
@@ -5020,12 +5132,29 @@ describe('API', function()
it('nvim__redraw', function()
local screen = Screen.new(60, 5)
screen:attach()
- local win = api.nvim_get_current_win()
eq('at least one action required', pcall_err(api.nvim__redraw, {}))
eq('at least one action required', pcall_err(api.nvim__redraw, { buf = 0 }))
eq('at least one action required', pcall_err(api.nvim__redraw, { win = 0 }))
eq("cannot use both 'buf' and 'win'", pcall_err(api.nvim__redraw, { buf = 0, win = 0 }))
+ local win = api.nvim_get_current_win()
+ -- Can move cursor to recently opened window and window is flushed #28868
feed(':echo getchar()<CR>')
+ local newwin = api.nvim_open_win(0, false, {
+ relative = 'editor',
+ width = 1,
+ height = 1,
+ row = 1,
+ col = 10,
+ })
+ api.nvim__redraw({ win = newwin, cursor = true })
+ screen:expect({
+ grid = [[
+ |
+ {1:~ }{4:^ }{1: }|
+ {1:~ }|*2
+ :echo getchar() |
+ ]],
+ })
fn.setline(1, 'foobar')
command('vnew')
fn.setline(1, 'foobaz')
@@ -5034,11 +5163,13 @@ describe('API', function()
screen:expect({
grid = [[
foobaz │foobar |
- {1:~ }│{1:~ }|*2
+ {1:~ }{4:^f}{1: }│{1:~ }|
+ {1:~ }│{1:~ }|
{3:[No Name] [+] }{2:[No Name] [+] }|
- ^:echo getchar() |
+ :echo getchar() |
]],
})
+ api.nvim_win_close(newwin, true)
-- Can update the grid cursor position #20793
api.nvim__redraw({ cursor = true })
screen:expect({
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 15b9b0945c..5ce93f9e04 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -85,7 +85,7 @@ describe('API/win', function()
[[
local cmdwin_buf = vim.api.nvim_get_current_buf()
local new_win, new_buf = ...
- vim.api.nvim_buf_call(new_buf, function()
+ vim._with({buf = new_buf}, function()
vim.api.nvim_win_set_buf(new_win, cmdwin_buf)
end)
]],
@@ -100,7 +100,7 @@ describe('API/win', function()
[[
local cmdwin_win = vim.api.nvim_get_current_win()
local new_win, new_buf = ...
- vim.api.nvim_win_call(new_win, function()
+ vim._with({win = new_win}, function()
vim.api.nvim_win_set_buf(cmdwin_win, new_buf)
end)
]],
@@ -164,17 +164,12 @@ describe('API/win', function()
eq('typing\n some dumb text', curbuf_contents())
end)
- it('does not leak memory when using invalid window ID with invalid pos', function()
+ it('no memory leak when using invalid window ID with invalid pos', function()
eq('Invalid window id: 1', pcall_err(api.nvim_win_set_cursor, 1, { 'b\na' }))
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')
@@ -221,10 +216,10 @@ describe('API/win', function()
grid = [[
^ |
{1:~ }|*2
- {2:[No Name] }|
+ {3:[No Name] }|
prologue |
|*2
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -235,10 +230,10 @@ describe('API/win', function()
grid = [[
^ |
{1:~ }|*2
- {2:[No Name] }|
+ {3:[No Name] }|
|*2
epilogue |
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -249,10 +244,10 @@ describe('API/win', function()
grid = [[
^ |
{1:~ }|*2
- {2:[No Name] }|
+ {3:[No Name] }|
prologue |
|*2
- {3:[No Name] [+] }|
+ {2:[No Name] [+] }|
|
]],
}
@@ -286,12 +281,6 @@ describe('API/win', function()
it('updates cursorline and statusline ruler 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 }, -- CursorLine
- [3] = { bold = true, reverse = true }, -- StatusLine
- [4] = { reverse = true }, -- StatusLineNC
- })
screen:attach()
command('set ruler')
command('set cursorline')
@@ -306,31 +295,25 @@ describe('API/win', function()
aaa │aaa |
bbb │bbb |
ccc │ccc |
- {2:dd^d }│{2:ddd }|
+ {21:dd^d }│{21:ddd }|
{1:~ }│{1:~ }|*2
- {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 4,3 All}|
+ {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 4,3 All}|
|
]])
api.nvim_win_set_cursor(oldwin, { 1, 0 })
screen:expect([[
- aaa │{2:aaa }|
+ aaa │{21:aaa }|
bbb │bbb |
ccc │ccc |
- {2:dd^d }│ddd |
+ {21:dd^d }│ddd |
{1:~ }│{1:~ }|*2
- {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 1,1 All}|
+ {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 1,1 All}|
|
]])
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([[
@@ -341,22 +324,22 @@ describe('API/win', function()
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} |
+ aa{21:a} │aa{21:a} |
+ bb{21:b} │bb{21:b} |
+ cc{21:c} │cc{21:c} |
dd^d │ddd |
{1:~ }│{1:~ }|*2
- {3:[No Name] [+] }{4:[No Name] [+] }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
|
]])
api.nvim_win_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 |
+ aa{21:a} │{21:a}aa |
+ bb{21:b} │bbb |
+ cc{21:c} │{21:c}cc |
+ dd^d │{21:d}dd |
{1:~ }│{1:~ }|*2
- {3:[No Name] [+] }{4:[No Name] [+] }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
|
]])
end)
@@ -655,7 +638,7 @@ describe('API/win', function()
feed('q:')
exec_lua(
[[
- vim.api.nvim_win_call(..., function()
+ vim._with({win = ...}, function()
vim.api.nvim_win_close(0, true)
end)
]],
@@ -674,7 +657,7 @@ describe('API/win', function()
exec_lua(
[[
local otherwin, cmdwin = ...
- vim.api.nvim_win_call(otherwin, function()
+ vim._with({win = otherwin}, function()
vim.api.nvim_win_close(cmdwin, true)
end)
]],
@@ -788,7 +771,7 @@ describe('API/win', function()
})
exec_lua(
[[
- vim.api.nvim_win_call(..., function()
+ vim._with({win = ...}, function()
vim.api.nvim_win_hide(0)
end)
]],
@@ -807,7 +790,7 @@ describe('API/win', function()
exec_lua(
[[
local otherwin, cmdwin = ...
- vim.api.nvim_win_call(otherwin, function()
+ vim._with({win = otherwin}, function()
vim.api.nvim_win_hide(cmdwin)
end)
]],
@@ -874,22 +857,6 @@ describe('API/win', function()
it('with two diff windows', function()
local X = api.nvim_get_vvar('maxcol')
local screen = Screen.new(45, 22)
- screen:set_default_attr_ids({
- [0] = { foreground = Screen.colors.Blue1, bold = true },
- [1] = { foreground = Screen.colors.Blue4, background = Screen.colors.Grey },
- [2] = { foreground = Screen.colors.Brown },
- [3] = {
- foreground = Screen.colors.Blue1,
- background = Screen.colors.LightCyan1,
- bold = true,
- },
- [4] = { background = Screen.colors.LightBlue },
- [5] = { foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey },
- [6] = { background = Screen.colors.Plum1 },
- [7] = { background = Screen.colors.Red, bold = true },
- [8] = { reverse = true },
- [9] = { bold = true, reverse = true },
- })
screen:attach()
exec([[
set diffopt+=context:2 number
@@ -902,35 +869,35 @@ describe('API/win', function()
feed('24gg')
screen:expect {
grid = [[
- {1: }{2: }{3:----------------}│{1: }{2: 1 }{4:00000001! }|
- {1: }{2: }{3:----------------}│{1: }{2: 2 }{4:00000002!! }|
- {1: }{2: 1 }00000003!!! │{1: }{2: 3 }00000003!!! |
- {1: }{2: 2 }00000004!!!! │{1: }{2: 4 }00000004!!!! |
- {1:+ }{2: 3 }{5:+-- 14 lines: 00}│{1:+ }{2: 5 }{5:+-- 14 lines: 00}|
- {1: }{2: 17 }00000019!!!!!!!!│{1: }{2: 19 }00000019!!!!!!!!|
- {1: }{2: 18 }00000020!!!!!!!!│{1: }{2: 20 }00000020!!!!!!!!|
- {1: }{2: }{3:----------------}│{1: }{2: 21 }{4:00000025!!!!!!!!}|
- {1: }{2: }{3:----------------}│{1: }{2: 22 }{4:00000026!!!!!!!!}|
- {1: }{2: }{3:----------------}│{1: }{2: 23 }{4:00000027!!!!!!!!}|
- {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!|
- {1: }{2: 20 }00000029!!!!!!!!│{1: }{2: 25 }00000029!!!!!!!!|
- {1:+ }{2: 21 }{5:+-- 14 lines: 00}│{1:+ }{2: 26 }{5:+-- 14 lines: 00}|
- {1: }{2: 35 }00000044!!!!!!!!│{1: }{2: 40 }00000044!!!!!!!!|
- {1: }{2: 36 }00000045!!!!!!!!│{1: }{2: 41 }00000045!!!!!!!!|
- {1: }{2: 37 }{4:00000046!!!!!!!!}│{1: }{2: }{3:----------------}|
- {1: }{2: 38 }{4:00000047!!!!!!!!}│{1: }{2: }{3:----------------}|
- {1: }{2: 39 }{4:00000048!!!!!!!!}│{1: }{2: }{3:----------------}|
- {1: }{2: 40 }{4:00000049!!!!!!!!}│{1: }{2: }{3:----------------}|
- {1: }{2: 41 }{4:00000050!!!!!!!!}│{1: }{2: }{3:----------------}|
- {8:[No Name] [+] }{9:[No Name] [+] }|
+ {7: }{8: }{23:----------------}│{7: }{8: 1 }{22:00000001! }|
+ {7: }{8: }{23:----------------}│{7: }{8: 2 }{22:00000002!! }|
+ {7: }{8: 1 }00000003!!! │{7: }{8: 3 }00000003!!! |
+ {7: }{8: 2 }00000004!!!! │{7: }{8: 4 }00000004!!!! |
+ {7:+ }{8: 3 }{13:+-- 14 lines: 00}│{7:+ }{8: 5 }{13:+-- 14 lines: 00}|
+ {7: }{8: 17 }00000019!!!!!!!!│{7: }{8: 19 }00000019!!!!!!!!|
+ {7: }{8: 18 }00000020!!!!!!!!│{7: }{8: 20 }00000020!!!!!!!!|
+ {7: }{8: }{23:----------------}│{7: }{8: 21 }{22:00000025!!!!!!!!}|
+ {7: }{8: }{23:----------------}│{7: }{8: 22 }{22:00000026!!!!!!!!}|
+ {7: }{8: }{23:----------------}│{7: }{8: 23 }{22:00000027!!!!!!!!}|
+ {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!|
+ {7: }{8: 20 }00000029!!!!!!!!│{7: }{8: 25 }00000029!!!!!!!!|
+ {7:+ }{8: 21 }{13:+-- 14 lines: 00}│{7:+ }{8: 26 }{13:+-- 14 lines: 00}|
+ {7: }{8: 35 }00000044!!!!!!!!│{7: }{8: 40 }00000044!!!!!!!!|
+ {7: }{8: 36 }00000045!!!!!!!!│{7: }{8: 41 }00000045!!!!!!!!|
+ {7: }{8: 37 }{22:00000046!!!!!!!!}│{7: }{8: }{23:----------------}|
+ {7: }{8: 38 }{22:00000047!!!!!!!!}│{7: }{8: }{23:----------------}|
+ {7: }{8: 39 }{22:00000048!!!!!!!!}│{7: }{8: }{23:----------------}|
+ {7: }{8: 40 }{22:00000049!!!!!!!!}│{7: }{8: }{23:----------------}|
+ {7: }{8: 41 }{22:00000050!!!!!!!!}│{7: }{8: }{23:----------------}|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
|
]],
}
screen:try_resize(45, 3)
screen:expect {
grid = [[
- {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!|
- {8:[No Name] [+] }{9:[No Name] [+] }|
+ {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
|
]],
}
@@ -1008,11 +975,6 @@ describe('API/win', function()
it('with wrapped lines', function()
local X = api.nvim_get_vvar('maxcol')
local screen = Screen.new(45, 22)
- screen:set_default_attr_ids({
- [0] = { foreground = Screen.colors.Blue1, bold = true },
- [1] = { foreground = Screen.colors.Brown },
- [2] = { background = Screen.colors.Yellow },
- })
screen:attach()
exec([[
set number cpoptions+=n
@@ -1035,26 +997,26 @@ describe('API/win', function()
)
screen:expect {
grid = [[
- {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar|
+ {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar|
-foobar-foobar-foobar-foobar-foobar-foobar-fo|
obar-foobar-foobar-foobar-foobar-foobar-fooba|
r-foobar-foobar-foobar-foobar-foobar-foobar-f|
oobar-foobar-foobar-foobar-foobar-foobar-foob|
ar-foobar-foobar-foobar-foobar- |
- {1: 2 }foobar-foobar-foobar-foobar-foobar-foobar|
+ {8: 2 }foobar-foobar-foobar-foobar-foobar-foobar|
-foobar-foobar-foobar-foobar-foobar-foobar-fo|
- obar-foobar-fo{2:???????????????}obar-foobar-foob|
+ obar-foobar-fo{10:???????????????}obar-foobar-foob|
ar-foobar-foobar-foobar-foobar-foobar-foobar-|
foobar-foobar-foobar-foobar-foobar-foobar-foo|
bar-foobar-foobar-foobar-foobar-foobar-foobar|
- |
- {1: 3 }foobar-foobar-foobar-foobar-foobar-foobar|
+ {8: 3 }foobar-foobar-foobar-foobar-foobar-foobar|
-foobar-foobar-foobar-foobar-foobar-foobar-fo|
obar-foobar-foobar-foobar-foobar-foobar-fooba|
r-foobar-foobar-foobar-foobar-foobar-foobar-f|
- oobar-foobar-foobar-foob{2:!!!!!!!!!!!!!!!!!!!!!}|
- {2:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}|
- {2:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba|
+ oobar-foobar-foobar-foob{10:!!!!!!!!!!!!!!!!!!!!!}|
+ {10:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}|
+ {10:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba|
r-foobar-foobar- |
|
]],
@@ -1062,7 +1024,7 @@ describe('API/win', function()
screen:try_resize(45, 2)
screen:expect {
grid = [[
- {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar|
+ {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar|
|
]],
}
@@ -1216,7 +1178,7 @@ describe('API/win', function()
exec_lua,
[[
local cmdwin_buf = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function()
+ vim._with({buf = vim.api.nvim_create_buf(false, true)}, function()
vim.api.nvim_open_win(cmdwin_buf, false, {
relative='editor', row=5, col=5, width=5, height=5,
})
@@ -1847,6 +1809,38 @@ describe('API/win', function()
eq(topdir .. '/Xacd', fn.getcwd())
end)
end)
+
+ it('no memory leak with valid title and invalid footer', function()
+ eq(
+ 'title/footer must be string or array',
+ pcall_err(api.nvim_open_win, 0, false, {
+ relative = 'editor',
+ row = 10,
+ col = 10,
+ height = 10,
+ width = 10,
+ border = 'single',
+ title = { { 'TITLE' } },
+ footer = 0,
+ })
+ )
+ end)
+
+ it('no memory leak with invalid title and valid footer', function()
+ eq(
+ 'title/footer must be string or array',
+ pcall_err(api.nvim_open_win, 0, false, {
+ relative = 'editor',
+ row = 10,
+ col = 10,
+ height = 10,
+ width = 10,
+ border = 'single',
+ title = 0,
+ footer = { { 'FOOTER' } },
+ })
+ )
+ end)
end)
describe('set_config', function()
@@ -2563,10 +2557,6 @@ describe('API/win', function()
it('updates statusline when moving bottom split', function()
local screen = Screen.new(10, 10)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { bold = true, reverse = true }, -- StatusLine
- })
screen:attach()
exec([[
set laststatus=0
@@ -2575,10 +2565,10 @@ describe('API/win', function()
]])
screen:expect([[
^ |
- {0:~ }|*3
- {1:[No Name] }|
+ {1:~ }|*3
+ {3:[No Name] }|
|
- {0:~ }|*3
+ {1:~ }|*3
|
]])
end)
@@ -2807,61 +2797,35 @@ describe('API/win', function()
border = 'single',
})
eq(
- 'title/footer cannot be an empty array',
- pcall_err(api.nvim_win_set_config, win, { title = {} })
+ 'title/footer must be string or array',
+ pcall_err(api.nvim_win_set_config, win, { title = 0 })
)
command('redraw!')
assert_alive()
- end)
-
- it('no crash with invalid footer', function()
- local win = api.nvim_open_win(0, true, {
- width = 10,
- height = 10,
- relative = 'editor',
- row = 10,
- col = 10,
- footer = { { 'test' } },
- border = 'single',
- })
eq(
'title/footer cannot be an empty array',
- pcall_err(api.nvim_win_set_config, win, { footer = {} })
+ pcall_err(api.nvim_win_set_config, win, { title = {} })
)
command('redraw!')
assert_alive()
end)
- end)
- describe('set_config', function()
- it('no crash with invalid title', function()
+ it('no crash with invalid footer', function()
local win = api.nvim_open_win(0, true, {
width = 10,
height = 10,
relative = 'editor',
row = 10,
col = 10,
- title = { { 'test' } },
+ footer = { { 'test' } },
border = 'single',
})
eq(
- 'title/footer cannot be an empty array',
- pcall_err(api.nvim_win_set_config, win, { title = {} })
+ 'title/footer must be string or array',
+ pcall_err(api.nvim_win_set_config, win, { footer = 0 })
)
command('redraw!')
assert_alive()
- end)
-
- it('no crash with invalid footer', function()
- local win = api.nvim_open_win(0, true, {
- width = 10,
- height = 10,
- relative = 'editor',
- row = 10,
- col = 10,
- footer = { { 'test' } },
- border = 'single',
- })
eq(
'title/footer cannot be an empty array',
pcall_err(api.nvim_win_set_config, win, { footer = {} })
@@ -2869,5 +2833,48 @@ describe('API/win', function()
command('redraw!')
assert_alive()
end)
+
+ describe('no crash or memory leak', function()
+ local win
+
+ before_each(function()
+ win = api.nvim_open_win(0, false, {
+ relative = 'editor',
+ row = 10,
+ col = 10,
+ height = 10,
+ width = 10,
+ border = 'single',
+ title = { { 'OLD_TITLE' } },
+ footer = { { 'OLD_FOOTER' } },
+ })
+ end)
+
+ it('with valid title and invalid footer', function()
+ eq(
+ 'title/footer must be string or array',
+ pcall_err(api.nvim_win_set_config, win, {
+ title = { { 'NEW_TITLE' } },
+ footer = 0,
+ })
+ )
+ command('redraw!')
+ assert_alive()
+ eq({ { 'OLD_TITLE' } }, api.nvim_win_get_config(win).title)
+ end)
+
+ it('with invalid title and valid footer', function()
+ eq(
+ 'title/footer must be string or array',
+ pcall_err(api.nvim_win_set_config, win, {
+ title = 0,
+ footer = { { 'NEW_FOOTER' } },
+ })
+ )
+ command('redraw!')
+ assert_alive()
+ eq({ { 'OLD_FOOTER' } }, api.nvim_win_get_config(win).footer)
+ end)
+ end)
end)
end)
diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua
index 1a3b723ac2..5e4beb7684 100644
--- a/test/functional/autocmd/autocmd_oldtest_spec.lua
+++ b/test/functional/autocmd/autocmd_oldtest_spec.lua
@@ -103,9 +103,9 @@ describe('oldtests', function()
it('no ml_get error with TextChanged autocommand and delete', function()
local screen = Screen.new(75, 10)
screen:attach()
- screen:set_default_attr_ids({
- [1] = { background = Screen.colors.Cyan },
- })
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Cyan1 },
+ }
exec([[
set noshowcmd noruler scrolloff=0
source test/old/testdir/samples/matchparen.vim
@@ -120,9 +120,9 @@ describe('oldtests', function()
} |
const auto &themes = _forPeer->owner().cloudThemes(); |
const auto theme = themes.themeForEmoji(themeEmoji); |
- if (!theme) {1:{} |
+ if (!theme) {100:{} |
return nonCustom; |
- {1:^}} |
+ {100:^}} |
353 fewer lines |
]],
}
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 5e407a9986..0429cfee89 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -259,15 +259,6 @@ describe('autocmd', function()
local screen = Screen.new(50, 10)
screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { background = Screen.colors.LightMagenta },
- [3] = {
- background = Screen.colors.LightMagenta,
- bold = true,
- foreground = Screen.colors.Blue1,
- },
- })
source([[
function! Doit()
@@ -292,8 +283,8 @@ describe('autocmd', function()
feed(':enew | doautoall User<cr>')
screen:expect([[
- {2:bb }|
- {3:~ }|*4
+ {4:bb }|
+ {11:~ }|*4
{1:~ }|*4
^:enew | doautoall User |
]])
@@ -318,8 +309,8 @@ describe('autocmd', function()
command('let g:had_value = v:null')
feed(':doautoall User<cr>')
screen:expect([[
- {2:bb }|
- {3:~ }|*4
+ {4:bb }|
+ {11:~ }|*4
{1:~ }|*4
^:doautoall User |
]])
@@ -343,18 +334,13 @@ describe('autocmd', function()
it('`aucmd_win` cannot be changed into a normal window #13699', function()
local screen = Screen.new(50, 10)
screen:attach()
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { reverse = true },
- [3] = { bold = true, reverse = true },
- }
-- Create specific layout and ensure it's left unchanged.
- -- Use nvim_buf_call on a hidden buffer so aucmd_win is used.
+ -- Use vim._with on a hidden buffer so aucmd_win is used.
exec_lua [[
vim.cmd "wincmd s | wincmd _"
_G.buf = vim.api.nvim_create_buf(true, true)
- vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd J" end)
+ vim._with({buf = _G.buf}, function() vim.cmd "wincmd J" end)
]]
screen:expect [[
^ |
@@ -367,14 +353,14 @@ describe('autocmd', function()
-- This used to crash after making aucmd_win a normal window via the above.
exec_lua [[
vim.cmd "tabnew | tabclose # | wincmd s | wincmd _"
- vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd K" end)
+ vim._with({buf = _G.buf}, function() vim.cmd "wincmd K" end)
]]
assert_alive()
screen:expect_unchanged()
-- Also check with win_splitmove().
exec_lua [[
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
vim.fn.win_splitmove(vim.fn.winnr(), vim.fn.win_getid(1))
end)
]]
@@ -382,11 +368,11 @@ describe('autocmd', function()
-- Also check with nvim_win_set_config().
matches(
- ': Failed to move window %d+ into split$',
+ '^Failed to move window %d+ into split$',
pcall_err(
exec_lua,
[[
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
vim.api.nvim_win_set_config(0, {
vertical = true,
win = vim.fn.win_getid(1)
@@ -398,7 +384,7 @@ describe('autocmd', function()
screen:expect_unchanged()
-- Ensure splitting still works from inside the aucmd_win.
- exec_lua [[vim.api.nvim_buf_call(_G.buf, function() vim.cmd "split" end)]]
+ exec_lua [[vim._with({buf = _G.buf}, function() vim.cmd "split" end)]]
screen:expect [[
^ |
{1:~ }|
@@ -418,7 +404,7 @@ describe('autocmd', function()
'editor',
exec_lua [[
vim.cmd "only"
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
_G.config = vim.api.nvim_win_get_config(0)
end)
return _G.config.relative
@@ -463,7 +449,7 @@ describe('autocmd', function()
pcall_err(
exec_lua,
[[
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_close(win, true)
end)
@@ -475,7 +461,7 @@ describe('autocmd', function()
pcall_err(
exec_lua,
[[
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
local win = vim.api.nvim_get_current_win()
vim.cmd('tabnext')
vim.api.nvim_win_close(win, true)
@@ -488,7 +474,7 @@ describe('autocmd', function()
pcall_err(
exec_lua,
[[
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
local win = vim.api.nvim_get_current_win()
vim.api.nvim_win_hide(win)
end)
@@ -500,7 +486,7 @@ describe('autocmd', function()
pcall_err(
exec_lua,
[[
- vim.api.nvim_buf_call(_G.buf, function()
+ vim._with({buf = _G.buf}, function()
local win = vim.api.nvim_get_current_win()
vim.cmd('tabnext')
vim.api.nvim_win_hide(win)
@@ -513,9 +499,6 @@ describe('autocmd', function()
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- })
feed(':doautocmd User Foo<cr>')
screen:expect {
diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua
index ad3bc3576f..ca137debb8 100644
--- a/test/functional/autocmd/cmdline_spec.lua
+++ b/test/functional/autocmd/cmdline_spec.lua
@@ -61,12 +61,6 @@ describe('cmdline autocommands', function()
clear()
local screen = Screen.new(72, 8)
screen:attach()
- 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 },
- [4] = { bold = true, reverse = true },
- })
command("autocmd CmdlineEnter * echoerr 'FAIL'")
command("autocmd CmdlineLeave * echoerr 'very error'")
@@ -74,22 +68,22 @@ describe('cmdline autocommands', function()
screen:expect([[
|
{1:~ }|*3
- {4: }|
+ {3: }|
: |
- {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
+ {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:^ |
]])
feed("put ='lorem ipsum'<cr>")
screen:expect([[
|
- {4: }|
+ {3: }|
: |
- {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
+ {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
+ {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
|
- {3:Press ENTER or type command to continue}^ |
+ {6:Press ENTER or type command to continue}^ |
]])
-- cmdline was still executed
@@ -108,11 +102,11 @@ describe('cmdline autocommands', function()
screen:expect([[
|
lorem ipsum |
- {4: }|
+ {3: }|
: |
- {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
+ {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
+ {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum'^ |
]])
@@ -120,37 +114,37 @@ describe('cmdline autocommands', function()
screen:expect([[
|
lorem ipsum |
- {4: }|
+ {3: }|
: |
- {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
+ {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
+ {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum^' |
]])
-- edit still works
feed('.')
screen:expect([[
- {4: }|
+ {3: }|
: |
- {2:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
+ {9:CmdlineEnter Autocommands for "*": Vim(echoerr):FAIL} |
:put ='lorem ipsum' |
- {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
+ {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
- {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
+ {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.^' |
]])
feed('<cr>')
screen:expect([[
:put ='lorem ipsum' |
- {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
+ {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
- {2:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
+ {9:CmdlineChanged Autocommands for "*": Vim(echoerr):change erreor} |
:put ='lorem ipsum.' |
- {2:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
+ {9:CmdlineLeave Autocommands for "*": Vim(echoerr):very error} |
|
- {3:Press ENTER or type command to continue}^ |
+ {6:Press ENTER or type command to continue}^ |
]])
-- cmdline was still executed
diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua
index 24ac737b5b..1cde0e0552 100644
--- a/test/functional/autocmd/dirchanged_spec.lua
+++ b/test/functional/autocmd/dirchanged_spec.lua
@@ -9,7 +9,7 @@ local request = n.request
local is_os = t.is_os
describe('autocmd DirChanged and DirChangedPre', function()
- local curdir = vim.uv.cwd():gsub('\\', '/')
+ local curdir = t.fix_slashes(vim.uv.cwd())
local dirs = {
curdir .. '/Xtest-functional-autocmd-dirchanged.dir1',
curdir .. '/Xtest-functional-autocmd-dirchanged.dir2',
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index 5163b576db..7f6092bf48 100644
--- a/test/functional/autocmd/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
@@ -1,6 +1,6 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local clear = n.clear
local feed_command = n.feed_command
diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua
index 7e1818c4fd..10d242527f 100644
--- a/test/functional/autocmd/show_spec.lua
+++ b/test/functional/autocmd/show_spec.lua
@@ -43,11 +43,9 @@ describe(':autocmd', function()
it('should not show group information if interrupted', function()
local screen = Screen.new(50, 6)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 }, -- NonText
- [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
- [3] = { bold = true, foreground = Screen.colors.Magenta }, -- Title
- })
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.Magenta, bold = true },
+ }
screen:attach()
exec([[
set more
@@ -73,11 +71,11 @@ describe(':autocmd', function()
feed(':autocmd<CR>')
screen:expect([[
:autocmd |
- {3:--- Autocommands ---} |
- {3:test_1} {3:BufEnter} |
+ {100:--- Autocommands ---} |
+ {100:test_1} {100:BufEnter} |
A echo 'A' |
B echo 'B' |
- {2:-- More --}^ |
+ {6:-- More --}^ |
]])
feed('q')
screen:expect([[
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index a63996ae36..64f16cf779 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -1,6 +1,6 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local uv = vim.uv
local clear, command, testprg = n.clear, n.command, n.testprg
@@ -199,7 +199,7 @@ end)
describe('autocmd TextChangedT', function()
clear()
- local screen = tt.screen_setup()
+ local screen = tt.setup_screen()
it('works', function()
command('autocmd TextChangedT * ++once let g:called = 1')
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index a98e190a60..dee13d19ae 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -288,6 +288,37 @@ describe('channels', function()
eq({ 'notification', 'exit', { 3, 0 } }, next_msg())
end)
+ it('stdio channel works with stdout redirected to file #30509', function()
+ t.write_file(
+ 'Xstdio_write.vim',
+ [[
+ let chan = stdioopen({})
+ call chansend(chan, 'foo')
+ call chansend(chan, 'bar')
+ qall!
+ ]]
+ )
+ local fd = assert(vim.uv.fs_open('Xstdio_redir', 'w', 420))
+ local exit_code, exit_signal
+ local handle = vim.uv.spawn(nvim_prog, {
+ args = { '-u', 'NONE', '-i', 'NONE', '--headless', '-S', 'Xstdio_write.vim' },
+ -- Simulate shell redirection: "nvim ... > Xstdio_redir". #30509
+ stdio = { nil, fd, nil },
+ }, function(code, signal)
+ vim.uv.stop()
+ exit_code, exit_signal = code, signal
+ end)
+ finally(function()
+ handle:close()
+ vim.uv.fs_close(fd)
+ os.remove('Xstdio_write.vim')
+ os.remove('Xstdio_redir')
+ end)
+ vim.uv.run('default')
+ eq({ 0, 0 }, { exit_code, exit_signal })
+ eq('foobar', t.read_file('Xstdio_redir'))
+ end)
+
it('can use buffered output mode', function()
skip(fn.executable('grep') == 0, 'missing "grep" command')
source([[
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index 5b0be1e83c..d33710a63d 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -276,11 +276,6 @@ describe('fileio', function()
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')
@@ -300,9 +295,9 @@ describe('fileio', function()
-- 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)?}|
+ {9:WARNING: The file has been changed since}|
+ {9: reading it!!!} |
+ {6:Do you really want to write to it (y/n)?}|
^ |
]])
@@ -326,11 +321,11 @@ end)
describe('tmpdir', function()
local tmproot_pat = [=[.*[/\\]nvim%.[^/\\]+]=]
local testlog = 'Xtest_tmpdir_log'
- local os_tmpdir
+ local os_tmpdir ---@type string
before_each(function()
-- Fake /tmp dir so that we can mess it up.
- os_tmpdir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX')
+ os_tmpdir = assert(vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX'))
end)
after_each(function()
@@ -419,15 +414,4 @@ describe('tmpdir', function()
rm_tmpdir()
eq('E5431: tempdir disappeared (3 times)', api.nvim_get_vvar('errmsg'))
end)
-
- it('$NVIM_APPNAME relative path', function()
- clear({
- env = {
- NVIM_APPNAME = 'a/b',
- NVIM_LOG_FILE = testlog,
- TMPDIR = os_tmpdir,
- },
- })
- matches([=[.*[/\\]a%%b%.[^/\\]+]=], fn.tempname())
- end)
end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index e1efc07452..68ac0a50f6 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local clear = n.clear
local eq = t.eq
@@ -910,11 +910,6 @@ describe('jobs', function()
it('hides cursor and flushes messages before blocking', function()
local screen = Screen.new(50, 6)
- screen:set_default_attr_ids({
- [0] = { foreground = Screen.colors.Blue, bold = true }, -- NonText
- [1] = { bold = true, reverse = true }, -- MsgSeparator
- [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
- })
screen:attach()
command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]])
source([[
@@ -928,8 +923,8 @@ describe('jobs', function()
screen:expect {
grid = [[
|
- {0:~ }|*2
- {1: }|
+ {1:~ }|*2
+ {3: }|
aaa |
bbb |
]],
@@ -938,11 +933,11 @@ describe('jobs', function()
screen:expect {
grid = [[
|
- {1: }|
+ {3: }|
aaa |
bbb |
ccc |
- {2:Press ENTER or type command to continue}^ |
+ {6:Press ENTER or type command to continue}^ |
]],
}
feed('<CR>')
diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua
index cac61cda2d..a952730779 100644
--- a/test/functional/core/log_spec.lua
+++ b/test/functional/core/log_spec.lua
@@ -1,5 +1,6 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
+local tt = require('test.functional.testterm')
local assert_log = t.assert_log
local clear = n.clear
@@ -29,10 +30,54 @@ describe('log', function()
assert(request('nvim__stats').log_skip <= 13)
end)
- it('messages are formatted with name or test id', function()
+ it('TUI client name is "ui"', function()
+ local function setup(env)
+ clear()
+ -- Start Nvim with builtin UI.
+ local screen = tt.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ n.nvim_set,
+ }, {
+ env = env,
+ })
+ screen:expect([[
+ {1: } |
+ ~ |*4
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end
+
+ -- Without $NVIM parent.
+ setup({
+ NVIM = '',
+ NVIM_LISTEN_ADDRESS = '',
+ NVIM_LOG_FILE = testlog,
+ __NVIM_TEST_LOG = '1',
+ })
+ -- Example:
+ -- ERR 2024-09-11T16:40:02.421 ui.47056 ui_client_run:165: test log message
+ assert_log(' ui%.%d+% +ui_client_run:%d+: test log message', testlog, 100)
+
+ -- With $NVIM parent.
+ setup({
+ NVIM_LOG_FILE = testlog,
+ __NVIM_TEST_LOG = '1',
+ })
+ -- Example:
+ -- ERR 2024-09-11T16:41:17.539 ui/c/T2.47826.0 ui_client_run:165: test log message
+ local tid = _G._nvim_test_id
+ assert_log(' ui/c/' .. tid .. '%.%d+%.%d +ui_client_run:%d+: test log message', testlog, 100)
+ end)
+
+ it('formats messages with session name or test id', function()
-- Examples:
- -- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message
- -- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message
+ -- ERR 2024-09-11T16:44:33.794 T3.49429.0 server_init:58: test log message
+ -- ERR 2024-09-11T16:44:33.823 c/T3.49429.0 server_init:58: test log message
clear({
env = {
@@ -47,10 +92,10 @@ describe('log', function()
exec_lua([[
local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict())
- vim.fn.jobwait({ j1 }, 10000)
+ vim.fn.jobwait({ j1 }, 5000)
]])
- -- Child Nvim spawned by jobstart() appends "/c" to parent name.
- assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100)
+ -- Child Nvim spawned by jobstart() prepends "c/" to parent name.
+ assert_log('c/' .. tid .. '%.%d+%.%d +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 5e903726db..a6e917b4b2 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -193,4 +193,26 @@ describe('command-line option', function()
matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' }))
matches('Compilation: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' }))
end)
+
+ if is_os('win') then
+ for _, prefix in ipairs({ '~/', '~\\' }) do
+ it('expands ' .. prefix .. ' on Windows', function()
+ local fname = os.getenv('USERPROFILE') .. '\\nvim_test.txt'
+ finally(function()
+ os.remove(fname)
+ end)
+ write_file(fname, 'some text')
+ eq(
+ 'some text',
+ fn.system({
+ nvim_prog_abs(),
+ '-es',
+ '+%print',
+ '+q',
+ prefix .. 'nvim_test.txt',
+ }):gsub('\n', '')
+ )
+ end)
+ end
+ end
end)
diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/core/server_spec.lua
index 4b0dc087f6..0ec11169e9 100644
--- a/test/functional/vimscript/server_spec.lua
+++ b/test/functional/core/server_spec.lua
@@ -1,10 +1,8 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local assert_log = t.assert_log
local eq, neq, eval = t.eq, t.neq, n.eval
local clear, fn, api = n.clear, n.fn, n.api
-local ok = t.ok
local matches = t.matches
local pcall_err = t.pcall_err
local check_close = n.check_close
@@ -20,12 +18,16 @@ local function clear_serverlist()
end
end
-describe('server', function()
- after_each(function()
- check_close()
- os.remove(testlog)
- end)
+after_each(function()
+ check_close()
+ os.remove(testlog)
+end)
+before_each(function()
+ os.remove(testlog)
+end)
+
+describe('server', function()
it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function()
local dir = 'Xtest_xdg_run'
mkdir(dir)
@@ -39,6 +41,21 @@ describe('server', function()
end
end)
+ it('broken $XDG_RUNTIME_DIR is not fatal #30282', function()
+ clear {
+ args_rm = { '--listen' },
+ env = { NVIM_LOG_FILE = testlog, XDG_RUNTIME_DIR = '/non-existent-dir/subdir//' },
+ }
+
+ if is_os('win') then
+ -- Windows pipes have a special namespace and thus aren't decided by $XDG_RUNTIME_DIR.
+ matches('nvim', api.nvim_get_vvar('servername'))
+ else
+ eq('', api.nvim_get_vvar('servername'))
+ t.assert_log('Failed to start server%: no such file or directory', testlog, 100)
+ end
+ end)
+
it('serverstart(), serverstop() does not set $NVIM', function()
clear()
local s = eval('serverstart()')
@@ -49,15 +66,6 @@ describe('server', function()
eq('', eval('$NVIM_LISTEN_ADDRESS'))
end)
- it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function()
- clear({ env = { NVIM_LISTEN_ADDRESS = '.' } })
- -- Cleared on startup.
- eq('', eval('$NVIM_LISTEN_ADDRESS'))
- local servers = fn.serverlist()
- eq(1, #servers)
- ok(string.len(servers[1]) > 4) -- "~/.local/state/nvim…/…" or "\\.\pipe\…"
- end)
-
it('sets v:servername at startup or if all servers were stopped', function()
clear()
local initial_server = api.nvim_get_vvar('servername')
@@ -89,20 +97,26 @@ describe('server', function()
end)
it('serverstop() returns false for invalid input', function()
- clear { env = {
- NVIM_LOG_FILE = testlog,
- NVIM_LISTEN_ADDRESS = '.',
- } }
+ clear {
+ args_rm = { '--listen' },
+ 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)
+ t.assert_log('Not listening on bogus%-socket%-name', testlog, 10)
end)
it('parses endpoints', function()
- clear { env = {
- NVIM_LOG_FILE = testlog,
- NVIM_LISTEN_ADDRESS = '.',
- } }
+ clear {
+ args_rm = { '--listen' },
+ env = {
+ NVIM_LOG_FILE = testlog,
+ NVIM_LISTEN_ADDRESS = '',
+ },
+ }
clear_serverlist()
eq({}, fn.serverlist())
@@ -126,7 +140,7 @@ describe('server', function()
if status then
table.insert(expected, v4)
pcall(fn.serverstart, v4) -- exists already; ignore
- assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10)
+ t.assert_log('Failed to start server: address already in use: 127%.0%.0%.1', testlog, 10)
end
local v6 = '::1:12345'
@@ -134,13 +148,13 @@ describe('server', function()
if status then
table.insert(expected, v6)
pcall(fn.serverstart, v6) -- exists already; ignore
- assert_log('Failed to start server: address already in use: ::1', testlog, 10)
+ t.assert_log('Failed to start server: address already in use: ::1', testlog, 10)
end
eq(expected, fn.serverlist())
clear_serverlist()
-- Address without slashes is a "name" which is appended to a generated path. #8519
- matches([[.*[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4'))
+ matches([[[/\\]xtest1%.2%.3%.4[^/\\]*]], fn.serverstart('xtest1.2.3.4'))
clear_serverlist()
eq('Vim:Failed to start server: invalid argument', pcall_err(fn.serverstart, '127.0.0.1:65536')) -- invalid port
@@ -176,24 +190,89 @@ describe('server', function()
end)
describe('startup --listen', function()
+ -- Tests Nvim output when failing to start, with and without "--headless".
+ -- TODO(justinmk): clear() should have a way to get stdout if Nvim fails to start.
+ local function _test(args, env, expected)
+ local function run(cmd)
+ return n.exec_lua(function(cmd_, env_)
+ return vim
+ .system(cmd_, {
+ text = true,
+ env = vim.tbl_extend(
+ 'force',
+ -- Avoid noise in the logs; we expect failures for these tests.
+ { NVIM_LOG_FILE = testlog },
+ env_ or {}
+ ),
+ })
+ :wait()
+ end, cmd, env) --[[@as vim.SystemCompleted]]
+ end
+
+ local cmd = vim.list_extend({ n.nvim_prog, '+qall!', '--headless' }, args)
+ local r = run(cmd)
+ eq(1, r.code)
+ matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' '))
+
+ if is_os('win') then
+ return -- On Windows, output without --headless is garbage.
+ end
+ table.remove(cmd, 3) -- Remove '--headless'.
+ assert(not vim.tbl_contains(cmd, '--headless'))
+ r = run(cmd)
+ eq(1, r.code)
+ matches(expected, (r.stderr .. r.stdout):gsub('\\n', ' '))
+ end
+
it('validates', function()
- clear()
- local cmd = { unpack(n.nvim_argv) }
- table.insert(cmd, '--listen')
- matches('nvim.*: Argument missing after: "%-%-listen"', fn.system(cmd))
+ clear { env = { NVIM_LOG_FILE = testlog } }
+ local in_use = n.eval('v:servername') ---@type string Address already used by another server.
+
+ t.assert_nolog('Failed to start server', testlog, 100)
+ t.assert_nolog('Host lookup failed', testlog, 100)
- cmd = { unpack(n.nvim_argv) }
- table.insert(cmd, '--listen2')
- matches('nvim.*: Garbage after option argument: "%-%-listen2"', fn.system(cmd))
+ _test({ '--listen' }, nil, 'nvim.*: Argument missing after: "%-%-listen"')
+ _test({ '--listen2' }, nil, 'nvim.*: Garbage after option argument: "%-%-listen2"')
+ _test(
+ { '--listen', in_use },
+ nil,
+ ('nvim.*: Failed to %%-%%-listen: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use))
+ )
+ _test({ '--listen', '/' }, nil, 'nvim.*: Failed to %-%-listen: [^:]+: "/"')
+ _test(
+ { '--listen', 'https://example.com' },
+ nil,
+ ('nvim.*: Failed to %%-%%-listen: %s: "https://example.com"'):format(
+ is_os('mac') and 'unknown node or service' or 'service not available for socket type'
+ )
+ )
+
+ t.assert_log('Failed to start server', testlog, 100)
+ t.assert_log('Host lookup failed', testlog, 100)
+
+ _test(
+ {},
+ { NVIM_LISTEN_ADDRESS = in_use },
+ ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+ already [^:]+: "%s"'):format(vim.pesc(in_use))
+ )
+ _test({}, { NVIM_LISTEN_ADDRESS = '/' }, 'nvim.*: Failed $NVIM_LISTEN_ADDRESS: [^:]+: "/"')
+ _test(
+ {},
+ { NVIM_LISTEN_ADDRESS = 'https://example.com' },
+ ('nvim.*: Failed $NVIM_LISTEN_ADDRESS: %s: "https://example.com"'):format(
+ is_os('mac') and 'unknown node or service' or 'service not available for socket type'
+ )
+ )
end)
it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
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 } })
+ eq('', eval('$NVIM_LISTEN_ADDRESS')) -- Cleared on startup.
eq(addr, api.nvim_get_vvar('servername'))
-- Address without slashes is a "name" which is appended to a generated path. #8519
clear({ args = { '--listen', 'test-name' } })
- matches([[.*[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername'))
+ matches([[[/\\]test%-name[^/\\]*]], api.nvim_get_vvar('servername'))
end)
end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index a53625ab1b..f48bcb9360 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -27,7 +27,6 @@ local sleep = vim.uv.sleep
local startswith = vim.startswith
local write_file = t.write_file
local api = n.api
-local alter_slashes = n.alter_slashes
local is_os = t.is_os
local dedent = t.dedent
local tbl_map = vim.tbl_map
@@ -40,22 +39,15 @@ local testlog = 'Xtest-startupspec-log'
describe('startup', function()
it('--clean', function()
clear()
- ok(
- string.find(
- alter_slashes(api.nvim_get_option_value('runtimepath', {})),
- fn.stdpath('config'),
- 1,
- true
- ) ~= nil
+ matches(
+ vim.pesc(t.fix_slashes(fn.stdpath('config'))),
+ t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
)
+
clear('--clean')
ok(
- string.find(
- alter_slashes(api.nvim_get_option_value('runtimepath', {})),
- fn.stdpath('config'),
- 1,
- true
- ) == nil
+ not t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
+ :match(vim.pesc(t.fix_slashes(fn.stdpath('config'))))
)
end)
@@ -112,6 +104,13 @@ describe('startup', function()
|*2
]])
end)
+
+ it(':filetype detect enables filetype detection with -u NONE', function()
+ clear()
+ eq('filetype detection:OFF plugin:OFF indent:OFF', exec_capture('filetype'))
+ command('filetype detect')
+ eq('filetype detection:ON plugin:OFF indent:OFF', exec_capture('filetype'))
+ end)
end)
describe('startup', function()
@@ -400,9 +399,6 @@ describe('startup', function()
read_file('Xtest_startup_ttyout')
)
end)
- if is_os('win') then
- assert_log('stream write failed. RPC canceled; closing channel', testlog)
- end
end)
it('input from pipe: has("ttyin")==0 has("ttyout")==1', function()
@@ -435,9 +431,6 @@ describe('startup', function()
read_file('Xtest_startup_ttyout')
)
end)
- if is_os('win') then
- assert_log('stream write failed. RPC canceled; closing channel', testlog)
- end
end)
it('input from pipe (implicit) #7679', function()
@@ -1331,31 +1324,59 @@ describe('runtime:', function()
end)
it("loads ftdetect/*.{vim,lua} respecting 'rtp' order", function()
- local ftdetect_folder = table.concat({ xconfig, 'nvim', 'ftdetect' }, pathsep)
- local after_ftdetect_folder = table.concat({ xconfig, 'nvim', 'after', 'ftdetect' }, pathsep)
+ local rtp_folder = table.concat({ xconfig, 'nvim' }, pathsep)
+ local after_rtp_folder = table.concat({ rtp_folder, 'after' }, pathsep)
+ local ftdetect_folder = table.concat({ rtp_folder, 'ftdetect' }, pathsep)
+ local after_ftdetect_folder = table.concat({ after_rtp_folder, 'ftdetect' }, pathsep)
mkdir_p(ftdetect_folder)
mkdir_p(after_ftdetect_folder)
finally(function()
rmdir(ftdetect_folder)
rmdir(after_ftdetect_folder)
end)
+ write_file(table.concat({ rtp_folder, 'scripts.vim' }, pathsep), [[let g:aseq ..= 'S']])
+ write_file(table.concat({ after_rtp_folder, 'scripts.vim' }, pathsep), [[let g:aseq ..= 's']])
-- A .lua file is loaded after a .vim file if they only differ in extension.
-- All files in after/ftdetect/ are loaded after all files in ftdetect/.
- write_file(table.concat({ ftdetect_folder, 'new-ft.vim' }, pathsep), [[let g:seq ..= 'A']])
+ write_file(
+ table.concat({ ftdetect_folder, 'new-ft.vim' }, pathsep),
+ [[
+ let g:seq ..= 'A'
+ autocmd BufRead,BufNewFile FTDETECT let g:aseq ..= 'A'
+ ]]
+ )
write_file(
table.concat({ ftdetect_folder, 'new-ft.lua' }, pathsep),
- [[vim.g.seq = vim.g.seq .. 'B']]
+ [[
+ vim.g.seq = vim.g.seq .. 'B'
+ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, {
+ pattern = 'FTDETECT',
+ command = "let g:aseq ..= 'B'",
+ })
+ ]]
)
write_file(
table.concat({ after_ftdetect_folder, 'new-ft.vim' }, pathsep),
- [[let g:seq ..= 'a']]
+ [[
+ let g:seq ..= 'a'
+ autocmd BufRead,BufNewFile FTDETECT let g:aseq ..= 'a'
+ ]]
)
write_file(
table.concat({ after_ftdetect_folder, 'new-ft.lua' }, pathsep),
- [[vim.g.seq = vim.g.seq .. 'b']]
+ [[
+ vim.g.seq = vim.g.seq .. 'b'
+ vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, {
+ pattern = 'FTDETECT',
+ command = "let g:aseq ..= 'b'",
+ })
+ ]]
)
clear { args_rm = { '-u' }, args = { '--cmd', 'let g:seq = ""' }, env = xenv }
eq('ABab', eval('g:seq'))
+ command('let g:aseq = ""')
+ command('edit FTDETECT')
+ eq('SsABab', eval('g:aseq'))
end)
end)
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index 62bb7e19f3..d543de4acd 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -4,7 +4,7 @@ local Screen = require('test.functional.ui.screen')
local assert_alive = n.assert_alive
local clear, feed = n.clear, n.feed
-local eval, eq, neq = n.eval, t.eq, t.neq
+local eval, eq, neq, ok = n.eval, t.eq, t.neq, t.ok
local feed_command, source, expect = n.feed_command, n.source, n.expect
local fn = n.fn
local command = n.command
@@ -18,19 +18,10 @@ describe('completion', function()
clear()
screen = Screen.new(60, 8)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.LightMagenta },
- [2] = { background = Screen.colors.Grey },
- [3] = { bold = true },
- [4] = { bold = true, foreground = Screen.colors.SeaGreen },
- [5] = { foreground = Screen.colors.Red },
- [6] = { background = Screen.colors.Black },
- [7] = { foreground = Screen.colors.White, background = Screen.colors.Red },
- [8] = { reverse = true },
- [9] = { bold = true, reverse = true },
- [10] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow },
- })
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow },
+ [101] = { background = Screen.colors.Gray0 },
+ }
end)
describe('v:completed_item', function()
@@ -42,15 +33,15 @@ describe('completion', function()
screen:expect([[
foo |
foo^ |
- {0:~ }|*5
- {3:-- Keyword Local completion (^N^P) The only match} |
+ {1:~ }|*5
+ {5:-- Keyword Local completion (^N^P) The only match} |
]])
feed('<C-e>')
screen:expect([[
foo |
^ |
- {0:~ }|*5
- {3:-- INSERT --} |
+ {1:~ }|*5
+ {5:-- INSERT --} |
]])
feed('<ESC>')
eq({}, eval('v:completed_item'))
@@ -104,10 +95,10 @@ describe('completion', function()
eq('foo', eval('getline(1)'))
screen:expect([[
foo^ |
- {2:bar foobaz baz }{0: }|
- {1:abbr kind menu }{0: }|
- {0:~ }|*4
- {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} |
+ {12:bar foobaz baz }{1: }|
+ {4:abbr kind menu }{1: }|
+ {1:~ }|*4
+ {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} |
]])
eq({
word = 'foo',
@@ -136,24 +127,24 @@ describe('completion', function()
screen:expect([[
foo |
^ |
- {0:~ }|*5
- {3:-- INSERT --} |
+ {1:~ }|*5
+ {5:-- INSERT --} |
]])
feed('<C-x>')
-- the ^X prompt, only test this once
screen:expect([[
foo |
^ |
- {0:~ }|*5
- {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} |
+ {1:~ }|*5
+ {5:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} |
]])
feed('<C-n>')
screen:expect([[
foo |
foo^ |
- {2:foo }{0: }|
- {0:~ }|*4
- {3:-- Keyword Local completion (^N^P) The only match} |
+ {12:foo }{1: }|
+ {1:~ }|*4
+ {5:-- Keyword Local completion (^N^P) The only match} |
]])
feed('bar<ESC>')
eq('foobar', eval('getline(2)'))
@@ -162,9 +153,9 @@ describe('completion', function()
foo |
foobar |
foo^ |
- {2:foo }{0: }|
- {0:~ }|*3
- {3:-- INSERT --} |
+ {12:foo }{1: }|
+ {1:~ }|*3
+ {5:-- INSERT --} |
]])
eq('foo', eval('getline(3)'))
end)
@@ -174,16 +165,16 @@ describe('completion', function()
screen:expect([[
foo |
^ |
- {2:foo }{0: }|
- {0:~ }|*4
- {3:-- Keyword Local completion (^N^P) The only match} |
+ {12:foo }{1: }|
+ {1:~ }|*4
+ {5:-- Keyword Local completion (^N^P) The only match} |
]])
feed('<C-y>')
screen:expect([[
foo |
foo^ |
- {0:~ }|*5
- {3:-- INSERT --} |
+ {1:~ }|*5
+ {5:-- INSERT --} |
]])
feed('<ESC>')
eq('foo', eval('getline(2)'))
@@ -191,9 +182,9 @@ describe('completion', function()
screen:expect([[
foo |*2
^ |
- {2:foo }{0: }|
- {0:~ }|*3
- {3:-- INSERT --} |
+ {12:foo }{1: }|
+ {1:~ }|*3
+ {5:-- INSERT --} |
]])
feed('<C-y><ESC>')
eq('foo', eval('getline(3)'))
@@ -204,16 +195,16 @@ describe('completion', function()
screen:expect([[
foo |
^ |
- {1:foo }{0: }|
- {0:~ }|*4
- {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ {4:foo }{1: }|
+ {1:~ }|*4
+ {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
]])
feed('b')
screen:expect([[
foo |
b^ |
- {0:~ }|*5
- {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ {1:~ }|*5
+ {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
]])
feed('ar<ESC>')
eq('bar', eval('getline(2)'))
@@ -222,9 +213,9 @@ describe('completion', function()
foo |
bar |
^ |
- {1:foo }{0: }|
- {0:~ }|*3
- {3:-- INSERT --} |
+ {4:foo }{1: }|
+ {1:~ }|*3
+ {5:-- INSERT --} |
]])
feed('bar<ESC>')
eq('bar', eval('getline(3)'))
@@ -235,15 +226,15 @@ describe('completion', function()
screen:expect([[
foo |
^ |
- {1:foo }{0: }|
- {0:~ }|*4
- {3:-- Keyword Local completion (^N^P) }{5:Back at original} |
+ {4:foo }{1: }|
+ {1:~ }|*4
+ {5:-- Keyword Local completion (^N^P) }{19:Back at original} |
]])
feed('<ESC>')
screen:expect([[
foo |
^ |
- {0:~ }|*5
+ {1:~ }|*5
|
]])
eq('', eval('getline(2)'))
@@ -252,16 +243,16 @@ describe('completion', function()
foo |
|
^ |
- {1:foo }{0: }|
- {0:~ }|*3
- {3:-- INSERT --} |
+ {4:foo }{1: }|
+ {1:~ }|*3
+ {5:-- INSERT --} |
]])
feed('<ESC>')
screen:expect([[
foo |
|
^ |
- {0:~ }|*4
+ {1:~ }|*4
|
]])
eq('', eval('getline(3)'))
@@ -336,7 +327,7 @@ describe('completion', function()
end
end)
- describe('refresh:always', function()
+ describe('with refresh:always and noselect', function()
before_each(function()
source([[
function! TestCompletion(findstart, base) abort
@@ -367,44 +358,44 @@ describe('completion', function()
feed('i<C-x><C-u>')
screen:expect([[
^ |
- {1:January }{6: }{0: }|
- {1:February }{6: }{0: }|
- {1:March }{6: }{0: }|
- {1:April }{2: }{0: }|
- {1:May }{2: }{0: }|
- {1:June }{2: }{0: }|
- {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ {4:January }{101: }{1: }|
+ {4:February }{101: }{1: }|
+ {4:March }{101: }{1: }|
+ {4:April }{12: }{1: }|
+ {4:May }{12: }{1: }|
+ {4:June }{12: }{1: }|
+ {5:-- User defined completion (^U^N^P) }{19:Back at original} |
]])
feed('u')
screen:expect([[
u^ |
- {1:January }{0: }|
- {1:February }{0: }|
- {1:June }{0: }|
- {1:July }{0: }|
- {1:August }{0: }|
- {0:~ }|
- {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ {4:January }{1: }|
+ {4:February }{1: }|
+ {4:June }{1: }|
+ {4:July }{1: }|
+ {4:August }{1: }|
+ {1:~ }|
+ {5:-- User defined completion (^U^N^P) }{19:Back at original} |
]])
feed('g')
screen:expect([[
ug^ |
- {1:August }{0: }|
- {0:~ }|*5
- {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ {4:August }{1: }|
+ {1:~ }|*5
+ {5:-- User defined completion (^U^N^P) }{19:Back at original} |
]])
feed('<Down>')
screen:expect([[
ug^ |
- {2:August }{0: }|
- {0:~ }|*5
- {3:-- User defined completion (^U^N^P) The only match} |
+ {12:August }{1: }|
+ {1:~ }|*5
+ {5:-- User defined completion (^U^N^P) The only match} |
]])
feed('<C-y>')
screen:expect([[
August^ |
- {0:~ }|*6
- {3:-- INSERT --} |
+ {1:~ }|*6
+ {5:-- INSERT --} |
]])
expect('August')
end)
@@ -414,45 +405,45 @@ describe('completion', function()
screen:expect([[
|
Ja^ |
- {1:January }{0: }|
- {0:~ }|*4
- {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ {4:January }{1: }|
+ {1:~ }|*4
+ {5:-- User defined completion (^U^N^P) }{19:Back at original} |
]])
feed('<BS>')
screen:expect([[
|
J^ |
- {1:January }{0: }|
- {1:June }{0: }|
- {1:July }{0: }|
- {0:~ }|*2
- {3:-- User defined completion (^U^N^P) }{5:Back at original} |
+ {4:January }{1: }|
+ {4:June }{1: }|
+ {4:July }{1: }|
+ {1:~ }|*2
+ {5:-- User defined completion (^U^N^P) }{19:Back at original} |
]])
feed('<C-n>')
screen:expect([[
|
January^ |
- {2:January }{0: }|
- {1:June }{0: }|
- {1:July }{0: }|
- {0:~ }|*2
- {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} |
+ {12:January }{1: }|
+ {4:June }{1: }|
+ {4:July }{1: }|
+ {1:~ }|*2
+ {5:-- User defined completion (^U^N^P) }{6:match 1 of 3} |
]])
feed('<C-n>')
screen:expect([[
|
June^ |
- {1:January }{0: }|
- {2:June }{0: }|
- {1:July }{0: }|
- {0:~ }|*2
- {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} |
+ {4:January }{1: }|
+ {12:June }{1: }|
+ {4:July }{1: }|
+ {1:~ }|*2
+ {5:-- User defined completion (^U^N^P) }{6:match 2 of 3} |
]])
feed('<Esc>')
screen:expect([[
|
Jun^e |
- {0:~ }|*5
+ {1:~ }|*5
|
]])
feed('.')
@@ -460,7 +451,7 @@ describe('completion', function()
|
June |
Jun^e |
- {0:~ }|*4
+ {1:~ }|*4
|
]])
expect([[
@@ -468,6 +459,67 @@ describe('completion', function()
June
June]])
end)
+
+ it('Enter does not select original text', function()
+ feed('iJ<C-x><C-u>')
+ poke_eventloop()
+ feed('u')
+ poke_eventloop()
+ feed('<CR>')
+ expect([[
+ Ju
+ ]])
+ feed('J<C-x><C-u>')
+ poke_eventloop()
+ feed('<CR>')
+ expect([[
+ Ju
+ J
+ ]])
+ end)
+ end)
+
+ describe('with noselect but not refresh:always', function()
+ before_each(function()
+ source([[
+ function! TestCompletion(findstart, base) abort
+ if a:findstart
+ let line = getline('.')
+ let start = col('.') - 1
+ while start > 0 && line[start - 1] =~ '\a'
+ let start -= 1
+ endwhile
+ return start
+ else
+ let ret = []
+ for m in split("January February March April May June July August September October November December")
+ if m =~ a:base " match by regex
+ call add(ret, m)
+ endif
+ endfor
+ return {'words':ret}
+ endif
+ endfunction
+
+ set completeopt=menuone,noselect
+ set completefunc=TestCompletion
+ ]])
+ end)
+
+ it('Enter selects original text after adding leader', function()
+ feed('iJ<C-x><C-u>')
+ poke_eventloop()
+ feed('u')
+ poke_eventloop()
+ feed('<CR>')
+ expect('Ju')
+ feed('<Esc>')
+ poke_eventloop()
+ -- The behavior should be the same when completion has been interrupted,
+ -- which can happen interactively if the completion function is slow.
+ feed('SJ<C-x><C-u>u<CR>')
+ expect('Ju')
+ end)
end)
describe('with a lot of items', function()
@@ -485,46 +537,46 @@ describe('completion', function()
feed('i<C-r>=TestComplete()<CR>')
screen:expect([[
^ |
- {1:0 }{6: }{0: }|
- {1:1 }{2: }{0: }|
- {1:2 }{2: }{0: }|
- {1:3 }{2: }{0: }|
- {1:4 }{2: }{0: }|
- {1:5 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:0 }{101: }{1: }|
+ {4:1 }{12: }{1: }|
+ {4:2 }{12: }{1: }|
+ {4:3 }{12: }{1: }|
+ {4:4 }{12: }{1: }|
+ {4:5 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('7')
screen:expect([[
7^ |
- {1:7 }{6: }{0: }|
- {1:70 }{6: }{0: }|
- {1:71 }{6: }{0: }|
- {1:72 }{2: }{0: }|
- {1:73 }{2: }{0: }|
- {1:74 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:7 }{101: }{1: }|
+ {4:70 }{101: }{1: }|
+ {4:71 }{101: }{1: }|
+ {4:72 }{12: }{1: }|
+ {4:73 }{12: }{1: }|
+ {4:74 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<c-n>')
screen:expect([[
7^ |
- {2:7 }{6: }{0: }|
- {1:70 }{6: }{0: }|
- {1:71 }{6: }{0: }|
- {1:72 }{2: }{0: }|
- {1:73 }{2: }{0: }|
- {1:74 }{2: }{0: }|
- {3:-- INSERT --} |
+ {12:7 }{101: }{1: }|
+ {4:70 }{101: }{1: }|
+ {4:71 }{101: }{1: }|
+ {4:72 }{12: }{1: }|
+ {4:73 }{12: }{1: }|
+ {4:74 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<c-n>')
screen:expect([[
70^ |
- {1:7 }{6: }{0: }|
- {2:70 }{6: }{0: }|
- {1:71 }{6: }{0: }|
- {1:72 }{2: }{0: }|
- {1:73 }{2: }{0: }|
- {1:74 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:7 }{101: }{1: }|
+ {12:70 }{101: }{1: }|
+ {4:71 }{101: }{1: }|
+ {4:72 }{12: }{1: }|
+ {4:73 }{12: }{1: }|
+ {4:74 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
end)
@@ -532,107 +584,107 @@ describe('completion', function()
feed('i<C-r>=TestComplete()<CR>')
screen:expect([[
^ |
- {1:0 }{6: }{0: }|
- {1:1 }{2: }{0: }|
- {1:2 }{2: }{0: }|
- {1:3 }{2: }{0: }|
- {1:4 }{2: }{0: }|
- {1:5 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:0 }{101: }{1: }|
+ {4:1 }{12: }{1: }|
+ {4:2 }{12: }{1: }|
+ {4:3 }{12: }{1: }|
+ {4:4 }{12: }{1: }|
+ {4:5 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageDown>')
screen:expect([[
^ |
- {1:0 }{6: }{0: }|
- {1:1 }{2: }{0: }|
- {1:2 }{2: }{0: }|
- {2:3 }{0: }|
- {1:4 }{2: }{0: }|
- {1:5 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:0 }{101: }{1: }|
+ {4:1 }{12: }{1: }|
+ {4:2 }{12: }{1: }|
+ {12:3 }{1: }|
+ {4:4 }{12: }{1: }|
+ {4:5 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageDown>')
screen:expect([[
^ |
- {1:5 }{6: }{0: }|
- {1:6 }{2: }{0: }|
- {2:7 }{0: }|
- {1:8 }{2: }{0: }|
- {1:9 }{2: }{0: }|
- {1:10 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:5 }{101: }{1: }|
+ {4:6 }{12: }{1: }|
+ {12:7 }{1: }|
+ {4:8 }{12: }{1: }|
+ {4:9 }{12: }{1: }|
+ {4:10 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<Down>')
screen:expect([[
^ |
- {1:5 }{6: }{0: }|
- {1:6 }{2: }{0: }|
- {1:7 }{2: }{0: }|
- {2:8 }{0: }|
- {1:9 }{2: }{0: }|
- {1:10 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:5 }{101: }{1: }|
+ {4:6 }{12: }{1: }|
+ {4:7 }{12: }{1: }|
+ {12:8 }{1: }|
+ {4:9 }{12: }{1: }|
+ {4:10 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageUp>')
screen:expect([[
^ |
- {1:2 }{6: }{0: }|
- {1:3 }{2: }{0: }|
- {2:4 }{0: }|
- {1:5 }{2: }{0: }|
- {1:6 }{2: }{0: }|
- {1:7 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:2 }{101: }{1: }|
+ {4:3 }{12: }{1: }|
+ {12:4 }{1: }|
+ {4:5 }{12: }{1: }|
+ {4:6 }{12: }{1: }|
+ {4:7 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageUp>') -- stop on first item
screen:expect([[
^ |
- {2:0 }{6: }{0: }|
- {1:1 }{2: }{0: }|
- {1:2 }{2: }{0: }|
- {1:3 }{2: }{0: }|
- {1:4 }{2: }{0: }|
- {1:5 }{2: }{0: }|
- {3:-- INSERT --} |
+ {12:0 }{101: }{1: }|
+ {4:1 }{12: }{1: }|
+ {4:2 }{12: }{1: }|
+ {4:3 }{12: }{1: }|
+ {4:4 }{12: }{1: }|
+ {4:5 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageUp>') -- when on first item, unselect
screen:expect([[
^ |
- {1:0 }{6: }{0: }|
- {1:1 }{2: }{0: }|
- {1:2 }{2: }{0: }|
- {1:3 }{2: }{0: }|
- {1:4 }{2: }{0: }|
- {1:5 }{2: }{0: }|
- {3:-- INSERT --} |
+ {4:0 }{101: }{1: }|
+ {4:1 }{12: }{1: }|
+ {4:2 }{12: }{1: }|
+ {4:3 }{12: }{1: }|
+ {4:4 }{12: }{1: }|
+ {4:5 }{12: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageUp>') -- when unselected, select last item
screen:expect([[
^ |
- {1:95 }{2: }{0: }|
- {1:96 }{2: }{0: }|
- {1:97 }{2: }{0: }|
- {1:98 }{2: }{0: }|
- {1:99 }{2: }{0: }|
- {2:100 }{6: }{0: }|
- {3:-- INSERT --} |
+ {4:95 }{12: }{1: }|
+ {4:96 }{12: }{1: }|
+ {4:97 }{12: }{1: }|
+ {4:98 }{12: }{1: }|
+ {4:99 }{12: }{1: }|
+ {12:100 }{101: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<PageUp>')
screen:expect([[
^ |
- {1:94 }{2: }{0: }|
- {1:95 }{2: }{0: }|
- {2:96 }{0: }|
- {1:97 }{2: }{0: }|
- {1:98 }{2: }{0: }|
- {1:99 }{6: }{0: }|
- {3:-- INSERT --} |
+ {4:94 }{12: }{1: }|
+ {4:95 }{12: }{1: }|
+ {12:96 }{1: }|
+ {4:97 }{12: }{1: }|
+ {4:98 }{12: }{1: }|
+ {4:99 }{101: }{1: }|
+ {5:-- INSERT --} |
]])
feed('<cr>')
screen:expect([[
96^ |
- {0:~ }|*6
- {3:-- INSERT --} |
+ {1:~ }|*6
+ {5:-- INSERT --} |
]])
end)
end)
@@ -668,9 +720,9 @@ describe('completion', function()
screen:expect([[
inc uninc indent unindent |
ind^ |
- {2:indent }{0: }|
- {0:~ }|*4
- {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
+ {12:indent }{1: }|
+ {1:~ }|*4
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
]])
-- Indents when the item is selected
@@ -678,8 +730,8 @@ describe('completion', function()
screen:expect([[
inc uninc indent unindent |
indent^ |
- {0:~ }|*5
- {3:-- INSERT --} |
+ {1:~ }|*5
+ {5:-- INSERT --} |
]])
-- Indents when completion is exited using ESC.
feed('<CR>in<C-N><BS>d<Esc>')
@@ -687,7 +739,7 @@ describe('completion', function()
inc uninc indent unindent |
indent |
in^d |
- {0:~ }|*4
+ {1:~ }|*4
|
]])
-- Works for unindenting too.
@@ -699,9 +751,9 @@ describe('completion', function()
indent |
ind |
unind^ |
- {0:~ }{2: unindent }{0: }|
- {0:~ }|*2
- {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
+ {1:~ }{12: unindent }{1: }|
+ {1:~ }|*2
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
]])
-- Works when going back and forth.
feed('<BS>c')
@@ -710,9 +762,9 @@ describe('completion', function()
indent |
ind |
uninc^ |
- {0:~ }{2: uninc }{0: }|
- {0:~ }|*2
- {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
+ {1:~ }{12: uninc }{1: }|
+ {1:~ }|*2
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
]])
feed('<BS>d')
screen:expect([[
@@ -720,9 +772,9 @@ describe('completion', function()
indent |
ind |
unind^ |
- {0:~ }{2: unindent }{0: }|
- {0:~ }|*2
- {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} |
+ {1:~ }{12: unindent }{1: }|
+ {1:~ }|*2
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} |
]])
feed('<C-N><C-N><C-Y><Esc>')
screen:expect([[
@@ -730,7 +782,7 @@ describe('completion', function()
indent |
ind |
uninden^t |
- {0:~ }|*3
+ {1:~ }|*3
|
]])
end)
@@ -741,15 +793,15 @@ describe('completion', function()
screen:expect([[
^foo |
bar |
- {0:~ }|*5
+ {1:~ }|*5
|
]])
feed('A<C-x><C-l>')
screen:expect([[
foo^ |
bar |
- {0:~ }|*5
- {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} |
+ {1:~ }|*5
+ {5:-- Whole line completion (^L^N^P) }{9:Pattern not found} |
]])
eq(-1, eval('foldclosed(1)'))
end)
@@ -761,10 +813,10 @@ describe('completion', function()
screen:expect([[
foobar fooegg |
fooegg^ |
- {1:foobar }{0: }|
- {2:fooegg }{0: }|
- {0:~ }|*3
- {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ {4:foobar }{1: }|
+ {12:fooegg }{1: }|
+ {1:~ }|*3
+ {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
]])
assert_alive()
@@ -773,10 +825,10 @@ describe('completion', function()
grid = [[
foobar fooegg |
fooegg^ |
- {1:foobar }{0: }|
- {2:fooegg }{0: }|
- {0:~ }|*3
- {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ {4:foobar }{1: }|
+ {12:fooegg }{1: }|
+ {1:~ }|*3
+ {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
]],
unchanged = true,
}
@@ -786,10 +838,10 @@ describe('completion', function()
screen:expect([[
foobar fooegg |
foobar^ |
- {2:foobar }{0: }|
- {1:fooegg }{0: }|
- {0:~ }|*3
- {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ {12:foobar }{1: }|
+ {4:fooegg }{1: }|
+ {1:~ }|*3
+ {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
]])
end)
@@ -800,7 +852,7 @@ describe('completion', function()
screen:expect {
grid = [[
|
- {0:~ }|*6
+ {1:~ }|*6
:lua CURRENT_TESTING_VAR^ |
]],
}
@@ -813,19 +865,73 @@ describe('completion', function()
screen:expect {
grid = [[
|
- {0:~ }|*5
- {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }|
+ {1:~ }|*5
+ {100:CURRENT_TESTING_BAR}{3: CURRENT_TESTING_FOO }|
:lua CURRENT_TESTING_BAR^ |
]],
unchanged = true,
}
end)
+ it('prefix is not included in completion for cmdline mode', function()
+ feed(':lua math.a<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {100:abs}{3: acos asin atan atan2 }|
+ :lua math.abs^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {3:abs }{100:acos}{3: asin atan atan2 }|
+ :lua math.acos^ |
+ ]])
+ end)
+
+ it('prefix is not included in completion for i_CTRL-X_CTRL-V #19623', function()
+ feed('ilua math.a<C-X><C-V>')
+ screen:expect([[
+ lua math.abs^ |
+ {1:~ }{12: abs }{1: }|
+ {1:~ }{4: acos }{1: }|
+ {1:~ }{4: asin }{1: }|
+ {1:~ }{4: atan }{1: }|
+ {1:~ }{4: atan2 }{1: }|
+ {1:~ }|
+ {5:-- Command-line completion (^V^N^P) }{6:match 1 of 5} |
+ ]])
+ feed('<C-V>')
+ screen:expect([[
+ lua math.acos^ |
+ {1:~ }{4: abs }{1: }|
+ {1:~ }{12: acos }{1: }|
+ {1:~ }{4: asin }{1: }|
+ {1:~ }{4: atan }{1: }|
+ {1:~ }{4: atan2 }{1: }|
+ {1:~ }|
+ {5:-- Command-line completion (^V^N^P) }{6:match 2 of 5} |
+ ]])
+ end)
+
+ it('works when cursor is in the middle of cmdline #29586', function()
+ feed(':lua math.a(); 1<Left><Left><Left><Left><Left><Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {100:abs}{3: acos asin atan atan2 }|
+ :lua math.abs^(); 1 |
+ ]])
+ end)
+
it('provides completion from `getcompletion()`', function()
eq({ 'vim' }, fn.getcompletion('vi', 'lua'))
eq({ 'api' }, fn.getcompletion('vim.ap', 'lua'))
eq({ 'tbl_filter' }, fn.getcompletion('vim.tbl_fil', 'lua'))
eq({ 'vim' }, fn.getcompletion('print(vi', 'lua'))
+ eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('math.a', 'lua'))
+ eq({ 'abs', 'acos', 'asin', 'atan', 'atan2' }, fn.getcompletion('lua math.a', 'cmdline'))
-- fuzzy completion is not supported, so the result should be the same
command('set wildoptions+=fuzzy')
eq({ 'vim' }, fn.getcompletion('vi', 'lua'))
@@ -841,36 +947,42 @@ describe('completion', function()
eq('SpecialKey', fn.getcompletion('set winhighlight=NonText:', 'cmdline')[1])
end)
+ it('cmdline completion for -complete does not contain spaces', function()
+ for _, str in ipairs(fn.getcompletion('command -complete=', 'cmdline')) do
+ ok(not str:find(' '), 'string without spaces', str)
+ end
+ end)
+
describe('from the commandline window', function()
it('is cleared after CTRL-C', function()
feed('q:')
feed('ifoo faa fee f')
screen:expect([[
|
- {8:[No Name] }|
- {0::}foo faa fee f^ |
- {0:~ }|*3
- {9:[Command Line] }|
- {3:-- INSERT --} |
+ {2:[No Name] }|
+ {1::}foo faa fee f^ |
+ {1:~ }|*3
+ {3:[Command Line] }|
+ {5:-- INSERT --} |
]])
feed('<c-x><c-n>')
screen:expect([[
|
- {8:[No Name] }|
- {0::}foo faa fee foo^ |
- {0:~ }{2: foo }{0: }|
- {0:~ }{1: faa }{0: }|
- {0:~ }{1: fee }{0: }|
- {9:[Command Line] }|
- {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} |
+ {2:[No Name] }|
+ {1::}foo faa fee foo^ |
+ {1:~ }{12: foo }{1: }|
+ {1:~ }{4: faa }{1: }|
+ {1:~ }{4: fee }{1: }|
+ {3:[Command Line] }|
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} |
]])
feed('<c-c>')
screen:expect([[
|
- {8:[No Name] }|
- {0::}foo faa fee foo |
- {0:~ }|*3
- {9:[Command Line] }|
+ {2:[No Name] }|
+ {1::}foo faa fee foo |
+ {1:~ }|*3
+ {3:[Command Line] }|
:foo faa fee foo^ |
]])
end)
@@ -903,9 +1015,9 @@ describe('completion', function()
feed('i<C-r>=TestComplete()<CR>')
screen:expect([[
^ |
- {1:1 3 2 }{0: }|
- {0:~ }|*5
- {3:-- INSERT --} |
+ {4:1 3 2 }{1: }|
+ {1:~ }|*5
+ {5:-- INSERT --} |
]])
end)
end)
@@ -918,12 +1030,12 @@ describe('completion', function()
grid = [[
*backers.txt* Nvim |
Xnull^ |
- {2:Xnull }{6: } |
- {1:Xoxomoon }{6: } |
- {1:Xu }{6: } NVIM REFERENCE MANUAL |
- {1:Xpayn }{2: } |
- {1:Xinity }{2: } |
- {3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} |
+ {12:Xnull }{101: } |
+ {4:Xoxomoon }{101: } |
+ {4:Xu }{101: } NVIM REFERENCE MANUAL |
+ {4:Xpayn }{12: } |
+ {4:Xinity }{12: } |
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 7} |
]],
}
end)
@@ -950,8 +1062,8 @@ describe('completion', function()
bar |
foobar |
f^ |
- {0:~ }|*3
- {3:-- Keyword completion (^N^P) }{5:Back at original} |
+ {1:~ }|*3
+ {5:-- Keyword completion (^N^P) }{19:Back at original} |
]],
popupmenu = {
anchor = { 1, 3, 0 },
@@ -970,8 +1082,8 @@ describe('completion', function()
bar |
foobar |
foob^ |
- {0:~ }|*3
- {3:-- Keyword completion (^N^P) }{5:Back at original} |
+ {1:~ }|*3
+ {5:-- Keyword completion (^N^P) }{19:Back at original} |
]],
popupmenu = {
anchor = { 1, 3, 0 },
@@ -992,10 +1104,10 @@ describe('completion', function()
bar |
foobar |
f^ |
- {1:foo }{0: }|
- {1:foobar }{0: }|
- {0:~ }|
- {3:-- Keyword completion (^N^P) }{5:Back at original} |
+ {4:foo }{1: }|
+ {4:foobar }{1: }|
+ {1:~ }|
+ {5:-- Keyword completion (^N^P) }{19:Back at original} |
]])
eq(
{ completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false },
@@ -1007,10 +1119,10 @@ describe('completion', function()
bar |
foobar |
foo^ |
- {2:foo }{0: }|
- {1:foobar }{0: }|
- {0:~ }|
- {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ {12:foo }{1: }|
+ {4:foobar }{1: }|
+ {1:~ }|
+ {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
]])
eq('foo', eval('g:word'))
feed('<C-N>')
@@ -1019,10 +1131,10 @@ describe('completion', function()
bar |
foobar |
foobar^ |
- {1:foo }{0: }|
- {2:foobar }{0: }|
- {0:~ }|
- {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ {4:foo }{1: }|
+ {12:foobar }{1: }|
+ {1:~ }|
+ {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
]])
eq('foobar', eval('g:word'))
feed('<up>')
@@ -1031,10 +1143,10 @@ describe('completion', function()
bar |
foobar |
foobar^ |
- {2:foo }{0: }|
- {1:foobar }{0: }|
- {0:~ }|
- {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ {12:foo }{1: }|
+ {4:foobar }{1: }|
+ {1:~ }|
+ {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
]])
eq('foo', eval('g:word'))
feed('<down>')
@@ -1043,10 +1155,10 @@ describe('completion', function()
bar |
foobar |
foobar^ |
- {1:foo }{0: }|
- {2:foobar }{0: }|
- {0:~ }|
- {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ {4:foo }{1: }|
+ {12:foobar }{1: }|
+ {1:~ }|
+ {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
]])
eq('foobar', eval('g:word'))
feed('<esc>')
@@ -1061,11 +1173,11 @@ describe('completion', function()
hullo |
heeee |
hello^ |
- {2:hello }{0: }|
- {1:hullo }{0: }|
- {1:heeee }{0: }|
- {0:~ }|*6
- {3:-- }{4:match 1 of 3} |
+ {12:hello }{1: }|
+ {4:hullo }{1: }|
+ {4:heeee }{1: }|
+ {1:~ }|*6
+ {5:-- }{6:match 1 of 3} |
]])
command([[call timer_start(100, { -> execute('stopinsert') })]])
vim.uv.sleep(200)
@@ -1075,7 +1187,7 @@ describe('completion', function()
hullo |
heee^e |
hello |
- {0:~ }|*9
+ {1:~ }|*9
|
]])
end)
@@ -1090,9 +1202,9 @@ describe('completion', function()
screen:expect([[
ii |
ii^ |
- {2:ii }{0: }|
- {0:~ }|*4
- {3:-- Keyword completion (^N^P) The only match} |
+ {12:ii }{1: }|
+ {1:~ }|*4
+ {5:-- Keyword completion (^N^P) The only match} |
]])
assert_alive()
end)
@@ -1129,22 +1241,22 @@ describe('completion', function()
screen:expect {
grid = [[
foo^ |
- {2:foo }{0: }|
- {1:bar }{0: }|
- {1:foa }{0: }|
- {1:.hidden }{0: }|
- {0:~ }|*3
- {3:-- }{4:match 1 of 4} |
+ {12:foo }{1: }|
+ {4:bar }{1: }|
+ {4:foa }{1: }|
+ {4:.hidden }{1: }|
+ {1:~ }|*3
+ {5:-- }{6:match 1 of 4} |
]],
}
feed('<Esc>ccf<C-n>')
screen:expect {
grid = [[
foo^ |
- {2:foo }{0: }|
- {1:foa }{0: }|
- {0:~ }|*5
- {3:-- }{4:match 1 of 2} |
+ {12:foo }{1: }|
+ {4:foa }{1: }|
+ {1:~ }|*5
+ {5:-- }{6:match 1 of 2} |
]],
}
end)
@@ -1168,10 +1280,10 @@ describe('completion', function()
eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
feed('<Esc>0Yppia<Esc>ggI<C-N>')
screen:expect([[
- aaaa{7:^aa}aa |
- {2:aaaa } |
- {1:aaaaa } |
- {3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
+ aaaa{9:^aa}aa |
+ {12:aaaa } |
+ {4:aaaaa } |
+ {5:-- Keyword completion (^N^P) }{6:match 1 of 2} |
]])
feed('<C-N><C-N><Esc>')
eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
@@ -1180,16 +1292,16 @@ describe('completion', function()
feed('<C-N>')
screen:expect([[
aaaaa^ |
- {1:aaaa } |
- {2:aaaaa } |
- {3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
+ {4:aaaa } |
+ {12:aaaaa } |
+ {5:-- Keyword completion (^N^P) }{6:match 2 of 2} |
]])
feed('<C-E>')
screen:expect([[
- {7:aa}aa^ |
+ {9:aa}aa^ |
aaaa |
aaaaa |
- {3:-- INSERT --} |
+ {5:-- INSERT --} |
]])
end)
end)
diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua
new file mode 100644
index 0000000000..47fd177f7b
--- /dev/null
+++ b/test/functional/editor/defaults_spec.lua
@@ -0,0 +1,100 @@
+--
+-- Tests for default autocmds, mappings, commands, and menus.
+--
+-- See options/defaults_spec.lua for default options and environment decisions.
+--
+
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+
+describe('default', function()
+ describe('autocommands', function()
+ it('nvim_terminal.TermClose closes terminal with default shell on success', function()
+ n.clear()
+ n.api.nvim_set_option_value('shell', n.testprg('shell-test'), {})
+ n.command('set shellcmdflag=EXIT shellredir= shellpipe= shellquote= shellxquote=')
+
+ -- Should not block other events
+ n.command('let g:n=0')
+ n.command('au BufEnter * let g:n = g:n + 1')
+
+ n.command('terminal')
+ t.eq(1, n.eval('get(g:, "n", 0)'))
+
+ t.retry(nil, 1000, function()
+ t.neq('terminal', n.api.nvim_get_option_value('buftype', { buf = 0 }))
+ t.eq(2, n.eval('get(g:, "n", 0)'))
+ end)
+ end)
+ end)
+
+ describe('popupmenu', function()
+ it('can be disabled by user', function()
+ n.clear {
+ args = { '+autocmd! nvim_popupmenu', '+aunmenu PopUp' },
+ }
+ local screen = Screen.new(40, 8)
+ screen:attach()
+ n.insert([[
+ 1 line 1
+ 2 https://example.com
+ 3 line 3
+ 4 line 4]])
+
+ n.api.nvim_input_mouse('right', 'press', '', 0, 1, 4)
+ screen:expect({
+ grid = [[
+ 1 line 1 |
+ 2 ht^tps://example.com |
+ 3 line 3 |
+ 4 line 4 |
+ {1:~ }|*3
+ |
+ ]],
+ })
+ end)
+
+ it('right-click on URL shows "Open in web browser"', function()
+ n.clear()
+ local screen = Screen.new(40, 8)
+ screen:attach()
+ n.insert([[
+ 1 line 1
+ 2 https://example.com
+ 3 line 3
+ 4 line 4]])
+
+ n.api.nvim_input_mouse('right', 'press', '', 0, 3, 4)
+ screen:expect({
+ grid = [[
+ 1 line 1 |
+ 2 https://example.com |
+ 3 line 3 |
+ 4 li^ne 4 |
+ {1:~ }{4: Inspect }{1: }|
+ {1:~ }{4: }{1: }|
+ {1:~ }{4: Paste }{1: }|
+ {4: Select All } |
+ ]],
+ })
+
+ n.api.nvim_input_mouse('right', 'press', '', 0, 1, 4)
+ screen:expect({
+ grid = [[
+ 1 line 1 |
+ 2 ht^tps://example.com |
+ 3 l{4: Open in web browser } |
+ 4 l{4: Inspect } |
+ {1:~ }{4: }{1: }|
+ {1:~ }{4: Paste }{1: }|
+ {1:~ }{4: Select All }{1: }|
+ {4: } |
+ ]],
+ })
+ end)
+ end)
+
+ -- describe('key mappings', function()
+ -- end)
+end)
diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua
index 880831d9f8..ab4cefaf84 100644
--- a/test/functional/editor/jump_spec.lua
+++ b/test/functional/editor/jump_spec.lua
@@ -194,7 +194,7 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
end)
end)
-describe('buffer deletion', function()
+describe('buffer deletion with jumpoptions+=clean', function()
local base_file = 'Xtest-functional-buffer-deletion'
local file1 = base_file .. '1'
local file2 = base_file .. '2'
@@ -227,6 +227,12 @@ describe('buffer deletion', function()
command('edit ' .. file3)
end)
+ after_each(function()
+ os.remove(file1)
+ os.remove(file2)
+ os.remove(file3)
+ end)
+
it('deletes jump list entries when the current buffer is deleted', function()
command('edit ' .. file1)
@@ -319,6 +325,44 @@ describe('buffer deletion', function()
end)
end)
+describe('buffer deletion with jumpoptions-=clean', function()
+ local base_file = 'Xtest-functional-buffer-deletion'
+ local file1 = base_file .. '1'
+ local file2 = base_file .. '2'
+ local base_content = 'text'
+ local content1 = base_content .. '1'
+ local content2 = base_content .. '2'
+
+ before_each(function()
+ clear()
+ command('clearjumps')
+ command('set jumpoptions-=clean')
+
+ write_file(file1, content1, false, false)
+ write_file(file2, content2, false, false)
+
+ command('edit ' .. file1)
+ command('edit ' .. file2)
+ end)
+
+ after_each(function()
+ os.remove(file1)
+ os.remove(file2)
+ end)
+
+ it('Ctrl-O reopens previous buffer with :bunload or :bdelete #28968', function()
+ eq(file2, fn.bufname(''))
+ command('bunload')
+ eq(file1, fn.bufname(''))
+ feed('<C-O>')
+ eq(file2, fn.bufname(''))
+ command('bdelete')
+ eq(file1, fn.bufname(''))
+ feed('<C-O>')
+ eq(file2, fn.bufname(''))
+ end)
+end)
+
describe('jumpoptions=view', function()
local file1 = 'Xtestfile-functional-editor-jumps'
local file2 = 'Xtestfile-functional-editor-jumps-2'
diff --git a/test/functional/editor/macro_spec.lua b/test/functional/editor/macro_spec.lua
index 27c5eddac8..680a70b78a 100644
--- a/test/functional/editor/macro_spec.lua
+++ b/test/functional/editor/macro_spec.lua
@@ -148,6 +148,23 @@ helloFOO]]
eq({ 0, 1, 1, 0 }, fn.getpos('v'))
end)
+ it('can be recorded and replayed in Visual mode when ignorecase', function()
+ command('set ignorecase')
+ insert('foo BAR BAR foo BAR foo BAR BAR BAR foo BAR BAR')
+ feed('0vqifofRq')
+ eq({ 0, 1, 7, 0 }, fn.getpos('.'))
+ eq({ 0, 1, 1, 0 }, fn.getpos('v'))
+ feed('Q')
+ eq({ 0, 1, 19, 0 }, fn.getpos('.'))
+ eq({ 0, 1, 1, 0 }, fn.getpos('v'))
+ feed('Q')
+ eq({ 0, 1, 27, 0 }, fn.getpos('.'))
+ eq({ 0, 1, 1, 0 }, fn.getpos('v'))
+ feed('@i')
+ eq({ 0, 1, 43, 0 }, fn.getpos('.'))
+ eq({ 0, 1, 1, 0 }, fn.getpos('v'))
+ end)
+
it('can be replayed with @ in blockwise Visual mode', function()
insert [[
hello
diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua
index 87fe395608..30027e2fd6 100644
--- a/test/functional/editor/meta_key_spec.lua
+++ b/test/functional/editor/meta_key_spec.lua
@@ -145,7 +145,8 @@ describe('meta-keys #8226 #13042', function()
end)
it('ALT/META with vim.on_key()', function()
- feed('ifoo<CR>bar<CR>baz<Esc>gg0')
+ feed('ifoo<CR>bar<CR>baz<Esc>gg0viw"ay')
+ command('nnoremap … "')
exec_lua [[
keys = {}
@@ -157,15 +158,15 @@ describe('meta-keys #8226 #13042', function()
end)
]]
- -- <M-"> is reinterpreted as <Esc>"
- feed('qrviw"ayc$FOO.<M-">apq')
+ -- <M-"> and <M-…> are reinterpreted as <Esc>" and <Esc>…
+ feed('c$FOO.<M-">apA.<M-…>ap')
expect([[
- FOO.foo
+ FOO.foo.foo
bar
baz]])
- -- vim.on_key() callback should only receive <Esc>"
- eq('qrviw"ayc$FOO.<Esc>"apq', exec_lua [[return table.concat(keys, '')]])
- eq('qrviw"ayc$FOO.<Esc>"apq', exec_lua [[return table.concat(typed, '')]])
+ -- vim.on_key() callback should only receive <Esc>" and <Esc>…
+ eq('c$FOO.<Esc>"apA.<Esc>"ap', exec_lua [[return table.concat(keys, '')]])
+ eq('c$FOO.<Esc>"apA.<Esc>…ap', exec_lua [[return table.concat(typed, '')]])
end)
end)
diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua
index 70bdc5d4c2..efd7a37c0b 100644
--- a/test/functional/editor/mode_cmdline_spec.lua
+++ b/test/functional/editor/mode_cmdline_spec.lua
@@ -48,18 +48,14 @@ describe('cmdline', function()
it('redraws statusline when toggling overstrike', function()
local screen = Screen.new(60, 4)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { reverse = true, bold = true }, -- StatusLine
- })
screen:attach()
command('set laststatus=2 statusline=%!mode(1)')
feed(':')
screen:expect {
grid = [[
|
- {0:~ }|
- {1:c }|
+ {1:~ }|
+ {3:c }|
:^ |
]],
}
@@ -67,8 +63,8 @@ describe('cmdline', function()
screen:expect {
grid = [[
|
- {0:~ }|
- {1:cr }|
+ {1:~ }|
+ {3:cr }|
:^ |
]],
}
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index fb3dda4bf4..87d5c46134 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -180,12 +180,6 @@ describe('insert-mode', function()
it('multi-char mapping updates screen properly #25626', function()
local screen = Screen.new(60, 6)
- 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 }, -- ModeMsg
- })
screen:attach()
command('vnew')
insert('foo\nfoo\nfoo')
@@ -197,10 +191,10 @@ describe('insert-mode', function()
grid = [[
foo │ |
foo │β^jβ |
- foo │{0:~ }|
- {0:~ }│{0:~ }|
- {2:[No Name] [+] }{1:[No Name] [+] }|
- {3:-- INSERT --} |
+ foo │{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ {5:-- INSERT --} |
]],
}
feed('k')
@@ -208,9 +202,9 @@ describe('insert-mode', function()
grid = [[
foo │ |
foo │^βββ |
- foo │{0:~ }|
- {0:~ }│{0:~ }|
- {2:[No Name] [+] }{1:[No Name] [+] }|
+ foo │{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] [+] }{3:[No Name] [+] }|
|
]],
}
@@ -357,4 +351,97 @@ describe('insert-mode', function()
eq(2, api.nvim_win_get_cursor(0)[1])
end)
end)
+
+ it('backspace after replacing multibyte chars', function()
+ local screen = Screen.new(30, 3)
+ screen:attach()
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̝̅̚m̆̉̐̐̇̈ å' })
+ feed('^Rabcdefghi')
+ screen:expect([[
+ abcdefghi^ |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcdefgh^å |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcdefg^ å |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcdef^m̆̉̐̐̇̈ å |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcde^ȧ̟̜̝̅̚m̆̉̐̐̇̈ å |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcd^ ȧ̟̜̝̅̚m̆̉̐̐̇̈ å |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<esc>')
+
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'wow 🧑‍🌾🏳️‍⚧️x' })
+ feed('^Rabcd')
+
+ screen:expect([[
+ abcd^🧑‍🌾🏳️‍⚧️x |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('e')
+ screen:expect([[
+ abcde^🏳️‍⚧️x |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('f')
+ screen:expect([[
+ abcdef^x |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcde^🏳️‍⚧️x |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abcd^🧑‍🌾🏳️‍⚧️x |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+
+ feed('<bs>')
+ screen:expect([[
+ abc^ 🧑‍🌾🏳️‍⚧️x |
+ {1:~ }|
+ {5:-- REPLACE --} |
+ ]])
+ end)
end)
diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index 0b26494436..c20a6e5cb5 100644
--- a/test/functional/editor/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
@@ -102,14 +102,9 @@ describe('tabpage', function()
it('switching tabpage after setting laststatus=3 #19591', function()
local screen = Screen.new(40, 8)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { bold = true, reverse = true }, -- StatusLine
- [2] = { reverse = true }, -- TabLineFill
- [3] = { bold = true }, -- TabLineSel
- [4] = { background = Screen.colors.LightGrey, underline = true }, -- TabLine
- [5] = { bold = true, foreground = Screen.colors.Magenta },
- })
+ screen:add_extra_attr_ids {
+ [100] = { bold = true, foreground = Screen.colors.Fuchsia },
+ }
screen:attach()
command('tabnew')
@@ -118,18 +113,18 @@ describe('tabpage', function()
command('tabnext')
feed('<C-G>')
screen:expect([[
- {4: [No Name] }{3: [No Name] }{2: }{4:X}|
+ {24: [No Name] }{5: [No Name] }{2: }{24:X}|
^ |
- {0:~ }|*4
- {1:[No Name] }|
+ {1:~ }|*4
+ {3:[No Name] }|
"[No Name]" --No lines in buffer-- |
]])
command('vnew')
screen:expect([[
- {4: [No Name] }{3: }{5:2}{3: [No Name] }{2: }{4:X}|
+ {24: [No Name] }{5: }{100:2}{5: [No Name] }{2: }{24:X}|
^ │ |
- {0:~ }│{0:~ }|*4
- {1:[No Name] }|
+ {1:~ }│{1:~ }|*4
+ {3:[No Name] }|
"[No Name]" --No lines in buffer-- |
]])
end)
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index 80fdcb3134..df62aecc7f 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -23,7 +23,7 @@ local cmdtest = function(cmd, prep, ret1)
end
it(cmd .. 's' .. prep .. ' the current line by default', function()
- command(cmd .. '\nabc\ndef\n')
+ command(cmd .. '\nabc\ndef')
eq(ret1, buffer_contents())
end)
-- Used to crash because this invokes history processing which uses
diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua
index 20ebb2dedb..923bb99eeb 100644
--- a/test/functional/ex_cmds/excmd_spec.lua
+++ b/test/functional/ex_cmds/excmd_spec.lua
@@ -29,13 +29,13 @@ describe('Ex cmds', function()
':tabnext 9999999999999999999999999999999999999999',
'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999'
)
- check_excmd_err(
- ':N 9999999999999999999999999999999999999999',
- 'Vim(Next):E939: Positive count required'
+ eq(
+ 'Vim(Next):E163: There is only one file to edit',
+ pcall_err(command, ':N 9999999999999999999999999999999999999999')
)
check_excmd_err(
':bdelete 9999999999999999999999999999999999999999',
- 'Vim(bdelete):E939: Positive count required'
+ 'Vim(bdelete):E516: No buffers were deleted'
)
eq(
'Vim(menu):E329: No menu "9999999999999999999999999999999999999999"',
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index 9b24854362..8f09e802eb 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -170,7 +170,7 @@ describe(':mksession', function()
skip(is_os('win'), 'causes rmdir() to fail')
local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
- cwd_dir = cwd_dir:gsub([[\]], '/') -- :mksession always uses unix slashes.
+ cwd_dir = t.fix_slashes(cwd_dir) -- :mksession always uses unix slashes.
local session_path = cwd_dir .. '/' .. session_file
command('cd ' .. tab_dir)
diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua
index 57e5c6b2dc..365583948b 100644
--- a/test/functional/ex_cmds/profile_spec.lua
+++ b/test/functional/ex_cmds/profile_spec.lua
@@ -6,17 +6,11 @@ require('os')
local eval = n.eval
local command = n.command
local eq, neq = t.eq, t.neq
-local tempfile = t.tmpname()
+local tempfile = t.tmpname(false)
local source = n.source
local matches = t.matches
local read_file = t.read_file
--- tmpname() also creates the file on POSIX systems. Remove it again.
--- We just need the name, ignoring any race conditions.
-if uv.fs_stat(tempfile).uid then
- os.remove(tempfile)
-end
-
local function assert_file_exists(filepath)
neq(nil, uv.fs_stat(filepath).uid)
end
@@ -31,6 +25,7 @@ describe(':profile', function()
after_each(function()
n.expect_exit(command, 'qall!')
if uv.fs_stat(tempfile).uid ~= nil then
+ -- Delete the tempfile. We just need the name, ignoring any race conditions.
os.remove(tempfile)
end
end)
diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua
index 3df41b015e..9c47b1f05f 100644
--- a/test/functional/ex_cmds/quickfix_commands_spec.lua
+++ b/test/functional/ex_cmds/quickfix_commands_spec.lua
@@ -185,6 +185,9 @@ describe('quickfix', function()
it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function()
local file = file_base .. '_reuse_qfbuf_BufAdd'
write_file(file, ('\n'):rep(100) .. 'foo')
+ finally(function()
+ os.remove(file)
+ end)
source([[
set grepprg=internal
autocmd BufAdd * call and(0, 0)
@@ -192,7 +195,24 @@ describe('quickfix', function()
]])
command('grep foo ' .. file)
command('grep foo ' .. file)
- os.remove(file)
+ end)
+
+ it('jump message does not scroll with cmdheight=0 and shm+=O #29597', function()
+ local screen = Screen.new(40, 6)
+ screen:attach()
+ command('set cmdheight=0')
+ local file = file_base .. '_reuse_qfbuf_BufAdd'
+ write_file(file, 'foobar')
+ finally(function()
+ os.remove(file)
+ end)
+ command('vimgrep /foo/gj ' .. file)
+ feed(':cc<CR>')
+ screen:expect([[
+ ^foobar |
+ {1:~ }|*4
+ (1 of 1): foobar |
+ ]])
end)
end)
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index f806869b40..f813927f77 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -939,6 +939,48 @@ function tests.basic_formatting()
}
end
+function tests.range_formatting()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = true,
+ },
+ }
+ end,
+ body = function()
+ notify('start')
+ expect_request('textDocument/rangeFormatting', function()
+ return nil, {}
+ end)
+ notify('shutdown')
+ end,
+ }
+end
+
+function tests.ranges_formatting()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ documentFormattingProvider = true,
+ documentRangeFormattingProvider = {
+ rangesSupport = true,
+ },
+ },
+ }
+ end,
+ body = function()
+ notify('start')
+ expect_request('textDocument/rangesFormatting', function()
+ return nil, {}
+ end)
+ notify('shutdown')
+ end,
+ }
+end
+
function tests.set_defaults_all_capabilities()
skeleton {
on_init = function(_)
diff --git a/test/functional/legacy/crash_spec.lua b/test/functional/legacy/crash_spec.lua
index 04f77c7d4f..b63b3146f4 100644
--- a/test/functional/legacy/crash_spec.lua
+++ b/test/functional/legacy/crash_spec.lua
@@ -1,9 +1,14 @@
+local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local assert_alive = n.assert_alive
local clear = n.clear
local command = n.command
+local eq = t.eq
+local eval = n.eval
+local exec = n.exec
local feed = n.feed
+local pcall_err = t.pcall_err
before_each(clear)
@@ -32,3 +37,29 @@ it('no crash with very long option error message', function()
pcall(command, 'source test/old/testdir/crash/poc_did_set_langmap')
assert_alive()
end)
+
+it('no crash when closing window with tag in loclist', function()
+ exec([[
+ new
+ lexpr ['foo']
+ lopen
+ let g:qf_bufnr = bufnr()
+ lclose
+ call settagstack(1, #{items: [#{tagname: 'foo', from: [g:qf_bufnr, 1, 1, 0]}]})
+ ]])
+ eq(1, eval('bufexists(g:qf_bufnr)'))
+ command('1close')
+ eq(0, eval('bufexists(g:qf_bufnr)'))
+ assert_alive()
+end)
+
+it('no crash when writing "Untitled" file fails', function()
+ t.mkdir('Untitled')
+ finally(function()
+ vim.uv.fs_rmdir('Untitled')
+ end)
+ feed('ifoobar')
+ command('set bufhidden=unload')
+ eq('Vim(enew):E502: "Untitled" is a directory', pcall_err(command, 'confirm enew'))
+ assert_alive()
+end)
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
index f3d18a2541..2d98188f9b 100644
--- a/test/functional/legacy/edit_spec.lua
+++ b/test/functional/legacy/edit_spec.lua
@@ -44,6 +44,12 @@ describe('edit', function()
{1:~ }|*4
=^ |
]])
+ feed([['r'<CR><Esc>]])
+ expect('r')
+ -- Test for inserting null and empty list
+ feed('a<C-R>=v:_null_list<CR><Esc>')
+ feed('a<C-R>=[]<CR><Esc>')
+ expect('r')
end)
-- oldtest: Test_edit_ctrl_r_failed()
diff --git a/test/functional/legacy/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua
index 574c3e4069..e033898d7a 100644
--- a/test/functional/legacy/ex_mode_spec.lua
+++ b/test/functional/legacy/ex_mode_spec.lua
@@ -48,7 +48,7 @@ describe('Ex mode', function()
command('set noincsearch nohlsearch inccommand=')
local screen = Screen.new(60, 6)
screen:attach()
- command([[call setline(1, ['foo foo', 'foo foo', 'foo foo'])]])
+ command([[call setline(1, repeat(['foo foo'], 4))]])
command([[set number]])
feed('gQ')
screen:expect([[
@@ -110,12 +110,24 @@ describe('Ex mode', function()
:^ |
]])
+ -- The printed line should overwrite the colon
+ feed('<CR>')
+ screen:expect([[
+ {8: 2 }foo foo |
+ ^^^q |
+ {8: 2 }foo foo |
+ {8: 3 }foo foo |
+ {8: 4 }foo foo |
+ :^ |
+ ]])
+
feed(':vi<CR>')
screen:expect([[
{8: 1 }foo bar |
{8: 2 }foo foo |
- {8: 3 }^foo foo |
- {1:~ }|*2
+ {8: 3 }foo foo |
+ {8: 4 }^foo foo |
+ {1:~ }|
|
]])
end)
diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua
index de3d498f27..753a45ee05 100644
--- a/test/functional/legacy/excmd_spec.lua
+++ b/test/functional/legacy/excmd_spec.lua
@@ -5,45 +5,14 @@ local Screen = require('test.functional.ui.screen')
local clear = n.clear
local command = n.command
local exec = n.exec
-local exec_lua = n.exec_lua
local expect_exit = n.expect_exit
local feed = n.feed
local fn = n.fn
-local api = n.api
local read_file = t.read_file
-local source = n.source
local eq = t.eq
local write_file = t.write_file
local is_os = t.is_os
-local function sizeoflong()
- if not exec_lua('return pcall(require, "ffi")') then
- pending('missing LuaJIT FFI')
- end
- return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))')
-end
-
-describe('Ex command', function()
- before_each(clear)
- after_each(function()
- eq({}, api.nvim_get_vvar('errors'))
- end)
-
- it('checks for address line overflow', function()
- if sizeoflong() < 8 then
- pending('Skipped: only works with 64 bit long ints')
- end
-
- source [[
- new
- call setline(1, 'text')
- call assert_fails('|.44444444444444444444444', 'E1247:')
- call assert_fails('|.9223372036854775806', 'E1247:')
- bwipe!
- ]]
- end)
-end)
-
describe(':confirm command dialog', function()
local screen
diff --git a/test/functional/legacy/matchparen_spec.lua b/test/functional/legacy/matchparen_spec.lua
index 3841761515..df0d80f0ab 100644
--- a/test/functional/legacy/matchparen_spec.lua
+++ b/test/functional/legacy/matchparen_spec.lua
@@ -120,8 +120,7 @@ describe('matchparen', function()
]])
feed('i<C-X><C-N><C-N>')
- screen:expect {
- grid = [[
+ screen:expect([[
aa |
aaa |
aaaa |
@@ -131,7 +130,79 @@ describe('matchparen', function()
{4: aaaa }{1: }|
{1:~ }|
{5:-- }{6:match 2 of 3} |
- ]],
- }
+ ]])
+ end)
+
+ -- oldtest: Test_matchparen_mbyte()
+ it("works with multibyte chars in 'matchpairs'", function()
+ local screen = Screen.new(30, 10)
+ screen:set_default_attr_ids({
+ [0] = { bold = true, foreground = Screen.colors.Blue },
+ [1] = { background = Screen.colors.Cyan },
+ [2] = { bold = true },
+ })
+ screen:attach()
+
+ exec([[
+ source $VIMRUNTIME/plugin/matchparen.vim
+ call setline(1, ['aaaaaaaa(', 'bbbb)cc'])
+ set matchpairs+=(:)
+ ]])
+
+ screen:expect([[
+ ^aaaaaaaa( |
+ bbbb)cc |
+ {0:~ }|*7
+ |
+ ]])
+ feed('$')
+ screen:expect([[
+ aaaaaaaa{1:^(} |
+ bbbb{1:)}cc |
+ {0:~ }|*7
+ |
+ ]])
+ feed('j')
+ screen:expect([[
+ aaaaaaaa( |
+ bbbb)c^c |
+ {0:~ }|*7
+ |
+ ]])
+ feed('2h')
+ screen:expect([[
+ aaaaaaaa{1:(} |
+ bbbb{1:^)}cc |
+ {0:~ }|*7
+ |
+ ]])
+ feed('0')
+ screen:expect([[
+ aaaaaaaa( |
+ ^bbbb)cc |
+ {0:~ }|*7
+ |
+ ]])
+ feed('kA')
+ screen:expect([[
+ aaaaaaaa{1:(}^ |
+ bbbb{1:)}cc |
+ {0:~ }|*7
+ {2:-- INSERT --} |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ aaaaaaaa( |
+ bbbb)cc^ |
+ {0:~ }|*7
+ {2:-- INSERT --} |
+ ]])
+ feed('<C-W>')
+ screen:expect([[
+ aaaaaaaa{1:(} |
+ bbbb{1:)}^ |
+ {0:~ }|*7
+ {2:-- INSERT --} |
+ ]])
end)
end)
diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua
index 587424da10..8b9b495679 100644
--- a/test/functional/legacy/put_spec.lua
+++ b/test/functional/legacy/put_spec.lua
@@ -1,52 +1,11 @@
-local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local clear = n.clear
-local exec_lua = n.exec_lua
-local api = n.api
local source = n.source
-local eq = t.eq
-
-local function sizeoflong()
- if not exec_lua('return pcall(require, "ffi")') then
- pending('missing LuaJIT FFI')
- end
- return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))')
-end
describe('put', function()
before_each(clear)
- after_each(function()
- eq({}, api.nvim_get_vvar('errors'))
- end)
-
- it('very large count 64-bit', function()
- if sizeoflong() < 8 then
- pending('Skipped: only works with 64 bit long ints')
- end
-
- source [[
- new
- let @" = repeat('x', 100)
- call assert_fails('norm 999999999p', 'E1240:')
- bwipe!
- ]]
- end)
-
- it('very large count (visual block) 64-bit', function()
- if sizeoflong() < 8 then
- pending('Skipped: only works with 64 bit long ints')
- end
-
- source [[
- new
- call setline(1, repeat('x', 100))
- exe "norm \<C-V>$y"
- call assert_fails('norm 999999999p', 'E1240:')
- bwipe!
- ]]
- end)
-- oldtest: Test_put_other_window()
it('above topline in buffer in two splits', function()
diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 97578067d5..ec1dc59d53 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -375,6 +375,108 @@ describe('smoothscroll', function()
screen:expect_unchanged()
end)
+ -- oldtest: Test_smoothscroll_diff_change_line()
+ it('works in diff mode when changing line', function()
+ screen:try_resize(55, 20)
+ exec([[
+ set diffopt+=followwrap smoothscroll
+ call setline(1, repeat(' abc', &columns))
+ call setline(2, 'bar')
+ call setline(3, repeat(' abc', &columns))
+ vnew
+ call setline(1, repeat(' abc', &columns))
+ call setline(2, 'foo')
+ call setline(3, 'bar')
+ call setline(4, repeat(' abc', &columns))
+ windo exe "normal! 2gg5\<C-E>"
+ windo diffthis
+ ]])
+
+ screen:expect([[
+ {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {7: }{22:foo }│{7: }{23:-------------------------}|
+ {7: }bar │{7: }^bar |
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {1:~ }│{1:~ }|*3
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ feed('Abar')
+ screen:expect([[
+ {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {7: }{22:foo }│{7: }{23:-------------------------}|
+ {7: }bar │{7: }barbar^ |
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {1:~ }│{1:~ }|*3
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ {5:-- INSERT --} |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {7: }{27:foo}{4: }│{7: }{27:barba^r}{4: }|
+ {7: }{22:bar }│{7: }{23:-------------------------}|
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {1:~ }│{1:~ }|*3
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ feed('yyp')
+ screen:expect([[
+ {1:<<<}bc abc abc abc abc abc a│{1:<<<}bc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {7: }{27:foo}{4: }│{7: }{27:barbar}{4: }|
+ {7: }{4:bar }│{7: }{4:^bar}{27:bar}{4: }|
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc abc │{7: } abc abc abc abc abc abc |
+ {7: }abc abc abc abc abc abc a│{7: }abc abc abc abc abc abc a|
+ {7: }bc abc abc abc abc abc ab│{7: }bc abc abc abc abc abc ab|
+ {7: }c abc abc abc abc abc abc│{7: }c abc abc abc abc abc abc|
+ {7: } abc abc abc abc abc │{7: } abc abc abc abc abc |
+ {1:~ }│{1:~ }|*3
+ {2:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ end)
+
-- oldtest: Test_smoothscroll_wrap_scrolloff_zero()
it("works with zero 'scrolloff'", function()
screen:try_resize(40, 8)
@@ -1204,16 +1306,15 @@ describe('smoothscroll', function()
set smoothscroll scrolloff=3
call setline(1, ['one', 'two long '->repeat(100), 'three', 'four', 'five', 'six'])
]])
- --FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans
feed(':norm j721|<CR>')
screen:expect([[
- two long two long two long two long two |
+ {1:<<<}two long two long two long two long t|
+ wo long two long two long two long two l|
+ ong two long two long two long two long |
+ ^two long two long two long two long two |
long two long two long two long two long|
two long two long two long two long two|
- ^ long two long two long two long two lon|
- g two long two long two long two long tw|
- o long two long two long two long two lo|
- ng two long two long two long two long t|
+ long two long two long two long two lon|
:norm j721| |
]])
feed('gj')
@@ -1272,15 +1373,14 @@ describe('smoothscroll', function()
:norm j721| |
]])
feed('gk')
- --FIXME: incorrect screen due to reset_skipcol()/curs_columns() shenanigans
screen:expect([[
+ {1:<<<}long two long two long two long two l|
+ ong two long two long two long two long |
two long two long two long two long two |
long two long two long two long two long|
two long two long two long two long two|
long two long two long two long two lon|
- g two long two long two long two long tw|
- o long two long two long two long two lo|
- ^ng two long two long two long two long t|
+ ^g two long two long |
:norm j721| |
]])
end)
diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua
index 614673ee3c..27145f4c91 100644
--- a/test/functional/legacy/signs_spec.lua
+++ b/test/functional/legacy/signs_spec.lua
@@ -1,13 +1,14 @@
-- Tests for signs
local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
-local clear, command, expect = n.clear, n.command, n.expect
+local clear, command, exec, expect, feed = n.clear, n.command, n.exec, n.expect, n.feed
describe('signs', function()
- setup(clear)
+ before_each(clear)
- it('is working', function()
+ it('are working', function()
command('sign define JumpSign text=x')
command([[exe 'sign place 42 line=2 name=JumpSign buffer=' . bufnr('')]])
-- Split the window to the bottom to verify :sign-jump will stay in the current
@@ -21,4 +22,60 @@ describe('signs', function()
2]])
end)
+
+ -- oldtest: Test_sign_cursor_position()
+ it('are drawn correctly', function()
+ local screen = Screen.new(75, 6)
+ screen:attach()
+ exec([[
+ call setline(1, [repeat('x', 75), 'mmmm', 'yyyy'])
+ call cursor(2,1)
+ sign define s1 texthl=Search text==>
+ sign define s2 linehl=Pmenu
+ redraw
+ sign place 10 line=2 name=s1
+ ]])
+ screen:expect([[
+ {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+ {7: }xx |
+ {10:=>}^mmmm |
+ {7: }yyyy |
+ {1:~ }|
+ |
+ ]])
+
+ -- Change the sign text
+ command('sign define s1 text=-)')
+ screen:expect([[
+ {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+ {7: }xx |
+ {10:-)}^mmmm |
+ {7: }yyyy |
+ {1:~ }|
+ |
+ ]])
+
+ -- Also place a line HL sign
+ command('sign place 11 line=2 name=s2')
+ screen:expect([[
+ {7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+ {7: }xx |
+ {10:-)}{4:^mmmm }|
+ {7: }yyyy |
+ {1:~ }|
+ |
+ ]])
+
+ -- update cursor position calculation
+ feed('lh')
+ command('sign unplace 11')
+ command('sign unplace 10')
+ screen:expect([[
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+ ^mmmm |
+ yyyy |
+ {1:~ }|*2
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index 56969150bd..741ed0cf6e 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -145,10 +145,10 @@ describe('luaeval(vim.api.…)', function()
eq(true, fn.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)'))
eq(
42,
- exec_lua [[
- local f = vim.api.nvim__id({42, vim.api.nvim__id})
- return f[2](f[1])
- ]]
+ exec_lua(function()
+ local f = vim.api.nvim__id({ 42, vim.api.nvim__id })
+ return f[2](f[1])
+ end)
)
end)
@@ -224,42 +224,39 @@ describe('luaeval(vim.api.…)', function()
end)
it('correctly converts dictionaries with type_idx to API objects', function()
- eq(
- 4,
- eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])
- )
+ eq(4, eval([[type(luaeval('vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary})'))]]))
- eq({}, fn.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))
+ eq({}, fn.luaeval('vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary})'))
eq(
{ v = { 42 } },
fn.luaeval(
- 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'
+ 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'
)
)
eq(
{ foo = 2 },
fn.luaeval(
- 'vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'
+ 'vim.api.nvim__id_dict({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})'
)
)
eq(
{ v = 10 },
fn.luaeval(
- 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'
+ 'vim.api.nvim__id_dict({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})'
)
)
eq(
{ v = {} },
fn.luaeval(
- 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})'
+ 'vim.api.nvim__id_dict({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
+ -- If API requests dict, then empty table will be the one. This is not
-- the case normally because empty table is an empty array.
- eq({}, fn.luaeval('vim.api.nvim__id_dictionary({})'))
- eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]]))
+ eq({}, fn.luaeval('vim.api.nvim__id_dict({})'))
+ eq(4, eval([[type(luaeval('vim.api.nvim__id_dict({})'))]]))
end)
it('converts booleans in positional args', function()
@@ -365,12 +362,12 @@ describe('luaeval(vim.api.…)', function()
eq(
[[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Lua table]],
- remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]]))
+ remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dict(1)")]]))
)
eq(
[[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Dict-like Lua table]],
remove_trace(
- exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]])
+ exc_exec([[call luaeval("vim.api.nvim__id_dict({[vim.type_idx]=vim.types.array})")]])
)
)
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index d4af7e4732..f277868b1c 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -27,30 +27,35 @@ local origlines = {
before_each(function()
clear()
- exec_lua [[
- local evname = ...
+ exec_lua(function()
local events = {}
- function test_register(bufnr, evname, id, changedtick, utf_sizes, preview)
+ function _G.test_register(bufnr, evname, id, changedtick, utf_sizes, preview)
local function callback(...)
- table.insert(events, {id, ...})
- if test_unreg == id then
+ table.insert(events, { id, ... })
+ if _G.test_unreg == id then
return true
end
end
- local opts = {[evname]=callback, on_detach=callback, on_reload=callback, utf_sizes=utf_sizes, preview=preview}
+ local opts = {
+ [evname] = callback,
+ on_detach = callback,
+ on_reload = callback,
+ utf_sizes = utf_sizes,
+ preview = preview,
+ }
if changedtick then
opts.on_changedtick = callback
end
vim.api.nvim_buf_attach(bufnr, false, opts)
end
- function get_events()
+ function _G.get_events()
local ret_events = events
events = {}
return ret_events
end
- ]]
+ end)
end)
describe('lua buffer event callbacks: on_lines', function()
@@ -257,13 +262,13 @@ describe('lua buffer event callbacks: on_lines', function()
it('has valid cursor position while shifting', function()
api.nvim_buf_set_lines(0, 0, -1, true, { 'line1' })
- exec_lua([[
+ exec_lua(function()
vim.api.nvim_buf_attach(0, false, {
on_lines = function()
vim.api.nvim_set_var('listener_cursor_line', vim.api.nvim_win_get_cursor(0)[1])
end,
})
- ]])
+ end)
feed('>>')
eq(1, api.nvim_get_var('listener_cursor_line'))
end)
@@ -277,19 +282,19 @@ describe('lua buffer event callbacks: on_lines', function()
end)
it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function()
- local code = [[
+ local code = function()
local buf = vim.api.nvim_create_buf(false, false)
- vim.cmd"split"
+ vim.cmd 'split'
vim.api.nvim_win_set_buf(0, buf)
vim.api.nvim_buf_attach(buf, false, {
- on_detach = function(_, buf)
+ on_detach = function(_, buf0)
vim.fn.tabpagebuflist()
- vim.fn.win_findbuf(buf)
- end
+ vim.fn.win_findbuf(buf0)
+ end,
})
- ]]
+ end
exec_lua(code)
command('q!')
@@ -302,13 +307,13 @@ describe('lua buffer event callbacks: on_lines', function()
it('#12718 lnume', function()
api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' })
- exec_lua([[
+ exec_lua(function()
vim.api.nvim_buf_attach(0, false, {
on_lines = function(...)
vim.api.nvim_set_var('linesev', { ... })
end,
})
- ]])
+ end)
feed('1G0')
feed('y<C-v>2j')
feed('G0')
@@ -326,13 +331,13 @@ describe('lua buffer event callbacks: on_lines', function()
end)
it('nvim_buf_call() from callback does not cause wrong Normal mode CTRL-A #16729', function()
- exec_lua([[
+ exec_lua(function()
vim.api.nvim_buf_attach(0, false, {
- on_lines = function(...)
+ on_lines = function()
vim.api.nvim_buf_call(0, function() end)
end,
})
- ]])
+ end)
feed('itest123<Esc><C-A>')
eq('test124', api.nvim_get_current_line())
end)
@@ -342,19 +347,19 @@ describe('lua buffer event callbacks: on_lines', function()
screen:attach()
api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' })
- exec_lua([[
+ exec_lua(function()
local ns = vim.api.nvim_create_namespace('')
vim.api.nvim_buf_attach(0, false, {
on_lines = function(_, _, _, row, _, end_row)
vim.api.nvim_buf_clear_namespace(0, ns, row, end_row)
for i = row, end_row - 1 do
- local id = vim.api.nvim_buf_set_extmark(0, ns, i, 0, {
- virt_text = {{ 'NEW' .. tostring(i), 'WarningMsg' }},
+ vim.api.nvim_buf_set_extmark(0, ns, i, 0, {
+ virt_text = { { 'NEW' .. tostring(i), 'WarningMsg' } },
})
end
end,
})
- ]])
+ end)
feed('o')
screen:expect({
@@ -379,6 +384,25 @@ describe('lua buffer event callbacks: on_lines', function()
]],
})
end)
+
+ it('line lengths are correct when pressing TAB with folding #29119', function()
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' })
+
+ exec_lua(function()
+ _G.res = {}
+ vim.o.foldmethod = 'indent'
+ vim.o.softtabstop = -1
+ vim.api.nvim_buf_attach(0, false, {
+ on_lines = function(_, bufnr, _, row, _, end_row)
+ local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true)
+ table.insert(_G.res, lines)
+ end,
+ })
+ end)
+
+ feed('i<Tab>')
+ eq({ '\ta' }, exec_lua('return _G.res[#_G.res]'))
+ end)
end)
describe('lua: nvim_buf_attach on_bytes', function()
diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua
index 2ba432133b..f8786a45bb 100644
--- a/test/functional/lua/command_line_completion_spec.lua
+++ b/test/functional/lua/command_line_completion_spec.lua
@@ -5,12 +5,14 @@ local clear = n.clear
local eq = t.eq
local exec_lua = n.exec_lua
+--- @return { [1]: string[], [2]: integer }
local get_completions = function(input, env)
- return exec_lua('return {vim._expand_pat(...)}', input, env)
+ return exec_lua('return { vim._expand_pat(...) }', input, env)
end
+--- @return { [1]: string[], [2]: integer }
local get_compl_parts = function(parts)
- return exec_lua('return {vim._expand_pat_get_parts(...)}', parts)
+ return exec_lua('return { vim._expand_pat_get_parts(...) }', parts)
end
before_each(clear)
@@ -123,6 +125,171 @@ describe('nlua_expand_pat', function()
)
end)
+ describe('should complete vim.fn', function()
+ it('correctly works for simple completion', function()
+ local actual = get_completions('vim.fn.did')
+ local expected = {
+ { 'did_filetype' },
+ #'vim.fn.',
+ }
+ eq(expected, actual)
+ end)
+ it('should not suggest items with #', function()
+ exec_lua [[
+ -- ensure remote#host#... functions exist
+ vim.cmd [=[
+ runtime! autoload/remote/host.vim
+ ]=]
+ -- make a dummy call to ensure vim.fn contains an entry: remote#host#...
+ vim.fn['remote#host#IsRunning']('python3')
+ ]]
+ local actual = get_completions('vim.fn.remo')
+ local expected = {
+ { 'remove' }, -- there should be no completion "remote#host#..."
+ #'vim.fn.',
+ }
+ eq(expected, actual)
+ end)
+ end)
+
+ describe('should complete for variable accessors for', function()
+ it('vim.v', function()
+ local actual = get_completions('vim.v.t_')
+ local expected = {
+ { 't_blob', 't_bool', 't_dict', 't_float', 't_func', 't_list', 't_number', 't_string' },
+ #'vim.v.',
+ }
+ eq(expected, actual)
+ end)
+
+ it('vim.g', function()
+ exec_lua [[
+ vim.cmd [=[
+ let g:nlua_foo = 'completion'
+ let g:nlua_foo_bar = 'completion'
+ let g:nlua_foo#bar = 'nocompletion' " should be excluded from lua completion
+ ]=]
+ ]]
+ local actual = get_completions('vim.g.nlua')
+ local expected = {
+ { 'nlua_foo', 'nlua_foo_bar' },
+ #'vim.g.',
+ }
+ eq(expected, actual)
+ end)
+
+ it('vim.b', function()
+ exec_lua [[
+ vim.b.nlua_foo_buf = 'bar'
+ vim.b.some_other_vars = 'bar'
+ ]]
+ local actual = get_completions('vim.b.nlua')
+ local expected = {
+ { 'nlua_foo_buf' },
+ #'vim.b.',
+ }
+ eq(expected, actual)
+ end)
+
+ it('vim.w', function()
+ exec_lua [[
+ vim.w.nlua_win_var = 42
+ ]]
+ local actual = get_completions('vim.w.nlua')
+ local expected = {
+ { 'nlua_win_var' },
+ #'vim.w.',
+ }
+ eq(expected, actual)
+ end)
+
+ it('vim.t', function()
+ exec_lua [[
+ vim.t.nlua_tab_var = 42
+ ]]
+ local actual = get_completions('vim.t.')
+ local expected = {
+ { 'nlua_tab_var' },
+ #'vim.t.',
+ }
+ eq(expected, actual)
+ end)
+ end)
+
+ describe('should complete for option accessors for', function()
+ -- for { vim.o, vim.go, vim.opt, vim.opt_local, vim.opt_global }
+ local test_opt = function(accessor)
+ do
+ local actual = get_completions(accessor .. '.file')
+ local expected = {
+ 'fileencoding',
+ 'fileencodings',
+ 'fileformat',
+ 'fileformats',
+ 'fileignorecase',
+ 'filetype',
+ }
+ eq({ expected, #accessor + 1 }, actual, accessor .. '.file')
+ end
+ do
+ local actual = get_completions(accessor .. '.winh')
+ local expected = {
+ 'winheight',
+ 'winhighlight',
+ }
+ eq({ expected, #accessor + 1 }, actual, accessor .. '.winh')
+ end
+ end
+
+ test_opt('vim.o')
+ test_opt('vim.go')
+ test_opt('vim.opt')
+ test_opt('vim.opt_local')
+ test_opt('vim.opt_global')
+
+ it('vim.o, suggesting all the known options', function()
+ local completions = get_completions('vim.o.')[1] ---@type string[]
+ eq(
+ exec_lua [[
+ return vim.tbl_count(vim.api.nvim_get_all_options_info())
+ ]],
+ #completions
+ )
+ end)
+
+ it('vim.bo', function()
+ do
+ local actual = get_completions('vim.bo.file')
+ local compls = {
+ -- should contain buffer options only
+ 'fileencoding',
+ 'fileformat',
+ 'filetype',
+ }
+ eq({ compls, #'vim.bo.' }, actual)
+ end
+ do
+ local actual = get_completions('vim.bo.winh')
+ local compls = {}
+ eq({ compls, #'vim.bo.' }, actual)
+ end
+ end)
+
+ it('vim.wo', function()
+ do
+ local actual = get_completions('vim.wo.file')
+ local compls = {}
+ eq({ compls, #'vim.wo.' }, actual)
+ end
+ do
+ local actual = get_completions('vim.wo.winh')
+ -- should contain window options only
+ local compls = { 'winhighlight' }
+ eq({ compls, #'vim.wo.' }, actual)
+ end
+ end)
+ end)
+
it('should return everything if the input is of length 0', function()
eq({ { 'other', 'vim' }, 0 }, get_completions('', { vim = true, other = true }))
end)
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index 57b084d3d6..456ee13da2 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -178,13 +178,15 @@ describe(':lua', function()
eq('hello', exec_capture(':lua = x()'))
exec_lua('x = {a = 1, b = 2}')
eq('{\n a = 1,\n b = 2\n}', exec_capture(':lua =x'))
- exec_lua([[function x(success)
- if success then
- return true, "Return value"
- else
- return false, nil, "Error message"
+ exec_lua(function()
+ function _G.x(success)
+ if success then
+ return true, 'Return value'
+ else
+ return false, nil, 'Error message'
+ end
end
- end]])
+ end)
eq(
dedent [[
true
diff --git a/test/functional/lua/deprecated_spec.lua b/test/functional/lua/deprecated_spec.lua
new file mode 100644
index 0000000000..fee34336cc
--- /dev/null
+++ b/test/functional/lua/deprecated_spec.lua
@@ -0,0 +1,22 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+local clear = n.clear
+local exec_lua = n.exec_lua
+local eq = t.eq
+
+describe('deprecated lua code', function()
+ before_each(clear)
+
+ describe('vim.treesitter.get_parser()', function()
+ it('returns nil for versions >= 0.12', function()
+ local result = exec_lua(function()
+ if vim.version.ge(vim.version(), '0.12') then
+ return vim.treesitter.get_parser(0, 'borklang')
+ end
+ return nil
+ end)
+ eq(nil, result)
+ end)
+ end)
+end)
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index 05082bc132..4ae1146703 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -1,7 +1,6 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local NIL = vim.NIL
local command = n.command
local clear = n.clear
local exec_lua = n.exec_lua
@@ -15,10 +14,10 @@ describe('vim.diagnostic', function()
before_each(function()
clear()
- exec_lua [[
+ exec_lua(function()
require('vim.diagnostic')
- function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code)
+ local function make_diagnostic(msg, lnum, col, end_lnum, end_col, severity, source, code)
return {
lnum = lnum,
col = col,
@@ -31,54 +30,97 @@ describe('vim.diagnostic', function()
}
end
- function make_error(msg, lnum, col, end_lnum, end_col, source, code)
- return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.ERROR, source, code)
+ function _G.make_error(msg, lnum, col, end_lnum, end_col, source, code)
+ return make_diagnostic(
+ msg,
+ lnum,
+ col,
+ end_lnum,
+ end_col,
+ vim.diagnostic.severity.ERROR,
+ source,
+ code
+ )
end
- function make_warning(msg, lnum, col, end_lnum, end_col, source, code)
- return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.WARN, source, code)
+ function _G.make_warning(msg, lnum, col, end_lnum, end_col, source, code)
+ return make_diagnostic(
+ msg,
+ lnum,
+ col,
+ end_lnum,
+ end_col,
+ vim.diagnostic.severity.WARN,
+ source,
+ code
+ )
end
- function make_info(msg, lnum, col, end_lnum, end_col, source, code)
- return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.INFO, source, code)
+ function _G.make_info(msg, lnum, col, end_lnum, end_col, source, code)
+ return make_diagnostic(
+ msg,
+ lnum,
+ col,
+ end_lnum,
+ end_col,
+ vim.diagnostic.severity.INFO,
+ source,
+ code
+ )
end
- function make_hint(msg, lnum, col, end_lnum, end_col, source, code)
- return make_diagnostic(msg, lnum, col, end_lnum, end_col, vim.diagnostic.severity.HINT, source, code)
+ function _G.make_hint(msg, lnum, col, end_lnum, end_col, source, code)
+ return make_diagnostic(
+ msg,
+ lnum,
+ col,
+ end_lnum,
+ end_col,
+ vim.diagnostic.severity.HINT,
+ source,
+ code
+ )
end
- function count_diagnostics(bufnr, severity, namespace)
- return #vim.diagnostic.get(bufnr, {severity = severity, namespace = namespace})
+ function _G.count_diagnostics(bufnr, severity, namespace)
+ return #vim.diagnostic.get(bufnr, { severity = severity, namespace = namespace })
end
- function count_extmarks(bufnr, namespace)
+ function _G.count_extmarks(bufnr, namespace)
local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = 0
if ns.user_data.virt_text_ns then
- extmarks = extmarks + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {})
+ extmarks = extmarks
+ + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {})
end
if ns.user_data.underline_ns then
- extmarks = extmarks + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {})
+ extmarks = extmarks
+ + #vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {})
end
return extmarks
end
- function get_virt_text_extmarks(ns)
- local ns = vim.diagnostic.get_namespace(ns)
+ function _G.get_virt_text_extmarks(ns)
+ ns = vim.diagnostic.get_namespace(ns)
local virt_text_ns = ns.user_data.virt_text_ns
- return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, virt_text_ns, 0, -1, {details = true})
+ return vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ virt_text_ns,
+ 0,
+ -1,
+ { details = true }
+ )
end
- ]]
-
- exec_lua([[
- diagnostic_ns = vim.api.nvim_create_namespace("diagnostic_spec")
- other_ns = vim.api.nvim_create_namespace("other_namespace")
- diagnostic_bufnr = vim.api.nvim_create_buf(true, false)
- local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"}
- vim.fn.bufload(diagnostic_bufnr)
- vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
- return diagnostic_bufnr
- ]])
+ end)
+
+ exec_lua(function()
+ _G.diagnostic_ns = vim.api.nvim_create_namespace('diagnostic_spec')
+ _G.other_ns = vim.api.nvim_create_namespace('other_namespace')
+ _G.diagnostic_bufnr = vim.api.nvim_create_buf(true, false)
+ local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
+ vim.fn.bufload(_G.diagnostic_bufnr)
+ vim.api.nvim_buf_set_lines(_G.diagnostic_bufnr, 0, 1, false, lines)
+ end)
end)
it('creates highlight groups', function()
@@ -115,27 +157,28 @@ describe('vim.diagnostic', function()
end)
it('retrieves diagnostics from all buffers and namespaces', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local other_bufnr = vim.api.nvim_create_buf(true, false)
- local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true)
+ local lines = vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, -1, true)
vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines)
- 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(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic #2', 2, 1, 2, 1),
})
- vim.diagnostic.set(other_ns, other_bufnr, {
- make_error('Diagnostic #3', 3, 1, 3, 1),
+ vim.diagnostic.set(_G.other_ns, other_bufnr, {
+ _G.make_error('Diagnostic #3', 3, 1, 3, 1),
})
return vim.diagnostic.get()
- ]]
+ end)
eq(3, #result)
eq(
2,
- exec_lua(
- [[return #vim.tbl_filter(function(d) return d.bufnr == diagnostic_bufnr end, ...)]],
- result
- )
+ exec_lua(function()
+ return #vim.tbl_filter(function(d)
+ return d.bufnr == _G.diagnostic_bufnr
+ end, result)
+ end)
)
eq('Diagnostic #1', result[1].message)
end)
@@ -143,155 +186,171 @@ describe('vim.diagnostic', function()
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()
- ]]
+ exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ local other_bufnr = vim.fn.bufadd('test | test')
+ local lines = vim.api.nvim_buf_get_lines(_G.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(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, {
+ _G.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()
+ end)
)
eq(
2,
- exec_lua [[
- vim.api.nvim_set_current_buf(diagnostic_bufnr)
- vim.opt_local.buflisted = false
- return #vim.diagnostic.get()
- ]]
+ exec_lua(function()
+ vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
+ vim.opt_local.buflisted = false
+ return #vim.diagnostic.get()
+ end)
)
eq(
0,
- exec_lua [[
- vim.cmd('bwipeout!')
- return #vim.diagnostic.get()
- ]]
+ exec_lua(function()
+ vim.cmd('bwipeout!')
+ return #vim.diagnostic.get()
+ end)
)
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 diagnostics = exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.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)
- ]]
+ vim.fn.bufadd('test | test')
+ vim.cmd('noautocmd bwipeout! ' .. _G.diagnostic_bufnr)
+ return vim.diagnostic.get(_G.diagnostic_bufnr)
+ end)
eq(2, #diagnostics)
- diagnostics = exec_lua [[
+ diagnostics = exec_lua(function()
vim.diagnostic.reset()
return vim.diagnostic.get()
- ]]
+ end)
eq(0, #diagnostics)
end)
it('always returns a copy of diagnostic tables', function()
- local result = exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
+ local result = exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
})
local diag = vim.diagnostic.get()
diag[1].col = 10000
return vim.diagnostic.get()[1].col == 10000
- ]]
+ end)
eq(false, result)
end)
it('resolves buffer number 0 to the current buffer', function()
eq(
2,
- exec_lua [[
- vim.api.nvim_set_current_buf(diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- make_error('Diagnostic #2', 2, 1, 2, 1),
- })
- return #vim.diagnostic.get(0)
- ]]
+ exec_lua(function()
+ vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ return #vim.diagnostic.get(0)
+ end)
)
end)
it('saves and count a single error', function()
eq(
1,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- })
- return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ return _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ )
+ end)
)
end)
it('saves and count multiple errors', function()
eq(
2,
- 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),
- })
- return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ return _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ )
+ end)
)
end)
it('saves and count from multiple namespaces', function()
eq(
{ 1, 1, 2 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic From Server 1', 1, 1, 1, 1),
- })
- vim.diagnostic.set(other_ns, diagnostic_bufnr, {
- make_error('Diagnostic From Server 2', 1, 1, 1, 1),
- })
- return {
- -- First namespace
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- -- Second namespace
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns),
- -- All namespaces
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR),
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic From Server 1', 1, 1, 1, 1),
+ })
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic From Server 2', 1, 1, 1, 1),
+ })
+ return {
+ -- First namespace
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ -- Second namespace
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns),
+ -- All namespaces
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR),
+ }
+ end)
)
end)
it('saves and count from multiple namespaces with respect to severity', function()
eq(
{ 3, 0, 3 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
- make_error('Diagnostic From Server 1:2', 2, 2, 2, 2),
- make_error('Diagnostic From Server 1:3', 2, 3, 3, 2),
- })
- vim.diagnostic.set(other_ns, diagnostic_bufnr, {
- make_warning('Warning From Server 2', 3, 3, 3, 3),
- })
- return {
- -- Namespace 1
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- -- Namespace 2
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns),
- -- All namespaces
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR),
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic From Server 1:2', 2, 2, 2, 2),
+ _G.make_error('Diagnostic From Server 1:3', 2, 3, 3, 2),
+ })
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning From Server 2', 3, 3, 3, 3),
+ })
+ return {
+ -- Namespace 1
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ -- Namespace 2
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.other_ns),
+ -- All namespaces
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.ERROR),
+ }
+ end)
)
end)
@@ -304,160 +363,190 @@ describe('vim.diagnostic', function()
local all_highlights = { 1, 1, 2, 4, 2 }
eq(
all_highlights,
- exec_lua [[
- local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 3),
- }
- local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 3),
- }
+ exec_lua(function()
+ local ns_1_diags = {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 3),
+ }
+ local ns_2_diags = {
+ _G.make_warning('Warning 1', 2, 1, 2, 3),
+ }
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
- return {
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- }
- ]]
+ return {
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
)
-- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2
eq(
{ 1, 1, 2, 0, 2 },
- exec_lua [[
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
- return {
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
+ return {
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
)
-- Show diagnostics from namespace 1 again
eq(
all_highlights,
- exec_lua([[
- vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
- return {
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- }
- ]])
+ exec_lua(function()
+ vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
+ return {
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
)
end)
it('does not display diagnostics when disabled', function()
eq(
{ 0, 2 },
- exec_lua [[
- local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 3),
- }
- local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 3),
- }
+ exec_lua(function()
+ local ns_1_diags = {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 3),
+ }
+ local ns_2_diags = {
+ _G.make_warning('Warning 1', 2, 1, 2, 3),
+ }
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
- return {
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- }
- ]]
+ return {
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
)
eq(
{ 4, 0 },
- exec_lua [[
- vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns })
+ exec_lua(function()
+ vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns })
- return {
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- }
- ]]
+ return {
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
)
end)
describe('show() and hide()', function()
it('works', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local other_bufnr = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
local result = {}
vim.diagnostic.config({ underline = false, virtual_text = true })
local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 5),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ _G.make_warning('Warning 1', 2, 1, 2, 5),
}
local other_buffer_diags = {
- make_info("This is interesting", 0, 0, 0, 0)
+ _G.make_info('This is interesting', 0, 0, 0, 0),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
- vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
-- All buffers and namespaces
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
-- Hide one namespace
- vim.diagnostic.hide(diagnostic_ns)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ vim.diagnostic.hide(_G.diagnostic_ns)
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
-- Show one namespace
- vim.diagnostic.show(diagnostic_ns)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ vim.diagnostic.show(_G.diagnostic_ns)
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
-- Hide one buffer
vim.diagnostic.hide(nil, other_bufnr)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
-- Hide everything
vim.diagnostic.hide()
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
-- Show one buffer
- vim.diagnostic.show(nil, diagnostic_bufnr)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ vim.diagnostic.show(nil, _G.diagnostic_bufnr)
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
return result
- ]]
+ end)
eq(4, result[1])
eq(1, result[2])
@@ -468,13 +557,17 @@ describe('vim.diagnostic', function()
end)
it("doesn't error after bwipeout on buffer", function()
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }})
- vim.cmd("bwipeout! " .. diagnostic_bufnr)
+ exec_lua(function()
+ vim.diagnostic.set(
+ _G.diagnostic_ns,
+ _G.diagnostic_bufnr,
+ { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
+ )
+ vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
- vim.diagnostic.show(diagnostic_ns)
- vim.diagnostic.hide(diagnostic_ns)
- ]]
+ vim.diagnostic.show(_G.diagnostic_ns)
+ vim.diagnostic.hide(_G.diagnostic_ns)
+ end)
end)
end)
@@ -505,52 +598,64 @@ describe('vim.diagnostic', function()
end)
it('without arguments', function()
- local result = exec_lua [[
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
local result = {}
vim.diagnostic.config({ underline = false, virtual_text = true })
local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 5),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ _G.make_warning('Warning 1', 2, 1, 2, 5),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ )
vim.diagnostic.enable(false)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ )
-- Create a new buffer
local other_bufnr = vim.api.nvim_create_buf(true, false)
local other_buffer_diags = {
- make_info("This is interesting", 0, 0, 0, 0)
+ _G.make_info('This is interesting', 0, 0, 0, 0),
}
- vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
vim.diagnostic.enable()
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
return result
- ]]
+ end)
eq(3, result[1])
eq(0, result[2])
@@ -559,54 +664,66 @@ describe('vim.diagnostic', function()
end)
it('with buffer argument', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local other_bufnr = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
local result = {}
vim.diagnostic.config({ underline = false, virtual_text = true })
local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 5),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ _G.make_warning('Warning 1', 2, 1, 2, 5),
}
local other_buffer_diags = {
- make_info("This is interesting", 0, 0, 0, 0)
+ _G.make_info('This is interesting', 0, 0, 0, 0),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
- vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr })
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr })
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
- vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr })
+ vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr })
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
vim.diagnostic.enable(false, { bufnr = other_bufnr })
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
return result
- ]]
+ end)
eq(4, result[1])
eq(1, result[2])
@@ -615,44 +732,56 @@ describe('vim.diagnostic', function()
end)
it('with a namespace argument', function()
- local result = exec_lua [[
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
local result = {}
vim.diagnostic.config({ underline = false, virtual_text = true })
local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 5),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ _G.make_warning('Warning 1', 2, 1, 2, 5),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ )
- vim.diagnostic.enable(false, { ns_id = diagnostic_ns })
+ vim.diagnostic.enable(false, { ns_id = _G.diagnostic_ns })
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ )
- vim.diagnostic.enable(true, { ns_id = diagnostic_ns })
+ vim.diagnostic.enable(true, { ns_id = _G.diagnostic_ns })
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ )
- vim.diagnostic.enable(false, { ns_id = other_ns })
+ vim.diagnostic.enable(false, { ns_id = _G.other_ns })
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ )
return result
- ]]
+ end)
eq(3, result[1])
eq(1, result[2])
@@ -662,84 +791,93 @@ describe('vim.diagnostic', function()
--- @return table
local function test_enable(legacy)
- local result = exec_lua(
- [[
- local legacy = ...
+ return exec_lua(function()
local other_bufnr = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
local result = {}
vim.diagnostic.config({ underline = false, virtual_text = true })
local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 5),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ _G.make_warning('Warning 1', 2, 1, 2, 5),
}
local other_buffer_diags = {
- make_info("This is interesting", 0, 0, 0, 0)
+ _G.make_info('This is interesting', 0, 0, 0, 0),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
- vim.diagnostic.set(diagnostic_ns, other_bufnr, other_buffer_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, other_bufnr, other_buffer_diags)
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
if legacy then
- vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns)
+ vim.diagnostic.disable(_G.diagnostic_bufnr, _G.diagnostic_ns)
else
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
end
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
if legacy then
- vim.diagnostic.disable(diagnostic_bufnr, other_ns)
+ vim.diagnostic.disable(_G.diagnostic_bufnr, _G.other_ns)
else
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = other_ns })
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.other_ns })
end
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
if legacy then
- vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns)
+ vim.diagnostic.enable(_G.diagnostic_bufnr, _G.diagnostic_ns)
else
- vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
+ vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
end
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
if legacy then
-- Should have no effect
- vim.diagnostic.disable(other_bufnr, other_ns)
+ vim.diagnostic.disable(other_bufnr, _G.other_ns)
else
-- Should have no effect
- vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = other_ns })
+ vim.diagnostic.enable(false, { bufnr = other_bufnr, ns_id = _G.other_ns })
end
- table.insert(result, count_extmarks(diagnostic_bufnr, diagnostic_ns) +
- count_extmarks(diagnostic_bufnr, other_ns) +
- count_extmarks(other_bufnr, diagnostic_ns))
+ table.insert(
+ result,
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ + _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns)
+ + _G.count_extmarks(other_bufnr, _G.diagnostic_ns)
+ )
return result
- ]],
- legacy
- )
-
- return result
+ end)
end
it('with both buffer and namespace arguments', function()
@@ -772,442 +910,600 @@ describe('vim.diagnostic', function()
local all_highlights = { 1, 1, 2, 4, 2 }
eq(
all_highlights,
- exec_lua [[
- local ns_1_diags = {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 3),
- }
- local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 3),
- }
+ exec_lua(function()
+ local ns_1_diags = {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 2, 1, 2, 3),
+ }
+ local ns_2_diags = {
+ _G.make_warning('Warning 1', 2, 1, 2, 3),
+ }
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diags)
- return {
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- }
- ]]
+ return {
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
)
-- Reset diagnostics from namespace 1
- exec_lua([[ vim.diagnostic.reset(diagnostic_ns) ]])
+ exec_lua([[ vim.diagnostic.reset( _G.diagnostic_ns) ]])
-- Make sure we have the right diagnostic count
eq(
{ 0, 1, 1, 0, 2 },
- exec_lua [[
- local diagnostic_count = {}
- vim.wait(100, function () diagnostic_count = {
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- } end )
- return diagnostic_count
- ]]
+ exec_lua(function()
+ local diagnostic_count = {}
+ vim.wait(100, function()
+ diagnostic_count = {
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
+ return diagnostic_count
+ end)
)
-- Reset diagnostics from namespace 2
- exec_lua([[ vim.diagnostic.reset(other_ns) ]])
+ exec_lua([[ vim.diagnostic.reset(_G.other_ns) ]])
-- Make sure we have the right diagnostic count
eq(
{ 0, 0, 0, 0, 0 },
- exec_lua [[
- local diagnostic_count = {}
- vim.wait(100, function () diagnostic_count = {
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
- count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
- count_extmarks(diagnostic_bufnr, diagnostic_ns),
- count_extmarks(diagnostic_bufnr, other_ns),
- } end )
- return diagnostic_count
- ]]
+ exec_lua(function()
+ local diagnostic_count = {}
+ vim.wait(100, function()
+ diagnostic_count = {
+ _G.count_diagnostics(
+ _G.diagnostic_bufnr,
+ vim.diagnostic.severity.ERROR,
+ _G.diagnostic_ns
+ ),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN, _G.other_ns),
+ _G.count_diagnostics(_G.diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ _G.count_extmarks(_G.diagnostic_bufnr, _G.other_ns),
+ }
+ end)
+ return diagnostic_count
+ end)
)
end)
it("doesn't error after bwipeout called on buffer", function()
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {{ lnum = 0, end_lnum = 0, col = 0, end_col = 0 }})
- vim.cmd("bwipeout! " .. diagnostic_bufnr)
+ exec_lua(function()
+ vim.diagnostic.set(
+ _G.diagnostic_ns,
+ _G.diagnostic_bufnr,
+ { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
+ )
+ vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
- vim.diagnostic.reset(diagnostic_ns)
- ]]
+ vim.diagnostic.reset(_G.diagnostic_ns)
+ end)
end)
end)
- describe('get_next_pos()', function()
+ describe('get_next()', function()
it('can find the next pos with only one namespace', function()
eq(
{ 1, 1 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- return vim.diagnostic.get_next_pos()
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ local next = vim.diagnostic.get_next()
+ return { next.lnum, next.col }
+ end)
)
end)
it('can find next pos with two errors', function()
eq(
{ 4, 4 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- make_error('Diagnostic #2', 4, 4, 4, 4),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
+ return { next.lnum, next.col }
+ end)
)
end)
it('can cycle when position is past error', function()
eq(
{ 1, 1 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
+ return { next.lnum, next.col }
+ end)
)
end)
it('will not cycle when wrap is off', function()
eq(
- false,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_next_pos { namespace = diagnostic_ns, wrap = false }
- ]]
+ nil,
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns, wrap = false })
+ return next
+ end)
)
end)
it('can cycle even from the last line', function()
eq(
{ 4, 4 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #2', 4, 4, 4, 4),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1})
- return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { vim.api.nvim_buf_line_count(0), 1 })
+ local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns })
+ return { prev.lnum, prev.col }
+ end)
)
end)
it('works with diagnostics past the end of the line #16349', function()
eq(
{ 4, 0 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 3, 9001, 3, 9001),
- make_error('Diagnostic #2', 4, 0, 4, 0),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {1, 1})
- vim.diagnostic.goto_next { float = false }
- return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 3, 9001, 3, 9001),
+ _G.make_error('Diagnostic #2', 4, 0, 4, 0),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ vim.diagnostic.jump({ count = 1, float = false })
+ local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
+ return { next.lnum, next.col }
+ end)
)
end)
it('works with diagnostics before the start of the line', function()
eq(
{ 4, 0 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 3, 9001, 3, 9001),
- make_error('Diagnostic #2', 4, -1, 4, -1),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 3, 9001, 3, 9001),
+ _G.make_error('Diagnostic #2', 4, -1, 4, -1),
})
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {1, 1})
- vim.diagnostic.goto_next { float = false }
- return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
- ]]
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ vim.diagnostic.jump({ count = 1, float = false })
+ local next = vim.diagnostic.get_next({ namespace = _G.diagnostic_ns })
+ return { next.lnum, next.col }
+ end)
)
end)
it('jumps to diagnostic with highest severity', function()
- exec_lua([[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_info('Info', 1, 0, 1, 1),
- make_error('Error', 2, 0, 2, 1),
- make_warning('Warning', 3, 0, 3, 1),
- make_error('Error', 4, 0, 4, 1),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_info('Info', 1, 0, 1, 1),
+ _G.make_error('Error', 2, 0, 2, 1),
+ _G.make_warning('Warning', 3, 0, 3, 1),
+ _G.make_error('Error', 4, 0, 4, 1),
})
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {1, 0})
- ]])
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ end)
eq(
{ 3, 0 },
- exec_lua([[
- vim.diagnostic.goto_next({_highest = true})
- return vim.api.nvim_win_get_cursor(0)
- ]])
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1, _highest = true })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
eq(
{ 5, 0 },
- exec_lua([[
- vim.diagnostic.goto_next({_highest = true})
- return vim.api.nvim_win_get_cursor(0)
- ]])
- )
-
- exec_lua([[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_info('Info', 1, 0, 1, 1),
- make_hint('Hint', 2, 0, 2, 1),
- make_warning('Warning', 3, 0, 3, 1),
- make_hint('Hint', 4, 0, 4, 1),
- make_warning('Warning', 5, 0, 5, 1),
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1, _highest = true })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_info('Info', 1, 0, 1, 1),
+ _G.make_hint('Hint', 2, 0, 2, 1),
+ _G.make_warning('Warning', 3, 0, 3, 1),
+ _G.make_hint('Hint', 4, 0, 4, 1),
+ _G.make_warning('Warning', 5, 0, 5, 1),
})
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {1, 0})
- ]])
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ end)
eq(
{ 4, 0 },
- exec_lua([[
- vim.diagnostic.goto_next({_highest = true})
- return vim.api.nvim_win_get_cursor(0)
- ]])
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1, _highest = true })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
eq(
{ 6, 0 },
- exec_lua([[
- vim.diagnostic.goto_next({_highest = true})
- return vim.api.nvim_win_get_cursor(0)
- ]])
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1, _highest = true })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
end)
it('jumps to next diagnostic if severity is non-nil', function()
- exec_lua([[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_info('Info', 1, 0, 1, 1),
- make_error('Error', 2, 0, 2, 1),
- make_warning('Warning', 3, 0, 3, 1),
- make_error('Error', 4, 0, 4, 1),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_info('Info', 1, 0, 1, 1),
+ _G.make_error('Error', 2, 0, 2, 1),
+ _G.make_warning('Warning', 3, 0, 3, 1),
+ _G.make_error('Error', 4, 0, 4, 1),
})
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {1, 0})
- ]])
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ end)
eq(
{ 2, 0 },
- exec_lua([[
- vim.diagnostic.goto_next()
- return vim.api.nvim_win_get_cursor(0)
- ]])
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
eq(
{ 3, 0 },
- exec_lua([[
- vim.diagnostic.goto_next()
- return vim.api.nvim_win_get_cursor(0)
- ]])
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
eq(
{ 4, 0 },
- exec_lua([[
- vim.diagnostic.goto_next()
- return vim.api.nvim_win_get_cursor(0)
- ]])
+ exec_lua(function()
+ vim.diagnostic.jump({ count = 1 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
end)
end)
- describe('get_prev_pos()', function()
- it('can find the prev pos with only one namespace', function()
+ describe('get_prev()', function()
+ it('can find the previous diagnostic with only one namespace', function()
eq(
{ 1, 1 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_prev_pos()
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local prev = vim.diagnostic.get_prev()
+ return { prev.lnum, prev.col }
+ end)
)
end)
- it('can find prev pos with two errors', function()
+ it('can find the previous diagnostic with two errors', function()
eq(
{ 1, 1 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- make_error('Diagnostic #2', 4, 4, 4, 4),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ _G.make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns })
+ return { prev.lnum, prev.col }
+ end)
)
end)
it('can cycle when position is past error', function()
eq(
{ 4, 4 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #2', 4, 4, 4, 4),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns })
+ return { prev.lnum, prev.col }
+ end)
)
end)
it('respects wrap parameter', function()
eq(
- false,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic #2', 4, 4, 4, 4),
- })
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 1})
- return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns, wrap = false}
- ]]
+ nil,
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 1 })
+ local prev = vim.diagnostic.get_prev({ namespace = _G.diagnostic_ns, wrap = false })
+ return prev
+ end)
)
end)
it('works on blank line #28397', function()
eq(
{ 0, 2 },
- exec_lua [[
- local test_bufnr = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, {
- 'first line',
- '',
- '',
- 'end line',
- })
- vim.diagnostic.set(diagnostic_ns, test_bufnr, {
- make_info('Diagnostic #1', 0, 2, 0, 2),
- make_info('Diagnostic #2', 2, 0, 2, 0),
- make_info('Diagnostic #3', 2, 0, 2, 0),
+ exec_lua(function()
+ local test_bufnr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_buf_set_lines(test_bufnr, 0, -1, false, {
+ 'first line',
+ '',
+ '',
+ 'end line',
+ })
+ vim.diagnostic.set(_G.diagnostic_ns, test_bufnr, {
+ _G.make_info('Diagnostic #1', 0, 2, 0, 2),
+ _G.make_info('Diagnostic #2', 2, 0, 2, 0),
+ _G.make_info('Diagnostic #3', 2, 0, 2, 0),
+ })
+ vim.api.nvim_win_set_buf(0, test_bufnr)
+ vim.api.nvim_win_set_cursor(0, { 3, 0 })
+ return vim.diagnostic.get_prev_pos { namespace = _G.diagnostic_ns }
+ end)
+ )
+ end)
+ end)
+
+ describe('jump()', function()
+ before_each(function()
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 0, 0, 0, 2),
+ _G.make_error('Diagnostic #2', 1, 1, 1, 4),
+ _G.make_warning('Diagnostic #3', 2, -1, 2, -1),
+ _G.make_info('Diagnostic #4', 3, 0, 3, 3),
})
- vim.api.nvim_win_set_buf(0, test_bufnr)
- vim.api.nvim_win_set_cursor(0, {3, 0})
- return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns}
- ]]
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ end)
+ end)
+
+ it('can move forward', function()
+ eq(
+ { 2, 1 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.diagnostic.jump({ count = 1 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ eq(
+ { 4, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.diagnostic.jump({ count = 3 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ eq(
+ { 4, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.diagnostic.jump({ count = math.huge, wrap = false })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+ end)
+
+ it('can move backward', function()
+ eq(
+ { 3, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 4, 0 })
+ vim.diagnostic.jump({ count = -1 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ eq(
+ { 1, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 4, 0 })
+ vim.diagnostic.jump({ count = -3 })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ eq(
+ { 1, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 4, 0 })
+ vim.diagnostic.jump({ count = -math.huge, wrap = false })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+ end)
+
+ it('can filter by severity', function()
+ eq(
+ { 3, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ eq(
+ { 3, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+ end)
+
+ it('can wrap', function()
+ eq(
+ { 1, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 4, 0 })
+ vim.diagnostic.jump({ count = 1, wrap = true })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
+ )
+
+ eq(
+ { 4, 0 },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.diagnostic.jump({ count = -1, wrap = true })
+ return vim.api.nvim_win_get_cursor(0)
+ end)
)
end)
end)
describe('get()', function()
it('returns an empty table when no diagnostics are present', function()
- eq({}, exec_lua [[return vim.diagnostic.get(diagnostic_bufnr, {namespace=diagnostic_ns})]])
+ eq(
+ {},
+ exec_lua [[return vim.diagnostic.get( _G.diagnostic_bufnr, {namespace=diagnostic_ns})]]
+ )
end)
it('returns all diagnostics when no severity is supplied', function()
eq(
2,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- })
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ })
- return #vim.diagnostic.get(diagnostic_bufnr)
- ]]
+ return #vim.diagnostic.get(_G.diagnostic_bufnr)
+ end)
)
end)
it('returns only requested diagnostics when severity range is supplied', function()
eq(
{ 2, 3, 2 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- make_info("Ignored information", 1, 1, 2, 3),
- make_hint("Here's a hint", 1, 1, 2, 3),
- })
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ _G.make_info('Ignored information', 1, 1, 2, 3),
+ _G.make_hint("Here's a hint", 1, 1, 2, 3),
+ })
- return {
- #vim.diagnostic.get(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }),
- #vim.diagnostic.get(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }),
- #vim.diagnostic.get(diagnostic_bufnr, {
- severity = {
- min=vim.diagnostic.severity.INFO,
- max=vim.diagnostic.severity.WARN,
- }
- }),
- }
- ]]
+ return {
+ #vim.diagnostic.get(
+ _G.diagnostic_bufnr,
+ { severity = { min = vim.diagnostic.severity.WARN } }
+ ),
+ #vim.diagnostic.get(
+ _G.diagnostic_bufnr,
+ { severity = { max = vim.diagnostic.severity.WARN } }
+ ),
+ #vim.diagnostic.get(_G.diagnostic_bufnr, {
+ severity = {
+ min = vim.diagnostic.severity.INFO,
+ max = vim.diagnostic.severity.WARN,
+ },
+ }),
+ }
+ end)
)
end)
it('returns only requested diagnostics when severities are supplied', function()
eq(
{ 1, 1, 2 },
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- make_info("Ignored information", 1, 1, 2, 3),
- make_hint("Here's a hint", 1, 1, 2, 3),
- })
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ _G.make_info('Ignored information', 1, 1, 2, 3),
+ _G.make_hint("Here's a hint", 1, 1, 2, 3),
+ })
- return {
- #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }),
- #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }),
- #vim.diagnostic.get(diagnostic_bufnr, {
- severity = {
- vim.diagnostic.severity.INFO,
- vim.diagnostic.severity.WARN,
- }
- }),
- }
- ]]
+ return {
+ #vim.diagnostic.get(
+ _G.diagnostic_bufnr,
+ { severity = { vim.diagnostic.severity.WARN } }
+ ),
+ #vim.diagnostic.get(
+ _G.diagnostic_bufnr,
+ { severity = { vim.diagnostic.severity.ERROR } }
+ ),
+ #vim.diagnostic.get(_G.diagnostic_bufnr, {
+ severity = {
+ vim.diagnostic.severity.INFO,
+ vim.diagnostic.severity.WARN,
+ },
+ }),
+ }
+ end)
)
end)
it('allows filtering by line', function()
eq(
2,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- make_info("Ignored information", 1, 1, 2, 3),
- make_error("Error On Other Line", 3, 1, 3, 5),
- })
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ _G.make_info('Ignored information', 1, 1, 2, 3),
+ _G.make_error('Error On Other Line', 3, 1, 3, 5),
+ })
- return #vim.diagnostic.get(diagnostic_bufnr, {lnum = 2})
- ]]
+ return #vim.diagnostic.get(_G.diagnostic_bufnr, { lnum = 2 })
+ end)
)
end)
end)
@@ -1215,118 +1511,144 @@ describe('vim.diagnostic', function()
describe('count', function()
it('returns actually present severity counts', function()
eq(
- exec_lua [[return {
- [vim.diagnostic.severity.ERROR] = 4,
- [vim.diagnostic.severity.WARN] = 3,
- [vim.diagnostic.severity.INFO] = 2,
- [vim.diagnostic.severity.HINT] = 1,
- }]],
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 2),
- make_error("Error 2", 1, 3, 1, 4),
- make_error("Error 3", 1, 5, 1, 6),
- make_error("Error 4", 1, 7, 1, 8),
- make_warning("Warning 1", 2, 1, 2, 2),
- make_warning("Warning 2", 2, 3, 2, 4),
- make_warning("Warning 3", 2, 5, 2, 6),
- make_info("Info 1", 3, 1, 3, 2),
- make_info("Info 2", 3, 3, 3, 4),
- make_hint("Hint 1", 4, 1, 4, 2),
+ exec_lua(function()
+ return {
+ [vim.diagnostic.severity.ERROR] = 4,
+ [vim.diagnostic.severity.WARN] = 3,
+ [vim.diagnostic.severity.INFO] = 2,
+ [vim.diagnostic.severity.HINT] = 1,
+ }
+ end),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 2),
+ _G.make_error('Error 2', 1, 3, 1, 4),
+ _G.make_error('Error 3', 1, 5, 1, 6),
+ _G.make_error('Error 4', 1, 7, 1, 8),
+ _G.make_warning('Warning 1', 2, 1, 2, 2),
+ _G.make_warning('Warning 2', 2, 3, 2, 4),
+ _G.make_warning('Warning 3', 2, 5, 2, 6),
+ _G.make_info('Info 1', 3, 1, 3, 2),
+ _G.make_info('Info 2', 3, 3, 3, 4),
+ _G.make_hint('Hint 1', 4, 1, 4, 2),
})
- return vim.diagnostic.count(diagnostic_bufnr)
- ]]
- )
- eq(
- exec_lua [[return {
- [vim.diagnostic.severity.ERROR] = 2,
- [vim.diagnostic.severity.INFO] = 1,
- }]],
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 2),
- make_error("Error 2", 1, 3, 1, 4),
- make_info("Info 1", 3, 1, 3, 2),
+ return vim.diagnostic.count(_G.diagnostic_bufnr)
+ end)
+ )
+ eq(
+ exec_lua(function()
+ return {
+ [vim.diagnostic.severity.ERROR] = 2,
+ [vim.diagnostic.severity.INFO] = 1,
+ }
+ end),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 2),
+ _G.make_error('Error 2', 1, 3, 1, 4),
+ _G.make_info('Info 1', 3, 1, 3, 2),
})
- return vim.diagnostic.count(diagnostic_bufnr)
- ]]
+ return vim.diagnostic.count(_G.diagnostic_bufnr)
+ end)
)
end)
it('returns only requested diagnostics count when severity range is supplied', function()
eq(
- exec_lua [[return {
- { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 },
- { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.HINT] = 1 },
- { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
- }]],
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- make_info("Ignored information", 1, 1, 2, 3),
- make_hint("Here's a hint", 1, 1, 2, 3),
+ exec_lua(function()
+ return {
+ { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 },
+ {
+ [vim.diagnostic.severity.WARN] = 1,
+ [vim.diagnostic.severity.INFO] = 1,
+ [vim.diagnostic.severity.HINT] = 1,
+ },
+ { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
+ }
+ end),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ _G.make_info('Ignored information', 1, 1, 2, 3),
+ _G.make_hint("Here's a hint", 1, 1, 2, 3),
})
return {
- vim.diagnostic.count(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }),
- vim.diagnostic.count(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }),
- vim.diagnostic.count(diagnostic_bufnr, {
+ vim.diagnostic.count(
+ _G.diagnostic_bufnr,
+ { severity = { min = vim.diagnostic.severity.WARN } }
+ ),
+ vim.diagnostic.count(
+ _G.diagnostic_bufnr,
+ { severity = { max = vim.diagnostic.severity.WARN } }
+ ),
+ vim.diagnostic.count(_G.diagnostic_bufnr, {
severity = {
- min=vim.diagnostic.severity.INFO,
- max=vim.diagnostic.severity.WARN,
- }
+ min = vim.diagnostic.severity.INFO,
+ max = vim.diagnostic.severity.WARN,
+ },
}),
}
- ]]
+ end)
)
end)
it('returns only requested diagnostics when severities are supplied', function()
eq(
- exec_lua [[return {
- { [vim.diagnostic.severity.WARN] = 1 },
- { [vim.diagnostic.severity.ERROR] = 1 },
- { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
- }]],
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- make_info("Ignored information", 1, 1, 2, 3),
- make_hint("Here's a hint", 1, 1, 2, 3),
+ exec_lua(function()
+ return {
+ { [vim.diagnostic.severity.WARN] = 1 },
+ { [vim.diagnostic.severity.ERROR] = 1 },
+ { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 },
+ }
+ end),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ _G.make_info('Ignored information', 1, 1, 2, 3),
+ _G.make_hint("Here's a hint", 1, 1, 2, 3),
})
return {
- vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }),
- vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }),
- vim.diagnostic.count(diagnostic_bufnr, {
+ vim.diagnostic.count(
+ _G.diagnostic_bufnr,
+ { severity = { vim.diagnostic.severity.WARN } }
+ ),
+ vim.diagnostic.count(
+ _G.diagnostic_bufnr,
+ { severity = { vim.diagnostic.severity.ERROR } }
+ ),
+ vim.diagnostic.count(_G.diagnostic_bufnr, {
severity = {
vim.diagnostic.severity.INFO,
vim.diagnostic.severity.WARN,
- }
+ },
}),
}
- ]]
+ end)
)
end)
it('allows filtering by line', function()
eq(
- exec_lua [[return {
- [vim.diagnostic.severity.WARN] = 1,
- [vim.diagnostic.severity.INFO] = 1,
- }]],
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 3),
- make_info("Ignored information", 1, 1, 2, 3),
- make_error("Error On Other Line", 3, 1, 3, 5),
+ exec_lua(function()
+ return {
+ [vim.diagnostic.severity.WARN] = 1,
+ [vim.diagnostic.severity.INFO] = 1,
+ }
+ end),
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 1, 1, 1, 5),
+ _G.make_warning('Warning on Server 1', 1, 1, 2, 3),
+ _G.make_info('Ignored information', 1, 1, 2, 3),
+ _G.make_error('Error On Other Line', 3, 1, 3, 5),
})
- return vim.diagnostic.count(diagnostic_bufnr, {lnum = 2})
- ]]
+ return vim.diagnostic.count(_G.diagnostic_bufnr, { lnum = 2 })
+ end)
)
end)
end)
@@ -1335,137 +1657,138 @@ describe('vim.diagnostic', function()
it('works with global, namespace, and ephemeral options', function()
eq(
1,
- exec_lua [[
- vim.diagnostic.config({
- virtual_text = false,
- })
+ exec_lua(function()
+ vim.diagnostic.config({
+ virtual_text = false,
+ })
- vim.diagnostic.config({
- virtual_text = true,
- underline = false,
- }, diagnostic_ns)
+ vim.diagnostic.config({
+ virtual_text = true,
+ underline = false,
+ }, _G.diagnostic_ns)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Some Error', 4, 4, 4, 4),
- })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Some Error', 4, 4, 4, 4),
+ })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
eq(
1,
- exec_lua [[
- vim.diagnostic.config({
- virtual_text = false,
- })
+ exec_lua(function()
+ vim.diagnostic.config({
+ virtual_text = false,
+ })
- vim.diagnostic.config({
- virtual_text = false,
- underline = false,
- }, diagnostic_ns)
+ vim.diagnostic.config({
+ virtual_text = false,
+ underline = false,
+ }, _G.diagnostic_ns)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Some Error', 4, 4, 4, 4),
- }, {virtual_text = true})
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Some Error', 4, 4, 4, 4),
+ }, { virtual_text = true })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
eq(
0,
- exec_lua [[
- vim.diagnostic.config({
- virtual_text = false,
- })
+ exec_lua(function()
+ vim.diagnostic.config({
+ virtual_text = false,
+ })
- vim.diagnostic.config({
- virtual_text = {severity=vim.diagnostic.severity.ERROR},
- underline = false,
- }, diagnostic_ns)
+ vim.diagnostic.config({
+ virtual_text = { severity = vim.diagnostic.severity.ERROR },
+ underline = false,
+ }, _G.diagnostic_ns)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning('Some Warning', 4, 4, 4, 4),
- }, {virtual_text = true})
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Some Warning', 4, 4, 4, 4),
+ }, { virtual_text = true })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
eq(
1,
- exec_lua [[
- vim.diagnostic.config({
- virtual_text = false,
- })
+ exec_lua(function()
+ vim.diagnostic.config({
+ virtual_text = false,
+ })
- vim.diagnostic.config({
- virtual_text = {severity=vim.diagnostic.severity.ERROR},
- underline = false,
- }, diagnostic_ns)
+ vim.diagnostic.config({
+ virtual_text = { severity = vim.diagnostic.severity.ERROR },
+ underline = false,
+ }, _G.diagnostic_ns)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning('Some Warning', 4, 4, 4, 4),
- }, {
- virtual_text = {} -- An empty table uses default values
- })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Some Warning', 4, 4, 4, 4),
+ }, {
+ virtual_text = {}, -- An empty table uses default values
+ })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
end)
it('can use functions for config values', function()
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
- virtual_text = function() return true end,
- }, diagnostic_ns)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ virtual_text = function()
+ return true
+ end,
+ }, _G.diagnostic_ns)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
})
- ]]
+ end)
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
-- Now, don't enable virtual text.
-- We should have one less extmark displayed.
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
- virtual_text = function() return false end,
- }, diagnostic_ns)
- ]]
+ virtual_text = function()
+ return false
+ end,
+ }, _G.diagnostic_ns)
+ end)
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
end)
it('allows filtering by severity', function()
local get_extmark_count_with_severity = function(min_severity)
- return exec_lua(
- [[
+ return exec_lua(function()
vim.diagnostic.config({
underline = false,
virtual_text = {
- severity = {min=...},
+ severity = { min = min_severity },
},
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning('Delayed Diagnostic', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
})
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]],
- min_severity
- )
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
end
-- No messages with Error or higher
@@ -1477,152 +1800,158 @@ describe('vim.diagnostic', function()
end)
it('allows sorting by severity', function()
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
underline = false,
signs = true,
virtual_text = true,
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning('Warning', 4, 4, 4, 4),
- make_error('Error', 4, 4, 4, 4),
- make_info('Info', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning', 4, 4, 4, 4),
+ _G.make_error('Error', 4, 4, 4, 4),
+ _G.make_info('Info', 4, 4, 4, 4),
})
- function get_virt_text_and_signs(severity_sort)
+ function _G.get_virt_text_and_signs(severity_sort)
vim.diagnostic.config({
severity_sort = severity_sort,
})
- local virt_text = get_virt_text_extmarks(diagnostic_ns)[1][4].virt_text
+ local virt_text = _G.get_virt_text_extmarks(_G.diagnostic_ns)[1][4].virt_text
local virt_texts = {}
for i = 2, #virt_text - 1 do
- table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", "")))
+ table.insert(virt_texts, (string.gsub(virt_text[i][2], 'DiagnosticVirtualText', '')))
end
- local ns = vim.diagnostic.get_namespace(diagnostic_ns)
+ local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
local sign_ns = ns.user_data.sign_ns
local signs = {}
- local all_signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type = 'sign', details = true})
+ local all_signs = vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ sign_ns,
+ 0,
+ -1,
+ { type = 'sign', details = true }
+ )
table.sort(all_signs, function(a, b)
return a[1] > b[1]
end)
for _, v in ipairs(all_signs) do
- local s = v[4].sign_hl_group:gsub('DiagnosticSign', "")
+ local s = v[4].sign_hl_group:gsub('DiagnosticSign', '')
if not vim.tbl_contains(signs, s) then
signs[#signs + 1] = s
end
end
- return {virt_texts, signs}
+ return { virt_texts, signs }
end
- ]]
+ end)
- local result = exec_lua [[return get_virt_text_and_signs(false)]]
+ local result = exec_lua [[return _G.get_virt_text_and_signs(false)]]
-- Virt texts are defined lowest priority to highest, signs from
-- highest to lowest
eq({ 'Warn', 'Error', 'Info' }, result[1])
eq({ 'Info', 'Error', 'Warn' }, result[2])
- result = exec_lua [[return get_virt_text_and_signs(true)]]
+ result = exec_lua [[return _G.get_virt_text_and_signs(true)]]
eq({ 'Info', 'Warn', 'Error' }, result[1])
eq({ 'Error', 'Warn', 'Info' }, result[2])
- result = exec_lua [[return get_virt_text_and_signs({ reverse = true })]]
+ result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]]
eq({ 'Error', 'Warn', 'Info' }, result[1])
eq({ 'Info', 'Warn', 'Error' }, result[2])
end)
it('can show diagnostic sources in virtual text', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local diagnostics = {
- make_error('Some error', 0, 0, 0, 0, 'source x'),
+ _G.make_error('Some error', 0, 0, 0, 0, 'source x'),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
underline = false,
virtual_text = {
prefix = '',
source = 'always',
- }
+ },
})
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
local virt_text = extmarks[1][4].virt_text[3][1]
return virt_text
- ]]
+ end)
eq(' source x: Some error', result)
- result = exec_lua [[
+ result = exec_lua(function()
vim.diagnostic.config({
underline = false,
virtual_text = {
prefix = '',
source = 'if_many',
- }
- }, diagnostic_ns)
+ },
+ }, _G.diagnostic_ns)
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
local virt_text = extmarks[1][4].virt_text[3][1]
return virt_text
- ]]
+ end)
eq(' Some error', result)
- result = exec_lua [[
+ result = exec_lua(function()
local diagnostics = {
- make_error('Some error', 0, 0, 0, 0, 'source x'),
- make_error('Another error', 1, 1, 1, 1, 'source y'),
+ _G.make_error('Some error', 0, 0, 0, 0, 'source x'),
+ _G.make_error('Another error', 1, 1, 1, 1, 'source y'),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
underline = false,
virtual_text = {
prefix = '',
source = 'if_many',
- }
+ },
})
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- local virt_text = {extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1]}
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ local virt_text = { extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1] }
return virt_text
- ]]
+ end)
eq(' source x: Some error', result[1])
eq(' source y: Another error', result[2])
end)
it('supports a format function for diagnostic messages', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
vim.diagnostic.config({
underline = false,
virtual_text = {
prefix = '',
format = function(diagnostic)
if diagnostic.severity == vim.diagnostic.severity.ERROR then
- return string.format("🔥 %s", diagnostic.message)
+ return string.format('🔥 %s', diagnostic.message)
end
- return string.format("👀 %s", diagnostic.message)
+ return string.format('👀 %s', diagnostic.message)
end,
- }
+ },
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning('Warning', 0, 0, 0, 0),
- make_error('Error', 1, 0, 1, 0),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning', 0, 0, 0, 0),
+ _G.make_error('Error', 1, 0, 1, 0),
})
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- return {extmarks[1][4].virt_text, extmarks[2][4].virt_text}
- ]]
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ return { extmarks[1][4].virt_text, extmarks[2][4].virt_text }
+ end)
eq(' 👀 Warning', result[1][3][1])
eq(' 🔥 Error', result[2][3][1])
end)
it('includes source for formatted diagnostics', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
vim.diagnostic.config({
underline = false,
virtual_text = {
@@ -1630,21 +1959,21 @@ describe('vim.diagnostic', function()
source = 'always',
format = function(diagnostic)
if diagnostic.severity == vim.diagnostic.severity.ERROR then
- return string.format("🔥 %s", diagnostic.message)
+ return string.format('🔥 %s', diagnostic.message)
end
- return string.format("👀 %s", diagnostic.message)
+ return string.format('👀 %s', diagnostic.message)
end,
- }
+ },
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning('Warning', 0, 0, 0, 0, 'some_linter'),
- make_error('Error', 1, 0, 1, 0, 'another_linter'),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning', 0, 0, 0, 0, 'some_linter'),
+ _G.make_error('Error', 1, 0, 1, 0, 'another_linter'),
})
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- return {extmarks[1][4].virt_text, extmarks[2][4].virt_text}
- ]]
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ return { extmarks[1][4].virt_text, extmarks[2][4].virt_text }
+ end)
eq(' some_linter: 👀 Warning', result[1][3][1])
eq(' another_linter: 🔥 Error', result[2][3][1])
end)
@@ -1652,90 +1981,94 @@ describe('vim.diagnostic', function()
it('can add a prefix to virtual text', function()
eq(
'E 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 = 'E',
- suffix = '',
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Some error', 0, 0, 0, 0),
}
- })
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- local prefix = extmarks[1][4].virt_text[2][1]
- local message = extmarks[1][4].virt_text[3][1]
- return prefix .. message
- ]]
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = 'E',
+ suffix = '',
+ },
+ })
+
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ local prefix = extmarks[1][4].virt_text[2][1]
+ local message = extmarks[1][4].virt_text[3][1]
+ return prefix .. message
+ end)
)
eq(
'[(1/1) err-code] Some error',
- 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 = function(diag, i, total) return string.format('[(%d/%d) %s]', i, total, diag.code) end,
- suffix = '',
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'),
}
- })
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- local prefix = extmarks[1][4].virt_text[2][1]
- local message = extmarks[1][4].virt_text[3][1]
- return prefix .. message
- ]]
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = function(diag, i, total)
+ return string.format('[(%d/%d) %s]', i, total, diag.code)
+ end,
+ suffix = '',
+ },
+ })
+
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ local prefix = extmarks[1][4].virt_text[2][1]
+ local message = extmarks[1][4].virt_text[3][1]
+ return prefix .. message
+ end)
)
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 = ' ✘',
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Some error', 0, 0, 0, 0),
}
- })
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- local virt_text = extmarks[1][4].virt_text[3][1]
- return virt_text
- ]]
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ suffix = ' ✘',
+ },
+ })
+
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ local virt_text = extmarks[1][4].virt_text[3][1]
+ return virt_text
+ end)
)
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,
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Some error', 0, 0, 0, 0, nil, 'err-code'),
}
- })
- local extmarks = get_virt_text_extmarks(diagnostic_ns)
- local virt_text = extmarks[1][4].virt_text[3][1]
- return virt_text
- ]]
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ suffix = function(diag)
+ return string.format(' [%s]', diag.code)
+ end,
+ },
+ })
+
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ local virt_text = extmarks[1][4].virt_text[3][1]
+ return virt_text
+ end)
)
end)
end)
@@ -1749,80 +2082,80 @@ describe('vim.diagnostic', function()
end)
it('can perform updates after insert_leave', function()
- exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
api.nvim_input('o')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
-- Save the diagnostics
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
update_in_insert = false,
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
})
- ]]
+ end)
-- No diagnostics displayed yet.
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
api.nvim_input('<esc>')
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
end)
it('does not perform updates when not needed', function()
- exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
api.nvim_input('o')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
-- Save the diagnostics
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
update_in_insert = false,
virtual_text = true,
})
- DisplayCount = 0
+ _G.DisplayCount = 0
local set_virtual_text = vim.diagnostic.handlers.virtual_text.show
vim.diagnostic.handlers.virtual_text.show = function(...)
- DisplayCount = DisplayCount + 1
+ _G.DisplayCount = _G.DisplayCount + 1
return set_virtual_text(...)
end
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
})
- ]]
+ end)
-- No diagnostics displayed yet.
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
- eq(0, exec_lua [[return DisplayCount]])
+ eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
+ eq(0, exec_lua [[return _G.DisplayCount]])
api.nvim_input('<esc>')
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
- eq(1, exec_lua [[return DisplayCount]])
+ eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
+ eq(1, exec_lua [[return _G.DisplayCount]])
-- Go in and out of insert mode one more time.
api.nvim_input('o')
@@ -1832,52 +2165,51 @@ describe('vim.diagnostic', function()
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
-- Should not have set the virtual text again.
- eq(1, exec_lua [[return DisplayCount]])
+ eq(1, exec_lua [[return _G.DisplayCount]])
end)
it('never sets virtual text, in combination with insert leave', function()
- exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
api.nvim_input('o')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
-- Save the diagnostics
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
update_in_insert = false,
virtual_text = false,
})
-
- DisplayCount = 0
+ _G.DisplayCount = 0
local set_virtual_text = vim.diagnostic.handlers.virtual_text.show
vim.diagnostic.handlers.virtual_text.show = function(...)
- DisplayCount = DisplayCount + 1
+ _G.DisplayCount = _G.DisplayCount + 1
return set_virtual_text(...)
end
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
})
- ]]
+ end)
-- No diagnostics displayed yet.
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
- eq(0, exec_lua [[return DisplayCount]])
+ eq(0, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
+ eq(0, exec_lua [[return _G.DisplayCount]])
api.nvim_input('<esc>')
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
- eq(0, exec_lua [[return DisplayCount]])
+ eq(1, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
+ eq(0, exec_lua [[return _G.DisplayCount]])
-- Go in and out of insert mode one more time.
api.nvim_input('o')
@@ -1887,124 +2219,136 @@ describe('vim.diagnostic', function()
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
-- Should not have set the virtual text still.
- eq(0, exec_lua [[return DisplayCount]])
+ eq(0, exec_lua [[return _G.DisplayCount]])
end)
it('can perform updates while in insert mode, if desired', function()
- exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
api.nvim_input('o')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
-- Save the diagnostics
- exec_lua [[
+ exec_lua(function()
vim.diagnostic.config({
update_in_insert = true,
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
})
- ]]
+ end)
-- Diagnostics are displayed, because the user wanted them that way!
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
api.nvim_input('<esc>')
eq({ mode = 'n', blocking = false }, api.nvim_get_mode())
eq(
1,
- exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]
+ exec_lua [[return _G.count_diagnostics( _G.diagnostic_bufnr, vim.diagnostic.severity.ERROR, _G.diagnostic_ns)]]
)
- eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(2, exec_lua [[return _G.count_extmarks( _G.diagnostic_bufnr, _G.diagnostic_ns)]])
end)
it('can set diagnostics without displaying them', function()
eq(
0,
- exec_lua [[
- vim.diagnostic.enable(false, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
- })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ exec_lua(function()
+ vim.diagnostic.enable(false, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ })
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
eq(
2,
- exec_lua [[
- vim.diagnostic.enable(true, { bufnr = diagnostic_bufnr, ns_id = diagnostic_ns })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ exec_lua(function()
+ vim.diagnostic.enable(true, { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns })
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
end)
it('can set display options', function()
eq(
0,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
- }, { virtual_text = false, underline = false })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ }, { virtual_text = false, underline = false })
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
eq(
1,
- exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
- }, { virtual_text = true, underline = false })
- return count_extmarks(diagnostic_bufnr, diagnostic_ns)
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ }, { virtual_text = true, underline = false })
+ return _G.count_extmarks(_G.diagnostic_bufnr, _G.diagnostic_ns)
+ end)
)
end)
it('sets and clears signs #26193 #26555', function()
do
- local result = exec_lua [[
+ local result = exec_lua(function()
vim.diagnostic.config({
signs = true,
})
local diagnostics = {
- make_error('Error', 1, 1, 1, 2),
- make_warning('Warning', 3, 3, 3, 3),
+ _G.make_error('Error', 1, 1, 1, 2),
+ _G.make_warning('Warning', 3, 3, 3, 3),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
- local ns = vim.diagnostic.get_namespace(diagnostic_ns)
+ local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
local sign_ns = ns.user_data.sign_ns
- local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true})
+ local signs = vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ sign_ns,
+ 0,
+ -1,
+ { type = 'sign', details = true }
+ )
local result = {}
for _, s in ipairs(signs) do
result[#result + 1] = { lnum = s[2] + 1, name = s[4].sign_hl_group }
end
return result
- ]]
+ end)
eq({ 2, 'DiagnosticSignError' }, { result[1].lnum, result[1].name })
eq({ 4, 'DiagnosticSignWarn' }, { result[2].lnum, result[2].name })
end
do
- local result = exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {})
+ local result = exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {})
- local ns = vim.diagnostic.get_namespace(diagnostic_ns)
+ local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
local sign_ns = ns.user_data.sign_ns
- return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true})
- ]]
+ return vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ sign_ns,
+ 0,
+ -1,
+ { type = 'sign', details = true }
+ )
+ end)
eq({}, result)
end
@@ -2019,22 +2363,28 @@ describe('vim.diagnostic', function()
n.command('sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined')
n.command('sign define DiagnosticSignHint text= texthl= linehl=Underlined numhl=Underlined')
- local result = exec_lua [[
+ local result = exec_lua(function()
vim.diagnostic.config({
signs = true,
})
local diagnostics = {
- make_error('Error', 1, 1, 1, 2),
- make_warning('Warning', 3, 3, 3, 3),
+ _G.make_error('Error', 1, 1, 1, 2),
+ _G.make_warning('Warning', 3, 3, 3, 3),
}
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
- local ns = vim.diagnostic.get_namespace(diagnostic_ns)
+ local ns = vim.diagnostic.get_namespace(_G.diagnostic_ns)
local sign_ns = ns.user_data.sign_ns
- local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true})
+ local signs = vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ sign_ns,
+ 0,
+ -1,
+ { type = 'sign', details = true }
+ )
local result = {}
for _, s in ipairs(signs) do
result[#result + 1] = {
@@ -2046,7 +2396,7 @@ describe('vim.diagnostic', function()
}
end
return result
- ]]
+ end)
eq({
lnum = 2,
@@ -2070,65 +2420,67 @@ describe('vim.diagnostic', function()
it('can display a header', function()
eq(
{ 'Diagnostics:', '1. Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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()
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float()
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ "We're no strangers to love...", '1. Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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 = "We're no strangers to love..."})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float({ header = "We're no strangers to love..." })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ 'You know the rules', '1. Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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 = {'You know the rules', 'Search'}})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float({ header = { 'You know the rules', 'Search' } })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
it('can show diagnostics from the whole buffer', function()
eq(
{ '1. Syntax error', '2. Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_warning("Some warning", 1, 1, 1, 3),
- }
- 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
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_warning('Some warning', 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.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
+ end)
)
end)
@@ -2136,37 +2488,70 @@ describe('vim.diagnostic', function()
-- Using cursor position
eq(
{ '1. Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_warning("Some warning", 1, 1, 1, 3),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- vim.api.nvim_win_set_cursor(0, {2, 1})
- local float_bufnr, winnr = vim.diagnostic.open_float({header=false})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_warning('Some warning', 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 2, 1 })
+ local float_bufnr, winnr = vim.diagnostic.open_float({ header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
-- With specified position
eq(
{ '1. Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_warning("Some warning", 1, 1, 1, 3),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- vim.api.nvim_win_set_cursor(0, {1, 1})
- local float_bufnr, winnr = vim.diagnostic.open_float({header=false, pos=1})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_warning('Some warning', 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, pos = 1 })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
+ )
+
+ -- End position is exclusive
+ eq(
+ nil,
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 1, 1, 2, 0),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local _, winnr = vim.diagnostic.open_float(0, { header = false, pos = { 2, 0 } })
+ return winnr
+ end)
+ )
+
+ -- Works when width == 0
+ eq(
+ { '1. Syntax error' },
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 2, 0, 2, 0),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(0, { header = false, pos = { 2, 1 } })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
@@ -2174,55 +2559,94 @@ describe('vim.diagnostic', function()
-- Using cursor position
eq(
{ 'Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 1, 1, 1, 2),
- make_warning("Some warning", 1, 3, 1, 4),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- vim.api.nvim_win_set_cursor(0, {2, 2})
- local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor"})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 1, 1, 1, 3),
+ _G.make_warning('Some warning', 1, 3, 1, 4),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 2, 2 })
+ local float_bufnr, winnr = vim.diagnostic.open_float({ header = false, scope = 'cursor' })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
-- With specified position
eq(
{ 'Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 1, 1, 1, 2),
- make_warning("Some warning", 1, 3, 1, 4),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- vim.api.nvim_win_set_cursor(0, {1, 1})
- local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={1,3}})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 1, 1, 1, 3),
+ _G.make_warning('Some warning', 1, 3, 1, 4),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 1, 3 } })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
-- With column position past the end of the line. #16062
eq(
{ 'Syntax error' },
- exec_lua [[
- local first_line_len = #vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, 1, true)[1]
- local diagnostics = {
- make_error("Syntax error", 0, first_line_len + 1, 1, 0),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- vim.api.nvim_win_set_cursor(0, {1, 1})
- local float_bufnr, winnr = vim.diagnostic.open_float({header=false, scope="cursor", pos={0,first_line_len}})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local first_line_len = #vim.api.nvim_buf_get_lines(_G.diagnostic_bufnr, 0, 1, true)[1]
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, first_line_len + 1, 1, 0),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local float_bufnr, winnr = vim.diagnostic.open_float({
+ header = false,
+ scope = 'cursor',
+ pos = { 0, first_line_len },
+ })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
+ )
+
+ -- End position is exclusive
+ eq(
+ nil,
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local _, winnr =
+ vim.diagnostic.open_float(0, { header = false, scope = 'cursor', pos = { 1, 3 } })
+ return winnr
+ end)
+ )
+
+ -- Works when width == 0
+ eq(
+ { 'Syntax error' },
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 2, 0, 2, 0),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ vim.api.nvim_win_set_cursor(0, { 1, 1 })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float({ header = false, scope = 'cursor', pos = { 2, 1 } })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
@@ -2234,17 +2658,17 @@ describe('vim.diagnostic', function()
-- 1. <msg>
eq(
2,
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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(diagnostic_bufnr)
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return #lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr)
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return #lines
+ end)
)
end
)
@@ -2252,43 +2676,44 @@ describe('vim.diagnostic', function()
it('only reports diagnostics from the current buffer when bufnr is omitted #15710', function()
eq(
2,
- exec_lua [[
- local other_bufnr = vim.api.nvim_create_buf(true, false)
- local buf_1_diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- local buf_2_diagnostics = {
- make_warning("Some warning", 0, 1, 0, 3),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, buf_1_diagnostics)
- vim.diagnostic.set(other_ns, other_bufnr, buf_2_diagnostics)
- local float_bufnr, winnr = vim.diagnostic.open_float()
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return #lines
- ]]
+ exec_lua(function()
+ local other_bufnr = vim.api.nvim_create_buf(true, false)
+ local buf_1_diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ local buf_2_diagnostics = {
+ _G.make_warning('Some warning', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, buf_1_diagnostics)
+ vim.diagnostic.set(_G.other_ns, other_bufnr, buf_2_diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float()
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return #lines
+ end)
)
end)
it('allows filtering by namespace', function()
eq(
2,
- exec_lua [[
- local ns_1_diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- local ns_2_diagnostics = {
- make_warning("Some warning", 0, 1, 0, 3),
- }
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diagnostics)
- vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diagnostics)
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {namespace = diagnostic_ns})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return #lines
- ]]
+ exec_lua(function()
+ local ns_1_diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ local ns_2_diagnostics = {
+ _G.make_warning('Some warning', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, ns_1_diagnostics)
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, ns_2_diagnostics)
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { namespace = _G.diagnostic_ns })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return #lines
+ end)
)
end)
@@ -2299,17 +2724,18 @@ describe('vim.diagnostic', function()
-- 1. <msg>
eq(
1,
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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(diagnostic_bufnr, {header = false})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return #lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return #lines
+ end)
)
end
)
@@ -2317,138 +2743,141 @@ describe('vim.diagnostic', function()
it('clamps diagnostic line numbers within the valid range', function()
eq(
1,
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 6, 0, 6, 0),
- }
- 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(diagnostic_bufnr, {header = false, pos = 5})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return #lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 6, 0, 6, 0),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false, pos = 5 })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return #lines
+ end)
)
end)
it('can show diagnostic source', function()
- exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]]
+ exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]]
eq(
{ '1. Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3, "source x"),
- }
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {
- header = false,
- source = "if_many",
- })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'),
+ }
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, {
+ header = false,
+ source = 'if_many',
+ })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ '1. source x: Syntax error' },
- exec_lua [[
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {
- header = false,
- source = "always",
- })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, {
+ header = false,
+ source = 'always',
+ })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ '1. source x: Syntax error', '2. source y: Another error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3, "source x"),
- make_error("Another error", 0, 1, 0, 3, "source y"),
- }
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, {
- header = false,
- source = "if_many",
- })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3, 'source x'),
+ _G.make_error('Another error', 0, 1, 0, 3, 'source y'),
+ }
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float(_G.diagnostic_bufnr, {
+ header = false,
+ source = 'if_many',
+ })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
it('respects severity_sort', function()
- exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]]
+ exec_lua [[vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)]]
eq(
{ '1. Syntax error', '2. Info', '3. Error', '4. Warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_info('Info', 0, 3, 0, 4),
- make_error('Error', 0, 2, 0, 2),
- make_warning('Warning', 0, 0, 0, 1),
- }
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_info('Info', 0, 3, 0, 4),
+ _G.make_error('Error', 0, 2, 0, 2),
+ _G.make_warning('Warning', 0, 0, 0, 1),
+ }
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
- vim.diagnostic.config({severity_sort = false})
+ vim.diagnostic.config({ severity_sort = false })
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ '1. Syntax error', '2. Error', '3. Warning', '4. Info' },
- exec_lua [[
- vim.diagnostic.config({severity_sort = true})
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ vim.diagnostic.config({ severity_sort = true })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ '1. Info', '2. Warning', '3. Error', '4. Syntax error' },
- exec_lua [[
- vim.diagnostic.config({severity_sort = { reverse = true } })
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ vim.diagnostic.config({ severity_sort = { reverse = true } })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
it('can filter by severity', function()
local count_diagnostics_with_severity = function(min_severity, max_severity)
- return exec_lua(
- [[
- local min_severity, max_severity = ...
+ return exec_lua(function()
vim.diagnostic.config({
float = {
- severity = {min=min_severity, max=max_severity},
+ severity = { min = min_severity, max = max_severity },
},
})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error("Syntax error", 0, 1, 0, 3),
- make_info('Info', 0, 3, 0, 4),
- make_error('Error', 0, 2, 0, 2),
- make_warning('Warning', 0, 0, 0, 1),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_info('Info', 0, 3, 0, 4),
+ _G.make_error('Error', 0, 2, 0, 2),
+ _G.make_warning('Warning', 0, 0, 0, 1),
})
- local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(_G.diagnostic_bufnr, { header = false })
if not float_bufnr then
return 0
end
@@ -2456,10 +2885,7 @@ describe('vim.diagnostic', function()
local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
vim.api.nvim_win_close(winnr, true)
return #lines
- ]],
- min_severity,
- max_severity
- )
+ end)
end
eq(2, count_diagnostics_with_severity('ERROR'))
@@ -2473,83 +2899,84 @@ describe('vim.diagnostic', function()
-- Default is to add a number
eq(
{ '1. Syntax error', '2. Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_warning("Some warning", 1, 1, 1, 3),
- }
- 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
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_warning('Some warning', 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.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
+ end)
)
eq(
{ 'Syntax error', 'Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_warning("Some warning", 1, 1, 1, 3),
- }
- 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", prefix = ""})
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_warning('Some warning', 1, 1, 1, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float({ header = false, scope = 'buffer', prefix = '' })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ '1. Syntax error', '2. Some warning' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- make_warning("Some warning", 0, 1, 0, 3),
- }
- 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,
- prefix = function(_, i, total)
- -- Only show a number if there is more than one diagnostic
- if total > 1 then
- return string.format("%d. ", i)
- end
- return ""
- end,
- })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ _G.make_warning('Some warning', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float({
+ header = false,
+ prefix = function(_, i, total)
+ -- Only show a number if there is more than one diagnostic
+ if total > 1 then
+ return string.format('%d. ', i)
+ end
+ return ''
+ end,
+ })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
{ 'Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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,
- prefix = function(_, i, total)
- -- Only show a number if there is more than one diagnostic
- if total > 1 then
- return string.format("%d. ", i)
- end
- return ""
- end,
- })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float({
+ header = false,
+ prefix = function(_, i, total)
+ -- Only show a number if there is more than one diagnostic
+ if total > 1 then
+ return string.format('%d. ', i)
+ end
+ return ''
+ end,
+ })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
eq(
@@ -2562,50 +2989,51 @@ describe('vim.diagnostic', 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
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'),
+ _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.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
+ end)
)
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
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3, nil, 'code-x'),
+ _G.make_warning('Some warning', 1, 1, 1, 3, nil, 'code-y'),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.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
+ end)
)
-- 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
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error\nMore context', 0, 1, 0, 3, nil, 'code-x'),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.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
+ end)
)
eq(
@@ -2617,96 +3045,134 @@ describe('vim.diagnostic', function()
it('works with the old signature', function()
eq(
{ '1. Syntax error' },
- exec_lua [[
- local diagnostics = {
- make_error("Syntax error", 0, 1, 0, 3),
- }
- 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(0, { header = false })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ local diagnostics = {
+ _G.make_error('Syntax error', 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
it('works for multi-line diagnostics #21949', function()
- -- open float failed non diagnostic lnum
- eq(
- vim.NIL,
- exec_lua [[
+ -- create diagnostic
+ exec_lua(function()
local diagnostics = {
- make_error("Error in two lines lnum is 1 and end_lnum is 2", 1, 1, 2, 3),
+ _G.make_error('Error in two lines lnum is 1 and end_lnum is 2', 1, 1, 2, 3),
}
- local winids = {}
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
- local _, winnr = vim.diagnostic.open_float(0, { header = false })
- return winnr
- ]]
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, diagnostics)
+ end)
+
+ -- open float failed non diagnostic lnum
+ eq(
+ nil,
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ local _, winnr = vim.diagnostic.open_float(0, { header = false })
+ return winnr
+ end)
+ )
+ eq(
+ nil,
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ local _, winnr = vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
+ return winnr
+ end)
)
-- can open a float window on lnum 1
eq(
{ '1. Error in two lines lnum is 1 and end_lnum is 2' },
- exec_lua [[
- vim.api.nvim_win_set_cursor(0, {2, 0})
- local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 2, 0 })
+ local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
+ )
+
+ -- can open a cursor-scoped float window on lnum 1
+ eq(
+ { 'Error in two lines lnum is 1 and end_lnum is 2' },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 2, 1 })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
-- can open a float window on end_lnum 2
eq(
{ '1. Error in two lines lnum is 1 and end_lnum is 2' },
- exec_lua [[
- vim.api.nvim_win_set_cursor(0, {3, 0})
- local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false })
- local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
- vim.api.nvim_win_close(winnr, true)
- return lines
- ]]
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 3, 0 })
+ local float_bufnr, winnr = vim.diagnostic.open_float(0, { header = false })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
+ )
+
+ -- can open a cursor-scoped float window on end_lnum 2
+ eq(
+ { 'Error in two lines lnum is 1 and end_lnum is 2' },
+ exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 3, 2 })
+ local float_bufnr, winnr =
+ vim.diagnostic.open_float(0, { header = false, scope = 'cursor' })
+ local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ end)
)
end)
end)
describe('setloclist()', function()
it('sets diagnostics in lnum order', function()
- local loc_list = exec_lua [[
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ local loc_list = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Farther Diagnostic', 4, 4, 4, 4),
- make_error('Lower Diagnostic', 1, 1, 1, 1),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Farther Diagnostic', 4, 4, 4, 4),
+ _G.make_error('Lower Diagnostic', 1, 1, 1, 1),
})
vim.diagnostic.setloclist()
return vim.fn.getloclist(0)
- ]]
+ end)
assert(loc_list[1].lnum < loc_list[2].lnum)
end)
it('sets diagnostics in lnum order, regardless of namespace', function()
- local loc_list = exec_lua [[
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ local loc_list = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Lower Diagnostic', 1, 1, 1, 1),
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Lower Diagnostic', 1, 1, 1, 1),
})
- vim.diagnostic.set(other_ns, diagnostic_bufnr, {
- make_warning('Farther Diagnostic', 4, 4, 4, 4),
+ vim.diagnostic.set(_G.other_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Farther Diagnostic', 4, 4, 4, 4),
})
vim.diagnostic.setloclist()
return vim.fn.getloclist(0)
- ]]
+ end)
assert(loc_list[1].lnum < loc_list[2].lnum)
end)
@@ -2725,22 +3191,23 @@ describe('vim.diagnostic', function()
}
eq(
diagnostic,
- exec_lua(
- [[
- return vim.diagnostic.match(..., "^(%w+): [^:]+:(%d+):(%d+):(.+)$", {"severity", "lnum", "col", "message"})
- ]],
- msg
- )
+ exec_lua(function()
+ return vim.diagnostic.match(
+ msg,
+ '^(%w+): [^:]+:(%d+):(%d+):(.+)$',
+ { 'severity', 'lnum', 'col', 'message' }
+ )
+ end)
)
end)
it('returns nil if the pattern fails to match', function()
eq(
- NIL,
- exec_lua [[
- local msg = "The answer to life, the universe, and everything is"
- return vim.diagnostic.match(msg, "This definitely will not match", {})
- ]]
+ nil,
+ exec_lua(function()
+ local msg = 'The answer to life, the universe, and everything is'
+ return vim.diagnostic.match(msg, 'This definitely will not match', {})
+ end)
)
end)
@@ -2756,12 +3223,15 @@ describe('vim.diagnostic', function()
}
eq(
diagnostic,
- exec_lua(
- [[
- return vim.diagnostic.match(..., "^[^:]+:(%d+):(.+)$", {"lnum", "message"}, nil, {severity = vim.diagnostic.severity.INFO})
- ]],
- msg
- )
+ exec_lua(function()
+ return vim.diagnostic.match(
+ msg,
+ '^[^:]+:(%d+):(.+)$',
+ { 'lnum', 'message' },
+ nil,
+ { severity = vim.diagnostic.severity.INFO }
+ )
+ end)
)
end)
@@ -2777,38 +3247,40 @@ describe('vim.diagnostic', function()
}
eq(
diagnostic,
- exec_lua(
- [[
- return vim.diagnostic.match(..., "^(%d+):(%w+):(.+)$", {"lnum", "severity", "message"}, {FATAL = vim.diagnostic.severity.ERROR})
- ]],
- msg
- )
+ exec_lua(function()
+ return vim.diagnostic.match(
+ msg,
+ '^(%d+):(%w+):(.+)$',
+ { 'lnum', 'severity', 'message' },
+ { FATAL = vim.diagnostic.severity.ERROR }
+ )
+ end)
)
end)
end)
describe('toqflist() and fromqflist()', function()
it('works', function()
- local result = exec_lua [[
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_error('Error 1', 0, 1, 0, 1),
- make_error('Error 2', 1, 1, 1, 1),
- make_warning('Warning', 2, 2, 2, 2),
- })
+ local result = exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error 1', 0, 1, 0, 1),
+ _G.make_error('Error 2', 1, 1, 1, 1),
+ _G.make_warning('Warning', 2, 2, 2, 2),
+ })
- local diagnostics = vim.diagnostic.get(diagnostic_bufnr)
- vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics))
- local list = vim.fn.getqflist()
- local new_diagnostics = vim.diagnostic.fromqflist(list)
+ local diagnostics = vim.diagnostic.get(_G.diagnostic_bufnr)
+ vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics))
+ local list = vim.fn.getqflist()
+ local new_diagnostics = vim.diagnostic.fromqflist(list)
- -- Remove namespace since it isn't present in the return value of
- -- fromlist()
- for _, v in ipairs(diagnostics) do
- v.namespace = nil
- end
+ -- Remove namespace since it isn't present in the return value of
+ -- fromlist()
+ for _, v in ipairs(diagnostics) do
+ v.namespace = nil
+ end
- return {diagnostics, new_diagnostics}
- ]]
+ return { diagnostics, new_diagnostics }
+ end)
eq(result[1], result[2])
end)
end)
@@ -2828,179 +3300,181 @@ describe('vim.diagnostic', function()
it('can add new handlers', function()
eq(
true,
- exec_lua [[
- local handler_called = false
- vim.diagnostic.handlers.test = {
- show = function(namespace, bufnr, diagnostics, opts)
- assert(namespace == diagnostic_ns)
- assert(bufnr == diagnostic_bufnr)
- assert(#diagnostics == 1)
- assert(opts.test.some_opt == 42)
- handler_called = true
- end,
- }
+ exec_lua(function()
+ local handler_called = false
+ vim.diagnostic.handlers.test = {
+ show = function(namespace, bufnr, diagnostics, opts)
+ assert(namespace == _G.diagnostic_ns)
+ assert(bufnr == _G.diagnostic_bufnr)
+ assert(#diagnostics == 1)
+ assert(opts.test.some_opt == 42)
+ handler_called = true
+ end,
+ }
- vim.diagnostic.config({test = {some_opt = 42}})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning("Warning", 0, 0, 0, 0),
- })
- return handler_called
- ]]
+ vim.diagnostic.config({ test = { some_opt = 42 } })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning', 0, 0, 0, 0),
+ })
+ return handler_called
+ end)
)
end)
it('can disable handlers by setting the corresponding option to false', function()
eq(
false,
- exec_lua [[
- local handler_called = false
- vim.diagnostic.handlers.test = {
- show = function(namespace, bufnr, diagnostics, opts)
- handler_called = true
- end,
- }
+ exec_lua(function()
+ local handler_called = false
+ vim.diagnostic.handlers.test = {
+ show = function(_, _, _, _)
+ handler_called = true
+ end,
+ }
- vim.diagnostic.config({test = false})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning("Warning", 0, 0, 0, 0),
- })
- return handler_called
- ]]
+ vim.diagnostic.config({ test = false })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning', 0, 0, 0, 0),
+ })
+ return handler_called
+ end)
)
end)
it("always calls a handler's hide function if defined", function()
eq(
{ false, true },
- exec_lua [[
- local hide_called = false
- local show_called = false
- vim.diagnostic.handlers.test = {
- show = function(namespace, bufnr, diagnostics, opts)
- show_called = true
- end,
- hide = function(namespace, bufnr)
- assert(namespace == diagnostic_ns)
- assert(bufnr == diagnostic_bufnr)
- hide_called = true
- end,
- }
+ exec_lua(function()
+ local hide_called = false
+ local show_called = false
+ vim.diagnostic.handlers.test = {
+ show = function(_, _, _, _)
+ show_called = true
+ end,
+ hide = function(namespace, bufnr)
+ assert(namespace == _G.diagnostic_ns)
+ assert(bufnr == _G.diagnostic_bufnr)
+ hide_called = true
+ end,
+ }
- vim.diagnostic.config({test = false})
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
- make_warning("Warning", 0, 0, 0, 0),
- })
- vim.diagnostic.hide(diagnostic_ns, diagnostic_bufnr)
- return {show_called, hide_called}
- ]]
+ vim.diagnostic.config({ test = false })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_warning('Warning', 0, 0, 0, 0),
+ })
+ vim.diagnostic.hide(_G.diagnostic_ns, _G.diagnostic_bufnr)
+ return { show_called, hide_called }
+ end)
)
end)
it('triggers the autocommand when diagnostics are set', function()
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)
-
- 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 {
- triggered[1] == diagnostic_bufnr,
- triggered[2] == 1,
- }
- ]]
+ exec_lua(function()
+ -- 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)
+
+ local triggered = {}
+ vim.api.nvim_create_autocmd('DiagnosticChanged', {
+ callback = function(args)
+ triggered = { args.buf, #args.data.diagnostics }
+ end,
+ })
+ vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test')
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic', 0, 0, 0, 0),
+ })
+ return {
+ triggered[1] == _G.diagnostic_bufnr,
+ triggered[2] == 1,
+ }
+ end)
)
end)
it('triggers the autocommand when diagnostics are cleared', function()
eq(
true,
- exec_lua [[
- 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>")')
- vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test")
- vim.diagnostic.reset(diagnostic_ns, diagnostic_bufnr)
- return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr
- ]]
+ exec_lua(function()
+ 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>")'
+ )
+ vim.api.nvim_buf_set_name(_G.diagnostic_bufnr, 'test | test')
+ vim.diagnostic.reset(_G.diagnostic_ns, _G.diagnostic_bufnr)
+ return vim.g.diagnostic_autocmd_triggered == _G.diagnostic_bufnr
+ end)
)
end)
it('is_enabled', function()
eq(
{ false, false, false, false, false },
- 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.enable(false)
- return {
- vim.diagnostic.is_enabled(),
- vim.diagnostic.is_enabled{ bufnr = 0 },
- vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr },
- vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns },
- vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns },
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
+ vim.diagnostic.enable(false)
+ return {
+ vim.diagnostic.is_enabled(),
+ vim.diagnostic.is_enabled { bufnr = 0 },
+ vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr },
+ vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns },
+ vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns },
+ }
+ end)
)
eq(
{ true, true, true, true, true },
- exec_lua [[
- vim.diagnostic.enable()
- return {
- vim.diagnostic.is_enabled(),
- vim.diagnostic.is_enabled{ bufnr = 0 },
- vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr },
- vim.diagnostic.is_enabled{ bufnr = diagnostic_bufnr, ns_id = diagnostic_ns },
- vim.diagnostic.is_enabled{ bufnr = 0, ns_id = diagnostic_ns },
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.enable()
+ return {
+ vim.diagnostic.is_enabled(),
+ vim.diagnostic.is_enabled { bufnr = 0 },
+ vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr },
+ vim.diagnostic.is_enabled { bufnr = _G.diagnostic_bufnr, ns_id = _G.diagnostic_ns },
+ vim.diagnostic.is_enabled { bufnr = 0, ns_id = _G.diagnostic_ns },
+ }
+ end)
)
end)
it('is_disabled (deprecated)', 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),
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
+ vim.diagnostic.disable()
+ return {
+ vim.diagnostic.is_disabled(),
+ vim.diagnostic.is_disabled(_G.diagnostic_bufnr),
+ vim.diagnostic.is_disabled(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ vim.diagnostic.is_disabled(0, _G.diagnostic_ns),
+ }
+ end)
)
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),
- }
- ]]
+ exec_lua(function()
+ vim.diagnostic.enable()
+ return {
+ vim.diagnostic.is_disabled(),
+ vim.diagnostic.is_disabled(_G.diagnostic_bufnr),
+ vim.diagnostic.is_disabled(_G.diagnostic_bufnr, _G.diagnostic_ns),
+ vim.diagnostic.is_disabled(0, _G.diagnostic_ns),
+ }
+ end)
)
end)
end)
diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua
index 85ca264107..96f5812493 100644
--- a/test/functional/lua/ffi_spec.lua
+++ b/test/functional/lua/ffi_spec.lua
@@ -15,27 +15,27 @@ describe('ffi.cdef', function()
eq(
12,
- exec_lua [=[
- local ffi = require('ffi')
+ exec_lua(function()
+ local ffi = require('ffi')
- ffi.cdef [[
+ ffi.cdef [[
typedef struct window_S win_T;
int win_col_off(win_T *wp);
extern win_T *curwin;
]]
- vim.cmd('set number numberwidth=4 signcolumn=yes:4')
+ vim.cmd('set number numberwidth=4 signcolumn=yes:4')
- return ffi.C.win_col_off(ffi.C.curwin)
- ]=]
+ return ffi.C.win_col_off(ffi.C.curwin)
+ end)
)
eq(
20,
- exec_lua [=[
- local ffi = require('ffi')
+ exec_lua(function()
+ local ffi = require('ffi')
- ffi.cdef[[
+ ffi.cdef [[
typedef struct {} stl_hlrec_t;
typedef struct {} StlClickRecord;
typedef struct {} statuscol_T;
@@ -58,32 +58,32 @@ describe('ffi.cdef', function()
);
]]
- return ffi.C.build_stl_str_hl(
- ffi.C.find_window_by_handle(0, ffi.new('Error')),
- ffi.new('char[1024]'),
- 1024,
- ffi.cast('char*', 'StatusLineOfLength20'),
- -1,
- 0,
- 0,
- 0,
- nil,
- nil,
- nil
- )
- ]=]
+ return ffi.C.build_stl_str_hl(
+ ffi.C.find_window_by_handle(0, ffi.new('Error')),
+ ffi.new('char[1024]'),
+ 1024,
+ ffi.cast('char*', 'StatusLineOfLength20'),
+ -1,
+ 0,
+ 0,
+ 0,
+ nil,
+ nil,
+ nil
+ )
+ end)
)
-- Check that extern symbols are exported and accessible
eq(
true,
- exec_lua [[
- local ffi = require('ffi')
+ exec_lua(function()
+ local ffi = require('ffi')
- ffi.cdef('uint64_t display_tick;')
+ ffi.cdef('uint64_t display_tick;')
- return ffi.C.display_tick >= 0
- ]]
+ return ffi.C.display_tick >= 0
+ end)
)
end)
end)
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index 7db04e6f6b..574c837f92 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -18,90 +18,82 @@ describe('vim.filetype', function()
before_each(function()
clear()
- exec_lua [[
+ exec_lua(function()
local bufnr = vim.api.nvim_create_buf(true, false)
vim.api.nvim_set_current_buf(bufnr)
- ]]
+ end)
end)
it('works with extensions', function()
eq(
'radicalscript',
- exec_lua [[
- vim.filetype.add({
- extension = {
- rs = 'radicalscript',
- },
- })
- return vim.filetype.match({ filename = 'main.rs' })
- ]]
+ exec_lua(function()
+ vim.filetype.add({
+ extension = {
+ rs = 'radicalscript',
+ },
+ })
+ return vim.filetype.match({ filename = 'main.rs' })
+ end)
)
end)
it('prioritizes filenames over extensions', function()
eq(
'somethingelse',
- exec_lua [[
- vim.filetype.add({
- extension = {
- rs = 'radicalscript',
- },
- filename = {
- ['main.rs'] = 'somethingelse',
- },
- })
- return vim.filetype.match({ filename = 'main.rs' })
- ]]
+ exec_lua(function()
+ vim.filetype.add({
+ extension = {
+ rs = 'radicalscript',
+ },
+ filename = {
+ ['main.rs'] = 'somethingelse',
+ },
+ })
+ return vim.filetype.match({ filename = 'main.rs' })
+ end)
)
end)
it('works with filenames', function()
eq(
'nim',
- exec_lua [[
- vim.filetype.add({
- filename = {
- ['s_O_m_e_F_i_l_e'] = 'nim',
- },
- })
- return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' })
- ]]
+ exec_lua(function()
+ vim.filetype.add({
+ filename = {
+ ['s_O_m_e_F_i_l_e'] = 'nim',
+ },
+ })
+ return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' })
+ end)
)
eq(
'dosini',
- exec_lua(
- [[
- local root = ...
- vim.filetype.add({
- filename = {
- ['config'] = 'toml',
- [root .. '/.config/fun/config'] = 'dosini',
- },
- })
- return vim.filetype.match({ filename = root .. '/.config/fun/config' })
- ]],
- root
- )
+ exec_lua(function()
+ vim.filetype.add({
+ filename = {
+ ['config'] = 'toml',
+ [root .. '/.config/fun/config'] = 'dosini',
+ },
+ })
+ return vim.filetype.match({ filename = root .. '/.config/fun/config' })
+ end)
)
end)
it('works with patterns', function()
eq(
'markdown',
- exec_lua(
- [[
- local root = ...
- vim.env.HOME = '/a-funky+home%dir'
- vim.filetype.add({
- pattern = {
- ['~/blog/.*%.txt'] = 'markdown',
- }
- })
- return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' })
- ]],
- root
- )
+ exec_lua(function()
+ vim.env.HOME = '/a-funky+home%dir'
+ vim.filetype.add({
+ pattern = {
+ ['~/blog/.*%.txt'] = 'markdown',
+ },
+ })
+ return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' })
+ end)
)
end)
@@ -110,43 +102,43 @@ describe('vim.filetype', function()
command('file relevant_to_me')
eq(
'foss',
- exec_lua [[
- vim.filetype.add({
- pattern = {
- ["relevant_to_(%a+)"] = function(path, bufnr, capture)
- if capture == "me" then
- return "foss"
- end
- end,
- }
- })
- return vim.filetype.match({ buf = 0 })
- ]]
+ exec_lua(function()
+ vim.filetype.add({
+ pattern = {
+ ['relevant_to_(%a+)'] = function(_, _, capture)
+ if capture == 'me' then
+ return 'foss'
+ end
+ end,
+ },
+ })
+ return vim.filetype.match({ buf = 0 })
+ end)
)
end)
it('works with contents #22180', function()
eq(
'sh',
- exec_lua [[
- -- Needs to be set so detect#sh doesn't fail
- vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
- return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } })
- ]]
+ exec_lua(function()
+ -- Needs to be set so detect#sh doesn't fail
+ vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$'
+ return (vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }))
+ end)
)
end)
it('considers extension mappings when matching from hashbang', function()
eq(
'fooscript',
- exec_lua [[
- vim.filetype.add({
- extension = {
- foo = 'fooscript',
- }
- })
- return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } })
- ]]
+ exec_lua(function()
+ vim.filetype.add({
+ extension = {
+ foo = 'fooscript',
+ },
+ })
+ return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } })
+ end)
)
end)
@@ -160,7 +152,12 @@ describe('vim.filetype', function()
xml = { formatexpr = 'xmlformat#Format()' },
} do
for option, value in pairs(opts) do
- eq(value, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option))
+ eq(
+ value,
+ exec_lua(function()
+ return vim.filetype.get_option(ft, option)
+ end)
+ )
end
end
end)
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index aba02ab01b..f0d49205e7 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -141,19 +141,14 @@ describe('vim.fs', function()
it('works', function()
eq(
true,
- exec_lua(
- [[
- local dir, nvim = ...
- for name, type in vim.fs.dir(dir) do
- if name == nvim and type == 'file' then
- return true
+ exec_lua(function()
+ for name, type in vim.fs.dir(nvim_dir) do
+ if name == nvim_prog_basename and type == 'file' then
+ return true
+ end
end
- end
- return false
- ]],
- nvim_dir,
- nvim_prog_basename
- )
+ return false
+ end)
)
end)
@@ -172,14 +167,12 @@ describe('vim.fs', function()
io.open('testd/a/b/c/c4', 'w'):close()
local function run(dir, depth, skip)
- local r = exec_lua(
- [[
- local dir, depth, skip = ...
+ return exec_lua(function()
local r = {}
local skip_f
if skip then
- skip_f = function(n)
- if vim.tbl_contains(skip or {}, n) then
+ skip_f = function(n0)
+ if vim.tbl_contains(skip or {}, n0) then
return false
end
end
@@ -188,12 +181,7 @@ describe('vim.fs', function()
r[name] = type_
end
return r
- ]],
- dir,
- depth,
- skip
- )
- return r
+ end)
end
local exp = {}
@@ -263,13 +251,12 @@ describe('vim.fs', function()
opts = { path = test_source_path .. '/contrib', limit = math.huge }
eq(
- exec_lua(
- [[
- local dir = ...
- return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir..'/contrib/*', false, true))
- ]],
- test_source_path
- ),
+ exec_lua(function()
+ return vim.tbl_map(
+ vim.fs.basename,
+ vim.fn.glob(test_source_path .. '/contrib/*', false, true)
+ )
+ end),
vim.tbl_map(
vim.fs.basename,
vim.fs.find(function(_, d)
@@ -299,11 +286,11 @@ describe('vim.fs', function()
it('works with a function', function()
---@type string
- local result = exec_lua([[
- return vim.fs.root(0, function(name, path)
+ local result = exec_lua(function()
+ return vim.fs.root(0, function(name, _)
return name:match('%.txt$')
end)
- ]])
+ end)
eq(vim.fs.joinpath(test_source_path, 'test/functional/fixtures'), result)
end)
@@ -352,13 +339,10 @@ describe('vim.fs', function()
local xdg_config_home = test_build_dir .. '/.config'
eq(
xdg_config_home .. '/nvim',
- exec_lua(
- [[
- vim.env.XDG_CONFIG_HOME = ...
- return vim.fs.normalize('$XDG_CONFIG_HOME/nvim')
- ]],
- xdg_config_home
- )
+ exec_lua(function()
+ vim.env.XDG_CONFIG_HOME = xdg_config_home
+ return vim.fs.normalize('$XDG_CONFIG_HOME/nvim')
+ end)
)
end)
diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua
index 56cd4c9bb5..8302c7334d 100644
--- a/test/functional/lua/glob_spec.lua
+++ b/test/functional/lua/glob_spec.lua
@@ -2,21 +2,15 @@ local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local eq = t.eq
-local exec_lua = n.exec_lua
describe('glob', function()
before_each(n.clear)
after_each(n.clear)
- local match = function(...)
- return exec_lua(
- [[
- local pattern = select(1, ...)
- local str = select(2, ...)
- return require("vim.glob").to_lpeg(pattern):match(str) ~= nil
- ]],
- ...
- )
+ local match = function(pattern, str)
+ return n.exec_lua(function()
+ return require('vim.glob').to_lpeg(pattern):match(str) ~= nil
+ end)
end
describe('glob matching', function()
@@ -161,7 +155,7 @@ describe('glob', function()
eq(false, match('{ab,cd}', 'a'))
eq(true, match('{ab,cd}', 'cd'))
eq(true, match('{a,b,c}', 'c'))
- eq(true, match('{a,{b,c}}', 'c'))
+ eq(false, match('{a,{b,c}}', 'c')) -- {} cannot nest
end)
it('should match [] groups', function()
@@ -205,6 +199,19 @@ describe('glob', function()
eq(true, match('[!a-zA-Z0-9]', '!'))
end)
+ it('should handle long patterns', function()
+ -- lpeg has a recursion limit of 200 by default, make sure the grammar does trigger it on
+ -- strings longer than that
+ local fill_200 =
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
+ eq(200, fill_200:len())
+ local long_lit = fill_200 .. 'a'
+ eq(false, match(long_lit, 'b'))
+ eq(true, match(long_lit, long_lit))
+ local long_pat = fill_200 .. 'a/**/*.c'
+ eq(true, match(long_pat, fill_200 .. 'a/b/c/d.c'))
+ end)
+
it('should match complex patterns', function()
eq(false, match('**/*.{c,h}', ''))
eq(false, match('**/*.{c,h}', 'c'))
@@ -223,6 +230,17 @@ describe('glob', function()
eq(true, match('{[0-9],[a-z]}', '0'))
eq(true, match('{[0-9],[a-z]}', 'a'))
eq(false, match('{[0-9],[a-z]}', 'A'))
+
+ -- glob is from willRename filter in typescript-language-server
+ -- https://github.com/typescript-language-server/typescript-language-server/blob/b224b878652438bcdd639137a6b1d1a6630129e4/src/lsp-server.ts#L266
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.js'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.ts'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mts'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.mjs'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cjs'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.cts'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.jsx'))
+ eq(true, match('**/*.{ts,js,jsx,tsx,mjs,mts,cjs,cts}', 'test.tsx'))
end)
end)
end)
diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua
index c9f2d0a47f..c048949df8 100644
--- a/test/functional/lua/highlight_spec.lua
+++ b/test/functional/lua/highlight_spec.lua
@@ -1,14 +1,112 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
local exec_lua = n.exec_lua
local eq = t.eq
-local neq = t.neq
local eval = n.eval
local command = n.command
local clear = n.clear
local api = n.api
+describe('vim.highlight.range', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 6)
+ screen:add_extra_attr_ids({
+ [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true },
+ })
+ screen:attach()
+ api.nvim_set_option_value('list', true, {})
+ api.nvim_set_option_value('listchars', 'eol:$', {})
+ api.nvim_buf_set_lines(0, 0, -1, true, {
+ 'asdfghjkl',
+ '«口=口»',
+ 'qwertyuiop',
+ '口口=口口',
+ 'zxcvbnm',
+ })
+ end)
+
+ it('works with charwise selection', function()
+ exec_lua(function()
+ local ns = vim.api.nvim_create_namespace('')
+ vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 })
+ end)
+ screen:expect([[
+ ^asdfghjkl{1:$} |
+ «口{10:=口»}{100:$} |
+ {10:qwertyuiop}{100:$} |
+ {10:口口=口}口{1:$} |
+ zxcvbnm{1:$} |
+ |
+ ]])
+ end)
+
+ it('works with linewise selection', function()
+ exec_lua(function()
+ local ns = vim.api.nvim_create_namespace('')
+ vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' })
+ end)
+ screen:expect([[
+ {10:^asdfghjkl}{100:$} |
+ {10:«口=口»}{100:$} |
+ {10:qwertyuiop}{100:$} |
+ {10:口口=口口}{100:$} |
+ {10:zxcvbnm}{100:$} |
+ |
+ ]])
+ end)
+
+ it('works with blockwise selection', function()
+ exec_lua(function()
+ local ns = vim.api.nvim_create_namespace('')
+ vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' })
+ end)
+ screen:expect([[
+ {10:^asdf}ghjkl{1:$} |
+ {10:«口=}口»{1:$} |
+ {10:qwer}tyuiop{1:$} |
+ {10:口口}=口口{1:$} |
+ {10:zxcv}bnm{1:$} |
+ |
+ ]])
+ end)
+
+ it('works with blockwise selection with width', function()
+ exec_lua(function()
+ local ns = vim.api.nvim_create_namespace('')
+ vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' })
+ end)
+ screen:expect([[
+ ^asdf{10:ghjkl}{1:$} |
+ «口={10:口»}{1:$} |
+ qwer{10:tyuiop}{1:$} |
+ 口口{10:=口口}{1:$} |
+ zxcv{10:bnm}{1:$} |
+ |
+ ]])
+ end)
+
+ it('can use -1 or v:maxcol to indicate end of line', function()
+ exec_lua(function()
+ local ns = vim.api.nvim_create_namespace('')
+ vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {})
+ vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {})
+ end)
+ screen:expect([[
+ ^asdf{10:ghjkl}{100:$} |
+ {10:«口=口»}{100:$} |
+ qwerty{10:uiop}{100:$} |
+ {10:口口=口口}{1:$} |
+ zxcvbnm{1:$} |
+ |
+ ]])
+ end)
+end)
+
describe('vim.highlight.on_yank', function()
before_each(function()
clear()
@@ -16,53 +114,62 @@ describe('vim.highlight.on_yank', function()
it('does not show errors even if buffer is wiped before timeout', function()
command('new')
- exec_lua([[
- vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}})
+ exec_lua(function()
+ vim.highlight.on_yank({
+ timeout = 10,
+ on_macro = true,
+ event = { operator = 'y', regtype = 'v' },
+ })
vim.cmd('bwipeout!')
- ]])
+ end)
vim.uv.sleep(10)
n.feed('<cr>') -- avoid hang if error message exists
eq('', eval('v:errmsg'))
end)
it('does not close timer twice', function()
- exec_lua([[
- vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}})
+ exec_lua(function()
+ vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } })
vim.uv.sleep(10)
vim.schedule(function()
- vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}})
+ vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } })
end)
- ]])
+ end)
eq('', eval('v:errmsg'))
end)
it('does not show in another window', function()
command('vsplit')
- exec_lua([[
- vim.api.nvim_buf_set_mark(0,"[",1,1,{})
- vim.api.nvim_buf_set_mark(0,"]",1,1,{})
- vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
- ]])
- neq({}, api.nvim__win_get_ns(0))
+ exec_lua(function()
+ vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
+ vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
+ vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
+ end)
+ local ns = api.nvim_create_namespace('hlyank')
+ local win = api.nvim_get_current_win()
+ eq({ win }, api.nvim__ns_get(ns).wins)
command('wincmd w')
- eq({}, api.nvim__win_get_ns(0))
+ eq({ win }, api.nvim__ns_get(ns).wins)
end)
it('removes old highlight if new one is created before old one times out', function()
command('vnew')
- exec_lua([[
- vim.api.nvim_buf_set_mark(0,"[",1,1,{})
- vim.api.nvim_buf_set_mark(0,"]",1,1,{})
- vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
- ]])
- neq({}, api.nvim__win_get_ns(0))
+ exec_lua(function()
+ vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
+ vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
+ vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
+ end)
+ local ns = api.nvim_create_namespace('hlyank')
+ eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
command('wincmd w')
- exec_lua([[
- vim.api.nvim_buf_set_mark(0,"[",1,1,{})
- vim.api.nvim_buf_set_mark(0,"]",1,1,{})
- vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}})
- ]])
+ exec_lua(function()
+ vim.api.nvim_buf_set_mark(0, '[', 1, 1, {})
+ vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
+ vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
+ end)
+ local win = api.nvim_get_current_win()
+ eq({ win }, api.nvim__ns_get(ns).wins)
command('wincmd w')
- eq({}, api.nvim__win_get_ns(0))
+ eq({ win }, api.nvim__ns_get(ns).wins)
end)
end)
diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua
index 8fadba6ee8..3a1263f6a3 100644
--- a/test/functional/lua/inspector_spec.lua
+++ b/test/functional/lua/inspector_spec.lua
@@ -12,22 +12,21 @@ describe('vim.inspect_pos', function()
end)
it('it returns items', function()
- local ret = exec_lua([[
+ local buf, items, other_buf_syntax = exec_lua(function()
local buf = vim.api.nvim_create_buf(true, false)
local buf1 = vim.api.nvim_create_buf(true, false)
- local ns1 = vim.api.nvim_create_namespace("ns1")
- local ns2 = vim.api.nvim_create_namespace("")
+ local ns1 = vim.api.nvim_create_namespace('ns1')
+ local ns2 = vim.api.nvim_create_namespace('')
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_lines(buf1, 0, -1, false, {"--commentline"})
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, { 'local a = 123' })
+ vim.api.nvim_buf_set_lines(buf1, 0, -1, false, { '--commentline' })
vim.bo[buf].filetype = 'lua'
vim.bo[buf1].filetype = 'lua'
- vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" })
- vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" })
- vim.cmd("syntax on")
- return {buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax }
- ]])
- local buf, items, other_buf_syntax = unpack(ret)
+ vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = 'Normal' })
+ vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = 'Normal' })
+ vim.cmd('syntax on')
+ return buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax
+ end)
eq('', eval('v:errmsg'))
eq({
@@ -95,14 +94,14 @@ describe('vim.show_pos', function()
end)
it('it does not error', function()
- exec_lua([[
+ exec_lua(function()
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_lines(0, 0, -1, false, { 'local a = 123' })
vim.bo[buf].filetype = 'lua'
- vim.cmd("syntax on")
- return {buf, vim.show_pos(0, 0, 10)}
- ]])
+ vim.cmd('syntax on')
+ return { buf, vim.show_pos(0, 0, 10) }
+ end)
eq('', eval('v:errmsg'))
end)
end)
diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua
index f13e6664c5..8508f2aa14 100644
--- a/test/functional/lua/loader_spec.lua
+++ b/test/functional/lua/loader_spec.lua
@@ -12,14 +12,14 @@ describe('vim.loader', function()
it('can work in compatibility with --luamod-dev #27413', function()
clear({ args = { '--luamod-dev' } })
- exec_lua [[
+ exec_lua(function()
vim.loader.enable()
- require("vim.fs")
+ require('vim.fs')
-- try to load other vim submodules as well (Nvim Lua stdlib)
for key, _ in pairs(vim._submodules) do
- local modname = 'vim.' .. key -- e.g. "vim.fs"
+ local modname = 'vim.' .. key -- e.g. "vim.fs"
local lhs = vim[key]
local rhs = require(modname)
@@ -28,28 +28,25 @@ describe('vim.loader', function()
('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs))
)
end
- ]]
+ end)
end)
it('handles changing files (#23027)', function()
- exec_lua [[
+ exec_lua(function()
vim.loader.enable()
- ]]
+ end)
local tmp = t.tmpname()
command('edit ' .. tmp)
eq(
1,
- exec_lua(
- [[
- vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=1'})
- vim.cmd.write()
- loadfile(...)()
- return _G.TEST
- ]],
- tmp
- )
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=1' })
+ vim.cmd.write()
+ loadfile(tmp)()
+ return _G.TEST
+ end)
)
-- fs latency
@@ -57,15 +54,12 @@ describe('vim.loader', function()
eq(
2,
- exec_lua(
- [[
- vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=2'})
- vim.cmd.write()
- loadfile(...)()
- return _G.TEST
- ]],
- tmp
- )
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(0, 0, -1, true, { '_G.TEST=2' })
+ vim.cmd.write()
+ loadfile(tmp)()
+ return _G.TEST
+ end)
)
end)
@@ -74,8 +68,7 @@ describe('vim.loader', function()
vim.loader.enable()
]]
- local tmp = t.tmpname()
- assert(os.remove(tmp))
+ local tmp = t.tmpname(false)
assert(t.mkdir(tmp))
assert(t.mkdir(tmp .. '/%'))
local tmp1 = tmp .. '/%/x'
@@ -88,4 +81,15 @@ describe('vim.loader', function()
eq(1, exec_lua('return loadfile(...)()', tmp1))
eq(2, exec_lua('return loadfile(...)()', tmp2))
end)
+
+ it('correct indent on error message (#29809)', function()
+ local errmsg = exec_lua [[
+ vim.loader.enable()
+ local _, errmsg = pcall(require, 'non_existent_module')
+ return errmsg
+ ]]
+ local errors = vim.split(errmsg, '\n')
+ eq("\tcache_loader: module 'non_existent_module' not found", errors[3])
+ eq("\tcache_loader_lib: module 'non_existent_module' not found", errors[4])
+ end)
end)
diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua
index 566a171a84..de8200a5f1 100644
--- a/test/functional/lua/loop_spec.lua
+++ b/test/functional/lua/loop_spec.lua
@@ -25,30 +25,34 @@ describe('vim.uv', function()
it('timer', function()
exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {})
- local code = [[
+ local code = function()
local touch = 0
local function wait(ms)
local this = coroutine.running()
assert(this)
- local timer = vim.uv.new_timer()
- timer:start(ms, 0, vim.schedule_wrap(function ()
- timer:close()
- touch = touch + 1
- coroutine.resume(this)
- touch = touch + 1
- assert(touch==3)
- vim.api.nvim_set_var("coroutine_cnt_1", touch)
- end))
+ local timer = assert(vim.uv.new_timer())
+ timer:start(
+ ms,
+ 0,
+ vim.schedule_wrap(function()
+ timer:close()
+ touch = touch + 1
+ coroutine.resume(this)
+ touch = touch + 1
+ assert(touch == 3)
+ vim.api.nvim_set_var('coroutine_cnt_1', touch)
+ end)
+ )
coroutine.yield()
touch = touch + 1
return touch
end
coroutine.wrap(function()
local touched = wait(10)
- assert(touched==touch)
- vim.api.nvim_set_var("coroutine_cnt", touched)
+ assert(touched == touch)
+ vim.api.nvim_set_var('coroutine_cnt', touched)
end)()
- ]]
+ end
eq(0, api.nvim_get_var('coroutine_cnt'))
exec_lua(code)
@@ -99,15 +103,19 @@ describe('vim.uv', function()
-- callbacks can be scheduled to be executed in the main event loop
-- where the entire API is available
- exec_lua([[
- local timer = vim.uv.new_timer()
- timer:start(20, 0, vim.schedule_wrap(function ()
- _G.is_fast = vim.in_fast_event()
- timer:close()
- vim.api.nvim_set_var("valid", true)
- vim.api.nvim_command("echomsg 'howdy'")
- end))
- ]])
+ exec_lua(function()
+ local timer = assert(vim.uv.new_timer())
+ timer:start(
+ 20,
+ 0,
+ vim.schedule_wrap(function()
+ _G.is_fast = vim.in_fast_event()
+ timer:close()
+ vim.api.nvim_set_var('valid', true)
+ vim.api.nvim_command("echomsg 'howdy'")
+ end)
+ )
+ end)
screen:expect([[
^ |
@@ -118,15 +126,15 @@ describe('vim.uv', function()
eq(false, exec_lua('return _G.is_fast'))
-- fast (not deferred) API functions are allowed to be called directly
- exec_lua([[
- local timer = vim.uv.new_timer()
- timer:start(20, 0, function ()
+ exec_lua(function()
+ local timer = assert(vim.uv.new_timer())
+ timer:start(20, 0, function()
timer:close()
-- input is queued for processing after the callback returns
- vim.api.nvim_input("isneaky")
+ vim.api.nvim_input('isneaky')
_G.mode = vim.api.nvim_get_mode()
end)
- ]])
+ end)
screen:expect([[
sneaky^ |
{1:~ }|*8
@@ -134,15 +142,15 @@ describe('vim.uv', function()
]])
eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode'))
- exec_lua([[
- local timer = vim.uv.new_timer()
- timer:start(20, 0, function ()
+ exec_lua(function()
+ local timer = assert(vim.uv.new_timer())
+ timer:start(20, 0, function()
_G.is_fast = vim.in_fast_event()
timer:close()
- _G.value = vim.fn.has("nvim-0.5")
- _G.unvalue = vim.fn.has("python3")
+ _G.value = vim.fn.has('nvim-0.5')
+ _G.unvalue = vim.fn.has('python3')
end)
- ]])
+ end)
screen:expect({ any = [[{3:Vim:E5560: Vimscript function must not be called i}]] })
feed('<cr>')
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 3f62cd8325..2b23f72c7d 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -13,6 +13,7 @@ local fn = n.fn
local clear = n.clear
local eval = n.eval
local feed = n.feed
+local assert_alive = n.assert_alive
local NIL = vim.NIL
local eq = t.eq
@@ -72,9 +73,9 @@ describe('luaeval()', function()
end)
it('are successfully converted to special dictionaries in table keys', function()
command([[let d = luaeval('{["\0"]=1}')]])
- eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, api.nvim_get_var('d'))
+ eq({_TYPE={}, _VAL={{'\000', 1}}}, api.nvim_get_var('d'))
eq(1, fn.eval('d._TYPE is v:msgpack_types.map'))
- eq(1, fn.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string'))
+ eq(eval('v:t_blob'), fn.eval('type(d._VAL[0][0])'))
end)
it('are successfully converted to blobs from a list', function()
command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]])
@@ -125,11 +126,11 @@ describe('luaeval()', function()
local level = 30
eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s))
- eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}},
+ eq({_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}},
fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]]))
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]]))
- eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]]))
- eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}},
+ eq(eval("v:t_blob"), eval([[type(luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0])]]))
+ eq({nested={{_TYPE={}, _VAL={{'\000\n\000', '\000\n\000\000'}}}}},
fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]]))
end)
@@ -177,17 +178,15 @@ describe('luaeval()', function()
end
it('correctly passes special dictionaries', function()
- eq({0, '\000\n\000'}, luaevalarg(sp('binary', '["\\n", "\\n"]')))
eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]')))
eq({0, true}, luaevalarg(sp('boolean', 1)))
eq({0, false}, luaevalarg(sp('boolean', 0)))
eq({0, NIL}, luaevalarg(sp('nil', 0)))
- eq({0, {[""]=""}}, luaevalarg(mapsp(sp('binary', '[""]'), '""')))
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""')))
end)
it('issues an error in some cases', function()
- eq("Vim(call):E5100: Cannot convert given lua table: table should contain either only integer keys or only string keys",
+ eq("Vim(call):E5100: Cannot convert given Lua table: table should contain either only integer keys or only string keys",
exc_exec('call luaeval("{1, foo=2}")'))
startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:",
@@ -511,23 +510,16 @@ describe('v:lua', function()
it('works in func options', function()
local screen = Screen.new(60, 8)
- screen:set_default_attr_ids({
- [1] = {bold = true, foreground = Screen.colors.Blue1},
- [2] = {background = Screen.colors.WebGray},
- [3] = {background = Screen.colors.LightMagenta},
- [4] = {bold = true},
- [5] = {bold = true, foreground = Screen.colors.SeaGreen4},
- })
screen:attach()
api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {})
feed('isome st<c-x><c-o>')
screen:expect{grid=[[
some stuff^ |
- {1:~ }{2: stuff }{1: }|
- {1:~ }{3: steam }{1: }|
- {1:~ }{3: strange things }{1: }|
+ {1:~ }{12: stuff }{1: }|
+ {1:~ }{4: steam }{1: }|
+ {1:~ }{4: strange things }{1: }|
{1:~ }|*3
- {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} |
+ {5:-- Omni completion (^O^N^P) }{6:match 1 of 3} |
]]}
api.nvim_set_option_value('operatorfunc', 'v:lua.mymod.noisy', {})
feed('<Esc>g@g@')
@@ -560,5 +552,41 @@ describe('v:lua', function()
eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua"))
eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()"))
eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "'bad'->v:lua.()"))
+
+ eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()"))
+ eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "v:lua.()"))
+ end)
+
+ describe('invalid use in fold text', function()
+ before_each(function()
+ feed('ifoo<CR>bar<Esc>')
+ command('1,2fold')
+ end)
+
+ it('with missing function name when used as simple function', function()
+ api.nvim_set_option_value('debug', 'throw', {})
+ eq(
+ [[Vim(eval):E15: Invalid expression: "v:lua.()"]],
+ pcall_err(command, 'set foldtext=v:lua.() | eval foldtextresult(1)')
+ )
+ end)
+
+ it('with missing function name when used in expression', function()
+ api.nvim_set_option_value('debug', 'throw', {})
+ eq(
+ [[Vim(eval):E15: Invalid expression: "+v:lua.()"]],
+ pcall_err(command, 'set foldtext=+v:lua.() | eval foldtextresult(1)')
+ )
+ end)
+
+ it('with non-existent function when used as simple function', function()
+ command('set foldtext=v:lua.NoSuchFunc() | eval foldtextresult(1)')
+ assert_alive()
+ end)
+
+ it('with non-existent function when used in expression', function()
+ command('set foldtext=+v:lua.NoSuchFunc() | eval foldtextresult(1)')
+ assert_alive()
+ end)
end)
end)
diff --git a/test/functional/lua/mpack_spec.lua b/test/functional/lua/mpack_spec.lua
index efd69d4607..ebede26936 100644
--- a/test/functional/lua/mpack_spec.lua
+++ b/test/functional/lua/mpack_spec.lua
@@ -11,20 +11,20 @@ describe('lua vim.mpack', function()
it('encodes vim.NIL', function()
eq(
{ true, true, true, true },
- exec_lua [[
- local var = vim.mpack.decode(vim.mpack.encode({33, vim.NIL, 77}))
- return {var[1]==33, var[2]==vim.NIL, var[3]==77, var[4]==nil}
- ]]
+ exec_lua(function()
+ local var = vim.mpack.decode(vim.mpack.encode({ 33, vim.NIL, 77 }))
+ return { var[1] == 33, var[2] == vim.NIL, var[3] == 77, var[4] == nil }
+ end)
)
end)
it('encodes vim.empty_dict()', function()
eq(
{ { {}, 'foo', {} }, true, false },
- exec_lua [[
- local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()}))
- return {var, vim.islist(var[1]), vim.islist(var[3])}
- ]]
+ exec_lua(function()
+ local var = vim.mpack.decode(vim.mpack.encode({ {}, 'foo', vim.empty_dict() }))
+ return { var, vim.islist(var[1]), vim.islist(var[3]) }
+ end)
)
end)
end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 849978f080..33a2813200 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -134,14 +134,12 @@ describe('print', function()
eq('abc def', exec_capture('lua print("abc", "", "def")'))
end)
it('defers printing in luv event handlers', function()
- exec_lua(
- [[
- local cmd = ...
+ exec_lua(function(cmd)
function test()
local timer = vim.uv.new_timer()
local done = false
timer:start(10, 0, function()
- print("very fast")
+ print('very fast')
timer:close()
done = true
end)
@@ -149,14 +147,12 @@ describe('print', function()
-- loop until we know for sure the callback has been executed
while not done do
os.execute(cmd)
- vim.uv.run("nowait") -- fake os_breakcheck()
+ vim.uv.run('nowait') -- fake os_breakcheck()
end
- print("very slow")
- vim.api.nvim_command("sleep 1m") -- force deferred event processing
+ print('very slow')
+ vim.api.nvim_command('sleep 1m') -- force deferred event processing
end
- ]],
- (is_os('win') and 'timeout 1') or 'sleep 0.1'
- )
+ end, (is_os('win') and 'timeout 1') or 'sleep 0.1')
eq('very slow\nvery fast', exec_capture('lua test()'))
end)
diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua
index 4adce42c3e..f63363d6d9 100644
--- a/test/functional/lua/runtime_spec.lua
+++ b/test/functional/lua/runtime_spec.lua
@@ -401,4 +401,12 @@ describe('runtime:', function()
eq('ABab', eval('g:seq'))
end)
end)
+
+ it('cpp ftplugin loads c ftplugin #29053', function()
+ eq('', eval('&commentstring'))
+ eq('', eval('&omnifunc'))
+ exec('edit file.cpp')
+ eq('// %s', eval('&commentstring'))
+ eq('ccomplete#Complete', eval('&omnifunc'))
+ end)
end)
diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua
index 413aa93994..eb2f17216c 100644
--- a/test/functional/lua/snippet_spec.lua
+++ b/test/functional/lua/snippet_spec.lua
@@ -1,3 +1,5 @@
+---@diagnostic disable: no-unknown
+
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
@@ -16,11 +18,6 @@ local retry = t.retry
describe('vim.snippet', function()
before_each(function()
clear()
-
- exec_lua([[
- vim.keymap.set({ 'i', 's' }, '<Tab>', function() vim.snippet.jump(1) end, { buffer = true })
- vim.keymap.set({ 'i', 's' }, '<S-Tab>', function() vim.snippet.jump(-1) end, { buffer = true })
- ]])
end)
after_each(clear)
@@ -61,7 +58,13 @@ describe('vim.snippet', function()
end)
it('adds indentation based on the start of snippet lines', function()
+ local curbuf = api.nvim_get_current_buf()
+
test_expand_success({ 'if $1 then', ' $0', 'end' }, { 'if then', ' ', 'end' })
+
+ -- Regression test: #29658
+ api.nvim_buf_set_lines(curbuf, 0, -1, false, {})
+ test_expand_success({ '${1:foo^bar}\n' }, { 'foo^bar', '' })
end)
it('replaces tabs with spaces when expandtab is set', function()
@@ -286,4 +289,24 @@ describe('vim.snippet', function()
]]
)
end)
+
+ it('restores snippet navigation keymaps', function()
+ -- Create a buffer keymap in insert mode that deletes all lines.
+ local curbuf = api.nvim_get_current_buf()
+ exec_lua('vim.api.nvim_buf_set_keymap(..., "i", "<Tab>", "<cmd>normal ggdG<cr>", {})', curbuf)
+
+ test_expand_success({ 'var $1 = $2' }, { 'var = ' })
+
+ -- While the snippet is active, <Tab> should navigate between tabstops.
+ feed('x')
+ poke_eventloop()
+ feed('<Tab>0')
+ eq({ 'var x = 0' }, buf_lines(0))
+
+ exec_lua('vim.snippet.stop()')
+
+ -- After exiting the snippet, the buffer keymap should be restored.
+ feed('<Esc>O<cr><Tab>')
+ eq({ '' }, buf_lines(0))
+ end)
end)
diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua
index e72a009d2e..482bfcf1a9 100644
--- a/test/functional/lua/system_spec.lua
+++ b/test/functional/lua/system_spec.lua
@@ -6,10 +6,8 @@ local exec_lua = n.exec_lua
local eq = t.eq
local function system_sync(cmd, opts)
- return exec_lua(
- [[
- local cmd, opts = ...
- local obj = vim.system(...)
+ return exec_lua(function()
+ local obj = vim.system(cmd, opts)
if opts.timeout then
-- Minor delay before calling wait() so the timeout uv timer can have a headstart over the
@@ -24,16 +22,11 @@ local function system_sync(cmd, opts)
assert(not proc, 'process still exists')
return res
- ]],
- cmd,
- opts
- )
+ end)
end
local function system_async(cmd, opts)
- return exec_lua(
- [[
- local cmd, opts = ...
+ return exec_lua(function()
_G.done = false
local obj = vim.system(cmd, opts, function(obj)
_G.done = true
@@ -51,10 +44,7 @@ local function system_async(cmd, opts)
assert(not proc, 'process still exists')
return _G.ret
- ]],
- cmd,
- opts
- )
+ end)
end
describe('vim.system', function()
@@ -84,7 +74,7 @@ describe('vim.system', function()
end
it('kill processes', function()
- exec_lua([[
+ exec_lua(function()
local signal
local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r)
signal = r.signal
@@ -104,19 +94,21 @@ describe('vim.system', function()
assert(not proc, 'process still exists')
assert(signal == 2)
- ]])
+ end)
end)
it('SystemObj:wait() does not process non-fast events #27292', function()
eq(
false,
- exec_lua([[
+ exec_lua(function()
_G.processed = false
local cmd = vim.system({ 'sleep', '1' })
- vim.schedule(function() _G.processed = true end)
+ vim.schedule(function()
+ _G.processed = true
+ end)
cmd:wait()
return _G.processed
- ]])
+ end)
)
eq(true, exec_lua([[return _G.processed]]))
end)
diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua
index 9e77953c8c..be471bfd62 100644
--- a/test/functional/lua/text_spec.lua
+++ b/test/functional/lua/text_spec.lua
@@ -20,5 +20,11 @@ describe('vim.text', function()
eq(input, vim.text.hexdecode(output))
end
end)
+
+ it('works with very large strings', function()
+ local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16)
+ eq(output, vim.text.hexencode(input))
+ eq(input, vim.text.hexdecode(output))
+ end)
end)
end)
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
index 780057b580..cbf23517dc 100644
--- a/test/functional/lua/thread_spec.lua
+++ b/test/functional/lua/thread_spec.lua
@@ -18,13 +18,6 @@ describe('thread', function()
clear()
screen = Screen.new(50, 10)
screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true, reverse = true },
- [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [5] = { bold = true },
- })
end)
it('entry func is executed in protected mode', function()
@@ -38,10 +31,10 @@ describe('thread', function()
screen:expect([[
|
{1:~ }|*5
- {2: }|
- {3:Error in luv thread:} |
- {3:[string "<nvim>"]:2: Error in thread entry func} |
- {4:Press ENTER or type command to continue}^ |
+ {3: }|
+ {9:Error in luv thread:} |
+ {9:[string "<nvim>"]:2: Error in thread entry func} |
+ {6:Press ENTER or type command to continue}^ |
]])
feed('<cr>')
assert_alive()
@@ -65,10 +58,10 @@ describe('thread', function()
screen:expect([[
|
{1:~ }|*5
- {2: }|
- {3:Error in luv callback, thread:} |
- {3:[string "<nvim>"]:6: Error in thread callback} |
- {4:Press ENTER or type command to continue}^ |
+ {3: }|
+ {9:Error in luv callback, thread:} |
+ {9:[string "<nvim>"]:6: Error in thread callback} |
+ {6:Press ENTER or type command to continue}^ |
]])
feed('<cr>')
assert_alive()
@@ -265,13 +258,6 @@ describe('threadpool', function()
it('with invalid return value', function()
local screen = Screen.new(50, 10)
screen:attach()
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true, reverse = true },
- [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [5] = { bold = true },
- })
exec_lua [[
local work = vim.uv.new_work(function() return {} end, function() end)
@@ -281,10 +267,10 @@ describe('threadpool', function()
screen:expect([[
|
{1:~ }|*5
- {2: }|
- {3:Error in luv thread:} |
- {3:Error: thread arg not support type 'table' at 1} |
- {4:Press ENTER or type command to continue}^ |
+ {3: }|
+ {9:Error in luv thread:} |
+ {9:Error: thread arg not support type 'table' at 1} |
+ {6:Press ENTER or type command to continue}^ |
]])
end)
diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua
index 1e80c88403..0a6deaa41c 100644
--- a/test/functional/lua/ui_event_spec.lua
+++ b/test/functional/lua/ui_event_spec.lua
@@ -37,6 +37,9 @@ describe('vim.ui_attach', function()
[2] = { bold = true },
[3] = { background = Screen.colors.Grey },
[4] = { background = Screen.colors.LightMagenta },
+ [5] = { reverse = true },
+ [6] = { reverse = true, bold = true },
+ [7] = { background = Screen.colors.Yellow1 },
})
screen:attach()
end)
@@ -188,6 +191,56 @@ describe('vim.ui_attach', function()
feed('version<CR><CR>v<Esc>')
n.assert_alive()
end)
+
+ it("preserved 'incsearch/command' screen state after :redraw from ext_cmdline", function()
+ exec_lua([[
+ vim.cmd.norm('ifoobar')
+ vim.cmd('1split cmdline')
+ local buf = vim.api.nvim_get_current_buf()
+ vim.cmd.wincmd('p')
+ vim.ui_attach(ns, { ext_cmdline = true }, function(event, ...)
+ if event == 'cmdline_show' then
+ local content = select(1, ...)
+ vim.api.nvim_buf_set_lines(buf, -2, -1, false, {content[1][2]})
+ vim.cmd('redraw')
+ end
+ return true
+ end)
+ ]])
+ -- Updates a cmdline window
+ feed(':cmdline')
+ screen:expect({
+ grid = [[
+ cmdline |
+ {5:cmdline [+] }|
+ fooba^r |
+ {6:[No Name] [+] }|
+ |
+ ]],
+ })
+ -- Does not clear 'incsearch' highlighting
+ feed('<Esc>/foo')
+ screen:expect({
+ grid = [[
+ foo |
+ {5:cmdline [+] }|
+ {5:foo}ba^r |
+ {6:[No Name] [+] }|
+ |
+ ]],
+ })
+ -- Shows new cmdline state during 'inccommand'
+ feed('<Esc>:%s/bar/baz')
+ screen:expect({
+ grid = [[
+ %s/bar/baz |
+ {5:cmdline [+] }|
+ foo{7:ba^z} |
+ {6:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
end)
describe('vim.ui_attach', function()
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
index d69e893c96..d5eede2885 100644
--- a/test/functional/lua/ui_spec.lua
+++ b/test/functional/lua/ui_spec.lua
@@ -157,5 +157,28 @@ describe('vim.ui', function()
exec_lua [[local _, err = vim.ui.open('foo') ; return err]]
)
end)
+
+ it('opt.cmd #29490', function()
+ t.matches(
+ 'ENOENT: no such file or directory',
+ t.pcall_err(exec_lua, function()
+ vim.ui.open('foo', { cmd = { 'non-existent-tool' } })
+ end)
+ )
+
+ eq(
+ {
+ code = 0,
+ signal = 0,
+ stderr = '',
+ stdout = 'arg1=arg1;arg2=https://example.com;',
+ },
+ exec_lua(function(cmd_)
+ local cmd, err = vim.ui.open('https://example.com', { cmd = cmd_ })
+ assert(cmd and not err)
+ return cmd:wait()
+ end, { n.testprg('printargs-test'), 'arg1' })
+ )
+ end)
end)
end)
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index 553afb35d3..258b96bc43 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -217,7 +217,7 @@ describe('URI methods', function()
]],
file
)
- local expected_uri = 'file:///' .. file:gsub('\\', '/')
+ local expected_uri = 'file:///' .. t.fix_slashes(file)
eq(expected_uri, exec_lua(test_case))
os.remove(file)
end)
diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua
index 4ce8fb8dfe..c172555091 100644
--- a/test/functional/lua/version_spec.lua
+++ b/test/functional/lua/version_spec.lua
@@ -112,6 +112,10 @@ describe('version', function()
assert(vim.version.range('1.2.3-alpha'):has('1.2.3-alpha'))
assert(not vim.version.range('1.2.3-alpha'):has('1.2.3-beta'))
end)
+
+ it('returns nil with empty version', function()
+ eq(vim.version.parse(''), nil)
+ end)
end)
describe('cmp()', function()
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index c8f94c6ffa..3c65ec664e 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -135,19 +135,19 @@ describe('lua stdlib', function()
-- See MAINTAIN.md for the soft/hard deprecation policy
describe(('vim.deprecate prerel=%s,'):format(prerel or 'nil'), function()
- local curver = exec_lua('return vim.version()') --[[@as {major:number, minor:number}]]
- -- "0.10" or "0.10-dev+xxx"
- local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '')
- -- "0.10" or "0.11"
- local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1))
- local was_removed = prerel and 'was removed' or 'will be removed'
+ local curver --- @type {major:number, minor:number}
+
+ before_each(function()
+ curver = exec_lua('return vim.version()')
+ end)
it('plugin=nil, same message skipped', function()
+ -- "0.10" or "0.10-dev+xxx"
+ local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '')
eq(
- dedent(
- [[
- foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]]
- ):format(curstr),
+ ([[foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]]):format(
+ curstr
+ ),
exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr)
)
-- Same message as above; skipped this time.
@@ -162,6 +162,10 @@ describe('lua stdlib', function()
end)
it('plugin=nil, show error if hard-deprecated', function()
+ -- "0.10" or "0.11"
+ local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1))
+
+ local was_removed = prerel and 'was removed' or 'will be removed'
eq(
dedent(
[[
@@ -173,8 +177,7 @@ describe('lua stdlib', function()
it('plugin=nil, to be deleted in the next major version (1.0)', function()
eq(
- dedent [[
- foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]],
+ [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]],
exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]]
)
end)
@@ -535,12 +538,6 @@ describe('lua stdlib', function()
matches('big failure\nvery async', remove_trace(eval('v:errmsg')))
local screen = Screen.new(60, 5)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true, reverse = true },
- [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- })
screen:attach()
screen:expect {
grid = [[
@@ -559,11 +556,11 @@ describe('lua stdlib', function()
]])
screen:expect {
grid = [[
- {3:stack traceback:} |
- {3: [C]: in function 'nvim_command'} |
- {3: [string "<nvim>"]:2: in function <[string "<nvim>"]:}|
- {3:1>} |
- {4:Press ENTER or type command to continue}^ |
+ {9:stack traceback:} |
+ {9: [C]: in function 'nvim_command'} |
+ {9: [string "<nvim>"]:2: in function <[string "<nvim>"]:}|
+ {9:1>} |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -1062,7 +1059,7 @@ describe('lua stdlib', function()
local a = { a = {[2] = 3} }
local b = { a = {[3] = 3} }
local c = vim.tbl_deep_extend("force", a, b)
- return vim.deep_equal(c, {a = {[3] = 3}})
+ return vim.deep_equal(c, {a = {[2] = 3, [3] = 3}})
]]))
eq(
@@ -1074,34 +1071,28 @@ describe('lua stdlib', function()
]])
)
- matches(
- 'invalid "behavior": nil',
- pcall_err(
- exec_lua,
- [[
- return vim.tbl_deep_extend()
- ]]
- )
- )
+ ok(exec_lua([[
+ local a = { sub = { 'a', 'b' } }
+ local b = { sub = { 'b', 'c' } }
+ local c = vim.tbl_deep_extend('force', a, b)
+ return vim.deep_equal(c, { sub = { 'b', 'c' } })
+ ]]))
+
+ matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]]))
matches(
'wrong number of arguments %(given 1, expected at least 3%)',
- pcall_err(
- exec_lua,
- [[
- return vim.tbl_deep_extend("keep")
- ]]
- )
+ pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep")]])
)
matches(
'wrong number of arguments %(given 2, expected at least 3%)',
- pcall_err(
- exec_lua,
- [[
- return vim.tbl_deep_extend("keep", {})
- ]]
- )
+ pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {})]])
+ )
+
+ matches(
+ 'after the second argument%: expected table, got number',
+ pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {}, 42)]])
)
end)
@@ -1200,8 +1191,7 @@ describe('lua stdlib', function()
]])
eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]]))
eq(3, eval('g:test'))
- -- compat: nvim_call_function uses "special" value for empty dict
- eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]]))
+ eq(true, exec_lua([[return vim.tbl_isempty(vim.api.nvim_call_function("FooFunc", {5}))]]))
eq(5, eval('g:test'))
eq({ 2, 'foo', true }, exec_lua([[return vim.fn.VarArg(2, "foo", true)]]))
@@ -1239,7 +1229,7 @@ describe('lua stdlib', function()
)
end)
- it('vim.fn should error when calling API function', function()
+ it('vim.fn errors when calling API function', function()
matches(
'Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead',
pcall_err(exec_lua, 'vim.fn.nvim_get_current_line()')
@@ -1314,12 +1304,6 @@ describe('lua stdlib', function()
end)
local screen = Screen.new(50, 7)
- screen:set_default_attr_ids({
- [1] = { bold = true, foreground = Screen.colors.Blue1 },
- [2] = { bold = true, reverse = true },
- [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [4] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- })
screen:attach()
exec_lua([[
timer = vim.uv.new_timer()
@@ -1332,13 +1316,13 @@ describe('lua stdlib', function()
]])
screen:expect {
grid = [[
- {3:[string "<nvim>"]:6: E5560: rpcrequest must not be}|
- {3: called in a lua loop callback} |
- {3:stack traceback:} |
- {3: [C]: in function 'rpcrequest'} |
- {3: [string "<nvim>"]:6: in function <[string }|
- {3:"<nvim>"]:2>} |
- {4:Press ENTER or type command to continue}^ |
+ {9:[string "<nvim>"]:6: E5560: rpcrequest must not be}|
+ {9: called in a lua loop callback} |
+ {9:stack traceback:} |
+ {9: [C]: in function 'rpcrequest'} |
+ {9: [string "<nvim>"]:6: in function <[string }|
+ {9:"<nvim>"]:2>} |
+ {6:Press ENTER or type command to continue}^ |
]],
}
feed('<cr>')
@@ -1408,7 +1392,25 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}")
-
+ vim.validate('arg1', 5, 'number')
+ vim.validate('arg1', '5', 'string')
+ vim.validate('arg1', { 5 }, 'table')
+ vim.validate('arg1', function()
+ return 5
+ end, 'function')
+ vim.validate('arg1', nil, 'number', true)
+ vim.validate('arg1', nil, 'string', true)
+ vim.validate('arg1', nil, 'table', true)
+ vim.validate('arg1', nil, 'function', true)
+
+ matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number'))
+ matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string'))
+ matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table'))
+ matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function'))
+ matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string'))
+ matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table'))
+ matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function'))
+ matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number'))
matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}'))
@@ -1472,6 +1474,60 @@ describe('lua stdlib', function()
]])
)
+ eq(
+ { false, false },
+ exec_lua([[
+ local meta = { __call = {} }
+ assert(meta.__call)
+ local function new()
+ return setmetatable({}, meta)
+ end
+ local not_callable = new()
+ return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
+ ]])
+ )
+ eq(
+ { false, false },
+ exec_lua([[
+ local function new()
+ return { __call = function()end }
+ end
+ local not_callable = new()
+ assert(not_callable.__call)
+ return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
+ ]])
+ )
+ eq(
+ { false, false },
+ exec_lua([[
+ local meta = setmetatable(
+ { __index = { __call = function() end } },
+ { __index = { __call = function() end } }
+ )
+ assert(meta.__call)
+ local not_callable = setmetatable({}, meta)
+ assert(not_callable.__call)
+ return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
+ ]])
+ )
+ eq(
+ { false, false },
+ exec_lua([[
+ local meta = setmetatable({
+ __index = function()
+ return function() end
+ end,
+ }, {
+ __index = function()
+ return function() end
+ end,
+ })
+ assert(meta.__call)
+ local not_callable = setmetatable({}, meta)
+ assert(not_callable.__call)
+ return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
+ ]])
+ )
eq(false, exec_lua('return vim.is_callable(1)'))
eq(false, exec_lua("return vim.is_callable('foo')"))
eq(false, exec_lua('return vim.is_callable({})'))
@@ -1891,7 +1947,7 @@ describe('lua stdlib', function()
eq(NIL, fn.luaeval 'vim.v.null')
matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath'))
eq('Key is read-only: count', pcall_err(exec_lua, [[vim.v.count = 42]]))
- eq('Dictionary is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]]))
+ eq('Dict is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]]))
eq('Key is fixed: errmsg', pcall_err(exec_lua, [[vim.v.errmsg = nil]]))
exec_lua([[vim.v.errmsg = 'set by Lua']])
eq('set by Lua', eval('v:errmsg'))
@@ -1919,16 +1975,12 @@ describe('lua stdlib', function()
eq({ 1, 5 }, api.nvim_win_get_cursor(0))
local screen = Screen.new(60, 3)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { background = Screen.colors.Yellow },
- })
screen:attach()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
- {1:foo} {1:^foo} {1:foo} |
- {0:~ }|
+ {10:foo} {10:^foo} {10:foo} |
+ {1:~ }|
|
]],
}
@@ -1937,7 +1989,7 @@ describe('lua stdlib', function()
screen:expect {
grid = [[
foo ^foo foo |
- {0:~ }|
+ {1:~ }|
|
]],
}
@@ -1945,8 +1997,8 @@ describe('lua stdlib', function()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
- {1:foo} {1:^foo} {1:foo} |
- {0:~ }|
+ {10:foo} {10:^foo} {10:foo} |
+ {1:~ }|
|
]],
}
@@ -2005,13 +2057,17 @@ describe('lua stdlib', function()
vim.cmd "enew"
]]
eq(100, fn.luaeval 'vim.wo.scrolloff')
+
+ matches('only bufnr=0 is supported', pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"'))
+
+ matches('only bufnr=0 is supported', pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn'))
end)
describe('vim.opt', function()
-- TODO: We still need to write some tests for optlocal, opt and then getting the options
-- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same.
- it('should allow setting number values', function()
+ it('allows setting number values', function()
local scrolloff = exec_lua [[
vim.opt.scrolloff = 10
return vim.o.scrolloff
@@ -2019,7 +2075,7 @@ describe('lua stdlib', function()
eq(10, scrolloff)
end)
- pending('should handle STUPID window things', function()
+ pending('handles STUPID window things', function()
local result = exec_lua [[
local result = {}
@@ -2032,7 +2088,7 @@ describe('lua stdlib', function()
eq({}, result)
end)
- it('should allow setting tables', function()
+ it('allows setting tables', function()
local wildignore = exec_lua [[
vim.opt.wildignore = { 'hello', 'world' }
return vim.o.wildignore
@@ -2040,7 +2096,7 @@ describe('lua stdlib', function()
eq('hello,world', wildignore)
end)
- it('should allow setting tables with shortnames', function()
+ it('allows setting tables with shortnames', function()
local wildignore = exec_lua [[
vim.opt.wig = { 'hello', 'world' }
return vim.o.wildignore
@@ -2048,7 +2104,7 @@ describe('lua stdlib', function()
eq('hello,world', wildignore)
end)
- it('should error when you attempt to set string values to numeric options', function()
+ it('errors when you attempt to set string values to numeric options', function()
local result = exec_lua [[
return {
pcall(function() vim.opt.textwidth = 'hello world' end)
@@ -2058,7 +2114,7 @@ describe('lua stdlib', function()
eq(false, result[1])
end)
- it('should error when you attempt to setlocal a global value', function()
+ it('errors when you attempt to setlocal a global value', function()
local result = exec_lua [[
return pcall(function() vim.opt_local.clipboard = "hello" end)
]]
@@ -2066,7 +2122,7 @@ describe('lua stdlib', function()
eq(false, result)
end)
- it('should allow you to set boolean values', function()
+ it('allows you to set boolean values', function()
eq(
{ true, false, true },
exec_lua [[
@@ -2086,7 +2142,7 @@ describe('lua stdlib', function()
)
end)
- it('should change current buffer values and defaults for global local values', function()
+ it('changes current buffer values and defaults for global local values', function()
local result = exec_lua [[
local result = {}
@@ -2125,7 +2181,7 @@ describe('lua stdlib', function()
eq('', result[8])
end)
- it('should allow you to retrieve window opts even if they have not been set', function()
+ it('allows you to retrieve window opts even if they have not been set', function()
local result = exec_lua [[
local result = {}
table.insert(result, vim.opt.number:get())
@@ -2140,7 +2196,7 @@ describe('lua stdlib', function()
eq({ false, false, true, true }, result)
end)
- it('should allow all sorts of string manipulation', function()
+ it('allows all sorts of string manipulation', function()
eq(
{ 'hello', 'hello world', 'start hello world' },
exec_lua [[
@@ -2161,7 +2217,7 @@ describe('lua stdlib', function()
end)
describe('option:get()', function()
- it('should work for boolean values', function()
+ it('works for boolean values', function()
eq(
false,
exec_lua [[
@@ -2171,7 +2227,7 @@ describe('lua stdlib', function()
)
end)
- it('should work for number values', function()
+ it('works for number values', function()
local tabstop = exec_lua [[
vim.opt.tabstop = 10
return vim.opt.tabstop:get()
@@ -2180,7 +2236,7 @@ describe('lua stdlib', function()
eq(10, tabstop)
end)
- it('should work for string values', function()
+ it('works for string values', function()
eq(
'hello world',
exec_lua [[
@@ -2190,7 +2246,7 @@ describe('lua stdlib', function()
)
end)
- it('should work for set type flaglists', function()
+ it('works for set type flaglists', function()
local formatoptions = exec_lua [[
vim.opt.formatoptions = 'tcro'
return vim.opt.formatoptions:get()
@@ -2200,7 +2256,7 @@ describe('lua stdlib', function()
eq(true, not formatoptions.q)
end)
- it('should work for set type flaglists', function()
+ it('works for set type flaglists', function()
local formatoptions = exec_lua [[
vim.opt.formatoptions = { t = true, c = true, r = true, o = true }
return vim.opt.formatoptions:get()
@@ -2210,7 +2266,7 @@ describe('lua stdlib', function()
eq(true, not formatoptions.q)
end)
- it('should work for array list type options', function()
+ it('works for array list type options', function()
local wildignore = exec_lua [[
vim.opt.wildignore = "*.c,*.o,__pycache__"
return vim.opt.wildignore:get()
@@ -2220,7 +2276,7 @@ describe('lua stdlib', function()
eq('*.c', wildignore[1])
end)
- it('should work for options that are both commalist and flaglist', function()
+ it('works for options that are both commalist and flaglist', function()
local result = exec_lua [[
vim.opt.whichwrap = "b,s"
return vim.opt.whichwrap:get()
@@ -2236,7 +2292,7 @@ describe('lua stdlib', function()
eq({ b = true, h = true }, result)
end)
- it('should work for key-value pair options', function()
+ it('works for key-value pair options', function()
local listchars = exec_lua [[
vim.opt.listchars = "tab:> ,space:_"
return vim.opt.listchars:get()
@@ -2248,7 +2304,7 @@ describe('lua stdlib', function()
}, listchars)
end)
- it('should allow you to add numeric options', function()
+ it('allows you to add numeric options', function()
eq(
16,
exec_lua [[
@@ -2259,7 +2315,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow you to subtract numeric options', function()
+ it('allows you to subtract numeric options', function()
eq(
2,
exec_lua [[
@@ -2272,7 +2328,7 @@ describe('lua stdlib', function()
end)
describe('key:value style options', function()
- it('should handle dictionary style', function()
+ it('handles dict style', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2284,7 +2340,7 @@ describe('lua stdlib', function()
eq('eol:~,space:.', listchars)
end)
- it('should allow adding dictionary style', function()
+ it('allows adding dict style', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2299,7 +2355,7 @@ describe('lua stdlib', function()
eq('eol:~,space:-', listchars)
end)
- it('should allow adding dictionary style', function()
+ it('allows adding dict style', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2313,7 +2369,7 @@ describe('lua stdlib', function()
eq('eol:~,space:_', listchars)
end)
- it('should allow completely new keys', function()
+ it('allows completely new keys', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2327,7 +2383,7 @@ describe('lua stdlib', function()
eq('eol:~,space:.,tab:>>>', listchars)
end)
- it('should allow subtracting dictionary style', function()
+ it('allows subtracting dict style', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2341,7 +2397,7 @@ describe('lua stdlib', function()
eq('eol:~', listchars)
end)
- it('should allow subtracting dictionary style', function()
+ it('allows subtracting dict style', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2355,7 +2411,7 @@ describe('lua stdlib', function()
eq('', listchars)
end)
- it('should allow subtracting dictionary style multiple times', function()
+ it('allows subtracting dict style multiple times', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2369,7 +2425,7 @@ describe('lua stdlib', function()
eq('eol:~', listchars)
end)
- it('should allow adding a key:value string to a listchars', function()
+ it('allows adding a key:value string to a listchars', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2383,7 +2439,7 @@ describe('lua stdlib', function()
eq('eol:~,space:.,tab:>~', listchars)
end)
- it('should allow prepending a key:value string to a listchars', function()
+ it('allows prepending a key:value string to a listchars', function()
local listchars = exec_lua [[
vim.opt.listchars = {
eol = "~",
@@ -2398,7 +2454,7 @@ describe('lua stdlib', function()
end)
end)
- it('should automatically set when calling remove', function()
+ it('automatically sets when calling remove', function()
eq(
'foo,baz',
exec_lua [[
@@ -2410,7 +2466,7 @@ describe('lua stdlib', function()
)
end)
- it('should automatically set when calling remove with a table', function()
+ it('automatically sets when calling remove with a table', function()
eq(
'foo',
exec_lua [[
@@ -2422,7 +2478,7 @@ describe('lua stdlib', function()
)
end)
- it('should automatically set when calling append', function()
+ it('automatically sets when calling append', function()
eq(
'foo,bar,baz,bing',
exec_lua [[
@@ -2434,7 +2490,7 @@ describe('lua stdlib', function()
)
end)
- it('should automatically set when calling append with a table', function()
+ it('automatically sets when calling append with a table', function()
eq(
'foo,bar,baz,bing,zap',
exec_lua [[
@@ -2446,7 +2502,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow adding tables', function()
+ it('allows adding tables', function()
local wildignore = exec_lua [[
vim.opt.wildignore = 'foo'
return vim.o.wildignore
@@ -2460,7 +2516,7 @@ describe('lua stdlib', function()
eq('foo,bar,baz', wildignore)
end)
- it('should handle adding duplicates', function()
+ it('handles adding duplicates', function()
local wildignore = exec_lua [[
vim.opt.wildignore = 'foo'
return vim.o.wildignore
@@ -2480,7 +2536,7 @@ describe('lua stdlib', function()
eq('foo,bar,baz', wildignore)
end)
- it('should allow adding multiple times', function()
+ it('allows adding multiple times', function()
local wildignore = exec_lua [[
vim.opt.wildignore = 'foo'
vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz'
@@ -2489,7 +2545,7 @@ describe('lua stdlib', function()
eq('foo,bar,baz', wildignore)
end)
- it('should remove values when you use minus', function()
+ it('removes values when you use minus', function()
local wildignore = exec_lua [[
vim.opt.wildignore = 'foo'
return vim.o.wildignore
@@ -2509,7 +2565,7 @@ describe('lua stdlib', function()
eq('foo,baz', wildignore)
end)
- it('should prepend values when using ^', function()
+ it('prepends values when using ^', function()
local wildignore = exec_lua [[
vim.opt.wildignore = 'foo'
vim.opt.wildignore = vim.opt.wildignore ^ 'first'
@@ -2524,7 +2580,7 @@ describe('lua stdlib', function()
eq('super_first,first,foo', wildignore)
end)
- it('should not remove duplicates from wildmode: #14708', function()
+ it('does not remove duplicates from wildmode: #14708', function()
local wildmode = exec_lua [[
vim.opt.wildmode = {"full", "list", "full"}
return vim.o.wildmode
@@ -2534,7 +2590,7 @@ describe('lua stdlib', function()
end)
describe('option types', function()
- it('should allow to set option with numeric value', function()
+ it('allows to set option with numeric value', function()
eq(
4,
exec_lua [[
@@ -2583,7 +2639,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow to set option with boolean value', function()
+ it('allows to set option with boolean value', function()
eq(
true,
exec_lua [[
@@ -2632,7 +2688,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow to set option with array or string value', function()
+ it('allows to set option with array or string value', function()
eq(
'indent,eol,start',
exec_lua [[
@@ -2679,7 +2735,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow set option with map or string value', function()
+ it('allows set option with map or string value', function()
eq(
'eol:~,space:.',
exec_lua [[
@@ -2729,7 +2785,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow set option with set or string value', function()
+ it('allows set option with set or string value', function()
local ww = exec_lua [[
vim.opt.whichwrap = {
b = true,
@@ -3179,11 +3235,11 @@ describe('lua stdlib', function()
]]
end)
- it('should run from lua', function()
+ it('runs from lua', function()
exec_lua [[vim.wait(100, function() return true end)]]
end)
- it('should wait the expected time if false', function()
+ it('waits the expected time if false', function()
eq(
{ time = true, wait_result = { false, -1 } },
exec_lua [[
@@ -3199,7 +3255,7 @@ describe('lua stdlib', function()
)
end)
- it('should not block other events', function()
+ it('does not block other events', function()
eq(
{ time = true, wait_result = true },
exec_lua [[
@@ -3224,7 +3280,7 @@ describe('lua stdlib', function()
)
end)
- it('should not process non-fast events when commanded', function()
+ it('does not process non-fast events when commanded', function()
eq(
{ wait_result = false },
exec_lua [[
@@ -3247,7 +3303,7 @@ describe('lua stdlib', function()
)
end)
- it('should work with vim.defer_fn', function()
+ it('works with vim.defer_fn', function()
eq(
{ time = true, wait_result = true },
exec_lua [[
@@ -3264,7 +3320,7 @@ describe('lua stdlib', function()
)
end)
- it('should not crash when callback errors', function()
+ it('does not crash when callback errors', function()
local result = exec_lua [[
return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)}
]]
@@ -3280,7 +3336,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow waiting with no callback, explicit', function()
+ it('allows waiting with no callback, explicit', function()
eq(
true,
exec_lua [[
@@ -3291,7 +3347,7 @@ describe('lua stdlib', function()
)
end)
- it('should allow waiting with no callback, implicit', function()
+ it('allows waiting with no callback, implicit', function()
eq(
true,
exec_lua [[
@@ -3302,7 +3358,7 @@ describe('lua stdlib', function()
)
end)
- it('should call callbacks exactly once if they return true immediately', function()
+ it('calls callbacks exactly once if they return true immediately', function()
eq(
true,
exec_lua [[
@@ -3316,7 +3372,7 @@ describe('lua stdlib', function()
)
end)
- it('should call callbacks few times with large `interval`', function()
+ it('calls callbacks few times with large `interval`', function()
eq(
true,
exec_lua [[
@@ -3327,7 +3383,7 @@ describe('lua stdlib', function()
)
end)
- it('should play nice with `not` when fails', function()
+ it('plays nice with `not` when fails', function()
eq(
true,
exec_lua [[
@@ -3340,7 +3396,7 @@ describe('lua stdlib', function()
)
end)
- it('should play nice with `if` when success', function()
+ it('plays nice with `if` when success', function()
eq(
true,
exec_lua [[
@@ -3353,7 +3409,7 @@ describe('lua stdlib', function()
)
end)
- it('should return immediately with false if timeout is 0', function()
+ it('returns immediately with false if timeout is 0', function()
eq(
{ false, -1 },
exec_lua [[
@@ -3364,7 +3420,7 @@ describe('lua stdlib', function()
)
end)
- it('should work with tables with __call', function()
+ it('works with tables with __call', function()
eq(
true,
exec_lua [[
@@ -3374,7 +3430,7 @@ describe('lua stdlib', function()
)
end)
- it('should work with tables with __call that change', function()
+ it('works with tables with __call that change', function()
eq(
true,
exec_lua [[
@@ -3391,7 +3447,7 @@ describe('lua stdlib', function()
)
end)
- it('should not work with negative intervals', function()
+ it('fails with negative intervals', function()
local pcall_result = exec_lua [[
return pcall(function() vim.wait(1000, function() return false end, -1) end)
]]
@@ -3399,7 +3455,7 @@ describe('lua stdlib', function()
eq(false, pcall_result)
end)
- it('should not work with weird intervals', function()
+ it('fails with weird intervals', function()
local pcall_result = exec_lua [[
return pcall(function() vim.wait(1000, function() return false end, 'a string value') end)
]]
@@ -3442,7 +3498,7 @@ describe('lua stdlib', function()
end)
end)
- it('should not run in fast callbacks #26122', function()
+ it('fails in fast callbacks #26122', function()
local screen = Screen.new(80, 10)
screen:attach()
exec_lua([[
@@ -3462,15 +3518,11 @@ describe('lua stdlib', function()
it('vim.notify_once', function()
local screen = Screen.new(60, 5)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { foreground = Screen.colors.Red },
- })
screen:attach()
screen:expect {
grid = [[
^ |
- {0:~ }|*3
+ {1:~ }|*3
|
]],
}
@@ -3478,15 +3530,15 @@ describe('lua stdlib', function()
screen:expect {
grid = [[
^ |
- {0:~ }|*3
- {1:I'll only tell you this once...} |
+ {1:~ }|*3
+ {19:I'll only tell you this once...} |
]],
}
feed('<C-l>')
screen:expect {
grid = [[
^ |
- {0:~ }|*3
+ {1:~ }|*3
|
]],
}
@@ -3663,10 +3715,6 @@ describe('lua stdlib', function()
it('updates ruler if cursor moved', function()
-- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too!
local screen = Screen.new(30, 5)
- screen:set_default_attr_ids {
- [1] = { reverse = true },
- [2] = { bold = true, reverse = true },
- }
screen:attach()
exec_lua [[
_G.api = vim.api
@@ -3681,9 +3729,9 @@ describe('lua stdlib', function()
]]
screen:expect [[
19 |
- {1:[No Name] [+] 20,1 3%}|
- ^19 |
{2:[No Name] [+] 20,1 3%}|
+ ^19 |
+ {3:[No Name] [+] 20,1 3%}|
|
]]
exec_lua [[
@@ -3692,9 +3740,9 @@ describe('lua stdlib', function()
]]
screen:expect [[
99 |
- {1:[No Name] [+] 100,1 19%}|
+ {2:[No Name] [+] 100,1 19%}|
^19 |
- {2:[No Name] [+] 20,1 3%}|
+ {3:[No Name] [+] 20,1 3%}|
|
]]
end)
@@ -3810,13 +3858,6 @@ describe('lua stdlib', function()
it('vim.lua_omnifunc', function()
local screen = Screen.new(60, 5)
- screen:set_default_attr_ids {
- [1] = { foreground = Screen.colors.Blue1, bold = true },
- [2] = { background = Screen.colors.WebGray },
- [3] = { background = Screen.colors.LightMagenta },
- [4] = { bold = true },
- [5] = { foreground = Screen.colors.SeaGreen, bold = true },
- }
screen:attach()
command [[ set omnifunc=v:lua.vim.lua_omnifunc ]]
@@ -3826,10 +3867,10 @@ describe('lua stdlib', function()
screen:expect {
grid = [[
vim.inspect^ |
- {1:~ }{2: inspect }{1: }|
- {1:~ }{3: inspect_pos }{1: }|
+ {1:~ }{12: inspect }{1: }|
+ {1:~ }{4: inspect_pos }{1: }|
{1:~ }|
- {4:-- Omni completion (^O^N^P) }{5:match 1 of 2} |
+ {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} |
]],
}
end)
@@ -4002,7 +4043,36 @@ end)
describe('vim.keymap', function()
before_each(clear)
- it('can make a mapping', function()
+ it('validates', function()
+ matches(
+ 'mode: expected string|table, got number',
+ pcall_err(exec_lua, [[vim.keymap.set(42, 'x', print)]])
+ )
+
+ matches(
+ 'rhs: expected string|function, got nil',
+ pcall_err(exec_lua, [[vim.keymap.set('n', 'x')]])
+ )
+
+ matches(
+ 'lhs: expected string, got table',
+ pcall_err(exec_lua, [[vim.keymap.set('n', {}, print)]])
+ )
+
+ matches(
+ 'opts: expected table, got function',
+ pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]])
+ )
+
+ matches(
+ 'rhs: expected string|function, got number',
+ pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]])
+ )
+
+ matches('Invalid mode shortname: "z"', pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 'y')]]))
+ end)
+
+ it('mapping', function()
eq(
0,
exec_lua [[
@@ -4017,7 +4087,7 @@ describe('vim.keymap', function()
eq(1, exec_lua [[return GlobalCount]])
end)
- it('can make an expr mapping', function()
+ it('expr mapping', function()
exec_lua [[
vim.keymap.set('n', 'aa', function() return '<Insert>π<C-V><M-π>foo<lt><Esc>' end, {expr = true})
]]
@@ -4027,7 +4097,7 @@ describe('vim.keymap', function()
eq({ 'π<M-π>foo<' }, api.nvim_buf_get_lines(0, 0, -1, false))
end)
- it('can overwrite a mapping', function()
+ it('overwrite a mapping', function()
eq(
0,
exec_lua [[
@@ -4050,7 +4120,7 @@ describe('vim.keymap', function()
eq(0, exec_lua [[return GlobalCount]])
end)
- it('can unmap a mapping', function()
+ it('unmap', function()
eq(
0,
exec_lua [[
@@ -4074,7 +4144,7 @@ describe('vim.keymap', function()
eq('\nNo mapping found', n.exec_capture('nmap asdf'))
end)
- it('works with buffer-local mappings', function()
+ it('buffer-local mappings', function()
eq(
0,
exec_lua [[
@@ -4116,7 +4186,7 @@ describe('vim.keymap', function()
)
end)
- it('can do <Plug> mappings', function()
+ it('<Plug> mappings', function()
eq(
0,
exec_lua [[
diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua
index bd8faadf5b..ad16df8a7c 100644
--- a/test/functional/lua/watch_spec.lua
+++ b/test/functional/lua/watch_spec.lua
@@ -12,7 +12,6 @@ local skip = t.skip
-- events which can happen with some backends on some platforms
local function touch(path)
local tmp = t.tmpname()
- io.open(tmp, 'w'):close()
assert(vim.uv.fs_rename(tmp, path))
end
@@ -22,16 +21,78 @@ describe('vim._watch', function()
end)
local function run(watchfunc)
- it('detects file changes (watchfunc=' .. watchfunc .. '())', function()
- if watchfunc == 'fswatch' then
+ -- Monkey-patches vim.notify_once so we can "spy" on it.
+ local function spy_notify_once()
+ exec_lua [[
+ _G.__notify_once_msgs = {}
+ vim.notify_once = (function(overridden)
+ return function(msg, level, opts)
+ table.insert(_G.__notify_once_msgs, msg)
+ return overridden(msg, level, opts)
+ end
+ end)(vim.notify_once)
+ ]]
+ end
+
+ local function last_notify_once_msg()
+ return exec_lua 'return _G.__notify_once_msgs[#_G.__notify_once_msgs]'
+ end
+
+ local function do_watch(root_dir, watchfunc_)
+ exec_lua(
+ [[
+ local root_dir, watchfunc = ...
+
+ _G.events = {}
+
+ _G.stop_watch = vim._watch[watchfunc](root_dir, {
+ debounce = 100,
+ include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1,
+ exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'),
+ }, function(path, change_type)
+ table.insert(_G.events, { path = path, change_type = change_type })
+ end)
+ ]],
+ root_dir,
+ watchfunc_
+ )
+ end
+
+ it(watchfunc .. '() ignores nonexistent paths', function()
+ if watchfunc == 'inotify' then
+ skip(n.fn.executable('inotifywait') == 0, 'inotifywait not found')
+ skip(is_os('bsd'), 'inotifywait on bsd CI seems to expect path to exist?')
+ end
+
+ local msg = ('watch.%s: ENOENT: no such file or directory'):format(watchfunc)
+
+ spy_notify_once()
+ do_watch('/i am /very/funny.go', watchfunc)
+
+ if watchfunc ~= 'inotify' then -- watch.inotify() doesn't (currently) call vim.notify_once.
+ t.retry(nil, 2000, function()
+ t.eq(msg, last_notify_once_msg())
+ end)
+ end
+ eq(0, exec_lua [[return #_G.events]])
+
+ exec_lua [[_G.stop_watch()]]
+ end)
+
+ it(watchfunc .. '() detects file changes', function()
+ if watchfunc == 'inotify' then
skip(is_os('win'), 'not supported on windows')
skip(is_os('mac'), 'flaky test on mac')
- skip(not is_ci() and n.fn.executable('fswatch') == 0, 'fswatch not installed and not on CI')
+ skip(not is_ci() and n.fn.executable('inotifywait') == 0, 'inotifywait not found')
end
+ -- Note: because this is not `elseif`, BSD is skipped for *all* cases...?
if watchfunc == 'watch' then
skip(is_os('mac'), 'flaky test on mac')
skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38')
+ elseif watchfunc == 'watchdirs' and is_os('mac') then
+ -- Bump this (or fix the bug) if CI continues to fail in future versions of macos CI.
+ skip(is_ci() and vim.uv.os_uname().release == '24.0.0', 'weird failure for macOS arm 15 CI')
else
skip(
is_os('bsd'),
@@ -39,10 +100,8 @@ describe('vim._watch', function()
)
end
- local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname()) .. '/nvim_XXXXXXXXXX')
-
local expected_events = 0
-
+ --- Waits for a new event, or fails if no events are triggered.
local function wait_for_event()
expected_events = expected_events + 1
exec_lua(
@@ -63,26 +122,11 @@ describe('vim._watch', function()
)
end
+ local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(t.tmpname(false)) .. '/nvim_XXXXXXXXXX')
local unwatched_path = root_dir .. '/file.unwatched'
local watched_path = root_dir .. '/file'
- exec_lua(
- [[
- local root_dir, watchfunc = ...
-
- _G.events = {}
-
- _G.stop_watch = vim._watch[watchfunc](root_dir, {
- debounce = 100,
- include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1,
- exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'),
- }, function(path, change_type)
- table.insert(_G.events, { path = path, change_type = change_type })
- end)
- ]],
- root_dir,
- watchfunc
- )
+ do_watch(root_dir, watchfunc)
if watchfunc ~= 'watch' then
vim.uv.sleep(200)
@@ -90,16 +134,13 @@ describe('vim._watch', function()
touch(watched_path)
touch(unwatched_path)
-
wait_for_event()
os.remove(watched_path)
os.remove(unwatched_path)
-
wait_for_event()
exec_lua [[_G.stop_watch()]]
-
-- No events should come through anymore
vim.uv.sleep(100)
@@ -123,5 +164,5 @@ describe('vim._watch', function()
run('watch')
run('watchdirs')
- run('fswatch')
+ run('inotify')
end)
diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua
new file mode 100644
index 0000000000..99b80ef749
--- /dev/null
+++ b/test/functional/lua/with_spec.lua
@@ -0,0 +1,1626 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+
+local fn = n.fn
+local api = n.api
+local command = n.command
+local eq = t.eq
+local exec_lua = n.exec_lua
+local exec_capture = n.exec_capture
+local matches = t.matches
+local pcall_err = t.pcall_err
+
+describe('vim._with', function()
+ before_each(function()
+ n.clear()
+ exec_lua([[
+ _G.fn = vim.fn
+ _G.api = vim.api
+
+ _G.setup_buffers = function()
+ return api.nvim_create_buf(false, true), api.nvim_get_current_buf()
+ end
+
+ _G.setup_windows = function()
+ local other_win = api.nvim_get_current_win()
+ vim.cmd.new()
+ return other_win, api.nvim_get_current_win()
+ end
+ ]])
+ end)
+
+ local assert_events_trigger = function()
+ local out = exec_lua [[
+ -- Needs three global values defined:
+ -- - `test_events` - array of events which are tested.
+ -- - `test_context` - context to be tested.
+ -- - `test_trig_event` - callable triggering at least one tested event.
+ _G.n_events = 0
+ local opts = { callback = function() _G.n_events = _G.n_events + 1 end }
+ api.nvim_create_autocmd(_G.test_events, opts)
+
+ local context = { bo = { commentstring = '-- %s' } }
+
+ -- Should not trigger events on its own
+ vim._with(_G.test_context, function() end)
+ local is_no_events = _G.n_events == 0
+
+ -- Should trigger events if specifically asked inside callback
+ local is_events = vim._with(_G.test_context, function()
+ _G.test_trig_event()
+ return _G.n_events > 0
+ end)
+ return { is_no_events, is_events }
+ ]]
+ eq({ true, true }, out)
+ end
+
+ describe('`bo` context', function()
+ before_each(function()
+ exec_lua [[
+ _G.other_buf, _G.cur_buf = setup_buffers()
+
+ -- 'commentstring' is local to buffer and string
+ vim.bo[other_buf].commentstring = '## %s'
+ vim.bo[cur_buf].commentstring = '// %s'
+ vim.go.commentstring = '$$ %s'
+
+ -- 'undolevels' is global or local to buffer (global-local) and number
+ vim.bo[other_buf].undolevels = 100
+ vim.bo[cur_buf].undolevels = 250
+ vim.go.undolevels = 500
+
+ _G.get_state = function()
+ return {
+ bo = {
+ cms_cur = vim.bo[cur_buf].commentstring,
+ cms_other = vim.bo[other_buf].commentstring,
+ ul_cur = vim.bo[cur_buf].undolevels,
+ ul_other = vim.bo[other_buf].undolevels,
+ },
+ go = {
+ cms = vim.go.commentstring,
+ ul = vim.go.undolevels,
+ },
+ }
+ end
+ ]]
+ end)
+
+ it('works', function()
+ local out = exec_lua [[
+ local context = { bo = { commentstring = '-- %s', undolevels = 0 } }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_buf() == cur_buf)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = 0, ul_other = 100 },
+ go = { cms = '$$ %s', ul = 500 },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('sets options in `buf` context', function()
+ local out = exec_lua [[
+ local context = { buf = other_buf, bo = { commentstring = '-- %s', undolevels = 0 } }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_buf() == other_buf)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = 0 },
+ go = { cms = '$$ %s', ul = 500 },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('restores only options from context', function()
+ local out = exec_lua [[
+ local context = { bo = { commentstring = '-- %s' } }
+
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_buf() == cur_buf)
+ vim.bo[cur_buf].undolevels = 750
+ vim.bo[cur_buf].commentstring = '!! %s'
+ return get_state()
+ end)
+
+ return { inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 },
+ go = { cms = '$$ %s', ul = 500 },
+ }, out.inner)
+ eq({
+ bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 },
+ go = { cms = '$$ %s', ul = 500 },
+ }, out.after)
+ end)
+
+ it('does not trigger events', function()
+ exec_lua [[
+ _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }
+ _G.test_context = { bo = { commentstring = '-- %s' } }
+ _G.test_trig_event = function() vim.cmd.new() end
+ ]]
+ assert_events_trigger()
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ local before, before_inner, after_inner = get_state(), nil, nil
+ vim._with({ bo = { commentstring = '-- %s', undolevels = 0 } }, function()
+ before_inner = get_state()
+ inner = vim._with({ bo = { commentstring = '!! %s' } }, get_state)
+ after_inner = get_state()
+ end)
+ return {
+ before = before, before_inner = before_inner,
+ inner = inner,
+ after_inner = after_inner, after = get_state(),
+ }
+ ]]
+ eq('!! %s', out.inner.bo.cms_cur)
+ eq(0, out.inner.bo.ul_cur)
+ eq(out.before_inner, out.after_inner)
+ eq(out.before, out.after)
+ end)
+ end)
+
+ describe('`buf` context', function()
+ it('works', function()
+ local out = exec_lua [[
+ local other_buf, cur_buf = setup_buffers()
+ local inner = vim._with({ buf = other_buf }, function()
+ return api.nvim_get_current_buf()
+ end)
+ return { inner == other_buf, api.nvim_get_current_buf() == cur_buf }
+ ]]
+ eq({ true, true }, out)
+ end)
+
+ it('does not trigger events', function()
+ exec_lua [[
+ _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }
+ _G.test_context = { buf = other_buf }
+ _G.test_trig_event = function() vim.cmd.new() end
+ ]]
+ assert_events_trigger()
+ end)
+
+ it('can access buffer options', function()
+ local out = exec_lua [[
+ other_buf, cur_buf = setup_buffers()
+ vim.bo[other_buf].commentstring = '## %s'
+ vim.bo[cur_buf].commentstring = '// %s'
+
+ vim._with({ buf = other_buf }, function()
+ vim.cmd.set('commentstring=--\\ %s')
+ end)
+
+ return vim.bo[other_buf].commentstring == '-- %s' and
+ vim.bo[cur_buf].commentstring == '// %s'
+ ]]
+ eq(true, out)
+ end)
+
+ it('works with different kinds of buffers', function()
+ exec_lua [[
+ local assert_buf = function(buf)
+ vim._with({ buf = buf }, function()
+ assert(api.nvim_get_current_buf() == buf)
+ end)
+ end
+
+ -- Current
+ assert_buf(api.nvim_get_current_buf())
+
+ -- Hidden listed
+ local listed = api.nvim_create_buf(true, true)
+ assert_buf(listed)
+
+ -- Visible
+ local other_win, cur_win = setup_windows()
+ api.nvim_win_set_buf(other_win, listed)
+ assert_buf(listed)
+
+ -- Shown but not visible
+ vim.cmd.tabnew()
+ assert_buf(listed)
+
+ -- Shown in several windows
+ api.nvim_win_set_buf(0, listed)
+ assert_buf(listed)
+
+ -- Shown in floating window
+ local float_buf = api.nvim_create_buf(false, true)
+ local config = { relative = 'editor', row = 1, col = 1, width = 5, height = 5 }
+ api.nvim_open_win(float_buf, false, config)
+ assert_buf(float_buf)
+ ]]
+ end)
+
+ it('does not cause ml_get errors with invalid visual selection', function()
+ exec_lua [[
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' })
+ api.nvim_feedkeys(vim.keycode('G<C-V>'), 'txn', false)
+ local other_buf, _ = setup_buffers()
+ vim._with({ buf = buf }, function() vim.cmd.redraw() end)
+ ]]
+ end)
+
+ it('can be nested', function()
+ exec_lua [[
+ local other_buf, cur_buf = setup_buffers()
+ vim._with({ buf = other_buf }, function()
+ assert(api.nvim_get_current_buf() == other_buf)
+ inner = vim._with({ buf = cur_buf }, function()
+ assert(api.nvim_get_current_buf() == cur_buf)
+ end)
+ assert(api.nvim_get_current_buf() == other_buf)
+ end)
+ assert(api.nvim_get_current_buf() == cur_buf)
+ ]]
+ end)
+
+ it('can be nested crazily with hidden buffers', function()
+ local out = exec_lua([[
+ local n = 0
+ local function with_recursive_nested_bufs()
+ n = n + 1
+ if n > 20 then return true end
+
+ local other_buf, _ = setup_buffers()
+ vim.bo[other_buf].commentstring = '## %s'
+ local callback = function()
+ return api.nvim_get_current_buf() == other_buf
+ and vim.bo[other_buf].commentstring == '## %s'
+ and with_recursive_nested_bufs()
+ end
+ return vim._with({ buf = other_buf }, callback) and
+ api.nvim_buf_delete(other_buf, {}) == nil
+ end
+
+ return with_recursive_nested_bufs()
+ ]])
+ eq(true, out)
+ end)
+ end)
+
+ describe('`emsg_silent` context', function()
+ pending('works', function()
+ local ok = pcall(
+ exec_lua,
+ [[
+ _G.f = function()
+ error('This error should not interfer with execution', 0)
+ end
+ -- Should not produce error same as `vim.cmd('silent! lua _G.f()')`
+ vim._with({ emsg_silent = true }, f)
+ ]]
+ )
+ eq(true, ok)
+
+ -- Should properly report errors afterwards
+ ok = pcall(exec_lua, 'lua _G.f()')
+ eq(false, ok)
+ end)
+
+ it('can be nested', function()
+ local ok = pcall(
+ exec_lua,
+ [[
+ _G.f = function()
+ error('This error should not interfer with execution', 0)
+ end
+ -- Should produce error same as `_G.f()`
+ vim._with({ emsg_silent = true }, function()
+ vim._with( { emsg_silent = false }, f)
+ end)
+ ]]
+ )
+ eq(false, ok)
+ end)
+ end)
+
+ describe('`env` context', function()
+ before_each(function()
+ exec_lua [[
+ vim.fn.setenv('aaa', 'hello')
+ _G.get_state = function()
+ return { aaa = vim.fn.getenv('aaa'), bbb = vim.fn.getenv('bbb') }
+ end
+ ]]
+ end)
+
+ it('works', function()
+ local out = exec_lua [[
+ local context = { env = { aaa = 'inside', bbb = 'wow' } }
+ local before = get_state()
+ local inner = vim._with(context, get_state)
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({ aaa = 'inside', bbb = 'wow' }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('restores only variables from context', function()
+ local out = exec_lua [[
+ local context = { env = { bbb = 'wow' } }
+ local before = get_state()
+ local inner = vim._with(context, function()
+ vim.env.aaa = 'inside'
+ return get_state()
+ end)
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({ aaa = 'inside', bbb = 'wow' }, out.inner)
+ eq({ aaa = 'inside', bbb = vim.NIL }, out.after)
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ local before, before_inner, after_inner = get_state(), nil, nil
+ vim._with({ env = { aaa = 'inside', bbb = 'wow' } }, function()
+ before_inner = get_state()
+ inner = vim._with({ env = { aaa = 'more inside' } }, get_state)
+ after_inner = get_state()
+ end)
+ return {
+ before = before, before_inner = before_inner,
+ inner = inner,
+ after_inner = after_inner, after = get_state(),
+ }
+ ]]
+ eq('more inside', out.inner.aaa)
+ eq('wow', out.inner.bbb)
+ eq(out.before_inner, out.after_inner)
+ eq(out.before, out.after)
+ end)
+ end)
+
+ describe('`go` context', function()
+ before_each(function()
+ exec_lua [[
+ vim.bo.commentstring = '## %s'
+ vim.go.commentstring = '$$ %s'
+ vim.wo.winblend = 25
+ vim.go.winblend = 50
+ vim.go.langmap = 'xy,yx'
+
+ _G.get_state = function()
+ return {
+ bo = { cms = vim.bo.commentstring },
+ wo = { winbl = vim.wo.winblend },
+ go = {
+ cms = vim.go.commentstring,
+ winbl = vim.go.winblend,
+ lmap = vim.go.langmap,
+ },
+ }
+ end
+ ]]
+ end)
+
+ it('works', function()
+ local out = exec_lua [[
+ local context = {
+ go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' },
+ }
+ local before = get_state()
+ local inner = vim._with(context, get_state)
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms = '## %s' },
+ wo = { winbl = 25 },
+ go = { cms = '-- %s', winbl = 75, lmap = 'ab,ba' },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('works with `eventignore`', function()
+ -- This might be an issue if saving and restoring option context is done
+ -- to account for triggering `OptionSet`, but in not a good way
+ local out = exec_lua [[
+ vim.go.eventignore = 'ModeChanged'
+ local inner = vim._with({ go = { eventignore = 'CursorMoved' } }, function()
+ return vim.go.eventignore
+ end)
+ return { inner = inner, after = vim.go.eventignore }
+ ]]
+ eq({ inner = 'CursorMoved', after = 'ModeChanged' }, out)
+ end)
+
+ it('restores only options from context', function()
+ local out = exec_lua [[
+ local context = { go = { langmap = 'ab,ba' } }
+
+ local inner = vim._with(context, function()
+ vim.go.commentstring = '!! %s'
+ vim.go.winblend = 75
+ vim.go.langmap = 'uv,vu'
+ return get_state()
+ end)
+
+ return { inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms = '## %s' },
+ wo = { winbl = 25 },
+ go = { cms = '!! %s', winbl = 75, lmap = 'uv,vu' },
+ }, out.inner)
+ eq({
+ bo = { cms = '## %s' },
+ wo = { winbl = 25 },
+ go = { cms = '!! %s', winbl = 75, lmap = 'xy,yx' },
+ }, out.after)
+ end)
+
+ it('does not trigger events', function()
+ exec_lua [[
+ _G.test_events = {
+ 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave', 'WinEnter', 'WinLeave'
+ }
+ _G.test_context = { go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' } }
+ _G.test_trig_event = function() vim.cmd.new() end
+ ]]
+ assert_events_trigger()
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ local before, before_inner, after_inner = get_state(), nil, nil
+ vim._with({ go = { langmap = 'ab,ba', commentstring = '-- %s' } }, function()
+ before_inner = get_state()
+ inner = vim._with({ go = { langmap = 'uv,vu' } }, get_state)
+ after_inner = get_state()
+ end)
+ return {
+ before = before, before_inner = before_inner,
+ inner = inner,
+ after_inner = after_inner, after = get_state(),
+ }
+ ]]
+ eq('uv,vu', out.inner.go.lmap)
+ eq('-- %s', out.inner.go.cms)
+ eq(out.before_inner, out.after_inner)
+ eq(out.before, out.after)
+ end)
+ end)
+
+ describe('`hide` context', function()
+ pending('works', function()
+ local ok = pcall(
+ exec_lua,
+ [[
+ vim.o.hidden = false
+ vim.bo.modified = true
+ local init_buf = api.nvim_get_current_buf()
+ -- Should not produce error same as `vim.cmd('hide enew')`
+ vim._with({ hide = true }, function()
+ vim.cmd.enew()
+ end)
+ assert(api.nvim_get_current_buf() ~= init_buf)
+ ]]
+ )
+ eq(true, ok)
+ end)
+
+ it('can be nested', function()
+ local ok = pcall(
+ exec_lua,
+ [[
+ vim.o.hidden = false
+ vim.bo.modified = true
+ -- Should produce error same as `vim.cmd.enew()`
+ vim._with({ hide = true }, function()
+ vim._with({ hide = false }, function()
+ vim.cmd.enew()
+ end)
+ end)
+ ]]
+ )
+ eq(false, ok)
+ end)
+ end)
+
+ describe('`horizontal` context', function()
+ local is_approx_eq = function(dim, id_1, id_2)
+ local f = dim == 'height' and api.nvim_win_get_height or api.nvim_win_get_width
+ return math.abs(f(id_1) - f(id_2)) <= 1
+ end
+
+ local win_id_1, win_id_2, win_id_3
+ before_each(function()
+ win_id_1 = api.nvim_get_current_win()
+ command('wincmd v | wincmd 5>')
+ win_id_2 = api.nvim_get_current_win()
+ command('wincmd s | wincmd 5+')
+ win_id_3 = api.nvim_get_current_win()
+
+ eq(is_approx_eq('width', win_id_1, win_id_2), false)
+ eq(is_approx_eq('height', win_id_3, win_id_2), false)
+ end)
+
+ pending('works', function()
+ exec_lua [[
+ -- Should be same as `vim.cmd('horizontal wincmd =')`
+ vim._with({ horizontal = true }, function()
+ vim.cmd.wincmd('=')
+ end)
+ ]]
+ eq(is_approx_eq('width', win_id_1, win_id_2), true)
+ eq(is_approx_eq('height', win_id_3, win_id_2), false)
+ end)
+
+ pending('can be nested', function()
+ exec_lua [[
+ -- Should be same as `vim.cmd.wincmd('=')`
+ vim._with({ horizontal = true }, function()
+ vim._with({ horizontal = false }, function()
+ vim.cmd.wincmd('=')
+ end)
+ end)
+ ]]
+ eq(is_approx_eq('width', win_id_1, win_id_2), true)
+ eq(is_approx_eq('height', win_id_3, win_id_2), true)
+ end)
+ end)
+
+ describe('`keepalt` context', function()
+ pending('works', function()
+ local out = exec_lua [[
+ vim.cmd('edit alt')
+ vim.cmd('edit new')
+ assert(fn.bufname('#') == 'alt')
+
+ -- Should work as `vim.cmd('keepalt edit very-new')`
+ vim._with({ keepalt = true }, function()
+ vim.cmd.edit('very-new')
+ end)
+ return fn.bufname('#') == 'alt'
+ ]]
+ eq(true, out)
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ vim.cmd('edit alt')
+ vim.cmd('edit new')
+ assert(fn.bufname('#') == 'alt')
+
+ -- Should work as `vim.cmd.edit('very-new')`
+ vim._with({ keepalt = true }, function()
+ vim._with({ keepalt = false }, function()
+ vim.cmd.edit('very-new')
+ end)
+ end)
+ return fn.bufname('#') == 'alt'
+ ]]
+ eq(false, out)
+ end)
+ end)
+
+ describe('`keepjumps` context', function()
+ pending('works', function()
+ local out = exec_lua [[
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
+ local jumplist_before = fn.getjumplist()
+ -- Should work as `vim.cmd('keepjumps normal! Ggg')`
+ vim._with({ keepjumps = true }, function()
+ vim.cmd('normal! Ggg')
+ end)
+ return vim.deep_equal(jumplist_before, fn.getjumplist())
+ ]]
+ eq(true, out)
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
+ local jumplist_before = fn.getjumplist()
+ vim._with({ keepjumps = true }, function()
+ vim._with({ keepjumps = false }, function()
+ vim.cmd('normal! Ggg')
+ end)
+ end)
+ return vim.deep_equal(jumplist_before, fn.getjumplist())
+ ]]
+ eq(false, out)
+ end)
+ end)
+
+ describe('`keepmarks` context', function()
+ pending('works', function()
+ local out = exec_lua [[
+ vim.cmd('set cpoptions+=R')
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' })
+ api.nvim_buf_set_mark(0, 'm', 2, 2, {})
+
+ -- Should be the same as `vim.cmd('keepmarks %!sort')`
+ vim._with({ keepmarks = true }, function()
+ vim.cmd('%!sort')
+ end)
+ return api.nvim_buf_get_mark(0, 'm')
+ ]]
+ eq({ 2, 2 }, out)
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ vim.cmd('set cpoptions+=R')
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' })
+ api.nvim_buf_set_mark(0, 'm', 2, 2, {})
+
+ vim._with({ keepmarks = true }, function()
+ vim._with({ keepmarks = false }, function()
+ vim.cmd('%!sort')
+ end)
+ end)
+ return api.nvim_buf_get_mark(0, 'm')
+ ]]
+ eq({ 0, 2 }, out)
+ end)
+ end)
+
+ describe('`keepatterns` context', function()
+ pending('works', function()
+ local out = exec_lua [[
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })
+ vim.cmd('/aaa')
+ -- Should be the same as `vim.cmd('keeppatterns /bbb')`
+ vim._with({ keeppatterns = true }, function()
+ vim.cmd('/bbb')
+ end)
+ return fn.getreg('/')
+ ]]
+ eq('aaa', out)
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })
+ vim.cmd('/aaa')
+ vim._with({ keeppatterns = true }, function()
+ vim._with({ keeppatterns = false }, function()
+ vim.cmd('/bbb')
+ end)
+ end)
+ return fn.getreg('/')
+ ]]
+ eq('bbb', out)
+ end)
+ end)
+
+ describe('`lockmarks` context', function()
+ it('works', function()
+ local mark = exec_lua [[
+ api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' })
+ api.nvim_buf_set_mark(0, 'm', 2, 2, {})
+ -- Should be same as `:lockmarks lua api.nvim_buf_set_lines(...)`
+ vim._with({ lockmarks = true }, function()
+ api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' })
+ end)
+ return api.nvim_buf_get_mark(0, 'm')
+ ]]
+ eq({ 2, 2 }, mark)
+ end)
+
+ it('can be nested', function()
+ local mark = exec_lua [[
+ api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' })
+ api.nvim_buf_set_mark(0, 'm', 2, 2, {})
+ vim._with({ lockmarks = true }, function()
+ vim._with({ lockmarks = false }, function()
+ api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' })
+ end)
+ end)
+ return api.nvim_buf_get_mark(0, 'm')
+ ]]
+ eq({ 0, 2 }, mark)
+ end)
+ end)
+
+ describe('`noautocmd` context', function()
+ it('works', function()
+ local out = exec_lua [[
+ _G.n_events = 0
+ vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1')
+ -- Should be the same as `vim.cmd('noautocmd normal! vv')`
+ vim._with({ noautocmd = true }, function()
+ vim.cmd('normal! vv')
+ end)
+ return _G.n_events
+ ]]
+ eq(0, out)
+ end)
+
+ it('works with User events', function()
+ local out = exec_lua [[
+ _G.n_events = 0
+ vim.cmd('au User MyEvent lua _G.n_events = _G.n_events + 1')
+ -- Should be the same as `vim.cmd('noautocmd doautocmd User MyEvent')`
+ vim._with({ noautocmd = true }, function()
+ api.nvim_exec_autocmds('User', { pattern = 'MyEvent' })
+ end)
+ return _G.n_events
+ ]]
+ eq(0, out)
+ end)
+
+ pending('can be nested', function()
+ local out = exec_lua [[
+ _G.n_events = 0
+ vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1')
+ vim._with({ noautocmd = true }, function()
+ vim._with({ noautocmd = false }, function()
+ vim.cmd('normal! vv')
+ end)
+ end)
+ return _G.n_events
+ ]]
+ eq(2, out)
+ end)
+ end)
+
+ describe('`o` context', function()
+ before_each(function()
+ exec_lua [[
+ _G.other_win, _G.cur_win = setup_windows()
+ _G.other_buf, _G.cur_buf = setup_buffers()
+
+ vim.bo[other_buf].commentstring = '## %s'
+ vim.bo[cur_buf].commentstring = '// %s'
+ vim.go.commentstring = '$$ %s'
+
+ vim.bo[other_buf].undolevels = 100
+ vim.bo[cur_buf].undolevels = 250
+ vim.go.undolevels = 500
+
+ vim.wo[other_win].virtualedit = 'block'
+ vim.wo[cur_win].virtualedit = 'insert'
+ vim.go.virtualedit = 'none'
+
+ vim.wo[other_win].winblend = 10
+ vim.wo[cur_win].winblend = 25
+ vim.go.winblend = 50
+
+ vim.go.langmap = 'xy,yx'
+
+ _G.get_state = function()
+ return {
+ bo = {
+ cms_cur = vim.bo[cur_buf].commentstring,
+ cms_other = vim.bo[other_buf].commentstring,
+ ul_cur = vim.bo[cur_buf].undolevels,
+ ul_other = vim.bo[other_buf].undolevels,
+ },
+ wo = {
+ ve_cur = vim.wo[cur_win].virtualedit,
+ ve_other = vim.wo[other_win].virtualedit,
+ winbl_cur = vim.wo[cur_win].winblend,
+ winbl_other = vim.wo[other_win].winblend,
+ },
+ go = {
+ cms = vim.go.commentstring,
+ ul = vim.go.undolevels,
+ ve = vim.go.virtualedit,
+ winbl = vim.go.winblend,
+ lmap = vim.go.langmap,
+ },
+ }
+ end
+ ]]
+ end)
+
+ it('works', function()
+ local out = exec_lua [[
+ local context = {
+ o = {
+ commentstring = '-- %s',
+ undolevels = 0,
+ virtualedit = 'all',
+ winblend = 75,
+ langmap = 'ab,ba',
+ },
+ }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_buf() == cur_buf)
+ assert(api.nvim_get_current_win() == cur_win)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ -- Options in context are set with `vim.o`, so usually both local
+ -- and global values are affected. Yet all of them should be later
+ -- restored to pre-context values.
+ eq({
+ bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 },
+ wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 },
+ go = { cms = '-- %s', ul = 0, ve = 'all', winbl = 75, lmap = 'ab,ba' },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('sets options in `buf` context', function()
+ local out = exec_lua [[
+ local context = { buf = other_buf, o = { commentstring = '-- %s', undolevels = 0 } }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_buf() == other_buf)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = -123456 },
+ wo = { ve_cur = 'insert', ve_other = 'block', winbl_cur = 25, winbl_other = 10 },
+ -- Global `winbl` inside context ideally should be untouched and equal
+ -- to 50. It seems to be equal to 0 because `context.buf` uses
+ -- `aucmd_prepbuf` C approach which has no guarantees about window or
+ -- window option values inside context.
+ go = { cms = '-- %s', ul = 0, ve = 'none', winbl = 0, lmap = 'xy,yx' },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('sets options in `win` context', function()
+ local out = exec_lua [[
+ local context = { win = other_win, o = { winblend = 75, virtualedit = 'all' } }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_win() == other_win)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 },
+ wo = { winbl_cur = 25, winbl_other = 75, ve_cur = 'insert', ve_other = 'all' },
+ go = { cms = '$$ %s', ul = 500, winbl = 75, ve = 'all', lmap = 'xy,yx' },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('restores only options from context', function()
+ local out = exec_lua [[
+ local context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } }
+
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_buf() == cur_buf)
+ assert(api.nvim_get_current_win() == cur_win)
+
+ vim.o.commentstring = '!! %s'
+ vim.o.undolevels = 750
+ vim.o.virtualedit = 'onemore'
+ vim.o.winblend = 99
+ vim.o.langmap = 'uv,vu'
+ return get_state()
+ end)
+
+ return { inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 },
+ wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 },
+ go = { cms = '!! %s', ul = 750, ve = 'onemore', winbl = 99, lmap = 'uv,vu' },
+ }, out.inner)
+ eq({
+ bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 },
+ wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 },
+ go = { cms = '!! %s', ul = 500, ve = 'onemore', winbl = 50, lmap = 'xy,yx' },
+ }, out.after)
+ end)
+
+ it('does not trigger events', function()
+ exec_lua [[
+ _G.test_events = {
+ 'BufEnter', 'BufLeave', 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave'
+ }
+ _G.test_context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } }
+ _G.test_trig_event = function() vim.cmd.new() end
+ ]]
+ assert_events_trigger()
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ local before, before_inner, after_inner = get_state(), nil, nil
+ local cxt_o = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba', undolevels = 0 }
+ vim._with({ o = cxt_o }, function()
+ before_inner = get_state()
+ local inner_cxt_o = { commentstring = '!! %s', winblend = 99, langmap = 'uv,vu' }
+ inner = vim._with({ o = inner_cxt_o }, get_state)
+ after_inner = get_state()
+ end)
+ return {
+ before = before, before_inner = before_inner,
+ inner = inner,
+ after_inner = after_inner, after = get_state(),
+ }
+ ]]
+ eq('!! %s', out.inner.bo.cms_cur)
+ eq(99, out.inner.wo.winbl_cur)
+ eq('uv,vu', out.inner.go.lmap)
+ eq(0, out.inner.go.ul)
+ eq(out.before_inner, out.after_inner)
+ eq(out.before, out.after)
+ end)
+ end)
+
+ describe('`sandbox` context', function()
+ it('works', function()
+ local ok, err = pcall(
+ exec_lua,
+ [[
+ -- Should work as `vim.cmd('sandbox call append(0, "aaa")')`
+ vim._with({ sandbox = true }, function()
+ fn.append(0, 'aaa')
+ end)
+ ]]
+ )
+ eq(false, ok)
+ matches('Not allowed in sandbox', err)
+ end)
+
+ it('can NOT be nested', function()
+ -- This behavior is intentionally different from other flags as allowing
+ -- disabling `sandbox` from nested function seems to be against the point
+ -- of using `sandbox` context in the first place
+ local ok, err = pcall(
+ exec_lua,
+ [[
+ vim._with({ sandbox = true }, function()
+ vim._with({ sandbox = false }, function()
+ fn.append(0, 'aaa')
+ end)
+ end)
+ ]]
+ )
+ eq(false, ok)
+ matches('Not allowed in sandbox', err)
+ end)
+ end)
+
+ describe('`silent` context', function()
+ it('works', function()
+ exec_lua [[
+ -- Should be same as `vim.cmd('silent lua print("aaa")')`
+ vim._with({ silent = true }, function() print('aaa') end)
+ ]]
+ eq('', exec_capture('messages'))
+
+ exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echomsg('"bbb"') end) ]]
+ eq('', exec_capture('messages'))
+
+ local screen = Screen.new(20, 5)
+ screen:set_default_attr_ids {
+ [1] = { bold = true, reverse = true },
+ [2] = { bold = true, foreground = Screen.colors.Blue },
+ }
+ screen:attach()
+ exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]]
+ screen:expect [[
+ ^ |
+ {2:~ }|*3
+ |
+ ]]
+ end)
+
+ pending('can be nested', function()
+ exec_lua [[ vim._with({ silent = true }, function()
+ vim._with({ silent = false }, function()
+ print('aaa')
+ end)
+ end)]]
+ eq('aaa', exec_capture('messages'))
+ end)
+ end)
+
+ describe('`unsilent` context', function()
+ it('works', function()
+ exec_lua [[
+ _G.f = function()
+ -- Should be same as `vim.cmd('unsilent lua print("aaa")')`
+ vim._with({ unsilent = true }, function() print('aaa') end)
+ end
+ ]]
+ command('silent lua f()')
+ eq('aaa', exec_capture('messages'))
+ end)
+
+ pending('can be nested', function()
+ exec_lua [[
+ _G.f = function()
+ vim._with({ unsilent = true }, function()
+ vim._with({ unsilent = false }, function() print('aaa') end)
+ end)
+ end
+ ]]
+ command('silent lua f()')
+ eq('', exec_capture('messages'))
+ end)
+ end)
+
+ describe('`win` context', function()
+ it('works', function()
+ local out = exec_lua [[
+ local other_win, cur_win = setup_windows()
+ local inner = vim._with({ win = other_win }, function()
+ return api.nvim_get_current_win()
+ end)
+ return { inner == other_win, api.nvim_get_current_win() == cur_win }
+ ]]
+ eq({ true, true }, out)
+ end)
+
+ it('does not trigger events', function()
+ exec_lua [[
+ _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' }
+ _G.test_context = { win = other_win }
+ _G.test_trig_event = function() vim.cmd.new() end
+ ]]
+ assert_events_trigger()
+ end)
+
+ it('can access window options', function()
+ local out = exec_lua [[
+ local other_win, cur_win = setup_windows()
+ vim.wo[other_win].winblend = 10
+ vim.wo[cur_win].winblend = 25
+
+ vim._with({ win = other_win }, function()
+ vim.cmd.setlocal('winblend=0')
+ end)
+
+ return vim.wo[other_win].winblend == 0 and vim.wo[cur_win].winblend == 25
+ ]]
+ eq(true, out)
+ end)
+
+ it('works with different kinds of windows', function()
+ exec_lua [[
+ local assert_win = function(win)
+ vim._with({ win = win }, function()
+ assert(api.nvim_get_current_win() == win)
+ end)
+ end
+
+ -- Current
+ assert_win(api.nvim_get_current_win())
+
+ -- Not visible
+ local other_win, cur_win = setup_windows()
+ vim.cmd.tabnew()
+ assert_win(other_win)
+
+ -- Floating
+ local float_win = api.nvim_open_win(
+ api.nvim_create_buf(false, true),
+ false,
+ { relative = 'editor', row = 1, col = 1, height = 5, width = 5}
+ )
+ assert_win(float_win)
+ ]]
+ end)
+
+ it('does not cause ml_get errors with invalid visual selection', function()
+ exec_lua [[
+ local feedkeys = function(keys) api.nvim_feedkeys(vim.keycode(keys), 'txn', false) end
+
+ -- Add lines to the current buffer and make another window looking into an empty buffer.
+ local win_empty, win_lines = setup_windows()
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' })
+
+ -- Start Visual in current window, redraw in other window with fewer lines.
+ -- Should be fixed by vim-patch:8.2.4018.
+ feedkeys('G<C-V>')
+ vim._with({ win = win_empty }, function() vim.cmd.redraw() end)
+
+ -- Start Visual in current window, extend it in other window with more lines.
+ -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected.
+ feedkeys('<Esc>gg')
+ api.nvim_set_current_win(win_empty)
+ feedkeys('gg<C-V>')
+ vim._with({ win = win_lines }, function() feedkeys('G<C-V>') end)
+ vim.cmd.redraw()
+ ]]
+ end)
+
+ it('can be nested', function()
+ exec_lua [[
+ local other_win, cur_win = setup_windows()
+ vim._with({ win = other_win }, function()
+ assert(api.nvim_get_current_win() == other_win)
+ inner = vim._with({ win = cur_win }, function()
+ assert(api.nvim_get_current_win() == cur_win)
+ end)
+ assert(api.nvim_get_current_win() == other_win)
+ end)
+ assert(api.nvim_get_current_win() == cur_win)
+ ]]
+ end)
+
+ it('updates ruler if cursor moved', function()
+ local screen = Screen.new(30, 5)
+ screen:set_default_attr_ids {
+ [1] = { reverse = true },
+ [2] = { bold = true, reverse = true },
+ }
+ screen:attach()
+ exec_lua [[
+ vim.opt.ruler = true
+ local lines = {}
+ for i = 0, 499 do lines[#lines + 1] = tostring(i) end
+ api.nvim_buf_set_lines(0, 0, -1, true, lines)
+ api.nvim_win_set_cursor(0, { 20, 0 })
+ vim.cmd 'split'
+ _G.win = api.nvim_get_current_win()
+ vim.cmd "wincmd w | redraw"
+ ]]
+ screen:expect [[
+ 19 |
+ {1:[No Name] [+] 20,1 3%}|
+ ^19 |
+ {2:[No Name] [+] 20,1 3%}|
+ |
+ ]]
+ exec_lua [[
+ vim._with({ win = win }, function() api.nvim_win_set_cursor(0, { 100, 0 }) end)
+ vim.cmd "redraw"
+ ]]
+ screen:expect [[
+ 99 |
+ {1:[No Name] [+] 100,1 19%}|
+ ^19 |
+ {2:[No Name] [+] 20,1 3%}|
+ |
+ ]]
+ end)
+
+ it('layout in current tabpage does not affect windows in others', function()
+ command('tab split')
+ local t2_move_win = api.nvim_get_current_win()
+ command('vsplit')
+ local t2_other_win = api.nvim_get_current_win()
+ command('tabprevious')
+ matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
+ command('vsplit')
+
+ exec_lua('vim._with({ win = ... }, function() vim.cmd.wincmd "J" end)', t2_move_win)
+ eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2))
+ end)
+ end)
+
+ describe('`wo` context', function()
+ before_each(function()
+ exec_lua [[
+ _G.other_win, _G.cur_win = setup_windows()
+
+ -- 'virtualedit' is global or local to window (global-local) and string
+ vim.wo[other_win].virtualedit = 'block'
+ vim.wo[cur_win].virtualedit = 'insert'
+ vim.go.virtualedit = 'none'
+
+ -- 'winblend' is local to window and number
+ vim.wo[other_win].winblend = 10
+ vim.wo[cur_win].winblend = 25
+ vim.go.winblend = 50
+
+ _G.get_state = function()
+ return {
+ wo = {
+ ve_cur = vim.wo[cur_win].virtualedit,
+ ve_other = vim.wo[other_win].virtualedit,
+ winbl_cur = vim.wo[cur_win].winblend,
+ winbl_other = vim.wo[other_win].winblend,
+ },
+ go = {
+ ve = vim.go.virtualedit,
+ winbl = vim.go.winblend,
+ },
+ }
+ end
+ ]]
+ end)
+
+ it('works', function()
+ local out = exec_lua [[
+ local context = { wo = { virtualedit = 'all', winblend = 75 } }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_win() == cur_win)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 },
+ go = { ve = 'none', winbl = 75 },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('sets options in `win` context', function()
+ local out = exec_lua [[
+ local context = { win = other_win, wo = { virtualedit = 'all', winblend = 75 } }
+
+ local before = get_state()
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_win() == other_win)
+ return get_state()
+ end)
+
+ return { before = before, inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ wo = { ve_cur = 'insert', ve_other = 'all', winbl_cur = 25, winbl_other = 75 },
+ go = { ve = 'none', winbl = 75 },
+ }, out.inner)
+ eq(out.before, out.after)
+ end)
+
+ it('restores only options from context', function()
+ local out = exec_lua [[
+ local context = { wo = { winblend = 75 } }
+
+ local inner = vim._with(context, function()
+ assert(api.nvim_get_current_win() == cur_win)
+ vim.wo[cur_win].virtualedit = 'onemore'
+ vim.wo[cur_win].winblend = 99
+ return get_state()
+ end)
+
+ return { inner = inner, after = get_state() }
+ ]]
+
+ eq({
+ wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 },
+ go = { ve = 'none', winbl = 99 },
+ }, out.inner)
+ eq({
+ wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 },
+ go = { ve = 'none', winbl = 50 },
+ }, out.after)
+ end)
+
+ it('does not trigger events', function()
+ exec_lua [[
+ _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' }
+ _G.test_context = { wo = { winblend = 75 } }
+ _G.test_trig_event = function() vim.cmd.new() end
+ ]]
+ assert_events_trigger()
+ end)
+
+ it('can be nested', function()
+ local out = exec_lua [[
+ local before, before_inner, after_inner = get_state(), nil, nil
+ vim._with({ wo = { winblend = 75, virtualedit = 'all' } }, function()
+ before_inner = get_state()
+ inner = vim._with({ wo = { winblend = 99 } }, get_state)
+ after_inner = get_state()
+ end)
+ return {
+ before = before, before_inner = before_inner,
+ inner = inner,
+ after_inner = after_inner, after = get_state(),
+ }
+ ]]
+ eq(99, out.inner.wo.winbl_cur)
+ eq('all', out.inner.wo.ve_cur)
+ eq(out.before_inner, out.after_inner)
+ eq(out.before, out.after)
+ end)
+ end)
+
+ it('returns what callback returns', function()
+ local out_verify = exec_lua [[
+ out = { vim._with({}, function()
+ return 'a', 2, nil, { 4 }, function() end
+ end) }
+ return {
+ out[1] == 'a', out[2] == 2, out[3] == nil,
+ vim.deep_equal(out[4], { 4 }),
+ type(out[5]) == 'function',
+ vim.tbl_count(out),
+ }
+ ]]
+ eq({ true, true, true, true, true, 4 }, out_verify)
+ end)
+
+ it('can return values by reference', function()
+ local out = exec_lua [[
+ local val = { 4, 10 }
+ local ref = vim._with({}, function() return val end)
+ ref[1] = 7
+ return val
+ ]]
+ eq({ 7, 10 }, out)
+ end)
+
+ it('can not work with conflicting `buf` and `win`', function()
+ local out = exec_lua [[
+ local other_buf, cur_buf = setup_buffers()
+ local other_win, cur_win = setup_windows()
+ assert(api.nvim_win_get_buf(other_win) ~= other_buf)
+ local _, err = pcall(vim._with, { buf = other_buf, win = other_win }, function() end)
+ return err
+ ]]
+ matches('Can not set both `buf` and `win`', out)
+ end)
+
+ it('works with several contexts at once', function()
+ local out = exec_lua [[
+ local other_buf, cur_buf = setup_buffers()
+ vim.bo[other_buf].commentstring = '## %s'
+ api.nvim_buf_set_lines(other_buf, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
+ api.nvim_buf_set_mark(other_buf, 'm', 2, 2, {})
+
+ vim.go.commentstring = '// %s'
+ vim.go.langmap = 'xy,yx'
+
+ local context = {
+ buf = other_buf,
+ bo = { commentstring = '-- %s' },
+ go = { langmap = 'ab,ba' },
+ lockmarks = true,
+ }
+
+ local inner = vim._with(context, function()
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'uuu', 'vvv', 'www' })
+ return {
+ buf = api.nvim_get_current_buf(),
+ bo = { cms = vim.bo.commentstring },
+ go = { cms = vim.go.commentstring, lmap = vim.go.langmap },
+ mark = api.nvim_buf_get_mark(0, 'm')
+ }
+ end)
+
+ local after = {
+ buf = api.nvim_get_current_buf(),
+ bo = { cms = vim.bo[other_buf].commentstring },
+ go = { cms = vim.go.commentstring, lmap = vim.go.langmap },
+ mark = api.nvim_buf_get_mark(other_buf, 'm')
+ }
+
+ return {
+ context_buf = other_buf, cur_buf = cur_buf,
+ inner = inner, after = after
+ }
+ ]]
+
+ eq({
+ buf = out.context_buf,
+ bo = { cms = '-- %s' },
+ go = { cms = '// %s', lmap = 'ab,ba' },
+ mark = { 2, 2 },
+ }, out.inner)
+ eq({
+ buf = out.cur_buf,
+ bo = { cms = '## %s' },
+ go = { cms = '// %s', lmap = 'xy,yx' },
+ mark = { 2, 2 },
+ }, out.after)
+ end)
+
+ it('works with same option set in different contexts', function()
+ local out = exec_lua [[
+ local get_state = function()
+ return {
+ bo = { cms = vim.bo.commentstring },
+ wo = { ve = vim.wo.virtualedit },
+ go = { cms = vim.go.commentstring, ve = vim.go.virtualedit },
+ }
+ end
+
+ vim.bo.commentstring = '// %s'
+ vim.go.commentstring = '$$ %s'
+ vim.wo.virtualedit = 'insert'
+ vim.go.virtualedit = 'none'
+
+ local before = get_state()
+ local context_no_go = {
+ o = { commentstring = '-- %s', virtualedit = 'all' },
+ bo = { commentstring = '!! %s' },
+ wo = { virtualedit = 'onemore' },
+ }
+ local inner_no_go = vim._with(context_no_go, get_state)
+ local middle = get_state()
+ local context_with_go = {
+ o = { commentstring = '-- %s', virtualedit = 'all' },
+ bo = { commentstring = '!! %s' },
+ wo = { virtualedit = 'onemore' },
+ go = { commentstring = '@@ %s', virtualedit = 'block' },
+ }
+ local inner_with_go = vim._with(context_with_go, get_state)
+ return {
+ before = before,
+ inner_no_go = inner_no_go,
+ middle = middle,
+ inner_with_go = inner_with_go,
+ after = get_state(),
+ }
+ ]]
+
+ -- Should prefer explicit local scopes instead of `o`
+ eq({
+ bo = { cms = '!! %s' },
+ wo = { ve = 'onemore' },
+ go = { cms = '-- %s', ve = 'all' },
+ }, out.inner_no_go)
+ eq(out.before, out.middle)
+
+ -- Should prefer explicit global scopes instead of `o`
+ eq({
+ bo = { cms = '!! %s' },
+ wo = { ve = 'onemore' },
+ go = { cms = '@@ %s', ve = 'block' },
+ }, out.inner_with_go)
+ eq(out.middle, out.after)
+ end)
+
+ pending('can forward command modifiers to user command', function()
+ local out = exec_lua [[
+ local test_flags = {
+ 'emsg_silent',
+ 'hide',
+ 'keepalt',
+ 'keepjumps',
+ 'keepmarks',
+ 'keeppatterns',
+ 'lockmarks',
+ 'noautocmd',
+ 'silent',
+ 'unsilent',
+ }
+
+ local used_smods
+ local command = function(data)
+ used_smods = data.smods
+ end
+ api.nvim_create_user_command('DummyLog', command, {})
+
+ local res = {}
+ for _, flag in ipairs(test_flags) do
+ used_smods = nil
+ vim._with({ [flag] = true }, function() vim.cmd('DummyLog') end)
+ res[flag] = used_smods[flag]
+ end
+ return res
+ ]]
+ for k, v in pairs(out) do
+ eq({ k, true }, { k, v })
+ end
+ end)
+
+ it('handles error in callback', function()
+ -- Should still restore initial context
+ local out_buf = exec_lua [[
+ local other_buf, cur_buf = setup_buffers()
+ vim.bo[other_buf].commentstring = '## %s'
+
+ local context = { buf = other_buf, bo = { commentstring = '-- %s' } }
+ local ok, err = pcall(vim._with, context, function() error('Oops buf', 0) end)
+
+ return {
+ ok,
+ err,
+ api.nvim_get_current_buf() == cur_buf,
+ vim.bo[other_buf].commentstring,
+ }
+ ]]
+ eq({ false, 'Oops buf', true, '## %s' }, out_buf)
+
+ local out_win = exec_lua [[
+ local other_win, cur_win = setup_windows()
+ vim.wo[other_win].winblend = 25
+
+ local context = { win = other_win, wo = { winblend = 50 } }
+ local ok, err = pcall(vim._with, context, function() error('Oops win', 0) end)
+
+ return {
+ ok,
+ err,
+ api.nvim_get_current_win() == cur_win,
+ vim.wo[other_win].winblend,
+ }
+ ]]
+ eq({ false, 'Oops win', true, 25 }, out_win)
+ end)
+
+ it('handles not supported option', function()
+ local out = exec_lua [[
+ -- Should still restore initial state
+ vim.bo.commentstring = '## %s'
+
+ local context = { o = { commentstring = '-- %s' }, bo = { winblend = 10 } }
+ local ok, err = pcall(vim._with, context, function() end)
+
+ return { ok = ok, err = err, cms = vim.bo.commentstring }
+ ]]
+ eq(false, out.ok)
+ matches('window.*option.*winblend', out.err)
+ eq('## %s', out.cms)
+ end)
+
+ it('validates arguments', function()
+ exec_lua [[
+ _G.get_error = function(...)
+ local _, err = pcall(vim._with, ...)
+ return err or ''
+ end
+ ]]
+ local get_error = function(string_args)
+ return exec_lua('return get_error(' .. string_args .. ')')
+ end
+
+ matches('context.*table', get_error("'a', function() end"))
+ matches('f.*function', get_error('{}, 1'))
+
+ local assert_context = function(bad_context, expected_type)
+ local bad_field = vim.tbl_keys(bad_context)[1]
+ matches(
+ 'context%.' .. bad_field .. '.*' .. expected_type,
+ get_error(vim.inspect(bad_context) .. ', function() end')
+ )
+ end
+
+ assert_context({ bo = 1 }, 'table')
+ assert_context({ buf = 'a' }, 'number')
+ assert_context({ emsg_silent = 1 }, 'boolean')
+ assert_context({ env = 1 }, 'table')
+ assert_context({ go = 1 }, 'table')
+ assert_context({ hide = 1 }, 'boolean')
+ assert_context({ keepalt = 1 }, 'boolean')
+ assert_context({ keepjumps = 1 }, 'boolean')
+ assert_context({ keepmarks = 1 }, 'boolean')
+ assert_context({ keeppatterns = 1 }, 'boolean')
+ assert_context({ lockmarks = 1 }, 'boolean')
+ assert_context({ noautocmd = 1 }, 'boolean')
+ assert_context({ o = 1 }, 'table')
+ assert_context({ sandbox = 1 }, 'boolean')
+ assert_context({ silent = 1 }, 'boolean')
+ assert_context({ unsilent = 1 }, 'boolean')
+ assert_context({ win = 'a' }, 'number')
+ assert_context({ wo = 1 }, 'table')
+
+ matches('Invalid buffer', get_error('{ buf = -1 }, function() end'))
+ matches('Invalid window', get_error('{ win = -1 }, function() end'))
+ end)
+end)
diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua
index d5589c1f13..269dbde10a 100644
--- a/test/functional/lua/xdiff_spec.lua
+++ b/test/functional/lua/xdiff_spec.lua
@@ -12,15 +12,11 @@ describe('xdiff bindings', function()
end)
describe('can diff text', function()
- before_each(function()
- exec_lua [[
- a1 = 'Hello\n'
- b1 = 'Helli\n'
-
- a2 = 'Hello\nbye\nfoo\n'
- b2 = 'Helli\nbye\nbar\nbaz\n'
- ]]
- end)
+ local a1 = 'Hello\n'
+ local b1 = 'Helli\n'
+
+ local a2 = 'Hello\nbye\nfoo\n'
+ local b2 = 'Helli\nbye\nbar\nbaz\n'
it('with no callback', function()
eq(
@@ -30,7 +26,9 @@ describe('xdiff bindings', function()
'+Helli',
'',
}, '\n'),
- exec_lua('return vim.diff(a1, b1)')
+ exec_lua(function()
+ return vim.diff(a1, b1)
+ end)
)
eq(
@@ -44,63 +42,81 @@ describe('xdiff bindings', function()
'+baz',
'',
}, '\n'),
- exec_lua('return vim.diff(a2, b2)')
+ exec_lua(function()
+ return vim.diff(a2, b2)
+ end)
)
end)
it('with callback', function()
- exec_lua([[on_hunk = function(sa, ca, sb, cb)
- exp[#exp+1] = {sa, ca, sb, cb}
- end]])
-
eq(
{ { 1, 1, 1, 1 } },
- exec_lua [[
- exp = {}
- assert(vim.diff(a1, b1, {on_hunk = on_hunk}) == nil)
+ exec_lua(function()
+ local exp = {} --- @type table[]
+ assert(vim.diff(a1, b1, {
+ on_hunk = function(...)
+ exp[#exp + 1] = { ... }
+ end,
+ }) == nil)
return exp
- ]]
+ end)
)
eq(
{ { 1, 1, 1, 1 }, { 3, 1, 3, 2 } },
- exec_lua [[
- exp = {}
- assert(vim.diff(a2, b2, {on_hunk = on_hunk}) == nil)
+ exec_lua(function()
+ local exp = {} --- @type table[]
+ assert(vim.diff(a2, b2, {
+ on_hunk = function(...)
+ exp[#exp + 1] = { ... }
+ end,
+ }) == nil)
return exp
- ]]
+ end)
)
-- gives higher precedence to on_hunk over result_type
eq(
{ { 1, 1, 1, 1 }, { 3, 1, 3, 2 } },
- exec_lua [[
- exp = {}
- assert(vim.diff(a2, b2, {on_hunk = on_hunk, result_type='indices'}) == nil)
+ exec_lua(function()
+ local exp = {} --- @type table[]
+ assert(vim.diff(a2, b2, {
+ on_hunk = function(...)
+ exp[#exp + 1] = { ... }
+ end,
+ result_type = 'indices',
+ }) == nil)
return exp
- ]]
+ end)
)
end)
it('with error callback', function()
- exec_lua [[
- on_hunk = function(sa, ca, sb, cb)
- error('ERROR1')
- end
- ]]
-
eq(
- [[error running function on_hunk: [string "<nvim>"]:0: ERROR1]],
- pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]])
+ [[.../xdiff_spec.lua:0: error running function on_hunk: .../xdiff_spec.lua:0: ERROR1]],
+ pcall_err(exec_lua, function()
+ vim.diff(a1, b1, {
+ on_hunk = function()
+ error('ERROR1')
+ end,
+ })
+ end)
)
end)
it('with hunk_lines', function()
- eq({ { 1, 1, 1, 1 } }, exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]]))
+ eq(
+ { { 1, 1, 1, 1 } },
+ exec_lua(function()
+ return vim.diff(a1, b1, { result_type = 'indices' })
+ end)
+ )
eq(
{ { 1, 1, 1, 1 }, { 3, 1, 3, 2 } },
- exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]])
+ exec_lua(function()
+ return vim.diff(a2, b2, { result_type = 'indices' })
+ end)
)
end)
@@ -143,16 +159,11 @@ describe('xdiff bindings', function()
'+}',
'',
}, '\n'),
- exec_lua(
- [[
- local args = {...}
- return vim.diff(args[1], args[2], {
- algorithm = 'patience'
+ exec_lua(function()
+ return vim.diff(a, b, {
+ algorithm = 'patience',
})
- ]],
- a,
- b
- )
+ end)
)
end)
end)
@@ -174,4 +185,13 @@ describe('xdiff bindings', function()
pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]])
)
end)
+
+ it('can handle strings with embedded NUL characters (GitHub #30305)', function()
+ eq(
+ { { 0, 0, 1, 1 }, { 1, 0, 3, 2 } },
+ exec_lua(function()
+ return vim.diff('\n', '\0\n\n\nb', { linematch = true, result_type = 'indices' })
+ end)
+ )
+ end)
end)
diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua
index c490ab67a9..a409262d84 100644
--- a/test/functional/options/autochdir_spec.lua
+++ b/test/functional/options/autochdir_spec.lua
@@ -22,7 +22,7 @@ describe("'autochdir'", function()
end)
it('is not overwritten by getwinvar() call #17609', function()
- local curdir = vim.uv.cwd():gsub('\\', '/')
+ local curdir = t.fix_slashes(vim.uv.cwd())
local dir_a = curdir .. '/Xtest-functional-options-autochdir.dir_a'
local dir_b = curdir .. '/Xtest-functional-options-autochdir.dir_b'
mkdir(dir_a)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index f61139d92d..e3d15fa30f 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -1,3 +1,9 @@
+--
+-- Tests for default options and environment decisions.
+--
+-- See editor/defaults_spec.lua for default autocmds, mappings, commands, and menus.
+--
+
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
@@ -17,7 +23,6 @@ local insert = n.insert
local neq = t.neq
local mkdir = t.mkdir
local rmdir = n.rmdir
-local alter_slashes = n.alter_slashes
local tbl_contains = vim.tbl_contains
local expect_exit = n.expect_exit
local check_close = n.check_close
@@ -247,6 +252,7 @@ describe('startup defaults', function()
} })
eq('Xtest-logpath', eval('$NVIM_LOG_FILE'))
end)
+
it('defaults to stdpath("log")/log if empty', function()
eq(true, mkdir(xdgdir) and mkdir(xdgstatedir))
clear({
@@ -255,8 +261,9 @@ describe('startup defaults', function()
NVIM_LOG_FILE = '', -- Empty is invalid.
},
})
- eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
+ eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE')))
end)
+
it('defaults to stdpath("log")/log if invalid', function()
eq(true, mkdir(xdgdir) and mkdir(xdgstatedir))
clear({
@@ -265,7 +272,9 @@ describe('startup defaults', function()
NVIM_LOG_FILE = '.', -- Any directory is invalid.
},
})
- eq(xdgstatedir .. '/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
+ eq(xdgstatedir .. '/log', t.fix_slashes(eval('$NVIM_LOG_FILE')))
+ -- Avoid "failed to open $NVIM_LOG_FILE" noise in test output.
+ expect_exit(command, 'qall!')
end)
end)
end)
@@ -339,9 +348,11 @@ describe('XDG defaults', function()
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()
+ describe('with too long XDG vars', function()
before_each(function()
clear({
+ -- Ensure valid --listen address despite broken XDG vars (else Nvim won't start).
+ args = { '--listen', is_os('win') and '' or t.tmpname(false) },
args_rm = { 'runtimepath' },
env = {
NVIM_LOG_FILE = testlog,
@@ -361,6 +372,9 @@ describe('XDG defaults', function()
it('are correctly set', function()
if not is_os('win') then
+ -- Broken XDG vars cause serverstart() to fail (except on Windows, where servernames are not
+ -- informed by $XDG_STATE_HOME).
+ t.matches('Failed to start server: no such file or directory', t.pcall_err(fn.serverstart))
assert_log('Failed to start server: no such file or directory: /X/X/X', testlog, 10)
end
@@ -368,69 +382,69 @@ describe('XDG defaults', function()
eq(
(
- (
+ t.fix_slashes(
root_path
- .. ('/x'):rep(4096)
- .. '/nvim'
- .. ','
- .. root_path
- .. ('/a'):rep(2048)
- .. '/nvim'
- .. ','
- .. root_path
- .. ('/b'):rep(2048)
- .. '/nvim'
- .. (',' .. root_path .. '/c/nvim')
- .. ','
- .. root_path
- .. ('/X'):rep(4096)
- .. '/'
- .. data_dir
- .. '/site'
- .. ','
- .. root_path
- .. ('/A'):rep(2048)
- .. '/nvim/site'
- .. ','
- .. root_path
- .. ('/B'):rep(2048)
- .. '/nvim/site'
- .. (',' .. root_path .. '/C/nvim/site')
- .. ','
- .. vimruntime
- .. ','
- .. libdir
- .. (',' .. root_path .. '/C/nvim/site/after')
- .. ','
- .. root_path
- .. ('/B'):rep(2048)
- .. '/nvim/site/after'
- .. ','
- .. root_path
- .. ('/A'):rep(2048)
- .. '/nvim/site/after'
- .. ','
- .. root_path
- .. ('/X'):rep(4096)
- .. '/'
- .. data_dir
- .. '/site/after'
- .. (',' .. root_path .. '/c/nvim/after')
- .. ','
- .. root_path
- .. ('/b'):rep(2048)
- .. '/nvim/after'
- .. ','
- .. root_path
- .. ('/a'):rep(2048)
- .. '/nvim/after'
- .. ','
- .. root_path
- .. ('/x'):rep(4096)
- .. '/nvim/after'
- ):gsub('\\', '/')
+ .. ('/x'):rep(4096)
+ .. '/nvim'
+ .. ','
+ .. root_path
+ .. ('/a'):rep(2048)
+ .. '/nvim'
+ .. ','
+ .. root_path
+ .. ('/b'):rep(2048)
+ .. '/nvim'
+ .. (',' .. root_path .. '/c/nvim')
+ .. ','
+ .. root_path
+ .. ('/X'):rep(4096)
+ .. '/'
+ .. data_dir
+ .. '/site'
+ .. ','
+ .. root_path
+ .. ('/A'):rep(2048)
+ .. '/nvim/site'
+ .. ','
+ .. root_path
+ .. ('/B'):rep(2048)
+ .. '/nvim/site'
+ .. (',' .. root_path .. '/C/nvim/site')
+ .. ','
+ .. vimruntime
+ .. ','
+ .. libdir
+ .. (',' .. root_path .. '/C/nvim/site/after')
+ .. ','
+ .. root_path
+ .. ('/B'):rep(2048)
+ .. '/nvim/site/after'
+ .. ','
+ .. root_path
+ .. ('/A'):rep(2048)
+ .. '/nvim/site/after'
+ .. ','
+ .. root_path
+ .. ('/X'):rep(4096)
+ .. '/'
+ .. data_dir
+ .. '/site/after'
+ .. (',' .. root_path .. '/c/nvim/after')
+ .. ','
+ .. root_path
+ .. ('/b'):rep(2048)
+ .. '/nvim/after'
+ .. ','
+ .. root_path
+ .. ('/a'):rep(2048)
+ .. '/nvim/after'
+ .. ','
+ .. root_path
+ .. ('/x'):rep(4096)
+ .. '/nvim/after'
+ )
),
- (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
)
command('set runtimepath&')
command('set backupdir&')
@@ -439,92 +453,94 @@ describe('XDG defaults', function()
command('set viewdir&')
eq(
(
- (
+ t.fix_slashes(
root_path
- .. ('/x'):rep(4096)
- .. '/nvim'
- .. ','
- .. root_path
- .. ('/a'):rep(2048)
- .. '/nvim'
- .. ','
- .. root_path
- .. ('/b'):rep(2048)
- .. '/nvim'
- .. (',' .. root_path .. '/c/nvim')
- .. ','
- .. root_path
- .. ('/X'):rep(4096)
- .. '/'
- .. data_dir
- .. '/site'
- .. ','
- .. root_path
- .. ('/A'):rep(2048)
- .. '/nvim/site'
- .. ','
- .. root_path
- .. ('/B'):rep(2048)
- .. '/nvim/site'
- .. (',' .. root_path .. '/C/nvim/site')
- .. ','
- .. vimruntime
- .. ','
- .. libdir
- .. (',' .. root_path .. '/C/nvim/site/after')
- .. ','
- .. root_path
- .. ('/B'):rep(2048)
- .. '/nvim/site/after'
- .. ','
- .. root_path
- .. ('/A'):rep(2048)
- .. '/nvim/site/after'
- .. ','
- .. root_path
- .. ('/X'):rep(4096)
- .. '/'
- .. data_dir
- .. '/site/after'
- .. (',' .. root_path .. '/c/nvim/after')
- .. ','
- .. root_path
- .. ('/b'):rep(2048)
- .. '/nvim/after'
- .. ','
- .. root_path
- .. ('/a'):rep(2048)
- .. '/nvim/after'
- .. ','
- .. root_path
- .. ('/x'):rep(4096)
- .. '/nvim/after'
- ):gsub('\\', '/')
+ .. ('/x'):rep(4096)
+ .. '/nvim'
+ .. ','
+ .. root_path
+ .. ('/a'):rep(2048)
+ .. '/nvim'
+ .. ','
+ .. root_path
+ .. ('/b'):rep(2048)
+ .. '/nvim'
+ .. (',' .. root_path .. '/c/nvim')
+ .. ','
+ .. root_path
+ .. ('/X'):rep(4096)
+ .. '/'
+ .. data_dir
+ .. '/site'
+ .. ','
+ .. root_path
+ .. ('/A'):rep(2048)
+ .. '/nvim/site'
+ .. ','
+ .. root_path
+ .. ('/B'):rep(2048)
+ .. '/nvim/site'
+ .. (',' .. root_path .. '/C/nvim/site')
+ .. ','
+ .. vimruntime
+ .. ','
+ .. libdir
+ .. (',' .. root_path .. '/C/nvim/site/after')
+ .. ','
+ .. root_path
+ .. ('/B'):rep(2048)
+ .. '/nvim/site/after'
+ .. ','
+ .. root_path
+ .. ('/A'):rep(2048)
+ .. '/nvim/site/after'
+ .. ','
+ .. root_path
+ .. ('/X'):rep(4096)
+ .. '/'
+ .. data_dir
+ .. '/site/after'
+ .. (',' .. root_path .. '/c/nvim/after')
+ .. ','
+ .. root_path
+ .. ('/b'):rep(2048)
+ .. '/nvim/after'
+ .. ','
+ .. root_path
+ .. ('/a'):rep(2048)
+ .. '/nvim/after'
+ .. ','
+ .. root_path
+ .. ('/x'):rep(4096)
+ .. '/nvim/after'
+ )
),
- (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
)
eq(
'.,' .. root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/backup//',
- (api.nvim_get_option_value('backupdir', {}):gsub('\\', '/'))
+ t.fix_slashes(api.nvim_get_option_value('backupdir', {}))
)
eq(
root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//',
- (api.nvim_get_option_value('directory', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('directory', {}))
)
eq(
root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//',
- (api.nvim_get_option_value('undodir', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('undodir', {}))
)
eq(
root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//',
- (api.nvim_get_option_value('viewdir', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('viewdir', {}))
)
end)
end)
- describe('with XDG variables that can be expanded', function()
+ describe('with expandable XDG vars', function()
before_each(function()
clear({
+ -- Ensure valid --listen address despite broken XDG vars (else Nvim won't start).
+ args = { '--listen', is_os('win') and '' or t.tmpname(false) },
args_rm = { 'runtimepath' },
env = {
NVIM_LOG_FILE = testlog,
@@ -544,6 +560,9 @@ describe('XDG defaults', function()
it('are not expanded', function()
if not is_os('win') then
+ -- Broken XDG vars cause serverstart() to fail (except on Windows, where servernames are not
+ -- informed by $XDG_STATE_HOME).
+ t.matches('Failed to start server: no such file or directory', t.pcall_err(fn.serverstart))
assert_log(
'Failed to start server: no such file or directory: %$XDG_RUNTIME_DIR%/',
testlog,
@@ -554,26 +573,26 @@ describe('XDG defaults', function()
local vimruntime, libdir = vimruntime_and_libdir()
eq(
(
- (
+ t.fix_slashes(
'$XDG_DATA_HOME/nvim'
- .. ',$XDG_DATA_DIRS/nvim'
- .. ',$XDG_CONFIG_HOME/'
- .. data_dir
- .. '/site'
- .. ',$XDG_CONFIG_DIRS/nvim/site'
- .. ','
- .. vimruntime
- .. ','
- .. libdir
- .. ',$XDG_CONFIG_DIRS/nvim/site/after'
- .. ',$XDG_CONFIG_HOME/'
- .. data_dir
- .. '/site/after'
- .. ',$XDG_DATA_DIRS/nvim/after'
- .. ',$XDG_DATA_HOME/nvim/after'
- ):gsub('\\', '/')
+ .. ',$XDG_DATA_DIRS/nvim'
+ .. ',$XDG_CONFIG_HOME/'
+ .. data_dir
+ .. '/site'
+ .. ',$XDG_CONFIG_DIRS/nvim/site'
+ .. ','
+ .. vimruntime
+ .. ','
+ .. libdir
+ .. ',$XDG_CONFIG_DIRS/nvim/site/after'
+ .. ',$XDG_CONFIG_HOME/'
+ .. data_dir
+ .. '/site/after'
+ .. ',$XDG_DATA_DIRS/nvim/after'
+ .. ',$XDG_DATA_HOME/nvim/after'
+ )
),
- (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
)
command('set runtimepath&')
command('set backupdir&')
@@ -582,80 +601,80 @@ describe('XDG defaults', function()
command('set viewdir&')
eq(
(
- (
+ t.fix_slashes(
'$XDG_DATA_HOME/nvim'
- .. ',$XDG_DATA_DIRS/nvim'
- .. ',$XDG_CONFIG_HOME/'
- .. data_dir
- .. '/site'
- .. ',$XDG_CONFIG_DIRS/nvim/site'
- .. ','
- .. vimruntime
- .. ','
- .. libdir
- .. ',$XDG_CONFIG_DIRS/nvim/site/after'
- .. ',$XDG_CONFIG_HOME/'
- .. data_dir
- .. '/site/after'
- .. ',$XDG_DATA_DIRS/nvim/after'
- .. ',$XDG_DATA_HOME/nvim/after'
- ):gsub('\\', '/')
+ .. ',$XDG_DATA_DIRS/nvim'
+ .. ',$XDG_CONFIG_HOME/'
+ .. data_dir
+ .. '/site'
+ .. ',$XDG_CONFIG_DIRS/nvim/site'
+ .. ','
+ .. vimruntime
+ .. ','
+ .. libdir
+ .. ',$XDG_CONFIG_DIRS/nvim/site/after'
+ .. ',$XDG_CONFIG_HOME/'
+ .. data_dir
+ .. '/site/after'
+ .. ',$XDG_DATA_DIRS/nvim/after'
+ .. ',$XDG_DATA_HOME/nvim/after'
+ )
),
- (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
)
eq(
('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
- api.nvim_get_option_value('backupdir', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('backupdir', {}))
)
eq(
('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
- api.nvim_get_option_value('directory', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('directory', {}))
)
eq(
('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
- api.nvim_get_option_value('undodir', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('undodir', {}))
)
eq(
('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
- api.nvim_get_option_value('viewdir', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('viewdir', {}))
)
command('set all&')
eq(
- (
+ t.fix_slashes(
'$XDG_DATA_HOME/nvim'
- .. ',$XDG_DATA_DIRS/nvim'
- .. ',$XDG_CONFIG_HOME/'
- .. data_dir
- .. '/site'
- .. ',$XDG_CONFIG_DIRS/nvim/site'
- .. ','
- .. vimruntime
- .. ','
- .. libdir
- .. ',$XDG_CONFIG_DIRS/nvim/site/after'
- .. ',$XDG_CONFIG_HOME/'
- .. data_dir
- .. '/site/after'
- .. ',$XDG_DATA_DIRS/nvim/after'
- .. ',$XDG_DATA_HOME/nvim/after'
- ):gsub('\\', '/'),
- (api.nvim_get_option_value('runtimepath', {})):gsub('\\', '/')
+ .. ',$XDG_DATA_DIRS/nvim'
+ .. ',$XDG_CONFIG_HOME/'
+ .. data_dir
+ .. '/site'
+ .. ',$XDG_CONFIG_DIRS/nvim/site'
+ .. ','
+ .. vimruntime
+ .. ','
+ .. libdir
+ .. ',$XDG_CONFIG_DIRS/nvim/site/after'
+ .. ',$XDG_CONFIG_HOME/'
+ .. data_dir
+ .. '/site/after'
+ .. ',$XDG_DATA_DIRS/nvim/after'
+ .. ',$XDG_DATA_HOME/nvim/after'
+ ),
+ t.fix_slashes(api.nvim_get_option_value('runtimepath', {}))
)
eq(
('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
- api.nvim_get_option_value('backupdir', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('backupdir', {}))
)
eq(
('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
- api.nvim_get_option_value('directory', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('directory', {}))
)
eq(
('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
- api.nvim_get_option_value('undodir', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('undodir', {}))
)
eq(
('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
- api.nvim_get_option_value('viewdir', {}):gsub('\\', '/')
+ t.fix_slashes(api.nvim_get_option_value('viewdir', {}))
)
eq(nil, (fn.tempname()):match('XDG_RUNTIME_DIR'))
end)
@@ -895,7 +914,7 @@ describe('stdpath()', function()
assert_alive() -- Check for crash. #8393
end)
- it('reacts to $NVIM_APPNAME', function()
+ it('$NVIM_APPNAME', function()
local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106)
clear({ env = { NVIM_APPNAME = appname, NVIM_LOG_FILE = testlog } })
eq(appname, fn.fnamemodify(fn.stdpath('config'), ':t'))
@@ -916,10 +935,10 @@ describe('stdpath()', function()
local function test_appname(testAppname, expected_exitcode)
local lua_code = string.format(
[[
- local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '+qall!' }, { env = { NVIM_APPNAME = %q } })
+ local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } })
return vim.fn.jobwait({ child }, %d)[1]
]],
- alter_slashes(testAppname),
+ testAppname,
3000
)
eq(expected_exitcode, exec_lua(lua_code))
@@ -935,9 +954,25 @@ describe('stdpath()', function()
-- Valid appnames:
test_appname('a/b', 0)
test_appname('a/b\\c', 0)
- if not is_os('win') then
- assert_log('Failed to start server: no such file or directory:', testlog)
- end
+ end)
+
+ it('$NVIM_APPNAME relative path', function()
+ local tmpdir = t.tmpname(false)
+ t.mkdir(tmpdir)
+
+ clear({
+ args_rm = { '--listen' },
+ env = {
+ NVIM_APPNAME = 'relative/appname',
+ NVIM_LOG_FILE = testlog,
+ TMPDIR = tmpdir,
+ },
+ })
+
+ t.matches(vim.pesc(tmpdir), t.fix_slashes(fn.tempname()))
+ t.assert_nolog('tempdir', testlog, 100)
+ t.assert_nolog('TMPDIR', testlog, 100)
+ t.matches([=[[/\\]relative%-appname.[^/\\]+]=], api.nvim_get_vvar('servername'))
end)
describe('returns a String', function()
@@ -945,19 +980,19 @@ describe('stdpath()', function()
it('knows XDG_CONFIG_HOME', function()
clear({
env = {
- XDG_CONFIG_HOME = alter_slashes('/home/docwhat/.config'),
+ XDG_CONFIG_HOME = '/home/docwhat/.config',
},
})
- eq(alter_slashes('/home/docwhat/.config/nvim'), fn.stdpath('config'))
+ eq('/home/docwhat/.config/nvim', t.fix_slashes(fn.stdpath('config')))
end)
it('handles changes during runtime', function()
clear({ env = {
- XDG_CONFIG_HOME = alter_slashes('/home/original'),
+ XDG_CONFIG_HOME = '/home/original',
} })
- eq(alter_slashes('/home/original/nvim'), fn.stdpath('config'))
- command("let $XDG_CONFIG_HOME='" .. alter_slashes('/home/new') .. "'")
- eq(alter_slashes('/home/new/nvim'), fn.stdpath('config'))
+ eq('/home/original/nvim', t.fix_slashes(fn.stdpath('config')))
+ command("let $XDG_CONFIG_HOME='/home/new'")
+ eq('/home/new/nvim', t.fix_slashes(fn.stdpath('config')))
end)
it("doesn't expand $VARIABLES", function()
@@ -967,32 +1002,32 @@ describe('stdpath()', function()
VARIABLES = 'this-should-not-happen',
},
})
- eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('config'))
+ eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('config')))
end)
it("doesn't expand ~/", function()
clear({ env = {
- XDG_CONFIG_HOME = alter_slashes('~/frobnitz'),
+ XDG_CONFIG_HOME = '~/frobnitz',
} })
- eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('config'))
+ eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('config')))
end)
end)
describe('with "data"', function()
it('knows XDG_DATA_HOME', function()
clear({ env = {
- XDG_DATA_HOME = alter_slashes('/home/docwhat/.local'),
+ XDG_DATA_HOME = '/home/docwhat/.local',
} })
- eq(alter_slashes('/home/docwhat/.local/' .. datadir), fn.stdpath('data'))
+ eq('/home/docwhat/.local/' .. datadir, t.fix_slashes(fn.stdpath('data')))
end)
it('handles changes during runtime', function()
clear({ env = {
- XDG_DATA_HOME = alter_slashes('/home/original'),
+ XDG_DATA_HOME = '/home/original',
} })
- eq(alter_slashes('/home/original/' .. datadir), fn.stdpath('data'))
- command("let $XDG_DATA_HOME='" .. alter_slashes('/home/new') .. "'")
- eq(alter_slashes('/home/new/' .. datadir), fn.stdpath('data'))
+ eq('/home/original/' .. datadir, t.fix_slashes(fn.stdpath('data')))
+ command("let $XDG_DATA_HOME='/home/new'")
+ eq('/home/new/' .. datadir, t.fix_slashes(fn.stdpath('data')))
end)
it("doesn't expand $VARIABLES", function()
@@ -1002,14 +1037,14 @@ describe('stdpath()', function()
VARIABLES = 'this-should-not-happen',
},
})
- eq(alter_slashes('$VARIABLES/' .. datadir), fn.stdpath('data'))
+ eq('$VARIABLES/' .. datadir, t.fix_slashes(fn.stdpath('data')))
end)
it("doesn't expand ~/", function()
clear({ env = {
- XDG_DATA_HOME = alter_slashes('~/frobnitz'),
+ XDG_DATA_HOME = '~/frobnitz',
} })
- eq(alter_slashes('~/frobnitz/' .. datadir), fn.stdpath('data'))
+ eq('~/frobnitz/' .. datadir, t.fix_slashes(fn.stdpath('data')))
end)
end)
@@ -1017,19 +1052,19 @@ describe('stdpath()', function()
it('knows XDG_STATE_HOME', function()
clear({
env = {
- XDG_STATE_HOME = alter_slashes('/home/docwhat/.local'),
+ XDG_STATE_HOME = '/home/docwhat/.local',
},
})
- eq(alter_slashes('/home/docwhat/.local/' .. statedir), fn.stdpath('state'))
+ eq('/home/docwhat/.local/' .. statedir, t.fix_slashes(fn.stdpath('state')))
end)
it('handles changes during runtime', function()
clear({ env = {
- XDG_STATE_HOME = alter_slashes('/home/original'),
+ XDG_STATE_HOME = '/home/original',
} })
- eq(alter_slashes('/home/original/' .. statedir), fn.stdpath('state'))
- command("let $XDG_STATE_HOME='" .. alter_slashes('/home/new') .. "'")
- eq(alter_slashes('/home/new/' .. statedir), fn.stdpath('state'))
+ eq('/home/original/' .. statedir, t.fix_slashes(fn.stdpath('state')))
+ command("let $XDG_STATE_HOME='" .. '/home/new' .. "'")
+ eq('/home/new/' .. statedir, t.fix_slashes(fn.stdpath('state')))
end)
it("doesn't expand $VARIABLES", function()
@@ -1039,14 +1074,14 @@ describe('stdpath()', function()
VARIABLES = 'this-should-not-happen',
},
})
- eq(alter_slashes('$VARIABLES/' .. statedir), fn.stdpath('state'))
+ eq('$VARIABLES/' .. statedir, t.fix_slashes(fn.stdpath('state')))
end)
it("doesn't expand ~/", function()
clear({ env = {
- XDG_STATE_HOME = alter_slashes('~/frobnitz'),
+ XDG_STATE_HOME = '~/frobnitz',
} })
- eq(alter_slashes('~/frobnitz/' .. statedir), fn.stdpath('state'))
+ eq('~/frobnitz/' .. statedir, t.fix_slashes(fn.stdpath('state')))
end)
end)
@@ -1054,19 +1089,19 @@ describe('stdpath()', function()
it('knows XDG_CACHE_HOME', function()
clear({
env = {
- XDG_CACHE_HOME = alter_slashes('/home/docwhat/.cache'),
+ XDG_CACHE_HOME = '/home/docwhat/.cache',
},
})
- eq(alter_slashes('/home/docwhat/.cache/nvim'), fn.stdpath('cache'))
+ eq('/home/docwhat/.cache/nvim', t.fix_slashes(fn.stdpath('cache')))
end)
it('handles changes during runtime', function()
clear({ env = {
- XDG_CACHE_HOME = alter_slashes('/home/original'),
+ XDG_CACHE_HOME = '/home/original',
} })
- eq(alter_slashes('/home/original/nvim'), fn.stdpath('cache'))
- command("let $XDG_CACHE_HOME='" .. alter_slashes('/home/new') .. "'")
- eq(alter_slashes('/home/new/nvim'), fn.stdpath('cache'))
+ eq('/home/original/nvim', t.fix_slashes(fn.stdpath('cache')))
+ command("let $XDG_CACHE_HOME='" .. '/home/new' .. "'")
+ eq('/home/new/nvim', t.fix_slashes(fn.stdpath('cache')))
end)
it("doesn't expand $VARIABLES", function()
@@ -1076,14 +1111,14 @@ describe('stdpath()', function()
VARIABLES = 'this-should-not-happen',
},
})
- eq(alter_slashes('$VARIABLES/nvim'), fn.stdpath('cache'))
+ eq('$VARIABLES/nvim', t.fix_slashes(fn.stdpath('cache')))
end)
it("doesn't expand ~/", function()
clear({ env = {
- XDG_CACHE_HOME = alter_slashes('~/frobnitz'),
+ XDG_CACHE_HOME = '~/frobnitz',
} })
- eq(alter_slashes('~/frobnitz/nvim'), fn.stdpath('cache'))
+ eq('~/frobnitz/nvim', t.fix_slashes(fn.stdpath('cache')))
end)
end)
end)
@@ -1097,6 +1132,7 @@ describe('stdpath()', function()
HOMEDRIVE = 'C:',
HOMEPATH = '\\Users\\docwhat',
LOCALAPPDATA = 'C:\\Users\\docwhat\\AppData\\Local',
+ NVIM_LOG_FILE = testlog,
TEMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp',
TMPDIR = 'C:\\Users\\docwhat\\AppData\\Local\\Temp',
TMP = 'C:\\Users\\docwhat\\AppData\\Local\\Temp',
@@ -1107,6 +1143,7 @@ describe('stdpath()', function()
HOMEDRIVE = 'HOMEDRIVE-should-be-ignored',
HOMEPATH = 'HOMEPATH-should-be-ignored',
LOCALAPPDATA = 'LOCALAPPDATA-should-be-ignored',
+ NVIM_LOG_FILE = testlog,
TEMP = 'TEMP-should-be-ignored',
TMPDIR = 'TMPDIR-should-be-ignored',
TMP = 'TMP-should-be-ignored',
@@ -1130,12 +1167,18 @@ describe('stdpath()', function()
describe(msg, function()
it('set via system', function()
set_paths_via_system(env_var_name, paths)
- eq(expected_paths, fn.stdpath(stdpath_arg))
+ eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg)))
+ if not is_os('win') then
+ assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100)
+ end
end)
it('set at runtime', function()
set_paths_at_runtime(env_var_name, paths)
- eq(expected_paths, fn.stdpath(stdpath_arg))
+ eq(expected_paths, t.fix_slashes(fn.stdpath(stdpath_arg)))
+ if not is_os('win') then
+ assert_log('$TMPDIR tempdir not a directory.*TMPDIR%-should%-be%-ignored', testlog, 100)
+ end
end)
end)
end
@@ -1146,10 +1189,10 @@ describe('stdpath()', function()
'config_dirs',
'XDG_CONFIG_DIRS',
{
- alter_slashes('/home/docwhat/.config'),
+ t.fix_slashes('/home/docwhat/.config'),
},
{
- alter_slashes('/home/docwhat/.config/nvim'),
+ t.fix_slashes('/home/docwhat/.config/nvim'),
}
)
@@ -1158,12 +1201,12 @@ describe('stdpath()', function()
'config_dirs',
'XDG_CONFIG_DIRS',
{
- alter_slashes('/home/docwhat/.config'),
- alter_slashes('/etc/config'),
+ t.fix_slashes('/home/docwhat/.config'),
+ t.fix_slashes('/etc/config'),
},
{
- alter_slashes('/home/docwhat/.config/nvim'),
- alter_slashes('/etc/config/nvim'),
+ t.fix_slashes('/home/docwhat/.config/nvim'),
+ t.fix_slashes('/etc/config/nvim'),
}
)
@@ -1173,25 +1216,25 @@ describe('stdpath()', function()
'XDG_CONFIG_DIRS',
{ '$HOME', '$TMP' },
{
- alter_slashes('$HOME/nvim'),
- alter_slashes('$TMP/nvim'),
+ t.fix_slashes('$HOME/nvim'),
+ t.fix_slashes('$TMP/nvim'),
}
)
behaves_like_dir_list_env("doesn't expand ~/", 'config_dirs', 'XDG_CONFIG_DIRS', {
- alter_slashes('~/.oldconfig'),
- alter_slashes('~/.olderconfig'),
+ t.fix_slashes('~/.oldconfig'),
+ t.fix_slashes('~/.olderconfig'),
}, {
- alter_slashes('~/.oldconfig/nvim'),
- alter_slashes('~/.olderconfig/nvim'),
+ t.fix_slashes('~/.oldconfig/nvim'),
+ t.fix_slashes('~/.olderconfig/nvim'),
})
end)
describe('with "data_dirs"', function()
behaves_like_dir_list_env('knows XDG_DATA_DIRS with one path', 'data_dirs', 'XDG_DATA_DIRS', {
- alter_slashes('/home/docwhat/.data'),
+ t.fix_slashes('/home/docwhat/.data'),
}, {
- alter_slashes('/home/docwhat/.data/nvim'),
+ t.fix_slashes('/home/docwhat/.data/nvim'),
})
behaves_like_dir_list_env(
@@ -1199,12 +1242,12 @@ describe('stdpath()', function()
'data_dirs',
'XDG_DATA_DIRS',
{
- alter_slashes('/home/docwhat/.data'),
- alter_slashes('/etc/local'),
+ t.fix_slashes('/home/docwhat/.data'),
+ t.fix_slashes('/etc/local'),
},
{
- alter_slashes('/home/docwhat/.data/nvim'),
- alter_slashes('/etc/local/nvim'),
+ t.fix_slashes('/home/docwhat/.data/nvim'),
+ t.fix_slashes('/etc/local/nvim'),
}
)
@@ -1214,17 +1257,17 @@ describe('stdpath()', function()
'XDG_DATA_DIRS',
{ '$HOME', '$TMP' },
{
- alter_slashes('$HOME/nvim'),
- alter_slashes('$TMP/nvim'),
+ t.fix_slashes('$HOME/nvim'),
+ t.fix_slashes('$TMP/nvim'),
}
)
behaves_like_dir_list_env("doesn't expand ~/", 'data_dirs', 'XDG_DATA_DIRS', {
- alter_slashes('~/.oldconfig'),
- alter_slashes('~/.olderconfig'),
+ t.fix_slashes('~/.oldconfig'),
+ t.fix_slashes('~/.olderconfig'),
}, {
- alter_slashes('~/.oldconfig/nvim'),
- alter_slashes('~/.olderconfig/nvim'),
+ t.fix_slashes('~/.oldconfig/nvim'),
+ t.fix_slashes('~/.olderconfig/nvim'),
})
end)
end)
@@ -1244,23 +1287,3 @@ describe('stdpath()', function()
end)
end)
end)
-
-describe('autocommands', function()
- it('closes terminal with default shell on success', function()
- clear()
- api.nvim_set_option_value('shell', n.testprg('shell-test'), {})
- command('set shellcmdflag=EXIT shellredir= shellpipe= shellquote= shellxquote=')
-
- -- Should not block other events
- command('let g:n=0')
- command('au BufEnter * let g:n = g:n + 1')
-
- command('terminal')
- eq(1, eval('get(g:, "n", 0)'))
-
- t.retry(nil, 1000, function()
- neq('terminal', api.nvim_get_option_value('buftype', { buf = 0 }))
- eq(2, eval('get(g:, "n", 0)'))
- end)
- end)
-end)
diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua
index 839a723405..5f69b8938a 100644
--- a/test/functional/plugin/editorconfig_spec.lua
+++ b/test/functional/plugin/editorconfig_spec.lua
@@ -7,7 +7,6 @@ local eq = t.eq
local pathsep = n.get_pathsep()
local fn = n.fn
local api = n.api
-local exec_lua = n.exec_lua
local testdir = 'Xtest-editorconfig'
@@ -16,8 +15,16 @@ 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, api.nvim_get_option_value(opt, { buf = 0 }), name)
+ local opt_info = api.nvim_get_option_info2(opt, {})
+ if opt_info.scope == 'win' then
+ eq(val, api.nvim_get_option_value(opt, { win = 0 }), name)
+ elseif opt_info.scope == 'buf' then
+ eq(val, api.nvim_get_option_value(opt, { buf = 0 }), name)
+ else
+ eq(val, api.nvim_get_option_value(opt, {}), name)
+ end
end
end
@@ -93,6 +100,12 @@ setup(function()
[max_line_length.txt]
max_line_length = 42
+
+ [short_spelling_language.txt]
+ spelling_language = de
+
+ [long_spelling_language.txt]
+ spelling_language = en-NZ
]]
)
end)
@@ -213,13 +226,18 @@ But not this one
end)
it('does not operate on invalid buffers', function()
- local ok, err = unpack(exec_lua([[
+ local ok, err = unpack(n.exec_lua(function()
vim.cmd.edit('test.txt')
local bufnr = vim.api.nvim_get_current_buf()
vim.cmd.bwipeout(bufnr)
- return {pcall(require('editorconfig').config, bufnr)}
- ]]))
+ return { pcall(require('editorconfig').config, bufnr) }
+ end))
eq(true, ok, err)
end)
+
+ it('sets spelllang', function()
+ test_case('short_spelling_language.txt', { spelllang = 'de' })
+ test_case('long_spelling_language.txt', { spelllang = 'en_nz' })
+ end)
end)
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 9c7c953fb0..7089313303 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -40,11 +40,22 @@ describe(':checkhealth', function()
matches('ERROR $VIM .* zub', curbuf_contents())
end)
- it('completions can be listed via getcompletion()', function()
- clear()
+ it('getcompletion()', function()
+ clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
+
eq('vim.deprecated', getcompletion('vim', 'checkhealth')[1])
eq('vim.provider', getcompletion('vim.prov', 'checkhealth')[1])
eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
+
+ -- "test_plug/health/init.lua" should complete as "test_plug", not "test_plug.health". #30342
+ eq({
+ 'test_plug',
+ 'test_plug.full_render',
+ 'test_plug.submodule',
+ 'test_plug.submodule_empty',
+ 'test_plug.success1',
+ 'test_plug.success2',
+ }, getcompletion('test_plug', 'checkhealth'))
end)
it('completion checks for vim.health._complete() return type #28456', function()
@@ -57,11 +68,9 @@ describe(':checkhealth', function()
end)
end)
-describe('health.vim', function()
+describe('vim.health', function()
before_each(function()
- clear { args = { '-u', 'NORC' } }
- -- Provides healthcheck functions
- command('set runtimepath+=test/functional/fixtures')
+ clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
end)
describe(':checkhealth', function()
@@ -70,7 +79,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- test_plug.full_render: require("test_plug.full_render.health").check()
+ test_plug.full_render: require("test_plug.full_render.health").check()
report 1 ~
- OK life is fine
@@ -93,7 +102,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- test_plug: require("test_plug.health").check()
+ test_plug: require("test_plug.health").check()
report 1 ~
- OK everything is fine
@@ -102,7 +111,7 @@ describe('health.vim', function()
- OK nothing to see here
==============================================================================
- test_plug.success1: require("test_plug.success1.health").check()
+ test_plug.success1: require("test_plug.success1.health").check()
report 1 ~
- OK everything is fine
@@ -111,7 +120,7 @@ describe('health.vim', function()
- OK nothing to see here
==============================================================================
- test_plug.success2: require("test_plug.success2.health").check()
+ test_plug.success2: require("test_plug.success2.health").check()
another 1 ~
- OK ok
@@ -123,7 +132,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- test_plug.submodule: require("test_plug.submodule.health").check()
+ test_plug.submodule: require("test_plug.submodule.health").check()
report 1 ~
- OK everything is fine
@@ -148,9 +157,10 @@ describe('health.vim', function()
local screen = Screen.new(50, 12)
screen:attach()
screen:set_default_attr_ids({
+ h1 = { reverse = true },
+ h2 = { foreground = tonumber('0x6a0dad') },
Ok = { foreground = Screen.colors.LightGreen },
Error = { foreground = Screen.colors.Red },
- Heading = { foreground = tonumber('0x6a0dad') },
Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey },
})
command('checkhealth foo success1')
@@ -158,15 +168,15 @@ describe('health.vim', function()
screen:expect {
grid = [[
^ |
- {Bar:──────────────────────────────────────────────────}|
- {Heading:foo: } |
+ {Bar: }|
+ {h1:foo: }|
|
- {Error:ERROR} No healthcheck found for "foo" plugin. |
|
- {Bar:──────────────────────────────────────────────────}|
- {Heading:test_plug.success1: require("test_plug.success1.he}|
+ {Bar: }|
+ {h1:test_plug.success1: require("test_pl}|
|
- {Heading:report 1} |
+ {h2:report 1} |
- {Ok:OK} everything is fine |
|
]],
@@ -179,7 +189,7 @@ describe('health.vim', function()
n.expect([[
==============================================================================
- non_existent_healthcheck:
+ non_existent_healthcheck:
- ERROR No healthcheck found for "non_existent_healthcheck" plugin.
]])
@@ -207,18 +217,17 @@ end)
describe(':checkhealth window', function()
before_each(function()
- clear { args = { '-u', 'NORC' } }
- -- Provides healthcheck functions
- command('set runtimepath+=test/functional/fixtures')
+ clear { args = { '-u', 'NORC', '+set runtimepath+=test/functional/fixtures' } }
command('set nofoldenable nowrap laststatus=0')
end)
it('opens directly if no buffer created', function()
local screen = Screen.new(50, 12)
screen:set_default_attr_ids {
+ h1 = { reverse = true },
+ h2 = { foreground = tonumber('0x6a0dad') },
[1] = { foreground = Screen.colors.Blue, bold = true },
[14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
- [31] = { foreground = tonumber('0x6a0dad') },
[32] = { foreground = Screen.colors.PaleGreen2 },
}
screen:attach({ ext_multigrid = true })
@@ -230,15 +239,15 @@ describe(':checkhealth window', function()
[3:--------------------------------------------------]|
## grid 2
^ |
- {14:──────────────────────────────────────────────────}|
- {14:────────────────────────────} |
- {31:test_plug.success1: require("test_plug.success1. }|
- {31:health").check()} |
+ {14: }|
+ {14: } |
+ {h1:test_plug.success1: }|
+ {h1:require("test_plug.success1.health").check()} |
|
- {31:report 1} |
+ {h2:report 1} |
- {32:OK} everything is fine |
|
- {31:report 2} |
+ {h2:report 2} |
- {32:OK} nothing to see here |
## grid 3
|
@@ -249,9 +258,10 @@ describe(':checkhealth window', function()
local function test_health_vsplit(left, emptybuf, mods)
local screen = Screen.new(50, 20)
screen:set_default_attr_ids {
+ h1 = { reverse = true },
+ h2 = { foreground = tonumber('0x6a0dad') },
[1] = { foreground = Screen.colors.Blue, bold = true },
[14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray },
- [31] = { foreground = tonumber('0x6a0dad') },
[32] = { foreground = Screen.colors.PaleGreen2 },
}
screen:attach({ ext_multigrid = true })
@@ -271,19 +281,20 @@ describe(':checkhealth window', function()
|
## grid 4
^ |
- {14:─────────────────────────}|*3
- {14:───} |
- {31:test_plug.success1: }|
- {31:require("test_plug. }|
- {31:success1.health").check()}|
+ {14: }|*3
+ {14: } |
+ {h1:test_plug. }|
+ {h1:success1: }|
+ {h1:require("test_plug. }|
+ {h1:success1.health").check()}|
|
- {31:report 1} |
+ {h2:report 1} |
- {32:OK} everything is fine |
|
- {31:report 2} |
+ {h2:report 2} |
- {32:OK} nothing to see here |
|
- {1:~ }|*4
+ {1:~ }|*3
]]):format(
left and '[4:-------------------------]│[2:------------------------]|*19'
or '[2:------------------------]│[4:-------------------------]|*19',
@@ -330,10 +341,10 @@ describe(':checkhealth window', function()
|
## grid 4
^ |
- ──────────────────────────────────────────────────|
- ──────────────────────────── |
- test_plug.success1: require("test_plug.success1. |
- health").check() |
+ |
+ |
+ test_plug.success1: |
+ require("test_plug.success1.health").check() |
|
report 1 |
- OK everything is fine |
@@ -382,7 +393,7 @@ describe(':checkhealth window', function()
command('file my_buff')
command('checkhealth success1')
-- define a function that collects all buffers in each tab
- -- returns a dictionary like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]}
+ -- returns a dict like {tab1 = ["buf1", "buf2"], tab2 = ["buf3"]}
source([[
function CollectBuffersPerTab()
let buffs = {}
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
index cd20e95dd1..20ef1cb49e 100644
--- a/test/functional/plugin/lsp/codelens_spec.lua
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -13,36 +13,34 @@ describe('vim.lsp.codelens', function()
it('on_codelens_stores_and_displays_lenses', function()
local fake_uri = 'file:///fake/uri'
- local bufnr = exec_lua(
- [[
- fake_uri = ...
+ local bufnr = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
- local lines = {'So', 'many', 'lines'}
+ local lines = { 'So', 'many', 'lines' }
vim.fn.bufload(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
return bufnr
- ]],
- fake_uri
- )
+ end)
- exec_lua(
- [[
- local bufnr = ...
+ exec_lua(function()
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 0 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
- ]],
- bufnr
- )
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
+ end)
- local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ local stored_lenses = exec_lua(function()
+ return vim.lsp.codelens.get(bufnr)
+ end)
local expected = {
{
range = {
@@ -57,58 +55,54 @@ describe('vim.lsp.codelens', function()
}
eq(expected, stored_lenses)
- local virtual_text_chunks = exec_lua(
- [[
- local bufnr = ...
+ local virtual_text_chunks = exec_lua(function()
local ns = vim.lsp.codelens.__namespaces[1]
local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {})
return vim.api.nvim_buf_get_extmark_by_id(bufnr, ns, extmarks[1][1], { details = true })[3].virt_text
- ]],
- bufnr
- )
+ end)
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 = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
- local lines = {'So', 'many', 'lines'}
+ local lines = { 'So', 'many', 'lines' }
vim.fn.bufload(bufnr)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
return bufnr
- ]],
- fake_uri
- )
+ end)
- exec_lua(
- [[
- local bufnr = ...
+ exec_lua(function()
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 0 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
- ]],
- bufnr
- )
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
+ end)
- local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ local stored_lenses = exec_lua(function()
+ return vim.lsp.codelens.get(bufnr)
+ end)
eq(1, #stored_lenses)
- exec_lua([[
+ exec_lua(function()
vim.lsp.codelens.clear()
- ]])
+ end)
- stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
+ stored_lenses = exec_lua(function()
+ return vim.lsp.codelens.get(bufnr)
+ end)
eq(0, #stored_lenses)
end)
end)
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index 2798d57381..4df8d77d44 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -1,9 +1,16 @@
---@diagnostic disable: no-unknown
local t = require('test.testutil')
+local t_lsp = require('test.functional.plugin.lsp.testutil')
local n = require('test.functional.testnvim')()
+local clear = n.clear
local eq = t.eq
+local neq = t.neq
local exec_lua = n.exec_lua
+local feed = n.feed
+local retry = t.retry
+
+local create_server_definition = t_lsp.create_server_definition
--- Convert completion results.
---
@@ -11,38 +18,32 @@ local exec_lua = n.exec_lua
---@param candidates lsp.CompletionList|lsp.CompletionItem[]
---@param lnum? integer 0-based, defaults to 0
---@return {items: table[], server_start_boundary: integer?}
-local function complete(line, candidates, lnum)
+local function complete(line, candidates, lnum, server_boundary)
lnum = lnum or 0
-- nvim_win_get_cursor returns 0 based column, line:find returns 1 based
local cursor_col = line:find('|') - 1
line = line:gsub('|', '')
- return exec_lua(
- [[
- local line, cursor_col, lnum, result = ...
+ return exec_lua(function(result)
local line_to_cursor = line:sub(1, cursor_col)
local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$')
- local items, server_start_boundary = require("vim.lsp._completion")._convert_results(
+ local items, new_server_boundary = require('vim.lsp.completion')._convert_results(
line,
lnum,
cursor_col,
+ 1,
client_start_boundary,
- nil,
+ server_boundary,
result,
- "utf-16"
+ 'utf-16'
)
return {
items = items,
- server_start_boundary = server_start_boundary
+ server_start_boundary = new_server_boundary,
}
- ]],
- line,
- cursor_col,
- lnum,
- candidates
- )
+ end, candidates)
end
-describe('vim.lsp._completion', function()
+describe('vim.lsp.completion: item conversion', function()
before_each(n.clear)
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
@@ -70,39 +71,24 @@ describe('vim.lsp._completion', function()
textEdit = { newText = 'foobar', range = range0 },
},
{ label = 'foocar', sortText = 'f', textEdit = { newText = 'foobar', range = range0 } },
- -- real-world snippet text
+ -- plain text
{
label = 'foocar',
sortText = 'g',
- insertText = 'foodar',
+ insertText = 'foodar(${1:var1})',
+ insertTextFormat = 1,
+ },
+ {
+ label = '•INT16_C(c)',
+ insertText = 'INT16_C(${1:c})',
insertTextFormat = 2,
+ filterText = 'INT16_C',
+ sortText = 'h',
textEdit = {
- newText = 'foobar(${1:place holder}, ${2:more ...holder{\\}})',
+ newText = 'INT16_C(${1:c})',
range = range0,
},
},
- {
- label = 'foocar',
- sortText = 'h',
- insertText = 'foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}',
- insertTextFormat = 2,
- },
- -- nested snippet tokens
- {
- label = 'foocar',
- sortText = 'i',
- insertText = 'foodar(${1:${2|typ1,typ2|}}) {$0\\}',
- insertTextFormat = 2,
- },
- -- braced tabstop
- { label = 'foocar', sortText = 'j', insertText = 'foodar()${0}', insertTextFormat = 2 },
- -- plain text
- {
- label = 'foocar',
- sortText = 'k',
- insertText = 'foodar(${1:var1})',
- insertTextFormat = 1,
- },
}
local expected = {
{
@@ -131,23 +117,167 @@ describe('vim.lsp._completion', function()
},
{
abbr = 'foocar',
- word = 'foobar(place holder, more ...holder{})',
+ word = 'foodar(${1:var1})', -- marked as PlainText, text is used as is
},
{
- abbr = 'foocar',
- word = 'foodar(var1 typ1, var2 *typ2) {}',
+ abbr = '•INT16_C(c)',
+ word = 'INT16_C',
},
+ }
+ local result = complete('|', completion_list)
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ eq(expected, result)
+ end)
+
+ it('filters on label if filterText is missing', function()
+ local completion_list = {
+ { label = 'foo' },
+ { label = 'bar' },
+ }
+ local result = complete('fo|', completion_list)
+ local expected = {
{
- abbr = 'foocar',
- word = 'foodar(typ1) {}',
+ abbr = 'foo',
+ word = 'foo',
},
+ }
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ eq(expected, result)
+ end)
+
+ it('works on non word prefix', function()
+ local completion_list = {
+ { label = ' foo', insertText = '->foo' },
+ }
+ local result = complete('wp.|', completion_list, 0, 2)
+ local expected = {
{
- abbr = 'foocar',
- word = 'foodar()',
+ abbr = ' foo',
+ word = '->foo',
},
+ }
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+ eq(expected, result)
+ end)
+
+ it('trims trailing newline or tab from textEdit', function()
+ local range0 = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ }
+ local items = {
{
- abbr = 'foocar',
- word = 'foodar(${1:var1})',
+ detail = 'ansible.builtin',
+ filterText = 'lineinfile ansible.builtin.lineinfile builtin ansible',
+ kind = 7,
+ label = 'ansible.builtin.lineinfile',
+ sortText = '2_ansible.builtin.lineinfile',
+ textEdit = {
+ newText = 'ansible.builtin.lineinfile:\n ',
+ range = range0,
+ },
+ },
+ }
+ local result = complete('|', items)
+ result = vim.tbl_map(function(x)
+ return {
+ abbr = x.abbr,
+ word = x.word,
+ }
+ end, result.items)
+
+ local expected = {
+ {
+ abbr = 'ansible.builtin.lineinfile',
+ word = 'ansible.builtin.lineinfile:',
+ },
+ }
+ eq(expected, result)
+ end)
+
+ it('prefers wordlike components for snippets', function()
+ -- There are two goals here:
+ --
+ -- 1. The `word` should match what the user started typing, so that vim.fn.complete() doesn't
+ -- filter it away, preventing snippet expansion
+ --
+ -- For example, if they type `items@ins`, luals returns `table.insert(items, $0)` as
+ -- textEdit.newText and `insert` as label.
+ -- There would be no prefix match if textEdit.newText is used as `word`
+ --
+ -- 2. If users do not expand a snippet, but continue typing, they should see a somewhat reasonable
+ -- `word` getting inserted.
+ --
+ -- For example in:
+ --
+ -- insertText: "testSuites ${1:Env}"
+ -- label: "testSuites"
+ --
+ -- "testSuites" should have priority as `word`, as long as the full snippet gets expanded on accept (<c-y>)
+ local range0 = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
+ }
+ local completion_list = {
+ -- luals postfix snippet (typed text: items@ins|)
+ {
+ label = 'insert',
+ insertTextFormat = 2,
+ textEdit = {
+ newText = 'table.insert(items, $0)',
+ range = range0,
+ },
+ },
+
+ -- eclipse.jdt.ls `new` snippet
+ {
+ label = 'new',
+ insertTextFormat = 2,
+ textEdit = {
+ newText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}',
+ range = range0,
+ },
+ textEditText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}',
+ },
+
+ -- eclipse.jdt.ls `List.copyO` function call completion
+ {
+ label = 'copyOf(Collection<? extends E> coll) : List<E>',
+ insertTextFormat = 2,
+ insertText = 'copyOf',
+ textEdit = {
+ newText = 'copyOf(${1:coll})',
+ range = range0,
+ },
+ },
+ }
+ local expected = {
+ {
+ abbr = 'copyOf(Collection<? extends E> coll) : List<E>',
+ word = 'copyOf',
+ },
+ {
+ abbr = 'insert',
+ word = 'insert',
+ },
+ {
+ abbr = 'new',
+ word = 'new',
},
}
local result = complete('|', completion_list)
@@ -159,6 +289,7 @@ describe('vim.lsp._completion', function()
end, result.items)
eq(expected, result)
end)
+
it('uses correct start boundary', function()
local completion_list = {
isIncomplete = false,
@@ -186,8 +317,10 @@ describe('vim.lsp._completion', function()
dup = 1,
empty = 1,
icase = 1,
+ info = '',
kind = 'Module',
menu = '',
+ hl_group = '',
word = 'this_thread',
}
local result = complete(' std::this|', completion_list)
@@ -218,7 +351,7 @@ describe('vim.lsp._completion', function()
},
},
{
- filterText = 'notthis_thread',
+ filterText = 'no_match',
insertText = 'notthis_thread',
insertTextFormat = 1,
kind = 9,
@@ -240,8 +373,10 @@ describe('vim.lsp._completion', function()
dup = 1,
empty = 1,
icase = 1,
+ info = '',
kind = 'Module',
menu = '',
+ hl_group = '',
word = 'this_thread',
}
local result = complete(' std::this|is', completion_list)
@@ -278,4 +413,316 @@ describe('vim.lsp._completion', function()
eq('item-property-has-priority', item.data)
eq({ line = 1, character = 1 }, item.textEdit.range.start)
end)
+
+ it(
+ 'uses insertText as textEdit.newText if there are editRange defaults but no textEditText',
+ function()
+ --- @type lsp.CompletionList
+ local completion_list = {
+ isIncomplete = false,
+ itemDefaults = {
+ editRange = {
+ start = { line = 1, character = 1 },
+ ['end'] = { line = 1, character = 4 },
+ },
+ insertTextFormat = 2,
+ data = 'foobar',
+ },
+ items = {
+ {
+ insertText = 'the-insertText',
+ label = 'hello',
+ data = 'item-property-has-priority',
+ },
+ },
+ }
+ local result = complete('|', completion_list)
+ eq(1, #result.items)
+ local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText
+ eq('the-insertText', text)
+ end
+ )
+
+ it(
+ 'defaults to label as textEdit.newText if insertText or textEditText are not present',
+ function()
+ local completion_list = {
+ isIncomplete = false,
+ itemDefaults = {
+ editRange = {
+ start = { line = 1, character = 1 },
+ ['end'] = { line = 1, character = 4 },
+ },
+ insertTextFormat = 2,
+ data = 'foobar',
+ },
+ items = {
+ {
+ label = 'hello',
+ data = 'item-property-has-priority',
+ },
+ },
+ }
+ local result = complete('|', completion_list)
+ eq(1, #result.items)
+ local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText
+ eq('hello', text)
+ end
+ )
+end)
+
+describe('vim.lsp.completion: protocol', function()
+ before_each(function()
+ clear()
+ exec_lua(create_server_definition)
+ exec_lua(function()
+ _G.capture = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.fn.complete = function(col, matches)
+ _G.capture.col = col
+ _G.capture.matches = matches
+ end
+ end)
+ end)
+
+ after_each(clear)
+
+ --- @param completion_result lsp.CompletionList
+ --- @return integer
+ local function create_server(completion_result)
+ return exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ completionProvider = {
+ triggerCharacters = { '.' },
+ },
+ },
+ handlers = {
+ ['textDocument/completion'] = function(_, _, callback)
+ callback(nil, completion_result)
+ end,
+ },
+ })
+
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ return vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ on_attach = function(client, bufnr0)
+ vim.lsp.completion.enable(true, client.id, bufnr0, {
+ convert = function(item)
+ return { abbr = item.label:gsub('%b()', '') }
+ end,
+ })
+ end,
+ })
+ end)
+ end
+
+ local function assert_matches(fn)
+ retry(nil, nil, function()
+ fn(exec_lua('return _G.capture.matches'))
+ end)
+ end
+
+ --- @param pos [integer, integer]
+ local function trigger_at_pos(pos)
+ exec_lua(function()
+ local win = vim.api.nvim_get_current_win()
+ vim.api.nvim_win_set_cursor(win, pos)
+ vim.lsp.completion.trigger()
+ end)
+
+ retry(nil, nil, function()
+ neq(nil, exec_lua('return _G.capture.col'))
+ end)
+ end
+
+ it('fetches completions and shows them using complete on trigger', function()
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ },
+ {
+ label = 'hercules',
+ tags = { 1 }, -- 1 represents Deprecated tag
+ },
+ {
+ label = 'hero',
+ deprecated = true,
+ },
+ },
+ })
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ assert_matches(function(matches)
+ eq({
+ {
+ abbr = 'hello',
+ dup = 1,
+ empty = 1,
+ icase = 1,
+ info = '',
+ kind = 'Unknown',
+ menu = '',
+ hl_group = '',
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = 1,
+ completion_item = {
+ label = 'hello',
+ },
+ },
+ },
+ },
+ word = 'hello',
+ },
+ {
+ abbr = 'hercules',
+ dup = 1,
+ empty = 1,
+ icase = 1,
+ info = '',
+ kind = 'Unknown',
+ menu = '',
+ hl_group = 'DiagnosticDeprecated',
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = 1,
+ completion_item = {
+ label = 'hercules',
+ tags = { 1 },
+ },
+ },
+ },
+ },
+ word = 'hercules',
+ },
+ {
+ abbr = 'hero',
+ dup = 1,
+ empty = 1,
+ icase = 1,
+ info = '',
+ kind = 'Unknown',
+ menu = '',
+ hl_group = 'DiagnosticDeprecated',
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = 1,
+ completion_item = {
+ label = 'hero',
+ deprecated = true,
+ },
+ },
+ },
+ },
+ word = 'hero',
+ },
+ }, matches)
+ end)
+ end)
+
+ it('merges results from multiple clients', function()
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ },
+ },
+ })
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hallo',
+ },
+ },
+ })
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ assert_matches(function(matches)
+ eq(2, #matches)
+ eq('hello', matches[1].word)
+ eq('hallo', matches[2].word)
+ end)
+ end)
+
+ it('executes commands', function()
+ local completion_list = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ command = {
+ arguments = { '1', '0' },
+ command = 'dummy',
+ title = '',
+ },
+ },
+ },
+ }
+ local client_id = create_server(completion_list)
+
+ exec_lua(function()
+ _G.called = false
+ local client = assert(vim.lsp.get_client_by_id(client_id))
+ client.commands.dummy = function()
+ _G.called = true
+ end
+ end)
+
+ feed('ih')
+ trigger_at_pos({ 1, 1 })
+
+ local item = completion_list.items[1]
+ exec_lua(function()
+ vim.v.completed_item = {
+ user_data = {
+ nvim = {
+ lsp = {
+ client_id = client_id,
+ completion_item = item,
+ },
+ },
+ },
+ }
+ end)
+
+ feed('<C-x><C-o><C-y>')
+
+ assert_matches(function(matches)
+ eq(1, #matches)
+ eq('hello', matches[1].word)
+ eq(true, exec_lua('return _G.called'))
+ end)
+ end)
+
+ it('enable(…,{convert=fn}) custom word/abbr format', function()
+ create_server({
+ isIncomplete = false,
+ items = {
+ {
+ label = 'foo(bar)',
+ },
+ },
+ })
+
+ feed('ifo')
+ trigger_at_pos({ 1, 1 })
+ assert_matches(function(matches)
+ eq('foo', matches[1].abbr)
+ end)
+ end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index c5e14ffdc2..78c684083b 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -11,7 +11,9 @@ local neq = t.neq
local create_server_definition = t_lsp.create_server_definition
describe('vim.lsp.diagnostic', function()
- local fake_uri
+ local fake_uri --- @type string
+ local client_id --- @type integer
+ local diagnostic_bufnr --- @type integer
before_each(function()
clear { env = {
@@ -19,198 +21,174 @@ describe('vim.lsp.diagnostic', function()
VIMRUNTIME = os.getenv 'VIMRUNTIME',
} }
- exec_lua [[
+ exec_lua(function()
require('vim.lsp')
- make_range = function(x1, y1, x2, y2)
+ _G.make_range = function(x1, y1, x2, y2)
return { start = { line = x1, character = y1 }, ['end'] = { line = x2, character = y2 } }
end
- make_error = function(msg, x1, y1, x2, y2)
+ _G.make_error = function(msg, x1, y1, x2, y2)
return {
- range = make_range(x1, y1, x2, y2),
+ range = _G.make_range(x1, y1, x2, y2),
message = msg,
severity = 1,
}
end
- make_warning = function(msg, x1, y1, x2, y2)
+ _G.make_warning = function(msg, x1, y1, x2, y2)
return {
- range = make_range(x1, y1, x2, y2),
+ range = _G.make_range(x1, y1, x2, y2),
message = msg,
severity = 2,
}
end
- make_information = function(msg, x1, y1, x2, y2)
+ _G.make_information = function(msg, x1, y1, x2, y2)
return {
- range = make_range(x1, y1, x2, y2),
+ range = _G.make_range(x1, y1, x2, y2),
message = msg,
severity = 3,
}
end
- function get_extmarks(bufnr, client_id)
- local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ function _G.get_extmarks(bufnr, client_id0)
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id0)
local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = {}
if ns.user_data.virt_text_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.virt_text_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
if ns.user_data.underline_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.underline_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
return extmarks
end
- client_id = vim.lsp.start_client {
+ client_id = assert(vim.lsp.start_client {
cmd_env = {
- NVIM_LUA_NOTRACK = "1";
- };
+ NVIM_LUA_NOTRACK = '1',
+ },
cmd = {
- vim.v.progpath, '-es', '-u', 'NONE', '--headless'
- };
- offset_encoding = "utf-16";
- }
- ]]
+ vim.v.progpath,
+ '-es',
+ '-u',
+ 'NONE',
+ '--headless',
+ },
+ offset_encoding = 'utf-16',
+ })
+ end)
fake_uri = 'file:///fake/uri'
- exec_lua(
- [[
- fake_uri = ...
+ exec_lua(function()
diagnostic_bufnr = vim.uri_to_bufnr(fake_uri)
- local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"}
+ local lines = { '1st line of text', '2nd line of text', 'wow', 'cool', 'more', 'lines' }
vim.fn.bufload(diagnostic_bufnr)
vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- return diagnostic_bufnr
- ]],
- fake_uri
- )
+ end)
end)
after_each(function()
clear()
end)
- describe('vim.lsp.diagnostic', function()
- it('maintains LSP information when translating diagnostics', function()
- local result = exec_lua [[
- local diagnostics = {
- make_error("Error 1", 1, 1, 1, 5),
- }
-
- diagnostics[1].code = 42
- diagnostics[1].data = "Hello world"
-
- vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = fake_uri,
- diagnostics = diagnostics,
- }, {client_id=client_id})
-
- return {
- vim.diagnostic.get(diagnostic_bufnr, {lnum=1})[1],
- vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1],
- }
- ]]
- eq({ code = 42, data = 'Hello world' }, result[1].user_data.lsp)
- eq(42, result[1].code)
- eq(42, result[2].code)
- eq('Hello world', result[2].data)
- end)
- end)
-
describe('vim.lsp.diagnostic.on_publish_diagnostics', function()
it('allows configuring the virtual text via vim.lsp.with', function()
local expected_spacing = 10
- local extmarks = exec_lua(
- [[
- PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ local extmarks = exec_lua(function()
+ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = {
- spacing = ...,
+ spacing = expected_spacing,
},
})
- PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
- }
- }, {client_id=client_id}
- )
+ _G.PublishDiagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ },
+ }, { client_id = client_id })
- return get_extmarks(diagnostic_bufnr, client_id)
- ]],
- expected_spacing
- )
+ return _G.get_extmarks(diagnostic_bufnr, client_id)
+ end)
- local virt_text = extmarks[1][4].virt_text
- local spacing = virt_text[1][1]
+ local spacing = extmarks[1][4].virt_text[1][1]
eq(expected_spacing, #spacing)
end)
it('allows configuring the virtual text via vim.lsp.with using a function', function()
local expected_spacing = 10
- local extmarks = exec_lua(
- [[
- spacing = ...
-
- PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ local extmarks = exec_lua(function()
+ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = function()
return {
- spacing = spacing,
+ spacing = expected_spacing,
}
end,
})
- PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_error('Delayed Diagnostic', 4, 4, 4, 4),
- }
- }, {client_id=client_id}
- )
+ _G.PublishDiagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ },
+ }, { client_id = client_id })
- return get_extmarks(diagnostic_bufnr, client_id)
- ]],
- expected_spacing
- )
+ return _G.get_extmarks(diagnostic_bufnr, client_id)
+ end)
- local virt_text = extmarks[1][4].virt_text
- local spacing = virt_text[1][1]
+ local spacing = extmarks[1][4].virt_text[1][1]
eq(expected_spacing, #spacing)
end)
it('allows filtering via severity limit', function()
local get_extmark_count_with_severity = function(severity_limit)
- return exec_lua(
- [[
- PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
+ return exec_lua(function()
+ _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
underline = false,
virtual_text = {
- severity = { min = ... }
+ severity = { min = severity_limit },
},
})
- PublishDiagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_warning('Delayed Diagnostic', 4, 4, 4, 4),
- }
- }, {client_id=client_id}
- )
-
- return #get_extmarks(diagnostic_bufnr, client_id)
- ]],
- severity_limit
- )
+ _G.PublishDiagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4),
+ },
+ }, { client_id = client_id })
+
+ return #_G.get_extmarks(diagnostic_bufnr, client_id)
+ end, client_id, fake_uri, severity_limit)
end
-- No messages with Error or higher
@@ -223,218 +201,284 @@ describe('vim.lsp.diagnostic', function()
it('correctly handles UTF-16 offsets', function()
local line = 'All 💼 and no 🎉 makes Jack a dull 👦'
- local result = exec_lua(
- [[
- local line = ...
- vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, {line})
+ local result = exec_lua(function()
+ vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, { line })
vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = fake_uri,
- diagnostics = {
- make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
- }
- }, {client_id=client_id}
- )
+ uri = fake_uri,
+ diagnostics = {
+ _G.make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
+ },
+ }, { client_id = client_id })
local diags = vim.diagnostic.get(diagnostic_bufnr)
vim.lsp.stop_client(client_id)
vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
return diags
- ]],
- line
- )
+ end)
eq(1, #result)
- eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col)
- eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col)
+ eq(
+ exec_lua(function()
+ return vim.str_byteindex(line, 7, true)
+ end),
+ result[1].col
+ )
+ eq(
+ exec_lua(function()
+ return vim.str_byteindex(line, 8, true)
+ end),
+ result[1].end_col
+ )
end)
it('does not create buffer on empty diagnostics', function()
- local bufnr
-
-- No buffer is created without diagnostics
- bufnr = exec_lua [[
- vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = "file:///fake/uri2",
- diagnostics = {},
- }, {client_id=client_id})
- return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
- ]]
- eq(-1, bufnr)
+ eq(
+ -1,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = 'file:///fake/uri2',
+ diagnostics = {},
+ }, { client_id = client_id })
+ return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
+ end)
+ )
-- Create buffer on diagnostics
- bufnr = exec_lua [[
- vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = "file:///fake/uri2",
- diagnostics = {
- make_error('Diagnostic', 0, 0, 0, 0),
- },
- }, {client_id=client_id})
- return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
- ]]
- neq(-1, bufnr)
- eq(1, exec_lua([[return #vim.diagnostic.get(...)]], bufnr))
+ neq(
+ -1,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = 'file:///fake/uri2',
+ diagnostics = {
+ _G.make_error('Diagnostic', 0, 0, 0, 0),
+ },
+ }, { client_id = client_id })
+ return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
+ end)
+ )
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(_G.bufnr)
+ end)
+ )
-- Clear diagnostics after buffer was created
- bufnr = exec_lua [[
- vim.lsp.diagnostic.on_publish_diagnostics(nil, {
- uri = "file:///fake/uri2",
- diagnostics = {},
- }, {client_id=client_id})
- return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
- ]]
- neq(-1, bufnr)
- eq(0, exec_lua([[return #vim.diagnostic.get(...)]], bufnr))
+ neq(
+ -1,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = 'file:///fake/uri2',
+ diagnostics = {},
+ }, { client_id = client_id })
+ return vim.fn.bufnr(vim.uri_to_fname('file:///fake/uri2'))
+ end)
+ )
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.diagnostic.get(_G.bufnr)
+ end)
+ )
end)
end)
describe('vim.lsp.diagnostic.on_diagnostic', function()
before_each(function()
exec_lua(create_server_definition)
- exec_lua([[
- server = _create_server({
+ exec_lua(function()
+ _G.server = _G._create_server({
capabilities = {
- diagnosticProvider = {
- }
- }
+ diagnosticProvider = {},
+ },
})
- function get_extmarks(bufnr, client_id)
- local namespace = vim.lsp.diagnostic.get_namespace(client_id, true)
+ function _G.get_extmarks(bufnr, client_id0)
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id0, true)
local ns = vim.diagnostic.get_namespace(namespace)
local extmarks = {}
if ns.user_data.virt_text_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.virt_text_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.virt_text_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
if ns.user_data.underline_ns then
- for _, e in pairs(vim.api.nvim_buf_get_extmarks(bufnr, ns.user_data.underline_ns, 0, -1, {details=true})) do
+ for _, e in
+ pairs(
+ vim.api.nvim_buf_get_extmarks(
+ bufnr,
+ ns.user_data.underline_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ )
+ do
table.insert(extmarks, e)
end
end
return extmarks
end
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
+ client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
end)
it('adds diagnostics to vim.diagnostics', function()
- local diags = exec_lua([[
- vim.lsp.diagnostic.on_diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ local diags = exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
return vim.diagnostic.get(diagnostic_bufnr)
- ]])
+ end)
eq(1, #diags)
eq('Pull Diagnostic', diags[1].message)
end)
+ it('severity defaults to error if missing', function()
+ ---@type vim.Diagnostic[]
+ local diagnostics = exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ {
+ range = _G.make_range(4, 4, 4, 4),
+ message = 'bad!',
+ },
+ },
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
+ },
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
+ return vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ eq(1, #diagnostics)
+ eq(1, diagnostics[1].severity)
+ end)
+
it('allows configuring the virtual text via vim.lsp.with', function()
local expected_spacing = 10
- local extmarks = exec_lua(
- [[
- Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
+ local extmarks = exec_lua(function()
+ _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, {
virtual_text = {
- spacing = ...,
+ spacing = expected_spacing,
},
})
- Diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ _G.Diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
- return get_extmarks(diagnostic_bufnr, client_id)
- ]],
- expected_spacing
- )
+ return _G.get_extmarks(diagnostic_bufnr, client_id)
+ end)
eq(2, #extmarks)
eq(expected_spacing, #extmarks[1][4].virt_text[1][1])
end)
it('clears diagnostics when client detaches', function()
- exec_lua([[
- vim.lsp.diagnostic.on_diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
- ]])
- local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(1, #diags)
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
+ end)
+
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
- exec_lua([[ vim.lsp.stop_client(client_id) ]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id)
+ end)
- diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(0, #diags)
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
end)
it('keeps diagnostics when one client detaches and others still are attached', function()
- exec_lua([[
- client_id2 = vim.lsp.start({ name = 'dummy2', cmd = server.cmd })
-
- vim.lsp.diagnostic.on_diagnostic(nil,
- {
- kind = 'full',
- items = {
- make_error('Pull Diagnostic', 4, 4, 4, 4),
- }
+ local client_id2
+ exec_lua(function()
+ client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server.cmd })
+
+ vim.lsp.diagnostic.on_diagnostic(nil, {
+ kind = 'full',
+ items = {
+ _G.make_error('Pull Diagnostic', 4, 4, 4, 4),
},
- {
- params = {
- textDocument = { uri = fake_uri },
- },
- uri = fake_uri,
- client_id = client_id,
+ }, {
+ params = {
+ textDocument = { uri = fake_uri },
},
- {}
- )
- ]])
- local diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(1, #diags)
+ uri = fake_uri,
+ client_id = client_id,
+ }, {})
+ end)
+
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
- exec_lua([[ vim.lsp.stop_client(client_id2) ]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id2)
+ end)
- diags = exec_lua([[return vim.diagnostic.get(diagnostic_bufnr)]])
- eq(1, #diags)
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ end)
+ )
end)
end)
end)
diff --git a/test/functional/plugin/lsp/handler_spec.lua b/test/functional/plugin/lsp/handler_spec.lua
index 013a5fb5e7..4b05b676a8 100644
--- a/test/functional/plugin/lsp/handler_spec.lua
+++ b/test/functional/plugin/lsp/handler_spec.lua
@@ -11,28 +11,31 @@ describe('lsp-handlers', function()
it('should return a table with the default keys', function()
eq(
{ hello = 'world' },
- exec_lua [[
- return vim.lsp._with_extend('test', { hello = 'world' })
- ]]
+ exec_lua(function()
+ return vim.lsp._with_extend('test', { hello = 'world' })
+ end)
)
end)
it('should override with config keys', function()
eq(
{ hello = 'universe', other = true },
- exec_lua [[
- return vim.lsp._with_extend('test', { other = true, hello = 'world' }, { hello = 'universe' })
- ]]
+ exec_lua(function()
+ return vim.lsp._with_extend(
+ 'test',
+ { other = true, hello = 'world' },
+ { hello = 'universe' }
+ )
+ end)
)
end)
it('should not allow invalid keys', function()
matches(
'.*Invalid option for `test`.*',
- pcall_err(
- exec_lua,
- "return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })"
- )
+ pcall_err(exec_lua, function()
+ return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })
+ end)
)
end)
end)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 238b90b57d..f60e159d64 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -10,11 +10,9 @@ local feed = n.feed
before_each(function()
clear()
- exec_lua [[
- local evname = ...
+ exec_lua(function()
local sync = require('vim.lsp.sync')
local events = {}
- local buffer_cache = {}
-- local format_line_ending = {
-- ["unix"] = '\n',
@@ -24,35 +22,43 @@ before_each(function()
-- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
-
- function test_register(bufnr, id, offset_encoding, line_ending)
- local curr_lines
+ --- @diagnostic disable-next-line:duplicate-set-field
+ function _G.test_register(bufnr, id, offset_encoding, line_ending)
local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
- local function callback(_, bufnr, changedtick, firstline, lastline, new_lastline)
- if test_unreg == id then
+ local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline)
+ if _G.test_unreg == id then
return true
end
- local curr_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
+ local curr_lines = vim.api.nvim_buf_get_lines(bufnr0, 0, -1, true)
local incremental_change = sync.compute_diff(
- prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding, line_ending)
+ prev_lines,
+ curr_lines,
+ firstline,
+ lastline,
+ new_lastline,
+ offset_encoding,
+ line_ending
+ )
table.insert(events, incremental_change)
prev_lines = curr_lines
end
- local opts = {on_lines=callback, on_detach=callback, on_reload=callback}
+ local opts = { on_lines = callback, on_detach = callback, on_reload = callback }
vim.api.nvim_buf_attach(bufnr, false, opts)
end
- function get_events()
+ --- @diagnostic disable-next-line:duplicate-set-field
+ function _G.get_events()
local ret_events = events
events = {}
return ret_events
end
- ]]
+ end)
end)
+--- @param edit_operations string[]
local function test_edit(
prev_buffer,
edit_operations,
@@ -64,13 +70,22 @@ local function test_edit(
line_ending = line_ending or '\n'
api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer)
- exec_lua('return test_register(...)', 0, 'test1', offset_encoding, line_ending)
+ exec_lua(function()
+ return _G.test_register(0, 'test1', offset_encoding, line_ending)
+ end)
for _, edit in ipairs(edit_operations) do
feed(edit)
end
- eq(expected_text_changes, exec_lua('return get_events(...)'))
- exec_lua("test_unreg = 'test1'")
+ eq(
+ expected_text_changes,
+ exec_lua(function()
+ return _G.get_events()
+ end)
+ )
+ exec_lua(function()
+ _G.test_unreg = 'test1'
+ end)
end
describe('incremental synchronization', function()
@@ -170,7 +185,7 @@ describe('incremental synchronization', function()
}
test_edit({ 'a' }, { 'rb' }, expected_text_changes, 'utf-16', '\n')
end)
- it('deleting a line', function()
+ it('deleting the first line', function()
local expected_text_changes = {
{
range = {
@@ -183,11 +198,49 @@ describe('incremental synchronization', function()
line = 1,
},
},
- rangeLength = 12,
+ rangeLength = 6,
+ text = '',
+ },
+ }
+ test_edit({ 'hello', 'world' }, { 'ggdd' }, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('deleting the last line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
+ },
+ rangeLength = 6,
+ text = '',
+ },
+ }
+ test_edit({ 'hello', 'world' }, { '2ggdd' }, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('deleting all lines', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0,
+ },
+ ['end'] = {
+ character = 5,
+ line = 1,
+ },
+ },
+ rangeLength = 11,
text = '',
},
}
- test_edit({ 'hello world' }, { 'dd' }, expected_text_changes, 'utf-16', '\n')
+ test_edit({ 'hello', 'world' }, { 'ggdG' }, expected_text_changes, 'utf-16', '\n')
end)
it('deleting an empty line', function()
local expected_text_changes = {
diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua
index d3b5ae0e4e..471f2cc3e8 100644
--- a/test/functional/plugin/lsp/inlay_hint_spec.lua
+++ b/test/functional/plugin/lsp/inlay_hint_spec.lua
@@ -12,7 +12,8 @@ local api = n.api
local clear_notrace = t_lsp.clear_notrace
local create_server_definition = t_lsp.create_server_definition
-local text = dedent([[
+describe('vim.lsp.inlay_hint', function()
+ local text = dedent([[
auto add(int a, int b) { return a + b; }
int main() {
@@ -22,7 +23,7 @@ int main() {
}
}]])
-local response = [==[
+ local response = [==[
[
{"kind":1,"paddingLeft":false,"label":"-> int","position":{"character":22,"line":0},"paddingRight":false},
{"kind":2,"paddingLeft":false,"label":"a:","position":{"character":15,"line":5},"paddingRight":true},
@@ -30,7 +31,7 @@ local response = [==[
]
]==]
-local grid_without_inlay_hints = [[
+ local grid_without_inlay_hints = [[
auto add(int a, int b) { return a + b; } |
|
int main() { |
@@ -42,7 +43,7 @@ local grid_without_inlay_hints = [[
|
]]
-local grid_with_inlay_hints = [[
+ local grid_with_inlay_hints = [[
auto add(int a, int b){1:-> int} { return a + b; } |
|
int main() { |
@@ -54,54 +55,58 @@ local grid_with_inlay_hints = [[
|
]]
---- @type test.functional.ui.screen
-local screen
-before_each(function()
- clear_notrace()
- screen = Screen.new(50, 9)
- screen:attach()
-
- exec_lua(create_server_definition)
- exec_lua(
- [[
- local response = ...
- server = _create_server({
- capabilities = {
- inlayHintProvider = true,
- },
- handlers = {
- ['textDocument/inlayHint'] = function(_, _, callback)
- callback(nil, vim.json.decode(response))
- end,
- }
- })
+ --- @type test.functional.ui.screen
+ local screen
- bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_win_set_buf(0, bufnr)
+ --- @type integer
+ local client_id
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]],
- response
- )
+ --- @type integer
+ local bufnr
- insert(text)
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
- screen:expect({ grid = grid_with_inlay_hints })
-end)
+ before_each(function()
+ clear_notrace()
+ screen = Screen.new(50, 9)
+ screen:attach()
-after_each(function()
- api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
-end)
+ bufnr = n.api.nvim_get_current_buf()
+ exec_lua(create_server_definition)
+ client_id = exec_lua(function()
+ _G.server = _G._create_server({
+ capabilities = {
+ inlayHintProvider = true,
+ },
+ handlers = {
+ ['textDocument/inlayHint'] = function(_, _, callback)
+ callback(nil, vim.json.decode(response))
+ end,
+ },
+ })
+
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+
+ insert(text)
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+ end)
+ screen:expect({ grid = grid_with_inlay_hints })
+ end)
+
+ after_each(function()
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
+ end)
-describe('vim.lsp.inlay_hint', function()
it('clears inlay hints when sole client detaches', function()
- exec_lua([[vim.lsp.stop_client(client_id)]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id)
+ end)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
end)
it('does not clear inlay hints when one of several clients detaches', function()
- exec_lua([[
- server2 = _create_server({
+ local client_id2 = exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
inlayHintProvider = true,
},
@@ -109,13 +114,16 @@ describe('vim.lsp.inlay_hint', function()
['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, {})
end,
- }
+ },
})
- client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
+ local client_id2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })
vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
- ]])
+ return client_id2
+ end)
- exec_lua([[ vim.lsp.stop_client(client2) ]])
+ exec_lua(function()
+ vim.lsp.stop_client(client_id2)
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
@@ -123,61 +131,85 @@ describe('vim.lsp.inlay_hint', function()
it('validation', function()
t.matches(
'enable: expected boolean, got table',
- t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })]])
+ t.pcall_err(exec_lua, function()
+ --- @diagnostic disable-next-line:param-type-mismatch
+ vim.lsp.inlay_hint.enable({}, { bufnr = bufnr })
+ end)
)
t.matches(
'enable: expected boolean, got number',
- t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(42)]])
+ t.pcall_err(exec_lua, function()
+ --- @diagnostic disable-next-line:param-type-mismatch
+ vim.lsp.inlay_hint.enable(42)
+ end)
)
t.matches(
'filter: expected table, got number',
- t.pcall_err(exec_lua, [[vim.lsp.inlay_hint.enable(true, 42)]])
+ t.pcall_err(exec_lua, function()
+ --- @diagnostic disable-next-line:param-type-mismatch
+ vim.lsp.inlay_hint.enable(true, 42)
+ end)
)
end)
describe('clears/applies inlay hints when passed false/true/nil', function()
+ local bufnr2 --- @type integer
before_each(function()
- exec_lua([[
- bufnr2 = vim.api.nvim_create_buf(true, false)
- vim.lsp.buf_attach_client(bufnr2, client_id)
- vim.api.nvim_win_set_buf(0, bufnr2)
- ]])
+ bufnr2 = exec_lua(function()
+ local bufnr2_0 = vim.api.nvim_create_buf(true, false)
+ vim.lsp.buf_attach_client(bufnr2_0, client_id)
+ vim.api.nvim_win_set_buf(0, bufnr2_0)
+ return bufnr2_0
+ end)
insert(text)
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })]])
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr2 })
+ end)
+ n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_with_inlay_hints })
end)
it('for one single buffer', function()
- exec_lua([[
+ exec_lua(function()
vim.lsp.inlay_hint.enable(false, { bufnr = bufnr })
vim.api.nvim_win_set_buf(0, bufnr2)
- ]])
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
+ n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
- exec_lua(
- [[vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }), { bufnr = bufnr })]]
- )
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(
+ not vim.lsp.inlay_hint.is_enabled({ bufnr = bufnr }),
+ { bufnr = bufnr }
+ )
+ end)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
it('for all buffers', function()
- exec_lua([[vim.lsp.inlay_hint.enable(false)]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(false)
+ end)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr2)]])
+ n.api.nvim_win_set_buf(0, bufnr2)
screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
- exec_lua([[vim.lsp.inlay_hint.enable(true)]])
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true)
+ end)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
- exec_lua([[vim.api.nvim_win_set_buf(0, bufnr)]])
+ n.api.nvim_win_set_buf(0, bufnr)
screen:expect({ grid = grid_with_inlay_hints, unchanged = true })
end)
end)
@@ -198,10 +230,8 @@ describe('vim.lsp.inlay_hint', function()
paddingRight = false,
}
- exec_lua(
- [[
- local expected2 = ...
- server2 = _create_server({
+ exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
inlayHintProvider = true,
},
@@ -209,52 +239,139 @@ describe('vim.lsp.inlay_hint', function()
['textDocument/inlayHint'] = function(_, _, callback)
callback(nil, { expected2 })
end,
- }
+ },
})
- client2 = vim.lsp.start({ name = 'dummy2', cmd = server2.cmd })
+ _G.client2 = vim.lsp.start({ name = 'dummy2', cmd = _G.server2.cmd })
vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
- ]],
- expected2
- )
+ end)
--- @type vim.lsp.inlay_hint.get.ret
- local res = exec_lua([[return vim.lsp.inlay_hint.get()]])
- eq({
- { bufnr = 1, client_id = 1, inlay_hint = expected[1] },
- { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
- { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
- { bufnr = 1, client_id = 2, inlay_hint = expected2 },
- }, res)
+ eq(
+ {
+ { bufnr = 1, client_id = 1, inlay_hint = expected[1] },
+ { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
+ { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
+ { bufnr = 1, client_id = 2, inlay_hint = expected2 },
+ },
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get()
+ end)
+ )
- --- @type vim.lsp.inlay_hint.get.ret
- res = exec_lua([[return vim.lsp.inlay_hint.get({
- range = {
- start = { line = 2, character = 10 },
- ["end"] = { line = 2, character = 10 },
+ eq(
+ {
+ { bufnr = 1, client_id = 2, inlay_hint = expected2 },
},
- })]])
- eq({
- { bufnr = 1, client_id = 2, inlay_hint = expected2 },
- }, res)
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get({
+ range = {
+ start = { line = 2, character = 10 },
+ ['end'] = { line = 2, character = 10 },
+ },
+ })
+ end)
+ )
- --- @type vim.lsp.inlay_hint.get.ret
- res = exec_lua([[return vim.lsp.inlay_hint.get({
- bufnr = vim.api.nvim_get_current_buf(),
- range = {
- start = { line = 4, character = 18 },
- ["end"] = { line = 5, character = 17 },
+ eq(
+ {
+ { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
+ { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
},
- })]])
- eq({
- { bufnr = 1, client_id = 1, inlay_hint = expected[2] },
- { bufnr = 1, client_id = 1, inlay_hint = expected[3] },
- }, res)
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get({
+ bufnr = vim.api.nvim_get_current_buf(),
+ range = {
+ start = { line = 4, character = 18 },
+ ['end'] = { line = 5, character = 17 },
+ },
+ })
+ end)
+ )
- --- @type vim.lsp.inlay_hint.get.ret
- res = exec_lua([[return vim.lsp.inlay_hint.get({
- bufnr = vim.api.nvim_get_current_buf() + 1,
- })]])
- eq({}, res)
+ eq(
+ {},
+ exec_lua(function()
+ return vim.lsp.inlay_hint.get({
+ bufnr = vim.api.nvim_get_current_buf() + 1,
+ })
+ end)
+ )
+ end)
+ end)
+end)
+
+describe('Inlay hints handler', function()
+ local text = dedent([[
+test text
+ ]])
+
+ local response = [==[
+ [
+ { "position": { "line": 0, "character": 0 }, "label": "0" },
+ { "position": { "line": 0, "character": 0 }, "label": "1" },
+ { "position": { "line": 0, "character": 0 }, "label": "2" },
+ { "position": { "line": 0, "character": 0 }, "label": "3" },
+ { "position": { "line": 0, "character": 0 }, "label": "4" }
+ ]
+ ]==]
+
+ local grid_without_inlay_hints = [[
+ test text |
+ ^ |
+ |
+]]
+
+ local grid_with_inlay_hints = [[
+ {1:01234}test text |
+ ^ |
+ |
+]]
+
+ --- @type test.functional.ui.screen
+ local screen
+
+ --- @type integer
+ local client_id
+
+ --- @type integer
+ local bufnr
+
+ before_each(function()
+ clear_notrace()
+ screen = Screen.new(50, 3)
+ screen:attach()
+
+ exec_lua(create_server_definition)
+ bufnr = n.api.nvim_get_current_buf()
+ client_id = exec_lua(function()
+ _G.server = _G._create_server({
+ capabilities = {
+ inlayHintProvider = true,
+ },
+ handlers = {
+ ['textDocument/inlayHint'] = function(_, _, callback)
+ callback(nil, vim.json.decode(response))
+ end,
+ },
+ })
+
+ vim.api.nvim_win_set_buf(0, bufnr)
+
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+ insert(text)
+ end)
+
+ it('renders hints with same position in received order', function()
+ exec_lua([[vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })]])
+ screen:expect({ grid = grid_with_inlay_hints })
+ exec_lua(function()
+ vim.lsp.stop_client(client_id)
end)
+ screen:expect({ grid = grid_without_inlay_hints, unchanged = true })
+ end)
+
+ after_each(function()
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
end)
end)
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index 7908c5d2e7..f72aab7e0b 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -25,7 +25,7 @@ after_each(function()
end)
describe('semantic token highlighting', function()
- local screen
+ local screen --- @type test.functional.ui.screen
before_each(function()
screen = Screen.new(40, 16)
screen:attach()
@@ -84,10 +84,8 @@ describe('semantic token highlighting', function()
before_each(function()
exec_lua(create_server_definition)
- exec_lua(
- [[
- local legend, response, edit_response = ...
- server = _create_server({
+ exec_lua(function()
+ _G.server = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = true },
@@ -101,24 +99,19 @@ describe('semantic token highlighting', function()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, vim.fn.json_decode(edit_response))
end,
- }
+ },
})
- ]],
- legend,
- response,
- edit_response
- )
+ end, legend, response, edit_response)
end)
it('buffer is highlighted when attached', function()
- exec_lua([[
- bufnr = vim.api.nvim_get_current_buf()
+ insert(text)
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
vim.bo[bufnr].filetype = 'some-filetype'
- client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]])
-
- insert(text)
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
screen:expect {
grid = [[
@@ -141,23 +134,20 @@ describe('semantic token highlighting', function()
end)
it('use LspTokenUpdate and highlight_token', function()
- exec_lua([[
- vim.api.nvim_create_autocmd("LspTokenUpdate", {
+ insert(text)
+ exec_lua(function()
+ vim.api.nvim_create_autocmd('LspTokenUpdate', {
callback = function(args)
- local token = args.data.token
- if token.type == "function" and token.modifiers.declaration then
- vim.lsp.semantic_tokens.highlight_token(
- token, args.buf, args.data.client_id, "Macro"
- )
+ local token = args.data.token --- @type STTokenRange
+ if token.type == 'function' and token.modifiers.declaration then
+ vim.lsp.semantic_tokens.highlight_token(token, args.buf, args.data.client_id, 'Macro')
end
end,
})
- bufnr = vim.api.nvim_get_current_buf()
+ local 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)
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
screen:expect {
grid = [[
@@ -180,18 +170,23 @@ describe('semantic token highlighting', function()
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([[
+ local bufnr = n.api.nvim_get_current_buf()
+ local client_id = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ local client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ vim.wait(1000, function()
+ return #_G.server.messages > 1
+ end)
+ return client_id
+ end)
+
+ exec_lua(function()
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end
vim.lsp.buf_detach_client(bufnr, client_id)
- ]])
+ end)
screen:expect {
grid = [[
@@ -216,18 +211,19 @@ describe('semantic token highlighting', function()
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 })
- ]])
+ local bufnr = n.api.nvim_get_current_buf()
+ local client_id = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, bufnr)
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
insert(text)
- exec_lua([[
- vim.notify = function() end
- vim.lsp.semantic_tokens.stop(bufnr, client_id)
- ]])
+ exec_lua(function()
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.notify = function() end
+ vim.lsp.semantic_tokens.stop(bufnr, client_id)
+ end)
screen:expect {
grid = [[
@@ -248,9 +244,9 @@ describe('semantic token highlighting', function()
]],
}
- exec_lua([[
- vim.lsp.semantic_tokens.start(bufnr, client_id)
- ]])
+ exec_lua(function()
+ vim.lsp.semantic_tokens.start(bufnr, client_id)
+ end)
screen:expect {
grid = [[
@@ -274,18 +270,17 @@ describe('semantic token highlighting', function()
)
it('highlights start and stop when using "0" for current buffer', 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 })
- ]])
+ local client_id = exec_lua(function()
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
insert(text)
- exec_lua([[
+ exec_lua(function()
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.notify = function() end
vim.lsp.semantic_tokens.stop(0, client_id)
- ]])
+ end)
screen:expect {
grid = [[
@@ -306,9 +301,9 @@ describe('semantic token highlighting', function()
]],
}
- exec_lua([[
+ exec_lua(function()
vim.lsp.semantic_tokens.start(0, client_id)
- ]])
+ end)
screen:expect {
grid = [[
@@ -331,13 +326,10 @@ describe('semantic token highlighting', function()
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)
+ exec_lua(function()
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
screen:expect {
grid = [[
@@ -358,9 +350,9 @@ describe('semantic token highlighting', function()
]],
}
- exec_lua([[
- vim.lsp.semantic_tokens.force_refresh(bufnr)
- ]])
+ exec_lua(function()
+ vim.lsp.semantic_tokens.force_refresh()
+ end)
screen:expect {
grid = [[
@@ -384,7 +376,9 @@ describe('semantic token highlighting', function()
local messages = exec_lua('return server.messages')
local token_request_count = 0
- for _, message in ipairs(messages) do
+ for _, message in
+ ipairs(messages --[[@as {method:string,params:table}[] ]])
+ 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
@@ -394,31 +388,29 @@ describe('semantic token highlighting', function()
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 })
- ]])
+ exec_lua(function()
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
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)
+ eq(
+ {},
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_delete(bufnr, { force = true })
+ return vim.lsp.semantic_tokens.__STHighlighter.active
+ end)
+ )
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)
+
+ exec_lua(function()
+ vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+
screen:expect {
grid = [[
#include <iostream> |
@@ -459,45 +451,49 @@ describe('semantic token highlighting', function()
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)'))
+ local client_id = exec_lua(function()
+ _G.notifications = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.notify = function(...)
+ table.insert(_G.notifications, 1, { ... })
+ end
+ return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+ eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', 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])
+ matches(
+ '%[LSP%] Client with id %d not attached to buffer %d',
+ exec_lua(function()
+ vim.lsp.semantic_tokens.start(0, client_id)
+ return _G.notifications[1][1]
+ end)
+ )
+
+ matches(
+ '%[LSP%] No client with id %d',
+ exec_lua(function()
+ vim.lsp.semantic_tokens.start(0, client_id + 1)
+ return _G.notifications[1][1]
+ end)
+ )
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({
+ local client_id = exec_lua(function()
+ return vim.lsp.start({
name = 'dummy',
- cmd = server.cmd,
- on_attach = vim.schedule_wrap(function(client, bufnr)
+ cmd = _G.server.cmd,
+ --- @param client vim.lsp.Client
+ 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)'))
+ end)
+ eq(true, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
insert(text)
@@ -520,13 +516,18 @@ describe('semantic token highlighting', function()
]],
}
- 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])
+ eq(
+ '[LSP] Server does not support semantic tokens',
+ exec_lua(function()
+ local notifications = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.notify = function(...)
+ table.insert(notifications, 1, { ... })
+ end
+ vim.lsp.semantic_tokens.start(0, client_id)
+ return notifications[1][1]
+ end)
+ )
screen:expect {
grid = [[
@@ -551,28 +552,32 @@ describe('semantic token highlighting', function()
)
it('ignores null responses from the server', function()
- exec_lua([[
- local legend, response, edit_response = ...
- server2 = _create_server({
+ local client_id = exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = false },
},
},
handlers = {
+ --- @param callback function
['textDocument/semanticTokens/full'] = function(_, _, callback)
callback(nil, nil)
end,
- ['textDocument/semanticTokens/full/delta'] = function()
+ --- @param callback function
+ ['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, 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)'))
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
+ end)
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(0, client_id)
+ end)
+ )
insert(text)
@@ -597,10 +602,9 @@ describe('semantic token highlighting', function()
end)
it('does not send delta requests if not supported by server', function()
- exec_lua(
- [[
- local legend, response, edit_response = ...
- server2 = _create_server({
+ insert(text)
+ exec_lua(function()
+ _G.server2 = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = false },
@@ -614,18 +618,11 @@ describe('semantic token highlighting', function()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, 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
- )
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server2.cmd })
+ end)
- insert(text)
screen:expect {
grid = [[
#include <iostream> |
@@ -669,7 +666,9 @@ describe('semantic token highlighting', function()
}
local messages = exec_lua('return server2.messages')
local token_request_count = 0
- for _, message in ipairs(messages) do
+ for _, message in
+ ipairs(messages --[[@as {method:string,params:table}[] ]])
+ 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
@@ -1064,10 +1063,8 @@ b = "as"]],
}) do
it(test.it, function()
exec_lua(create_server_definition)
- exec_lua(
- [[
- local legend, resp = ...
- server = _create_server({
+ local client_id = exec_lua(function(legend, resp)
+ _G.server = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = false },
@@ -1078,25 +1075,22 @@ b = "as"]],
['textDocument/semanticTokens/full'] = function(_, _, callback)
callback(nil, 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
- )
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end, test.legend, test.response)
insert(test.text)
test.expected_screen()
- 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)
+ eq(
+ test.expected,
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ end)
+ )
end)
end
end)
@@ -1449,11 +1443,11 @@ int main()
},
}) do
it(test.it, function()
+ local bufnr = n.api.nvim_get_current_buf()
+ insert(test.text1)
exec_lua(create_server_definition)
- exec_lua(
- [[
- local legend, resp1, resp2 = ...
- server = _create_server({
+ local client_id = exec_lua(function(legend, resp1, resp2)
+ _G.server = _G._create_server({
capabilities = {
semanticTokensProvider = {
full = { delta = true },
@@ -1467,54 +1461,44 @@ int main()
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
callback(nil, 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 })
+ local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = _G.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 })
+ vim.lsp.semantic_tokens.stop(bufnr, client_id)
+ vim.lsp.semantic_tokens.start(bufnr, client_id, { debounce = 10 })
end)
- ]],
- test.legend,
- test.response1,
- test.response2
- )
-
- insert(test.text1)
+ return client_id
+ end, test.legend, test.response1, test.response2)
test.expected_screen1()
- local highlights = exec_lua([[
- return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
- ]])
-
- eq(test.expected1, highlights)
+ eq(
+ test.expected1,
+ exec_lua(function()
+ return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ end)
+ )
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"))
+ exec_lua(function(text)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, '\n'))
vim.wait(15) -- wait for debounce
- ]],
- test.text2
- )
+ end, test.text2)
end
test.expected_screen2()
- highlights = exec_lua([[
- return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
- ]])
-
- eq(test.expected2, highlights)
+ eq(
+ test.expected2,
+ exec_lua(function()
+ return vim.lsp.semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
+ end)
+ )
end)
end
end)
diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua
index 3430a1e1a3..a36cbac568 100644
--- a/test/functional/plugin/lsp/testutil.lua
+++ b/test/functional/plugin/lsp/testutil.lua
@@ -21,8 +21,35 @@ function M.clear_notrace()
}
end
-M.create_server_definition = [[
- function _create_server(opts)
+M.create_tcp_echo_server = function()
+ --- Create a TCP server that echos the first message it receives.
+ --- @param host string
+ ---@return uv.uv_tcp_t
+ ---@return integer
+ ---@return fun():string|nil
+ function _G._create_tcp_server(host)
+ local uv = vim.uv
+ local server = assert(uv.new_tcp())
+ local init = nil
+ server:bind(host, 0)
+ server:listen(127, function(err)
+ assert(not err, err)
+ local socket = assert(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
+ return server, port, function()
+ return init
+ end
+ end
+end
+
+M.create_server_definition = function()
+ function _G._create_server(opts)
opts = opts or {}
local server = {}
server.messages = {}
@@ -42,7 +69,7 @@ M.create_server_definition = [[
handler(method, params, callback)
elseif method == 'initialize' then
callback(nil, {
- capabilities = opts.capabilities or {}
+ capabilities = opts.capabilities or {},
})
elseif method == 'shutdown' then
callback(nil, nil)
@@ -54,7 +81,7 @@ M.create_server_definition = [[
function srv.notify(method, params)
table.insert(server.messages, {
method = method,
- params = params
+ params = params,
})
if method == 'exit' then
dispatchers.on_exit(0, 15)
@@ -74,63 +101,62 @@ M.create_server_definition = [[
return server
end
-]]
+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, fake_lsp_code, fake_lsp_logfile, timeout, options, settings = ...
- TEST_RPC_CLIENT_ID = lsp.start_client {
+ exec_lua(function(fake_lsp_code, fake_lsp_logfile, timeout)
+ options = options or {}
+ settings = settings or {}
+ _G.lsp = require('vim.lsp')
+ _G.TEST_RPC_CLIENT_ID = _G.lsp.start_client {
cmd_env = {
- NVIM_LOG_FILE = fake_lsp_logfile;
- NVIM_LUA_NOTRACK = "1";
- NVIM_APPNAME = "nvim_lsp_test";
- };
+ NVIM_LOG_FILE = fake_lsp_logfile,
+ NVIM_LUA_NOTRACK = '1',
+ NVIM_APPNAME = 'nvim_lsp_test',
+ },
cmd = {
- vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout),
- };
+ vim.v.progpath,
+ '-l',
+ fake_lsp_code,
+ test_name,
+ tostring(timeout),
+ },
handlers = setmetatable({}, {
- __index = function(t, method)
+ __index = function(_t, _method)
return function(...)
return vim.rpcrequest(1, 'handler', ...)
end
- end;
- });
- workspace_folders = {{
+ end,
+ }),
+ workspace_folders = {
+ {
uri = 'file://' .. vim.uv.cwd(),
name = 'test_folder',
- }};
- before_init = function(params, config)
+ },
+ },
+ before_init = function(_params, _config)
vim.schedule(function()
- vim.rpcrequest(1, "setup")
+ vim.rpcrequest(1, 'setup')
end)
end,
on_init = function(client, result)
- TEST_RPC_CLIENT = client
- vim.rpcrequest(1, "init", result)
- end;
+ _G.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;
+ 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;
+ vim.rpcnotify(1, 'exit', ...)
+ end,
}
- ]=],
- test_name,
- M.fake_lsp_code,
- M.fake_lsp_logfile,
- timeout_ms or 1e3,
- options or {},
- settings or {}
- )
+ end, M.fake_lsp_code, M.fake_lsp_logfile, timeout_ms or 1e3)
end
--- @class test.lsp.Config
@@ -160,18 +186,13 @@ function M.test_rpc_server(config)
-- 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,
- ...
- )
+ return exec_lua(function(...)
+ if type(_G.TEST_RPC_CLIENT[name]) == 'function' then
+ return _G.TEST_RPC_CLIENT[name](...)
+ else
+ return _G.TEST_RPC_CLIENT[name]
+ end
+ end, ...)
end
end,
})
diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua
index 6c6dec0667..64d58eeffd 100644
--- a/test/functional/plugin/lsp/utils_spec.lua
+++ b/test/functional/plugin/lsp/utils_spec.lua
@@ -11,21 +11,11 @@ describe('vim.lsp.util', function()
describe('stylize_markdown', function()
local stylize_markdown = function(content, opts)
- return exec_lua(
- [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ return exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
vim.fn.bufload(bufnr)
-
- local args = { ... }
- local content = args[1]
- local opts = args[2]
- local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts)
-
- return stripped_content
- ]],
- content,
- opts
- )
+ return vim.lsp.util.stylize_markdown(bufnr, content, opts)
+ end)
end
it('code fences', function()
@@ -93,9 +83,64 @@ describe('vim.lsp.util', function()
end)
end)
- describe('normalize_markdown', function()
+ it('convert_input_to_markdown_lines', function()
+ local r = exec_lua(function()
+ local hover_data = {
+ kind = 'markdown',
+ value = '```lua\nfunction vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)\n -> boolean\n```\n\n---\n\n Activates buffer-update events. Example:\n\n\n\n ```lua\n events = {}\n vim.api.nvim_buf_attach(0, false, {\n on_lines = function(...)\n table.insert(events, {...})\n end,\n })\n ```\n\n\n @see `nvim_buf_detach()`\n @see `api-buffer-updates-lua`\n@*param* `buffer` — Buffer handle, or 0 for current buffer\n\n\n\n@*param* `send_buffer` — True if whole buffer.\n Else the first notification will be `nvim_buf_changedtick_event`.\n\n\n@*param* `opts` — Optional parameters.\n\n - on_lines: Lua callback. Args:\n - the string "lines"\n - buffer handle\n - b:changedtick\n@*return* — False if foo;\n\n otherwise True.\n\n@see foo\n@see bar\n\n',
+ }
+ return vim.lsp.util.convert_input_to_markdown_lines(hover_data)
+ end)
+ local expected = {
+ '```lua',
+ 'function vim.api.nvim_buf_attach(buffer: integer, send_buffer: boolean, opts: vim.api.keyset.buf_attach)',
+ ' -> boolean',
+ '```',
+ '',
+ '---',
+ '',
+ ' Activates buffer-update events. Example:',
+ '',
+ '',
+ '',
+ ' ```lua',
+ ' events = {}',
+ ' vim.api.nvim_buf_attach(0, false, {',
+ ' on_lines = function(...)',
+ ' table.insert(events, {...})',
+ ' end,',
+ ' })',
+ ' ```',
+ '',
+ '',
+ ' @see `nvim_buf_detach()`',
+ ' @see `api-buffer-updates-lua`',
+ '',
+ -- For each @param/@return: #30695
+ -- - Separate each by one empty line.
+ -- - Remove all other blank lines.
+ '@*param* `buffer` — Buffer handle, or 0 for current buffer',
+ '',
+ '@*param* `send_buffer` — True if whole buffer.',
+ ' Else the first notification will be `nvim_buf_changedtick_event`.',
+ '',
+ '@*param* `opts` — Optional parameters.',
+ ' - on_lines: Lua callback. Args:',
+ ' - the string "lines"',
+ ' - buffer handle',
+ ' - b:changedtick',
+ '',
+ '@*return* — False if foo;',
+ ' otherwise True.',
+ '@see foo',
+ '@see bar',
+ }
+ eq(expected, r)
+ end)
+
+ describe('_normalize_markdown', function()
it('collapses consecutive blank lines', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local lines = {
'foo',
'',
@@ -103,25 +148,25 @@ describe('vim.lsp.util', function()
'',
'bar',
'',
- 'baz'
+ 'baz',
}
return vim.lsp.util._normalize_markdown(lines)
- ]]
+ end)
local expected = { 'foo', '', 'bar', '', 'baz' }
eq(expected, result)
end)
it('removes preceding and trailing empty lines', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local lines = {
'',
'foo',
'bar',
'',
- ''
+ '',
}
return vim.lsp.util._normalize_markdown(lines)
- ]]
+ end)
local expected = { 'foo', 'bar' }
eq(expected, result)
end)
@@ -129,19 +174,14 @@ describe('vim.lsp.util', function()
describe('make_floating_popup_options', function()
local function assert_anchor(anchor_bias, expected_anchor)
- local opts = exec_lua(
- [[
- local args = { ... }
- local anchor_bias = args[1]
- return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
- ]],
- anchor_bias
- )
+ local opts = exec_lua(function()
+ return vim.lsp.util.make_floating_popup_options(30, 10, { anchor_bias = anchor_bias })
+ end)
eq(expected_anchor, string.sub(opts.anchor, 1, 1))
end
- local screen
+ local screen --- @type test.functional.ui.screen
before_each(function()
n.clear()
screen = Screen.new(80, 80)
@@ -221,9 +261,9 @@ describe('vim.lsp.util', function()
end)
it('bordered window truncates dimensions correctly', function()
- local opts = exec_lua([[
+ local opts = exec_lua(function()
return vim.lsp.util.make_floating_popup_options(100, 100, { border = 'single' })
- ]])
+ end)
eq(56, opts.height)
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index c95a96baca..9956fdf628 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -33,12 +33,38 @@ local create_server_definition = t_lsp.create_server_definition
local fake_lsp_code = t_lsp.fake_lsp_code
local fake_lsp_logfile = t_lsp.fake_lsp_logfile
local test_rpc_server = t_lsp.test_rpc_server
+local create_tcp_echo_server = t_lsp.create_tcp_echo_server
local function get_buf_option(name, bufnr)
- bufnr = bufnr or 'BUFFER'
- return exec_lua(
- string.format("return vim.api.nvim_get_option_value('%s', { buf = %s })", name, bufnr)
+ return exec_lua(function()
+ bufnr = bufnr or _G.BUFFER
+ return vim.api.nvim_get_option_value(name, { buf = bufnr })
+ end)
+end
+
+local function make_edit(y_0, x_0, y_1, x_1, text)
+ return {
+ range = {
+ start = { line = y_0, character = x_0 },
+ ['end'] = { line = y_1, character = x_1 },
+ },
+ newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''),
+ }
+end
+
+--- @param edits [integer, integer, integer, integer, string|string[]][]
+--- @param encoding? string
+local function apply_text_edits(edits, encoding)
+ local edits1 = vim.tbl_map(
+ --- @param edit [integer, integer, integer, integer, string|string[]]
+ function(edit)
+ return make_edit(unpack(edit))
+ end,
+ edits
)
+ exec_lua(function()
+ vim.lsp.util.apply_text_edits(edits1, 1, encoding or 'utf-16')
+ end)
end
-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
@@ -46,111 +72,156 @@ if skip(is_os('win')) then
return
end
-teardown(function()
- os.remove(fake_lsp_logfile)
-end)
-
describe('LSP', function()
before_each(function()
clear_notrace()
-
- -- Run an instance of nvim on the file which contains our "scripts".
- -- Pass TEST_NAME to pick the script.
- local test_name = 'basic_init'
- exec_lua(
- [=[
- lsp = require('vim.lsp')
- local test_name, fake_lsp_code, fake_lsp_logfile = ...
- function test__start_client()
- return lsp.start_client {
- cmd_env = {
- NVIM_LOG_FILE = fake_lsp_logfile;
- NVIM_APPNAME = "nvim_lsp_test";
- };
- cmd = {
- vim.v.progpath, '-l', fake_lsp_code, test_name;
- };
- workspace_folders = {{
- uri = 'file://' .. vim.uv.cwd(),
- name = 'test_folder',
- }};
- }
- end
- TEST_CLIENT1 = test__start_client()
- ]=],
- test_name,
- fake_lsp_code,
- fake_lsp_logfile
- )
end)
after_each(function()
+ stop()
+ exec_lua('lsp.stop_client(lsp.get_clients(), true)')
api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
- -- exec_lua("lsp.stop_all_clients(true)")
+ end)
+
+ teardown(function()
+ os.remove(fake_lsp_logfile)
end)
describe('server_name specified', function()
+ before_each(function()
+ -- Run an instance of nvim on the file which contains our "scripts".
+ -- Pass TEST_NAME to pick the script.
+ local test_name = 'basic_init'
+ exec_lua(function()
+ _G.lsp = require('vim.lsp')
+ function _G.test__start_client()
+ return vim.lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = fake_lsp_logfile,
+ NVIM_APPNAME = 'nvim_lsp_test',
+ },
+ cmd = {
+ vim.v.progpath,
+ '-l',
+ fake_lsp_code,
+ test_name,
+ },
+ workspace_folders = {
+ {
+ uri = 'file://' .. vim.uv.cwd(),
+ name = 'test_folder',
+ },
+ },
+ }
+ end
+ _G.TEST_CLIENT1 = _G.test__start_client()
+ end)
+ end)
+
it('start_client(), stop_client()', function()
retry(nil, 4000, function()
- eq(1, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 1,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
eq(
2,
- exec_lua([[
- TEST_CLIENT2 = test__start_client()
- return TEST_CLIENT2
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT2 = _G.test__start_client()
+ return _G.TEST_CLIENT2
+ end)
)
eq(
3,
- exec_lua([[
- TEST_CLIENT3 = test__start_client()
- return TEST_CLIENT3
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT3 = _G.test__start_client()
+ return _G.TEST_CLIENT3
+ end)
)
retry(nil, 4000, function()
- eq(3, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 3,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
- eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil'))
- eq(false, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).is_stopped()'))
- exec_lua('return lsp.get_client_by_id(TEST_CLIENT1).stop()')
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil
+ end)
+ )
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).is_stopped()
+ end)
+ )
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1).stop()
+ end)
retry(nil, 4000, function()
- eq(2, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 2,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
- eq(true, exec_lua('return lsp.get_client_by_id(TEST_CLIENT1) == nil'))
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.get_client_by_id(_G.TEST_CLIENT1) == nil
+ end)
+ )
- exec_lua('lsp.stop_client({TEST_CLIENT2, TEST_CLIENT3})')
+ exec_lua(function()
+ vim.lsp.stop_client({ _G.TEST_CLIENT2, _G.TEST_CLIENT3 })
+ end)
retry(nil, 4000, function()
- eq(0, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
end)
it('stop_client() also works on client objects', function()
- exec_lua([[
- TEST_CLIENT2 = test__start_client()
- TEST_CLIENT3 = test__start_client()
- ]])
+ exec_lua(function()
+ _G.TEST_CLIENT2 = _G.test__start_client()
+ _G.TEST_CLIENT3 = _G.test__start_client()
+ end)
retry(nil, 4000, function()
- eq(3, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 3,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
-- Stop all clients.
- exec_lua('lsp.stop_client(lsp.get_clients())')
+ exec_lua(function()
+ vim.lsp.stop_client(vim.lsp.get_clients())
+ end)
retry(nil, 4000, function()
- eq(0, exec_lua('return #lsp.get_clients()'))
+ eq(
+ 0,
+ exec_lua(function()
+ return #vim.lsp.get_clients()
+ end)
+ )
end)
end)
end)
-end)
-describe('LSP', function()
describe('basic_init test', function()
- after_each(function()
- stop()
- exec_lua('lsp.stop_client(lsp.get_clients(), true)')
- api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
- end)
-
it('should run correctly', function()
local expected_handlers = {
{ NIL, {}, { method = 'test', client_id = 1 } },
@@ -221,28 +292,28 @@ describe('LSP', function()
function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
- capabilities = {
- positionEncoding = "utf-8"
- },
- })
+ local result = exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ positionEncoding = 'utf-8',
+ },
+ })
- local client_id = vim.lsp.start({
- name = 'dummy',
- cmd = server.cmd,
- })
+ local client_id = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
- if not client_id then
- return 'vim.lsp.start did not return client_id'
- end
+ if not client_id then
+ return 'vim.lsp.start did not return client_id'
+ end
- local client = vim.lsp.get_client_by_id(client_id)
- if not client then
- return 'No client found with id ' .. client_id
- end
- return client.offset_encoding
- ]])
+ local client = vim.lsp.get_client_by_id(client_id)
+ if not client then
+ return 'No client found with id ' .. client_id
+ end
+ return client.offset_encoding
+ end)
eq('utf-8', result)
end
)
@@ -255,7 +326,7 @@ describe('LSP', function()
return
end
local expected_handlers = {
- { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 0 } },
{ NIL, {}, { method = 'test', client_id = 1 } },
}
test_rpc_server {
@@ -285,14 +356,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_finish',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- ]]
- eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)'))
- eq(true, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)'))
- exec_lua [[
- vim.api.nvim_command(BUFFER.."bwipeout")
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ end)
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
+ exec_lua(function()
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(_client)
client = _client
@@ -305,8 +386,15 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)')
- eq(false, exec_lua('return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)'))
+ exec_lua(function()
+ return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ eq(
+ false,
+ exec_lua(function()
+ return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
client.stop()
end
end,
@@ -318,31 +406,38 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- vim.g.lsp_attached = client.name
+ local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ vim.g.lsp_attached = client0.name
end,
})
vim.api.nvim_create_autocmd('LspDetach', {
callback = function(args)
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- vim.g.lsp_detached = client.name
+ local client0 = assert(vim.lsp.get_client_by_id(args.data.client_id))
+ vim.g.lsp_detached = client0.name
end,
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- eq(true, exec_lua('return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)'))
+ eq(
+ true,
+ exec_lua(function()
+ return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
+ )
client.notify('finish')
end,
on_handler = function(_, _, ctx)
if ctx.method == 'finish' then
eq('basic_init', api.nvim_get_var('lsp_attached'))
- exec_lua('return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)')
+ exec_lua(function()
+ return vim.lsp.buf_detach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
eq('basic_init', api.nvim_get_var('lsp_detached'))
client.stop()
end
@@ -356,10 +451,10 @@ describe('LSP', function()
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
@@ -369,13 +464,13 @@ describe('LSP', function()
eq('', get_buf_option('keywordprg'))
eq(
true,
- exec_lua [[
- local keymap
- vim.api.nvim_buf_call(BUFFER, function()
- keymap = vim.fn.maparg("K", "n", false, true)
+ exec_lua(function()
+ local keymap --- @type table<string,any>
+ vim._with({ buf = _G.BUFFER }, function()
+ keymap = vim.fn.maparg('K', 'n', false, true)
+ end)
+ return keymap.callback == vim.lsp.buf.hover
end)
- return keymap.callback == vim.lsp.buf.hover
- ]]
)
client.stop()
end
@@ -386,13 +481,13 @@ describe('LSP', function()
eq('', get_buf_option('formatexpr'))
eq(
'',
- exec_lua [[
- local keymap
- vim.api.nvim_buf_call(BUFFER, function()
- keymap = vim.fn.maparg("K", "n", false, false)
+ exec_lua(function()
+ local keymap --- @type string
+ vim._with({ buf = _G.BUFFER }, function()
+ keymap = vim.fn.maparg('K', 'n', false, false)
+ end)
+ return keymap
end)
- return keymap
- ]]
)
end,
}
@@ -400,40 +495,42 @@ describe('LSP', function()
it('should overwrite options set by ftplugins', function()
local client --- @type vim.lsp.Client
+ local BUFFER_1 --- @type integer
+ local BUFFER_2 --- @type integer
test_rpc_server {
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
+ exec_lua(function()
vim.api.nvim_command('filetype plugin on')
BUFFER_1 = vim.api.nvim_create_buf(false, true)
BUFFER_2 = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 })
vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 })
- ]]
+ end)
-- Sanity check to ensure that some values are set after setting filetype.
- eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', 'BUFFER_1'))
- eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('xmlformat#Format()', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq("v:lua.require'man'.goto_tag", get_buf_option('tagfunc', BUFFER_1))
+ eq('xmlcomplete#CompleteTags', get_buf_option('omnifunc', BUFFER_2))
+ eq('xmlformat#Format()', get_buf_option('formatexpr', BUFFER_2))
- exec_lua [[
- lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)
- lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ vim.lsp.buf_attach_client(BUFFER_1, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(BUFFER_2, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
- eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', 'BUFFER_1'))
- eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq('v:lua.vim.lsp.tagfunc', get_buf_option('tagfunc', BUFFER_1))
+ eq('v:lua.vim.lsp.omnifunc', get_buf_option('omnifunc', BUFFER_2))
+ eq('v:lua.vim.lsp.formatexpr()', get_buf_option('formatexpr', BUFFER_2))
client.stop()
end
end,
on_exit = function(_, _)
- eq('', get_buf_option('tagfunc', 'BUFFER_1'))
- eq('', get_buf_option('omnifunc', 'BUFFER_2'))
- eq('', get_buf_option('formatexpr', 'BUFFER_2'))
+ eq('', get_buf_option('tagfunc', BUFFER_1))
+ eq('', get_buf_option('omnifunc', BUFFER_2))
+ eq('', get_buf_option('formatexpr', BUFFER_2))
end,
}
end)
@@ -444,13 +541,13 @@ describe('LSP', function()
test_name = 'set_defaults_all_capabilities',
on_init = function(_client)
client = _client
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = BUFFER })
- vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = BUFFER })
- vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = BUFFER })
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- ]]
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = _G.BUFFER })
+ vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = _G.BUFFER })
+ vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = _G.BUFFER })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ end)
end,
on_handler = function(_, _, ctx)
if ctx.method == 'test' then
@@ -471,19 +568,19 @@ describe('LSP', function()
it('should detach buffer on bufwipe', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server()
+ local result = exec_lua(function()
+ local server = _G._create_server()
local bufnr = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_current_buf(bufnr)
local detach_called = false
- vim.api.nvim_create_autocmd("LspDetach", {
+ vim.api.nvim_create_autocmd('LspDetach', {
callback = function()
detach_called = true
- end
+ end,
})
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)
+ assert(client_id, 'lsp.start must return client_id')
+ local client = assert(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)
@@ -494,7 +591,7 @@ describe('LSP', function()
num_attached_after = num_attached_after,
detach_called = detach_called,
}
- ]])
+ end)
eq(true, result ~= nil, 'exec_lua must return result')
eq(1, result.num_attached_before)
eq(0, result.num_attached_after)
@@ -504,30 +601,62 @@ describe('LSP', function()
it('should not re-attach buffer if it was deleted in on_init #28575', function()
clear()
exec_lua(create_server_definition)
- exec_lua([[
- local server = _create_server({
+ exec_lua(function()
+ local server = _G._create_server({
handlers = {
- initialize = function(method, params, callback)
+ initialize = function(_, _, callback)
vim.schedule(function()
callback(nil, { capabilities = {} })
end)
- end
- }
+ end,
+ },
})
local bufnr = vim.api.nvim_create_buf(false, true)
local on_init_called = false
- local client_id = vim.lsp.start({
+ local client_id = assert(vim.lsp.start({
name = 'detach-dummy',
cmd = server.cmd,
on_init = function()
vim.api.nvim_buf_delete(bufnr, {})
on_init_called = true
- end
- })
+ end,
+ }))
vim.lsp.buf_attach_client(bufnr, client_id)
- local ok = vim.wait(1000, function() return on_init_called end)
- assert(ok, "on_init was not called")
- ]])
+ local ok = vim.wait(1000, function()
+ return on_init_called
+ end)
+ assert(ok, 'on_init was not called')
+ end)
+ end)
+
+ it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function()
+ clear()
+ exec_lua(create_server_definition)
+ exec_lua(function()
+ local initialized = false
+ local server = _G._create_server({
+ handlers = {
+ initialize = function(_, _, callback)
+ vim.schedule(function()
+ callback(nil, { capabilities = {} })
+ initialized = true
+ end)
+ end,
+ },
+ })
+ local bufnr = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.lsp.start({
+ name = 'detach-dummy',
+ cmd = server.cmd,
+ })
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'hello' })
+ vim.api.nvim_buf_delete(bufnr, {})
+ local ok = vim.wait(1000, function()
+ return initialized
+ end)
+ assert(ok, 'lsp did not initialize')
+ end)
end)
it('client should return settings via workspace/configuration handler', function()
@@ -560,19 +689,25 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID)
- client.settings = {
- testSetting1 = true;
- testSetting2 = false;
- test = {Setting3 = 'nested' };
- }]=])
+ exec_lua(function()
+ local client0 = vim.lsp.get_client_by_id(_G.TEST_RPC_CLIENT_ID)
+ client0.settings = {
+ testSetting1 = true,
+ testSetting2 = false,
+ test = { Setting3 = 'nested' },
+ }
+ end)
end
if ctx.method == 'workspace/configuration' then
local server_result = exec_lua(
- [=[
+ [[
local method, params = ...
- return require'vim.lsp.handlers'['workspace/configuration'](err, params, {method=method, client_id=TEST_RPC_CLIENT_ID})]=],
+ return require 'vim.lsp.handlers'['workspace/configuration'](
+ err,
+ params,
+ { method = method, client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ ]],
ctx.method,
result
)
@@ -584,6 +719,7 @@ describe('LSP', function()
end,
}
end)
+
it(
'workspace/configuration returns NIL per section if client was started without config.settings',
function()
@@ -594,15 +730,19 @@ describe('LSP', function()
c.stop()
end,
on_setup = function()
- result = exec_lua [[
- local result = {
- items = {
- {section = 'foo'},
- {section = 'bar'},
+ result = exec_lua(function()
+ local result0 = {
+ items = {
+ { section = 'foo' },
+ { section = 'bar' },
+ },
}
- }
- return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
- ]]
+ return vim.lsp.handlers['workspace/configuration'](
+ nil,
+ result0,
+ { client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ end)
end,
}
eq({ NIL, NIL }, result)
@@ -617,7 +757,9 @@ describe('LSP', function()
test_name = 'basic_check_capabilities',
on_init = function(client)
client.stop()
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq({ includeText = false }, client.server_capabilities().textDocumentSync.save)
eq(false, client.server_capabilities().codeLensProvider)
@@ -650,11 +792,11 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
+ end)
else
client.stop()
end
@@ -665,21 +807,21 @@ describe('LSP', function()
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({
+ local messages = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
textDocumentSync = {
willSave = false,
willSaveWaitUntil = false,
- }
+ },
},
})
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(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
- ]])
+ end)
eq(4, #messages)
eq('initialize', messages[1].method)
eq('initialized', messages[2].method)
@@ -690,13 +832,13 @@ describe('LSP', function()
it('BufWritePre sends willSave / willSaveWaitUntil, applies textEdits', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
+ local result = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
textDocumentSync = {
willSave = true,
willSaveWaitUntil = true,
- }
+ },
},
handlers = {
['textDocument/willSaveWaitUntil'] = function(_, _, callback)
@@ -705,21 +847,21 @@ describe('LSP', function()
start = { line = 0, character = 0 },
['end'] = { line = 0, character = 0 },
},
- newText = 'Hello'
+ newText = 'Hello',
}
- callback(nil, { text_edit, })
- end
+ callback(nil, { text_edit })
+ end,
},
})
local buf = vim.api.nvim_get_current_buf()
- local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
+ local client_id = assert(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)
+ lines = vim.api.nvim_buf_get_lines(buf, 0, -1, true),
}
- ]])
+ end)
local messages = result.messages
eq('textDocument/willSave', messages[3].method)
eq('textDocument/willSaveWaitUntil', messages[4].method)
@@ -745,20 +887,16 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
local tmpfile_old = tmpname()
- local tmpfile_new = tmpname()
- os.remove(tmpfile_new)
- exec_lua(
- [=[
- local oldname, newname = ...
- BUFFER = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_name(BUFFER, oldname)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_buf_call(BUFFER, function() vim.cmd('saveas ' .. newname) end)
- ]=],
- tmpfile_old,
- tmpfile_new
- )
+ local tmpfile_new = tmpname(false)
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_name(_G.BUFFER, tmpfile_old)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim._with({ buf = _G.BUFFER }, function()
+ vim.cmd('saveas ' .. tmpfile_new)
+ end)
+ end)
else
client.stop()
end
@@ -784,12 +922,12 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, true, { 'help me' })
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
+ end)
else
client.stop()
end
@@ -843,16 +981,18 @@ describe('LSP', function()
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_setup = function()
- exec_lua([=[
- BUFFER = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.lsp.handlers['textDocument/typeDefinition'] = function() end
- vim.cmd(BUFFER.."bwipeout")
- ]=])
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function() end
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(client)
client.stop()
- exec_lua('vim.lsp.buf.type_definition()')
+ exec_lua(function()
+ vim.lsp.buf.type_definition()
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -873,13 +1013,15 @@ describe('LSP', function()
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_setup = function()
- exec_lua([=[
+ exec_lua(function()
vim.lsp.handlers['textDocument/typeDefinition'] = function() end
- ]=])
+ end)
end,
on_init = function(client)
client.stop()
- exec_lua('vim.lsp.buf.type_definition()')
+ exec_lua(function()
+ vim.lsp.buf.type_definition()
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -920,7 +1062,11 @@ describe('LSP', function()
it('should forward ContentModified to callback', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } },
+ {
+ { code = -32801 },
+ NIL,
+ { method = 'error_code_test', bufnr = 1, client_id = 1, version = 0 },
+ },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -950,7 +1096,7 @@ describe('LSP', function()
it('should track pending requests to the language server', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -958,7 +1104,9 @@ describe('LSP', function()
on_init = function(_client)
client = _client
client.request('slow_request')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('pending', request.type)
client.notify('release')
@@ -971,8 +1119,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
client.notify('finish')
end
if ctx.method == 'finish' then
@@ -993,7 +1143,9 @@ describe('LSP', function()
client = _client
client.request('slow_request')
client.cancel_request(2)
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('cancel', request.type)
client.notify('release')
@@ -1005,8 +1157,10 @@ describe('LSP', function()
end,
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
if ctx.method == 'finish' then
client.stop()
end
@@ -1017,7 +1171,7 @@ describe('LSP', function()
it('should clear pending and cancel requests on reply', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1025,11 +1179,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
client.request('slow_request')
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('pending', request.type)
client.cancel_request(2)
- request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
+ request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
eq('slow_request', request.method)
eq('cancel', request.type)
client.notify('release')
@@ -1042,8 +1200,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- local request = exec_lua([=[ return TEST_RPC_CLIENT.requests[2] ]=])
- eq(NIL, request)
+ local request = exec_lua(function()
+ return _G.TEST_RPC_CLIENT.requests[2]
+ end)
+ eq(nil, request)
client.notify('finish')
end
if ctx.method == 'finish' then
@@ -1056,7 +1216,7 @@ describe('LSP', function()
it('should trigger LspRequest autocmd when requests table changes', function()
local expected_handlers = {
{ NIL, {}, { method = 'finish', client_id = 1 } },
- { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } },
+ { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 0 } },
}
local client --- @type vim.lsp.Client
test_rpc_server {
@@ -1098,21 +1258,23 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_finish',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- assert(TEST_RPC_CLIENT_ID == 1)
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- assert(lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID))
- vim.cmd(BUFFER.."bwipeout")
- ]]
+ assert(_G.TEST_RPC_CLIENT_ID == 1)
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ assert(vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ vim.cmd(_G.BUFFER .. 'bwipeout')
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
client.notify('finish')
@@ -1140,25 +1302,30 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ end)
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Already attached, returns true")
- ]]
+ exec_lua(function()
+ assert(
+ vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID),
+ 'Already attached, returns true'
+ )
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1186,22 +1353,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1229,22 +1398,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1252,11 +1423,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1277,23 +1448,25 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_noeol',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- vim.bo[BUFFER].eol = false
- ]]
+ vim.bo[_G.BUFFER].eol = false
+ end)
end,
on_init = function(_client)
client = _client
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local full_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1301,11 +1474,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1336,6 +1509,7 @@ describe('LSP', function()
},
bufnr = 2,
client_id = 1,
+ version = 0,
},
},
{ NIL, {}, { method = 'start', client_id = 1 } },
@@ -1344,21 +1518,21 @@ describe('LSP', function()
test_rpc_server {
test_name = 'inlay_hint',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- vim.bo[BUFFER].eol = false
- ]]
+ vim.bo[_G.BUFFER].eol = false
+ end)
end,
on_init = function(_client)
client = _client
eq(true, client.supports_method('textDocument/inlayHint'))
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1366,9 +1540,9 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.lsp.inlay_hint.enable(true, { bufnr = BUFFER })
- ]]
+ exec_lua(function()
+ vim.lsp.inlay_hint.enable(true, { bufnr = _G.BUFFER })
+ end)
end
if ctx.method == 'textDocument/inlayHint' then
client.notify('finish')
@@ -1394,23 +1568,24 @@ describe('LSP', function()
allow_incremental_sync = true,
},
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1418,11 +1593,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "123boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '123boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1432,6 +1607,7 @@ describe('LSP', function()
end,
}
end)
+
it('should check the body and didChange incremental with debounce', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -1446,23 +1622,24 @@ describe('LSP', function()
debounce_text_changes = 5,
},
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1470,11 +1647,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "123boop";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '123boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1496,23 +1673,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_incremental_editing',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind =
- exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Incremental
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1541,22 +1719,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_multi',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1564,14 +1744,14 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "321";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '321',
})
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- ]]
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1592,22 +1772,24 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_buffer_open_and_change_multi_and_close',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
+ local sync_kind = exec_lua(function()
+ return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
+ end)
eq(sync_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1615,15 +1797,15 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- exec_lua [[
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "321";
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ '321',
})
- vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
- "boop";
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 1, 2, false, {
+ 'boop',
})
- vim.api.nvim_command(BUFFER.."bwipeout")
- ]]
+ vim.api.nvim_command(_G.BUFFER .. 'bwipeout')
+ end)
client.notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
@@ -1679,19 +1861,19 @@ describe('LSP', function()
test_rpc_server {
test_name = 'decode_nil',
on_setup = function()
- exec_lua [[
- BUFFER = vim.api.nvim_create_buf(false, true)
- vim.api.nvim_buf_set_lines(BUFFER, 0, -1, false, {
- "testing";
- "123";
+ exec_lua(function()
+ _G.BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(_G.BUFFER, 0, -1, false, {
+ 'testing',
+ '123',
})
- ]]
+ end)
end,
on_init = function(_client)
client = _client
- exec_lua [[
- assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
- ]]
+ exec_lua(function()
+ assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1706,22 +1888,58 @@ describe('LSP', function()
}
end)
end)
-end)
-describe('LSP', function()
- before_each(function()
- clear_notrace()
- end)
+ describe('apply vscode text_edits', function()
+ it('single replace', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 6, { 'Hello' } },
+ })
+ eq({ '012Hello678901234567890123456789' }, buf_lines(1))
+ end)
- local function make_edit(y_0, x_0, y_1, x_1, text)
- return {
- range = {
- start = { line = y_0, character = x_0 },
- ['end'] = { line = y_1, character = x_1 },
- },
- newText = type(text) == 'table' and table.concat(text, '\n') or (text or ''),
- }
- end
+ it('two replaces', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 6, { 'Hello' } },
+ { 0, 6, 0, 9, { 'World' } },
+ })
+ eq({ '012HelloWorld901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('same start pos insert are kept in order', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 3, { 'World' } },
+ { 0, 3, 0, 3, { 'Hello' } },
+ })
+ eq({ '012WorldHello345678901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('same start pos insert and replace are kept in order', function()
+ insert('012345678901234567890123456789')
+ apply_text_edits({
+ { 0, 3, 0, 3, { 'World' } },
+ { 0, 3, 0, 3, { 'Hello' } },
+ { 0, 3, 0, 8, { 'No' } },
+ })
+ eq({ '012WorldHelloNo8901234567890123456789' }, buf_lines(1))
+ end)
+
+ it('multiline', function()
+ exec_lua(function()
+ vim.api.nvim_buf_set_lines(1, 0, 0, true, { ' {', ' "foo": "bar"', ' }' })
+ end)
+ eq({ ' {', ' "foo": "bar"', ' }', '' }, buf_lines(1))
+ apply_text_edits({
+ { 0, 0, 3, 0, { '' } },
+ { 3, 0, 3, 0, { '{\n' } },
+ { 3, 0, 3, 0, { ' "foo": "bar"\n' } },
+ { 3, 0, 3, 0, { '}\n' } },
+ })
+ eq({ '{', ' "foo": "bar"', '}', '' }, buf_lines(1))
+ end)
+ end)
describe('apply_text_edits', function()
before_each(function()
@@ -1732,14 +1950,14 @@ describe('LSP', function()
Fourth line of text
å å ɧ 汉语 ↥ 🤦 🦄]]))
end)
+
it('applies simple edits', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '123' }),
- make_edit(1, 0, 1, 1, { '2' }),
- make_edit(2, 0, 2, 2, { '3' }),
- make_edit(3, 2, 3, 4, { '' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '123' } },
+ { 1, 0, 1, 1, { '2' } },
+ { 2, 0, 2, 2, { '3' } },
+ { 3, 2, 3, 4, { '' } },
+ })
eq({
'123First line of text',
'2econd line of text',
@@ -1748,18 +1966,18 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies complex edits', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '', '12' }),
- make_edit(0, 0, 0, 0, { '3', 'foo' }),
- make_edit(0, 1, 0, 1, { 'bar', '123' }),
- make_edit(0, #'First ', 0, #'First line of text', { 'guy' }),
- make_edit(1, 0, 1, #'Second', { 'baz' }),
- make_edit(2, #'Th', 2, #'Third', { 'e next' }),
- make_edit(3, #'', 3, #'Fourth', { 'another line of text', 'before this' }),
- make_edit(3, #'Fourth', 3, #'Fourth line of text', { '!' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '', '12' } },
+ { 0, 0, 0, 0, { '3', 'foo' } },
+ { 0, 1, 0, 1, { 'bar', '123' } },
+ { 0, #'First ', 0, #'First line of text', { 'guy' } },
+ { 1, 0, 1, #'Second', { 'baz' } },
+ { 2, #'Th', 2, #'Third', { 'e next' } },
+ { 3, #'', 3, #'Fourth', { 'another line of text', 'before this' } },
+ { 3, #'Fourth', 3, #'Fourth line of text', { '!' } },
+ })
eq({
'',
'123',
@@ -1772,18 +1990,18 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies complex edits (reversed range)', function()
- local edits = {
- make_edit(0, 0, 0, 0, { '', '12' }),
- make_edit(0, 0, 0, 0, { '3', 'foo' }),
- make_edit(0, 1, 0, 1, { 'bar', '123' }),
- make_edit(0, #'First line of text', 0, #'First ', { 'guy' }),
- make_edit(1, #'Second', 1, 0, { 'baz' }),
- make_edit(2, #'Third', 2, #'Th', { 'e next' }),
- make_edit(3, #'Fourth', 3, #'', { 'another line of text', 'before this' }),
- make_edit(3, #'Fourth line of text', 3, #'Fourth', { '!' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 0, 0, { '', '12' } },
+ { 0, 0, 0, 0, { '3', 'foo' } },
+ { 0, 1, 0, 1, { 'bar', '123' } },
+ { 0, #'First line of text', 0, #'First ', { 'guy' } },
+ { 1, #'Second', 1, 0, { 'baz' } },
+ { 2, #'Third', 2, #'Th', { 'e next' } },
+ { 3, #'Fourth', 3, #'', { 'another line of text', 'before this' } },
+ { 3, #'Fourth line of text', 3, #'Fourth', { '!' } },
+ })
eq({
'',
'123',
@@ -1796,11 +2014,11 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies non-ASCII characters edits', function()
- local edits = {
- make_edit(4, 3, 4, 4, { 'ä' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 4, 3, 4, 4, { 'ä' } },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1809,11 +2027,11 @@ describe('LSP', function()
'å ä ɧ 汉语 ↥ 🤦 🦄',
}, buf_lines(1))
end)
+
it('applies text edits at the end of the document', function()
- local edits = {
- make_edit(5, 0, 5, 0, 'foobar'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 5, 0, 5, 0, 'foobar' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1823,12 +2041,12 @@ describe('LSP', function()
'foobar',
}, buf_lines(1))
end)
+
it('applies multiple text edits at the end of the document', function()
- local edits = {
- make_edit(4, 0, 5, 0, ''),
- make_edit(5, 0, 5, 0, 'foobar'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 4, 0, 5, 0, '' },
+ { 5, 0, 5, 0, 'foobar' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1837,62 +2055,56 @@ describe('LSP', function()
'foobar',
}, buf_lines(1))
end)
+
it('it restores marks', function()
- local edits = {
- make_edit(1, 0, 2, 5, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 5, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobar line of text',
'Fourth line of text',
'barfoo',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 1 }, mark)
+ eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a'))
end)
it('it restores marks to last valid col', function()
- local edits = {
- make_edit(1, 0, 2, 15, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 2, 10, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 15, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobarext',
'Fourth line of text',
'barfoo',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 9 }, mark)
+ eq({ 2, 9 }, api.nvim_buf_get_mark(1, 'a'))
end)
it('it restores marks to last valid line', function()
- local edits = {
- make_edit(1, 0, 4, 5, 'foobar'),
- make_edit(4, 0, 5, 0, 'barfoo'),
- }
eq(true, api.nvim_buf_set_mark(1, 'a', 4, 1, {}))
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 4, 5, 'foobar' },
+ { 4, 0, 5, 0, 'barfoo' },
+ })
eq({
'First line of text',
'foobaro',
}, buf_lines(1))
- local mark = api.nvim_buf_get_mark(1, 'a')
- eq({ 2, 1 }, mark)
+ eq({ 2, 1 }, api.nvim_buf_get_mark(1, 'a'))
end)
describe('cursor position', function()
it("don't fix the cursor if the range contains the cursor", function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 19, 'Second line of text'),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 19, 'Second line of text' },
+ })
eq({
'First line of text',
'Second line of text',
@@ -1905,11 +2117,10 @@ describe('LSP', function()
it('fix the cursor to the valid col if the content was removed', function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 6, ''),
- make_edit(1, 6, 1, 19, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 6, '' },
+ { 1, 6, 1, 19, '' },
+ })
eq({
'First line of text',
'',
@@ -1922,11 +2133,10 @@ describe('LSP', function()
it('fix the cursor to the valid row if the content was removed', function()
api.nvim_win_set_cursor(0, { 2, 6 })
- local edits = {
- make_edit(1, 0, 1, 6, ''),
- make_edit(0, 18, 5, 0, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 1, 6, '' },
+ { 0, 18, 5, 0, '' },
+ })
eq({
'First line of text',
}, buf_lines(1))
@@ -1935,10 +2145,9 @@ describe('LSP', function()
it('fix the cursor row', function()
api.nvim_win_set_cursor(0, { 3, 0 })
- local edits = {
- make_edit(1, 0, 2, 0, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 0, 2, 0, '' },
+ })
eq({
'First line of text',
'Third line of text',
@@ -1953,10 +2162,9 @@ describe('LSP', function()
api.nvim_buf_set_lines(1, -1, -1, true, { '' })
api.nvim_win_set_cursor(0, { 2, 11 })
- local edits = {
- make_edit(1, 7, 1, 11, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 1, 7, 1, 11, '' },
+ })
eq({
'First line of text',
'Second of text',
@@ -1970,10 +2178,9 @@ describe('LSP', function()
it('fix the cursor row and col', function()
api.nvim_win_set_cursor(0, { 2, 12 })
- local edits = {
- make_edit(0, 11, 1, 12, ''),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 11, 1, 12, '' },
+ })
eq({
'First line of text',
'Third line of text',
@@ -1986,24 +2193,23 @@ describe('LSP', function()
describe('with LSP end line after what Vim considers to be the end line', function()
it('applies edits when the last linebreak is considered a new line', function()
- local edits = {
- make_edit(0, 0, 5, 0, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 5, 0, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
+
it("applies edits when the end line is 2 larger than vim's", function()
- local edits = {
- make_edit(0, 0, 6, 0, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 6, 0, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
+
it('applies edits with a column offset', function()
- local edits = {
- make_edit(0, 0, 5, 2, { 'All replaced' }),
- }
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, 'utf-16')
+ apply_text_edits({
+ { 0, 0, 5, 2, { 'All replaced' } },
+ })
eq({ 'All replaced' }, buf_lines(1))
end)
end)
@@ -2015,38 +2221,38 @@ describe('LSP', function()
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')
+ apply_text_edits({
+ { 0, 0, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, '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')
+ apply_text_edits({
+ { 0, 0, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, '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')
+ apply_text_edits({
+ { 0, 2, 1, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, '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')
+ apply_text_edits({
+ { 0, 2, 0, 22, { '#include "whatever.h"\r\n#include <algorithm>\r' } },
+ }, 'utf-8')
eq(
{ 'Te#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char' },
buf_lines(1)
@@ -2057,6 +2263,7 @@ describe('LSP', function()
describe('apply_text_document_edit', function()
local target_bufnr --- @type integer
+
local text_document_edit = function(editVersion)
return {
edits = {
@@ -2068,50 +2275,43 @@ describe('LSP', function()
},
}
end
+
before_each(function()
- target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "2nd line of 语text"}
+ target_bufnr = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { '1st line of text', '2nd line of 语text' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
- ]]
+ end)
end)
+
it('correctly goes ahead with the edit if all is normal', function()
- exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5))
+ exec_lua(function(text_edit)
+ vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
+ end, text_document_edit(5))
eq({
'First ↥ 🤦 🦄 line of text',
'2nd line of 语text',
}, buf_lines(target_bufnr))
end)
+
it('always accepts edit with version = 0', function()
- exec_lua(
- [[
- local args = {...}
- local bufnr = select(1, ...)
- local text_edit = select(2, ...)
- vim.lsp.util.buf_versions[bufnr] = 10
+ exec_lua(function(text_edit)
+ vim.lsp.util.buf_versions[target_bufnr] = 10
vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
- ]],
- target_bufnr,
- text_document_edit(0)
- )
+ end, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text',
'2nd line of 语text',
}, buf_lines(target_bufnr))
end)
+
it('skips the edit if the version of the edit is behind the local buffer ', function()
local apply_edit_mocking_current_version = function(edit, versionedBuf)
- exec_lua(
- [[
- local args = {...}
- local versionedBuf = args[2]
+ exec_lua(function()
vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
- vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
- ]],
- edit,
- versionedBuf
- )
+ vim.lsp.util.apply_text_document_edit(edit, nil, 'utf-16')
+ end)
end
local baseText = {
@@ -2164,13 +2364,17 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local apply_edit = {
- label = nil;
- edit = {};
- }
- return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID})
- ]]
+ exec_lua(function()
+ local apply_edit = {
+ label = nil,
+ edit = {},
+ }
+ return vim.lsp.handlers['workspace/applyEdit'](
+ nil,
+ apply_edit,
+ { client_id = _G.TEST_RPC_CLIENT_ID }
+ )
+ end)
)
eq(table.remove(expected_handlers), { ... })
end,
@@ -2200,34 +2404,30 @@ describe('LSP', function()
}
end
- local target_bufnr, changedtick = nil, nil
+ local target_bufnr --- @type integer
+ local changedtick --- @type integer
before_each(function()
- local ret = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ exec_lua(function()
+ target_bufnr = vim.uri_to_bufnr('file:///fake/uri')
local lines = {
- "Original Line #1",
- "Original Line #2"
+ 'Original Line #1',
+ 'Original Line #2',
}
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
+ vim.api.nvim_buf_set_lines(target_bufnr, 0, -1, false, lines)
- local update_changed_tick = function()
- vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick')
+ local function update_changed_tick()
+ vim.lsp.util.buf_versions[target_bufnr] = vim.b[target_bufnr].changedtick
end
update_changed_tick()
- vim.api.nvim_buf_attach(bufnr, false, {
- on_changedtick = function()
- update_changed_tick()
- end
+ vim.api.nvim_buf_attach(target_bufnr, false, {
+ on_changedtick = update_changed_tick,
})
- return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')}
- ]]
-
- target_bufnr = ret[1]
- changedtick = ret[2]
+ changedtick = vim.b[target_bufnr].changedtick
+ end)
end)
it('apply_workspace_edit applies a single edit', function()
@@ -2245,19 +2445,11 @@ describe('LSP', function()
'First Line',
'Original Line #2',
},
- exec_lua(
- [[
- local args = {...}
- local workspace_edits = args[1]
- local target_bufnr = args[2]
-
- vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
+ exec_lua(function(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
- return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
- ]],
- make_workspace_edit(edits),
- target_bufnr
- )
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ end, make_workspace_edit(edits))
)
end)
@@ -2274,24 +2466,15 @@ describe('LSP', function()
eq(
new_lines,
- exec_lua(
- [[
- local args = {...}
- local workspace_edits = args[1]
- local target_bufnr = args[2]
-
- vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
-
- return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
- ]],
- make_workspace_edit(edits),
- target_bufnr
- )
+ exec_lua(function(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
+ return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
+ end, make_workspace_edit(edits))
)
end)
+
it('Supports file creation with CreateFile payload', function()
- local tmpfile = tmpname()
- os.remove(tmpfile) -- Should not exist, only interested in a tmpname
+ local tmpfile = tmpname(false)
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2301,15 +2484,16 @@ describe('LSP', function()
},
},
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ exec_lua(function()
+ vim.lsp.util.apply_workspace_edit(edit, 'utf-16')
+ end)
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
end)
+
it(
'Supports file creation in folder that needs to be created with CreateFile payload',
function()
- local tmpfile = tmpname()
- os.remove(tmpfile) -- Should not exist, only interested in a tmpname
- tmpfile = tmpfile .. '/dummy/x/'
+ local tmpfile = tmpname(false) .. '/dummy/x/'
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2319,10 +2503,13 @@ describe('LSP', function()
},
},
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
+ exec_lua(function()
+ vim.lsp.util.apply_workspace_edit(edit, 'utf-16')
+ end)
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
end
)
+
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2342,6 +2529,7 @@ describe('LSP', function()
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
eq('Dummy content', read_file(tmpfile))
end)
+
it('createFile overrides file if overwrite is set', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Dummy content')
@@ -2362,18 +2550,15 @@ describe('LSP', function()
eq(true, vim.uv.fs_stat(tmpfile) ~= nil)
eq('', read_file(tmpfile))
end)
+
it('DeleteFile delete file and buffer', function()
local tmpfile = tmpname()
write_file(tmpfile, 'Be gone')
- local uri = exec_lua(
- [[
- local fname = select(1, ...)
- local bufnr = vim.fn.bufadd(fname)
+ local uri = exec_lua(function()
+ local bufnr = vim.fn.bufadd(tmpfile)
vim.fn.bufload(bufnr)
- return vim.uri_from_fname(fname)
- ]],
- tmpfile
- )
+ return vim.uri_from_fname(tmpfile)
+ end)
local edit = {
documentChanges = {
{
@@ -2386,9 +2571,9 @@ describe('LSP', function()
eq(false, vim.uv.fs_stat(tmpfile) ~= nil)
eq(false, api.nvim_buf_is_loaded(fn.bufadd(tmpfile)))
end)
+
it('DeleteFile fails if file does not exist and ignoreIfNotExists is false', function()
- local tmpfile = tmpname()
- os.remove(tmpfile)
+ local tmpfile = tmpname(false)
local uri = exec_lua('return vim.uri_from_fname(...)', tmpfile)
local edit = {
documentChanges = {
@@ -2412,12 +2597,8 @@ describe('LSP', function()
it('Can rename an existing file', function()
local old = tmpname()
write_file(old, 'Test content')
- local new = tmpname()
- os.remove(new) -- only reserve the name, file must not exist for the test scenario
- local lines = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local new = tmpname(false)
+ local lines = exec_lua(function()
local old_bufnr = vim.fn.bufadd(old)
vim.fn.bufload(old_bufnr)
vim.lsp.util.rename(old, new)
@@ -2425,10 +2606,7 @@ describe('LSP', function()
local new_bufnr = vim.fn.bufadd(new)
vim.fn.bufload(new_bufnr)
return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true)
- ]],
- old,
- new
- )
+ end)
eq({ 'Test content' }, lines)
local exists = vim.uv.fs_stat(old) ~= nil
eq(false, exists)
@@ -2436,24 +2614,18 @@ describe('LSP', function()
eq(true, exists)
os.remove(new)
end)
+
it('Can rename a directory', function()
-- only reserve the name, file must not exist for the test scenario
- local old_dir = tmpname()
- local new_dir = tmpname()
- os.remove(old_dir)
- os.remove(new_dir)
+ local old_dir = tmpname(false)
+ local new_dir = tmpname(false)
n.mkdir_p(old_dir)
local file = 'file.txt'
write_file(old_dir .. pathsep .. file, 'Test content')
- local lines = exec_lua(
- [[
- local old_dir = select(1, ...)
- local new_dir = select(2, ...)
- local pathsep = select(3, ...)
- local file = select(4, ...)
+ local lines = exec_lua(function()
local old_bufnr = vim.fn.bufadd(old_dir .. pathsep .. file)
vim.fn.bufload(old_bufnr)
vim.lsp.util.rename(old_dir, new_dir)
@@ -2461,12 +2633,7 @@ describe('LSP', function()
local new_bufnr = vim.fn.bufadd(new_dir .. pathsep .. file)
vim.fn.bufload(new_bufnr)
return (old_bufnr == new_bufnr) and vim.api.nvim_buf_get_lines(new_bufnr, 0, -1, true)
- ]],
- old_dir,
- new_dir,
- pathsep,
- file
- )
+ end)
eq({ 'Test content' }, lines)
eq(false, vim.uv.fs_stat(old_dir) ~= nil)
eq(true, vim.uv.fs_stat(new_dir) ~= nil)
@@ -2474,47 +2641,41 @@ describe('LSP', function()
os.remove(new_dir)
end)
+
it('Does not touch buffers that do not match path prefix', function()
- local old = tmpname()
- local new = tmpname()
- os.remove(old)
- os.remove(new)
+ local old = tmpname(false)
+ local new = tmpname(false)
n.mkdir_p(old)
- local result = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- local old_prefixed = 'explorer://' .. old
- local old_suffixed = old .. '.bak'
- local new_prefixed = 'explorer://' .. new
- local new_suffixed = new .. '.bak'
+ eq(
+ true,
+ exec_lua(function()
+ local old_prefixed = 'explorer://' .. old
+ local old_suffixed = old .. '.bak'
+ local new_prefixed = 'explorer://' .. new
+ local new_suffixed = new .. '.bak'
- local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
- local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
- local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
- local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
+ local old_prefixed_buf = vim.fn.bufadd(old_prefixed)
+ local old_suffixed_buf = vim.fn.bufadd(old_suffixed)
+ local new_prefixed_buf = vim.fn.bufadd(new_prefixed)
+ local new_suffixed_buf = vim.fn.bufadd(new_suffixed)
- vim.lsp.util.rename(old, new)
+ vim.lsp.util.rename(old, new)
- return
- vim.api.nvim_buf_is_valid(old_prefixed_buf) and
- vim.api.nvim_buf_is_valid(old_suffixed_buf) and
- vim.api.nvim_buf_is_valid(new_prefixed_buf) and
- vim.api.nvim_buf_is_valid(new_suffixed_buf) and
- vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed and
- vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed and
- vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed and
- vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
- ]],
- old,
- new
+ return vim.api.nvim_buf_is_valid(old_prefixed_buf)
+ and vim.api.nvim_buf_is_valid(old_suffixed_buf)
+ and vim.api.nvim_buf_is_valid(new_prefixed_buf)
+ and vim.api.nvim_buf_is_valid(new_suffixed_buf)
+ and vim.api.nvim_buf_get_name(old_prefixed_buf) == old_prefixed
+ and vim.api.nvim_buf_get_name(old_suffixed_buf) == old_suffixed
+ and vim.api.nvim_buf_get_name(new_prefixed_buf) == new_prefixed
+ and vim.api.nvim_buf_get_name(new_suffixed_buf) == new_suffixed
+ end)
)
- eq(true, result)
os.remove(new)
end)
+
it(
'Does not rename file if target exists and ignoreIfExists is set or overwrite is false',
function()
@@ -2523,45 +2684,28 @@ describe('LSP', function()
local new = tmpname()
write_file(new, 'New file')
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- vim.lsp.util.rename(old, new, { ignoreIfExists = true })
- ]],
- old,
- new
- )
+ exec_lua(function()
+ vim.lsp.util.rename(old, new, { ignoreIfExists = true })
+ end)
eq(true, vim.uv.fs_stat(old) ~= nil)
eq('New file', read_file(new))
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
- vim.lsp.util.rename(old, new, { overwrite = false })
- ]],
- old,
- new
- )
+ exec_lua(function()
+ vim.lsp.util.rename(old, new, { overwrite = false })
+ end)
eq(true, vim.uv.fs_stat(old) ~= nil)
eq('New file', read_file(new))
end
)
+
it('Maintains undo information for loaded buffer', function()
local old = tmpname()
write_file(old, 'line')
- local new = tmpname()
- os.remove(new)
+ local new = tmpname(false)
- local undo_kept = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local undo_kept = exec_lua(function()
vim.opt.undofile = true
vim.cmd.edit(old)
vim.cmd.normal('dd')
@@ -2574,24 +2718,18 @@ describe('LSP', function()
undotree.save_last = undotree.save_last + 1
undotree.entries[1].save = undotree.entries[1].save + 1
return vim.deep_equal(undotree, vim.fn.undotree())
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
eq(true, undo_kept)
end)
+
it('Maintains undo information for unloaded buffer', function()
local old = tmpname()
write_file(old, 'line')
- local new = tmpname()
- os.remove(new)
+ local new = tmpname(false)
- local undo_kept = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
+ local undo_kept = exec_lua(function()
vim.opt.undofile = true
vim.cmd.split(old)
vim.cmd.normal('dd')
@@ -2601,54 +2739,39 @@ describe('LSP', function()
vim.lsp.util.rename(old, new)
vim.cmd.edit(new)
return vim.deep_equal(undotree, vim.fn.undotree())
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
eq(true, undo_kept)
end)
+
it('Does not rename file when it conflicts with a buffer without file', function()
local old = tmpname()
write_file(old, 'Old File')
- local new = tmpname()
- os.remove(new)
-
- local lines = exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
- local old_buf = vim.fn.bufadd(old)
- vim.fn.bufload(old_buf)
- local conflict_buf = vim.api.nvim_create_buf(true, false)
- vim.api.nvim_buf_set_name(conflict_buf, new)
- vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, {'conflict'})
- vim.api.nvim_win_set_buf(0, conflict_buf)
- vim.lsp.util.rename(old, new)
- return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true)
- ]],
- old,
- new
- )
+ local new = tmpname(false)
+
+ local lines = exec_lua(function()
+ local old_buf = vim.fn.bufadd(old)
+ vim.fn.bufload(old_buf)
+ local conflict_buf = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_buf_set_name(conflict_buf, new)
+ vim.api.nvim_buf_set_lines(conflict_buf, 0, -1, true, { 'conflict' })
+ vim.api.nvim_win_set_buf(0, conflict_buf)
+ vim.lsp.util.rename(old, new)
+ return vim.api.nvim_buf_get_lines(conflict_buf, 0, -1, true)
+ end)
eq({ 'conflict' }, lines)
eq('Old File', read_file(old))
end)
+
it('Does override target if overwrite is true', function()
local old = tmpname()
write_file(old, 'Old file')
local new = tmpname()
write_file(new, 'New file')
- exec_lua(
- [[
- local old = select(1, ...)
- local new = select(2, ...)
-
+ exec_lua(function()
vim.lsp.util.rename(old, new, { overwrite = true })
- ]],
- old,
- new
- )
+ end)
eq(false, vim.uv.fs_stat(old) ~= nil)
eq(true, vim.uv.fs_stat(new) ~= nil)
@@ -2658,44 +2781,59 @@ describe('LSP', function()
describe('lsp.util.locations_to_items', function()
it('Convert Location[] to items', function()
- local expected = {
+ local expected_template = {
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 2,
col = 3,
+ end_col = 4,
text = 'testing',
- user_data = {
+ user_data = {},
+ },
+ }
+ local test_params = {
+ {
+ {
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
+ ['end'] = { line = 1, character = 3 },
},
},
},
- }
- local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"testing", "123"}
- vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
- local locations = {
+ {
{
uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
- ['end'] = { line = 0, character = 3 },
- }
+ -- LSP spec: if character > line length, default to the line length.
+ ['end'] = { line = 1, character = 10000 },
+ },
},
- }
- return vim.lsp.util.locations_to_items(locations, 'utf-16')
- ]]
- eq(expected, actual)
+ },
+ }
+ for _, params in ipairs(test_params) do
+ local actual = exec_lua(function(params0)
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { 'testing', '123' }
+ vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
+ return vim.lsp.util.locations_to_items(params0, 'utf-16')
+ end, params)
+ local expected = vim.deepcopy(expected_template)
+ expected[1].user_data = params[1]
+ eq(expected, actual)
+ end
end)
+
it('Convert LocationLink[] to items', function()
local expected = {
{
filename = '/fake/uri',
lnum = 1,
+ end_lnum = 1,
col = 3,
+ end_col = 4,
text = 'testing',
user_data = {
targetUri = 'file:///fake/uri',
@@ -2710,9 +2848,9 @@ describe('LSP', function()
},
},
}
- local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"testing", "123"}
+ local actual = exec_lua(function()
+ local bufnr = vim.uri_to_bufnr('file:///fake/uri')
+ local lines = { 'testing', '123' }
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = {
{
@@ -2724,11 +2862,11 @@ describe('LSP', function()
targetSelectionRange = {
start = { line = 0, character = 2 },
['end'] = { line = 0, character = 3 },
- }
+ },
},
}
return vim.lsp.util.locations_to_items(locations, 'utf-16')
- ]]
+ end)
eq(expected, actual)
end)
end)
@@ -2761,94 +2899,95 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local doc_syms = {
- {
- deprecated = false,
- detail = "A",
- kind = 1,
- name = "TestA",
- range = {
- start = {
- character = 0,
- line = 1
+ exec_lua(function()
+ local doc_syms = {
+ {
+ deprecated = false,
+ detail = 'A',
+ kind = 1,
+ name = 'TestA',
+ range = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
},
- ["end"] = {
- character = 0,
- line = 2
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 1
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 4,
+ line = 1,
+ },
},
- ["end"] = {
- character = 4,
- line = 1
- }
- },
- children = {
- {
- children = {},
- deprecated = false,
- detail = "B",
- kind = 2,
- name = "TestB",
- range = {
- start = {
- character = 0,
- line = 3
+ children = {
+ {
+ children = {},
+ deprecated = false,
+ detail = 'B',
+ kind = 2,
+ name = 'TestB',
+ range = {
+ start = {
+ character = 0,
+ line = 3,
+ },
+ ['end'] = {
+ character = 0,
+ line = 4,
+ },
},
- ["end"] = {
- character = 0,
- line = 4
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 3
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 3,
+ },
+ ['end'] = {
+ character = 4,
+ line = 3,
+ },
},
- ["end"] = {
- character = 4,
- line = 3
- }
- }
- }
- }
- },
- {
- deprecated = false,
- detail = "C",
- kind = 3,
- name = "TestC",
- range = {
- start = {
- character = 0,
- line = 5
+ },
},
- ["end"] = {
- character = 0,
- line = 6
- }
},
- selectionRange = {
- start = {
- character = 0,
- line = 5
+ {
+ deprecated = false,
+ detail = 'C',
+ kind = 3,
+ name = 'TestC',
+ range = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 0,
+ line = 6,
+ },
},
- ["end"] = {
- character = 4,
- line = 5
- }
- }
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 4,
+ line = 5,
+ },
+ },
+ },
}
- }
- return vim.lsp.util.symbols_to_items(doc_syms, nil)
- ]]
+ return vim.lsp.util.symbols_to_items(doc_syms, nil)
+ end)
)
end)
+
it('DocumentSymbol has no children', function()
local expected = {
{
@@ -2868,66 +3007,67 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
- local doc_syms = {
- {
- deprecated = false,
- detail = "A",
- kind = 1,
- name = "TestA",
- range = {
- start = {
- character = 0,
- line = 1
+ exec_lua(function()
+ local doc_syms = {
+ {
+ deprecated = false,
+ detail = 'A',
+ kind = 1,
+ name = 'TestA',
+ range = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 0,
+ line = 2,
+ },
},
- ["end"] = {
- character = 0,
- line = 2
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 1
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 1,
+ },
+ ['end'] = {
+ character = 4,
+ line = 1,
+ },
},
- ["end"] = {
- character = 4,
- line = 1
- }
},
- },
- {
- deprecated = false,
- detail = "C",
- kind = 3,
- name = "TestC",
- range = {
- start = {
- character = 0,
- line = 5
+ {
+ deprecated = false,
+ detail = 'C',
+ kind = 3,
+ name = 'TestC',
+ range = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 0,
+ line = 6,
+ },
},
- ["end"] = {
- character = 0,
- line = 6
- }
- },
- selectionRange = {
- start = {
- character = 0,
- line = 5
+ selectionRange = {
+ start = {
+ character = 0,
+ line = 5,
+ },
+ ['end'] = {
+ character = 4,
+ line = 5,
+ },
},
- ["end"] = {
- character = 4,
- line = 5
- }
- }
+ },
}
- }
- return vim.lsp.util.symbols_to_items(doc_syms, nil)
- ]]
+ return vim.lsp.util.symbols_to_items(doc_syms, nil)
+ end)
)
end)
end)
+
it('convert SymbolInformation[] to items', function()
local expected = {
{
@@ -2947,62 +3087,88 @@ describe('LSP', function()
}
eq(
expected,
- exec_lua [[
+ exec_lua(function()
local sym_info = {
{
deprecated = false,
kind = 1,
- name = "TestA",
+ name = 'TestA',
location = {
range = {
start = {
character = 0,
- line = 1
+ line = 1,
},
- ["end"] = {
+ ['end'] = {
character = 0,
- line = 2
- }
+ line = 2,
+ },
},
- uri = "file:///test_a"
+ uri = 'file:///test_a',
},
- containerName = "TestAContainer"
+ containerName = 'TestAContainer',
},
{
deprecated = false,
kind = 2,
- name = "TestB",
+ name = 'TestB',
location = {
range = {
start = {
character = 0,
- line = 3
+ line = 3,
},
- ["end"] = {
+ ['end'] = {
character = 0,
- line = 4
- }
+ line = 4,
+ },
},
- uri = "file:///test_b"
+ uri = 'file:///test_b',
},
- containerName = "TestBContainer"
- }
+ containerName = 'TestBContainer',
+ },
}
return vim.lsp.util.symbols_to_items(sym_info, nil)
- ]]
+ end)
)
end)
end)
describe('lsp.util._get_symbol_kind_name', function()
it('returns the name specified by protocol', function()
- eq('File', exec_lua('return vim.lsp.util._get_symbol_kind_name(1)'))
- eq('TypeParameter', exec_lua('return vim.lsp.util._get_symbol_kind_name(26)'))
+ eq(
+ 'File',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(1)
+ end)
+ )
+ eq(
+ 'TypeParameter',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(26)
+ end)
+ )
end)
+
it('returns the name not specified by protocol', function()
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(nil)'))
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(vim.NIL)'))
- eq('Unknown', exec_lua('return vim.lsp.util._get_symbol_kind_name(1000)'))
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(nil)
+ end)
+ )
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(vim.NIL)
+ end)
+ )
+ eq(
+ 'Unknown',
+ exec_lua(function()
+ return vim.lsp.util._get_symbol_kind_name(1000)
+ end)
+ )
end)
end)
@@ -3010,12 +3176,12 @@ describe('LSP', function()
local target_bufnr --- @type integer
before_each(function()
- target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr = exec_lua(function()
+ 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
- ]]
+ end)
end)
local location = function(start_line, start_char, end_line, end_char)
@@ -3084,19 +3250,19 @@ describe('LSP', function()
local target_bufnr2 --- @type integer
before_each(function()
- target_bufnr = exec_lua([[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr = exec_lua(function()
+ 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
- ]])
+ end)
- target_bufnr2 = exec_lua([[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri2")
- local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
+ target_bufnr2 = exec_lua(function()
+ 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)
end)
local location = function(start_line, start_char, end_line, end_char, second_uri)
@@ -3136,14 +3302,14 @@ describe('LSP', function()
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 = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(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 }
+ ['end'] = { line = 0, character = 9 },
},
takeFocus = true,
}
@@ -3154,9 +3320,9 @@ describe('LSP', function()
vim.lsp.handlers['window/showDocument'](nil, result, ctx)
vim.lsp.stop_client(client_id)
return {
- cursor = vim.api.nvim_win_get_cursor(0)
+ cursor = vim.api.nvim_win_get_cursor(0),
}
- ]])
+ end)
eq(1, result.cursor[1])
eq(9, result.cursor[2])
end)
@@ -3231,7 +3397,9 @@ describe('LSP', function()
api.nvim_win_set_buf(0, target_bufnr)
api.nvim_win_set_cursor(0, { 2, 3 })
- exec_lua([[vim.cmd.new()]])
+ exec_lua(function()
+ vim.cmd.new()
+ end)
api.nvim_win_set_buf(0, target_bufnr2)
api.nvim_win_set_cursor(0, { 2, 3 })
@@ -3247,7 +3415,9 @@ describe('LSP', function()
api.nvim_win_set_buf(0, target_bufnr)
local win = api.nvim_get_current_win()
- exec_lua([[vim.cmd.new()]])
+ exec_lua(function()
+ vim.cmd.new()
+ end)
api.nvim_win_set_buf(0, target_bufnr2)
api.nvim_win_set_cursor(0, { 2, 3 })
local split = api.nvim_get_current_win()
@@ -3268,34 +3438,53 @@ describe('LSP', function()
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
- exec_lua [[ contents =
- {"text tαxt txtα tex",
- "text tααt tααt text",
- "text tαxt tαxt"}
- ]]
+ exec_lua(function()
+ _G.contents = { 'text tαxt txtα tex', 'text tααt tααt text', 'text tαxt tαxt' }
+ end)
end)
it('calculates size correctly', function()
- eq({ 19, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 19, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
end)
it('calculates size correctly with wrapping', function()
eq(
{ 15, 5 },
- exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents,{width = 15, wrap_at = 14})} ]]
+ exec_lua(function()
+ return {
+ vim.lsp.util._make_floating_popup_size(_G.contents, { width = 15, wrap_at = 14 }),
+ }
+ end)
)
end)
it('handles NUL bytes in text', function()
- exec_lua([[ contents = {
- '\000\001\002\003\004\005\006\007\008\009',
- '\010\011\012\013\014\015\016\017\018\019',
- '\020\021\022\023\024\025\026\027\028\029',
- } ]])
+ exec_lua(function()
+ _G.contents = {
+ '\000\001\002\003\004\005\006\007\008\009',
+ '\010\011\012\013\014\015\016\017\018\019',
+ '\020\021\022\023\024\025\026\027\028\029',
+ }
+ end)
command('set list listchars=')
- eq({ 20, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 20, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
command('set display+=uhex')
- eq({ 40, 3 }, exec_lua [[ return {vim.lsp.util._make_floating_popup_size(contents)} ]])
+ eq(
+ { 40, 3 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents) }
+ end)
+ )
end)
end)
@@ -3303,27 +3492,30 @@ describe('LSP', function()
it('properly trims empty lines', function()
eq(
{ { 'foo', 'bar' } },
- exec_lua [[ return vim.lsp.util.trim_empty_lines({{ "foo", "bar" }, nil}) ]]
+ exec_lua(function()
+ --- @diagnostic disable-next-line:deprecated
+ return vim.lsp.util.trim_empty_lines({ { 'foo', 'bar' }, nil })
+ end)
)
end)
end)
describe('lsp.util.convert_signature_help_to_markdown_lines', function()
it('can handle negative activeSignature', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
local signature_help = {
activeParameter = 0,
activeSignature = -1,
signatures = {
{
- documentation = "some doc",
- label = "TestEntity.TestEntity()",
- parameters = {}
+ documentation = 'some doc',
+ label = 'TestEntity.TestEntity()',
+ parameters = {},
},
- }
+ },
}
- return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','})
- ]]
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', { ',' })
+ end)
local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' }
eq(expected, result)
end)
@@ -3338,12 +3530,18 @@ describe('LSP', function()
]],
shiftwidth
))
- eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()'))
+ eq(
+ tabsize,
+ exec_lua(function()
+ return vim.lsp.util.get_effective_tabstop()
+ end)
+ )
end
it('with shiftwidth = 1', function()
test_tabstop(1, 1)
end)
+
it('with shiftwidth = 0', function()
test_tabstop(2, 0)
end)
@@ -3351,57 +3549,61 @@ describe('LSP', function()
describe('vim.lsp.buf.outgoing_calls', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right caller', function()
- local qflist = exec_lua([=[
- local rust_analyzer_response = { {
- fromRanges = { {
- ['end'] = {
- character = 7,
- line = 3
- },
- start = {
- character = 4,
- line = 3
- }
- } },
- to = {
- detail = "fn foo()",
- kind = 12,
- name = "foo",
- range = {
- ['end'] = {
- character = 11,
- line = 0
+ local qflist = exec_lua(function()
+ local rust_analyzer_response = {
+ {
+ fromRanges = {
+ {
+ ['end'] = {
+ character = 7,
+ line = 3,
+ },
+ start = {
+ character = 4,
+ line = 3,
+ },
},
- start = {
- character = 0,
- line = 0
- }
},
- selectionRange = {
- ['end'] = {
- character = 6,
- line = 0
+ to = {
+ detail = 'fn foo()',
+ kind = 12,
+ name = 'foo',
+ range = {
+ ['end'] = {
+ character = 11,
+ line = 0,
+ },
+ start = {
+ character = 0,
+ line = 0,
+ },
},
- start = {
- character = 3,
- line = 0
- }
+ selectionRange = {
+ ['end'] = {
+ character = 6,
+ line = 0,
+ },
+ start = {
+ character = 3,
+ line = 0,
+ },
+ },
+ uri = 'file:///src/main.rs',
},
- uri = "file:///src/main.rs"
- }
- } }
- local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
+ },
+ }
+ local handler = require 'vim.lsp.handlers'['callHierarchy/outgoingCalls']
handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3426,58 +3628,62 @@ describe('LSP', function()
describe('vim.lsp.buf.incoming_calls', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right callee', function()
- local qflist = exec_lua([=[
- local rust_analyzer_response = { {
- from = {
- detail = "fn main()",
- kind = 12,
- name = "main",
- range = {
- ['end'] = {
- character = 1,
- line = 4
+ local qflist = exec_lua(function()
+ local rust_analyzer_response = {
+ {
+ from = {
+ detail = 'fn main()',
+ kind = 12,
+ name = 'main',
+ range = {
+ ['end'] = {
+ character = 1,
+ line = 4,
+ },
+ start = {
+ character = 0,
+ line = 2,
+ },
},
- start = {
- character = 0,
- line = 2
- }
+ selectionRange = {
+ ['end'] = {
+ character = 7,
+ line = 2,
+ },
+ start = {
+ character = 3,
+ line = 2,
+ },
+ },
+ uri = 'file:///src/main.rs',
},
- selectionRange = {
- ['end'] = {
- character = 7,
- line = 2
+ fromRanges = {
+ {
+ ['end'] = {
+ character = 7,
+ line = 3,
+ },
+ start = {
+ character = 4,
+ line = 3,
+ },
},
- start = {
- character = 3,
- line = 2
- }
},
- uri = "file:///src/main.rs"
},
- fromRanges = { {
- ['end'] = {
- character = 7,
- line = 3
- },
- start = {
- character = 4,
- line = 3
- }
- } }
- } }
+ }
- local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
+ local handler = require 'vim.lsp.handlers'['callHierarchy/incomingCalls']
handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3502,103 +3708,126 @@ describe('LSP', function()
describe('vim.lsp.buf.typehierarchy subtypes', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['typeHierarchy/subtypes'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right subtypes', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
- local clangd_response = { {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "EDC336589C09ABB2"
- },
- kind = 5,
- name = "D2",
- range = {
- ["end"] = {
- character = 8,
- line = 9
+ local qflist = exec_lua(function()
+ local clangd_response = {
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'EDC336589C09ABB2',
},
- start = {
- character = 6,
- line = 9
- }
- },
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 9
+ kind = 5,
+ name = 'D2',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 9
- }
- },
- uri = "file:///home/jiangyinzuo/hello.cpp"
- }, {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "AFFCAED15557EF08"
- },
- kind = 5,
- name = "D1",
- range = {
- ["end"] = {
- character = 8,
- line = 8
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 8
- }
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 8
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'AFFCAED15557EF08',
},
- start = {
- character = 6,
- line = 8
- }
+ kind = 5,
+ name = 'D1',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- uri = "file:///home/jiangyinzuo/hello.cpp"
- } }
+ }
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes']
- handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'class B : public A{};',
+ 'class C : public B{};',
+ 'class D1 : public C{};',
+ 'class D2 : public C{};',
+ 'class E : public D1, D2 {};',
+ })
+ handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3606,7 +3835,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 10,
+ lnum = 4,
module = '',
nr = 0,
pattern = '',
@@ -3620,7 +3849,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 9,
+ lnum = 3,
module = '',
nr = 0,
pattern = '',
@@ -3637,7 +3866,7 @@ describe('LSP', function()
it('opens the quickfix list with the right subtypes and details', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
+ local qflist = exec_lua(function()
local jdtls_response = {
{
data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' },
@@ -3673,16 +3902,24 @@ describe('LSP', function()
},
}
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/subtypes']
- handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/subtypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'package mylist;',
+ '',
+ 'public class MyList {',
+ ' static class Inner extends MyList{}',
+ '~}',
+ })
+ handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3720,103 +3957,127 @@ describe('LSP', function()
describe('vim.lsp.buf.typehierarchy supertypes', function()
it('does nothing for an empty response', function()
- local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {})
+ local qflist_count = exec_lua(function()
+ require 'vim.lsp.handlers'['typeHierarchy/supertypes'](nil, nil, {})
return #vim.fn.getqflist()
- ]=])
+ end)
eq(0, qflist_count)
end)
it('opens the quickfix list with the right supertypes', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
- local clangd_response = { {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "EDC336589C09ABB2"
- },
- kind = 5,
- name = "D2",
- range = {
- ["end"] = {
- character = 8,
- line = 9
+ local qflist = exec_lua(function()
+ local clangd_response = {
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'EDC336589C09ABB2',
},
- start = {
- character = 6,
- line = 9
- }
- },
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 9
+ kind = 5,
+ name = 'D2',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 9
- }
- },
- uri = "file:///home/jiangyinzuo/hello.cpp"
- }, {
- data = {
- parents = { {
- parents = { {
- parents = { {
- parents = {},
- symbolID = "62B3D268A01B9978"
- } },
- symbolID = "DC9B0AD433B43BEC"
- } },
- symbolID = "06B5F6A19BA9F6A8"
- } },
- symbolID = "AFFCAED15557EF08"
- },
- kind = 5,
- name = "D1",
- range = {
- ["end"] = {
- character = 8,
- line = 8
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 3,
+ },
+ start = {
+ character = 6,
+ line = 3,
+ },
},
- start = {
- character = 6,
- line = 8
- }
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- selectionRange = {
- ["end"] = {
- character = 8,
- line = 8
+ {
+ data = {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {
+ {
+ parents = {},
+ symbolID = '62B3D268A01B9978',
+ },
+ },
+ symbolID = 'DC9B0AD433B43BEC',
+ },
+ },
+ symbolID = '06B5F6A19BA9F6A8',
+ },
+ },
+ symbolID = 'AFFCAED15557EF08',
},
- start = {
- character = 6,
- line = 8
- }
+ kind = 5,
+ name = 'D1',
+ range = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ selectionRange = {
+ ['end'] = {
+ character = 8,
+ line = 2,
+ },
+ start = {
+ character = 6,
+ line = 2,
+ },
+ },
+ uri = 'file:///home/jiangyinzuo/hello.cpp',
},
- uri = "file:///home/jiangyinzuo/hello.cpp"
- } }
+ }
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes']
- handler(nil, clangd_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'class B : public A{};',
+ 'class C : public B{};',
+ 'class D1 : public C{};',
+ 'class D2 : public C{};',
+ 'class E : public D1, D2 {};',
+ })
+
+ handler(nil, clangd_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3824,7 +4085,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 10,
+ lnum = 4,
module = '',
nr = 0,
pattern = '',
@@ -3838,7 +4099,7 @@ describe('LSP', function()
col = 7,
end_col = 0,
end_lnum = 0,
- lnum = 9,
+ lnum = 3,
module = '',
nr = 0,
pattern = '',
@@ -3855,7 +4116,7 @@ describe('LSP', function()
it('opens the quickfix list with the right supertypes and details', function()
clear()
exec_lua(create_server_definition)
- local qflist = exec_lua([=[
+ local qflist = exec_lua(function()
local jdtls_response = {
{
data = { element = '=hello-java_ed323c3c/_<{Main.java[Main[A' },
@@ -3891,16 +4152,24 @@ describe('LSP', function()
},
}
- local server = _create_server({
+ local server = _G._create_server({
capabilities = {
- positionEncoding = "utf-8"
+ positionEncoding = 'utf-8',
},
})
local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- local handler = require'vim.lsp.handlers'['typeHierarchy/supertypes']
- handler(nil, jdtls_response, { client_id = client_id, bufnr = 1 })
+ local handler = require 'vim.lsp.handlers'['typeHierarchy/supertypes']
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
+ 'package mylist;',
+ '',
+ 'public class MyList {',
+ ' static class Inner extends MyList{}',
+ '~}',
+ })
+ handler(nil, jdtls_response, { client_id = client_id, bufnr = bufnr })
return vim.fn.getqflist()
- ]=])
+ end)
local expected = {
{
@@ -3984,18 +4253,19 @@ describe('LSP', function()
eq(true, client.server_capabilities().renameProvider.prepareProvider)
end,
on_setup = function()
- exec_lua([=[
- local bufnr = vim.api.nvim_get_current_buf()
- lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- vim.lsp._stubs = {}
- vim.fn.input = function(opts, on_confirm)
- vim.lsp._stubs.input_prompt = opts.prompt
- vim.lsp._stubs.input_text = opts.default
- return 'renameto' -- expect this value in fake lsp
- end
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'', 'this is line two'})
- vim.fn.cursor(2, 13) -- the space between "line" and "two"
- ]=])
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp._stubs = {}
+ --- @diagnostic disable-next-line:duplicate-set-field
+ vim.fn.input = function(opts, _)
+ vim.lsp._stubs.input_prompt = opts.prompt
+ vim.lsp._stubs.input_text = opts.default
+ return 'renameto' -- expect this value in fake lsp
+ end
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { '', 'this is line two' })
+ vim.fn.cursor(2, 13) -- the space between "line" and "two"
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -4009,12 +4279,24 @@ describe('LSP', function()
eq(table.remove(test.expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'start' then
- exec_lua('vim.lsp.buf.rename()')
+ exec_lua(function()
+ vim.lsp.buf.rename()
+ end)
end
if ctx.method == 'shutdown' then
if test.expected_text then
- eq('New Name: ', exec_lua('return vim.lsp._stubs.input_prompt'))
- eq(test.expected_text, exec_lua('return vim.lsp._stubs.input_text'))
+ eq(
+ 'New Name: ',
+ exec_lua(function()
+ return vim.lsp._stubs.input_prompt
+ end)
+ )
+ eq(
+ test.expected_text,
+ exec_lua(function()
+ return vim.lsp._stubs.input_text
+ end)
+ )
end
client.stop()
end
@@ -4044,25 +4326,31 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
- vim.lsp.commands['dummy1'] = function(cmd)
- vim.lsp.commands['dummy2'] = function()
- end
+ exec_lua(function()
+ vim.lsp.commands['dummy1'] = function(_)
+ vim.lsp.commands['dummy2'] = function() end
end
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ --- @diagnostic disable-next-line:duplicate-set-field
vim.fn.inputlist = function()
return 1
end
vim.lsp.buf.code_action()
- ]])
+ end)
elseif ctx.method == 'shutdown' then
- eq('function', exec_lua [[return type(vim.lsp.commands['dummy2'])]])
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['dummy2'])
+ end)
+ )
client.stop()
end
end,
}
end)
+
it('Calls workspace/executeCommand if no client side command', function()
local client --- @type vim.lsp.Client
local expected_handlers = {
@@ -4089,20 +4377,21 @@ describe('LSP', function()
ctx.version = nil
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
+ exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
vim.fn.inputlist = function()
return 1
end
vim.lsp.buf.code_action()
- ]])
+ end)
elseif ctx.method == 'shutdown' then
client.stop()
end
end,
})
end)
+
it('Filters and automatically applies action if requested', function()
local client --- @type vim.lsp.Client
local expected_handlers = {
@@ -4122,83 +4411,102 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
- exec_lua([[
- vim.lsp.commands['preferred_command'] = function(cmd)
- vim.lsp.commands['executed_preferred'] = function()
- end
+ exec_lua(function()
+ vim.lsp.commands['preferred_command'] = function(_)
+ vim.lsp.commands['executed_preferred'] = function() end
end
- vim.lsp.commands['type_annotate_command'] = function(cmd)
- vim.lsp.commands['executed_type_annotate'] = function()
- end
+ vim.lsp.commands['type_annotate_command'] = function(_)
+ vim.lsp.commands['executed_type_annotate'] = function() end
end
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ vim.lsp.buf.code_action({
+ filter = function(a)
+ return a.isPreferred
+ end,
+ apply = true,
+ })
vim.lsp.buf.code_action({
- -- expect to be returned actions 'type-annotate' and 'type-annotate.foo'
- context = { only = { 'type-annotate' }, },
- apply = true,
- filter = function(a)
- if a.kind == 'type-annotate.foo' then
- vim.lsp.commands['filtered_type_annotate_foo'] = function() end
- return false
- elseif a.kind == 'type-annotate' then
- return true
- else
- assert(nil, 'unreachable')
- end
- end,
+ -- expect to be returned actions 'type-annotate' and 'type-annotate.foo'
+ context = { only = { 'type-annotate' } },
+ apply = true,
+ filter = function(a)
+ if a.kind == 'type-annotate.foo' then
+ vim.lsp.commands['filtered_type_annotate_foo'] = function() end
+ return false
+ elseif a.kind == 'type-annotate' then
+ return true
+ else
+ assert(nil, 'unreachable')
+ end
+ end,
})
- ]])
+ end)
elseif ctx.method == 'shutdown' then
- eq('function', exec_lua [[return type(vim.lsp.commands['executed_preferred'])]])
- eq('function', exec_lua [[return type(vim.lsp.commands['filtered_type_annotate_foo'])]])
- eq('function', exec_lua [[return type(vim.lsp.commands['executed_type_annotate'])]])
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['executed_preferred'])
+ end)
+ )
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['filtered_type_annotate_foo'])
+ end)
+ )
+ eq(
+ 'function',
+ exec_lua(function()
+ return type(vim.lsp.commands['executed_type_annotate'])
+ end)
+ )
client.stop()
end
end,
}
end)
+
it('Fallback to command execution on resolve error', function()
clear()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({
+ local result = exec_lua(function()
+ local server = _G._create_server({
capabilities = {
executeCommandProvider = {
- commands = {"command:1"},
+ commands = { 'command:1' },
},
codeActionProvider = {
- resolveProvider = true
- }
+ resolveProvider = true,
+ },
},
handlers = {
- ["textDocument/codeAction"] = function(_, _, callback)
+ ['textDocument/codeAction'] = function(_, _, callback)
callback(nil, {
{
- title = "Code Action 1",
+ title = 'Code Action 1',
command = {
- title = "Command 1",
- command = "command:1",
- }
- }
+ title = 'Command 1',
+ command = 'command:1',
+ },
+ },
})
end,
- ["codeAction/resolve"] = function(_, _, callback)
- callback("resolve failed", nil)
+ ['codeAction/resolve'] = function(_, _, callback)
+ callback('resolve failed', nil)
end,
- }
+ },
})
- local client_id = vim.lsp.start({
- name = "dummy",
+ local client_id = assert(vim.lsp.start({
+ name = 'dummy',
cmd = server.cmd,
- })
+ }))
vim.lsp.buf.code_action({ apply = true })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq('codeAction/resolve', result[4].method)
eq('workspace/executeCommand', result[5].method)
eq('command:1', result[5].params.command)
@@ -4212,6 +4520,7 @@ describe('LSP', function()
pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end')
)
end)
+
it('Accepts only function values', function()
matches(
'.*Command added to `vim.lsp.commands` must be a function',
@@ -4241,32 +4550,32 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
local fake_uri = 'file:///fake/uri'
- local cmd = exec_lua(
- [[
- fake_uri = ...
+ local cmd = exec_lua(function()
local bufnr = vim.uri_to_bufnr(fake_uri)
vim.fn.bufload(bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' })
local lenses = {
{
range = {
- start = { line = 0, character = 0, },
- ['end'] = { line = 0, character = 8 }
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 8 },
},
- command = { title = 'Lens1', command = 'Dummy' }
+ command = { title = 'Lens1', command = 'Dummy' },
},
}
- vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ vim.lsp.codelens.on_codelens(
+ nil,
+ lenses,
+ { method = 'textDocument/codeLens', client_id = 1, bufnr = bufnr }
+ )
local cmd_called = nil
- vim.lsp.commands['Dummy'] = function(command)
- cmd_called = command
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.api.nvim_set_current_buf(bufnr)
vim.lsp.codelens.run()
return cmd_called
- ]],
- fake_uri
- )
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, cmd)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4287,20 +4596,20 @@ describe('LSP', function()
client = client_
end,
on_setup = function()
- exec_lua([=[
- local bufnr = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
-
- CALLED = false
- RESPONSE = nil
- local on_codelens = vim.lsp.codelens.on_codelens
- vim.lsp.codelens.on_codelens = function (err, result, ...)
- CALLED = true
- RESPONSE = { err = err, result = result }
- return on_codelens(err, result, ...)
- end
- ]=])
+ exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'One line' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+
+ _G.CALLED = false
+ _G.RESPONSE = nil
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function(err, result, ...)
+ _G.CALLED = true
+ _G.RESPONSE = { err = err, result = result }
+ return on_codelens(err, result, ...)
+ end
+ end)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -4310,42 +4619,52 @@ describe('LSP', function()
eq(table.remove(expected_handlers), { err, result, ctx })
if ctx.method == 'start' then
-- 1. first codelens request errors
- local response = exec_lua([=[
- CALLED = false
+ local response = exec_lua(function()
+ _G.CALLED = false
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
- return RESPONSE
- ]=])
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
+ return _G.RESPONSE
+ end)
eq({ err = { code = -32002, message = 'ServerNotInitialized' } }, response)
-- 2. second codelens request runs
- response = exec_lua([=[
- CALLED = false
- local cmd_called = nil
- vim.lsp.commands["Dummy"] = function (command)
- cmd_called = command
+ response = exec_lua(function()
+ _G.CALLED = false
+ local cmd_called --- @type string?
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
vim.lsp.codelens.run()
- vim.wait(100, function () return cmd_called end)
+ vim.wait(100, function()
+ return cmd_called ~= nil
+ end)
return cmd_called
- ]=])
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, response)
-- 3. third codelens request runs
- response = exec_lua([=[
- CALLED = false
- local cmd_called = nil
- vim.lsp.commands["Dummy"] = function (command)
- cmd_called = command
+ response = exec_lua(function()
+ _G.CALLED = false
+ local cmd_called --- @type string?
+ vim.lsp.commands['Dummy'] = function(command0)
+ cmd_called = command0
end
vim.lsp.codelens.refresh()
- vim.wait(100, function () return CALLED end)
+ vim.wait(100, function()
+ return _G.CALLED
+ end)
vim.lsp.codelens.run()
- vim.wait(100, function () return cmd_called end)
+ vim.wait(100, function()
+ return cmd_called ~= nil
+ end)
return cmd_called
- ]=])
+ end)
eq({ command = 'Dummy', title = 'Lens2' }, response)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4363,79 +4682,73 @@ describe('LSP', function()
exec_lua(create_server_definition)
-- setup lsp
- exec_lua(
- [[
- local lens_title_per_fake_uri = ...
- local server = _create_server({
- capabilities = {
- codeLensProvider = {
- resolveProvider = true
- },
+ exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ codeLensProvider = {
+ resolveProvider = true,
},
- handlers = {
- ["textDocument/codeLens"] = function(method, params, callback)
- local lenses = {
- {
- range = {
- start = { line = 0, character = 0 },
- ['end'] = { line = 0, character = 0 },
- },
- command = {
- title = lens_title_per_fake_uri[params.textDocument.uri],
- command = 'Dummy',
- },
+ },
+ handlers = {
+ ['textDocument/codeLens'] = function(_, params, callback)
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0 },
+ ['end'] = { line = 0, character = 0 },
},
- }
- callback(nil, lenses)
- end,
- }
- })
+ command = {
+ title = lens_title_per_fake_uri[params.textDocument.uri],
+ command = 'Dummy',
+ },
+ },
+ }
+ callback(nil, lenses)
+ end,
+ },
+ })
- CLIENT_ID = vim.lsp.start({
- name = "dummy",
- cmd = server.cmd,
- })
- ]],
- lens_title_per_fake_uri
- )
+ _G.CLIENT_ID = vim.lsp.start({
+ name = 'dummy',
+ cmd = server.cmd,
+ })
+ end)
-- create buffers and setup handler
- exec_lua(
- [[
- local lens_title_per_fake_uri = ...
- local default_buf = vim.api.nvim_get_current_buf()
- for fake_uri, _ in pairs(lens_title_per_fake_uri) do
- local bufnr = vim.uri_to_bufnr(fake_uri)
- vim.api.nvim_set_current_buf(bufnr)
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'Some contents'})
- vim.lsp.buf_attach_client(bufnr, CLIENT_ID)
- end
- vim.api.nvim_buf_delete(default_buf, {force = true})
-
- REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri)
- RESPONSES = {}
- local on_codelens = vim.lsp.codelens.on_codelens
- vim.lsp.codelens.on_codelens = function (err, result, ctx, ...)
- table.insert(RESPONSES, { err = err, result = result, ctx = ctx })
- return on_codelens(err, result, ctx, ...)
- end
- ]],
- lens_title_per_fake_uri
- )
+ exec_lua(function()
+ local default_buf = vim.api.nvim_get_current_buf()
+ for fake_uri in pairs(lens_title_per_fake_uri) do
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { 'Some contents' })
+ vim.lsp.buf_attach_client(bufnr, _G.CLIENT_ID)
+ end
+ vim.api.nvim_buf_delete(default_buf, { force = true })
+
+ _G.REQUEST_COUNT = vim.tbl_count(lens_title_per_fake_uri)
+ _G.RESPONSES = {}
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function(err, result, ctx, ...)
+ table.insert(_G.RESPONSES, { err = err, result = result, ctx = ctx })
+ return on_codelens(err, result, ctx, ...)
+ end
+ end)
-- call codelens refresh
- local cmds = exec_lua([[
- RESPONSES = {}
+ local cmds = exec_lua(function()
+ _G.RESPONSES = {}
vim.lsp.codelens.refresh()
- vim.wait(100, function () return #RESPONSES >= REQUEST_COUNT end)
+ vim.wait(100, function()
+ return #_G.RESPONSES >= _G.REQUEST_COUNT
+ end)
local cmds = {}
- for _, resp in ipairs(RESPONSES) do
+ for _, resp in ipairs(_G.RESPONSES) do
local uri = resp.ctx.params.textDocument.uri
cmds[uri] = resp.result[1].command
end
return cmds
- ]])
+ end)
eq({ command = 'Dummy', title = 'Lens1' }, cmds['file:///fake/uri1'])
eq({ command = 'Dummy', title = 'Lens2' }, cmds['file:///fake/uri2'])
end)
@@ -4450,23 +4763,24 @@ describe('LSP', function()
client = c
end,
on_handler = function()
- local notify_msg = exec_lua([[
+ local notify_msg = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- local notify_msg
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
vim.lsp.buf.format({ name = 'does-not-exist' })
vim.notify = notify
return notify_msg
- ]])
+ end)
eq('[LSP] Format request failed, no matching language servers.', notify_msg)
client.stop()
end,
}
end)
+
it('Sends textDocument/formatting request to format buffer', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -4481,25 +4795,114 @@ describe('LSP', function()
on_handler = function(_, _, ctx)
table.remove(expected_handlers)
if ctx.method == 'start' then
- local notify_msg = exec_lua([[
+ local notify_msg = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
- local notify_msg
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
vim.lsp.buf.format({ bufnr = bufnr })
vim.notify = notify
return notify_msg
- ]])
- eq(NIL, notify_msg)
+ end)
+ eq(nil, notify_msg)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ }
+ end)
+
+ it('Sends textDocument/rangeFormatting request to format a range', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'range_formatting',
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == 'start' then
+ local notify_msg = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
+ local notify = vim.notify
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({
+ bufnr = bufnr,
+ range = {
+ start = { 1, 1 },
+ ['end'] = { 1, 1 },
+ },
+ })
+ vim.notify = notify
+ return notify_msg
+ end)
+ eq(nil, notify_msg)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ }
+ end)
+
+ it('Sends textDocument/rangesFormatting request to format multiple ranges', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'ranges_formatting',
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == 'start' then
+ local notify_msg = exec_lua(function()
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar', 'baz' })
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
+ local notify_msg --- @type string?
+ local notify = vim.notify
+ vim.notify = function(msg, _)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({
+ bufnr = bufnr,
+ range = {
+ {
+ start = { 1, 1 },
+ ['end'] = { 1, 1 },
+ },
+ {
+ start = { 2, 2 },
+ ['end'] = { 2, 2 },
+ },
+ },
+ })
+ vim.notify = notify
+ return notify_msg
+ end)
+ eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
client.stop()
end
end,
}
end)
+
it('Can format async', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
@@ -4514,29 +4917,31 @@ describe('LSP', function()
on_handler = function(_, _, ctx)
table.remove(expected_handlers)
if ctx.method == 'start' then
- local result = exec_lua([[
+ local result = exec_lua(function()
local bufnr = vim.api.nvim_get_current_buf()
- vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf_attach_client(bufnr, _G.TEST_RPC_CLIENT_ID)
- local notify_msg
+ local notify_msg --- @type string?
local notify = vim.notify
- vim.notify = function(msg, log_level)
+ vim.notify = function(msg, _)
notify_msg = msg
end
local handler = vim.lsp.handlers['textDocument/formatting']
local handler_called = false
- vim.lsp.handlers['textDocument/formatting'] = function(...)
+ vim.lsp.handlers['textDocument/formatting'] = function()
handler_called = true
end
vim.lsp.buf.format({ bufnr = bufnr, async = true })
- vim.wait(1000, function() return handler_called end)
+ vim.wait(1000, function()
+ return handler_called
+ end)
vim.notify = notify
vim.lsp.handlers['textDocument/formatting'] = handler
- return {notify = notify_msg, handler_called = handler_called}
- ]])
+ return { notify = notify_msg, handler_called = handler_called }
+ end)
eq({ handler_called = true }, result)
elseif ctx.method == 'shutdown' then
client.stop()
@@ -4544,24 +4949,27 @@ 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 result = exec_lua(function()
+ local server = _G._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 })
+ local client_id = assert(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_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 })
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
eq('textDocument/rangeFormatting', result[3].method)
local expected_range = {
start = { line = 0, character = 0 },
@@ -4569,17 +4977,20 @@ describe('LSP', function()
}
eq(expected_range, result[3].params.range)
end)
+
it('format formats range in visual line mode', function()
exec_lua(create_server_definition)
- local result = exec_lua([[
- local server = _create_server({ capabilities = {
- documentFormattingProvider = true,
- documentRangeFormattingProvider = true,
- }})
+ local result = exec_lua(function()
+ local server = _G._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 })
+ local client_id = assert(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 baz'})
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'foo', 'bar baz' })
vim.api.nvim_win_set_cursor(0, { 1, 2 })
vim.cmd.normal('V')
vim.api.nvim_win_set_cursor(0, { 2, 1 })
@@ -4587,7 +4998,7 @@ describe('LSP', function()
-- Format again with visual lines going from bottom to top
-- Must result in same formatting
- vim.cmd.normal("<ESC>")
+ vim.cmd.normal('<ESC>')
vim.api.nvim_win_set_cursor(0, { 2, 1 })
vim.cmd.normal('V')
vim.api.nvim_win_set_cursor(0, { 1, 2 })
@@ -4595,7 +5006,7 @@ describe('LSP', function()
vim.lsp.stop_client(client_id)
return server.messages
- ]])
+ end)
local expected_methods = {
'initialize',
'initialized',
@@ -4620,40 +5031,57 @@ describe('LSP', function()
eq(expected_range, result[3].params.range)
eq(expected_range, result[5].params.range)
end)
+
it('Aborts with notify if no clients support requested method', function()
exec_lua(create_server_definition)
- exec_lua([[
+ exec_lua(function()
vim.notify = function(msg, _)
- notify_msg = msg
+ _G.notify_msg = msg
end
- ]])
+ end)
local fail_msg = '[LSP] Format request failed, no matching language servers.'
--- @param name string
--- @param formatting boolean
--- @param range_formatting boolean
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,
- }})
+ exec_lua(function()
+ local server = _G._create_server({
+ capabilities = {
+ documentFormattingProvider = formatting,
+ documentRangeFormattingProvider = range_formatting,
+ },
+ })
vim.lsp.start({ name = name, cmd = server.cmd })
- notify_msg = nil
+ _G.notify_msg = nil
vim.lsp.buf.format({ name = name, timeout_ms = 1 })
- ]],
- formatting,
- range_formatting,
- name
+ end)
+ eq(
+ formatting and timeout_msg or fail_msg,
+ exec_lua(function()
+ return _G.notify_msg
+ end)
+ )
+ exec_lua(function()
+ _G.notify_msg = nil
+ vim.lsp.buf.format({
+ name = name,
+ timeout_ms = 1,
+ range = {
+ start = { 1, 0 },
+ ['end'] = {
+ 1,
+ 0,
+ },
+ },
+ })
+ end)
+ eq(
+ range_formatting and timeout_msg or fail_msg,
+ exec_lua(function()
+ return _G.notify_msg
+ end)
)
- 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)
@@ -4683,10 +5111,9 @@ describe('LSP', function()
},
}
exec_lua(create_server_definition)
- exec_lua(
- [[
- _G.mock_locations = ...
- _G.server = _create_server({
+ exec_lua(function()
+ _G.mock_locations = mock_locations
+ _G.server = _G._create_server({
---@type lsp.ServerCapabilities
capabilities = {
definitionProvider = true,
@@ -4710,26 +5137,25 @@ describe('LSP', function()
name = 'vim.foobar',
kind = 12, ---@type lsp.SymbolKind
location = _G.mock_locations[2],
- }
+ },
})
end,
},
})
- _G.client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd })
- ]],
- mock_locations
- )
+ _G.client_id = vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
end)
+
after_each(function()
- exec_lua [[
+ exec_lua(function()
vim.lsp.stop_client(_G.client_id)
- ]]
+ end)
end)
it('with flags=c, returns matching tags using textDocument/definition', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
return vim.lsp.tagfunc('foobar', 'c')
- ]]
+ end)
eq({
{
cmd = '/\\%6l\\%1c/', -- for location (5, 23)
@@ -4740,9 +5166,9 @@ describe('LSP', function()
end)
it('without flags=c, returns all matching tags using workspace/symbol', function()
- local result = exec_lua [[
+ local result = exec_lua(function()
return vim.lsp.tagfunc('foobar', '')
- ]]
+ end)
eq({
{
cmd = '/\\%6l\\%1c/', -- for location (5, 23)
@@ -4761,80 +5187,81 @@ describe('LSP', function()
end)
describe('cmd', function()
- it('can connect to lsp server via rpc.connect', function()
- local result = exec_lua [[
- local uv = vim.uv
- 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
+ it('connects to lsp server via rpc.connect using ip address', function()
+ exec_lua(create_tcp_echo_server)
+ local result = exec_lua(function()
+ local server, port, last_message = _G._create_tcp_server('127.0.0.1')
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")
+ vim.wait(1000, function()
+ return last_message() ~= nil
+ end)
+ local init = last_message()
+ assert(init, 'server must receive `initialize` request')
+ server:close()
+ server:shutdown()
+ return vim.json.decode(init)
+ end)
+ eq('initialize', result.method)
+ end)
+
+ it('connects to lsp server via rpc.connect using hostname', function()
+ skip(is_os('bsd'), 'issue with host resolution in ci')
+ exec_lua(create_tcp_echo_server)
+ local result = exec_lua(function()
+ local server, port, last_message = _G._create_tcp_server('::1')
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('localhost', port) })
+ vim.wait(1000, function()
+ return last_message() ~= nil
+ end)
+ local init = last_message()
+ assert(init, 'server must receive `initialize` request')
server:close()
server:shutdown()
return vim.json.decode(init)
- ]]
+ end)
eq('initialize', result.method)
end)
+
it('can connect to lsp server via pipe or domain_socket', function()
- local tmpfile --- @type string
- if is_os('win') then
- tmpfile = '\\\\.\\\\pipe\\pipe.test'
- else
- tmpfile = tmpname()
- os.remove(tmpfile)
- end
- local result = exec_lua(
- [[
- local SOCK = ...
+ local tmpfile = is_os('win') and '\\\\.\\\\pipe\\pipe.test' or tmpname(false)
+ local result = exec_lua(function()
local uv = vim.uv
- local server = uv.new_pipe(false)
- server:bind(SOCK)
+ local server = assert(uv.new_pipe(false))
+ server:bind(tmpfile)
local init = nil
server:listen(127, function(err)
- assert(not err, err)
- local client = uv.new_pipe()
- server:accept(client)
- client:read_start(require("vim.lsp.rpc").create_read_loop(function(body)
- init = body
- client:close()
- end))
+ assert(not err, err)
+ local client = assert(vim.uv.new_pipe())
+ server:accept(client)
+ client:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
+ init = body
+ client:close()
+ end))
+ end)
+ vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect(tmpfile) })
+ vim.wait(1000, function()
+ return init ~= nil
end)
- vim.lsp.start({ name = "dummy", cmd = vim.lsp.rpc.connect(SOCK) })
- vim.wait(1000, function() return init ~= nil end)
- assert(init, "server must receive `initialize` request")
+ assert(init, 'server must receive `initialize` request')
server:close()
server:shutdown()
return vim.json.decode(init)
- ]],
- tmpfile
- )
+ end)
eq('initialize', result.method)
end)
end)
describe('handlers', function()
it('handler can return false as response', function()
- local result = exec_lua [[
- local uv = vim.uv
- local server = uv.new_tcp()
+ local result = exec_lua(function()
+ local server = assert(vim.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()
+ local socket = assert(vim.uv.new_tcp())
server:accept(socket)
socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body)
local payload = vim.json.decode(body)
@@ -4845,10 +5272,10 @@ describe('LSP', function()
id = payload.id,
jsonrpc = '2.0',
result = {
- capabilities = {}
+ capabilities = {},
},
})
- socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ 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,
@@ -4856,7 +5283,7 @@ describe('LSP', function()
method = 'dummy',
params = {},
})
- socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg}))
+ socket:write(table.concat({ 'Content-Length: ', tostring(#msg), '\r\n\r\n', msg }))
end
else
table.insert(responses, payload)
@@ -4866,20 +5293,24 @@ describe('LSP', function()
end)
local port = server:getsockname().port
local handler_called = false
- vim.lsp.handlers['dummy'] = function(err, result)
+ vim.lsp.handlers['dummy'] = function(_, _)
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)
+ local client_id =
+ assert(vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }))
+ 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 }
- ]]
+ responses = responses,
+ }
+ end)
local expected = {
messages = { 'initialize', 'initialized' },
handler_called = true,
@@ -4897,9 +5328,7 @@ describe('LSP', function()
describe('#dynamic vim.lsp._dynamic', function()
it('supports dynamic registration', function()
- ---@type string
- local root_dir = tmpname()
- os.remove(root_dir)
+ local root_dir = tmpname(false)
mkdir(root_dir)
local tmpfile = root_dir .. '/dynamic.foo'
local file = io.open(tmpfile, 'w')
@@ -4908,17 +5337,14 @@ describe('LSP', function()
end
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir, tmpfile = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'dynamic-test',
cmd = server.cmd,
root_dir = root_dir,
get_language_id = function()
- return "dummy-lang"
+ return 'dummy-lang'
end,
capabilities = {
textDocument = {
@@ -4930,9 +5356,7 @@ describe('LSP', function()
},
},
},
- })
-
- local expected_messages = 2 -- initialize, initialized
+ }))
vim.lsp.handlers['client/registerCapability'](nil, {
registrations = {
@@ -4940,9 +5364,11 @@ describe('LSP', function()
id = 'formatting',
method = 'textDocument/formatting',
registerOptions = {
- documentSelector = {{
- pattern = root_dir .. '/*.foo',
- }},
+ documentSelector = {
+ {
+ pattern = root_dir .. '/*.foo',
+ },
+ },
},
},
},
@@ -4954,12 +5380,12 @@ describe('LSP', function()
id = 'range-formatting',
method = 'textDocument/rangeFormatting',
registerOptions = {
- documentSelector = {
+ documentSelector = {
{
- language = "dummy-lang"
+ language = 'dummy-lang',
},
- }
- }
+ },
+ },
},
},
}, { client_id = client_id })
@@ -4976,26 +5402,22 @@ describe('LSP', function()
local result = {}
local function check(method, fname)
local bufnr = fname and vim.fn.bufadd(fname) or nil
- local client = vim.lsp.get_client_by_id(client_id)
+ local client = assert(vim.lsp.get_client_by_id(client_id))
result[#result + 1] = {
method = method,
fname = fname,
- supported = client.supports_method(method, {bufnr = bufnr})
+ supported = client.supports_method(method, { bufnr = bufnr }),
}
end
-
- check("textDocument/formatting")
- check("textDocument/formatting", tmpfile)
- check("textDocument/rangeFormatting")
- check("textDocument/rangeFormatting", tmpfile)
- check("textDocument/completion")
+ check('textDocument/formatting')
+ check('textDocument/formatting', tmpfile)
+ check('textDocument/rangeFormatting')
+ check('textDocument/rangeFormatting', tmpfile)
+ check('textDocument/completion')
return result
- ]],
- root_dir,
- tmpfile
- )
+ end)
eq(5, #result)
eq({ method = 'textDocument/formatting', supported = false }, result[1])
@@ -5007,16 +5429,26 @@ describe('LSP', function()
end)
describe('vim.lsp._watchfiles', function()
+ --- @type integer, integer, integer
+ local created, changed, deleted
+
+ setup(function()
+ clear()
+ created = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]])
+ changed = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]])
+ deleted = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]])
+ end)
+
local function test_filechanges(watchfunc)
it(
string.format('sends notifications when files change (watchfunc=%s)', watchfunc),
function()
- if watchfunc == 'fswatch' then
+ if watchfunc == 'inotify' then
skip(is_os('win'), 'not supported on windows')
skip(is_os('mac'), 'flaky test on mac')
skip(
- not is_ci() and fn.executable('fswatch') == 0,
- 'fswatch not installed and not on CI'
+ not is_ci() and fn.executable('inotifywait') == 0,
+ 'inotify-tools not installed and not on CI'
)
end
@@ -5033,87 +5465,80 @@ describe('LSP', function()
)
end
- local root_dir = tmpname()
- os.remove(root_dir)
+ local root_dir = tmpname(false)
mkdir(root_dir)
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir, watchfunc = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
- name = 'watchfiles-test',
- cmd = server.cmd,
- root_dir = root_dir,
- capabilities = {
- workspace = {
- didChangeWatchedFiles = {
- dynamicRegistration = true,
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
+ name = 'watchfiles-test',
+ cmd = server.cmd,
+ root_dir = root_dir,
+ capabilities = {
+ workspace = {
+ didChangeWatchedFiles = {
+ dynamicRegistration = true,
+ },
},
},
- },
- })
+ }))
- require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc]
+ require('vim.lsp._watchfiles')._watchfunc = require('vim._watch')[watchfunc]
- local expected_messages = 0
+ local expected_messages = 0
- local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500
+ local msg_wait_timeout = watchfunc == 'watch' and 200 or 2500
- local function wait_for_message(incr)
- expected_messages = expected_messages + (incr or 1)
- assert(
- vim.wait(msg_wait_timeout, function()
- return #server.messages == expected_messages
- end),
- 'Timed out waiting for expected number of messages. Current messages seen so far: '
- .. vim.inspect(server.messages)
- )
- end
+ local function wait_for_message(incr)
+ expected_messages = expected_messages + (incr or 1)
+ assert(
+ vim.wait(msg_wait_timeout, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
+ end
- wait_for_message(2) -- initialize, initialized
+ wait_for_message(2) -- initialize, initialized
- vim.lsp.handlers['client/registerCapability'](nil, {
- registrations = {
- {
- id = 'watchfiles-test-0',
- method = 'workspace/didChangeWatchedFiles',
- registerOptions = {
- watchers = {
- {
- globPattern = '**/watch',
- kind = 7,
+ vim.lsp.handlers['client/registerCapability'](nil, {
+ registrations = {
+ {
+ id = 'watchfiles-test-0',
+ method = 'workspace/didChangeWatchedFiles',
+ registerOptions = {
+ watchers = {
+ {
+ globPattern = '**/watch',
+ kind = 7,
+ },
},
},
},
},
- },
- }, { client_id = client_id })
+ }, { client_id = client_id })
- if watchfunc ~= 'watch' then
- vim.wait(100)
- end
+ if watchfunc ~= 'watch' then
+ vim.wait(100)
+ end
- local path = root_dir .. '/watch'
- local tmp = vim.fn.tempname()
- io.open(tmp, 'w'):close()
- vim.uv.fs_rename(tmp, path)
+ local path = root_dir .. '/watch'
+ local tmp = vim.fn.tempname()
+ io.open(tmp, 'w'):close()
+ vim.uv.fs_rename(tmp, path)
- wait_for_message()
+ wait_for_message()
- os.remove(path)
+ os.remove(path)
- wait_for_message()
+ wait_for_message()
- vim.lsp.stop_client(client_id)
+ vim.lsp.stop_client(client_id)
- return server.messages
- ]],
- root_dir,
- watchfunc
- )
+ return server.messages
+ end)
local uri = vim.uri_from_fname(root_dir .. '/watch')
@@ -5124,7 +5549,7 @@ describe('LSP', function()
params = {
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = uri,
},
},
@@ -5136,7 +5561,7 @@ describe('LSP', function()
params = {
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = uri,
},
},
@@ -5148,17 +5573,14 @@ describe('LSP', function()
test_filechanges('watch')
test_filechanges('watchdirs')
- test_filechanges('fswatch')
+ test_filechanges('inotify')
it('correctly registers and unregisters', function()
local root_dir = '/some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5169,16 +5591,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local send_event
+ local send_event --- @type function
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
local stopped = false
send_event = function(...)
@@ -5245,9 +5673,7 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
local function watched_uri(fname)
return vim.uri_from_fname(root_dir .. '/' .. fname)
@@ -5258,7 +5684,7 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('file.watch0'),
},
},
@@ -5267,7 +5693,7 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('file.watch1'),
},
},
@@ -5277,12 +5703,9 @@ describe('LSP', function()
it('correctly handles the registered watch kind', function()
local root_dir = 'some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5293,16 +5716,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local watch_callbacks = {}
+ local watch_callbacks = {} --- @type function[]
local function send_event(...)
for _, cb in ipairs(watch_callbacks) do
cb(...)
@@ -5318,12 +5747,14 @@ describe('LSP', function()
local protocol = require('vim.lsp.protocol')
local watchers = {}
- local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete
+ local max_kind = protocol.WatchKind.Create
+ + protocol.WatchKind.Change
+ + protocol.WatchKind.Delete
for i = 0, max_kind do
table.insert(watchers, {
globPattern = {
baseUri = vim.uri_from_fname('/dir'),
- pattern = 'watch'..tostring(i),
+ pattern = 'watch' .. tostring(i),
},
kind = i,
})
@@ -5351,9 +5782,7 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
local function watched_uri(fname)
return vim.uri_from_fname('/dir/' .. fname)
@@ -5364,51 +5793,51 @@ describe('LSP', function()
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch2'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch3'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch3'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch4'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch5'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch5'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch6'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch6'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = watched_uri('watch7'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = watched_uri('watch7'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]),
+ type = deleted,
uri = watched_uri('watch7'),
},
},
@@ -5418,12 +5847,9 @@ describe('LSP', function()
it('prunes duplicate events', function()
local root_dir = 'some_dir'
exec_lua(create_server_definition)
- local result = exec_lua(
- [[
- local root_dir = ...
-
- local server = _create_server()
- local client_id = vim.lsp.start({
+ local result = exec_lua(function()
+ local server = _G._create_server()
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
cmd = server.cmd,
root_dir = root_dir,
@@ -5434,16 +5860,22 @@ describe('LSP', function()
},
},
},
- })
+ }))
local expected_messages = 2 -- initialize, initialized
local function wait_for_messages()
- assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages))
+ assert(
+ vim.wait(200, function()
+ return #server.messages == expected_messages
+ end),
+ 'Timed out waiting for expected number of messages. Current messages seen so far: '
+ .. vim.inspect(server.messages)
+ )
end
wait_for_messages()
- local send_event
+ local send_event --- @type function
require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
send_event = callback
return function()
@@ -5477,24 +5909,22 @@ describe('LSP', function()
wait_for_messages()
return server.messages
- ]],
- root_dir
- )
+ end)
eq(3, #result)
eq('workspace/didChangeWatchedFiles', result[3].method)
eq({
changes = {
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = vim.uri_from_fname('file1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]),
+ type = changed,
uri = vim.uri_from_fname('file1'),
},
{
- type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]),
+ type = created,
uri = vim.uri_from_fname('file2'),
},
},
@@ -5503,27 +5933,28 @@ describe('LSP', function()
it("ignores registrations by servers when the client doesn't advertise support", function()
exec_lua(create_server_definition)
- exec_lua([[
- server = _create_server()
- require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
+ exec_lua(function()
+ _G.server = _G._create_server()
+ require('vim.lsp._watchfiles')._watchfunc = function(_, _, _)
-- Since the registration is ignored, this should not execute and `watching` should stay false
- watching = true
+ _G.watching = true
return function() end
end
- ]])
+ end)
local function check_registered(capabilities)
- return exec_lua(
- [[
- watching = false
- local client_id = vim.lsp.start({
+ return exec_lua(function()
+ _G.watching = false
+ local client_id = assert(vim.lsp.start({
name = 'watchfiles-test',
- cmd = server.cmd,
+ cmd = _G.server.cmd,
root_dir = 'some_dir',
- capabilities = ...,
+ capabilities = capabilities,
}, {
- reuse_client = function() return false end,
- })
+ reuse_client = function()
+ return false
+ end,
+ }))
vim.lsp.handlers['client/registerCapability'](nil, {
registrations = {
@@ -5552,10 +5983,8 @@ describe('LSP', function()
}, { client_id = client_id })
vim.lsp.stop_client(client_id, true)
- return watching
- ]],
- capabilities
- )
+ return _G.watching
+ end)
end
eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities().
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index 978178191c..6f0eeff748 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -8,7 +8,6 @@ local exec_lua = n.exec_lua
local fn = n.fn
local nvim_prog = n.nvim_prog
local matches = t.matches
-local write_file = t.write_file
local tmpname = t.tmpname
local eq = t.eq
local pesc = vim.pesc
@@ -17,21 +16,20 @@ local is_ci = t.is_ci
-- Collects all names passed to find_path() after attempting ":Man foo".
local function get_search_history(name)
- local args = vim.split(name, ' ')
- local code = [[
- local args = ...
- local man = require('runtime.lua.man')
+ return exec_lua(function()
+ local args = vim.split(name, ' ')
+ local man = require('man')
local res = {}
- man.find_path = function(sect, name)
- table.insert(res, {sect, name})
+ --- @diagnostic disable-next-line:duplicate-set-field
+ man.find_path = function(sect, name0)
+ table.insert(res, { sect, name0 })
return nil
end
- local ok, rv = pcall(man.open_page, -1, {tab = 0}, args)
+ local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args)
assert(not ok)
assert(rv and rv:match('no manual entry'))
return res
- ]]
- return exec_lua(code, args)
+ end)
end
clear()
@@ -117,6 +115,29 @@ describe(':Man', function()
]])
end)
+ it('clears OSC 8 hyperlink markup from text', function()
+ feed(
+ [[
+ ithis <C-v><ESC>]8;;http://example.com<C-v><ESC>\Link Title<C-v><ESC>]8;;<C-v><ESC>\<ESC>]]
+ )
+
+ screen:expect {
+ grid = [=[
+ this {c:^[}]8;;http://example.com{c:^[}\Link Title{c:^[}]8;;{c:^[}^\ |
+ {eob:~ }|*3
+ |
+ ]=],
+ }
+
+ exec_lua [[require'man'.init_pager()]]
+
+ screen:expect([[
+ ^this Link Title |
+ {eob:~ }|*3
+ |
+ ]])
+ end)
+
it('highlights multibyte text', function()
feed(
[[
@@ -203,7 +224,6 @@ describe(':Man', function()
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(
diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua
index 1d5d20ec02..61ab730da8 100644
--- a/test/functional/plugin/msgpack_spec.lua
+++ b/test/functional/plugin/msgpack_spec.lua
@@ -58,23 +58,11 @@ describe('autoload/msgpack.vim', function()
msgpack_eq(1, '"abc\\ndef"', '"abc\\ndef"')
msgpack_eq(0, '"abc\\ndef"', '"abc\\nghi"')
end)
- it('compares binary specials correctly', function()
- msgpack_eq(1, sp('binary', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]'))
- msgpack_eq(0, sp('binary', '["abc", "def"]'), sp('binary', '["abc\\n", "def"]'))
- end)
- it('compares binary specials with raw binaries correctly', function()
- msgpack_eq(1, sp('binary', '["abc", "def"]'), '"abc\\ndef"')
- msgpack_eq(0, sp('binary', '["abc", "def"]'), '"abcdef"')
- end)
it('compares string specials correctly', function()
msgpack_eq(1, sp('string', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
msgpack_eq(0, sp('string', '["abc", "def"]'), sp('string', '["abc\\n", "def"]'))
- end)
- it('compares string specials with binary correctly', function()
- msgpack_eq(0, sp('string', '["abc\\n", "def"]'), sp('binary', '["abc\\n", "def"]'))
- msgpack_eq(0, sp('string', '["abc", "def"]'), '"abc\\ndef"')
- msgpack_eq(0, sp('binary', '["abc\\n", "def"]'), sp('string', '["abc\\n", "def"]'))
- msgpack_eq(0, '"abc\\ndef"', sp('string', '["abc", "def"]'))
+ msgpack_eq(1, sp('string', '["abc", "def"]'), '"abc\\ndef"')
+ msgpack_eq(1, '"abc\\ndef"', sp('string', '["abc", "def"]'))
end)
it('compares ext specials correctly', function()
msgpack_eq(1, sp('ext', '[1, ["", "ac"]]'), sp('ext', '[1, ["", "ac"]]'))
@@ -92,20 +80,16 @@ describe('autoload/msgpack.vim', function()
end)
it('compares map specials correctly', function()
msgpack_eq(1, mapsp(), mapsp())
- msgpack_eq(1, mapsp(sp('binary', '[""]'), '""'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(
1,
mapsp(mapsp('1', '1'), mapsp('1', '1')),
mapsp(mapsp('1', '1'), mapsp('1', '1'))
)
msgpack_eq(0, mapsp(), mapsp('1', '1'))
- msgpack_eq(0, mapsp(sp('binary', '["a"]'), '""'), mapsp(sp('binary', '[""]'), '""'))
- msgpack_eq(0, mapsp(sp('binary', '[""]'), '"a"'), mapsp(sp('binary', '[""]'), '""'))
- msgpack_eq(0, mapsp(sp('binary', '["a"]'), '"a"'), mapsp(sp('binary', '[""]'), '""'))
msgpack_eq(
0,
mapsp(mapsp('1', '1'), mapsp('1', '1')),
- mapsp(sp('binary', '[""]'), mapsp('1', '1'))
+ mapsp(sp('string', '[""]'), mapsp('1', '1'))
)
msgpack_eq(
0,
@@ -138,7 +122,7 @@ describe('autoload/msgpack.vim', function()
msgpack_eq(1, mapsp(sp('string', '["1"]'), '1'), '{"1": 1}')
msgpack_eq(1, mapsp(sp('string', '["1"]'), sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(0, mapsp(sp('integer', '[1, 0, 0, 1]'), sp('string', '["1"]')), '{1: "1"}')
- msgpack_eq(0, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
+ msgpack_eq(1, mapsp('"1"', sp('integer', '[1, 0, 0, 1]')), '{"1": 1}')
msgpack_eq(0, mapsp(sp('string', '["1"]'), '1', sp('string', '["2"]'), '2'), '{"1": 1}')
msgpack_eq(0, mapsp(sp('string', '["1"]'), '1'), '{"1": 1, "2": 2}')
end)
@@ -290,7 +274,6 @@ describe('autoload/msgpack.vim', function()
it('works for special dictionaries', function()
type_eq('string', sp('string', '[""]'))
- type_eq('binary', sp('binary', '[""]'))
type_eq('ext', sp('ext', '[1, [""]]'))
type_eq('array', sp('array', '[]'))
type_eq('map', sp('map', '[]'))
@@ -301,7 +284,7 @@ describe('autoload/msgpack.vim', function()
end)
it('works for regular values', function()
- type_eq('binary', '""')
+ type_eq('string', '""')
type_eq('array', '[]')
type_eq('map', '{}')
type_eq('integer', '1')
@@ -319,7 +302,6 @@ describe('autoload/msgpack.vim', function()
it('works for special dictionaries', function()
sp_type_eq('string', sp('string', '[""]'))
- sp_type_eq('binary', sp('binary', '[""]'))
sp_type_eq('ext', sp('ext', '[1, [""]]'))
sp_type_eq('array', sp('array', '[]'))
sp_type_eq('map', sp('map', '[]'))
@@ -347,12 +329,9 @@ describe('autoload/msgpack.vim', function()
end
it('works for special dictionaries', function()
- string_eq('=""', sp('string', '[""]'))
- string_eq('="\\n"', sp('string', '["", ""]'))
- string_eq('="ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
- string_eq('""', sp('binary', '[""]'))
- string_eq('"\\n"', sp('binary', '["", ""]'))
- string_eq('"ab\\0c\\nde"', sp('binary', '["ab\\nc", "de"]'))
+ string_eq('""', sp('string', '[""]'))
+ string_eq('"\\n"', sp('string', '["", ""]'))
+ string_eq('"ab\\0c\\nde"', sp('string', '["ab\\nc", "de"]'))
string_eq('+(2)""', sp('ext', '[2, [""]]'))
string_eq('+(2)"\\n"', sp('ext', '[2, ["", ""]]'))
string_eq('+(2)"ab\\0c\\nde"', sp('ext', '[2, ["ab\\nc", "de"]]'))
@@ -397,8 +376,8 @@ describe('autoload/msgpack.vim', function()
string_eq('[]', '[]')
string_eq('[[[{}]]]', '[[[{}]]]')
string_eq('{}', '{}')
- string_eq('{="2": 10}', '{2: 10}')
- string_eq('{="2": [{}]}', '{2: [{}]}')
+ string_eq('{"2": 10}', '{2: 10}')
+ string_eq('{"2": [{}]}', '{2: [{}]}')
string_eq('1', '1')
string_eq('0.0', '0.0')
string_eq('inf', '(1.0/0.0)')
@@ -422,7 +401,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt = ' .. sp('float', '1.0'))
nvim_command('let spext = ' .. sp('ext', '[2, ["abc", "def"]]'))
nvim_command('let spstr = ' .. sp('string', '["abc", "def"]'))
- nvim_command('let spbin = ' .. sp('binary', '["abc", "def"]'))
nvim_command('let spbln = ' .. sp('boolean', '0'))
nvim_command('let spnil = ' .. sp('nil', '0'))
@@ -432,7 +410,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt2 = msgpack#deepcopy(spflt)')
nvim_command('let spext2 = msgpack#deepcopy(spext)')
nvim_command('let spstr2 = msgpack#deepcopy(spstr)')
- nvim_command('let spbin2 = msgpack#deepcopy(spbin)')
nvim_command('let spbln2 = msgpack#deepcopy(spbln)')
nvim_command('let spnil2 = msgpack#deepcopy(spnil)')
@@ -442,7 +419,6 @@ describe('autoload/msgpack.vim', function()
eq('float', nvim_eval('msgpack#type(spflt2)'))
eq('ext', nvim_eval('msgpack#type(spext2)'))
eq('string', nvim_eval('msgpack#type(spstr2)'))
- eq('binary', nvim_eval('msgpack#type(spbin2)'))
eq('boolean', nvim_eval('msgpack#type(spbln2)'))
eq('nil', nvim_eval('msgpack#type(spnil2)'))
@@ -457,7 +433,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spext._VAL[0] = 3')
nvim_command('let spext._VAL[1][0] = "gh"')
nvim_command('let spstr._VAL[0] = "gh"')
- nvim_command('let spbin._VAL[0] = "gh"')
nvim_command('let spbln._VAL = 1')
nvim_command('let spnil._VAL = 1')
@@ -467,7 +442,6 @@ describe('autoload/msgpack.vim', function()
eq({ _TYPE = {}, _VAL = 1.0 }, nvim_eval('spflt2'))
eq({ _TYPE = {}, _VAL = { 2, { 'abc', 'def' } } }, nvim_eval('spext2'))
eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spstr2'))
- eq({ _TYPE = {}, _VAL = { 'abc', 'def' } }, nvim_eval('spbin2'))
eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spbln2'))
eq({ _TYPE = {}, _VAL = 0 }, nvim_eval('spnil2'))
@@ -477,7 +451,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('let spflt._TYPE = []')
nvim_command('let spext._TYPE = []')
nvim_command('let spstr._TYPE = []')
- nvim_command('let spbin._TYPE = []')
nvim_command('let spbln._TYPE = []')
nvim_command('let spnil._TYPE = []')
@@ -487,7 +460,6 @@ describe('autoload/msgpack.vim', function()
eq('float', nvim_eval('msgpack#special_type(spflt2)'))
eq('ext', nvim_eval('msgpack#special_type(spext2)'))
eq('string', nvim_eval('msgpack#special_type(spstr2)'))
- eq('binary', nvim_eval('msgpack#special_type(spbin2)'))
eq('boolean', nvim_eval('msgpack#special_type(spbln2)'))
eq('nil', nvim_eval('msgpack#special_type(spnil2)'))
end)
@@ -509,7 +481,7 @@ describe('autoload/msgpack.vim', function()
eq('map', nvim_eval('msgpack#type(map2)'))
eq('integer', nvim_eval('msgpack#type(int2)'))
eq('float', nvim_eval('msgpack#type(flt2)'))
- eq('binary', nvim_eval('msgpack#type(bin2)'))
+ eq('string', nvim_eval('msgpack#type(bin2)'))
nvim_command('call add(arr, 0)')
nvim_command('call add(arr[0], 0)')
@@ -566,21 +538,6 @@ describe('autoload/msgpack.vim', function()
nvim_command('unlet g:__val')
end
- it('correctly loads binary strings', function()
- eval_eq('binary', { 'abcdef' }, '"abcdef"')
- eval_eq('binary', { 'abc', 'def' }, '"abc\\ndef"')
- eval_eq('binary', { 'abc\ndef' }, '"abc\\0def"')
- eval_eq('binary', { '\nabc\ndef\n' }, '"\\0abc\\0def\\0"')
- eval_eq('binary', { 'abc\n\n\ndef' }, '"abc\\0\\0\\0def"')
- eval_eq('binary', { 'abc\n', '\ndef' }, '"abc\\0\\n\\0def"')
- eval_eq('binary', { 'abc', '', '', 'def' }, '"abc\\n\\n\\ndef"')
- eval_eq('binary', { 'abc', '', '', 'def', '' }, '"abc\\n\\n\\ndef\\n"')
- eval_eq('binary', { '', 'abc', '', '', 'def' }, '"\\nabc\\n\\n\\ndef"')
- eval_eq('binary', { '' }, '""')
- eval_eq('binary', { '"' }, '"\\""')
- eval_eq('binary', { 'py3 print(sys.version_info)' }, '"py3 print(sys.version_info)"')
- end)
-
it('correctly loads strings', function()
eval_eq('string', { 'abcdef' }, '="abcdef"')
eval_eq('string', { 'abc', 'def' }, '="abc\\ndef"')
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 1c2bcbd497..c9d49f7d01 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -68,7 +68,7 @@ describe('autoload/shada.vim', function()
endfor
return ret
elseif type(a:val) == type('')
- return {'_TYPE': v:msgpack_types.binary, '_VAL': split(a:val, "\n", 1)}
+ return {'_TYPE': v:msgpack_types.string, '_VAL': split(a:val, "\n", 1)}
else
return a:val
endif
@@ -253,8 +253,7 @@ describe('autoload/shada.vim', function()
' + sm magic value "TRUE"',
' # Expected integer',
' + so offset value "TRUE"',
- ' # Expected binary string',
- ' + sp pattern ="abc"',
+ ' + sp pattern "abc"',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'sm': 'TRUE',
@@ -267,7 +266,7 @@ describe('autoload/shada.vim', function()
'n': -0x40,
'l': -10,
'c': 'abc',
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -276,15 +275,14 @@ describe('autoload/shada.vim', function()
' % Key Description Value',
' # Expected no NUL bytes',
' + f file name "abc\\0def"',
- ' # Expected array of binary strings',
- ' + rc contents ["abc", ="abc"]',
+ ' + rc contents ["abc", "abc"]',
' # Expected integer',
' + rt type "ABC"',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
'rt': 'ABC',
'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["abc"]}],
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -295,7 +293,7 @@ describe('autoload/shada.vim', function()
' + rc contents ["abc", "a\\nd\\0"]',
},
([[ [{'type': 1, 'timestamp': 0, 'data': {
- 'rc': ["abc", {'_TYPE': v:msgpack_types.binary, '_VAL': ["a", "d\n"]}],
+ 'rc': ["abc", {'_TYPE': v:msgpack_types.string, '_VAL': ["a", "d\n"]}],
}}] ]]):gsub('\n', '')
)
end)
@@ -468,7 +466,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Replacement string with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 3, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@@ -498,7 +496,7 @@ describe('autoload/shada.vim', function()
' - :s replacement string "abc\\0def"',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -508,7 +506,7 @@ describe('autoload/shada.vim', function()
' - :s replacement string "abc\\ndef"',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -519,7 +517,7 @@ describe('autoload/shada.vim', function()
' - 0',
},
([[ [{'type': 3, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc", "def"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc", "def"]},
0,
]}] ]]):gsub('\n', '')
)
@@ -529,7 +527,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'History entry with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 4, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@@ -682,7 +680,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 4, 'timestamp': 0, 'data': [
4,
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["abc\ndef"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["abc\ndef"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -909,7 +907,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Variable with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 6, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq(
{
@@ -941,7 +939,7 @@ describe('autoload/shada.vim', function()
' # Expected more elements in list',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -952,7 +950,7 @@ describe('autoload/shada.vim', function()
' # Expected more elements in list',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -963,7 +961,7 @@ describe('autoload/shada.vim', function()
' - value NIL',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
)
@@ -976,7 +974,7 @@ describe('autoload/shada.vim', function()
' - NIL',
},
([[ [{'type': 6, 'timestamp': 0, 'data': [
- {'_TYPE': v:msgpack_types.binary, '_VAL': ["foo"]},
+ {'_TYPE': v:msgpack_types.string, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
{'_TYPE': v:msgpack_types.nil, '_VAL': ["foo"]},
]}] ]]):gsub('\n', '')
@@ -1041,7 +1039,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 7, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1174,7 +1172,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 8, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1237,7 +1235,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
}, { { type = 9, timestamp = 0, data = { a = { 10 } } } })
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
@@ -1247,7 +1245,7 @@ describe('autoload/shada.vim', function()
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": 10}, []]',
+ ' = [{"a": 10}, []]',
}, { { type = 9, timestamp = 0, data = { { a = 10 }, {} } } })
sd2strings_eq({
'Buffer list with timestamp ' .. epoch .. ':',
@@ -1322,7 +1320,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 9, 'timestamp': 0, 'data': [
{'f': 10},
- {'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]}},
+ {'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]}},
]}] ]]):gsub('\n', '')
)
end)
@@ -1385,7 +1383,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 10, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1504,7 +1502,7 @@ describe('autoload/shada.vim', function()
},
([[ [{'type': 11, 'timestamp': 0, 'data': {
'n': -10,
- 'f': {'_TYPE': v:msgpack_types.binary, '_VAL': ["\n"]},
+ 'f': {'_TYPE': v:msgpack_types.string, '_VAL': ["\n"]},
}}] ]]):gsub('\n', '')
)
sd2strings_eq(
@@ -1616,7 +1614,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
c = 'abc',
- f = { '!binary', { 'abc\ndef' } },
+ f = { '!string', { 'abc\ndef' } },
l = -10,
n = -64,
rc = '10',
@@ -1711,7 +1709,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
c = 'abc',
- f = { '!binary', { 'abc\ndef' } },
+ f = { '!string', { 'abc\ndef' } },
l = -10,
n = -64,
rc = '10',
@@ -1892,7 +1890,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Replacement string with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq({ { type = 3, timestamp = 0, data = {} } }, {
'Replacement string with timestamp ' .. epoch .. ':',
@@ -1934,7 +1932,7 @@ describe('autoload/shada.vim', function()
} } }, {
'History entry with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq({ { type = 4, timestamp = 0, data = {} } }, {
'History entry with timestamp ' .. epoch .. ':',
@@ -2184,7 +2182,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Variable with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq({ { type = 6, timestamp = 0, data = {} } }, {
'Variable with timestamp ' .. epoch .. ':',
@@ -2315,7 +2313,7 @@ describe('autoload/shada.vim', function()
} } }, {
'Buffer list with timestamp ' .. epoch .. ':',
' # Unexpected type: map instead of array',
- ' = {="a": [10]}',
+ ' = {"a": [10]}',
})
strings2sd_eq(
{ { type = 9, timestamp = 0, data = {
@@ -2325,7 +2323,7 @@ describe('autoload/shada.vim', function()
{
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": 10}, []]',
+ ' = [{"a": 10}, []]',
}
)
strings2sd_eq({ { type = 9, timestamp = 0, data = {
@@ -2421,7 +2419,7 @@ describe('autoload/shada.vim', function()
timestamp = 0,
data = {
{ f = 10 },
- { f = { '!binary', { '\n' } } },
+ { f = { '!string', { '\n' } } },
},
},
}, {
@@ -2955,7 +2953,7 @@ describe('ftplugin/shada.vim', function()
' - :s replacement string "abc\\ndef"',
' Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- '= [{="a": 10}, []]',
+ '= [{"a": 10}, []]',
' Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
' # Expected binary string',
@@ -2992,7 +2990,7 @@ describe('ftplugin/shada.vim', function()
' - :s replacement string "abc\\ndef"',
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": 10}, []]',
+ ' = [{"a": 10}, []]',
'Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
' # Expected binary string',
@@ -3083,7 +3081,7 @@ describe('syntax/shada.vim', function()
' - :s replacement string DEBUG',
'Buffer list with timestamp ' .. epoch .. ':',
' # Expected array of maps',
- ' = [{="a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]',
+ ' = [{"a": +(10)"ac\\0df\\ngi\\"tt\\.", TRUE: FALSE}, [NIL, +(-10)""]]',
'Buffer list with timestamp ' .. epoch .. ':',
' % Key Description Value',
'',
@@ -3119,8 +3117,8 @@ describe('syntax/shada.vim', function()
{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:[{"}{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:-1}|
+ {5:0}{1:)""]]} |
{1:Buffer list} with timestamp 1970{1:-}01{1:-}01{1:T}00{1::}00{1::}00: |
{2: % Key Description Value} |
|
@@ -3464,7 +3462,6 @@ describe('syntax/shada.vim', function()
{ { 'ShaDaEntryRawMsgpack' }, ' = ' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackArrayBraces' }, '[' },
{ { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackMapBraces' }, '{' },
- { { 'ShaDaMsgpackArray', 'ShaDaMsgpackMap', 'ShaDaMsgpackString' }, '=' },
{
{
'ShaDaMsgpackArray',
diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua
index 200a5f34b2..1d05f4d6b4 100644
--- a/test/functional/plugin/tohtml_spec.lua
+++ b/test/functional/plugin/tohtml_spec.lua
@@ -33,6 +33,10 @@ local function html_syntax_match()
attr.underline = nil
attr.undercurl = true
end
+ attr.sp = style:match('text%-decoration%-color: #(%x+)')
+ if attr.sp then
+ attr.sp = tonumber(attr.sp, 16)
+ end
attr.bg = style:match('background%-color: #(%x+)')
if attr.bg then
attr.bg = tonumber(attr.bg, 16)
@@ -49,7 +53,7 @@ local function html_syntax_match()
local whitelist = {
'fg',
'bg',
- --'sp',
+ 'sp',
--'blend',
'bold',
--'standout',
@@ -132,6 +136,50 @@ local function run_tohtml_and_assert(screen, func)
screen:expect({ grid = expected.grid, attr_ids = expected.attr_ids })
end
+---@param guifont boolean
+local function test_generates_html(guifont, expect_font)
+ insert([[line]])
+ exec('set termguicolors')
+ local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
+ local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
+ local tmpfile = t.tmpname()
+
+ exec_lua(
+ [[
+ local guifont, outfile = ...
+ local html = (guifont
+ and require('tohtml').tohtml(0,{title="title"})
+ or require('tohtml').tohtml(0,{title="title",font={ "dumyfont","anotherfont" }}))
+ vim.fn.writefile(html, outfile)
+ vim.cmd.split(outfile)
+ ]],
+ guifont,
+ tmpfile
+ )
+
+ local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
+ eq({
+ '<!DOCTYPE html>',
+ '<html>',
+ '<head>',
+ '<meta charset="UTF-8">',
+ '<title>title</title>',
+ ('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
+ '<style>',
+ ('* {font-family: %s,monospace}'):format(expect_font),
+ ('body {background-color: %s; color: %s}'):format(bg, fg),
+ '</style>',
+ '</head>',
+ '<body style="display: flex">',
+ '<pre>',
+ 'line',
+ '',
+ '</pre>',
+ '</body>',
+ '</html>',
+ }, fn.readfile(out_file))
+end
+
describe(':TOhtml', function()
--- @type test.functional.ui.screen
local screen
@@ -142,33 +190,44 @@ describe(':TOhtml', function()
exec('colorscheme default')
end)
- it('expected internal html generated', function()
- insert([[line]])
+ it('generates html with given font', function()
+ test_generates_html(false, '"dumyfont","anotherfont"')
+ end)
+
+ it("generates html, respects 'guifont'", function()
+ exec_lua [[vim.o.guifont='Font,Escape\\,comma, Ignore space after comma']]
+ test_generates_html(true, '"Font","Escape,comma","Ignore space after comma"')
+ end)
+
+ it('generates html from range', function()
+ insert([[
+ line1
+ line2
+ line3
+ ]])
+ local ns = api.nvim_create_namespace ''
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { end_col = 1, end_row = 1, hl_group = 'Visual' })
exec('set termguicolors')
local bg = fn.synIDattr(fn.hlID('Normal'), 'bg#', 'gui')
local fg = fn.synIDattr(fn.hlID('Normal'), 'fg#', 'gui')
- exec_lua [[
- local outfile = vim.fn.tempname() .. '.html'
- local html = require('tohtml').tohtml(0,{title="title",font="dumyfont"})
- vim.fn.writefile(html, outfile)
- vim.cmd.split(outfile)
- ]]
+ n.command('2,2TOhtml')
local out_file = api.nvim_buf_get_name(api.nvim_get_current_buf())
eq({
'<!DOCTYPE html>',
'<html>',
'<head>',
'<meta charset="UTF-8">',
- '<title>title</title>',
+ '<title></title>',
('<meta name="colorscheme" content="%s"></meta>'):format(api.nvim_get_var('colors_name')),
'<style>',
- '* {font-family: dumyfont,monospace}',
+ '* {font-family: monospace}',
('body {background-color: %s; color: %s}'):format(bg, fg),
+ '.Visual {background-color: #9b9ea4}',
'</style>',
'</head>',
'<body style="display: flex">',
- '<pre>',
- 'line',
+ '<pre><span class="Visual">',
+ 'l</span>ine2',
'',
'</pre>',
'</body>',
@@ -176,9 +235,9 @@ describe(':TOhtml', function()
}, fn.readfile(out_file))
end)
- it('highlight attributes generated', function()
+ it('generates highlight attributes', function()
--Make sure to uncomment the attribute in `html_syntax_match()`
- exec('hi LINE gui=' .. table.concat({
+ exec('hi LINE guisp=#00ff00 gui=' .. table.concat({
'bold',
'underline',
'italic',
@@ -287,7 +346,13 @@ describe(':TOhtml', function()
0,
{ virt_text = { { 'foo' } }, virt_text_pos = 'overlay' }
)
- api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' })
+ api.nvim_buf_set_extmark(
+ 0,
+ ns,
+ 2,
+ 0,
+ { virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' }
+ )
--api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'})
run_tohtml_and_assert(screen)
end)
@@ -341,12 +406,12 @@ describe(':TOhtml', function()
local function run()
local buf = api.nvim_get_current_buf()
run_tohtml_and_assert(screen, function()
- exec_lua [[
- local outfile = vim.fn.tempname() .. '.html'
- local html = require('tohtml').tohtml(0,{number_lines=true})
- vim.fn.writefile(html, outfile)
- vim.cmd.split(outfile)
- ]]
+ exec_lua(function()
+ local outfile = vim.fn.tempname() .. '.html'
+ local html = require('tohtml').tohtml(0, { number_lines = true })
+ vim.fn.writefile(html, outfile)
+ vim.cmd.split(outfile)
+ end)
end)
api.nvim_set_current_buf(buf)
end
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 9e7df0ba6b..1094f9f4e5 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -94,12 +94,6 @@ describe('clipboard', function()
before_each(function()
clear()
screen = Screen.new(72, 4)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- [2] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- [3] = { bold = true, reverse = true },
- })
screen:attach()
end)
@@ -114,13 +108,13 @@ describe('clipboard', function()
feed('"+yl')
screen:expect([[
^a |
- {0:~ }|*2
+ {1:~ }|*2
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
]])
feed('"+p')
screen:expect([[
a^a |
- {0:~ }|*2
+ {1:~ }|*2
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
]])
end)
@@ -132,19 +126,19 @@ describe('clipboard', function()
feed('yl')
screen:expect([[
^a |
- {0:~ }|*2
+ {1:~ }|*2
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
]])
feed(':<CR>')
screen:expect([[
^a |
- {0:~ }|*2
+ {1:~ }|*2
: |
]])
feed('p')
screen:expect([[
a^a |
- {0:~ }|*2
+ {1:~ }|*2
: |
]])
end)
@@ -154,7 +148,7 @@ describe('clipboard', function()
feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END')
screen:expect([[
^ |
- {0:~ }|*2
+ {1:~ }|*2
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
]])
end)
@@ -166,8 +160,8 @@ describe('clipboard', function()
grid = [[
{3: }|
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
- {1:E492: Not an editor command: bogus_cmd | redir END} |
- {2:Press ENTER or type command to continue}^ |
+ {9:E492: Not an editor command: bogus_cmd | redir END} |
+ {6:Press ENTER or type command to continue}^ |
]],
}
end)
@@ -182,7 +176,7 @@ describe('clipboard', function()
feed_command('let @+="foo"')
screen:expect([[
^ |
- {0:~ }|*2
+ {1:~ }|*2
clipboard: No provider. Try ":checkhealth" or ":h clipboard". |
]])
end)
@@ -325,15 +319,11 @@ describe('clipboard (with fake clipboard.vim)', function()
it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184', function()
local screen = Screen.new(72, 4)
screen:attach()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
- })
feed_command('redir @+> | bogus_cmd | redir END')
screen:expect([[
^ |
- {0:~ }|*2
- {1:E492: Not an editor command: bogus_cmd | redir END} |
+ {1:~ }|*2
+ {9:E492: Not an editor command: bogus_cmd | redir END} |
]])
end)
@@ -719,9 +709,6 @@ describe('clipboard (with fake clipboard.vim)', function()
feed_command('set mouse=a')
local screen = Screen.new(30, 5)
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue },
- })
screen:attach()
insert([[
the source
@@ -731,7 +718,7 @@ describe('clipboard (with fake clipboard.vim)', function()
screen:expect([[
the ^source |
a target |
- {0:~ }|*2
+ {1:~ }|*2
|
]])
diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua
index 6d444e1888..8bc55879d4 100644
--- a/test/functional/script/luacats_grammar_spec.lua
+++ b/test/functional/script/luacats_grammar_spec.lua
@@ -159,4 +159,129 @@ describe('luacats grammar', function()
name = 'type',
type = '`T`',
})
+
+ test('@param type [number,string,"good"|"bad"] this is a tuple type', {
+ desc = 'this is a tuple type',
+ kind = 'param',
+ name = 'type',
+ type = '[number,string,"good"|"bad"]',
+ })
+
+ test('@class vim.diagnostic.JumpOpts', {
+ kind = 'class',
+ name = 'vim.diagnostic.JumpOpts',
+ })
+
+ test('@class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts', {
+ kind = 'class',
+ name = 'vim.diagnostic.JumpOpts',
+ parent = 'vim.diagnostic.GetOpts',
+ })
+
+ test('@param opt? { cmd?: string[] } Options', {
+ kind = 'param',
+ name = 'opt?',
+ type = '{ cmd?: string[] }',
+ desc = 'Options',
+ })
+
+ ---@type [string, string?][]
+ local test_cases = {
+ { 'foo' },
+ { 'foo ', 'foo' }, -- trims whitespace
+ { 'true' },
+ { 'vim.type' },
+ { 'vim-type' },
+ { 'vim_type' },
+ { 'foo.bar-baz_baz' },
+ { '`ABC`' },
+ { '42' },
+ { '-42' },
+ { '(foo)', 'foo' }, -- removes unnecessary parens
+ { 'true?' },
+ { '(true)?' },
+ { 'string[]' },
+ { 'string|number' },
+ { '(string)[]' },
+ { '(string|number)[]' },
+ { 'coalesce??', 'coalesce?' }, -- removes unnecessary ?
+ { 'number?|string' },
+ { "'foo'|'bar'|'baz'" },
+ { '"foo"|"bar"|"baz"' },
+ { '(number)?|string' }, --
+ { 'number[]|string' },
+ { 'string[]?' },
+ { 'foo?[]' },
+ { 'vim.type?|string? ', 'vim.type?|string?' },
+ { 'number[][]' },
+ { 'number[][][]' },
+ { 'number[][]?' },
+ { 'string|integer[][]?' },
+
+ -- tuples
+ { '[string]' },
+ { '[1]' },
+ { '[string, number]' },
+ { '[string, number]?' },
+ { '[string, number][]' },
+ { '[string, number]|string' },
+ { '[string|number, number?]' },
+ { 'string|[string, number]' },
+ { '(true)?|[foo]' },
+ { '[fun(a: string):boolean]' },
+
+ -- dict
+ { '{[string]:string}' },
+ { '{ [ string ] : string }' },
+ { '{ [ string|any ] : string }' },
+ { '{[string]: string, [number]: boolean}' },
+
+ -- key-value table
+ { 'table<string,any>' },
+ { 'table' },
+ { 'string|table|boolean' },
+ { 'string|table|(boolean)' },
+
+ -- table literal
+ { '{foo: number}' },
+ { '{foo: string, bar: [number, boolean]?}' },
+ { 'boolean|{reverse?:boolean}' },
+ { '{ cmd?: string[] }' },
+
+ -- function
+ { 'fun(a: string, b:foo|bar): string' },
+ { 'fun(a?: string): string' },
+ { 'fun(a?: string): number?,string?' },
+ { '(fun(a: string, b:foo|bar): string)?' },
+ { 'fun(a: string, b:foo|bar): string, string' },
+ { 'fun(a: string, b:foo|bar)' },
+ { 'fun(_, foo, bar): string' },
+ { 'fun(...): number' },
+ { 'fun( ... ): number' },
+ { 'fun(...:number): number' },
+ { 'fun( ... : number): number' },
+
+ -- generics
+ { 'elem_or_list<string>' },
+ {
+ 'elem_or_list<fun(client: vim.lsp.Client, initialize_result: lsp.InitializeResult)>',
+ nil,
+ },
+ }
+
+ for _, tc in ipairs(test_cases) do
+ local ty, exp_ty = tc[1], tc[2]
+ if exp_ty == nil then
+ exp_ty = ty
+ end
+
+ local var, desc = 'x', 'some desc'
+ local param = string.format('@param %s %s %s', var, ty, desc)
+ test(param, {
+ kind = 'param',
+ name = var,
+ type = exp_ty,
+ desc = desc,
+ })
+ end
end)
diff --git a/test/functional/script/text_utils_spec.lua b/test/functional/script/text_utils_spec.lua
index 176c2ef816..74098b9287 100644
--- a/test/functional/script/text_utils_spec.lua
+++ b/test/functional/script/text_utils_spec.lua
@@ -11,8 +11,8 @@ local function md_to_vimdoc(text, start_indent, indent, text_width)
start_indent = start_indent or 0
indent = indent or 0
text_width = text_width or 70
- local text_utils = require('scripts/text_utils')
- return text_utils.md_to_vimdoc(table.concat(text, '\n'), start_indent, indent, text_width)
+ local util = require('scripts/util')
+ return util.md_to_vimdoc(table.concat(text, '\n'), start_indent, indent, text_width)
]],
text,
start_indent,
diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua
index a9084da929..0016e0bdf9 100644
--- a/test/functional/shada/errors_spec.lua
+++ b/test/functional/shada/errors_spec.lua
@@ -28,7 +28,7 @@ describe('ShaDa error handling', function()
it('fails on zero', function()
wshada('\000')
eq(
- 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0, but got nothing',
+ 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 1, but got nothing',
exc_exec(sdrcmd())
)
end)
@@ -58,7 +58,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with zero length', function()
wshada('\002\000\000')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict',
exc_exec(sdrcmd())
)
end)
@@ -89,18 +89,10 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with invalid byte', function()
-- 195 (== 0xC1) cannot start any valid messagepack entry (the only byte
- -- that cannot do this). Specifically unpack_template.h contains
- --
- -- //case 0xc1: // string
- -- // again_terminal_trail(NEXT_CS(p), p+1);
- --
- -- (literally: commented out code) which means that in place of this code
- -- `goto _failed` is used from default: case. I do not know any other way to
- -- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or
- -- MSGPACK_UNPACK_EXTRA_BYTES.
+ -- that cannot do this)
wshada('\002\000\001\193')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file due to a msgpack parser error at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict',
exc_exec(sdrcmd())
)
end)
@@ -108,7 +100,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with incomplete map', function()
wshada('\002\000\001\129')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key value which is not a string',
exc_exec(sdrcmd())
)
end)
@@ -124,7 +116,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern with extra bytes', function()
wshada('\002\000\002\128\000')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file: extra bytes in msgpack string at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has no pattern',
exc_exec(sdrcmd())
)
end)
@@ -132,16 +124,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with NIL value', function()
wshada('\002\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary',
- exc_exec(sdrcmd())
- )
- end)
-
- -- sp entry is here because it causes an allocation.
- it('fails on search pattern item with BIN key', function()
- wshada('\002\000\014\131\162sp\196\001a\162sX\192\196\000\000')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key which is not a string',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dict',
exc_exec(sdrcmd())
)
end)
@@ -235,35 +218,16 @@ describe('ShaDa error handling', function()
)
end)
- it('fails on search pattern item with STR pat key value', function()
- wshada('\002\000\011\130\162sX\192\162sp\162sp')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sp key value which is not a binary',
- exc_exec(sdrcmd())
- )
- end)
-
for _, v in ipairs({
{ name = 'global mark', mpack = '\007' },
{ name = 'jump', mpack = '\008' },
{ name = 'local mark', mpack = '\010' },
{ name = 'change', mpack = '\011' },
}) do
- local is_mark_test = ({ ['global mark'] = true, ['local mark'] = true })[v.name]
-
it('fails on ' .. v.name .. ' item with NIL value', function()
wshada(v.mpack .. '\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dictionary',
- exc_exec(sdrcmd())
- )
- end)
-
- -- f entry is here because it causes an allocation.
- it('fails on ' .. v.name .. ' item with BIN key', function()
- wshada(v.mpack .. '\000\013\131\161f\196\001/\162mX\192\196\000\000')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has key which is not a string',
+ 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 is not a dict',
exc_exec(sdrcmd())
)
end)
@@ -312,9 +276,7 @@ describe('ShaDa error handling', function()
it('fails on ' .. v.name .. ' item with STR n key value', function()
wshada(v.mpack .. '\000\011\130\162mX\192\161n\163spa')
eq(
- is_mark_test
- and 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an unsigned integer'
- or 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key which is only valid for local and global mark entries',
+ 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -334,29 +296,12 @@ describe('ShaDa error handling', function()
exc_exec(sdrcmd())
)
end)
-
- it('fails on ' .. v.name .. ' item with STR f key value', function()
- wshada(v.mpack .. '\000\010\130\162mX\192\161f\162sp')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has f key value which is not a binary',
- exc_exec(sdrcmd())
- )
- end)
end
it('fails on register item with NIL value', function()
wshada('\005\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dictionary',
- exc_exec(sdrcmd())
- )
- end)
-
- -- rc entry is here because it causes an allocation
- it('fails on register item with BIN key', function()
- wshada('\005\000\015\131\162rc\145\196\001a\162rX\192\196\000\000')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has key which is not a string',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 is not a dict',
exc_exec(sdrcmd())
)
end)
@@ -373,7 +318,7 @@ describe('ShaDa error handling', function()
it('fails on register item with NIL rt key value', function()
wshada('\005\000\009\130\162rX\192\162rt\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an unsigned integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -381,7 +326,7 @@ describe('ShaDa error handling', function()
it('fails on register item with NIL rw key value', function()
wshada('\005\000\009\130\162rX\192\162rw\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an unsigned integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -397,7 +342,7 @@ describe('ShaDa error handling', function()
it('fails on register item with empty rc key value', function()
wshada('\005\000\009\130\162rX\192\162rc\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with empty array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array',
exc_exec(sdrcmd())
)
end)
@@ -413,7 +358,7 @@ describe('ShaDa error handling', function()
it('fails on register item without rc array', function()
wshada('\005\000\009\129\162rX\146\196\001a\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has missing rc array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array',
exc_exec(sdrcmd())
)
end)
@@ -421,7 +366,7 @@ describe('ShaDa error handling', function()
it('fails on history item with NIL value', function()
wshada('\004\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -429,7 +374,7 @@ describe('ShaDa error handling', function()
it('fails on history item with empty value', function()
wshada('\004\000\001\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -437,7 +382,7 @@ describe('ShaDa error handling', function()
it('fails on history item with single element value', function()
wshada('\004\000\002\145\000')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -485,7 +430,7 @@ describe('ShaDa error handling', function()
it('fails on variable item with NIL value', function()
wshada('\006\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -493,7 +438,7 @@ describe('ShaDa error handling', function()
it('fails on variable item with empty value', function()
wshada('\006\000\001\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -501,7 +446,7 @@ describe('ShaDa error handling', function()
it('fails on variable item with single element value', function()
wshada('\006\000\002\145\000')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -525,7 +470,7 @@ describe('ShaDa error handling', function()
it('fails on replacement item with NIL value', function()
wshada('\003\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -533,7 +478,7 @@ describe('ShaDa error handling', function()
it('fails on replacement item with empty value', function()
wshada('\003\000\001\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -559,7 +504,7 @@ describe('ShaDa error handling', function()
nvim_command('set shada+=%')
wshada('\009\000\008\146\129\161f\196\001/\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dictionary',
+ 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that is not a dict',
exc_exec(sdrcmd())
)
end)
@@ -577,7 +522,7 @@ describe('ShaDa error handling', function()
nvim_command('set shada+=%')
wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has l key value which is not an integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has l key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -613,7 +558,7 @@ describe('ShaDa error handling', function()
nvim_command('set shada+=%')
wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161c\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has c key value which is not an integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has c key value which is not an integer',
exc_exec(sdrcmd())
)
end)
diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua
index 12c8615799..4a61e0203d 100644
--- a/test/functional/terminal/altscreen_spec.lua
+++ b/test/functional/terminal/altscreen_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local clear, eq, api = n.clear, t.eq, n.api
local feed = n.feed
local feed_data = tt.feed_data
@@ -17,7 +17,7 @@ describe(':terminal altscreen', function()
before_each(function()
clear()
- screen = tt.screen_setup()
+ screen = tt.setup_screen()
feed_data({
'line1',
'line2',
diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index 1f10dda551..b550df80c3 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local ok = t.ok
if t.skip(t.is_os('win')) then
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 96abd9f543..7a30367917 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local assert_alive = n.assert_alive
local feed, clear = n.feed, n.clear
@@ -29,7 +29,7 @@ describe(':terminal buffer', function()
before_each(function()
clear()
command('set modifiable swapfile undolevels=20')
- screen = tt.screen_setup()
+ screen = tt.setup_screen()
end)
it('terminal-mode forces various options', function()
@@ -199,7 +199,7 @@ describe(':terminal buffer', function()
{5:========== }|
rows: 2, cols: 50 |
{2: } |
- {1:========== }|
+ {18:========== }|
|
]])
@@ -312,6 +312,16 @@ describe(':terminal buffer', function()
pcall_err(command, 'write test/functional/fixtures/tty-test.c')
)
end)
+
+ it('external interrupt (got_int) does not hang #20726', function()
+ eq({ mode = 't', blocking = false }, api.nvim_get_mode())
+ command('call timer_start(0, {-> interrupt()})')
+ feed('<Ignore>') -- Add input to separate two RPC requests
+ eq({ mode = 't', blocking = false }, api.nvim_get_mode())
+ feed([[<C-\><C-N>]])
+ eq({ mode = 'nt', blocking = false }, api.nvim_get_mode())
+ command('bd!')
+ end)
end)
describe(':terminal buffer', function()
@@ -332,7 +342,7 @@ describe(':terminal buffer', function()
command('wincmd p')
-- cwd will be inserted in a file URI, which cannot contain backs
- local cwd = fn.getcwd():gsub('\\', '/')
+ local cwd = t.fix_slashes(fn.getcwd())
local parent = cwd:match('^(.+/)')
local expected = '\027]7;file://host' .. parent
api.nvim_chan_send(term, string.format('%s\027\\', expected))
@@ -340,7 +350,7 @@ describe(':terminal buffer', function()
eq(termbuf, eval('g:termbuf'))
end)
- it('TermReqeust synchronization #27572', function()
+ it('TermRequest synchronization #27572', function()
command('autocmd! nvim_terminal TermRequest')
local term = exec_lua([[
_G.input = {}
@@ -564,7 +574,7 @@ if is_os('win') then
feed_command('set modifiable swapfile undolevels=20')
poke_eventloop()
local cmd = { 'cmd.exe', '/K', 'PROMPT=$g$s' }
- screen = tt.screen_setup(nil, cmd)
+ screen = tt.setup_screen(nil, cmd)
end)
it('"put" operator sends data normally', function()
diff --git a/test/functional/terminal/clipboard_spec.lua b/test/functional/terminal/clipboard_spec.lua
new file mode 100644
index 0000000000..4a1a0e29fd
--- /dev/null
+++ b/test/functional/terminal/clipboard_spec.lua
@@ -0,0 +1,65 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+local eq = t.eq
+local retry = t.retry
+
+local clear = n.clear
+local fn = n.fn
+local testprg = n.testprg
+local exec_lua = n.exec_lua
+local eval = n.eval
+
+describe(':terminal', function()
+ before_each(function()
+ clear()
+
+ exec_lua([[
+ local function clipboard(reg, type)
+ if type == 'copy' then
+ return function(lines)
+ local data = table.concat(lines, '\n')
+ vim.g.clipboard_data = data
+ end
+ end
+
+ if type == 'paste' then
+ return function()
+ error()
+ end
+ end
+
+ error('invalid type: ' .. type)
+ end
+
+ vim.g.clipboard = {
+ name = 'Test',
+ copy = {
+ ['+'] = clipboard('+', 'copy'),
+ ['*'] = clipboard('*', 'copy'),
+ },
+ paste = {
+ ['+'] = clipboard('+', 'paste'),
+ ['*'] = clipboard('*', 'paste'),
+ },
+ }
+ ]])
+ end)
+
+ it('can write to the system clipboard', function()
+ eq('Test', eval('g:clipboard.name'))
+
+ local text = 'Hello, world! This is some\nexample text\nthat spans multiple\nlines'
+ local encoded = exec_lua('return vim.base64.encode(...)', text)
+
+ local function osc52(arg)
+ return string.format('\027]52;;%s\027\\', arg)
+ end
+
+ fn.termopen({ testprg('shell-test'), '-t', osc52(encoded) })
+
+ retry(nil, 1000, function()
+ eq(text, exec_lua([[ return vim.g.clipboard_data ]]))
+ end)
+ end)
+end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index 51c6b12e62..0c5de45829 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear
local testprg, command = n.testprg, n.command
@@ -18,7 +18,7 @@ describe(':terminal cursor', function()
before_each(function()
clear()
- screen = tt.screen_setup()
+ screen = tt.setup_screen()
end)
it('moves the screen cursor when focused', function()
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 4f3d010d02..05d68f6754 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear
local api = n.api
@@ -380,3 +380,23 @@ describe(':terminal highlight with custom palette', function()
]])
end)
end)
+
+describe(':terminal', function()
+ before_each(clear)
+
+ it('can display URLs', function()
+ local screen = Screen.new(50, 7)
+ screen:add_extra_attr_ids {
+ [100] = { url = 'https://example.com' },
+ }
+ screen:attach()
+ local chan = api.nvim_open_term(0, {})
+ api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\')
+ screen:expect({
+ grid = [[
+ {100:^Example} |
+ |*6
+ ]],
+ })
+ end)
+end)
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index ad98dfc6c3..38d6b83417 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local clear, eq, eval = n.clear, t.eq, n.eval
local feed, api, command = n.feed, n.api, n.command
local feed_data = tt.feed_data
@@ -14,10 +14,12 @@ describe(':terminal mouse', function()
before_each(function()
clear()
api.nvim_set_option_value('statusline', '==========', {})
- command('highlight StatusLine cterm=NONE')
- command('highlight StatusLineNC cterm=NONE')
- command('highlight VertSplit cterm=NONE')
- screen = tt.screen_setup()
+ screen = tt.setup_screen()
+ command('highlight StatusLine NONE')
+ command('highlight StatusLineNC NONE')
+ command('highlight StatusLineTerm NONE')
+ command('highlight StatusLineTermNC NONE')
+ command('highlight VertSplit NONE')
local lines = {}
for i = 1, 30 do
table.insert(lines, 'line' .. tostring(i))
diff --git a/test/functional/terminal/parser_spec.lua b/test/functional/terminal/parser_spec.lua
new file mode 100644
index 0000000000..67f47c7888
--- /dev/null
+++ b/test/functional/terminal/parser_spec.lua
@@ -0,0 +1,15 @@
+local n = require('test.functional.testnvim')()
+
+local clear = n.clear
+local api = n.api
+local assert_alive = n.assert_alive
+
+describe(':terminal', function()
+ before_each(clear)
+
+ it('handles invalid OSC terminators #30084', function()
+ local chan = api.nvim_open_term(0, {})
+ api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\n')
+ assert_alive()
+ end)
+end)
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 229a169996..da0bd97270 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local clear, eq = n.clear, t.eq
local feed, testprg = n.feed, n.testprg
@@ -22,7 +22,7 @@ describe(':terminal scrollback', function()
before_each(function()
clear()
- screen = tt.screen_setup(nil, nil, 30)
+ screen = tt.setup_screen(nil, nil, 30)
end)
describe('when the limit is exceeded', function()
@@ -399,9 +399,9 @@ describe("'scrollback' option", function()
it('set to 0 behaves as 1', function()
local screen
if is_os('win') then
- screen = tt.screen_setup(nil, { 'cmd.exe' }, 30)
+ screen = tt.setup_screen(nil, { 'cmd.exe' }, 30)
else
- screen = tt.screen_setup(nil, { 'sh' }, 30)
+ screen = tt.setup_screen(nil, { 'sh' }, 30)
end
api.nvim_set_option_value('scrollback', 0, {})
@@ -416,10 +416,10 @@ describe("'scrollback' option", function()
local screen
if is_os('win') then
command([[let $PROMPT='$$']])
- screen = tt.screen_setup(nil, { 'cmd.exe' }, 30)
+ screen = tt.setup_screen(nil, { 'cmd.exe' }, 30)
else
command('let $PS1 = "$"')
- screen = tt.screen_setup(nil, { 'sh' }, 30)
+ screen = tt.setup_screen(nil, { 'sh' }, 30)
end
api.nvim_set_option_value('scrollback', 200, {})
@@ -480,8 +480,8 @@ describe("'scrollback' option", function()
end)
it('deletes extra lines immediately', function()
- -- Scrollback is 10 on screen_setup
- local screen = tt.screen_setup(nil, nil, 30)
+ -- Scrollback is 10 on setup_screen
+ local screen = tt.setup_screen(nil, nil, 30)
local lines = {}
for i = 1, 30 do
table.insert(lines, 'line' .. tostring(i))
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index d4628ea626..a7d87bb231 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -7,7 +7,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local eq = t.eq
local feed_data = tt.feed_data
@@ -40,8 +40,8 @@ if t.skip(is_os('win')) then
end
describe('TUI', function()
- local screen
- local child_session
+ local screen --[[@type test.functional.ui.screen]]
+ local child_session --[[@type test.Session]]
local child_exec_lua
before_each(function()
@@ -630,6 +630,8 @@ describe('TUI', function()
set mouse=a mousemodel=popup
aunmenu PopUp
+ " Delete the default MenuPopup event handler.
+ autocmd! nvim_popupmenu
menu PopUp.foo :let g:menustr = 'foo'<CR>
menu PopUp.bar :let g:menustr = 'bar'<CR>
menu PopUp.baz :let g:menustr = 'baz'<CR>
@@ -973,6 +975,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
feed_data('\027[201~') -- End paste.
+ screen:expect_unchanged()
feed_data('\027[27u') -- ESC: go to Normal mode.
wait_for_mode('n')
screen:expect([[
@@ -1056,6 +1059,11 @@ describe('TUI', function()
if is_ci('github') then
pending('tty-test complains about not owning the terminal -- actions/runner#241')
end
+ screen:set_default_attr_ids({
+ [1] = { reverse = true }, -- focused cursor
+ [3] = { bold = true },
+ [19] = { bold = true, background = 121, foreground = 0 }, -- StatusLineTerm
+ })
child_exec_lua('vim.o.statusline="^^^^^^^"')
child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
feed_data('i')
@@ -1063,7 +1071,7 @@ describe('TUI', function()
tty ready |
{1: } |
|*2
- {5:^^^^^^^ }|
+ {19:^^^^^^^ }|
{3:-- TERMINAL --} |*2
]])
feed_data('\027[200~')
@@ -1073,7 +1081,7 @@ describe('TUI', function()
tty ready |
hallo{1: } |
|*2
- {5:^^^^^^^ }|
+ {19:^^^^^^^ }|
{3:-- TERMINAL --} |*2
]])
end)
@@ -1099,7 +1107,7 @@ describe('TUI', function()
screen:expect(expected_grid1)
-- Dot-repeat/redo.
feed_data('.')
- screen:expect([[
+ local expected_grid2 = [[
ESC:{6:^[} / CR: |
xline 1 |
ESC:{6:^[} / CR: |
@@ -1107,7 +1115,8 @@ describe('TUI', function()
{5:[No Name] [+] 5,1 Bot}|
|
{3:-- TERMINAL --} |
- ]])
+ ]]
+ screen:expect(expected_grid2)
-- Undo.
feed_data('u')
expect_child_buf_lines(expected_crlf)
@@ -1121,6 +1130,14 @@ describe('TUI', function()
feed_data('\027[200~' .. table.concat(expected_lf, '\r\n') .. '\027[201~')
screen:expect(expected_grid1)
expect_child_buf_lines(expected_crlf)
+ -- Dot-repeat/redo.
+ feed_data('.')
+ screen:expect(expected_grid2)
+ -- Undo.
+ feed_data('u')
+ expect_child_buf_lines(expected_crlf)
+ feed_data('u')
+ expect_child_buf_lines({ '' })
end)
it('paste: cmdline-mode inserts 1 line', function()
@@ -1184,6 +1201,7 @@ describe('TUI', function()
expect_cmdline('"stuff 1 more"')
-- End the paste sequence.
feed_data('\027[201~')
+ expect_cmdline('"stuff 1 more"')
feed_data(' typed')
expect_cmdline('"stuff 1 more typed"')
end)
@@ -1227,6 +1245,7 @@ describe('TUI', function()
feed_data('line 7\nline 8\n')
-- Stop paste.
feed_data('\027[201~')
+ screen:expect_unchanged()
feed_data('\n') -- <CR> to dismiss hit-enter prompt
expect_child_buf_lines({ 'foo', '' })
-- Dot-repeat/redo is not modified by failed paste.
@@ -1274,10 +1293,46 @@ describe('TUI', function()
{}
)
feed_data('\027[200~line A\nline B\n\027[201~')
+ expect_child_buf_lines({ '' })
feed_data('ifoo\n\027[27u')
expect_child_buf_lines({ 'foo', '' })
end)
+ it('paste: vim.paste() cancel (retval=false) with streaming #30462', function()
+ child_session:request(
+ 'nvim_exec_lua',
+ [[
+ vim.paste = (function(overridden)
+ return function(lines, phase)
+ for i, line in ipairs(lines) do
+ if line:find('!') then
+ return false
+ end
+ end
+ return overridden(lines, phase)
+ end
+ end)(vim.paste)
+ ]],
+ {}
+ )
+ feed_data('A')
+ wait_for_mode('i')
+ feed_data('\027[200~aaa')
+ expect_child_buf_lines({ 'aaa' })
+ feed_data('bbb')
+ expect_child_buf_lines({ 'aaabbb' })
+ feed_data('ccc!') -- This chunk is cancelled.
+ expect_child_buf_lines({ 'aaabbb' })
+ feed_data('ddd\027[201~') -- This chunk is ignored.
+ expect_child_buf_lines({ 'aaabbb' })
+ feed_data('\027[27u')
+ wait_for_mode('n')
+ feed_data('.') -- Dot-repeat only includes chunks actually pasted.
+ expect_child_buf_lines({ 'aaabbbaaabbb' })
+ feed_data('$\027[200~eee\027[201~') -- A following paste works normally.
+ expect_child_buf_lines({ 'aaabbbaaabbbeee' })
+ end)
+
it("paste: 'nomodifiable' buffer", function()
child_session:request('nvim_command', 'set nomodifiable')
child_session:request(
@@ -1396,7 +1451,6 @@ describe('TUI', function()
feed_data('\n')
-- Send the "stop paste" sequence.
feed_data('\027[201~')
-
screen:expect([[
|
pasted from terminal (1) |
@@ -1548,10 +1602,32 @@ describe('TUI', function()
screen:set_rgb_cterm(true)
screen:set_default_attr_ids({
[1] = { { reverse = true }, { reverse = true } },
- [2] = { { bold = true, reverse = true }, { bold = true, reverse = true } },
+ [2] = {
+ { bold = true, background = Screen.colors.LightGreen, foreground = Screen.colors.Black },
+ { bold = true },
+ },
[3] = { { bold = true }, { bold = true } },
[4] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
[5] = { { foreground = tonumber('0xff8000') }, {} },
+ [6] = {
+ {
+ fg_indexed = true,
+ bg_indexed = true,
+ bold = true,
+ background = tonumber('0x66ff99'),
+ foreground = Screen.colors.Black,
+ },
+ { bold = true, background = 121, foreground = 0 },
+ },
+ [7] = {
+ {
+ fg_indexed = true,
+ bg_indexed = true,
+ background = tonumber('0x66ff99'),
+ foreground = Screen.colors.Black,
+ },
+ { background = 121, foreground = 0 },
+ },
})
child_exec_lua('vim.o.statusline="^^^^^^^"')
@@ -1586,7 +1662,7 @@ describe('TUI', function()
{1:t}ty ready |
{4:text}colortext |
|*2
- {2:^^^^^^^ }|
+ {6:^^^^^^^}{7: }|
:set notermguicolors |
{3:-- TERMINAL --} |
]],
@@ -1622,12 +1698,13 @@ describe('TUI', function()
]])
end)
- it('in nvim_list_uis()', function()
+ it('in nvim_list_uis(), sets nvim_set_client_info()', function()
-- $TERM in :terminal.
local exp_term = is_os('bsd') and 'builtin_xterm' or 'xterm-256color'
+ local ui_chan = 1
local expected = {
{
- chan = 1,
+ chan = ui_chan,
ext_cmdline = false,
ext_hlstate = false,
ext_linegrid = true,
@@ -1650,6 +1727,43 @@ describe('TUI', function()
}
local _, rv = child_session:request('nvim_list_uis')
eq(expected, rv)
+
+ ---@type table
+ local expected_version = ({
+ child_session:request('nvim_exec_lua', 'return vim.version()', {}),
+ })[2]
+ -- vim.version() returns `prerelease` string. Coerce it to boolean.
+ expected_version.prerelease = not not expected_version.prerelease
+
+ local expected_chan_info = {
+ client = {
+ attributes = {
+ license = 'Apache 2',
+ -- pid = 5371,
+ website = 'https://neovim.io',
+ },
+ methods = {},
+ name = 'nvim-tui',
+ type = 'ui',
+ version = expected_version,
+ },
+ id = ui_chan,
+ mode = 'rpc',
+ stream = 'stdio',
+ }
+
+ local status, chan_info = child_session:request('nvim_get_chan_info', ui_chan)
+ ok(status)
+ local info = chan_info.client
+ ok(info.attributes.pid and info.attributes.pid > 0, 'PID', info.attributes.pid or 'nil')
+ ok(info.version.major >= 0)
+ ok(info.version.minor >= 0)
+ ok(info.version.patch >= 0)
+
+ -- Delete variable fields so we can deep-compare.
+ info.attributes.pid = nil
+
+ eq(expected_chan_info, chan_info)
end)
it('allows grid to assume wider ambiwidth chars than host terminal', function()
@@ -1941,9 +2055,9 @@ describe('TUI', function()
if not req then
return
end
- local url = req:match('\027]8;;(.*)$')
- if url ~= nil then
- table.insert(_G.urls, url)
+ local id, url = req:match('\027]8;id=(%d+);(.*)$')
+ if id ~= nil and url ~= nil then
+ table.insert(_G.urls, { id = tonumber(id), url = url })
end
end,
})
@@ -1957,7 +2071,7 @@ describe('TUI', function()
})
]])
retry(nil, 1000, function()
- eq({ 'https://example.com', '' }, exec_lua([[return _G.urls]]))
+ eq({ { id = 0xE1EA0000, url = 'https://example.com' } }, exec_lua([[return _G.urls]]))
end)
end)
end)
@@ -1973,6 +2087,7 @@ describe('TUI', function()
[3] = { bold = true },
[4] = { foreground = tonumber('0x4040ff'), fg_indexed = true },
[5] = { bold = true, reverse = true },
+ [6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen },
})
screen:attach()
fn.termopen({
@@ -1998,43 +2113,44 @@ describe('TUI', function()
{2:~ }│{4:~ }|*5
{2:~ }│{5:[No Name] 0,0-1 All}|
{2:~ }│ |
- {5:new }{1:{MATCH:<.*[/\]nvim }}|
- |
- ]])
- end)
-
- it('invalidated regions are cleared with terminal background attr', function()
- local screen = Screen.new(50, 10)
- screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.Black } })
- screen:attach()
- fn.termopen({
- nvim_prog,
- '--clean',
- '--cmd',
- 'set termguicolors',
- '--cmd',
- 'sleep 10',
- }, {
- env = {
- VIMRUNTIME = os.getenv('VIMRUNTIME'),
- },
- })
- screen:expect({
- grid = [[
- {1:^ }|
- {1: }|*8
- |
- ]],
- })
- screen:try_resize(51, 11)
- screen:expect({
- grid = [[
- {1:^ }|
- {1: }|*9
- |
- ]],
- })
- end)
+ {5:new }{6:{MATCH:<.*[/\]nvim }}|
+ |
+ ]])
+ end)
+
+ -- #28667, #28668
+ for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do
+ it('has no black flicker when clearing regions during startup with ' .. guicolors, function()
+ local screen = Screen.new(50, 10)
+ screen:attach()
+ fn.termopen({
+ nvim_prog,
+ '--clean',
+ '--cmd',
+ 'set ' .. guicolors,
+ '--cmd',
+ 'sleep 10',
+ }, {
+ env = {
+ VIMRUNTIME = os.getenv('VIMRUNTIME'),
+ },
+ })
+ screen:expect({
+ grid = [[
+ ^ |
+ |*9
+ ]],
+ intermediate = true,
+ })
+ screen:try_resize(51, 11)
+ screen:expect({
+ grid = [[
+ ^ |
+ |*10
+ ]],
+ })
+ end)
+ end
it('argv[0] can be overridden #23953', function()
if not exec_lua('return pcall(require, "ffi")') then
@@ -2080,7 +2196,7 @@ describe('TUI', function()
finally(function()
os.remove('testF')
end)
- local screen = tt.screen_setup(
+ local screen = tt.setup_screen(
0,
('"%s" -u NONE -i NONE --cmd "set noswapfile noshowcmd noruler" --cmd "normal iabc" > /dev/null 2>&1 && cat testF && rm testF'):format(
nvim_prog
@@ -2170,6 +2286,47 @@ describe('TUI', function()
}
end)
+ it('draws screen lines with leading spaces correctly #29711', function()
+ local screen = tt.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'set foldcolumn=6 | call setline(1, ["", repeat("aabb", 1000)]) | echo 42',
+ }, { extra_rows = 10, cols = 66 })
+ screen:expect {
+ grid = [[
+ |
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@|
+ [No Name] [+] 1,0-1 Top|
+ 42 |
+ -- TERMINAL -- |
+ ]],
+ attr_ids = {},
+ }
+ feed_data('\12') -- Ctrl-L
+ -- The first line counts as 3 cells.
+ -- For the second line, 6 repeated spaces at the start counts as 2 cells,
+ -- so each screen line of the second line counts as 62 cells.
+ -- After drawing the first line and 8 screen lines of the second line,
+ -- 3 + 8 * 62 = 499 cells have been counted.
+ -- The 6 repeated spaces at the start of the next screen line exceeds the
+ -- 500-cell limit, so the buffer is flushed after these spaces.
+ screen:expect {
+ grid = [[
+ |
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12
+ aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@|
+ [No Name] [+] 1,0-1 Top|
+ |
+ -- TERMINAL -- |
+ ]],
+ attr_ids = {},
+ }
+ end)
+
it('no heap-buffer-overflow when changing &columns', function()
-- Set a different bg colour and change $TERM to something dumber so the `print_spaces()`
-- codepath in `clear_region()` is hit.
@@ -2938,6 +3095,61 @@ describe('TUI', function()
end)
end)
+ it('does not query the terminal for truecolor support if $COLORTERM is set', function()
+ clear()
+ exec_lua([[
+ vim.api.nvim_create_autocmd('TermRequest', {
+ callback = function(args)
+ local req = args.data
+ vim.g.termrequest = req
+ local xtgettcap = req:match('^\027P%+q([%x;]+)$')
+ if xtgettcap then
+ local t = {}
+ for cap in vim.gsplit(xtgettcap, ';') do
+ local resp = string.format('\027P1+r%s\027\\', xtgettcap)
+ vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp)
+ t[vim.text.hexdecode(cap)] = true
+ end
+ vim.g.xtgettcap = t
+ return true
+ elseif req:match('^\027P$qm\027\\$') then
+ vim.g.decrqss = true
+ end
+ end,
+ })
+ ]])
+
+ local child_server = new_pipename()
+ screen = tt.setup_child_nvim({
+ '--listen',
+ child_server,
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ }, {
+ env = {
+ VIMRUNTIME = os.getenv('VIMRUNTIME'),
+ -- With COLORTERM=256, Nvim should not query the terminal and should not set 'tgc'
+ COLORTERM = '256',
+ TERM = 'xterm-256colors',
+ },
+ })
+
+ screen:expect({ any = '%[No Name%]' })
+
+ local child_session = n.connect(child_server)
+ retry(nil, 1000, function()
+ local xtgettcap = eval("get(g:, 'xtgettcap', {})")
+ eq(nil, xtgettcap['Tc'])
+ eq(nil, xtgettcap['RGB'])
+ eq(nil, xtgettcap['setrgbf'])
+ eq(nil, xtgettcap['setrgbb'])
+ eq(0, eval([[get(g:, 'decrqss')]]))
+ eq({ true, 0 }, { child_session:request('nvim_eval', '&termguicolors') })
+ end)
+ end)
+
it('queries the terminal for OSC 52 support', function()
clear()
exec_lua([[
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index f85e26a66d..fdb606e959 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local feed_data = tt.feed_data
local feed, clear = n.feed, n.clear
local poke_eventloop = n.poke_eventloop
@@ -13,11 +13,31 @@ local skip = t.skip
local is_os = t.is_os
describe(':terminal window', function()
+ before_each(clear)
+
+ it('sets local values of window options #29325', function()
+ command('setglobal wrap list')
+ command('terminal')
+ eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]'))
+ eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]'))
+ command('enew')
+ eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]'))
+ eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]'))
+ command('buffer #')
+ eq({ 0, 0, 1 }, eval('[&l:wrap, &wrap, &g:wrap]'))
+ eq({ 0, 0, 1 }, eval('[&l:list, &list, &g:list]'))
+ command('new')
+ eq({ 1, 1, 1 }, eval('[&l:wrap, &wrap, &g:wrap]'))
+ eq({ 1, 1, 1 }, eval('[&l:list, &list, &g:list]'))
+ end)
+end)
+
+describe(':terminal window', function()
local screen
before_each(function()
clear()
- screen = tt.screen_setup()
+ screen = tt.setup_screen()
end)
it('sets topline correctly #8556', function()
@@ -37,7 +57,6 @@ describe(':terminal window', function()
describe("with 'number'", function()
it('wraps text', function()
- skip(is_os('win')) -- todo(clason): unskip when reenabling reflow
feed([[<C-\><C-N>]])
feed([[:set numberwidth=1 number<CR>i]])
screen:expect([[
@@ -67,7 +86,7 @@ describe(':terminal window', function()
{7: 1 }tty ready |
{7: 2 }rows: 6, cols: 48 |
{7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
- {7: 4 }WXYZrows: 6, cols: 41 |
+ {7: 4 }PQRSTUVWXYZrows: 6, cols: 41 |
{7: 5 }{1: } |
{7: 6 } |
{3:-- TERMINAL --} |
@@ -77,7 +96,7 @@ describe(':terminal window', function()
{7: 1 }tty ready |
{7: 2 }rows: 6, cols: 48 |
{7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
- {7: 4 }WXYZrows: 6, cols: 41 |
+ {7: 4 }PQRSTUVWXYZrows: 6, cols: 41 |
{7: 5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN|
{7: 6 }OPQRSTUVWXYZ{1: } |
{3:-- TERMINAL --} |
@@ -87,7 +106,6 @@ describe(':terminal window', function()
describe("with 'statuscolumn'", function()
it('wraps text', function()
- skip(is_os('win')) -- todo(clason): unskip when reenabling reflow
command([[set number statuscolumn=++%l\ \ ]])
screen:expect([[
{7:++1 }tty ready |
@@ -110,11 +128,11 @@ describe(':terminal window', function()
]])
feed_data('\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
screen:expect([[
- {7:++7 } |
- {7:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR|
- {7:++9 }TUVWXYZ |
+ {7:++ 7 } |
+ {7:++ 8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR|
+ {7:++ 9 }STUVWXYZ |
{7:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR|
- {7:++11 }TUVWXYZrows: 6, cols: 44 |
+ {7:++11 }STUVWXYZrows: 6, cols: 44 |
{7:++12 }{1: } |
{3:-- TERMINAL --} |
]])
@@ -178,7 +196,7 @@ describe(':terminal with multigrid', function()
before_each(function()
clear()
- screen = tt.screen_setup(0, nil, 50, nil, { ext_multigrid = true })
+ screen = tt.setup_screen(0, nil, 50, nil, { ext_multigrid = true })
end)
it('resizes to requested size', function()
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 04d2e0bca7..e9218e9a3b 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local assert_alive = n.assert_alive
local clear = n.clear
local feed = n.feed
@@ -22,10 +22,12 @@ describe(':terminal', function()
-- set the statusline to a constant value because of variables like pid
-- and current directory and to improve visibility of splits
api.nvim_set_option_value('statusline', '==========', {})
- command('highlight StatusLine cterm=NONE')
- command('highlight StatusLineNC cterm=NONE')
- command('highlight VertSplit cterm=NONE')
- screen = tt.screen_setup(3)
+ screen = tt.setup_screen(3)
+ command('highlight StatusLine NONE')
+ command('highlight StatusLineNC NONE')
+ command('highlight StatusLineTerm NONE')
+ command('highlight StatusLineTermNC NONE')
+ command('highlight VertSplit NONE')
end)
after_each(function()
diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua
index 6b858e4d69..8a2281e2a1 100644
--- a/test/functional/testnvim.lua
+++ b/test/functional/testnvim.lua
@@ -14,15 +14,14 @@ local is_os = t.is_os
local ok = t.ok
local sleep = uv.sleep
---- This module uses functions from the context of the test session, i.e. in the context of the
---- nvim being tests.
+--- Functions executing in the current nvim session/process being tested.
local M = {}
local runtime_set = 'set runtimepath^=./build/lib/nvim/'
M.nvim_prog = (os.getenv('NVIM_PRG') or t.paths.test_build_dir .. '/bin/nvim')
-- Default settings for the test session.
M.nvim_set = (
- 'set shortmess+=IS background=light termguicolors noswapfile noautoindent startofline'
+ 'set shortmess+=IS background=light noswapfile noautoindent startofline'
.. ' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
.. ' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid'
)
@@ -251,12 +250,14 @@ function M.set_method_error(err)
method_error = err
end
+--- Runs the event loop of the given session.
+---
--- @param lsession test.Session
--- @param request_cb function?
--- @param notification_cb function?
--- @param setup_cb function?
--- @param timeout integer
---- @return {[1]: integer, [2]: string}
+--- @return [integer, string]
function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
local on_request --- @type function?
local on_notification --- @type function?
@@ -297,6 +298,7 @@ function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
return lsession.eof_err
end
+--- Runs the event loop of the current global session.
function M.run(request_cb, notification_cb, setup_cb, timeout)
assert(session)
return M.run_session(session, request_cb, notification_cb, setup_cb, timeout)
@@ -456,7 +458,7 @@ end
--- @param argv string[]
--- @param merge boolean?
--- @param env string[]?
---- @param keep boolean
+--- @param keep boolean?
--- @param io_extra uv.uv_pipe_t? used for stdin_fd, see :help ui-option
--- @return test.Session
function M.spawn(argv, merge, env, keep, io_extra)
@@ -757,58 +759,21 @@ function M.assert_visible(bufnr, visible)
end
end
---- @param path string
-local function do_rmdir(path)
- local stat = uv.fs_stat(path)
- if stat == nil then
- return
- end
- if stat.type ~= 'directory' then
- error(string.format('rmdir: not a directory: %s', path))
- end
- for file in vim.fs.dir(path) do
- if file ~= '.' and file ~= '..' then
- local abspath = path .. '/' .. file
- if t.isdir(abspath) then
- do_rmdir(abspath) -- recurse
- else
- local ret, err = os.remove(abspath)
- if not ret then
- if not session then
- error('os.remove: ' .. err)
- else
- -- Try Nvim delete(): it handles `readonly` attribute on Windows,
- -- and avoids Lua cross-version/platform incompatibilities.
- if -1 == M.call('delete', abspath) then
- local hint = (is_os('win') and ' (hint: try :%bwipeout! before rmdir())' or '')
- error('delete() failed' .. hint .. ': ' .. abspath)
- end
- end
- end
- end
- end
- end
- local ret, err = uv.fs_rmdir(path)
- if not ret then
- error('luv.fs_rmdir(' .. path .. '): ' .. err)
- end
-end
-
local start_dir = uv.cwd()
function M.rmdir(path)
- local ret, _ = pcall(do_rmdir, path)
+ local ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true })
if not ret and is_os('win') then
-- Maybe "Permission denied"; try again after changing the nvim
-- process to the top-level directory.
M.command([[exe 'cd '.fnameescape(']] .. start_dir .. "')")
- ret, _ = pcall(do_rmdir, path)
+ ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true })
end
-- During teardown, the nvim process may not exit quickly enough, then rmdir()
-- will fail (on Windows).
if not ret then -- Try again.
sleep(1000)
- do_rmdir(path)
+ vim.fs.rm(path, { recursive = true, force = true })
end
end
@@ -835,10 +800,171 @@ function M.exec_capture(code)
return M.api.nvim_exec2(code, { output = true }).output
end
---- @param code string
+--- @param f function
+--- @return table<string,any>
+local function get_upvalues(f)
+ local i = 1
+ local upvalues = {} --- @type table<string,any>
+ while true do
+ local n, v = debug.getupvalue(f, i)
+ if not n then
+ break
+ end
+ upvalues[n] = v
+ i = i + 1
+ end
+ return upvalues
+end
+
+--- @param f function
+--- @param upvalues table<string,any>
+local function set_upvalues(f, upvalues)
+ local i = 1
+ while true do
+ local n = debug.getupvalue(f, i)
+ if not n then
+ break
+ end
+ if upvalues[n] then
+ debug.setupvalue(f, i, upvalues[n])
+ end
+ i = i + 1
+ end
+end
+
+--- @type fun(f: function): table<string,any>
+_G.__get_upvalues = nil
+
+--- @type fun(f: function, upvalues: table<string,any>)
+_G.__set_upvalues = nil
+
+--- @param self table<string,function>
+--- @param bytecode string
+--- @param upvalues table<string,any>
+--- @param ... any[]
+--- @return any[] result
+--- @return table<string,any> upvalues
+local function exec_lua_handler(self, bytecode, upvalues, ...)
+ local f = assert(loadstring(bytecode))
+ self.set_upvalues(f, upvalues)
+ local ret = { f(...) } --- @type any[]
+ --- @type table<string,any>
+ local new_upvalues = self.get_upvalues(f)
+
+ do -- Check return value types for better error messages
+ local invalid_types = {
+ ['thread'] = true,
+ ['function'] = true,
+ ['userdata'] = true,
+ }
+
+ for k, v in pairs(ret) do
+ if invalid_types[type(v)] then
+ error(
+ string.format(
+ "Return index %d with value '%s' of type '%s' cannot be serialized over RPC",
+ k,
+ tostring(v),
+ type(v)
+ )
+ )
+ end
+ end
+ end
+
+ return ret, new_upvalues
+end
+
+--- Execute Lua code in the wrapped Nvim session.
+---
+--- When `code` is passed as a function, it is converted into Lua byte code.
+---
+--- Direct upvalues are copied over, however upvalues contained
+--- within nested functions are not. Upvalues are also copied back when `code`
+--- finishes executing. See `:help lua-upvalue`.
+---
+--- Only types which can be serialized can be transferred over, e.g:
+--- `table`, `number`, `boolean`, `string`.
+---
+--- `code` runs with a different environment and thus will have a different global
+--- environment. See `:help lua-environments`.
+---
+--- Example:
+--- ```lua
+--- local upvalue1 = 'upvalue1'
+--- exec_lua(function(a, b, c)
+--- print(upvalue1, a, b, c)
+--- (function()
+--- print(upvalue2)
+--- end)()
+--- end, 'a', 'b', 'c'
+--- ```
+--- Prints:
+--- ```
+--- upvalue1 a b c
+--- nil
+--- ```
+---
+--- Not supported:
+--- ```lua
+--- local a = vim.uv.new_timer()
+--- exec_lua(function()
+--- print(a) -- Error: a is of type 'userdata' which cannot be serialized.
+--- end)
+--- ```
+--- @param code string|function
+--- @param ... any
--- @return any
function M.exec_lua(code, ...)
- return M.api.nvim_exec_lua(code, { ... })
+ if type(code) == 'string' then
+ return M.api.nvim_exec_lua(code, { ... })
+ end
+
+ assert(session)
+
+ if not session.exec_lua_setup then
+ M.api.nvim_exec_lua(
+ [[
+ _G.__test_exec_lua = {
+ get_upvalues = loadstring((select(1,...))),
+ set_upvalues = loadstring((select(2,...))),
+ handler = loadstring((select(3,...)))
+ }
+ setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua })
+ ]],
+ { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) }
+ )
+ session.exec_lua_setup = true
+ end
+
+ --- @type any[], table<string,any>
+ local ret, upvalues = unpack(M.api.nvim_exec_lua(
+ [[
+ return {
+ _G.__test_exec_lua:handler(...)
+ }
+ ]],
+ {
+ string.dump(code),
+ get_upvalues(code),
+ ...,
+ }
+ ))
+
+ -- Update upvalues
+ if next(upvalues) then
+ local caller = debug.getinfo(2)
+ local f = caller.func
+ -- On PUC-Lua, if the function is a tail call, then func will be nil.
+ -- In this case we need to use the current function.
+ if not f then
+ assert(caller.source == '=(tail call)')
+ f = debug.getinfo(1).func
+ end
+ set_upvalues(f, upvalues)
+ end
+
+ return unpack(ret, 1, table.maxn(ret))
end
function M.get_pathsep()
@@ -894,26 +1020,6 @@ function M.missing_provider(provider)
assert(false, 'Unknown provider: ' .. provider)
end
---- @param obj string|table
---- @return any
-function M.alter_slashes(obj)
- if not is_os('win') then
- return obj
- end
- if type(obj) == 'string' then
- local ret = obj:gsub('/', '\\')
- return ret
- elseif type(obj) == 'table' then
- --- @cast obj table<any,any>
- local ret = {} --- @type table<any,any>
- for k, v in pairs(obj) do
- ret[k] = M.alter_slashes(v)
- end
- return ret
- end
- assert(false, 'expected string or table of strings, got ' .. type(obj))
-end
-
local load_factor = 1
if t.is_ci() then
-- Compute load factor only once (but outside of any tests).
diff --git a/test/functional/terminal/testutil.lua b/test/functional/testterm.lua
index f3fc5d3f93..e46ae0793c 100644
--- a/test/functional/terminal/testutil.lua
+++ b/test/functional/testterm.lua
@@ -1,6 +1,13 @@
--- To test tui/input.c, this module spawns `nvim` inside :terminal and sends
--- bytes via jobsend(). Note: the functional/testutil.lua test-session methods
--- operate on the _host_ session, _not_ the child session.
+-- Functions to test :terminal and the Nvim TUI.
+-- Starts a child process in a `:terminal` and sends bytes to the child via nvim_chan_send().
+-- Note: the global functional/testutil.lua test-session is _host_ session, _not_
+-- the child session.
+--
+-- - Use `setup_screen()` to test `:terminal` behavior with an arbitrary command.
+-- - Use `setup_child_nvim()` to test the Nvim TUI.
+-- - NOTE: Only use this if your test actually needs the full lifecycle/capabilities of the
+-- builtin Nvim TUI. Most tests should just use `Screen.new()` directly, or plain old API calls.
+
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
@@ -9,18 +16,20 @@ local exec_lua = n.exec_lua
local api = n.api
local nvim_prog = n.nvim_prog
-local function feed_data(data)
+local M = {}
+
+function M.feed_data(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_data('\027' .. data)
+function M.feed_termcode(data)
+ M.feed_data('\027' .. data)
end
-local function make_lua_executor(session)
+function M.make_lua_executor(session)
return function(code, ...)
local status, rv = session:request('nvim_exec_lua', code, { ... })
if not status then
@@ -34,64 +43,74 @@ end
-- some t for controlling the terminal. the codes were taken from
-- infocmp xterm-256color which is less what libvterm understands
-- civis/cnorm
-local function hide_cursor()
- feed_termcode('[?25l')
+function M.hide_cursor()
+ M.feed_termcode('[?25l')
end
-local function show_cursor()
- feed_termcode('[?25h')
+function M.show_cursor()
+ M.feed_termcode('[?25h')
end
-- smcup/rmcup
-local function enter_altscreen()
- feed_termcode('[?1049h')
+function M.enter_altscreen()
+ M.feed_termcode('[?1049h')
end
-local function exit_altscreen()
- feed_termcode('[?1049l')
+function M.exit_altscreen()
+ M.feed_termcode('[?1049l')
end
-- character attributes
-local function set_fg(num)
- feed_termcode('[38;5;' .. num .. 'm')
+function M.set_fg(num)
+ M.feed_termcode('[38;5;' .. num .. 'm')
end
-local function set_bg(num)
- feed_termcode('[48;5;' .. num .. 'm')
+function M.set_bg(num)
+ M.feed_termcode('[48;5;' .. num .. 'm')
end
-local function set_bold()
- feed_termcode('[1m')
+function M.set_bold()
+ M.feed_termcode('[1m')
end
-local function set_italic()
- feed_termcode('[3m')
+function M.set_italic()
+ M.feed_termcode('[3m')
end
-local function set_underline()
- feed_termcode('[4m')
+function M.set_underline()
+ M.feed_termcode('[4m')
end
-local function set_underdouble()
- feed_termcode('[4:2m')
+function M.set_underdouble()
+ M.feed_termcode('[4:2m')
end
-local function set_undercurl()
- feed_termcode('[4:3m')
+function M.set_undercurl()
+ M.feed_termcode('[4:3m')
end
-local function set_strikethrough()
- feed_termcode('[9m')
+function M.set_strikethrough()
+ M.feed_termcode('[9m')
end
-local function clear_attrs()
- feed_termcode('[0;10m')
+function M.clear_attrs()
+ M.feed_termcode('[0;10m')
end
-- mouse
-local function enable_mouse()
- feed_termcode('[?1002h')
+function M.enable_mouse()
+ M.feed_termcode('[?1002h')
end
-local function disable_mouse()
- feed_termcode('[?1002l')
+function M.disable_mouse()
+ M.feed_termcode('[?1002l')
end
local default_command = { testprg('tty-test') }
-local function screen_setup(extra_rows, command, cols, env, screen_opts)
+--- Runs `cmd` in a :terminal, and returns a `Screen` object.
+---
+---@param extra_rows? integer Extra rows to add to the default screen.
+---@param cmd? string|string[] Command to run in the terminal (default: `{ 'tty-test' }`)
+---@param cols? integer Create screen with this many columns (default: 50)
+---@param env? table Environment set on the `cmd` job.
+---@param screen_opts? table Options for `Screen.new()`.
+---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session.
+function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
extra_rows = extra_rows and extra_rows or 0
- command = command and command or default_command
+ cmd = cmd and cmd or default_command
cols = cols and cols or 50
api.nvim_command('highlight TermCursor cterm=reverse')
api.nvim_command('highlight TermCursorNC ctermbg=11')
+ api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0')
+ api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8')
local screen = Screen.new(cols, 7 + extra_rows)
screen:set_default_attr_ids({
@@ -111,12 +130,14 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
[14] = { underline = true, reverse = true, bold = true },
[15] = { underline = true, foreground = 12 },
[16] = { background = 248, foreground = 0 }, -- Visual in :terminal session
+ [17] = { background = 2, foreground = 0 }, -- StatusLineTerm
+ [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC
})
screen:attach(screen_opts or { rgb = false })
api.nvim_command('enew')
- api.nvim_call_function('termopen', { command, env and { env = env } or nil })
+ api.nvim_call_function('termopen', { cmd, env and { env = env } or nil })
api.nvim_input('<CR>')
local vim_errmsg = api.nvim_eval('v:errmsg')
if vim_errmsg and '' ~= vim_errmsg then
@@ -129,7 +150,7 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
-- tty-test puts the terminal into raw mode and echoes input. Tests work by
-- feeding termcodes to control the display and asserting by screen:expect.
- if command == default_command and screen_opts == nil then
+ if cmd == default_command and screen_opts == nil then
-- Wait for "tty ready" to be printed before each test or the terminal may
-- still be in canonical mode (will echo characters for example).
local empty_line = (' '):rep(cols)
@@ -156,37 +177,24 @@ local function screen_setup(extra_rows, command, cols, env, screen_opts)
return screen
end
-local function setup_child_nvim(args, opts)
+--- Spawns Nvim with `args` in a :terminal, and returns a `Screen` object.
+---
+--- @note Only use this if you actually need the full lifecycle/capabilities of the builtin Nvim
+--- TUI. Most tests should just use `Screen.new()` directly, or plain old API calls.
+---
+---@param args? string[] Args passed to child Nvim.
+---@param opts? table Options
+---@return test.functional.ui.screen # Screen attached to the global (not child) Nvim session.
+function M.setup_child_nvim(args, opts)
opts = opts or {}
- local argv = { nvim_prog, unpack(args) }
+ local argv = { nvim_prog, unpack(args or {}) }
local env = opts.env or {}
if not env.VIMRUNTIME then
env.VIMRUNTIME = os.getenv('VIMRUNTIME')
end
- return screen_setup(0, argv, opts.cols, env)
-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,
- exit_altscreen = exit_altscreen,
- set_fg = set_fg,
- set_bg = set_bg,
- 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,
- disable_mouse = disable_mouse,
- screen_setup = screen_setup,
- setup_child_nvim = setup_child_nvim,
-}
+ return M.setup_screen(opts.extra_rows, argv, opts.cols, env)
+end
+
+return M
diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua
index a7f278aa01..24b085920c 100644
--- a/test/functional/treesitter/fold_spec.lua
+++ b/test/functional/treesitter/fold_spec.lua
@@ -48,13 +48,13 @@ void ui_refresh(void)
end
local function get_fold_levels()
- return exec_lua([[
- local res = {}
- for i = 1, vim.api.nvim_buf_line_count(0) do
- res[i] = vim.treesitter.foldexpr(i)
- end
- return res
- ]])
+ return exec_lua(function()
+ local res = {}
+ for i = 1, vim.api.nvim_buf_line_count(0) do
+ res[i] = vim.treesitter.foldexpr(i)
+ end
+ return res
+ end)
end
it('can compute fold levels', function()
@@ -246,9 +246,13 @@ function f()
end
-- comment]])
- exec_lua(
- [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (parameters) (arguments)] @fold')]]
- )
+ exec_lua(function()
+ vim.treesitter.query.set(
+ 'lua',
+ 'folds',
+ '[(function_declaration) (parameters) (arguments)] @fold'
+ )
+ end)
parse('lua')
eq({
@@ -290,9 +294,13 @@ function f()
)
end]])
- exec_lua(
- [[vim.treesitter.query.set('lua', 'folds', '[(function_declaration) (function_definition) (parameters) (arguments)] @fold')]]
- )
+ exec_lua(function()
+ vim.treesitter.query.set(
+ 'lua',
+ 'folds',
+ '[(function_declaration) (function_definition) (parameters) (arguments)] @fold'
+ )
+ end)
parse('lua')
-- If fold1.stop = fold2.start, then move fold1's stop up so that fold2.start gets proper level.
@@ -333,9 +341,13 @@ function f(a)
end
end]])
- exec_lua(
- [[vim.treesitter.query.set('lua', 'folds', '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold')]]
- )
+ exec_lua(function()
+ vim.treesitter.query.set(
+ 'lua',
+ 'folds',
+ '[(if_statement) (function_declaration) (parameters) (arguments) (table_constructor)] @fold'
+ )
+ end)
parse('lua')
eq({
@@ -408,15 +420,15 @@ t3]])
it('handles quantified patterns', function()
insert([[
-import hello
-import hello
-import hello
-import hello
-import hello
-import hello]])
-
- exec_lua([[vim.treesitter.query.set('python', 'folds', '(import_statement)+ @fold')]])
- parse('python')
+-- hello
+-- hello
+-- hello
+-- hello
+-- hello
+-- hello]])
+
+ exec_lua([[vim.treesitter.query.set('lua', 'folds', '(comment)+ @fold')]])
+ parse('lua')
eq({
[1] = '>1',
@@ -646,6 +658,67 @@ import hello]])
}
end)
+ it('does not extend closed fold with `o`/`O`', function()
+ local screen = Screen.new(60, 24)
+ screen:attach()
+
+ insert(test_text)
+ parse('c')
+ command([[set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1]])
+
+ feed('5ggzco')
+ screen:expect({
+ grid = [[
+ {7:-}void ui_refresh(void) |
+ {7:│}{ |
+ {7:│} int width = INT_MAX, height = INT_MAX; |
+ {7:│} bool ext_widgets[kUIExtCount]; |
+ {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}|
+ {7:│}^ |
+ {7:│} |
+ {7:│} bool inclusive = ui_override(); |
+ {7:-} for (size_t i = 0; i < ui_count; i++) { |
+ {7:2} UI *ui = uis[i]; |
+ {7:2} width = MIN(ui->width, width); |
+ {7:2} height = MIN(ui->height, height); |
+ {7:2} foo = BAR(ui->bazaar, bazaar); |
+ {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
+ {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ {7:3} } |
+ {7:2} } |
+ {7:│}} |
+ {1:~ }|*5
+ {5:-- INSERT --} |
+ ]],
+ })
+
+ feed('<Esc>O')
+ screen:expect({
+ grid = [[
+ {7:-}void ui_refresh(void) |
+ {7:│}{ |
+ {7:│} int width = INT_MAX, height = INT_MAX; |
+ {7:│} bool ext_widgets[kUIExtCount]; |
+ {7:+}{13:+--- 3 lines: for (UIExtension i = 0; (int)i < kUIExtCount}|
+ {7:│}^ |
+ {7:│} |*2
+ {7:│} bool inclusive = ui_override(); |
+ {7:-} for (size_t i = 0; i < ui_count; i++) { |
+ {7:2} UI *ui = uis[i]; |
+ {7:2} width = MIN(ui->width, width); |
+ {7:2} height = MIN(ui->height, height); |
+ {7:2} foo = BAR(ui->bazaar, bazaar); |
+ {7:-} for (UIExtension j = 0; (int)j < kUIExtCount; j++) { |
+ {7:3} ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ {7:3} } |
+ {7:2} } |
+ {7:│}} |
+ {1:~ }|*4
+ {5:-- INSERT --} |
+ ]],
+ })
+ end)
+
it("doesn't open folds that are not touched", function()
local screen = Screen.new(40, 8)
screen:set_default_attr_ids({
@@ -674,7 +747,7 @@ t2]])
grid = [[
{1:-}# h1 |
{1:│}t1 |
- {1:│}^ |
+ {1:-}^ |
{1:+}{2:+-- 2 lines: # h2·····················}|
{3:~ }|*3
{4:-- INSERT --} |
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 69984b3233..b5a6cb5c17 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -8,10 +8,9 @@ local exec_lua = n.exec_lua
local feed = n.feed
local command = n.command
local api = n.api
+local fn = n.fn
local eq = t.eq
-before_each(clear)
-
local hl_query_c = [[
(ERROR) @error
@@ -65,6 +64,46 @@ static int nlua_schedule(lua_State *const lstate)
return 0;
}]]
+local hl_grid_legacy_c = [[
+ {2:^/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} nlua_schedule(lua_State *{3:const} lstate) |
+ { |
+ {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION |
+ || lstate != lstate) { |
+ lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} lua_error(lstate); |
+ } |
+ |
+ LuaRef cb = nlua_ref(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, nlua_schedule_event, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|*2
+ |
+]]
+
+local hl_grid_ts_c = [[
+ {2:^/// Schedule Lua callback on main loop's event queue} |
+ {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
+ { |
+ {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
+ || {6:lstate} != {6:lstate}) { |
+ {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
+ {4:return} {11:lua_error}(lstate); |
+ } |
+ |
+ {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ |
+ multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
+ {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
+ {4:return} {5:0}; |
+ } |
+ {1:~ }|*2
+ |
+]]
+
local test_text_c = [[
void ui_refresh(void)
{
@@ -117,9 +156,10 @@ local injection_grid_expected_c = [[
]]
describe('treesitter highlighting (C)', function()
- local screen
+ local screen --- @type test.functional.ui.screen
before_each(function()
+ clear()
screen = Screen.new(65, 18)
screen:attach()
screen:set_default_attr_ids {
@@ -136,16 +176,49 @@ describe('treesitter highlighting (C)', function()
[11] = { foreground = Screen.colors.Cyan4 },
}
- exec_lua([[ hl_query = ... ]], hl_query_c)
command [[ hi link @error ErrorMsg ]]
command [[ hi link @warning WarningMsg ]]
end)
+ it('starting and stopping treesitter highlight works', function()
+ command('setfiletype c | syntax on')
+ fn.setreg('r', hl_text_c)
+ feed('i<C-R><C-O>r<Esc>gg')
+ -- legacy syntax highlighting is used by default
+ screen:expect(hl_grid_legacy_c)
+
+ exec_lua(function()
+ vim.treesitter.query.set('c', 'highlights', hl_query_c)
+ vim.treesitter.start()
+ end)
+ -- treesitter highlighting is used
+ screen:expect(hl_grid_ts_c)
+
+ exec_lua(function()
+ vim.treesitter.stop()
+ end)
+ -- legacy syntax highlighting is used
+ screen:expect(hl_grid_legacy_c)
+
+ exec_lua(function()
+ vim.treesitter.start()
+ end)
+ -- treesitter highlighting is used
+ screen:expect(hl_grid_ts_c)
+
+ exec_lua(function()
+ vim.treesitter.stop()
+ end)
+ -- legacy syntax highlighting is used
+ screen:expect(hl_grid_legacy_c)
+ end)
+
it('is updated with edits', function()
insert(hl_text_c)
+ feed('gg')
screen:expect {
grid = [[
- /// Schedule Lua callback on main loop's event queue |
+ ^/// Schedule Lua callback on main loop's event queue |
static int nlua_schedule(lua_State *const lstate) |
{ |
if (lua_type(lstate, 1) != LUA_TFUNCTION |
@@ -159,38 +232,18 @@ describe('treesitter highlighting (C)', function()
multiqueue_put(main_loop.events, nlua_schedule_event, |
1, (void *)(ptrdiff_t)cb); |
return 0; |
- ^} |
+ } |
{1:~ }|*2
|
]],
}
- exec_lua [[
- local parser = vim.treesitter.get_parser(0, "c")
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
local highlighter = vim.treesitter.highlighter
- test_hl = highlighter.new(parser, {queries = {c = hl_query}})
- ]]
- screen:expect {
- grid = [[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- ^} |
- {1:~ }|*2
- |
- ]],
- }
+ highlighter.new(parser, { queries = { c = hl_query_c } })
+ end)
+ screen:expect(hl_grid_ts_c)
feed('5Goc<esc>dd')
@@ -316,10 +369,10 @@ describe('treesitter highlighting (C)', function()
it('is updated with :sort', function()
insert(test_text_c)
- exec_lua [[
- local parser = vim.treesitter.get_parser(0, "c")
- test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}})
- ]]
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
+ end)
screen:expect {
grid = [[
{3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
@@ -422,19 +475,19 @@ describe('treesitter highlighting (C)', function()
]],
}
- exec_lua [[
- parser = vim.treesitter.get_parser(0, "c")
- query = vim.treesitter.query.parse("c", "(declaration) @decl")
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local query = vim.treesitter.query.parse('c', '(declaration) @decl')
local nodes = {}
for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do
table.insert(nodes, node)
end
- parser:set_included_regions({nodes})
+ parser:set_included_regions({ nodes })
- local hl = vim.treesitter.highlighter.new(parser, {queries = {c = "(identifier) @type"}})
- ]]
+ vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } })
+ end)
screen:expect {
grid = [[
@@ -465,13 +518,15 @@ describe('treesitter highlighting (C)', function()
screen:expect { grid = injection_grid_c }
- exec_lua [[
- local parser = vim.treesitter.get_parser(0, "c", {
- injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'}
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c', {
+ injections = {
+ c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))',
+ },
})
local highlighter = vim.treesitter.highlighter
- test_hl = highlighter.new(parser, {queries = {c = hl_query}})
- ]]
+ highlighter.new(parser, { queries = { c = hl_query_c } })
+ end)
screen:expect { grid = injection_grid_expected_c }
end)
@@ -481,14 +536,16 @@ describe('treesitter highlighting (C)', function()
screen:expect { grid = injection_grid_c }
- exec_lua [[
- vim.treesitter.language.register("c", "foo")
- local parser = vim.treesitter.get_parser(0, "c", {
- injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))'}
+ exec_lua(function()
+ vim.treesitter.language.register('c', 'foo')
+ local parser = vim.treesitter.get_parser(0, 'c', {
+ injections = {
+ c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))',
+ },
})
local highlighter = vim.treesitter.highlighter
- test_hl = highlighter.new(parser, {queries = {c = hl_query}})
- ]]
+ highlighter.new(parser, { queries = { c = hl_query_c } })
+ end)
screen:expect { grid = injection_grid_expected_c }
end)
@@ -502,13 +559,14 @@ describe('treesitter highlighting (C)', function()
}
]])
- exec_lua [[
- local injection_query = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
- vim.treesitter.query.set("c", "highlights", hl_query)
- vim.treesitter.query.set("c", "injections", injection_query)
+ exec_lua(function()
+ local injection_query =
+ '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
+ vim.treesitter.query.set('c', 'highlights', hl_query_c)
+ vim.treesitter.query.set('c', 'injections', injection_query)
- vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, "c"))
- ]]
+ vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
+ end)
screen:expect {
grid = [[
@@ -526,40 +584,21 @@ describe('treesitter highlighting (C)', function()
it('supports highlighting with custom highlight groups', function()
insert(hl_text_c)
+ feed('gg')
- exec_lua [[
- local parser = vim.treesitter.get_parser(0, "c")
- test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}})
- ]]
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
+ end)
- screen:expect {
- grid = [[
- {2:/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- ^} |
- {1:~ }|*2
- |
- ]],
- }
+ screen:expect(hl_grid_ts_c)
-- 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 @string.nonexistent_specializer comment")]]
screen:expect {
grid = [[
- {2:/// Schedule Lua callback on main loop's event queue} |
+ {2:^/// Schedule Lua callback on main loop's event queue} |
{3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
{ |
{4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
@@ -573,7 +612,7 @@ describe('treesitter highlighting (C)', function()
multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
{5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
{4:return} {5:0}; |
- ^} |
+ } |
{1:~ }|*2
|
]],
@@ -590,10 +629,14 @@ describe('treesitter highlighting (C)', function()
}
]])
- exec_lua [[
- local parser = vim.treesitter.get_parser(0, "c")
- test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @constant (#set! "priority" 101))\n'}})
- ]]
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ vim.treesitter.highlighter.new(parser, {
+ queries = {
+ c = hl_query_c .. '\n((translation_unit) @constant (#set! "priority" 101))\n',
+ },
+ })
+ end)
-- expect everything to have Constant highlight
screen:expect {
grid = [[
@@ -640,11 +683,14 @@ describe('treesitter highlighting (C)', function()
hi link @foo.bar Type
hi link @foo String
]]
- exec_lua [[
- local parser = vim.treesitter.get_parser(0, "c", {})
- local highlighter = vim.treesitter.highlighter
- test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}})
- ]]
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c', {})
+ local highlighter = vim.treesitter.highlighter
+ highlighter.new(
+ parser,
+ { queries = { c = '(primitive_type) @foo.bar (string_literal) @foo' } }
+ )
+ end)
screen:expect {
grid = [[
@@ -672,10 +718,12 @@ describe('treesitter highlighting (C)', function()
insert(hl_text_c)
-- conceal can be empty or a single cchar.
- exec_lua [=[
+ exec_lua(function()
vim.opt.cole = 2
- local parser = vim.treesitter.get_parser(0, "c")
- test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = [[
+ local parser = vim.treesitter.get_parser(0, 'c')
+ vim.treesitter.highlighter.new(parser, {
+ queries = {
+ c = [[
("static" @keyword
(#set! conceal "R"))
@@ -688,8 +736,10 @@ describe('treesitter highlighting (C)', function()
arguments: (argument_list) @arguments)
(#eq? @function "multiqueue_put")
(#set! @function conceal "V"))
- ]]}})
- ]=]
+ ]],
+ },
+ })
+ end)
screen:expect {
grid = [[
@@ -746,11 +796,11 @@ describe('treesitter highlighting (C)', function()
int z = 6;
]])
- exec_lua([[
+ exec_lua(function()
local query = '((declaration)+ @string)'
vim.treesitter.query.set('c', 'highlights', query)
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
- ]])
+ end)
screen:expect {
grid = [[
@@ -776,14 +826,10 @@ describe('treesitter highlighting (C)', function()
declarator: (pointer_declarator) @variable.parameter)
]]
- exec_lua(
- [[
- local query = ...
+ exec_lua(function()
vim.treesitter.query.set('c', 'highlights', query)
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
- ]],
- query
- )
+ end)
screen:expect {
grid = [[
@@ -800,6 +846,7 @@ describe('treesitter highlighting (lua)', function()
local screen
before_each(function()
+ clear()
screen = Screen.new(65, 18)
screen:attach()
screen:set_default_attr_ids {
@@ -817,10 +864,10 @@ describe('treesitter highlighting (lua)', function()
ffi.cdef("int (*fun)(int, char *);")
]]
- exec_lua [[
+ exec_lua(function()
vim.bo.filetype = 'lua'
vim.treesitter.start()
- ]]
+ end)
screen:expect {
grid = [[
@@ -838,6 +885,7 @@ describe('treesitter highlighting (help)', function()
local screen
before_each(function()
+ clear()
screen = Screen.new(40, 6)
screen:attach()
screen:set_default_attr_ids {
@@ -846,9 +894,45 @@ describe('treesitter highlighting (help)', function()
[3] = { bold = true, foreground = Screen.colors.Brown },
[4] = { foreground = Screen.colors.Cyan4 },
[5] = { foreground = Screen.colors.Magenta1 },
+ title = { bold = true, foreground = Screen.colors.Magenta1 },
+ h1_delim = { nocombine = true, underdouble = true },
+ h2_delim = { nocombine = true, underline = true },
}
end)
+ it('defaults in vimdoc/highlights.scm', function()
+ -- Avoid regressions when syncing upstream vimdoc queries.
+
+ insert [[
+ ==============================================================================
+ NVIM DOCUMENTATION
+
+ ------------------------------------------------------------------------------
+ ABOUT NVIM *tag-1* *tag-2*
+
+ |news| News
+ |nvim| NVim
+ ]]
+
+ feed('gg')
+ exec_lua(function()
+ vim.wo.wrap = false
+ vim.bo.filetype = 'help'
+ vim.treesitter.start()
+ end)
+
+ screen:expect({
+ grid = [[
+ {h1_delim:^========================================}|
+ {title:NVIM DOCUMENTATION} |
+ |
+ {h2_delim:----------------------------------------}|
+ {title:ABOUT NVIM} |
+ |
+ ]],
+ })
+ end)
+
it('correctly redraws added/removed injections', function()
insert [[
>ruby
@@ -857,10 +941,10 @@ describe('treesitter highlighting (help)', function()
<
]]
- exec_lua [[
+ exec_lua(function()
vim.bo.filetype = 'help'
vim.treesitter.start()
- ]]
+ end)
screen:expect {
grid = [[
@@ -912,15 +996,15 @@ describe('treesitter highlighting (help)', function()
]]
]=])
- exec_lua [[
- parser = vim.treesitter.get_parser(0, "lua", {
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'lua', {
injections = {
- lua = '(string content: (_) @injection.content (#set! injection.language lua))'
- }
+ lua = '(string content: (_) @injection.content (#set! injection.language lua))',
+ },
})
vim.treesitter.highlighter.new(parser)
- ]]
+ end)
screen:expect {
grid = [=[
@@ -936,9 +1020,10 @@ describe('treesitter highlighting (help)', function()
end)
describe('treesitter highlighting (nested injections)', function()
- local screen
+ local screen --- @type test.functional.ui.screen
before_each(function()
+ clear()
screen = Screen.new(80, 7)
screen:attach()
screen:set_default_attr_ids {
@@ -964,11 +1049,11 @@ vim.cmd([[
]])
]=]
- exec_lua [[
+ exec_lua(function()
vim.opt.scrolloff = 0
vim.bo.filetype = 'lua'
vim.treesitter.start()
- ]]
+ end)
-- invalidate the language tree
feed('ggi--[[<ESC>04x')
@@ -1006,41 +1091,93 @@ describe('treesitter highlighting (markdown)', function()
local screen
before_each(function()
+ clear()
screen = Screen.new(40, 6)
screen:attach()
- screen:set_default_attr_ids {
- [1] = { foreground = Screen.colors.Blue1 },
- [2] = { bold = true, foreground = Screen.colors.Blue1 },
- [3] = { bold = true, foreground = Screen.colors.Brown },
- [4] = { foreground = Screen.colors.Cyan4 },
- [5] = { foreground = Screen.colors.Magenta1 },
- }
+ exec_lua(function()
+ vim.bo.filetype = 'markdown'
+ vim.treesitter.start()
+ end)
end)
it('supports hyperlinks', function()
local url = 'https://example.com'
insert(string.format('[This link text](%s) is a hyperlink.', url))
- exec_lua([[
- vim.bo.filetype = 'markdown'
- vim.treesitter.start()
- ]])
+ screen:add_extra_attr_ids({
+ [100] = { foreground = Screen.colors.DarkCyan, url = 'https://example.com' },
+ [101] = {
+ foreground = Screen.colors.SlateBlue,
+ url = 'https://example.com',
+ underline = true,
+ },
+ })
+ screen:expect({
+ grid = [[
+ {25:[}{100:This link text}{25:](}{101:https://example.com}{25:)} is|
+ a hyperlink^. |
+ {1:~ }|*3
+ |
+ ]],
+ })
+ end)
- screen:expect {
+ it('works with spellchecked and smoothscrolled topline', function()
+ insert([[
+- $f(0)=\sum_{k=1}^{\infty}\frac{2}{\pi^{2}k^{2}}+\lim_{w \to 0}x$.
+
+```c
+printf('Hello World!');
+```
+ ]])
+ command('set spell smoothscroll')
+ feed('gg<C-E>')
+ screen:add_extra_attr_ids({ [100] = { undercurl = true, special = Screen.colors.Red } })
+ screen:expect({
grid = [[
- {4:[}{6:This link text}{4:](}{7:https://example.com}{4:)} is|
- a hyperlink^. |
- {2:~ }|*3
- |
- ]],
- attr_ids = {
- [1] = { foreground = Screen.colors.Blue1 },
- [2] = { bold = true, foreground = Screen.colors.Blue1 },
- [3] = { bold = true, foreground = Screen.colors.Brown },
- [4] = { foreground = Screen.colors.Cyan4 },
- [5] = { foreground = Screen.colors.Magenta },
- [6] = { foreground = Screen.colors.Cyan4, url = url },
- [7] = { underline = true, foreground = Screen.colors.SlateBlue },
- },
- }
+ {1:<<<}k^{2}}+\{100:lim}_{w \to 0}x$^. |
+ |
+ {18:```}{15:c} |
+ {25:printf}{16:(}{26:'Hello World!'}{16:);} |
+ {18:```} |
+ |
+ ]],
+ })
end)
end)
+
+it('starting and stopping treesitter highlight in init.lua works #29541', function()
+ t.write_file(
+ 'Xinit.lua',
+ [[
+ vim.bo.ft = 'c'
+ vim.treesitter.start()
+ vim.treesitter.stop()
+ ]]
+ )
+ finally(function()
+ os.remove('Xinit.lua')
+ end)
+ clear({ args = { '-u', 'Xinit.lua' } })
+ eq('', api.nvim_get_vvar('errmsg'))
+
+ local screen = Screen.new(65, 18)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = { bold = true, foreground = Screen.colors.Blue1 },
+ [2] = { foreground = Screen.colors.Blue1 },
+ [3] = { bold = true, foreground = Screen.colors.SeaGreen4 },
+ [4] = { bold = true, foreground = Screen.colors.Brown },
+ [5] = { foreground = Screen.colors.Magenta },
+ [6] = { foreground = Screen.colors.Red },
+ [7] = { bold = true, foreground = Screen.colors.SlateBlue },
+ [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
+ [9] = { foreground = Screen.colors.Magenta, background = Screen.colors.Red },
+ [10] = { foreground = Screen.colors.Red, background = Screen.colors.Red },
+ [11] = { foreground = Screen.colors.Cyan4 },
+ }
+
+ fn.setreg('r', hl_text_c)
+ feed('i<C-R><C-O>r<Esc>gg')
+ -- legacy syntax highlighting is used
+ screen:expect(hl_grid_legacy_c)
+end)
diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua
index f5acfe7c4a..1f7d15cc96 100644
--- a/test/functional/treesitter/inspect_tree_spec.lua
+++ b/test/functional/treesitter/inspect_tree_spec.lua
@@ -22,10 +22,10 @@ describe('vim.treesitter.inspect_tree', function()
print()
]])
- exec_lua([[
+ exec_lua(function()
vim.treesitter.start(0, 'lua')
vim.treesitter.inspect_tree()
- ]])
+ end)
expect_tree [[
(chunk ; [0, 0] - [2, 0]
@@ -37,22 +37,26 @@ describe('vim.treesitter.inspect_tree', function()
it('can toggle to show anonymous nodes', function()
insert([[
- print()
+ print('hello')
]])
- exec_lua([[
+ exec_lua(function()
vim.treesitter.start(0, 'lua')
vim.treesitter.inspect_tree()
- ]])
+ end)
feed('a')
expect_tree [[
(chunk ; [0, 0] - [2, 0]
- (function_call ; [0, 0] - [0, 7]
+ (function_call ; [0, 0] - [0, 14]
name: (identifier) ; [0, 0] - [0, 5]
- arguments: (arguments ; [0, 5] - [0, 7]
+ arguments: (arguments ; [0, 5] - [0, 14]
"(" ; [0, 5] - [0, 6]
- ")"))) ; [0, 6] - [0, 7]
+ (string ; [0, 6] - [0, 13]
+ start: "'" ; [0, 6] - [0, 7]
+ content: (string_content) ; [0, 7] - [0, 12]
+ end: "'") ; [0, 12] - [0, 13]
+ ")"))) ; [0, 13] - [0, 14]
]]
end)
@@ -63,11 +67,11 @@ describe('vim.treesitter.inspect_tree', function()
```
]])
- exec_lua([[
+ exec_lua(function()
vim.treesitter.start(0, 'markdown')
vim.treesitter.get_parser():parse()
vim.treesitter.inspect_tree()
- ]])
+ end)
expect_tree [[
(document ; [0, 0] - [4, 0]
@@ -92,11 +96,11 @@ describe('vim.treesitter.inspect_tree', function()
```
]])
- exec_lua([[
+ exec_lua(function()
vim.treesitter.start(0, 'markdown')
vim.treesitter.get_parser():parse()
vim.treesitter.inspect_tree()
- ]])
+ end)
feed('I')
expect_tree [[
@@ -114,4 +118,57 @@ describe('vim.treesitter.inspect_tree', function()
(fenced_code_block_delimiter)))) ; [2, 0] - [2, 3] markdown
]]
end)
+
+ it('updates source and tree buffer windows and closes them correctly', function()
+ insert([[
+ print()
+ ]])
+
+ -- setup two windows for the source buffer
+ exec_lua(function()
+ _G.source_win = vim.api.nvim_get_current_win()
+ vim.api.nvim_open_win(0, false, {
+ win = 0,
+ split = 'left',
+ })
+ end)
+
+ -- setup three windows for the tree buffer
+ exec_lua(function()
+ vim.treesitter.start(0, 'lua')
+ vim.treesitter.inspect_tree()
+ _G.tree_win = vim.api.nvim_get_current_win()
+ _G.tree_win_copy_1 = vim.api.nvim_open_win(0, false, {
+ win = 0,
+ split = 'left',
+ })
+ _G.tree_win_copy_2 = vim.api.nvim_open_win(0, false, {
+ win = 0,
+ split = 'left',
+ })
+ end)
+
+ -- close original source window
+ exec_lua('vim.api.nvim_win_close(source_win, false)')
+
+ -- navigates correctly to the remaining source buffer window
+ feed('<CR>')
+ eq('', n.api.nvim_get_vvar('errmsg'))
+
+ -- close original tree window
+ exec_lua(function()
+ vim.api.nvim_set_current_win(_G.tree_win_copy_1)
+ vim.api.nvim_win_close(_G.tree_win, false)
+ end)
+
+ -- navigates correctly to the remaining source buffer window
+ feed('<CR>')
+ eq('', n.api.nvim_get_vvar('errmsg'))
+
+ -- close source buffer window and all remaining tree windows
+ t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)')
+
+ eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_1)'))
+ eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_2)'))
+ end)
end)
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index 40c974beee..e1e34fcecc 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -8,6 +8,7 @@ local exec_lua = n.exec_lua
local pcall_err = t.pcall_err
local matches = t.matches
local insert = n.insert
+local NIL = vim.NIL
before_each(clear)
@@ -15,10 +16,12 @@ describe('treesitter language API', function()
-- error tests not requiring a parser library
it('handles missing language', function()
eq(
- ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"',
pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')")
)
+ eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })"))
+
-- actual message depends on platform
matches(
"Failed to load parser for language 'borklang': uv_dlopen: .+",
@@ -28,37 +31,33 @@ describe('treesitter language API', function()
)
)
- eq(false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang')"))
+ eq(NIL, exec_lua("return vim.treesitter.language.add('borklang')"))
eq(
false,
exec_lua("return pcall(vim.treesitter.language.add, 'borklang', { path = 'borkbork.so' })")
)
- eq(
- ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
- pcall_err(exec_lua, "parser = vim.treesitter.language.inspect('borklang')")
- )
-
matches(
'Failed to load parser: uv_dlsym: .+',
pcall_err(exec_lua, 'vim.treesitter.language.add("c", { symbol_name = "borklang" })')
)
end)
- it('shows error for invalid language name', function()
- eq(
- ".../language.lua:0: '/foo/' is not a valid language name",
- pcall_err(exec_lua, 'vim.treesitter.language.add("/foo/")')
- )
+ it('does not load parser for invalid language name', function()
+ eq(NIL, exec_lua('vim.treesitter.language.add("/foo/")'))
end)
it('inspects language', function()
- local keys, fields, symbols = unpack(exec_lua([[
+ local keys, fields, symbols = unpack(exec_lua(function()
local lang = vim.treesitter.language.inspect('c')
local keys, symbols = {}, {}
- for k,_ in pairs(lang) do
- keys[k] = true
+ for k, v in pairs(lang) do
+ if type(v) == 'boolean' then
+ keys[k] = v
+ else
+ keys[k] = true
+ end
end
-- symbols array can have "holes" and is thus not a valid msgpack array
@@ -66,10 +65,10 @@ describe('treesitter language API', function()
for _, v in pairs(lang.symbols) do
table.insert(symbols, v)
end
- return {keys, lang.fields, symbols}
- ]]))
+ return { keys, lang.fields, symbols }
+ end))
- eq({ fields = true, symbols = true, _abi_version = true }, keys)
+ eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys)
local fset = {}
for _, f in pairs(fields) do
@@ -101,9 +100,10 @@ describe('treesitter language API', function()
command('set filetype=borklang')
-- Should throw an error when filetype changes to borklang
eq(
- ".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ '.../treesitter.lua:0: Parser could not be created for buffer 1 and language "borklang"',
pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')")
)
+ eq(NIL, exec_lua("return vim.treesitter.get_parser(0, 'borklang', { error = false })"))
end
)
@@ -113,12 +113,14 @@ describe('treesitter language API', function()
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())'))
+ eq(
+ '<node translation_unit>',
+ exec_lua(function()
+ local langtree = vim.treesitter.get_parser(0, 'c')
+ local tree = langtree:tree_for_range({ 1, 3, 1, 3 })
+ return tostring(tree:root())
+ end)
+ )
end)
it('retrieve the tree given a range when range is out of bounds relative to buffer', function()
@@ -127,12 +129,14 @@ describe('treesitter language API', function()
int x = 3;
}]])
- exec_lua([[
- langtree = vim.treesitter.get_parser(0, "c")
- tree = langtree:tree_for_range({10, 10, 10, 10})
- ]])
-
- eq('<node translation_unit>', exec_lua('return tostring(tree:root())'))
+ eq(
+ '<node translation_unit>',
+ exec_lua(function()
+ local langtree = vim.treesitter.get_parser(0, 'c')
+ local tree = langtree:tree_for_range({ 10, 10, 10, 10 })
+ return tostring(tree:root())
+ end)
+ )
end)
it('retrieve the node given a range', function()
@@ -141,11 +145,24 @@ describe('treesitter language API', function()
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(function()
+ local langtree = vim.treesitter.get_parser(0, 'c')
+ local node = langtree:named_node_for_range({ 1, 3, 1, 3 })
+ return tostring(node)
+ end)
+ )
+ end)
+
+ it('retrieve an anonymous node given a range', function()
+ insert([[vim.fn.input()]])
+
+ exec_lua(function()
+ _G.langtree = vim.treesitter.get_parser(0, 'lua')
+ _G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 })
+ end)
- eq('<node primitive_type>', exec_lua('return tostring(node)'))
+ eq('.', exec_lua('return node:type()'))
end)
end)
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index 96579f296b..d07ed35368 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -18,43 +18,60 @@ describe('treesitter node API', function()
it('double free tree', function()
insert('F')
- exec_lua([[
+ exec_lua(function()
vim.treesitter.start(0, 'lua')
vim.treesitter.get_node():tree()
vim.treesitter.get_node():tree()
collectgarbage()
- ]])
+ end)
assert_alive()
end)
it('double free tree 2', function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
local x = parser:parse()[1]:root():tree()
- vim.api.nvim_buf_set_text(0, 0,0, 0,0, {'y'})
+ vim.api.nvim_buf_set_text(0, 0, 0, 0, 0, { 'y' })
parser:parse()
- vim.api.nvim_buf_set_text(0, 0,0, 0,1, {'z'})
+ vim.api.nvim_buf_set_text(0, 0, 0, 0, 1, { 'z' })
parser:parse()
collectgarbage()
x:root()
- ]])
+ end)
assert_alive()
end)
it('get_node() with lang given', function()
-- this buffer doesn't have filetype set!
insert('local foo = function() end')
- exec_lua([[
- node = vim.treesitter.get_node({
+ exec_lua(function()
+ _G.node = vim.treesitter.get_node({
bufnr = 0,
- pos = { 0, 6 }, -- on "foo"
+ pos = { 0, 6 }, -- on "foo"
lang = 'lua',
})
- ]])
+ end)
eq('foo', lua_eval('vim.treesitter.get_node_text(node, 0)'))
eq('identifier', lua_eval('node:type()'))
end)
+ it('get_node() with anonymous nodes included', function()
+ insert([[print('test')]])
+
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'lua')
+ _G.tree = _G.parser:parse()[1]
+ _G.node = vim.treesitter.get_node({
+ bufnr = 0,
+ pos = { 0, 6 }, -- on the first apostrophe
+ include_anonymous = true,
+ })
+ end)
+
+ eq("'", lua_eval('node:type()'))
+ eq(false, lua_eval('node:named()'))
+ end)
+
it('can move between siblings', function()
insert([[
int main(int x, int y, int z) {
@@ -62,16 +79,16 @@ describe('treesitter node API', function()
}
]])
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- root = tree:root()
- lang = vim.treesitter.language.inspect('c')
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ _G.root = tree:root()
+ vim.treesitter.language.inspect('c')
- function node_text(node)
+ function _G.node_text(node)
return vim.treesitter.get_node_text(node, 0)
end
- ]])
+ end)
exec_lua 'node = root:descendant_for_range(0, 11, 0, 16)'
eq('int x', lua_eval('node_text(node)'))
@@ -101,13 +118,13 @@ describe('treesitter node API', function()
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()
+ local len = exec_lua(function()
+ local tree = vim.treesitter.get_parser(0, 'c'):parse()[1]
+ local node = assert(tree:root():child(0))
+ _G.children = node:named_children()
- return #children
- ]])
+ return #_G.children
+ end)
eq(3, len)
eq('<node compound_statement>', lua_eval('tostring(children[3])'))
@@ -119,11 +136,11 @@ describe('treesitter node API', function()
int x = 3;
}]])
- exec_lua([[
- tree = vim.treesitter.get_parser(0, "c"):parse()[1]
- root = tree:root()
- node = root:child(0):child(2)
- ]])
+ exec_lua(function()
+ local tree = vim.treesitter.get_parser(0, 'c'):parse()[1]
+ _G.root = tree:root()
+ _G.node = _G.root:child(0):child(2)
+ end)
eq(lua_eval('tostring(root)'), lua_eval('tostring(node:root())'))
end)
@@ -134,11 +151,11 @@ describe('treesitter node API', function()
int x = 3;
}]])
- exec_lua([[
- tree = vim.treesitter.get_parser(0, "c"):parse()[1]
- root = tree:root()
- child = root:child(0):child(0)
- ]])
+ exec_lua(function()
+ local tree = vim.treesitter.get_parser(0, 'c'):parse()[1]
+ _G.root = tree:root()
+ _G.child = _G.root:child(0):child(0)
+ end)
eq(28, lua_eval('root:byte_length()'))
eq(3, lua_eval('child:byte_length()'))
@@ -150,15 +167,15 @@ describe('treesitter node API', function()
int x = 3;
}]])
- exec_lua([[
- tree = vim.treesitter.get_parser(0, "c"):parse()[1]
- root = tree:root()
- main = root:child(0)
- body = main:child(2)
- statement = body:child(1)
- declarator = statement:child(1)
- value = declarator:child(1)
- ]])
+ exec_lua(function()
+ local tree = vim.treesitter.get_parser(0, 'c'):parse()[1]
+ _G.root = tree:root()
+ _G.main = _G.root:child(0)
+ _G.body = _G.main:child(2)
+ _G.statement = _G.body:child(1)
+ _G.declarator = _G.statement:child(1)
+ _G.value = _G.declarator:child(1)
+ end)
eq(lua_eval('main:type()'), lua_eval('root:child_containing_descendant(value):type()'))
eq(lua_eval('body:type()'), lua_eval('main:child_containing_descendant(value):type()'))
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index dbd6bb3c23..c8829f4785 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -12,9 +12,9 @@ local feed = n.feed
describe('treesitter parser API', function()
before_each(function()
clear()
- exec_lua [[
+ exec_lua(function()
vim.g.__ts_debug = 1
- ]]
+ end)
end)
it('parses buffer', function()
@@ -23,12 +23,12 @@ describe('treesitter parser API', function()
int x = 3;
}]])
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- root = tree:root()
- lang = vim.treesitter.language.inspect('c')
- ]])
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c')
+ _G.tree = _G.parser:parse()[1]
+ _G.root = _G.tree:root()
+ _G.lang = vim.treesitter.language.inspect('c')
+ end)
eq('<tree>', exec_lua('return tostring(tree)'))
eq('<node translation_unit>', exec_lua('return tostring(root)'))
@@ -59,11 +59,11 @@ describe('treesitter parser API', function()
)
feed('2G7|ay')
- exec_lua([[
- tree2 = parser:parse()[1]
- root2 = tree2:root()
- descendant2 = root2:descendant_for_range(1,2,1,13)
- ]])
+ exec_lua(function()
+ _G.tree2 = _G.parser:parse()[1]
+ _G.root2 = _G.tree2:root()
+ _G.descendant2 = _G.root2:descendant_for_range(1, 2, 1, 13)
+ end)
eq(false, exec_lua('return tree2 == tree1'))
eq(false, exec_lua('return root2 == root'))
eq('<node declaration>', exec_lua('return tostring(descendant2)'))
@@ -112,17 +112,17 @@ void ui_refresh(void)
it('allows to iterate over nodes children', function()
insert(test_text)
- local res = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
+ local res = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
- func_node = parser:parse()[1]:root():child(0)
+ local func_node = parser:parse()[1]:root():child(0)
- res = {}
+ local res = {}
for node, field in func_node:iter_children() do
table.insert(res, { node:type(), field })
end
return res
- ]])
+ end)
eq({
{ 'primitive_type', 'type' },
@@ -135,9 +135,7 @@ void ui_refresh(void)
insert(test_text)
eq(
- '.../treesitter.lua:0: There is no parser available for buffer 1 and one'
- .. ' could not be created because lang could not be determined. Either'
- .. ' pass lang or set the buffer filetype',
+ '.../treesitter.lua:0: Parser not found for buffer 1: language could not be determined',
pcall_err(exec_lua, 'vim.treesitter.get_parser(0)')
)
@@ -148,43 +146,43 @@ void ui_refresh(void)
it('allows to get a child by field', function()
insert(test_text)
- local res = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
+ local res = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
- func_node = parser:parse()[1]:root():child(0)
+ _G.func_node = parser:parse()[1]:root():child(0)
local res = {}
- for _, node in ipairs(func_node:field("type")) do
+ for _, node in ipairs(_G.func_node:field('type')) do
table.insert(res, { node:type(), node:range() })
end
return res
- ]])
+ end)
eq({ { 'primitive_type', 0, 0, 0, 4 } }, res)
- local res_fail = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c")
+ local res_fail = exec_lua(function()
+ vim.treesitter.get_parser(0, 'c')
- return #func_node:field("foo") == 0
- ]])
+ return #_G.func_node:field('foo') == 0
+ end)
assert(res_fail)
end)
it('supports getting text of multiline node', function()
insert(test_text)
- local res = exec_lua([[
- local parser = vim.treesitter.get_parser(0, "c")
+ local res = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
local tree = parser:parse()[1]
return vim.treesitter.get_node_text(tree:root(), 0)
- ]])
+ end)
eq(test_text, res)
- local res2 = exec_lua([[
- local parser = vim.treesitter.get_parser(0, "c")
+ local res2 = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
local root = parser:parse()[1]:root()
return vim.treesitter.get_node_text(root:child(0):child(0), 0)
- ]])
+ end)
eq('void', res2)
end)
@@ -196,7 +194,7 @@ end]]
insert(text)
eq(
'',
- exec_lua [[
+ exec_lua(function()
local fake_node = {}
function fake_node:start()
return 3, 0, 23
@@ -211,7 +209,7 @@ end]]
return 3, 0, 3, 0
end
return vim.treesitter.get_node_text(fake_node, 0)
- ]]
+ end)
)
end)
@@ -221,7 +219,7 @@ end]]
{}
```]]
insert(text)
- local result = exec_lua([[
+ local result = exec_lua(function()
local fake_node = {}
function fake_node:start()
return 1, 0, 7
@@ -233,38 +231,38 @@ end]]
return 1, 0, 1, 0
end
return vim.treesitter.get_node_text(fake_node, 0) == ''
- ]])
+ end)
eq(true, result)
end)
it('allows to set simple ranges', function()
insert(test_text)
- local res = exec_lua [[
- parser = vim.treesitter.get_parser(0, "c")
- return { parser:parse()[1]:root():range() }
- ]]
+ local res = exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c')
+ return { _G.parser:parse()[1]:root():range() }
+ end)
eq({ 0, 0, 19, 0 }, res)
-- The following sets the included ranges for the current parser
-- As stated here, this only includes the function (thus the whole buffer, without the last line)
- local res2 = exec_lua [[
- local root = parser:parse()[1]:root()
- parser:set_included_regions({{root:child(0)}})
- parser:invalidate()
- return { parser:parse(true)[1]:root():range() }
- ]]
+ local res2 = exec_lua(function()
+ local root = _G.parser:parse()[1]:root()
+ _G.parser:set_included_regions({ { root:child(0) } })
+ _G.parser:invalidate()
+ return { _G.parser:parse(true)[1]:root():range() }
+ end)
eq({ 0, 0, 18, 1 }, res2)
eq({ { { 0, 0, 0, 18, 1, 512 } } }, exec_lua [[ return parser:included_regions() ]])
- local range_tbl = exec_lua [[
- parser:set_included_regions { { { 0, 0, 17, 1 } } }
- parser:parse()
- return parser:included_regions()
- ]]
+ local range_tbl = exec_lua(function()
+ _G.parser:set_included_regions { { { 0, 0, 17, 1 } } }
+ _G.parser:parse()
+ return _G.parser:included_regions()
+ end)
eq({ { { 0, 0, 0, 17, 1, 508 } } }, range_tbl)
end)
@@ -272,25 +270,25 @@ end]]
it('allows to set complex ranges', function()
insert(test_text)
- local res = exec_lua [[
- parser = vim.treesitter.get_parser(0, "c")
- query = vim.treesitter.query.parse("c", "(declaration) @decl")
+ local res = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local query = vim.treesitter.query.parse('c', '(declaration) @decl')
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
- table.insert(nodes, node)
- end
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
+ table.insert(nodes, node)
+ end
- parser:set_included_regions({nodes})
+ parser:set_included_regions({ nodes })
- local root = parser:parse(true)[1]:root()
+ local root = parser:parse(true)[1]:root()
- local res = {}
- for i=0,(root:named_child_count() - 1) do
- table.insert(res, { root:named_child(i):range() })
- end
- return res
- ]]
+ local res = {}
+ for i = 0, (root:named_child_count() - 1) do
+ table.insert(res, { root:named_child(i):range() })
+ end
+ return res
+ end)
eq({
{ 2, 2, 2, 40 },
@@ -304,10 +302,10 @@ end]]
end)
it('allows to create string parsers', function()
- local ret = exec_lua [[
- local parser = vim.treesitter.get_string_parser("int foo = 42;", "c")
+ local ret = exec_lua(function()
+ local parser = vim.treesitter.get_string_parser('int foo = 42;', 'c')
return { parser:parse()[1]:root():range() }
- ]]
+ end)
eq({ 0, 0, 0, 13 }, ret)
end)
@@ -318,33 +316,31 @@ end]]
int bar = 13;
]]
- local ret = exec_lua(
- [[
- local str = ...
- local parser = vim.treesitter.get_string_parser(str, "c")
+ local ret = exec_lua(function(str)
+ local parser = vim.treesitter.get_string_parser(str, 'c')
- local nodes = {}
- local query = vim.treesitter.query.parse("c", '((identifier) @id (#eq? @id "foo"))')
+ local nodes = {}
+ local query = vim.treesitter.query.parse('c', '((identifier) @id (#eq? @id "foo"))')
- for _, node in query:iter_captures(parser:parse()[1]:root(), str) do
- table.insert(nodes, { node:range() })
- end
+ for _, node in query:iter_captures(parser:parse()[1]:root(), str) do
+ table.insert(nodes, { node:range() })
+ end
- return nodes
- ]],
- txt
- )
+ return nodes
+ end, txt)
eq({ { 0, 10, 0, 13 } }, ret)
end)
describe('when creating a language tree', function()
local function get_ranges()
- return exec_lua [[
+ return exec_lua(function()
local result = {}
- parser:for_each_tree(function(tree) table.insert(result, {tree:root():range()}) end)
+ _G.parser:for_each_tree(function(tree)
+ table.insert(result, { tree:root():range() })
+ end)
return result
- ]]
+ end)
end
before_each(function()
@@ -360,16 +356,17 @@ int x = INT_MAX;
describe('when parsing regions independently', function()
it('should inject a language', function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c', {
injections = {
c = (
- '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) ' ..
- '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
- )
- }})
- parser:parse(true)
- ]])
+ '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c")) '
+ .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
+ ),
+ },
+ })
+ _G.parser:parse(true)
+ end)
eq('table', exec_lua('return type(parser:children().c)'))
eq(5, exec_lua('return #parser:children().c:trees()'))
@@ -397,16 +394,17 @@ int x = INT_MAX;
describe('when parsing regions combined', function()
it('should inject a language', function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c', {
injections = {
c = (
- '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) ' ..
- '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))'
- )
- }})
- parser:parse(true)
- ]])
+ '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined)) '
+ .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c") (#set! injection.combined))'
+ ),
+ },
+ })
+ _G.parser:parse(true)
+ end)
eq('table', exec_lua('return type(parser:children().c)'))
eq(2, exec_lua('return #parser:children().c:trees()'))
@@ -447,16 +445,17 @@ int x = INT_MAX;
describe('when using injection.self', function()
it('should inject the source language', function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c', {
injections = {
c = (
- '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) ' ..
- '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))'
- )
- }})
- parser:parse(true)
- ]])
+ '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) '
+ .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))'
+ ),
+ },
+ })
+ _G.parser:parse(true)
+ end)
eq('table', exec_lua('return type(parser:children().c)'))
eq(5, exec_lua('return #parser:children().c:trees()'))
@@ -484,16 +483,17 @@ int x = INT_MAX;
describe('when using the offset directive', function()
it('should shift the range by the directive amount', function()
- exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c', {
injections = {
c = (
- '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) ' ..
- '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
- )
- }})
- parser:parse(true)
- ]])
+ '(preproc_def ((preproc_arg) @injection.content (#set! injection.language "c") (#offset! @injection.content 0 2 0 -1))) '
+ .. '(preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "c"))'
+ ),
+ },
+ })
+ _G.parser:parse(true)
+ end)
eq('table', exec_lua('return type(parser:children().c)'))
eq({
@@ -506,7 +506,7 @@ int x = INT_MAX;
}, get_ranges())
end)
it('should list all directives', function()
- local res_list = exec_lua [[
+ local res_list = exec_lua(function()
local query = vim.treesitter.query
local list = query.list_directives()
@@ -514,7 +514,7 @@ int x = INT_MAX;
table.sort(list)
return list
- ]]
+ end)
eq({ 'gsub!', 'offset!', 'set!', 'trim!' }, res_list)
end)
@@ -530,18 +530,18 @@ int x = INT_MAX;
end)
it('should return the correct language tree', function()
- local result = exec_lua([[
- parser = vim.treesitter.get_parser(0, "c", {
+ local result = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c', {
injections = {
- c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))'
- }
+ c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "c"))',
+ },
})
parser:parse(true)
- local sub_tree = parser:language_for_range({1, 18, 1, 19})
+ local sub_tree = parser:language_for_range({ 1, 18, 1, 19 })
return sub_tree == parser:children().c
- ]])
+ end)
eq(true, result)
end)
@@ -555,23 +555,23 @@ print()
end)
it('ignores optional captures #23100', function()
- local result = exec_lua([[
- parser = vim.treesitter.get_parser(0, "lua", {
+ local result = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'lua', {
injections = {
lua = (
- '(function_call ' ..
- '(arguments ' ..
- '(string)? @injection.content ' ..
- '(number)? @injection.content ' ..
- '(#offset! @injection.content 0 1 0 -1) ' ..
- '(#set! injection.language "c")))'
- )
- }
+ '(function_call '
+ .. '(arguments '
+ .. '(string)? @injection.content '
+ .. '(number)? @injection.content '
+ .. '(#offset! @injection.content 0 1 0 -1) '
+ .. '(#set! injection.language "c")))'
+ ),
+ },
})
parser:parse(true)
return parser:is_valid()
- ]])
+ end)
eq(true, result)
end)
@@ -584,18 +584,14 @@ print()
int x = 3;
]])
- local result = exec_lua([[
- local result
-
- query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! "key" "value"))')
- parser = vim.treesitter.get_parser(0, "c")
-
- for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do
- result = metadata.key
- end
+ local result = exec_lua(function()
+ local query =
+ vim.treesitter.query.parse('c', '((number_literal) @number (#set! "key" "value"))')
+ local parser = vim.treesitter.get_parser(0, 'c')
- return result
- ]])
+ local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)()
+ return metadata.key
+ end)
eq('value', result)
end)
@@ -606,19 +602,17 @@ print()
int x = 3;
]])
- local result = exec_lua([[
- local query = vim.treesitter.query
- local value
+ local result = exec_lua(function()
+ local query = vim.treesitter.query.parse(
+ 'c',
+ '((number_literal) @number (#set! @number "key" "value"))'
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
- query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value"))')
- parser = vim.treesitter.get_parser(0, "c")
-
- for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do
- for _, nested_tbl in pairs(metadata) do
- return nested_tbl.key
- end
- end
- ]])
+ local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)()
+ local _, nested_tbl = next(metadata)
+ return nested_tbl.key
+ end)
eq('value', result)
end)
@@ -628,19 +622,17 @@ print()
int x = 3;
]])
- local result = exec_lua([[
- local query = vim.treesitter.query
- local result
-
- query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))')
- parser = vim.treesitter.get_parser(0, "c")
+ local result = exec_lua(function()
+ local query = vim.treesitter.query.parse(
+ 'c',
+ '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))'
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
- for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0, 0, -1, { all = true }) do
- for _, nested_tbl in pairs(metadata) do
- return nested_tbl
- end
- end
- ]])
+ local _, _, metadata = query:iter_matches(parser:parse()[1]:root(), 0, 0, -1)()
+ local _, nested_tbl = next(metadata)
+ return nested_tbl
+ end)
local expected = {
['key'] = 'value',
['key2'] = 'value2',
@@ -663,24 +655,21 @@ print()
(function_definition) @function
]]
- exec_lua([[
+ exec_lua(function()
vim.treesitter.start(0, 'c')
- ]])
+ end)
local function run_query()
- return exec_lua(
- [[
- local query = vim.treesitter.query.parse("c", ...)
- parser = vim.treesitter.get_parser()
- tree = parser:parse()[1]
- res = {}
- for id, node in query:iter_captures(tree:root()) do
- table.insert(res, {query.captures[id], node:range()})
- end
- return res
- ]],
- query0
- )
+ return exec_lua(function()
+ local query = vim.treesitter.query.parse('c', query0)
+ local parser = vim.treesitter.get_parser()
+ local tree = parser:parse()[1]
+ local res = {}
+ for id, node in query:iter_captures(tree:root()) do
+ table.insert(res, { query.captures[id], node:range() })
+ end
+ return res
+ end)
end
eq({
@@ -718,18 +707,15 @@ print()
]]
]==]
- local r = exec_lua(
- [[
- local parser = vim.treesitter.get_string_parser(..., 'lua')
- parser:parse(true)
- local ranges = {}
- parser:for_each_tree(function(tstree, tree)
- ranges[tree:lang()] = { tstree:root():range(true) }
- end)
- return ranges
- ]],
- source
- )
+ local r = exec_lua(function()
+ local parser = vim.treesitter.get_string_parser(source, 'lua')
+ parser:parse(true)
+ local ranges = {}
+ parser:for_each_tree(function(tstree, tree)
+ ranges[tree:lang()] = { tstree:root():range(true) }
+ end)
+ return ranges
+ end)
eq({
lua = { 0, 6, 6, 16, 4, 438 },
@@ -741,19 +727,14 @@ print()
-- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure
-- add_bytes() produces the same result.
- local rb = exec_lua(
- [[
- local r, source = ...
- local add_bytes = require('vim.treesitter._range').add_bytes
- for lang, range in pairs(r) do
- r[lang] = {range[1], range[2], range[4], range[5]}
- r[lang] = add_bytes(source, r[lang])
- end
- return r
- ]],
- r,
- source
- )
+ local rb = exec_lua(function()
+ local add_bytes = require('vim.treesitter._range').add_bytes
+ for lang, range in pairs(r) do
+ r[lang] = { range[1], range[2], range[4], range[5] }
+ r[lang] = add_bytes(source, r[lang])
+ end
+ return r
+ end)
eq(rb, r)
end)
@@ -766,25 +747,25 @@ print()
]]
-- This is not a valid injection since (code) has children and include-children is not set
- exec_lua [[
- parser1 = require('vim.treesitter.languagetree').new(0, "vimdoc", {
+ exec_lua(function()
+ _G.parser1 = require('vim.treesitter.languagetree').new(0, 'vimdoc', {
injections = {
- vimdoc = "((codeblock (language) @injection.language (code) @injection.content))"
- }
+ vimdoc = '((codeblock (language) @injection.language (code) @injection.content))',
+ },
})
- parser1:parse(true)
- ]]
+ _G.parser1:parse(true)
+ end)
eq(0, exec_lua('return #vim.tbl_keys(parser1:children())'))
- exec_lua [[
- parser2 = require('vim.treesitter.languagetree').new(0, "vimdoc", {
+ exec_lua(function()
+ _G.parser2 = require('vim.treesitter.languagetree').new(0, 'vimdoc', {
injections = {
- vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))"
- }
+ vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))',
+ },
})
- parser2:parse(true)
- ]]
+ _G.parser2:parse(true)
+ end)
eq(1, exec_lua('return #vim.tbl_keys(parser2:children())'))
eq({ { { 1, 0, 21, 2, 0, 42 } } }, exec_lua('return parser2:children().lua:included_regions()'))
@@ -821,46 +802,46 @@ print()
<
]])
- exec_lua [[
- parser = require('vim.treesitter.languagetree').new(0, "vimdoc", {
+ exec_lua(function()
+ _G.parser = require('vim.treesitter.languagetree').new(0, 'vimdoc', {
injections = {
- vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))"
- }
+ vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))',
+ },
})
- ]]
+ end)
--- Do not parse injections by default
eq(
0,
- exec_lua [[
- parser:parse()
- return #vim.tbl_keys(parser:children())
- ]]
+ exec_lua(function()
+ _G.parser:parse()
+ return #vim.tbl_keys(_G.parser:children())
+ end)
)
--- Only parse injections between lines 0, 2
eq(
1,
- exec_lua [[
- parser:parse({0, 2})
- return #parser:children().lua:trees()
- ]]
+ exec_lua(function()
+ _G.parser:parse({ 0, 2 })
+ return #_G.parser:children().lua:trees()
+ end)
)
eq(
2,
- exec_lua [[
- parser:parse({2, 6})
- return #parser:children().lua:trees()
- ]]
+ exec_lua(function()
+ _G.parser:parse({ 2, 6 })
+ return #_G.parser:children().lua:trees()
+ end)
)
eq(
7,
- exec_lua [[
- parser:parse(true)
- return #parser:children().lua:trees()
- ]]
+ exec_lua(function()
+ _G.parser:parse(true)
+ return #_G.parser:children().lua:trees()
+ end)
)
end)
@@ -876,13 +857,13 @@ print()
feed(':set ft=help<cr>')
- exec_lua [[
- vim.treesitter.get_parser(0, "vimdoc", {
+ exec_lua(function()
+ vim.treesitter.get_parser(0, 'vimdoc', {
injections = {
- vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))"
- }
+ vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))',
+ },
})
- ]]
+ end)
end)
it('is valid excluding, invalid including children initially', function()
diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua
index c3a376cd71..c97619c913 100644
--- a/test/functional/treesitter/query_spec.lua
+++ b/test/functional/treesitter/query_spec.lua
@@ -10,28 +10,26 @@ local pcall_err = t.pcall_err
local api = n.api
local fn = n.fn
-local get_query_result_code = [[
- function get_query_result(query_text)
- cquery = vim.treesitter.query.parse("c", query_text)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for cid, node in cquery:iter_captures(tree:root(), 0) do
- -- can't transmit node over RPC. just check the name, range, and text
- local text = vim.treesitter.get_node_text(node, 0)
- local range = {node:range()}
- table.insert(res, { cquery.captures[cid], node:type(), range, text })
- end
- return res
+local function get_query_result(query_text)
+ local cquery = vim.treesitter.query.parse('c', query_text)
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for cid, node in cquery:iter_captures(tree:root(), 0) do
+ -- can't transmit node over RPC. just check the name, range, and text
+ local text = vim.treesitter.get_node_text(node, 0)
+ local range = { node:range() }
+ table.insert(res, { cquery.captures[cid], node:type(), range, text })
end
-]]
+ return res
+end
describe('treesitter query API', function()
before_each(function()
clear()
- exec_lua [[
+ exec_lua(function()
vim.g.__ts_debug = 1
- ]]
+ end)
end)
local test_text = [[
@@ -71,9 +69,9 @@ void ui_refresh(void)
it('supports runtime queries', function()
---@type string[]
- local ret = exec_lua [[
- return vim.treesitter.query.get("c", "highlights").captures
- ]]
+ local ret = exec_lua(function()
+ return vim.treesitter.query.get('c', 'highlights').captures
+ end)
-- see $VIMRUNTIME/queries/c/highlights.scm
eq('variable', ret[1])
@@ -84,22 +82,17 @@ void ui_refresh(void)
local long_query = test_query:rep(100)
---@return number
local function q(_n)
- return exec_lua(
- [[
- local query, n = ...
- local before = vim.api.nvim__stats().ts_query_parse_count
- collectgarbage("stop")
- for i=1, n, 1 do
- cquery = vim.treesitter.query.parse("c", ...)
- end
- collectgarbage("restart")
- collectgarbage("collect")
- local after = vim.api.nvim__stats().ts_query_parse_count
- return after - before
- ]],
- long_query,
- _n
- )
+ return exec_lua(function()
+ local before = vim.api.nvim__stats().ts_query_parse_count
+ collectgarbage('stop')
+ for _ = 1, _n, 1 do
+ vim.treesitter.query.parse('c', long_query, _n)
+ end
+ collectgarbage('restart')
+ collectgarbage('collect')
+ local after = vim.api.nvim__stats().ts_query_parse_count
+ return after - before
+ end)
end
eq(1, q(1))
@@ -110,20 +103,17 @@ void ui_refresh(void)
it('supports query and iter by capture (iter_captures)', function()
insert(test_text)
- local res = exec_lua(
- [[
- cquery = vim.treesitter.query.parse("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
- -- can't transmit node over RPC. just check the name and range
- table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() })
- end
- return res
- ]],
- test_query
- )
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse('c', test_query)
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
+ -- can't transmit node over RPC. just check the name and range
+ table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() })
+ end
+ return res
+ end)
eq({
{ '@type', 'primitive_type', 8, 2, 8, 6 }, -- bool
@@ -143,26 +133,23 @@ void ui_refresh(void)
insert(test_text)
---@type table
- local res = exec_lua(
- [[
- cquery = vim.treesitter.query.parse("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do
- -- can't transmit node over RPC. just check the name and range
- local mrepr = {}
- for cid, nodes in pairs(match) do
- for _, node in ipairs(nodes) do
- table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
- end
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse('c', test_query)
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do
+ -- can't transmit node over RPC. just check the name and range
+ local mrepr = {}
+ for cid, nodes in pairs(match) do
+ for _, node in ipairs(nodes) do
+ table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
end
- table.insert(res, { pattern, mrepr })
end
- return res
- ]],
- test_query
- )
+ table.insert(res, { pattern, mrepr })
+ end
+ return res
+ end)
eq({
{ 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } },
@@ -191,20 +178,20 @@ void ui_refresh(void)
it('supports query and iter by capture for quantifiers', function()
insert(test_text)
- local res = exec_lua(
- [[
- cquery = vim.treesitter.query.parse("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
- -- can't transmit node over RPC. just check the name and range
- table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() })
- end
- return res
- ]],
- '(expression_statement (assignment_expression (call_expression)))+ @funccall'
- )
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse(
+ 'c',
+ '(expression_statement (assignment_expression (call_expression)))+ @funccall'
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for cid, node in cquery:iter_captures(tree:root(), 0, 7, 14) do
+ -- can't transmit node over RPC. just check the name and range
+ table.insert(res, { '@' .. cquery.captures[cid], node:type(), node:range() })
+ end
+ return res
+ end)
eq({
{ '@funccall', 'expression_statement', 11, 4, 11, 34 },
@@ -216,26 +203,26 @@ void ui_refresh(void)
it('supports query and iter by match for quantifiers', function()
insert(test_text)
- local res = exec_lua(
- [[
- cquery = vim.treesitter.query.parse("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = true }) do
- -- can't transmit node over RPC. just check the name and range
- local mrepr = {}
- for cid, nodes in pairs(match) do
- for _, node in ipairs(nodes) do
- table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
- end
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse(
+ 'c',
+ '(expression_statement (assignment_expression (call_expression)))+ @funccall'
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do
+ -- can't transmit node over RPC. just check the name and range
+ local mrepr = {}
+ for cid, nodes in pairs(match) do
+ for _, node in ipairs(nodes) do
+ table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
end
- table.insert(res, {pattern, mrepr})
end
- return res
- ]],
- '(expression_statement (assignment_expression (call_expression)))+ @funccall'
- )
+ table.insert(res, { pattern, mrepr })
+ end
+ return res
+ end, '(expression_statement (assignment_expression (call_expression)))+ @funccall')
eq({
{
@@ -249,23 +236,78 @@ void ui_refresh(void)
}, res)
end)
+ it('returns quantified matches in order of range #29344', function()
+ insert([[
+ int main() {
+ int a, b, c, d, e, f, g, h, i;
+ a = MIN(0, 1);
+ b = MIN(0, 1);
+ c = MIN(0, 1);
+ d = MIN(0, 1);
+ e = MIN(0, 1);
+ f = MIN(0, 1);
+ g = MIN(0, 1);
+ h = MIN(0, 1);
+ i = MIN(0, 1);
+ }
+ ]])
+
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse(
+ 'c',
+ '(expression_statement (assignment_expression (call_expression)))+ @funccall'
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do
+ -- can't transmit node over RPC. just check the name and range
+ local mrepr = {}
+ for cid, nodes in pairs(match) do
+ for _, node in ipairs(nodes) do
+ table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
+ end
+ end
+ table.insert(res, { pattern, mrepr })
+ end
+ return res
+ end)
+
+ eq({
+ {
+ 1,
+ {
+ { '@funccall', 'expression_statement', 2, 2, 2, 16 },
+ { '@funccall', 'expression_statement', 3, 2, 3, 16 },
+ { '@funccall', 'expression_statement', 4, 2, 4, 16 },
+ { '@funccall', 'expression_statement', 5, 2, 5, 16 },
+ { '@funccall', 'expression_statement', 6, 2, 6, 16 },
+ { '@funccall', 'expression_statement', 7, 2, 7, 16 },
+ { '@funccall', 'expression_statement', 8, 2, 8, 16 },
+ { '@funccall', 'expression_statement', 9, 2, 9, 16 },
+ { '@funccall', 'expression_statement', 10, 2, 10, 16 },
+ },
+ },
+ }, res)
+ end)
+
it('can match special regex characters like \\ * + ( with `vim-match?`', function()
insert('char* astring = "\\n"; (1 + 1) * 2 != 2;')
---@type table
- local res = exec_lua([[
- query = (
- '([_] @plus (#vim-match? @plus "^\\\\+$"))' ..
- '([_] @times (#vim-match? @times "^\\\\*$"))' ..
- '([_] @paren (#vim-match? @paren "^\\\\($"))' ..
- '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))' ..
- '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))'
+ local res = exec_lua(function()
+ local query = (
+ '([_] @plus (#vim-match? @plus "^\\\\+$"))'
+ .. '([_] @times (#vim-match? @times "^\\\\*$"))'
+ .. '([_] @paren (#vim-match? @paren "^\\\\($"))'
+ .. '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))'
+ .. '([_] @string (#vim-match? @string "^\\"\\\\\\\\n\\"$"))'
)
- cquery = vim.treesitter.query.parse("c", query)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do
+ local cquery = vim.treesitter.query.parse('c', query)
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do
-- can't transmit node over RPC. just check the name and range
local mrepr = {}
for cid, nodes in pairs(match) do
@@ -276,7 +318,7 @@ void ui_refresh(void)
table.insert(res, { pattern, mrepr })
end
return res
- ]])
+ end)
eq({
{ 2, { { '@times', '*', 0, 4, 0, 5 } } },
@@ -307,10 +349,9 @@ void ui_refresh(void)
return 0;
}
]])
- exec_lua(get_query_result_code)
local res0 = exec_lua(
- [[return get_query_result(...)]],
+ get_query_result,
[[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]]
)
eq({
@@ -319,7 +360,7 @@ void ui_refresh(void)
}, res0)
local res1 = exec_lua(
- [[return get_query_result(...)]],
+ get_query_result,
[[
((string_literal) @fizzbuzz-strings (#any-of? @fizzbuzz-strings
"\"number= %d FizzBuzz\\n\""
@@ -340,16 +381,15 @@ void ui_refresh(void)
int x = 123;
enum C { y = 124 };
int main() { int z = 125; }]])
- exec_lua(get_query_result_code)
local result = exec_lua(
- [[return get_query_result(...)]],
+ get_query_result,
[[((number_literal) @literal (#has-ancestor? @literal "function_definition"))]]
)
eq({ { 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' } }, result)
result = exec_lua(
- [[return get_query_result(...)]],
+ get_query_result,
[[((number_literal) @literal (#has-ancestor? @literal "function_definition" "enum_specifier"))]]
)
eq({
@@ -358,7 +398,7 @@ void ui_refresh(void)
}, result)
result = exec_lua(
- [[return get_query_result(...)]],
+ get_query_result,
[[((number_literal) @literal (#not-has-ancestor? @literal "enum_specifier"))]]
)
eq({
@@ -370,12 +410,15 @@ void ui_refresh(void)
it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function()
insert('char* astring = "Hello World!";')
- local res = exec_lua([[
- cquery = vim.treesitter.query.parse("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))')
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1, { all = true }) do
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse(
+ 'c',
+ '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))'
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 0, -1) do
-- can't transmit node over RPC. just check the name and range
local mrepr = {}
for cid, nodes in pairs(match) do
@@ -386,7 +429,7 @@ void ui_refresh(void)
table.insert(res, { pattern, mrepr })
end
return res
- ]])
+ end)
eq({
{ 1, { { '@quote', '"', 0, 16, 0, 17 } } },
@@ -406,70 +449,60 @@ void ui_refresh(void)
local custom_query = '((identifier) @main (#is-main? @main))'
do
- local res = exec_lua(
- [[
- local query = vim.treesitter.query
-
- local function is_main(match, pattern, bufnr, predicate)
- local nodes = match[ predicate[2] ]
- for _, node in ipairs(nodes) do
- if vim.treesitter.get_node_text(node, bufnr) == 'main' then
- return true
- end
+ local res = exec_lua(function()
+ local query = vim.treesitter.query
+
+ local function is_main(match, _pattern, bufnr, predicate)
+ local nodes = match[predicate[2]]
+ for _, node in ipairs(nodes) do
+ if vim.treesitter.get_node_text(node, bufnr) == 'main' then
+ return true
end
- return false
end
+ return false
+ end
- local parser = vim.treesitter.get_parser(0, "c")
+ local parser = vim.treesitter.get_parser(0, 'c')
- -- Time bomb: update this in 0.12
- if vim.fn.has('nvim-0.12') == 1 then
- return 'Update this test to remove this message and { all = true } from add_predicate'
- end
- query.add_predicate("is-main?", is_main, { all = true })
+ query.add_predicate('is-main?', is_main)
- local query = query.parse("c", ...)
+ local query0 = query.parse('c', custom_query)
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
- table.insert(nodes, {node:range()})
- end
+ local nodes = {}
+ for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
+ table.insert(nodes, { node:range() })
+ end
- return nodes
- ]],
- custom_query
- )
+ return nodes
+ end)
eq({ { 0, 4, 0, 8 } }, res)
end
-- Once with the old API. Remove this whole 'do' block in 0.12
do
- local res = exec_lua(
- [[
- local query = vim.treesitter.query
+ local res = exec_lua(function()
+ local query = vim.treesitter.query
- local function is_main(match, pattern, bufnr, predicate)
- local node = match[ predicate[2] ]
+ local function is_main(match, _pattern, bufnr, predicate)
+ local node = match[predicate[2]]
- return vim.treesitter.get_node_text(node, bufnr) == 'main'
- end
+ return vim.treesitter.get_node_text(node, bufnr) == 'main'
+ end
- local parser = vim.treesitter.get_parser(0, "c")
+ local parser = vim.treesitter.get_parser(0, 'c')
- query.add_predicate("is-main?", is_main, true)
+ query.add_predicate('is-main?', is_main, { all = false, force = true })
- local query = query.parse("c", ...)
+ local query0 = query.parse('c', custom_query)
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
- table.insert(nodes, {node:range()})
- end
+ local nodes = {}
+ for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
+ table.insert(nodes, { node:range() })
+ end
- return nodes
- ]],
- custom_query
- )
+ return nodes
+ end)
-- Remove this 'do' block in 0.12
eq(0, fn.has('nvim-0.12'))
@@ -477,16 +510,16 @@ void ui_refresh(void)
end
do
- local res = exec_lua [[
+ local res = exec_lua(function()
local query = vim.treesitter.query
- local t = {}
+ local r = {}
for _, v in ipairs(query.list_predicates()) do
- t[v] = true
+ r[v] = true
end
- return t
- ]]
+ return r
+ end)
eq(true, res['is-main?'])
end
@@ -505,18 +538,15 @@ void ui_refresh(void)
local function test(input, query)
api.nvim_buf_set_lines(0, 0, -1, true, vim.split(dedent(input), '\n'))
- return exec_lua(
- [[
- local parser = vim.treesitter.get_parser(0, "lua")
- local query = vim.treesitter.query.parse("lua", ...)
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
- nodes[#nodes+1] = { node:range() }
- end
- return nodes
- ]],
- query
- )
+ return exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'lua')
+ local query0 = vim.treesitter.query.parse('lua', query)
+ local nodes = {}
+ for _, node in query0:iter_captures(parser:parse()[1]:root(), 0) do
+ nodes[#nodes + 1] = { node:range() }
+ end
+ return nodes
+ end)
end
eq(
@@ -583,23 +613,21 @@ void ui_refresh(void)
-- Comment
]])
- local query = [[
+ local result = exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'lua')
+ local query = vim.treesitter.query.parse(
+ 'lua',
+ [[
(((comment (comment_content))+) @bar
(#lua-match? @bar "Comment"))
]]
-
- local result = exec_lua(
- [[
- local parser = vim.treesitter.get_parser(0, "lua")
- local query = vim.treesitter.query.parse("lua", ...)
- local nodes = {}
- for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
- nodes[#nodes+1] = { node:range() }
- end
- return nodes
- ]],
- query
- )
+ )
+ local nodes = {}
+ for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do
+ nodes[#nodes + 1] = { node:range() }
+ end
+ return nodes
+ end)
eq({
{ 0, 2, 0, 12 },
@@ -613,23 +641,20 @@ void ui_refresh(void)
eq(0, fn.has('nvim-0.12'))
insert(test_text)
- local res = exec_lua(
- [[
- cquery = vim.treesitter.query.parse("c", ...)
- parser = vim.treesitter.get_parser(0, "c")
- tree = parser:parse()[1]
- res = {}
- for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14) do
- local mrepr = {}
- for cid, node in pairs(match) do
- table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
- end
- table.insert(res, { pattern, mrepr })
+ local res = exec_lua(function()
+ local cquery = vim.treesitter.query.parse('c', test_query)
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local res = {}
+ for pattern, match in cquery:iter_matches(tree:root(), 0, 7, 14, { all = false }) do
+ local mrepr = {}
+ for cid, node in pairs(match) do
+ table.insert(mrepr, { '@' .. cquery.captures[cid], node:type(), node:range() })
end
- return res
- ]],
- test_query
- )
+ table.insert(res, { pattern, mrepr })
+ end
+ return res
+ end)
eq({
{ 3, { { '@type', 'primitive_type', 8, 2, 8, 6 } } },
@@ -661,23 +686,19 @@ void ui_refresh(void)
int bar = 13;
]]
- local ret = exec_lua(
- [[
- local str = ...
- local parser = vim.treesitter.get_string_parser(str, "c")
+ local ret = exec_lua(function()
+ local parser = vim.treesitter.get_string_parser(txt, 'c')
- local nodes = {}
- local query = vim.treesitter.query.parse("c", '((identifier) @foo)')
- local first_child = parser:parse()[1]:root():child(1)
+ local nodes = {}
+ local query = vim.treesitter.query.parse('c', '((identifier) @foo)')
+ local first_child = assert(parser:parse()[1]:root():child(1))
- for _, node in query:iter_captures(first_child, str) do
- table.insert(nodes, { node:range() })
- end
+ for _, node in query:iter_captures(first_child, txt) do
+ table.insert(nodes, { node:range() })
+ end
- return nodes
- ]],
- txt
- )
+ return nodes
+ end)
eq({ { 1, 10, 1, 13 } }, ret)
end)
@@ -734,7 +755,10 @@ void ui_refresh(void)
const char *sql = "SELECT * FROM Students WHERE name = 'Robert'); DROP TABLE Students;--";
]])
- local query = [[
+ local result = exec_lua(function()
+ local query = vim.treesitter.query.parse(
+ 'c',
+ [[
(declaration
type: (_)
declarator: (init_declarator
@@ -745,20 +769,15 @@ void ui_refresh(void)
(#set! injection.language "sql")
(#contains? @_id "sql"))
]]
-
- local result = exec_lua(
- [=[
- local query = vim.treesitter.query.parse("c", ...)
- local parser = vim.treesitter.get_parser(0, "c")
+ )
+ local parser = vim.treesitter.get_parser(0, 'c')
local root = parser:parse()[1]:root()
- local t = {}
- for id, node, metadata in query:iter_captures(root, 0) do
- t[query.captures[id]] = metadata
+ local res = {}
+ for id, _, metadata in query:iter_captures(root, 0) do
+ res[query.captures[id]] = metadata
end
- return t
- ]=],
- query
- )
+ return res
+ end)
eq({
['_id'] = { ['injection.language'] = 'sql' },
@@ -782,25 +801,22 @@ void ui_refresh(void)
(#eq? @function.name "foo"))
]]
- local result = exec_lua(
- [[
- local query = vim.treesitter.query.parse("c", ...)
- local match_preds = query.match_preds
+ local result = exec_lua(function()
+ local query0 = vim.treesitter.query.parse('c', query)
+ local match_preds = query0.match_preds
local called = 0
- function query:match_preds(...)
+ function query0:match_preds(...)
called = called + 1
return match_preds(self, ...)
end
- local parser = vim.treesitter.get_parser(0, "c")
+ local parser = vim.treesitter.get_parser(0, 'c')
local root = parser:parse()[1]:root()
local captures = {}
- for id, node in query:iter_captures(root, 0) do
+ for id in query0:iter_captures(root, 0) do
captures[#captures + 1] = id
end
return { called, captures }
- ]],
- query
- )
+ end)
eq({ 2, { 1, 1, 2, 2 } }, result)
end)
diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua
index bca0aca0cb..34bea349f6 100644
--- a/test/functional/treesitter/utils_spec.lua
+++ b/test/functional/treesitter/utils_spec.lua
@@ -17,26 +17,30 @@ describe('treesitter utils', function()
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)'))
+ exec_lua(function()
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local tree = parser:parse()[1]
+ local root = tree:root()
+ _G.ancestor = assert(root:child(0))
+ _G.child = assert(_G.ancestor:named_child(1))
+ _G.child_sibling = assert(_G.ancestor:named_child(2))
+ _G.grandchild = assert(_G.child:named_child(0))
+ end)
+
+ eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.child)'))
+ eq(true, exec_lua('return vim.treesitter.is_ancestor(_G.ancestor, _G.grandchild)'))
+ eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.ancestor)'))
+ eq(false, exec_lua('return vim.treesitter.is_ancestor(_G.child, _G.child_sibling)'))
end)
it('can detect if a position is contained in a node', function()
- exec_lua([[
- node = {
+ exec_lua(function()
+ _G.node = {
range = function()
return 0, 4, 0, 8
end,
}
- ]])
+ end)
eq(false, exec_lua('return vim.treesitter.is_in_node_range(node, 0, 3)'))
for i = 4, 7 do
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 8bfceb8cce..619153724b 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -246,11 +246,11 @@ describe('ui/cursor', function()
end
end
if m.hl_id then
- m.hl_id = 64
+ m.hl_id = 66
m.attr = { background = Screen.colors.DarkGray }
end
if m.id_lm then
- m.id_lm = 69
+ m.id_lm = 73
end
end
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 746bfb3262..042975f898 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2341,21 +2341,28 @@ describe('extmark decorations', function()
it('supports URLs', function()
insert(example_text)
- local url = 'https://example.com'
+ local url1 = 'https://example.com'
+ local url2 = 'http://127.0.0.1'
screen:add_extra_attr_ids {
- u = { url = "https://example.com" },
+ u = { url = url1 },
+ uh = { url = url2, background = Screen.colors.Yellow },
}
api.nvim_buf_set_extmark(0, ns, 1, 4, {
end_col = 14,
- url = url,
+ url = url1,
+ })
+ api.nvim_buf_set_extmark(0, ns, 2, 4, {
+ end_col = 17,
+ hl_group = 'Search',
+ url = url2,
})
- screen:expect{grid=[[
+ screen:expect([[
for _,item in ipairs(items) do |
{u:local text}, hl_id_cell, count = unpack(item) |
- if hl_id_cell ~= nil then |
+ {uh:if hl_id_cell} ~= nil then |
hl_id = hl_id_cell |
end |
for _ = 1, (count or 1) do |
@@ -2368,7 +2375,7 @@ describe('extmark decorations', function()
{1:~ }|
{1:~ }|
|
- ]]}
+ ]])
end)
it('can replace marks in place with different decorations #27211', function()
@@ -4027,11 +4034,85 @@ describe('decorations: inline virtual text', function()
normal! $
]])
api.nvim_buf_set_extmark(0, ns, 0, 40, { virt_text = { { ('b'):rep(9) } }, virt_text_pos = 'inline' })
- screen:expect{grid=[[
+ screen:expect([[
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
口1234^5 |
|
- ]]}
+ ]])
+ feed('g0')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
+ ^口12345 |
+ |
+ ]])
+ command('set showbreak=+++')
+ screen:expect([[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbb{1:>}|
+ {1:+++}^口12345 |
+ |
+ ]])
+ end)
+
+ it('cursor position is correct if end_row or end_col is specified', function()
+ screen:try_resize(50, 8)
+ api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48), ('c'):rep(48), ('d'):rep(48) })
+ api.nvim_buf_set_extmark(0, ns, 0, 0, {end_row = 2, virt_text_pos = 'inline', virt_text = {{'I1', 'NonText'}}})
+ api.nvim_buf_set_extmark(0, ns, 3, 0, {end_col = 2, virt_text_pos = 'inline', virt_text = {{'I2', 'NonText'}}})
+ feed('$')
+ screen:expect([[
+ {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^a|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ cccccccccccccccccccccccccccccccccccccccccccccccc |
+ {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
+ {1:~ }|*3
+ |
+ ]])
+ feed('j')
+ screen:expect([[
+ {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b |
+ cccccccccccccccccccccccccccccccccccccccccccccccc |
+ {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
+ {1:~ }|*3
+ |
+ ]])
+ feed('j')
+ screen:expect([[
+ {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ ccccccccccccccccccccccccccccccccccccccccccccccc^c |
+ {1:I2}dddddddddddddddddddddddddddddddddddddddddddddddd|
+ {1:~ }|*3
+ |
+ ]])
+ feed('j')
+ screen:expect([[
+ {1:I1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ cccccccccccccccccccccccccccccccccccccccccccccccc |
+ {1:I2}ddddddddddddddddddddddddddddddddddddddddddddddd^d|
+ {1:~ }|*3
+ |
+ ]])
+ end)
+
+ it('cursor position is correct with invalidated inline virt text', function()
+ screen:try_resize(50, 8)
+ api.nvim_buf_set_lines(0, 0, -1, false, { ('a'):rep(48), ('b'):rep(48) })
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_text_pos = 'inline', virt_text = {{'INLINE', 'NonText'}}, invalidate = true })
+ screen:expect([[
+ {1:INLINE}^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaa |
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ {1:~ }|*4
+ |
+ ]])
+ feed('dd$')
+ screen:expect([[
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb^b |
+ {1:~ }|*6
+ |
+ ]])
end)
end)
@@ -4936,6 +5017,28 @@ if (h->n_buckets < new_n_buckets) { // expand
|
]])
end)
+
+ it('not drawn when invalid', function()
+ api.nvim_buf_set_lines(0, 0, -1, false, { 'foo', 'bar' })
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines = {{{'VIRT1'}}}, invalidate = true })
+ screen:expect({
+ grid = [[
+ ^foo |
+ VIRT1 |
+ bar |
+ {1:~ }|*8
+ |
+ ]]
+ })
+ feed('dd')
+ screen:expect({
+ grid = [[
+ ^bar |
+ {1:~ }|*10
+ |
+ ]]
+ })
+ end)
end)
describe('decorations: signs', function()
@@ -5497,6 +5600,60 @@ l5
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
+
+ it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function()
+ command('set number numberwidth=1 signcolumn=number')
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' })
+ screen:expect({
+ grid = [[
+ S1 ^ |
+ {1:~ }|*8
+ |
+ ]]
+ })
+ api.nvim_buf_del_extmark(0, ns, 1)
+ screen:expect({
+ grid = [[
+ {8:1 }^ |
+ {1:~ }|*8
+ |
+ ]]
+ })
+ end)
+
+ it('supports emoji as signs', function()
+ insert(example_test3)
+ feed 'gg'
+ api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text='🧑‍🌾'})
+ -- VS16 can change width of character
+ api.nvim_buf_set_extmark(0, ns, 2, 0, {sign_text='❤️'})
+ api.nvim_buf_set_extmark(0, ns, 3, 0, {sign_text='❤'})
+ api.nvim_buf_set_extmark(0, ns, 4, 0, {sign_text='❤x'})
+ screen:expect([[
+ {7: }^l1 |
+ 🧑‍🌾l2 |
+ ❤️l3 |
+ ❤ l4 |
+ ❤xl5 |
+ {7: } |
+ {1:~ }|*3
+ |
+ ]])
+ eq("Invalid 'sign_text'", pcall_err(api.nvim_buf_set_extmark, 0, ns, 5, 0, {sign_text='❤️x'}))
+ end)
+
+ it('auto signcolumn hides with invalidated sign', function()
+ api.nvim_set_option_value('signcolumn', 'auto', {})
+ api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S1', invalidate=true})
+ feed('ia<cr>b<esc>dd')
+ screen:expect({
+ grid = [[
+ ^a |
+ {1:~ }|*8
+ |
+ ]]
+ })
+ end)
end)
describe('decorations: virt_text', function()
@@ -5575,20 +5732,26 @@ describe('decorations: virt_text', function()
end)
describe('decorations: window scoped', function()
- local screen, ns
+ local screen, ns, win_other
local url = 'https://example.com'
before_each(function()
clear()
screen = Screen.new(20, 10)
screen:attach()
screen:add_extra_attr_ids {
- [100] = { special = Screen.colors.Red, undercurl = true },
- [101] = { url = "https://example.com" },
+ [100] = { special = Screen.colors.Red, undercurl = true },
+ [101] = { url = 'https://example.com' },
}
ns = api.nvim_create_namespace 'test'
insert('12345')
+
+ win_other = api.nvim_open_win(0, false, {
+ col=0,row=0,width=20,height=10,
+ relative = 'win',style = 'minimal',
+ hide = true
+ })
end)
local noextmarks = {
@@ -5596,28 +5759,28 @@ describe('decorations: window scoped', function()
1234^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- local function set_scoped_extmark(line, col, opts)
- return api.nvim_buf_set_extmark(0, ns, line, col, vim.tbl_extend('error', { scoped = true }, opts))
+ local function set_extmark(line, col, opts)
+ return api.nvim_buf_set_extmark(0, ns, line, col, opts)
end
it('hl_group', function()
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
hl_group = 'Comment',
end_col = 3,
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5626,48 +5789,55 @@ describe('decorations: window scoped', function()
end)
it('virt_text', function()
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
virt_text = { { 'a', 'Comment' } },
virt_text_pos = 'eol',
})
- set_scoped_extmark(0, 5, {
+ set_extmark(0, 5, {
virt_text = { { 'b', 'Comment' } },
virt_text_pos = 'inline',
})
- set_scoped_extmark(0, 1, {
+ set_extmark(0, 1, {
virt_text = { { 'c', 'Comment' } },
virt_text_pos = 'overlay',
})
- set_scoped_extmark(0, 1, {
+ set_extmark(0, 1, {
virt_text = { { 'd', 'Comment' } },
virt_text_pos = 'right_align',
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
1{18:c}34^5{18:b} {18:a} {18:d}|
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
screen:expect(noextmarks)
+
+ api.nvim__ns_set(ns, { wins = {} })
+
+ screen:expect {
+ grid = [[
+ 1{18:c}34^5{18:b} {18:a} {18:d}|
+ {1:~ }|*8
+ |
+ ]],
+ }
end)
it('virt_lines', function()
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
virt_lines = { { { 'a', 'Comment' } } },
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
@@ -5675,7 +5845,8 @@ describe('decorations: window scoped', function()
{18:a} |
{1:~ }|*7
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5684,14 +5855,12 @@ describe('decorations: window scoped', function()
end)
it('redraws correctly with inline virt_text and wrapping', function()
- set_scoped_extmark(0, 2, {
- virt_text = {{ ('b'):rep(18), 'Comment' }},
- virt_text_pos = 'inline'
+ set_extmark(0, 2, {
+ virt_text = { { ('b'):rep(18), 'Comment' } },
+ virt_text_pos = 'inline',
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
@@ -5699,9 +5868,10 @@ describe('decorations: window scoped', function()
34^5 |
{1:~ }|*7
|
- ]]}
+ ]],
+ }
- api.nvim__win_del_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { win_other } })
screen:expect(noextmarks)
end)
@@ -5709,21 +5879,20 @@ describe('decorations: window scoped', function()
pending('sign_text', function()
-- TODO(altermo): The window signcolumn width is calculated wrongly (when `signcolumn=auto`)
-- This happens in function `win_redraw_signcols` on line containing `buf_meta_total(buf, kMTMetaSignText) > 0`
- set_scoped_extmark(0, 0, {
+ set_extmark(0, 0, {
sign_text = 'a',
sign_hl_group = 'Comment',
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
a 1234^5 |
{2:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5732,30 +5901,34 @@ describe('decorations: window scoped', function()
end)
it('statuscolumn hl group', function()
- set_scoped_extmark(0, 0, {
- number_hl_group='comment',
+ set_extmark(0, 0, {
+ number_hl_group = 'comment',
})
- set_scoped_extmark(0, 0, {
- line_hl_group='comment',
+ set_extmark(0, 0, {
+ line_hl_group = 'comment',
})
command 'set number'
+ api.nvim__ns_set(ns, { wins = { win_other } })
+
screen:expect {
grid = [[
{8: 1 }1234^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{18: 1 1234^5 }|
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5765,36 +5938,43 @@ describe('decorations: window scoped', function()
{8: 1 }1234^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
end)
it('spell', function()
- api.nvim_buf_set_lines(0,0,-1,true,{'aa'})
+ api.nvim_buf_set_lines(0, 0, -1, true, { 'aa' })
- set_scoped_extmark(0, 0, {
- spell=true,
- end_col=2,
+ set_extmark(0, 0, {
+ spell = true,
+ end_col = 2,
})
command 'set spelloptions=noplainbuffer'
command 'set spell'
command 'syntax off'
+ screen:expect({ unchanged = true })
+
+ api.nvim__ns_set(ns, { wins = { win_other } })
+
screen:expect {
grid = [[
a^a |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{100:a^a} |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5804,25 +5984,25 @@ describe('decorations: window scoped', function()
a^a |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
end)
it('url', function()
- set_scoped_extmark(0, 0, {
- end_col=3,
- url=url,
+ set_extmark(0, 0, {
+ end_col = 3,
+ url = url,
})
- screen:expect(noextmarks)
-
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
screen:expect {
grid = [[
{101:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
@@ -5830,85 +6010,72 @@ describe('decorations: window scoped', function()
screen:expect(noextmarks)
end)
- it('change extmarks scoped option', function()
- local id = set_scoped_extmark(0, 0, {
+ it('change namespace scope', function()
+ set_extmark(0, 0, {
hl_group = 'Comment',
end_col = 3,
})
- api.nvim__win_add_ns(0, ns)
+ api.nvim__ns_set(ns, { wins = { 0 } })
+ eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
command 'split'
command 'only'
screen:expect(noextmarks)
- api.nvim_buf_set_extmark(0, ns, 0, 0, {
- id = id,
- hl_group = 'Comment',
- end_col = 3,
- scoped = false,
- })
+ api.nvim__ns_set(ns, { wins = { 0 } })
+ eq({ wins={ api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
screen:expect {
grid = [[
{18:123}4^5 |
{1:~ }|*8
|
- ]]}
+ ]],
+ }
- api.nvim_buf_set_extmark(0, ns, 0, 0, {
- id = id,
- hl_group = 'Comment',
- end_col = 3,
- scoped = true,
+ local win_new = api.nvim_open_win(0, false, {
+ col=0,row=0,width=20,height=10,
+ relative = 'win',style = 'minimal',
+ hide = true
})
+ api.nvim__ns_set(ns, { wins = { win_new } })
+ eq({ wins={ win_new } }, api.nvim__ns_get(ns))
+
screen:expect(noextmarks)
end)
- it('change namespace scope', function()
- set_scoped_extmark(0, 0, {
- hl_group = 'Comment',
- end_col = 3,
- })
+ it('namespace get works', function()
+ eq({ wins = {} }, api.nvim__ns_get(ns))
- eq(true, api.nvim__win_add_ns(0, ns))
- eq({ ns }, api.nvim__win_get_ns(0))
+ api.nvim__ns_set(ns, { wins = { 0 } })
- screen:expect {
- grid = [[
- {18:123}4^5 |
- {1:~ }|*8
- |
- ]]}
+ eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
- command 'split'
- command 'only'
- eq({}, api.nvim__win_get_ns(0))
+ api.nvim__ns_set(ns, { wins = {} })
- screen:expect(noextmarks)
+ eq({ wins = {} }, api.nvim__ns_get(ns))
+ end)
- eq(true, api.nvim__win_add_ns(0, ns))
- eq({ ns }, api.nvim__win_get_ns(0))
+ it('remove window from namespace scope when deleted', function ()
+ api.nvim__ns_set(ns, { wins = { 0 } })
- screen:expect {
- grid = [[
- {18:123}4^5 |
- {1:~ }|*8
- |
- ]]}
+ eq({ wins = { api.nvim_get_current_win() } }, api.nvim__ns_get(ns))
- eq(true, api.nvim__win_del_ns(0, ns))
- eq({}, api.nvim__win_get_ns(0))
+ command 'split'
+ command 'only'
- screen:expect(noextmarks)
+ eq({ wins = {} }, api.nvim__ns_get(ns))
end)
end)
+
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index e79621f364..d6a04f90f6 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -12,6 +12,19 @@ local exec = n.exec
local eq = t.eq
local api = n.api
+local function WriteDiffFiles(text1, text2)
+ write_file('Xdifile1', text1)
+ write_file('Xdifile2', text2)
+ command('checktime')
+end
+
+local function WriteDiffFiles3(text1, text2, text3)
+ write_file('Xdifile1', text1)
+ write_file('Xdifile2', text2)
+ write_file('Xdifile3', text3)
+ command('checktime')
+end
+
before_each(clear)
describe('Diff mode screen', function()
@@ -614,6 +627,34 @@ int main(int argc, char **argv)
]])
end)
+ it('Diff empty and non-empty file', function()
+ write_file(fname, '', false)
+ write_file(fname_2, 'foo\nbar\nbaz', false)
+ reread()
+
+ feed(':set diffopt=filler<cr>')
+ screen:expect([[
+ {7: }{23:------------------}│{7: }{22:foo }|
+ {7: }{23:------------------}│{7: }{22:bar }|
+ {7: }{23:------------------}│{7: }{22:baz }|
+ {7: }^ │{1:~ }|
+ {1:~ }│{1:~ }|*10
+ {3:<onal-diff-screen-1 }{2:<l-diff-screen-1.2 }|
+ :set diffopt=filler |
+ ]])
+
+ feed(':set diffopt+=internal<cr>')
+ screen:expect([[
+ {7: }{23:------------------}│{7: }{22:foo }|
+ {7: }{23:------------------}│{7: }{22:bar }|
+ {7: }{23:------------------}│{7: }{22:baz }|
+ {7: }^ │{1:~ }|
+ {1:~ }│{1:~ }|*10
+ {3:<onal-diff-screen-1 }{2:<l-diff-screen-1.2 }|
+ :set diffopt+=internal |
+ ]])
+ end)
+
it('diffopt+=icase', function()
write_file(fname, 'a\nb\ncd\n', false)
write_file(fname_2, 'A\nb\ncDe\n', false)
@@ -1346,6 +1387,46 @@ it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function()
eq('0', api.nvim_get_option_value('foldcolumn', {}))
end)
+it("'relativenumber' doesn't draw beyond end of window in diff mode #29403", function()
+ local screen = Screen.new(60, 12)
+ screen:attach()
+ command('set relativenumber')
+ feed('10aa<CR><Esc>gg')
+ command('vnew')
+ feed('ab<CR><Esc>gg')
+ command('windo diffthis')
+ command('wincmd |')
+ screen:expect([[
+ {8: }│{7: }{8: 0 }{27:^a}{4: }|
+ {8: }│{7: }{8: 1 }{22:a }|
+ {8: }│{7: }{8: 2 }{22:a }|
+ {8: }│{7: }{8: 3 }{22:a }|
+ {8: }│{7: }{8: 4 }{22:a }|
+ {8: }│{7: }{8: 5 }{22:a }|
+ {8: }│{7: }{8: 6 }{22:a }|
+ {8: }│{7: }{8: 7 }{22:a }|
+ {8: }│{7: }{8: 8 }{22:a }|
+ {8: }│{7: }{8: 9 }{22:a }|
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]])
+ feed('j')
+ screen:expect([[
+ {8: }│{7: }{8: 1 }{27:a}{4: }|
+ {8: }│{7: }{8: 0 }{22:^a }|
+ {8: }│{7: }{8: 1 }{22:a }|
+ {8: }│{7: }{8: 2 }{22:a }|
+ {8: }│{7: }{8: 3 }{22:a }|
+ {8: }│{7: }{8: 4 }{22:a }|
+ {8: }│{7: }{8: 5 }{22:a }|
+ {8: }│{7: }{8: 6 }{22:a }|
+ {8: }│{7: }{8: 7 }{22:a }|
+ {8: }│{7: }{8: 8 }{22:a }|
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]])
+end)
+
-- oldtest: Test_diff_binary()
it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function()
local screen = Screen.new(40, 20)
@@ -1447,3 +1528,529 @@ it("diff mode draws 'breakindent' correctly after filler lines", function()
|
]])
end)
+
+-- oldtest: Test_diff_overlapped_diff_blocks_will_be_merged()
+it('diff mode overlapped diff blocks will be merged', function()
+ write_file('Xdifile1', '')
+ write_file('Xdifile2', '')
+ write_file('Xdifile3', '')
+
+ finally(function()
+ os.remove('Xdifile1')
+ os.remove('Xdifile2')
+ os.remove('Xdifile3')
+ os.remove('Xdiin1')
+ os.remove('Xdinew1')
+ os.remove('Xdiout1')
+ os.remove('Xdiin2')
+ os.remove('Xdinew2')
+ os.remove('Xdiout2')
+ end)
+
+ exec([[
+ func DiffExprStub()
+ let txt_in = readfile(v:fname_in)
+ let txt_new = readfile(v:fname_new)
+ if txt_in == ["line1"] && txt_new == ["line2"]
+ call writefile(["1c1"], v:fname_out)
+ elseif txt_in == readfile("Xdiin1") && txt_new == readfile("Xdinew1")
+ call writefile(readfile("Xdiout1"), v:fname_out)
+ elseif txt_in == readfile("Xdiin2") && txt_new == readfile("Xdinew2")
+ call writefile(readfile("Xdiout2"), v:fname_out)
+ endif
+ endfunc
+ ]])
+
+ local screen = Screen.new(35, 20)
+ screen:attach()
+ command('set winwidth=10 diffopt=filler,internal')
+
+ command('args Xdifile1 Xdifile2 | vert all | windo diffthis')
+
+ WriteDiffFiles('a\nb', 'x\nx')
+ write_file('Xdiin1', 'a\nb')
+ write_file('Xdinew1', 'x\nx')
+ write_file('Xdiout1', '1c1\n2c2')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:^x}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }|
+ {1:~ }│{1:~ }|*16
+ {2:Xdifile1 }{3:Xdifile2 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ WriteDiffFiles('a\nb\nc', 'x\nc')
+ write_file('Xdiin1', 'a\nb\nc')
+ write_file('Xdinew1', 'x\nc')
+ write_file('Xdiout1', '1c1\n2c1')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:^x}{4: }|
+ {7: }{22:b }│{7: }{23:---------------}|
+ {7: }c │{7: }c |
+ {1:~ }│{1:~ }|*15
+ {2:Xdifile1 }{3:Xdifile2 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ WriteDiffFiles('a\nc', 'x\nx\nc')
+ write_file('Xdiin1', 'a\nc')
+ write_file('Xdinew1', 'x\nx\nc')
+ write_file('Xdiout1', '1c1\n1a2')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:^x}{4: }|
+ {7: }{23:---------------}│{7: }{22:x }|
+ {7: }c │{7: }c |
+ {1:~ }│{1:~ }|*15
+ {2:Xdifile1 }{3:Xdifile2 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ command('args Xdifile1 Xdifile2 Xdifile3 | vert all | windo diffthis')
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\nb\nc')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\nc')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nb\ny')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\ny\nc')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\ny')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'y\ny\ny')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nx', 'y\ny\nc')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:c}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'x\nx\nc', 'a\ny\ny')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^a}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\nd\ne')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\ny\ne')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'y\ny\ny\ny\ny')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\nd\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\ny\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ny\ny\ny\ny')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\nd\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\ny\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ny\ny\ny')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:e}{4: }│{7: }{27:e}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb', 'x\nb', 'y\ny')
+ write_file('Xdiin1', 'a\nb')
+ write_file('Xdinew1', 'x\nb')
+ write_file('Xdiout1', '1c1')
+ write_file('Xdiin2', 'a\nb')
+ write_file('Xdinew2', 'y\ny')
+ write_file('Xdiout2', '1c1\n2c2')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*16
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\nc\nd')
+ write_file('Xdiin1', 'a\nb\nc\nd')
+ write_file('Xdinew1', 'x\nb\nx\nd')
+ write_file('Xdiout1', '1c1\n3c3')
+ write_file('Xdiin2', 'a\nb\nc\nd')
+ write_file('Xdinew2', 'y\ny\nc\nd')
+ write_file('Xdiout2', '1c1\n2c2')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:c}{4: }|
+ {7: }d │{7: }d │{7: }d |
+ {1:~ }│{1:~ }│{1:~ }|*14
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\ny\nd')
+ write_file('Xdiin1', 'a\nb\nc\nd')
+ write_file('Xdinew1', 'x\nb\nx\nd')
+ write_file('Xdiout1', '1c1\n3c3')
+ write_file('Xdiin2', 'a\nb\nc\nd')
+ write_file('Xdinew2', 'y\ny\ny\nd')
+ write_file('Xdiout2', '1c1\n2,3c2,3')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }d │{7: }d │{7: }d |
+ {1:~ }│{1:~ }│{1:~ }|*14
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ WriteDiffFiles3('a\nb\nc\nd', 'x\nb\nx\nd', 'y\ny\ny\ny')
+ write_file('Xdiin1', 'a\nb\nc\nd')
+ write_file('Xdinew1', 'x\nb\nx\nd')
+ write_file('Xdiout1', '1c1\n3c3')
+ write_file('Xdiin2', 'a\nb\nc\nd')
+ write_file('Xdinew2', 'y\ny\ny\ny')
+ write_file('Xdiout2', '1c1\n2,4c2,4')
+ command('set diffexpr=DiffExprStub()')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:x}{4: }│{7: }{27:^y}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:b}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:d}{4: }│{7: }{27:y}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*14
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+ command('set diffexpr&')
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'b\nc')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^b}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'c')
+ screen:expect([[
+ {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }c │{7: }c │{7: }^c |
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', '')
+ screen:expect([[
+ {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{7: }^ |
+ {1:~ }│{1:~ }│{1:~ }|*14
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nc')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'b')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^b}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'd\ne')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:a}{4: }│{7: }{27:^d}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'e')
+ screen:expect([[
+ {7: }{4:a }│{7: }{4:a }│{7: }{23:---------}|
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }e │{7: }e │{7: }^e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nd\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:d}{4: }|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:e }│{7: }{4:e }│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\nd\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{27:c}{4: }│{7: }{27:c}{4: }│{7: }{27:d}{4: }|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb\ne')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }e │{7: }e │{7: }e |
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc\nd\ne', 'a\nx\nc\nx\ne', 'a\nb')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{4:c }│{7: }{4:c }│{7: }{23:---------}|
+ {7: }{27:d}{4: }│{7: }{27:x}{4: }│{7: }{23:---------}|
+ {7: }{4:e }│{7: }{4:e }│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\ny\nb\nc')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:y}{4: }|
+ {7: }{23:---------}│{7: }{23:---------}│{7: }{22:b }|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*14
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'a\nx\nc', 'a\nb\ny\nc')
+ screen:expect([[
+ {7: }a │{7: }a │{7: }^a |
+ {7: }{27:b}{4: }│{7: }{27:x}{4: }│{7: }{27:b}{4: }|
+ {7: }{23:---------}│{7: }{23:---------}│{7: }{22:y }|
+ {7: }c │{7: }c │{7: }c |
+ {1:~ }│{1:~ }│{1:~ }|*14
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 248220e28b..9b77cb4014 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -327,6 +327,35 @@ describe('float window', function()
eq(12, pos[2])
end)
+ it('error message when invalid field specified for split', function()
+ local bufnr = api.nvim_create_buf(false, true)
+ eq(
+ "non-float cannot have 'row'",
+ pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', row = 10 })
+ )
+ eq(
+ "non-float cannot have 'col'",
+ pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', col = 10 })
+ )
+ eq(
+ "non-float cannot have 'bufpos'",
+ pcall_err(api.nvim_open_win, bufnr, true, { split = 'right', bufpos = { 0, 0 } })
+ )
+ local winid = api.nvim_open_win(bufnr, true, { split = 'right' })
+ eq(
+ "non-float cannot have 'row'",
+ pcall_err(api.nvim_win_set_config, winid, { split = 'right', row = 10 })
+ )
+ eq(
+ "non-float cannot have 'col'",
+ pcall_err(api.nvim_win_set_config, winid, { split = 'right', col = 10 })
+ )
+ eq(
+ "non-float cannot have 'bufpos'",
+ pcall_err(api.nvim_win_set_config, winid, { split = 'right', bufpos = { 0, 0 } })
+ )
+ end)
+
it('error message when reconfig missing relative field', function()
local bufnr = api.nvim_create_buf(false, true)
local opts = {
@@ -337,15 +366,16 @@ describe('float window', function()
relative = 'editor',
style = 'minimal',
}
- local win_id = api.nvim_open_win(bufnr, true, opts)
+ local winid = api.nvim_open_win(bufnr, true, opts)
eq(
- "Missing 'relative' field when reconfiguring floating window 1001",
- pcall_err(api.nvim_win_set_config, win_id, {
- width = 3,
- height = 3,
- row = 10,
- col = 10,
- }))
+ "Missing 'relative' field when reconfiguring floating window 1001",
+ pcall_err(api.nvim_win_set_config, winid, {
+ width = 3,
+ height = 3,
+ row = 10,
+ col = 10,
+ })
+ )
end)
it('is not operated on by windo when non-focusable #15374', function()
@@ -632,6 +662,22 @@ describe('float window', function()
screen:detach()
end)
+ it('no crash with relative="win" after %bdelete #30569', function()
+ exec([[
+ botright vsplit
+ %bdelete
+ ]])
+ api.nvim_open_win(0, false, {
+ relative = 'win',
+ win = 0,
+ row = 0,
+ col = 5,
+ width = 5,
+ height = 5,
+ })
+ assert_alive()
+ 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
@@ -1314,6 +1360,53 @@ describe('float window', function()
|
]])
end
+
+ --
+ -- floating windows inherit NormalFloat from global-ns.
+ --
+ command('fclose')
+ command('hi NormalFloat guibg=LightRed')
+ api.nvim_open_win(0, false, { relative = 'win', row = 3, col = 3, width = 12, height = 3, style = 'minimal' })
+ api.nvim_set_hl_ns(api.nvim_create_namespace('test1'))
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*6
+ [3:----------------------------------------]|
+ ## grid 2
+ {14: 1 }^x |
+ {14: 2 }y |
+ {14: 3 } |
+ {0:~ }|*3
+ ## grid 3
+ |
+ ## grid 5
+ {22:x }|
+ {22:y }|
+ {22: }|
+ ]], float_pos={
+ [5] = {1002, "NW", 2, 3, 3, true, 50};
+ }, win_viewport={
+ [2] = {win = 1000, topline = 0, botline = 4, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
+ [5] = {win = 1002, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0};
+ }, win_viewport_margins={
+ [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 },
+ [5] = { bottom = 0, left = 0, right = 0, top = 0, win = 1002 }
+ }})
+ else
+ screen:expect({
+ grid = [[
+ {14: 1 }^x |
+ {14: 2 }y |
+ {14: 3 } |
+ {0:~ }{22:x }{0: }|
+ {0:~ }{22:y }{0: }|
+ {0:~ }{22: }{0: }|
+ |
+ ]]
+ })
+ end
end)
it("can use 'minimal' style", function()
@@ -1532,9 +1625,9 @@ describe('float window', function()
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
- {20:1}{19: }{20: }{22:^x}{21: }|
- {14:2}{19: }{14: }{22:y} |
- {14:3}{19: }{14: }{22: } |
+ {20: 1}{19: }{22:^x}{21: }|
+ {14: 2}{19: }{22:y} |
+ {14: 3}{19: }{22: } |
{0:~ }|*3
## grid 3
|
@@ -1545,9 +1638,9 @@ describe('float window', function()
]], float_pos={[4] = {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 } |
+ {20: 1}{19: }{22:^x}{21: }|
+ {14: 2}{19: }{22:y} |
+ {14: 3}{19: }{22: } {15:x } |
{0:~ }{15:y }{0: }|
{0:~ }{15: }{0: }|*2
|
@@ -2127,7 +2220,7 @@ describe('float window', function()
## grid 3
|
## grid 4
- {5:╔═════}🦄BB{5:╗}|
+ {5:╔═════}{11:🦄BB}{5:╗}|
{5:║}{1: halloj! }{5:║}|
{5:║}{1: BORDAA }{5:║}|
{5:╚═════════╝}|
@@ -2141,7 +2234,7 @@ describe('float window', function()
screen:expect{grid=[[
^ |
{0:~ }|
- {0:~ }{5:╔═════}🦄BB{5:╗}{0: }|
+ {0:~ }{5:╔═════}{11:🦄BB}{5:╗}{0: }|
{0:~ }{5:║}{1: halloj! }{5:║}{0: }|
{0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
{0:~ }{5:╚═════════╝}{0: }|
@@ -2275,7 +2368,7 @@ describe('float window', function()
{5:╔═════════╗}|
{5:║}{1: halloj! }{5:║}|
{5:║}{1: BORDAA }{5:║}|
- {5:╚═════}🦄BB{5:╝}|
+ {5:╚═════}{11:🦄BB}{5:╝}|
]], float_pos={
[4] = { 1001, "NW", 1, 2, 5, true }
}, win_viewport={
@@ -2289,7 +2382,7 @@ describe('float window', function()
{0:~ }{5:╔═════════╗}{0: }|
{0:~ }{5:║}{1: halloj! }{5:║}{0: }|
{0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
- {0:~ }{5:╚═════}🦄BB{5:╝}{0: }|
+ {0:~ }{5:╚═════}{11:🦄BB}{5:╝}{0: }|
|
]]}
end
@@ -2423,10 +2516,10 @@ describe('float window', function()
## grid 3
|
## grid 4
- {5:╔═════}🦄{7:BB}{5:╗}|
+ {5:╔═════}{11:🦄}{7:BB}{5:╗}|
{5:║}{1: halloj! }{5:║}|
{5:║}{1: BORDAA }{5:║}|
- {5:╚═════}🦄{7:BB}{5:╝}|
+ {5:╚═════}{11:🦄}{7:BB}{5:╝}|
]], float_pos={
[4] = { 1001, "NW", 1, 2, 5, true }
}, win_viewport={
@@ -2437,10 +2530,10 @@ describe('float window', function()
screen:expect{grid=[[
^ |
{0:~ }|
- {0:~ }{5:╔═════}🦄{7:BB}{5:╗}{0: }|
+ {0:~ }{5:╔═════}{11:🦄}{7:BB}{5:╗}{0: }|
{0:~ }{5:║}{1: halloj! }{5:║}{0: }|
{0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
- {0:~ }{5:╚═════}🦄{7:BB}{5:╝}{0: }|
+ {0:~ }{5:╚═════}{11:🦄}{7:BB}{5:╝}{0: }|
|
]]}
end
@@ -2485,6 +2578,37 @@ describe('float window', function()
end
eq({{"🦄", ""}, {"BB", {"B0", "B1", ""}}}, api.nvim_win_get_config(win).title)
eq({{"🦄", ""}, {"BB", {"B0", "B1", ""}}}, api.nvim_win_get_config(win).footer)
+
+ -- making it a split should not leak memory
+ api.nvim_win_set_config(win, { vertical = true })
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [4:--------------------]{5:│}[2:-------------------]|*5
+ {5:[No Name] [+] }{4:[No Name] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|*4
+ ## grid 3
+ |
+ ## grid 4
+ halloj! |
+ BORDAA |
+ {0:~ }|*3
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ [4] = {win = 1001, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0};
+ }}
+ else
+ screen:expect{grid=[[
+ halloj! {5:│}^ |
+ BORDAA {5:│}{0:~ }|
+ {0:~ }{5:│}{0:~ }|*3
+ {5:[No Name] [+] }{4:[No Name] }|
+ |
+ ]]}
+ end
end)
it('terminates border on edge of viewport when window extends past viewport', function()
@@ -8991,6 +9115,7 @@ describe('float window', function()
end)
it('float window with hide option', function()
+ local cwin = api.nvim_get_current_win()
local buf = api.nvim_create_buf(false,false)
local win = api.nvim_open_win(buf, false, {relative='editor', width=10, height=2, row=2, col=5, hide = true})
local expected_pos = {
@@ -9070,6 +9195,22 @@ describe('float window', function()
|
]])
end
+ -- check window jump with hide
+ feed('<C-W><C-W>')
+ -- should keep on current window
+ eq(cwin, api.nvim_get_current_win())
+ api.nvim_win_set_config(win, {hide=false})
+ api.nvim_set_current_win(win)
+ local win3 = api.nvim_open_win(buf, true, {relative='editor', width=4, height=4, row=2, col=5, hide = false})
+ api.nvim_win_set_config(win, {hide=true})
+ feed('<C-W>w')
+ -- should goto the first window with prev
+ eq(cwin, api.nvim_get_current_win())
+ -- windo
+ command('windo set winheight=6')
+ eq(win3, api.nvim_get_current_win())
+ eq(6, api.nvim_win_get_height(win3))
+ eq(2, api.nvim_win_get_height(win))
end)
it(':fclose command #9663', function()
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index b7b46ddfae..87d66fa604 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -596,13 +596,13 @@ describe('highlight', function()
]])
screen:expect(
[[
- {1: }^ |
+ {1: }{5:^ }|
{1: }{2:01}{3:234 67}{2:89}{5: }|
{4:~ }|*2
{7:[No Name] [+] }|
- {1: } |
{1: }{6:-----------------------}|
- {4:~ }|
+ {1: }{6:-----------------------}|
+ {1: } |
{8:[No Name] }|
|
]],
@@ -1078,6 +1078,44 @@ describe('CursorLine and CursorLineNr highlights', function()
]])
end)
+ -- oldtest: Test_cursorline_screenline_resize()
+ it("'cursorlineopt' screenline is updated on window resize", function()
+ local screen = Screen.new(75, 8)
+ screen:attach()
+ exec([[
+ 50vnew
+ call setline(1, repeat('xyz ', 30))
+ setlocal number cursorline cursorlineopt=screenline
+ normal! $
+ ]])
+ screen:expect([[
+ {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ |
+ {8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }|
+ {8: }{21:xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }|
+ {1:~ }│{1:~ }|*3
+ {3:[No Name] [+] }{2:[No Name] }|
+ |
+ ]])
+ command('vertical resize -4')
+ screen:expect([[
+ {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ |
+ {8: }z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }|
+ {8: }{21:xyz xyz xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }|
+ {1:~ }│{1:~ }|*3
+ {3:[No Name] [+] }{2:[No Name] }|
+ |
+ ]])
+ command('set cpoptions+=n')
+ screen:expect([[
+ {8: 1 }xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xy│ |
+ z xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz │{1:~ }|
+ {21:xyz xyz xyz xyz xyz xyz xyz xyz^ }│{1:~ }|
+ {1:~ }│{1:~ }|*3
+ {3:[No Name] [+] }{2:[No Name] }|
+ |
+ ]])
+ end)
+
-- oldtest: Test_cursorline_after_yank()
it('always updated. vim-patch:8.1.0849', function()
local screen = Screen.new(50, 5)
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index 8d14c9f73d..a255047ed7 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local clear, insert = n.clear, n.insert
local command = n.command
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index ca52a265fa..a3e5068e55 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1081,6 +1081,22 @@ stack traceback:
},
})
end)
+
+ it('does not do showmode unnecessarily #29086', function()
+ local screen_showmode = screen._handle_msg_showmode
+ local showmode = 0
+ screen._handle_msg_showmode = function(...)
+ screen_showmode(...)
+ showmode = showmode + 1
+ end
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ })
+ eq(showmode, 1)
+ end)
end)
describe('ui/builtin messages', function()
@@ -1149,7 +1165,12 @@ describe('ui/builtin messages', function()
it(':syntax list langGroup output', function()
command('syntax on')
- command('set syntax=vim')
+ exec([[
+ syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup,vimCommentString
+ syn match vimComment +\<endif\s\+".*$+lc=5 contains=@vimCommentGroup,vimCommentString
+ syn match vimComment +\<else\s\+".*$+lc=4 contains=@vimCommentGroup,vimCommentString
+ hi link vimComment Comment
+ ]])
screen:try_resize(110, 7)
feed(':syntax list vimComment<cr>')
screen:expect([[
@@ -1420,6 +1441,41 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
}
end)
+ it('supports nvim_echo messages with emoji', function()
+ -- stylua: ignore
+ async_meths.nvim_echo(
+ { { 'wow, 🏳️‍⚧️🧑‍🌾❤️😂🏴‍☠️\nvariant ❤️ one\nvariant ❤ two' } }, true, {}
+ )
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {3: }|
+ wow, 🏳️‍⚧️🧑‍🌾❤️😂🏴‍☠️ |
+ variant ❤️ one |
+ variant ❤ two |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed '<cr>'
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ |
+ ]])
+
+ feed ':messages<cr>'
+ screen:expect([[
+ |
+ {1:~ }|
+ {3: }|
+ wow, 🏳️‍⚧️🧑‍🌾❤️😂🏴‍☠️ |
+ variant ❤️ one |
+ variant ❤ two |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
it('prints lines in Ex mode correctly with a burst of carriage returns #19341', function()
command('set number')
api.nvim_buf_set_lines(0, 0, 0, true, { 'aaa', 'bbb', 'ccc' })
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 42c877fd92..bc18680749 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -367,7 +367,7 @@ describe('ui/mouse/input', function()
})
end)
- it('left click in default tabline (position 4) switches to tab', function()
+ it('left click in default tabline (tabpage label) switches to tab', function()
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
@@ -385,9 +385,47 @@ describe('ui/mouse/input', function()
{0:~ }|*2
|
]])
+ feed('<LeftMouse><6,0>')
+ screen:expect_unchanged()
+ feed('<LeftMouse><10,0>')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r{0:$} |
+ {0:~ }|*2
+ |
+ ]])
+ feed('<LeftMouse><12,0>')
+ screen:expect_unchanged()
+ end)
+
+ it('left click in default tabline (blank space) switches tab', function()
+ feed_command('%delete')
+ insert('this is foo')
+ feed_command('silent file foo | tabnew | file bar')
+ insert('this is bar')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r{0:$} |
+ {0:~ }|*2
+ |
+ ]])
+ feed('<LeftMouse><20,0>')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|*2
+ |
+ ]])
+ feed('<LeftMouse><22,0>')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r{0:$} |
+ {0:~ }|*2
+ |
+ ]])
end)
- it('left click in default tabline (position 24) closes tab', function()
+ it('left click in default tabline (close label) closes tab', function()
api.nvim_set_option_value('hidden', true, {})
feed_command('%delete')
insert('this is foo')
@@ -407,8 +445,7 @@ describe('ui/mouse/input', function()
]])
end)
- it('double click in default tabline (position 4) opens new tab', function()
- api.nvim_set_option_value('hidden', true, {})
+ it('double click in default tabline opens new tab before', function()
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
@@ -426,6 +463,34 @@ describe('ui/mouse/input', function()
{0:~ }|*2
|
]])
+ command('tabclose')
+ screen:expect([[
+ {sel: + foo }{tab: + bar }{fill: }{tab:X}|
+ this is fo^o |
+ {0:~ }|*2
+ |
+ ]])
+ feed('<2-LeftMouse><20,0>')
+ screen:expect([[
+ {tab: + foo + bar }{sel: Name] }{fill: }{tab:X}|
+ {0:^$} |
+ {0:~ }|*2
+ |
+ ]])
+ command('tabclose')
+ screen:expect([[
+ {tab: + foo }{sel: + bar }{fill: }{tab:X}|
+ this is ba^r{0:$} |
+ {0:~ }|*2
+ |
+ ]])
+ feed('<2-LeftMouse><10,0>')
+ screen:expect([[
+ {tab: + foo }{sel: Name] }{tab: + bar }{fill: }{tab:X}|
+ {0:^$} |
+ {0:~ }|*2
+ |
+ ]])
end)
describe('%@ label', function()
@@ -987,7 +1052,7 @@ describe('ui/mouse/input', function()
command('set sidescroll=0')
feed('<esc>:set nowrap<cr>')
- feed('a <esc>20Ab<esc>')
+ feed('a <esc>17Ab<esc>3Ab<esc>')
screen:expect([[
|*2
bbbbbbbbbbbbbbb^b |
@@ -1017,7 +1082,7 @@ describe('ui/mouse/input', function()
command('set sidescroll=0')
feed('<esc>:set nowrap<cr>')
- feed('a <esc>20Ab<esc>')
+ feed('a <esc>17Ab<esc>3Ab<esc>')
screen:expect([[
|*2
bbbbbbbbbbbbbbb^b |
@@ -2002,5 +2067,24 @@ describe('ui/mouse/input', function()
feed('<Down><CR>')
eq({ 4, 20 }, api.nvim_win_get_cursor(0))
eq('the moon', fn.getreg('"'))
+
+ -- Try clicking in the cmdline
+ api.nvim_input_mouse('right', 'press', '', 0, 23, 0)
+ api.nvim_input_mouse('right', 'release', '', 0, 23, 0)
+ feed('<Down><Down><Down><CR>')
+ eq('baz', api.nvim_get_var('menustr'))
+
+ -- Try clicking in horizontal separator with global statusline
+ command('set laststatus=3')
+ api.nvim_input_mouse('right', 'press', '', 0, 5, 0)
+ api.nvim_input_mouse('right', 'release', '', 0, 5, 0)
+ feed('<Down><CR>')
+ eq('foo', api.nvim_get_var('menustr'))
+
+ -- Try clicking in the cmdline with global statusline
+ api.nvim_input_mouse('right', 'press', '', 0, 23, 0)
+ api.nvim_input_mouse('right', 'release', '', 0, 23, 0)
+ feed('<Down><Down><CR>')
+ eq('bar', api.nvim_get_var('menustr'))
end)
end)
diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua
index dc25a09d0d..f16f750ea1 100644
--- a/test/functional/ui/multibyte_spec.lua
+++ b/test/functional/ui/multibyte_spec.lua
@@ -296,6 +296,86 @@ describe('multibyte rendering', function()
]],
}
end)
+
+ it('supports emoji with variant selectors and ZWJ', function()
+ command('set ruler')
+ insert('🏳️‍⚧️')
+ screen:expect([[
+ ^🏳️‍⚧️ |
+ {1:~ }|*4
+ 1,1 All |
+ ]])
+
+ feed('a word<esc>')
+ screen:expect([[
+ 🏳️‍⚧️ wor^d |
+ {1:~ }|*4
+ 1,21-7 All |
+ ]])
+
+ feed('0')
+ screen:expect([[
+ ^🏳️‍⚧️ word |
+ {1:~ }|*4
+ 1,1 All |
+ ]])
+
+ feed('l')
+ screen:expect([[
+ 🏳️‍⚧️^ word |
+ {1:~ }|*4
+ 1,17-3 All |
+ ]])
+
+ feed('h')
+ screen:expect([[
+ ^🏳️‍⚧️ word |
+ {1:~ }|*4
+ 1,1 All |
+ ]])
+
+ feed('o❤️ variant selected<esc>')
+ screen:expect([[
+ 🏳️‍⚧️ word |
+ ❤️ variant selecte^d |
+ {1:~ }|*3
+ 2,23-19 All |
+ ]])
+
+ feed('0')
+ screen:expect([[
+ 🏳️‍⚧️ word |
+ ^❤️ variant selected |
+ {1:~ }|*3
+ 2,1 All |
+ ]])
+
+ feed('l')
+ screen:expect([[
+ 🏳️‍⚧️ word |
+ ❤️^ variant selected |
+ {1:~ }|*3
+ 2,7-3 All |
+ ]])
+
+ feed('h')
+ screen:expect([[
+ 🏳️‍⚧️ word |
+ ^❤️ variant selected |
+ {1:~ }|*3
+ 2,1 All |
+ ]])
+
+ -- without selector: single width (note column 18 and not 19)
+ feed('o❤ variant selected<esc>')
+ screen:expect([[
+ 🏳️‍⚧️ word |
+ ❤️ variant selected |
+ ❤ variant selecte^d |
+ {1:~ }|*2
+ 3,20-18 All |
+ ]])
+ end)
end)
describe('multibyte rendering: statusline', function()
@@ -348,11 +428,12 @@ describe('multibyte rendering: statusline', function()
it('non-printable followed by MAX_MCO unicode combination points', function()
command('set statusline=Ÿ̸⃯ᷰ⃐⃧⃝')
-- U+9F + U+1DF0 + U+20EF + U+0338 + U+20D0 + U+20E7 + U+20DD
+ -- TODO: not ideal, better with plain ">" and then space+combining
screen:expect([[
- ^ |
- {1:~ }|
- {3:<9f><1df0><20ef><0338><20d0><20e7><20dd>}|
- |
+ ^ |
+ {1:~ }|
+ {3:<9f≯⃯ᷰ⃐⃧⃝ }|
+ |
]])
end)
@@ -368,9 +449,20 @@ describe('multibyte rendering: statusline', function()
}
end)
- it('unprintable chars in filename with default stl', function()
+ it('emoji with ZWJ in filename with default stl', function()
command('file 🧑‍💻')
- -- TODO: this is wrong but avoids a crash
+ screen:expect {
+ grid = [[
+ ^ |
+ {1:~ }|
+ {3:🧑‍💻 }|
+ |
+ ]],
+ }
+ end)
+
+ it('unprintable chars in filename with default stl', function()
+ command('file 🧑​💻')
screen:expect {
grid = [[
^ |
@@ -381,15 +473,27 @@ describe('multibyte rendering: statusline', function()
}
end)
- it('unprintable chars in filename with custom stl', function()
+ it('emoji with ZWJ in filename with custom stl', function()
command('set statusline=xx%#ErrorMsg#%f%##yy')
command('file 🧑‍💻')
- -- TODO: this is also wrong but also avoids a crash
screen:expect {
grid = [[
^ |
{1:~ }|
- {3:xx}{9:🧑<200d>💻}{3:yy }|
+ {3:xx}{9:🧑‍💻}{3:yy }|
+ |
+ ]],
+ }
+ end)
+
+ it('unprintable chars in filename with custom stl', function()
+ command('set statusline=xx%#ErrorMsg#%f%##yy')
+ command('file 🧑​💻')
+ screen:expect {
+ grid = [[
+ ^ |
+ {1:~ }|
+ {3:xx}{9:🧑<200b>💻}{3:yy }|
|
]],
}
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index dc48061a6c..e009ed0a29 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -1095,6 +1095,7 @@ describe('ext_multigrid', function()
end)
it('supports mouse', function()
+ command('autocmd! nvim_popupmenu') -- Delete the default MenuPopup event handler.
insert('some text\nto be clicked')
screen:expect{grid=[[
## grid 1
@@ -2598,4 +2599,257 @@ describe('ext_multigrid', function()
]])
eq(1, api.nvim_get_option_value('cmdheight', {}))
end)
+
+ describe('centered cursorline', function()
+ before_each(function()
+ -- Force a centered cursorline, this caused some redrawing problems described in #30576.
+ -- Most importantly, win_viewport was not received in time, and sum_scroll_delta did not refresh.
+ command('set cursorline scrolloff=9999')
+ end)
+ it('insert line scrolls correctly', function()
+ for i = 1, 11 do
+ insert('line' .. i .. '\n')
+ end
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ line1 |
+ line2 |
+ line3 |
+ line4 |
+ line5 |
+ line6 |
+ line7 |
+ line8 |
+ line9 |
+ line10 |
+ line11 |
+ {23:^ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 0, botline = 12, curline = 11, curcol = 0, linecount = 12, sum_scroll_delta = 0};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ insert('line12\n')
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ line2 |
+ line3 |
+ line4 |
+ line5 |
+ line6 |
+ line7 |
+ line8 |
+ line9 |
+ line10 |
+ line11 |
+ line12 |
+ {23:^ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 1, botline = 13, curline = 12, curcol = 0, linecount = 13, sum_scroll_delta = 1};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ end)
+
+ it('got to top scrolls correctly', function()
+ for i = 1, 20 do
+ insert('line' .. i .. '\n')
+ end
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ line10 |
+ line11 |
+ line12 |
+ line13 |
+ line14 |
+ line15 |
+ line16 |
+ line17 |
+ line18 |
+ line19 |
+ line20 |
+ {23:^ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ feed('gg')
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {23:^line1 }|
+ line2 |
+ line3 |
+ line4 |
+ line5 |
+ line6 |
+ line7 |
+ line8 |
+ line9 |
+ line10 |
+ line11 |
+ line12 |
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 0, botline = 13, curline = 0, curcol = 0, linecount = 21, sum_scroll_delta = 0};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ end)
+
+ it('scrolls in the middle', function()
+ for i = 1, 20 do
+ insert('line' .. i .. '\n')
+ end
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ line10 |
+ line11 |
+ line12 |
+ line13 |
+ line14 |
+ line15 |
+ line16 |
+ line17 |
+ line18 |
+ line19 |
+ line20 |
+ {23:^ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 9, botline = 21, curline = 20, curcol = 0, linecount = 21, sum_scroll_delta = 9};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ feed('M')
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ line10 |
+ line11 |
+ line12 |
+ line13 |
+ line14 |
+ {23:^line15 }|
+ line16 |
+ line17 |
+ line18 |
+ line19 |
+ line20 |
+ |
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 9, botline = 21, curline = 14, curcol = 0, linecount = 21, sum_scroll_delta = 9};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ feed('k')
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:-----------------------------------------------------]|*12
+ {11:[No Name] [+] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ line9 |
+ line10 |
+ line11 |
+ line12 |
+ line13 |
+ {23:^line14 }|
+ line15 |
+ line16 |
+ line17 |
+ line18 |
+ line19 |
+ line20 |
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = 1000, topline = 8, botline = 21, curline = 13, curcol = 0, linecount = 21, sum_scroll_delta = 8};
+ }, win_viewport_margins={
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ }
+ }})
+ end)
+ end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 4f6454a0fb..220af06f53 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -1,7 +1,7 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local tt = require('test.functional.terminal.testutil')
+local tt = require('test.functional.testterm')
local assert_alive = n.assert_alive
local mkdir, write_file, rmdir = t.mkdir, t.write_file, n.rmdir
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 8f8604eecb..f84362ede8 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -851,6 +851,8 @@ describe('ui/ext_popupmenu', function()
set mouse=a mousemodel=popup
aunmenu PopUp
+ " Delete the default MenuPopup event handler.
+ autocmd! nvim_popupmenu
menu PopUp.foo :let g:menustr = 'foo'<CR>
menu PopUp.bar :let g:menustr = 'bar'<CR>
menu PopUp.baz :let g:menustr = 'baz'<CR>
@@ -1129,7 +1131,7 @@ describe("builtin popupmenu 'pumblend'", function()
[10] = { foreground = tonumber('0x000002') },
})
screen:attach({ rgb = false })
- command('set notermguicolors pumblend=10')
+ command('set pumblend=10')
insert([[
Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor
@@ -1160,23 +1162,47 @@ describe('builtin popupmenu', function()
screen = Screen.new(32, 20)
screen:set_default_attr_ids({
-- popup selected item / scrollbar track
- ['s'] = { background = Screen.colors.WebGray },
+ s = { background = Screen.colors.Grey },
-- popup non-selected item
- ['n'] = { background = Screen.colors.LightMagenta },
+ n = { background = Screen.colors.Plum1 },
-- popup scrollbar knob
- ['c'] = { background = Screen.colors.Grey0 },
+ c = { background = Screen.colors.Black },
[1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { bold = true },
[3] = { reverse = true },
[4] = { bold = true, reverse = true },
[5] = { bold = true, foreground = Screen.colors.SeaGreen },
- [6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
+ [6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search
[8] = { foreground = Screen.colors.Red },
- kn = { foreground = Screen.colors.Red, background = Screen.colors.Magenta },
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
- xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta },
+ kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
+ xn = { foreground = Screen.colors.White, background = Screen.colors.Plum1 },
+ ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey },
+ mn = { foreground = Screen.colors.Blue, background = Screen.colors.Plum1 },
+ ds = { foreground = Screen.colors.DarkRed, background = Screen.colors.Grey },
+ dn = { foreground = Screen.colors.DarkRed, background = Screen.colors.Plum1 },
+ ums = {
+ foreground = Screen.colors.Blue,
+ background = Screen.colors.Grey,
+ underline = true,
+ },
+ umn = {
+ foreground = Screen.colors.Blue,
+ background = Screen.colors.Plum1,
+ underline = true,
+ },
+ uds = {
+ foreground = Screen.colors.DarkRed,
+ background = Screen.colors.Grey,
+ underline = true,
+ },
+ udn = {
+ foreground = Screen.colors.DarkRed,
+ background = Screen.colors.Plum1,
+ underline = true,
+ },
})
screen:attach({ ext_multigrid = multigrid })
end)
@@ -2528,6 +2554,7 @@ describe('builtin popupmenu', function()
]],
}
+ -- oldtest: Test_wildmenu_pum_rightleft()
feed('<tab>')
screen:expect {
grid = [[
@@ -2917,11 +2944,12 @@ describe('builtin popupmenu', function()
feed('<C-U>sign define <Tab>')
screen:expect([[
|
- {1:~ }|*2
+ {1:~ }|
{1:~ }{s: culhl= }{1: }|
{1:~ }{n: icon= }{1: }|
{1:~ }{n: linehl= }{1: }|
{1:~ }{n: numhl= }{1: }|
+ {1:~ }{n: priority= }{1: }|
{1:~ }{n: text= }{1: }|
{1:~ }{n: texthl= }{1: }|
:sign define culhl=^ |
@@ -2930,11 +2958,12 @@ describe('builtin popupmenu', function()
feed('<Space><Tab>')
screen:expect([[
|
- {1:~ }|*2
+ {1:~ }|
{1:~ }{s: culhl= }{1: }|
{1:~ }{n: icon= }{1: }|
{1:~ }{n: linehl= }{1: }|
{1:~ }{n: numhl= }{1: }|
+ {1:~ }{n: priority= }{1: }|
{1:~ }{n: text= }{1: }|
{1:~ }{n: texthl= }{1: }|
:sign define culhl= culhl=^ |
@@ -3547,6 +3576,66 @@ describe('builtin popupmenu', function()
|
]])
end)
+
+ -- oldtest: Test_wildmenu_pum_hl_match()
+ it('highlighting matched text in cmdline pum', function()
+ exec([[
+ set wildoptions=pum,fuzzy
+ hi PmenuMatchSel guifg=Blue guibg=Grey
+ hi PmenuMatch guifg=Blue guibg=Plum1
+ ]])
+
+ feed(':sign plc<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{s: }{ms:pl}{s:a}{ms:c}{s:e }{1: }|
+ {1:~ }{n: un}{mn:pl}{n:a}{mn:c}{n:e }{1: }|
+ :sign place^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{n: }{mn:pl}{n:a}{mn:c}{n:e }{1: }|
+ {1:~ }{s: un}{ms:pl}{s:a}{ms:c}{s:e }{1: }|
+ :sign unplace^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{n: }{mn:pl}{n:a}{mn:c}{n:e }{1: }|
+ {1:~ }{n: un}{mn:pl}{n:a}{mn:c}{n:e }{1: }|
+ :sign plc^ |
+ ]])
+ feed('<Esc>')
+ command('set wildoptions-=fuzzy')
+ feed(':sign un<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{s: }{ms:un}{s:define }{1: }|
+ {1:~ }{n: }{mn:un}{n:place }{1: }|
+ :sign undefine^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{n: }{mn:un}{n:define }{1: }|
+ {1:~ }{s: }{ms:un}{s:place }{1: }|
+ :sign unplace^ |
+ ]])
+ feed('<Tab>')
+ screen:expect([[
+ |
+ {1:~ }|*16
+ {1:~ }{n: }{mn:un}{n:define }{1: }|
+ {1:~ }{n: }{mn:un}{n:place }{1: }|
+ :sign un^ |
+ ]])
+ end)
end
it("'pumheight'", function()
@@ -3718,6 +3807,8 @@ describe('builtin popupmenu', function()
call setline(1, 'popup menu test')
set mouse=a mousemodel=popup
+ " Delete the default MenuPopup event handler.
+ autocmd! nvim_popupmenu
aunmenu PopUp
menu PopUp.foo :let g:menustr = 'foo'<CR>
menu PopUp.bar :let g:menustr = 'bar'<CR>
@@ -4402,6 +4493,9 @@ describe('builtin popupmenu', function()
-- oldtest: Test_popup_command_dump()
it(':popup command', function()
exec([[
+ " Delete the default MenuPopup event handler.
+ autocmd! nvim_popupmenu
+
func ChangeMenu()
aunmenu PopUp.&Paste
nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR>
@@ -4477,6 +4571,27 @@ describe('builtin popupmenu', function()
feed('<Esc>')
+ command('set rightleft')
+ feed('/X<CR>:popup PopUp<CR>')
+ screen:expect([[
+ evif ruof eerht owt eno|
+ evif ruof eerht{7:^X} owt eno dna|
+ {n: odnU }wt erom eno|
+ {1: }{n: }{1: ~}|
+ {1: }{n: etsaP }{1: ~}|
+ {1: }{n: }{1: ~}|
+ {1: }{n: droW tceleS }{1: ~}|
+ {1: }{n: ecnetneS tceleS }{1: ~}|
+ {1: }{n: hpargaraP tceleS }{1: ~}|
+ {1: }{n: eniL tceleS }{1: ~}|
+ {1: }{n: kcolB tceleS }{1: ~}|
+ {1: }{n: llA tceleS }{1: ~}|
+ {1: ~}|*7
+ :popup PopUp |
+ ]])
+ feed('<Esc>')
+ command('set norightleft')
+
-- 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.
@@ -4533,6 +4648,57 @@ describe('builtin popupmenu', function()
feed('<Esc>')
end)
+ -- oldtest: Test_mouse_popup_position()
+ it('position of right-click menu when clicking near edge', function()
+ screen:try_resize(50, 20)
+ exec([[
+ set mousemodel=popup_setpos
+ " Delete the default MenuPopup event handler.
+ autocmd! nvim_popupmenu
+ aunmenu *
+ source $VIMRUNTIME/menu.vim
+ call setline(1, join(range(20)))
+ ]])
+
+ api.nvim_input_mouse('right', 'press', '', 0, 0, 45 - 1)
+ screen:expect([[
+ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ^18 19 |
+ {1:~ }{n: Undo }|
+ {1:~ }{n: }|
+ {1:~ }{n: Paste }|
+ {1:~ }{n: }|
+ {1:~ }{n: Select Word }|
+ {1:~ }{n: Select Sentence }|
+ {1:~ }{n: Select Paragraph}|
+ {1:~ }{n: Select Line }|
+ {1:~ }{n: Select Block }|
+ {1:~ }{n: Select All }|
+ {1:~ }|*8
+ |
+ ]])
+ feed('<Esc>')
+
+ command('set rightleft')
+ api.nvim_input_mouse('right', 'press', '', 0, 0, 50 - 45)
+ screen:expect([[
+ 91 8^1 71 61 51 41 31 21 11 01 9 8 7 6 5 4 3 2 1 0|
+ {n: odnU }{1: ~}|
+ {n: }{1: ~}|
+ {n: etsaP }{1: ~}|
+ {n: }{1: ~}|
+ {n: droW tceleS }{1: ~}|
+ {n: ecnetneS tceleS }{1: ~}|
+ {n:hpargaraP tceleS }{1: ~}|
+ {n: eniL tceleS }{1: ~}|
+ {n: kcolB tceleS }{1: ~}|
+ {n: llA tceleS }{1: ~}|
+ {1: ~}|*8
+ |
+ ]])
+ feed('<Esc>')
+ command('set norightleft')
+ end)
+
describe('"kind" and "menu"', function()
before_each(function()
screen:try_resize(30, 8)
@@ -4569,9 +4735,9 @@ describe('builtin popupmenu', function()
-- oldtest: Test_pum_highlights_custom()
it('custom highlight groups', function()
exec([[
- hi PmenuKind guifg=Red guibg=Magenta
+ hi PmenuKind guifg=Red guibg=Plum1
hi PmenuKindSel guifg=Red guibg=Grey
- hi PmenuExtra guifg=White guibg=Magenta
+ hi PmenuExtra guifg=White guibg=Plum1
hi PmenuExtraSel guifg=Black guibg=Grey
]])
feed('iaw<C-X><C-u>')
@@ -4585,6 +4751,443 @@ describe('builtin popupmenu', function()
]])
end)
end)
+
+ -- oldtest: Test_pum_highlights_match()
+ it('can highlight matched text', function()
+ exec([[
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'foo', 'kind': 'fookind' },
+ \ { 'word': 'foofoo', 'kind': 'fookind' },
+ \ { 'word': 'foobar', 'kind': 'fookind' },
+ \ { 'word': 'fooBaz', 'kind': 'fookind' },
+ \ { 'word': 'foobala', 'kind': 'fookind' },
+ \ { 'word': '你好' },
+ \ { 'word': '你好吗' },
+ \ { 'word': '你不好吗' },
+ \ { 'word': '你可好吗' },
+ \]}
+ endfunc
+
+ func Comp()
+ let col = col('.')
+ if getline('.') == 'f'
+ let col -= 1
+ endif
+ call complete(col, [
+ \ #{word: "foo", icase: 1},
+ \ #{word: "Foobar", icase: 1},
+ \ #{word: "fooBaz", icase: 1},
+ \])
+ return ''
+ endfunc
+
+ set omnifunc=Omni_test
+ set completeopt=menu,noinsert,fuzzy
+ hi PmenuMatchSel guifg=Blue guibg=Grey
+ hi PmenuMatch guifg=Blue guibg=Plum1
+ ]])
+ feed('i<C-X><C-O>')
+ local pum_start = [[
+ ^ |
+ {s:foo fookind }{1: }|
+ {n:foofoo fookind }{1: }|
+ {n:foobar fookind }{1: }|
+ {n:fooBaz fookind }{1: }|
+ {n:foobala fookind }{1: }|
+ {n:你好 }{1: }|
+ {n:你好吗 }{1: }|
+ {n:你不好吗 }{1: }|
+ {n:你可好吗 }{1: }|
+ {1:~ }|*9
+ {2:-- }{5:match 1 of 9} |
+ ]]
+ screen:expect(pum_start)
+ feed('fo')
+ screen:expect([[
+ fo^ |
+ {ms:fo}{s:o fookind }{1: }|
+ {mn:fo}{n:ofoo fookind }{1: }|
+ {mn:fo}{n:obar fookind }{1: }|
+ {mn:fo}{n:oBaz fookind }{1: }|
+ {mn:fo}{n:obala fookind }{1: }|
+ {1:~ }|*13
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('<Esc>S<C-X><C-O>')
+ screen:expect(pum_start)
+ feed('你')
+ screen:expect([[
+ 你^ |
+ {ms:你}{s:好 }{1: }|
+ {mn:你}{n:好吗 }{1: }|
+ {mn:你}{n:不好吗 }{1: }|
+ {mn:你}{n:可好吗 }{1: }|
+ {1:~ }|*14
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('吗')
+ screen:expect([[
+ 你吗^ |
+ {ms:你}{s:好}{ms:吗}{s: }{1: }|
+ {mn:你}{n:不好}{mn:吗}{n: }{1: }|
+ {mn:你}{n:可好}{mn:吗}{n: }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('<C-E><Esc>')
+
+ command('set rightleft')
+ feed('S<C-X><C-O>')
+ local pum_start_rl = [[
+ ^ |
+ {1: }{s: dnikoof oof}|
+ {1: }{n: dnikoof oofoof}|
+ {1: }{n: dnikoof raboof}|
+ {1: }{n: dnikoof zaBoof}|
+ {1: }{n: dnikoof alaboof}|
+ {1: }{n: 好你}|
+ {1: }{n: 吗好你}|
+ {1: }{n: 吗好不你}|
+ {1: }{n: 吗好可你}|
+ {1: ~}|*9
+ {2:-- }{5:match 1 of 9} |
+ ]]
+ screen:expect(pum_start_rl)
+ feed('fo')
+ screen:expect([[
+ ^ of|
+ {1: }{s: dnikoof o}{ms:of}|
+ {1: }{n: dnikoof oofo}{mn:of}|
+ {1: }{n: dnikoof rabo}{mn:of}|
+ {1: }{n: dnikoof zaBo}{mn:of}|
+ {1: }{n: dnikoof alabo}{mn:of}|
+ {1: ~}|*13
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('<Esc>S<C-X><C-O>')
+ screen:expect(pum_start_rl)
+ feed('你')
+ screen:expect([[
+ ^ 你|
+ {1: }{s: 好}{ms:你}|
+ {1: }{n: 吗好}{mn:你}|
+ {1: }{n: 吗好不}{mn:你}|
+ {1: }{n: 吗好可}{mn:你}|
+ {1: ~}|*14
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('吗')
+ screen:expect([[
+ ^ 吗你|
+ {1: }{s: }{ms:吗}{s:好}{ms:你}|
+ {1: }{n: }{mn:吗}{n:好不}{mn:你}|
+ {1: }{n: }{mn:吗}{n:好可}{mn:你}|
+ {1: ~}|*15
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('<C-E><Esc>')
+ command('set norightleft')
+
+ command('set completeopt-=fuzzy')
+ feed('S<C-X><C-O>')
+ screen:expect(pum_start)
+ feed('fo')
+ screen:expect([[
+ fo^ |
+ {ms:fo}{s:o fookind }{1: }|
+ {mn:fo}{n:ofoo fookind }{1: }|
+ {mn:fo}{n:obar fookind }{1: }|
+ {mn:fo}{n:oBaz fookind }{1: }|
+ {mn:fo}{n:obala fookind }{1: }|
+ {1:~ }|*13
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('<C-E><Esc>')
+
+ command('set rightleft')
+ feed('S<C-X><C-O>')
+ screen:expect(pum_start_rl)
+ feed('fo')
+ screen:expect([[
+ ^ of|
+ {1: }{s: dnikoof o}{ms:of}|
+ {1: }{n: dnikoof oofo}{mn:of}|
+ {1: }{n: dnikoof rabo}{mn:of}|
+ {1: }{n: dnikoof zaBo}{mn:of}|
+ {1: }{n: dnikoof alabo}{mn:of}|
+ {1: ~}|*13
+ {2:-- }{5:match 1 of 9} |
+ ]])
+ feed('<C-E><Esc>')
+ command('set norightleft')
+
+ feed('S<C-R>=Comp()<CR>f')
+ screen:expect([[
+ f^ |
+ {ms:f}{s:oo }{1: }|
+ {mn:F}{n:oobar }{1: }|
+ {mn:f}{n:ooBaz }{1: }|
+ {1:~ }|*15
+ {2:-- INSERT --} |
+ ]])
+ feed('o<BS><C-R>=Comp()<CR>')
+ screen:expect_unchanged(true)
+
+ feed('<Esc>')
+ command('set completeopt+=fuzzy,menu')
+ feed('S hello helio hero h<C-X><C-P>')
+ screen:expect([[
+ hello helio hero h^ |
+ {1:~ }{n: }{mn:h}{n:ello }{1: }|
+ {1:~ }{n: }{mn:h}{n:elio }{1: }|
+ {1:~ }{s: }{ms:h}{s:ero }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+
+ feed('<Esc>S hello helio hero h<C-X><C-P><C-P>')
+ screen:expect([[
+ hello helio hero h^ |
+ {1:~ }{n: }{mn:h}{n:ello }{1: }|
+ {1:~ }{s: }{ms:h}{s:elio }{1: }|
+ {1:~ }{n: }{mn:h}{n:ero }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 2 of 3} |
+ ]])
+
+ feed('<C-E><Esc>')
+ end)
+
+ -- oldtest: Test_pum_user_hl_group()
+ it('custom hl_group override', function()
+ exec([[
+ func CompleteFunc( findstart, base )
+ if a:findstart
+ return 0
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
+ \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \]}
+ endfunc
+ set completeopt=menu
+ set completefunc=CompleteFunc
+
+ hi StrikeFake guifg=DarkRed
+ func HlMatch()
+ hi PmenuMatchSel guifg=Blue guibg=Grey gui=underline
+ hi PmenuMatch guifg=Blue guibg=Plum1 gui=underline
+ endfunc
+ ]])
+
+ feed('Saw<C-X><C-U>')
+ screen:expect([[
+ aword1^ |
+ {ds:aword1 W extra text 1 }{1: }|
+ {n:aword2 W extra text 2 }{1: }|
+ {dn:你好 W extra text 3 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+
+ command('call HlMatch()')
+
+ feed('Saw<C-X><C-U>')
+ screen:expect([[
+ aword1^ |
+ {uds:aw}{ds:ord1 W extra text 1 }{1: }|
+ {umn:aw}{n:ord2 W extra text 2 }{1: }|
+ {dn:你好 W extra text 3 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-N>')
+ screen:expect([[
+ aword2^ |
+ {udn:aw}{dn:ord1 W extra text 1 }{1: }|
+ {ums:aw}{s:ord2 W extra text 2 }{1: }|
+ {dn:你好 W extra text 3 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 2 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+ end)
+
+ -- oldtest: Test_pum_user_kind_hlgroup()
+ it('custom kind_hlgroup override', function()
+ exec([[
+ func CompleteFunc( findstart, base )
+ if a:findstart
+ return 0
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' },
+ \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' },
+ \]}
+ endfunc
+ set completeopt=menu
+ set completefunc=CompleteFunc
+
+ hi StrikeFake guifg=DarkRed
+ hi KindVar guifg=DarkYellow
+ hi KindFunc guifg=DarkBlue
+ hi KindClass guifg=DarkGreen
+ ]])
+
+ local attr_ids = screen:get_default_attr_ids()
+ attr_ids.kvs = { foreground = Screen.colors.DarkYellow, background = Screen.colors.Grey }
+ attr_ids.kfn = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Plum1 }
+ attr_ids.kcn = { foreground = Screen.colors.DarkGreen, background = Screen.colors.Plum1 }
+ screen:set_default_attr_ids(attr_ids)
+
+ feed('S<C-X><C-U>')
+ screen:expect([[
+ aword1^ |
+ {ds:aword1 }{kvs:variable }{ds:extra text 1 }{1: }|
+ {n:aword2 }{kfn:function }{n:extra text 2 }{1: }|
+ {n:你好 }{kcn:class }{n:extra text 3 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+ end)
+
+ -- oldtest: Test_pum_completeitemalign()
+ it('completeitemalign option', function()
+ screen:try_resize(30, 15)
+ exec([[
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'foo', 'kind': 'S', 'menu': 'menu' },
+ \ { 'word': 'bar', 'kind': 'T', 'menu': 'menu' },
+ \ { 'word': '你好', 'kind': 'C', 'menu': '中文' },
+ \]}
+ endfunc
+
+ func Omni_long(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'loooong_foo', 'kind': 'S', 'menu': 'menu' },
+ \ { 'word': 'loooong_bar', 'kind': 'T', 'menu': 'menu' },
+ \]}
+ endfunc
+ set omnifunc=Omni_test
+ ]])
+ -- T1
+ command('set cia=abbr,kind,menu')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:foo S menu }{1: }|
+ {n:bar T menu }{1: }|
+ {n:你好 C 中文 }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+ -- T2
+ command('set cia=abbr,menu,kind')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:foo menu S }{1: }|
+ {n:bar menu T }{1: }|
+ {n:你好 中文 C }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+ -- T3
+ command('set cia=kind,abbr,menu')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:S foo menu }{1: }|
+ {n:T bar menu }{1: }|
+ {n:C 你好 中文 }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+ -- T4
+ command('set cia=kind,menu,abbr')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:S menu foo }{1: }|
+ {n:T menu bar }{1: }|
+ {n:C 中文 你好 }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+ -- T5
+ command('set cia=menu,abbr,kind')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:menu foo S }{1: }|
+ {n:menu bar T }{1: }|
+ {n:中文 你好 C }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+ -- T6
+ command('set cia=menu,kind,abbr')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:menu S foo }{1: }|
+ {n:menu T bar }{1: }|
+ {n:中文 C 你好 }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+ -- T7
+ command('set cia&')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ foo^ |
+ {s:foo S menu }{1: }|
+ {n:bar T menu }{1: }|
+ {n:你好 C 中文 }{1: }|
+ {1:~ }|*10
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+
+ -- Test_pum_completeitemalign_07
+ command('set cia=menu,kind,abbr columns=12 cmdheight=2 omnifunc=Omni_long')
+ feed('S<C-X><C-O>')
+ screen:expect([[
+ loooong_foo^ |
+ {s:menu S loooo}|
+ {n:menu T loooo}|
+ {1:~ }|*10
+ |
+ {2:--} |
+ ]])
+ feed('<C-E><ESC>')
+ end)
end
end
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 4625ce8553..f1891b608e 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -255,6 +255,7 @@ end
function Screen:set_default_attr_ids(attr_ids)
self._default_attr_ids = attr_ids
+ self._attrs_overridden = true
end
function Screen:add_extra_attr_ids(extra_attr_ids)
@@ -437,7 +438,7 @@ end
--- @field mouse_enabled? boolean
---
--- @field win_viewport? table<integer,table<string,integer>>
---- @field float_pos? {[1]:integer,[2]:integer}
+--- @field float_pos? [integer,integer]
--- @field hl_groups? table<string,integer>
---
--- The following keys should be used to expect the state of various ext_
@@ -699,9 +700,9 @@ screen:redraw_debug() to show all intermediate screen states.]]
end, expected)
end
-function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs)
+function Screen:expect_unchanged(intermediate, waittime_ms)
-- Collect the current screen state.
- local kwargs = self:get_snapshot(nil, ignore_attrs)
+ local kwargs = self:get_snapshot()
if intermediate then
kwargs.intermediate = true
@@ -787,7 +788,9 @@ function Screen:_wait(check, flags)
end
local eof = run_session(self._session, flags.request_cb, notification_cb, nil, minimal_timeout)
if not did_flush then
- err = 'no flush received'
+ if eof then
+ err = 'no flush received'
+ end
elseif not checked then
err = check()
if not err and flags.unchanged then
@@ -800,6 +803,9 @@ function Screen:_wait(check, flags)
did_minimal_timeout = true
eof =
run_session(self._session, flags.request_cb, notification_cb, nil, timeout - minimal_timeout)
+ if not did_flush then
+ err = 'no flush received'
+ end
end
local did_warn = false
@@ -1536,13 +1542,14 @@ end
-- Use snapshot_util({}) to generate a text-only (no attributes) test.
--
-- @see Screen:redraw_debug()
-function Screen:snapshot_util(attrs, ignore, request_cb)
+function Screen:snapshot_util(request_cb)
+ -- TODO: simplify this later when existing tests have been updated
self:sleep(250, request_cb)
- self:print_snapshot(attrs, ignore)
+ self:print_snapshot()
end
-function Screen:redraw_debug(attrs, ignore, timeout)
- self:print_snapshot(attrs, ignore)
+function Screen:redraw_debug(timeout)
+ self:print_snapshot()
local function notification_cb(method, args)
assert(method == 'redraw')
for _, update in ipairs(args) do
@@ -1552,7 +1559,7 @@ function Screen:redraw_debug(attrs, ignore, timeout)
end
end
self:_redraw(args)
- self:print_snapshot(attrs, ignore)
+ self:print_snapshot()
return true
end
if timeout == nil then
@@ -1596,23 +1603,12 @@ end
-- Returns the current screen state in the form of a screen:expect()
-- keyword-args map.
-function Screen:get_snapshot(attrs, ignore)
- if ignore == nil then
- ignore = self._default_attr_ignore
- end
+function Screen:get_snapshot()
local attr_state = {
ids = {},
- ignore = ignore,
mutable = true, -- allow _row_repr to add missing highlights
}
- if attrs == nil then
- attrs = self._default_attr_ids
- elseif isempty(attrs) then
- attrs = nil
- attr_state.ids = nil
- else
- attr_state.modified = true
- end
+ local attrs = self._default_attr_ids
if attrs ~= nil then
for i, a in pairs(attrs) do
@@ -1708,9 +1704,10 @@ local function fmt_ext_state(name, state)
end
end
-function Screen:_print_snapshot(attrs, ignore)
- local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore)
+function Screen:_print_snapshot()
+ local kwargs, ext_state, attr_state = self:get_snapshot()
local attrstr = ''
+ local modify_attrs = not self._attrs_overridden
if attr_state.modified then
local attrstrs = {}
for i, a in pairs(attr_state.ids) do
@@ -1721,16 +1718,20 @@ function Screen:_print_snapshot(attrs, ignore)
dict = '{ ' .. self:_pprint_attrs(a) .. ' }'
end
local keyval = (type(i) == 'number') and '[' .. tostring(i) .. ']' or i
- table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',')
+ if not (type(i) == 'number' and modify_attrs and i <= 30) then
+ table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',')
+ end
+ if modify_attrs then
+ self._default_attr_ids = attr_state.ids
+ end
end
- attrstr = (',\n attr_ids = {\n ' .. table.concat(attrstrs, '\n ') .. '\n },')
- elseif isempty(attrs) then
- attrstr = ',\n attr_ids = {},'
+ local fn_name = modify_attrs and 'add_extra_attr_ids' or 'set_default_attr_ids'
+ attrstr = ('screen:' .. fn_name .. ' {\n' .. table.concat(attrstrs, '\n') .. '\n}\n\n')
end
- local result = ('screen:expect({\n grid = [[\n %s\n ]]%s'):format(
- kwargs.grid:gsub('\n', '\n '),
- attrstr
+ local result = ('%sscreen:expect({\n grid = [[\n %s\n ]]'):format(
+ attrstr,
+ kwargs.grid:gsub('\n', '\n ')
)
for _, k in ipairs(ext_keys) do
if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then
@@ -1742,8 +1743,8 @@ function Screen:_print_snapshot(attrs, ignore)
return result
end
-function Screen:print_snapshot(attrs, ignore)
- print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n')
+function Screen:print_snapshot()
+ print('\n' .. self:_print_snapshot() .. '\n')
io.stdout:flush()
end
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 54580bf47c..85a653df36 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen')
local spawn, set_session, clear = n.spawn, n.set_session, n.clear
local feed, command = n.feed, n.command
+local exec = n.exec
local insert = n.insert
local eq = t.eq
local fn, api = n.fn, n.api
@@ -819,3 +820,39 @@ it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", f
]],
}
end)
+
+it("scrolling in narrow window doesn't draw over separator #29033", function()
+ clear()
+ local screen = Screen.new(60, 8)
+ screen:attach()
+ feed('100Oa<Esc>gg')
+ exec([[
+ set number nowrap
+ vsplit
+ set scrollbind
+ wincmd l
+ set scrollbind
+ wincmd |
+ ]])
+ screen:expect([[
+ {8: }│{8: 1 }^a |
+ {8: }│{8: 2 }a |
+ {8: }│{8: 3 }a |
+ {8: }│{8: 4 }a |
+ {8: }│{8: 5 }a |
+ {8: }│{8: 6 }a |
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]])
+ feed('<C-F>')
+ screen:expect([[
+ {8: }│{8: 5 }^a |
+ {8: }│{8: 6 }a |
+ {8: }│{8: 7 }a |
+ {8: }│{8: 8 }a |
+ {8: }│{8: 9 }a |
+ {8: }│{8: 10 }a |
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]])
+end)
diff --git a/test/functional/ui/scrollbind_spec.lua b/test/functional/ui/scrollbind_spec.lua
new file mode 100644
index 0000000000..9e70b25efa
--- /dev/null
+++ b/test/functional/ui/scrollbind_spec.lua
@@ -0,0 +1,442 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local clear = n.clear
+local Screen = require('test.functional.ui.screen')
+
+before_each(clear)
+
+describe('Scrollbind', function()
+ local screen --- @type test.functional.ui.screen
+
+ before_each(function()
+ screen = Screen.new(40, 12)
+ screen:attach()
+ end)
+
+ it('works with one buffer with virtual lines', function()
+ n.exec_lua(function()
+ local lines = {} --- @type string[]
+
+ for i = 1, 20 do
+ lines[i] = tostring(i * 2 - 1)
+ end
+
+ local ns = vim.api.nvim_create_namespace('test')
+
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
+ vim.bo.buftype = 'nofile'
+
+ for i in ipairs(lines) do
+ vim.api.nvim_buf_set_extmark(0, ns, i - 1, 0, {
+ virt_lines = { { { tostring(2 * i) .. ' v' } } },
+ })
+ end
+
+ vim.wo.scrollbind = true
+ vim.cmd.vsplit()
+ vim.wo.scrollbind = true
+ end)
+
+ n.feed('<C-d>')
+
+ t.eq(5, n.api.nvim_get_option_value('scroll', {}))
+
+ screen:expect({
+ grid = [[
+ 6 v │6 v |
+ 7 │7 |
+ 8 v │8 v |
+ 9 │9 |
+ 10 v │10 v |
+ ^11 │11 |
+ 12 v │12 v |
+ 13 │13 |
+ 14 v │14 v |
+ 15 │15 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-u>')
+
+ local line1_grid = [[
+ ^1 │1 |
+ 2 v │2 v |
+ 3 │3 |
+ 4 v │4 v |
+ 5 │5 |
+ 6 v │6 v |
+ 7 │7 |
+ 8 v │8 v |
+ 9 │9 |
+ 10 v │10 v |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]]
+
+ screen:expect({ grid = line1_grid })
+
+ n.api.nvim_set_option_value('scroll', 6, {})
+
+ n.feed('<C-d>')
+
+ screen:expect({
+ grid = [[
+ 7 │7 |
+ 8 v │8 v |
+ 9 │9 |
+ 10 v │10 v |
+ 11 │11 |
+ 12 v │12 v |
+ ^13 │13 |
+ 14 v │14 v |
+ 15 │15 |
+ 16 v │16 v |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-u>')
+
+ screen:expect({ grid = line1_grid })
+ end)
+
+ it('works with two buffers with virtual lines on one side', function()
+ n.exec_lua(function()
+ local lines = {} --- @type string[]
+
+ for i = 1, 20 do
+ lines[i] = tostring(i)
+ end
+
+ local ns = vim.api.nvim_create_namespace('test')
+
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
+ vim.bo.buftype = 'nofile'
+
+ vim.wo.scrollbind = true
+ vim.cmd.vnew()
+
+ lines = {} --- @type string[]
+
+ for i = 1, 20 do
+ lines[i] = tostring(i + (i > 3 and 4 or 0))
+ end
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
+ vim.bo.buftype = 'nofile'
+
+ vim.api.nvim_buf_set_extmark(0, ns, 2, 0, {
+ virt_lines = {
+ { { '4 v' } },
+ { { '5 v' } },
+ { { '6 v' } },
+ { { '7 v' } },
+ },
+ })
+
+ vim.wo.scrollbind = true
+ end)
+
+ n.feed('<C-d>')
+
+ t.eq(5, n.api.nvim_get_option_value('scroll', {}))
+
+ screen:expect({
+ grid = [[
+ 6 v │6 |
+ 7 v │7 |
+ 8 │8 |
+ 9 │9 |
+ ^10 │10 |
+ 11 │11 |
+ 12 │12 |
+ 13 │13 |
+ 14 │14 |
+ 15 │15 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-u>')
+
+ local line1_grid = [[
+ ^1 │1 |
+ 2 │2 |
+ 3 │3 |
+ 4 v │4 |
+ 5 v │5 |
+ 6 v │6 |
+ 7 v │7 |
+ 8 │8 |
+ 9 │9 |
+ 10 │10 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]]
+
+ screen:expect({ grid = line1_grid })
+
+ n.api.nvim_set_option_value('scroll', 6, {})
+
+ n.feed('<C-d>')
+
+ screen:expect({
+ grid = [[
+ 7 v │7 |
+ 8 │8 |
+ 9 │9 |
+ 10 │10 |
+ ^11 │11 |
+ 12 │12 |
+ 13 │13 |
+ 14 │14 |
+ 15 │15 |
+ 16 │16 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-u>')
+
+ screen:expect({ grid = line1_grid })
+
+ -- Note: not the same as n.feed('4<C-e>')
+ n.feed('<C-e>')
+ n.feed('<C-e>')
+ n.feed('<C-e>')
+ n.feed('<C-e>')
+
+ screen:expect({
+ grid = [[
+ 5 v │5 |
+ 6 v │6 |
+ 7 v │7 |
+ ^8 │8 |
+ 9 │9 |
+ 10 │10 |
+ 11 │11 |
+ 12 │12 |
+ 13 │13 |
+ 14 │14 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-e>')
+
+ screen:expect({
+ grid = [[
+ 6 v │6 |
+ 7 v │7 |
+ ^8 │8 |
+ 9 │9 |
+ 10 │10 |
+ 11 │11 |
+ 12 │12 |
+ 13 │13 |
+ 14 │14 |
+ 15 │15 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+
+ screen:expect({
+ grid = [[
+ 4 v │4 |
+ 5 v │5 |
+ 6 v │6 |
+ 7 v │7 |
+ ^8 │8 |
+ 9 │9 |
+ 10 │10 |
+ 11 │11 |
+ 12 │12 |
+ 13 │13 |
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+ end)
+
+ it('works with buffers of different lengths', function()
+ n.exec_lua(function()
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, { '1', '2', '3' })
+ vim.bo.buftype = 'nofile'
+
+ vim.wo.scrollbind = true
+ vim.cmd.vnew()
+
+ local lines = {} --- @type string[]
+
+ for i = 1, 50 do
+ lines[i] = tostring(i)
+ end
+
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
+ vim.bo.buftype = 'nofile'
+ vim.wo.scrollbind = true
+ end)
+
+ n.feed('10<C-e>')
+
+ screen:expect({
+ grid = [[
+ ^11 │3 |
+ 12 │{1:~ }|
+ 13 │{1:~ }|
+ 14 │{1:~ }|
+ 15 │{1:~ }|
+ 16 │{1:~ }|
+ 17 │{1:~ }|
+ 18 │{1:~ }|
+ 19 │{1:~ }|
+ 20 │{1:~ }|
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-y>')
+
+ screen:expect({
+ grid = [[
+ 10 │3 |
+ ^11 │{1:~ }|
+ 12 │{1:~ }|
+ 13 │{1:~ }|
+ 14 │{1:~ }|
+ 15 │{1:~ }|
+ 16 │{1:~ }|
+ 17 │{1:~ }|
+ 18 │{1:~ }|
+ 19 │{1:~ }|
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+ end)
+
+ it('works with buffers of different lengths and virtual lines', function()
+ n.exec_lua(function()
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, { '1', '5', '6' })
+
+ local ns = vim.api.nvim_create_namespace('test')
+ vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {
+ virt_lines = {
+ { { '2 v' } },
+ { { '3 v' } },
+ { { '4 v' } },
+ },
+ })
+
+ vim.bo.buftype = 'nofile'
+
+ vim.wo.scrollbind = true
+ vim.cmd.vnew()
+
+ local lines = {} --- @type string[]
+
+ for i = 1, 50 do
+ lines[i] = tostring(i)
+ end
+
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
+ vim.bo.buftype = 'nofile'
+ vim.wo.scrollbind = true
+ end)
+
+ n.feed('<C-e>')
+ n.feed('<C-e>')
+ screen:expect({
+ grid = [[
+ ^3 │3 v |
+ 4 │4 v |
+ 5 │5 |
+ 6 │6 |
+ 7 │{1:~ }|
+ 8 │{1:~ }|
+ 9 │{1:~ }|
+ 10 │{1:~ }|
+ 11 │{1:~ }|
+ 12 │{1:~ }|
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('8<C-e>')
+
+ screen:expect({
+ grid = [[
+ ^11 │6 |
+ 12 │{1:~ }|
+ 13 │{1:~ }|
+ 14 │{1:~ }|
+ 15 │{1:~ }|
+ 16 │{1:~ }|
+ 17 │{1:~ }|
+ 18 │{1:~ }|
+ 19 │{1:~ }|
+ 20 │{1:~ }|
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+
+ t.eq(n.exec_lua [[return vim.fn.line('w0', 1001)]], 6)
+ t.eq(n.exec_lua [[return vim.fn.line('w0', 1000)]], 3)
+
+ screen:expect({
+ grid = [[
+ 6 │6 |
+ 7 │{1:~ }|
+ 8 │{1:~ }|
+ 9 │{1:~ }|
+ 10 │{1:~ }|
+ ^11 │{1:~ }|
+ 12 │{1:~ }|
+ 13 │{1:~ }|
+ 14 │{1:~ }|
+ 15 │{1:~ }|
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+ n.feed('<C-y>')
+
+ screen:expect({
+ grid = [[
+ 3 │3 v |
+ 4 │4 v |
+ 5 │5 |
+ 6 │6 |
+ 7 │{1:~ }|
+ 8 │{1:~ }|
+ 9 │{1:~ }|
+ 10 │{1:~ }|
+ ^11 │{1:~ }|
+ 12 │{1:~ }|
+ {3:[Scratch] }{2:[Scratch] }|
+ |
+ ]],
+ })
+ end)
+end)
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 8bdf528412..eab265cbb1 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -197,7 +197,8 @@ describe('search highlighting', function()
}
end)
- it('works for multiline match', function()
+ -- oldtest: Test_hlsearch_cursearch()
+ it('works for multiline match, no duplicate highlight', function()
command([[call setline(1, ['one', 'foo', 'bar', 'baz', 'foo the foo and foo', 'bar'])]])
feed('gg/foo<CR>')
screen:expect([[
@@ -281,6 +282,28 @@ describe('search highlighting', function()
{2:hij}kl |
/efg\nhij |
]])
+
+ -- check clearing CurSearch when using it for another match
+ feed('G?^abcd<CR>Y')
+ screen:expect([[
+ --- |
+ {1:abcd}efg |
+ hijkl |
+ --- |
+ {2:^abcd}efg |
+ hijkl |
+ ?^abcd |
+ ]])
+ feed('kkP')
+ screen:expect([[
+ --- |
+ {1:abcd}efg |
+ {2:^abcd}efg |
+ hijkl |
+ --- |
+ {1:abcd}efg |
+ ?^abcd |
+ ]])
end)
end)
@@ -345,12 +368,19 @@ describe('search highlighting', function()
bar baz foo
bar foo baz]])
feed('/foo')
+ screen:set_default_attr_ids({
+ [1] = { bold = true, foreground = Screen.colors.Blue },
+ [2] = { background = Screen.colors.Yellow }, -- Search
+ [3] = { reverse = true },
+ [4] = { bold = true, reverse = true },
+ [5] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen },
+ })
screen:expect([[
{3:foo} bar baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}|
bar baz {2:foo} │{MATCH:%d+}: {2:foo}{MATCH:%s+}|
bar {2:foo} baz │{MATCH:%d+}: {2:foo}{MATCH:%s+}|
{1:~ }│{MATCH:.*}|*2
- {5:[No Name] [+] }{3:term }|
+ {4:[No Name] [+] }{5:term }|
/foo^ |
]])
end)
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index b353b3738a..30da79af47 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen')
local api, clear, eq = n.api, n.clear, t.eq
local eval, exec, feed = n.eval, n.exec, n.feed
+local exec_lua = n.exec_lua
describe('Signs', function()
local screen
@@ -577,4 +578,45 @@ describe('Signs', function()
]])
eq({}, eval('sign_getdefined()'))
end)
+
+ it('no crash when unplacing signs beyond end of buffer', function()
+ exec([[
+ sign define S1 text=S1
+ sign define S2 text=S2
+ sign place 1 line=8 name=S1
+ sign place 2 line=9 name=S2
+ ]])
+ -- Now placed at end of buffer
+ local s1 = {
+ grid = [[
+ S2^ |
+ {0:~ }|*12
+ |
+ ]],
+ }
+ screen:expect(s1)
+ -- Signcolumn tracking used to not count signs placed beyond end of buffer here
+ exec('set signcolumn=auto:9')
+ screen:expect({
+ grid = [[
+ S2S1^ |
+ {0:~ }|*12
+ |
+ ]],
+ })
+ -- Unplacing the sign does not crash by decrementing tracked signs below zero
+ exec('sign unplace 1')
+ screen:expect(s1)
+ end)
+
+ it('signcolumn width is set immediately after splitting window #30547', function()
+ local infos = exec_lua([[
+ vim.o.number = true
+ vim.o.signcolumn = 'yes'
+ vim.cmd.wincmd('v')
+ return vim.fn.getwininfo()
+ ]])
+ eq(6, infos[1].textoff)
+ eq(6, infos[2].textoff)
+ end)
end)
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index faf94bccbe..b4d4c94a5e 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -91,49 +91,87 @@ describe('statuscolumn', function()
{8:2 }aaaaa |
|
]])
+ -- Doesn't crash when clicking inside padded area without click_defs
+ command('set numberwidth=10')
+ api.nvim_input_mouse('left', 'press', '', 0, 0, 5)
+ assert_alive()
end)
it("works with 'number' and 'relativenumber'", function()
- command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
- screen:expect([[
- {8:4 │}aaaaa |
- {8:5 │}aaaaa |
- {8:6 │}aaaaa |
- {8:7 │}aaaaa |
- {8:8 │}^aaaaa |
- {8:9 │}aaaaa |
- {8:10│}aaaaa |
- {8:11│}aaaaa |
- {8:12│}aaaaa |
- {8:13│}aaaaa |
- {8:14│}aaaaa |
- {8:15│}aaaaa |
- {8:16│}aaaaa |
- |
- ]])
- command([[set stc=%l%=%{&rnu?'\ ':''}%r│]])
+ screen:expect([[
+ {8: 4 }aaaaa |
+ {8: 5 }aaaaa |
+ {8: 6 }aaaaa |
+ {8: 7 }aaaaa |
+ {8: 8 }^aaaaa |
+ {8: 9 }aaaaa |
+ {8:10 }aaaaa |
+ {8:11 }aaaaa |
+ {8:12 }aaaaa |
+ {8:13 }aaaaa |
+ {8:14 }aaaaa |
+ {8:15 }aaaaa |
+ {8:16 }aaaaa |
+ |
+ ]])
+ command([[set stc=%l\ ]])
screen:expect_unchanged()
- command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
command('set relativenumber')
screen:expect([[
- {8:4 4│}aaaaa |
- {8:5 3│}aaaaa |
- {8:6 2│}aaaaa |
- {8:7 1│}aaaaa |
- {8:8 0│}^aaaaa |
- {8:9 1│}aaaaa |
- {8:10 2│}aaaaa |
- {8:11 3│}aaaaa |
- {8:12 4│}aaaaa |
- {8:13 5│}aaaaa |
- {8:14 6│}aaaaa |
- {8:15 7│}aaaaa |
- {8:16 8│}aaaaa |
- |
- ]])
- command([[set stc=%l%=%{&rnu?'\ ':''}%r│]])
+ {8: 4 }aaaaa |
+ {8: 3 }aaaaa |
+ {8: 2 }aaaaa |
+ {8: 1 }aaaaa |
+ {8:8 }^aaaaa |
+ {8: 1 }aaaaa |
+ {8: 2 }aaaaa |
+ {8: 3 }aaaaa |
+ {8: 4 }aaaaa |
+ {8: 5 }aaaaa |
+ {8: 6 }aaaaa |
+ {8: 7 }aaaaa |
+ {8: 8 }aaaaa |
+ |
+ ]])
+ command('set stc=')
+ screen:expect_unchanged()
+ command([[set nonu stc=%l\ ]])
+ screen:expect([[
+ {8: 4 }aaaaa |
+ {8: 3 }aaaaa |
+ {8: 2 }aaaaa |
+ {8: 1 }aaaaa |
+ {8: 0 }^aaaaa |
+ {8: 1 }aaaaa |
+ {8: 2 }aaaaa |
+ {8: 3 }aaaaa |
+ {8: 4 }aaaaa |
+ {8: 5 }aaaaa |
+ {8: 6 }aaaaa |
+ {8: 7 }aaaaa |
+ {8: 8 }aaaaa |
+ |
+ ]])
+ command('set nuw=1 stc=')
screen:expect_unchanged()
- command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]])
+ -- Correct alignment with items before and after number column
+ command([[set nu stc=foo\ %l\ bar]])
+ screen:expect([[
+ {8:foo 4 bar}aaaaa |
+ {8:foo 3 bar}aaaaa |
+ {8:foo 2 bar}aaaaa |
+ {8:foo 1 bar}aaaaa |
+ {8:foo 8 bar}^aaaaa |
+ {8:foo 1 bar}aaaaa |
+ {8:foo 2 bar}aaaaa |
+ {8:foo 3 bar}aaaaa |
+ {8:foo 4 bar}aaaaa |
+ {8:foo 5 bar}aaaaa |
+ {8:foo 6 bar}aaaaa |
+ {8:foo 7 bar}aaaaa |
+ {8:foo 8 bar}aaaaa |
+ |
+ ]])
end)
it("works with highlighted 'statuscolumn'", function()
@@ -160,36 +198,36 @@ describe('statuscolumn', function()
]])
command('set relativenumber')
screen:expect([[
- {1:4 }{8: 4│}aaaaa |
- {1:5 3}{8:│}aaaaa |
- {1:6 }{8: 2│}aaaaa |
- {1:7 1}{8:│}aaaaa |
- {1:8 }{8: 0│}^aaaaa |
- {1:9 1}{8:│}aaaaa |
- {1:10}{8: 2│}aaaaa |
- {1:11 3}{8:│}aaaaa |
- {1:12}{8: 4│}aaaaa |
- {1:13 5}{8:│}aaaaa |
- {1:14}{8: 6│}aaaaa |
- {1:15 7}{8:│}aaaaa |
- {1:16}{8: 8│}aaaaa |
+ {1:4 }{8: 4│}aaaaa |
+ {1:5 3}{8:│}aaaaa |
+ {1:6 }{8: 2│}aaaaa |
+ {1:7 1}{8:│}aaaaa |
+ {1:8 }{8: 0│}^aaaaa |
+ {1:9 1}{8:│}aaaaa |
+ {1:10 }{8: 2│}aaaaa |
+ {1:11 3}{8:│}aaaaa |
+ {1:12 }{8: 4│}aaaaa |
+ {1:13 5}{8:│}aaaaa |
+ {1:14 }{8: 6│}aaaaa |
+ {1:15 7}{8:│}aaaaa |
+ {1:16 }{8: 8│}aaaaa |
|
]])
command('set nonumber')
screen:expect([[
- {8:4│}aaaaa |
- {1:3}{8:│}aaaaa |
- {8:2│}aaaaa |
- {1:1}{8:│}aaaaa |
- {8:0│}^aaaaa |
- {1:1}{8:│}aaaaa |
- {8:2│}aaaaa |
- {1:3}{8:│}aaaaa |
- {8:4│}aaaaa |
- {1:5}{8:│}aaaaa |
- {8:6│}aaaaa |
- {1:7}{8:│}aaaaa |
- {8:8│}aaaaa |
+ {1: }{8:4│}aaaaa |
+ {1: 3}{8:│}aaaaa |
+ {1: }{8:2│}aaaaa |
+ {1: 1}{8:│}aaaaa |
+ {1: }{8:0│}^aaaaa |
+ {1: 1}{8:│}aaaaa |
+ {1: }{8:2│}aaaaa |
+ {1: 3}{8:│}aaaaa |
+ {1: }{8:4│}aaaaa |
+ {1: 5}{8:│}aaaaa |
+ {1: }{8:6│}aaaaa |
+ {1: 7}{8:│}aaaaa |
+ {1: }{8:8│}aaaaa |
|
]])
end)
@@ -305,36 +343,36 @@ describe('statuscolumn', function()
-- 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: }{6:^+-- 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 |
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 4│}{2: }{1: }aaaaaaa |
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 3│}{2: }{1: }aaaaaaa |
+ {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 2│}{2: }{1: }aaaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 1│}{2: }{1: }aaaaaaa |
+ {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 1│}{2: }{1: }aaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: 2│}{2: }{1: }aaaaaaa |
|
]])
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: }{6:^+-- 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 |
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaa |
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaa |
+ {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaa |
+ {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaa |
|
]])
-- Up to 9 signs in a line
@@ -347,75 +385,75 @@ describe('statuscolumn', function()
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: }{6:^+-- 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 |
+ {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
+ {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa |
|
]])
-- Also test fold and sign column when 'cpoptions' includes "n"
command('set cpoptions+=n')
feed('Hgjg0')
screen:expect([[
- {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{5:^aaaaaaaaaaaaaaaaaaaa }|
- {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}|
- {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
+ {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{5:^aaaaaaaaaaaaaaaaaaaaa }|
+ {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
|
]])
command('set breakindent')
command('sign unplace 2')
feed('J2gjg0')
screen:expect([[
- {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: } {5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaa}|
- {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: } {5:^aaaaaaaaaaa }|
- {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaa |
- {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}|
- {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: } aaaaaaaaaaaaaaaaaaaa |
+ {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: } {5:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}|
+ {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: } {5:^aaaaaaaaaaaaaa }|
+ {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: } aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: } aaaaaaaaaaaaaaaaaaaaa |
+ {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: } aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: } aaaaaaaaaaaaaaaaaaaaa |
|
]])
command('set nobreakindent')
feed('$g0')
screen:expect([[
- {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{5:aaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaa}|
+ {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {2: }{5:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}|
{2: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
- {2: }{5:^aaa }|
- {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaaa}|
- {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
- {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {2: }aaaaaaaaaaaaaaaaaaaa |
+ {2: }{5:^aaaa }|
+ {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}|
+ {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
+ {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {2: }aaaaaaaaaaaaaaaaaaaaa |
|
]])
command('silent undo')
@@ -427,7 +465,23 @@ describe('statuscolumn', function()
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 foldcolumn=0 signcolumn=number stc=%l')
+ screen:expect([[
+ {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1: }virt_line |
+ {1: }virt_line above |
+ {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {4: 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {1: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {1:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ |
+ ]])
command(
[[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]]
)
@@ -533,8 +587,8 @@ describe('statuscolumn', function()
command([[set stc=%6s\ %l]])
exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "𒀀"})')
screen:expect([[
- {8: 𒀀 8 }^aaaaa |
- {8: }{7: }{8: 9 }aaaaa |
+ {8: 𒀀 8}^aaaaa |
+ {8: }{7: }{8: 9}aaaaa |
|
]])
end)
@@ -598,9 +652,6 @@ describe('statuscolumn', function()
-- Check that statusline click doesn't register as statuscolumn click
api.nvim_input_mouse('right', 'press', '', 0, 12, 0)
eq('', eval('g:testvar'))
- -- Check that cmdline click doesn't register as statuscolumn click
- api.nvim_input_mouse('right', 'press', '', 0, 13, 0)
- eq('', eval('g:testvar'))
end)
it('clicks and highlights work with control characters', function()
@@ -644,26 +695,26 @@ describe('statuscolumn', function()
-- clicking an item does not drag mouse
api.nvim_input_mouse('left', 'press', '', 0, 0, 0)
screen:expect([[
- {0:8 }^aaaaa |
+ {0: 8}^aaaaa |
{1: Echo } |
]])
api.nvim_input_mouse('left', 'press', '', 0, 1, 5)
api.nvim_input_mouse('left', 'release', '', 0, 1, 5)
screen:expect([[
- {0:8 }^aaaaa |
+ {0: 8}^aaaaa |
0 1 l 8 |
]])
command('echo')
-- clicking outside to close the menu does not drag mouse
api.nvim_input_mouse('left', 'press', '', 0, 0, 0)
screen:expect([[
- {0:8 }^aaaaa |
+ {0: 8}^aaaaa |
{1: Echo } |
]])
api.nvim_input_mouse('left', 'press', '', 0, 0, 10)
api.nvim_input_mouse('left', 'release', '', 0, 0, 10)
screen:expect([[
- {0:8 }^aaaaa |
+ {0: 8}^aaaaa |
|
]])
end)
@@ -749,9 +800,9 @@ describe('statuscolumn', function()
it('works with cmdwin', function()
feed(':set stc=%l<CR>q:k$')
screen:expect([[
- {8:7 }aaaaa |
- {8:8 }aaaaa |
- {8:9 }aaaaa |
+ {8: 7}aaaaa |
+ {8: 8}aaaaa |
+ {8: 9}aaaaa |
{8:10}aaaaa |
{2:[No Name] [+] }|
{1::}{8:1}set stc=%^l |
@@ -899,16 +950,16 @@ describe('statuscolumn', function()
command([[set spell stc=%l\ ]])
command('call setline(8, "This is a line that contains ᶏ multibyte character.")')
screen:expect([[
- {8:8 }^This is a line that contains {31:ᶏ}|
+ {8: 8 }^This is a line that contains {31:ᶏ}|
{8: } {31:multibyte} character. |
- {8:9 }{31:aaaaa} |
+ {8: 9 }{31:aaaaa} |
|
]])
end)
it('line increase properly redraws buffer text with relativenumber #27709', function()
screen:try_resize(33, 4)
- command([[set rnu nuw=3 stc=%l\ ]])
+ command([[set rnu nuw=3 stc=%{v:lnum}\ ]])
command('call setline(1, range(1, 99))')
feed('Gyyp')
screen:expect([[
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index 3087a0cde1..937e709d66 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -63,6 +63,22 @@ for _, model in ipairs(mousemodels) do
eq('0 3 r', eval('g:testvar'))
api.nvim_input_mouse('right', 'press', '', 0, 6, 28)
eq('0 4 r', eval('g:testvar'))
+ api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
+ eq('0 1 x1', eval('g:testvar'))
+ api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
+ eq('0 2 x1', eval('g:testvar'))
+ api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
+ eq('0 3 x1', eval('g:testvar'))
+ api.nvim_input_mouse('x1', 'press', '', 0, 6, 17)
+ eq('0 4 x1', eval('g:testvar'))
+ api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
+ eq('0 1 x2', eval('g:testvar'))
+ api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
+ eq('0 2 x2', eval('g:testvar'))
+ api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
+ eq('0 3 x2', eval('g:testvar'))
+ api.nvim_input_mouse('x2', 'press', '', 0, 6, 28)
+ eq('0 4 x2', eval('g:testvar'))
end)
it('works with control characters and highlight', function()
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
index e86fdbe5a3..3189232957 100644
--- a/test/functional/ui/title_spec.lua
+++ b/test/functional/ui/title_spec.lua
@@ -22,7 +22,7 @@ describe('title', function()
end)
it('has correct default title with unnamed file', function()
- local expected = '[No Name] - NVIM'
+ local expected = '[No Name] - Nvim'
command('set title')
screen:expect(function()
eq(expected, screen.title)
@@ -30,7 +30,7 @@ describe('title', function()
end)
it('has correct default title with named file', function()
- local expected = (is_os('win') 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(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
screen:expect(function()
@@ -41,7 +41,7 @@ describe('title', function()
describe('is not changed by', function()
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 expected = (is_os('win') and 'myfile1 (C:\\mydir) - Nvim' or 'myfile1 (/mydir) - Nvim')
local buf2
before_each(function()
@@ -82,11 +82,11 @@ describe('title', function()
end)
end)
- it('a Lua callback calling nvim_buf_call in a hidden buffer', function()
+ it('a Lua callback calling vim._with in a hidden buffer', function()
exec_lua(string.format(
[[
vim.schedule(function()
- vim.api.nvim_buf_call(%d, function() end)
+ vim._with({buf = %d}, function() end)
end)
]],
buf2
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 0feec6bd03..4d01b7a779 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -16,30 +16,24 @@ describe("'wildmenu'", function()
before_each(function()
clear()
screen = Screen.new(25, 5)
- screen:set_default_attr_ids {
- [1] = { foreground = Screen.colors.Blue, bold = true },
- [2] = { reverse = true },
- [3] = { bold = true, reverse = true },
- [5] = { bold = true },
- [31] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow },
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
}
screen:attach()
end)
-- oldtest: Test_wildmenu_screendump()
it('works', function()
- screen:set_default_attr_ids({
- [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText
- [1] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow }, -- WildMenu
- [2] = { bold = true, reverse = true }, -- StatusLine
- })
+ screen:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
+ }
-- Test simple wildmenu
feed(':sign <Tab>')
screen:expect {
grid = [[
|
- {0:~ }|*2
- {1:define}{2: jump list > }|
+ {1:~ }|*2
+ {100:define}{3: jump list > }|
:sign define^ |
]],
}
@@ -48,8 +42,8 @@ describe("'wildmenu'", function()
screen:expect {
grid = [[
|
- {0:~ }|*2
- {2:define }{1:jump}{2: list > }|
+ {1:~ }|*2
+ {3:define }{100:jump}{3: list > }|
:sign jump^ |
]],
}
@@ -58,8 +52,8 @@ describe("'wildmenu'", function()
screen:expect {
grid = [[
|
- {0:~ }|*2
- {2:define jump }{1:list}{2: > }|
+ {1:~ }|*2
+ {3:define jump }{100:list}{3: > }|
:sign list^ |
]],
}
@@ -69,8 +63,8 @@ describe("'wildmenu'", function()
screen:expect {
grid = [[
|
- {0:~ }|*2
- {2:define jump list > }|
+ {1:~ }|*2
+ {3:define jump list > }|
:sign ^ |
]],
}
@@ -80,7 +74,7 @@ describe("'wildmenu'", function()
screen:expect {
grid = [[
|
- {0:~ }|*3
+ {1:~ }|*3
:sign ^ |
]],
}
@@ -92,8 +86,8 @@ describe("'wildmenu'", function()
screen:expect {
grid = [[
|
- {0:~ }|*2
- {1:define}{2: jump list > }|
+ {1:~ }|*2
+ {100:define}{3: jump list > }|
:sign define^ |
]],
}
@@ -104,7 +98,7 @@ describe("'wildmenu'", function()
screen:expect {
grid = [[
^ |
- {0:~ }|*3
+ {1:~ }|*3
|
]],
}
@@ -115,7 +109,7 @@ describe("'wildmenu'", function()
screen:expect([[
|
{1:~ }|*2
- {31:define}{3: jump list > }|
+ {100:define}{3: jump list > }|
:sign define^ |
]])
feed('<C-E>')
@@ -131,7 +125,7 @@ describe("'wildmenu'", function()
screen:expect([[
|
{1:~ }|*2
- {31:define}{3: jump list > }|
+ {100:define}{3: jump list > }|
:sign define^ |
]])
feed('<tab><C-Y>')
@@ -148,7 +142,7 @@ describe("'wildmenu'", function()
screen:expect([[
|
{1:~ }|*2
- {31:define}{3: jump list > }|
+ {100:define}{3: jump list > }|
:sign define^ |
]])
end)
@@ -162,7 +156,7 @@ describe("'wildmenu'", function()
screen:expect([[
|
{1:~ }|*2
- {31:define}{3: jump list > }|
+ {100:define}{3: jump list > }|
:sign define^ |
]])
feed('<space>')
@@ -188,7 +182,7 @@ describe("'wildmenu'", function()
screen:expect([[
|
{1:~ }|*2
- {31:!}{3: # & < = > @ > }|
+ {100:!}{3: # & < = > @ > }|
:!^ |
]])
end)
@@ -199,9 +193,17 @@ describe("'wildmenu'", function()
feed((':terminal "%s" REP 5000 !terminal_output!<cr>'):format(testprg('shell-test')))
feed('G') -- Follow :terminal output.
feed([[:sign <Tab>]]) -- Invoke wildmenu.
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow },
+ [101] = {
+ bold = true,
+ foreground = Screen.colors.White,
+ background = Screen.colors.DarkGreen,
+ },
+ }
-- NB: in earlier versions terminal output was redrawn during cmdline mode.
-- For now just assert that the screen remains unchanged.
- screen:expect { any = '{31:define}{3: jump list > }|\n:sign define^ |' }
+ screen:expect { any = '{100:define}{101: jump list > }|\n:sign define^ |' }
screen:expect_unchanged()
-- cmdline CTRL-D display should also be preserved.
@@ -232,7 +234,7 @@ describe("'wildmenu'", function()
grid = [[
|
{1:~ }|*2
- {31:define}{3: jump list > }|
+ {100:define}{3: jump list > }|
:sign define^ |
]],
}
@@ -259,9 +261,17 @@ describe("'wildmenu'", function()
feed([[<C-\><C-N>]])
feed([[:<Tab>]]) -- Invoke wildmenu.
+ screen:add_extra_attr_ids {
+ [100] = { foreground = Screen.colors.Black, background = Screen.colors.Yellow },
+ [101] = {
+ bold = true,
+ foreground = Screen.colors.White,
+ background = Screen.colors.DarkGreen,
+ },
+ }
-- Check only the last 2 lines, because the shell output is
-- system-dependent.
- screen:expect { any = '{31:!}{3: # & < = > @ > }|\n:!^' }
+ screen:expect { any = '{100:!}{101: # & < = > @ > }|\n:!^' }
-- Because this test verifies a _lack_ of activity, we must wait the full timeout.
-- So make it reasonable.
screen:expect_unchanged(false, 1000)
@@ -290,7 +300,7 @@ describe("'wildmenu'", function()
{3: }|
:set wildm |
wildmenu wildmode |
- {31:wildmenu}{3: wildmode }|
+ {100:wildmenu}{3: wildmode }|
:set wildmenu^ |
]])
feed('<Esc>')
@@ -416,10 +426,8 @@ describe("'wildmenu'", function()
end)
it('works with c_CTRL_Z standard mapping', function()
- 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:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
}
-- Wildcharm? where we are going we aint't no need no wildcharm.
@@ -436,7 +444,7 @@ describe("'wildmenu'", function()
grid = [[
|
{1:~ }|*2
- {2:case}{3: clear cluster > }|
+ {100:case}{3: clear cluster > }|
:syntax case^ |
]],
}
@@ -481,11 +489,9 @@ describe('command line completion', function()
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:add_extra_attr_ids {
+ [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black },
+ }
screen:attach()
end)
after_each(function()
@@ -513,7 +519,7 @@ describe('command line completion', function()
screen:expect([[
|
{1:~ }|*2
- {2:XTEST_1}{3: XTEST_2 }|
+ {100:XTEST_1}{3: XTEST_2 }|
:!echo $XTEST_1^ |
]])
end)
@@ -529,7 +535,7 @@ describe('command line completion', function()
screen:expect([[
|
{1:~ }|*2
- {2:XTEST_1AaあB}{3: XTEST_2 }|
+ {100:XTEST_1AaあB}{3: XTEST_2 }|
:!echo $XTEST_1AaあB^ |
]])
end)
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index b2865d2b4c..30d6c969ca 100644
--- a/test/functional/vimscript/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -115,7 +115,7 @@ describe('eval-API', function()
exec_lua,
[[
local cmdwin_buf = vim.api.nvim_get_current_buf()
- vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function()
+ vim._with({buf = vim.api.nvim_create_buf(false, true)}, function()
vim.api.nvim_open_term(cmdwin_buf, {})
end)
]]
diff --git a/test/functional/vimscript/changedtick_spec.lua b/test/functional/vimscript/changedtick_spec.lua
index baea53a700..ef9d6b1a69 100644
--- a/test/functional/vimscript/changedtick_spec.lua
+++ b/test/functional/vimscript/changedtick_spec.lua
@@ -38,7 +38,7 @@ describe('b:changedtick', function()
-- Somehow undo counts as two changes
eq(5, changedtick())
end)
- it('is present in b: dictionary', function()
+ it('is present in b: dict', function()
eq(2, changedtick())
command('let d = b:')
eq(2, api.nvim_get_var('d').changedtick)
@@ -168,7 +168,7 @@ describe('b:changedtick', function()
)
eq(2, changedtick())
end)
- it('does not inherit VAR_FIXED when copying dictionary over', function()
+ it('does not inherit VAR_FIXED when copying dict over', function()
eq(2, changedtick())
eq('', exec_capture('let d1 = copy(b:)|let d1.changedtick = 42'))
eq('', exec_capture('let d2 = copy(b:)|unlet d2.changedtick'))
diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua
index 5e9a803b5d..873e4f820d 100644
--- a/test/functional/vimscript/ctx_functions_spec.lua
+++ b/test/functional/vimscript/ctx_functions_spec.lua
@@ -295,7 +295,7 @@ describe('context functions', function()
eq(outofbounds, pcall_err(call, 'ctxget', 0))
end)
- it('returns context dictionary at index in context stack', function()
+ it('returns context dict at index in context stack', function()
feed('i1<cr>2<cr>3<c-[>ddddddqahjklq')
command('edit! ' .. fname1)
feed('G')
@@ -404,7 +404,7 @@ describe('context functions', function()
eq(outofbounds, pcall_err(call, 'ctxset', { dummy = 1 }, 0))
end)
- it('errors when context dictionary is invalid', function()
+ it('errors when context dict is invalid', function()
call('ctxpush')
eq(
'Vim:E474: Failed to convert list to msgpack string buffer',
@@ -412,7 +412,7 @@ describe('context functions', function()
)
end)
- it('sets context dictionary at index in context stack', function()
+ it('sets context dict at index in context stack', function()
api.nvim_set_var('one', 1)
api.nvim_set_var('Two', 2)
api.nvim_set_var('THREE', 3)
diff --git a/test/functional/vimscript/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua
index 51b1e8489a..f2cee9b83e 100644
--- a/test/functional/vimscript/fnamemodify_spec.lua
+++ b/test/functional/vimscript/fnamemodify_spec.lua
@@ -7,11 +7,10 @@ local fnamemodify = n.fn.fnamemodify
local getcwd = n.fn.getcwd
local command = n.command
local write_file = t.write_file
-local alter_slashes = n.alter_slashes
local is_os = t.is_os
local function eq_slashconvert(expected, got)
- eq(alter_slashes(expected), alter_slashes(got))
+ eq(t.fix_slashes(expected), t.fix_slashes(got))
end
describe('fnamemodify()', function()
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index 552ae6d5cc..0b774404eb 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -108,7 +108,7 @@ describe('input()', function()
{T:1}^ |
]])
end)
- it('allows unequal numeric values when using {opts} dictionary', function()
+ it('allows unequal numeric values when using {opts} dict', function()
command('echohl Test')
api.nvim_set_var('opts', { prompt = 1, default = 2, cancelreturn = 3 })
feed([[:echo input(opts)<CR>]])
@@ -164,7 +164,7 @@ describe('input()', function()
reset = true,
}
end)
- it('allows omitting everything with dictionary argument', function()
+ it('allows omitting everything with dict argument', function()
command('echohl Test')
feed([[:call input({})<CR>]])
screen:expect([[
@@ -290,7 +290,7 @@ describe('inputdialog()', function()
{T:1}^ |
]])
end)
- it('allows unequal numeric values when using {opts} dictionary', function()
+ it('allows unequal numeric values when using {opts} dict', function()
command('echohl Test')
api.nvim_set_var('opts', { prompt = 1, default = 2, cancelreturn = 3 })
feed([[:echo input(opts)<CR>]])
@@ -346,7 +346,7 @@ describe('inputdialog()', function()
reset = true,
}
end)
- it('allows omitting everything with dictionary argument', function()
+ it('allows omitting everything with dict argument', function()
command('echohl Test')
feed(':echo inputdialog({})<CR>')
screen:expect([[
diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua
index ae56e8873d..895e722e96 100644
--- a/test/functional/vimscript/json_functions_spec.lua
+++ b/test/functional/vimscript/json_functions_spec.lua
@@ -502,9 +502,9 @@ describe('json_decode() function', function()
end
it('parses strings with NUL properly', function()
- sp_decode_eq({ _TYPE = 'string', _VAL = { '\n' } }, '"\\u0000"')
- sp_decode_eq({ _TYPE = 'string', _VAL = { '\n', '\n' } }, '"\\u0000\\n\\u0000"')
- sp_decode_eq({ _TYPE = 'string', _VAL = { '\n«\n' } }, '"\\u0000\\u00AB\\u0000"')
+ sp_decode_eq('\000', '"\\u0000"')
+ sp_decode_eq('\000\n\000', '"\\u0000\\n\\u0000"')
+ sp_decode_eq('\000«\000', '"\\u0000\\u00AB\\u0000"')
end)
it('parses dictionaries with duplicate keys to special maps', function()
@@ -580,14 +580,8 @@ describe('json_decode() function', function()
end)
it('parses dictionaries with keys with NUL bytes to special maps', function()
- sp_decode_eq(
- { _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b' } }, 4 } } },
- '{"a\\u0000\\nb": 4}'
- )
- sp_decode_eq(
- { _TYPE = 'map', _VAL = { { { _TYPE = 'string', _VAL = { 'a\n', 'b', '' } }, 4 } } },
- '{"a\\u0000\\nb\\n": 4}'
- )
+ sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb', 4 } } }, '{"a\\u0000\\nb": 4}')
+ sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb\n', 4 } } }, '{"a\\u0000\\nb\\n": 4}')
sp_decode_eq({
_TYPE = 'map',
_VAL = {
@@ -595,10 +589,7 @@ describe('json_decode() function', function()
{ 'a', 1 },
{ 'c', 4 },
{ 'd', 2 },
- {
- { _TYPE = 'string', _VAL = { '\n' } },
- 4,
- },
+ { '\000', 4 },
},
}, '{"b": 3, "a": 1, "c": 4, "d": 2, "\\u0000": 4}')
end)
@@ -738,22 +729,11 @@ describe('json_encode() function', function()
eq('{"\\u0000": 1}', eval('json_encode(todump)'))
end)
- it('can dump generic mapping with BIN special key and NUL', function()
- command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n"]}')
- command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}')
- eq('{"\\u0000": 1}', eval('json_encode(todump)'))
- end)
-
it('can dump STR special mapping with NUL and NL', function()
command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}')
eq('"\\u0000\\n"', eval('json_encode(todump)'))
end)
- it('can dump BIN special mapping with NUL and NL', function()
- command('let todump = {"_TYPE": v:msgpack_types.binary, "_VAL": ["\\n", ""]}')
- eq('"\\u0000\\n"', eval('json_encode(todump)'))
- end)
-
it('cannot dump special ext mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)'))
@@ -931,7 +911,7 @@ describe('json_encode() function', function()
eq('[]', eval('json_encode(v:_null_list)'))
end)
- it('can dump NULL dictionary', function()
+ it('can dump NULL dict', function()
eq('{}', eval('json_encode(v:_null_dict)'))
end)
diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua
index 44be5b3185..b69b7dbd57 100644
--- a/test/functional/vimscript/map_functions_spec.lua
+++ b/test/functional/vimscript/map_functions_spec.lua
@@ -36,7 +36,7 @@ describe('maparg()', function()
lnum = 0,
}
- it('returns a dictionary', function()
+ it('returns a dict', function()
command('nnoremap foo bar')
eq('bar', fn.maparg('foo'))
eq(foo_bar_map_table, fn.maparg('foo', 'n', false, true))
@@ -54,7 +54,7 @@ describe('maparg()', function()
eq('', fn.maparg('not a mapping'))
end)
- it('returns an empty dictionary when no map is present and dict is requested', function()
+ it('returns an empty dict when no map is present and dict is requested', function()
eq({}, fn.maparg('not a mapping', 'n', false, true))
end)
diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua
index d59dceef31..d2011f9fec 100644
--- a/test/functional/vimscript/msgpack_functions_spec.lua
+++ b/test/functional/vimscript/msgpack_functions_spec.lua
@@ -371,13 +371,14 @@ describe('msgpack*() functions', function()
eq(1, eval('dumped ==# dumped2'))
end)
- it('can restore and dump STR string with zero byte', function()
+ it('can restore and dump STR string contents with zero byte', function()
command('let dumped = ["\\xA1\\n"]')
command('let parsed = msgpackparse(dumped)')
command('let dumped2 = msgpackdump(parsed)')
- eq({ { _TYPE = {}, _VAL = { '\n' } } }, eval('parsed'))
- eq(1, eval('parsed[0]._TYPE is v:msgpack_types.string'))
- eq(1, eval('dumped ==# dumped2'))
+ eq({ '\000' }, eval('parsed'))
+ eq(eval('v:t_blob'), eval('type(parsed[0])'))
+ -- type is not preserved: prefer BIN for binary contents
+ eq(0, eval('dumped ==# dumped2'))
end)
it('can restore and dump BIN string with NL', function()
@@ -428,26 +429,24 @@ describe('msgpackparse() function', function()
parse_eq({ true }, { '\195' })
end)
- it('restores FIXSTR as special dict', function()
- parse_eq({ { _TYPE = {}, _VAL = { 'ab' } } }, { '\162ab' })
- eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string'))
+ it('restores FIXSTR as string', function()
+ parse_eq({ 'ab' }, { '\162ab' })
end)
it('restores BIN 8 as string', function()
parse_eq({ 'ab' }, { '\196\002ab' })
end)
- it('restores FIXEXT1 as special dictionary', function()
+ it('restores FIXEXT1 as special dict', function()
parse_eq({ { _TYPE = {}, _VAL = { 0x10, { '', '' } } } }, { '\212\016', '' })
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext'))
end)
- it('restores MAP with BIN key as special dictionary', function()
- parse_eq({ { _TYPE = {}, _VAL = { { 'a', '' } } } }, { '\129\196\001a\196\n' })
- eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
+ it('restores MAP with BIN key as ordinary dict', function()
+ parse_eq({ { a = '' } }, { '\129\196\001a\196\n' })
end)
- it('restores MAP with duplicate STR keys as special dictionary', function()
+ it('restores MAP with duplicate STR keys as special dict', function()
command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
-- FIXME Internal error bug, can't use parse_eq() here
command('silent! let parsed = msgpackparse(dumped)')
@@ -455,17 +454,17 @@ describe('msgpackparse() function', function()
{
_TYPE = {},
_VAL = {
- { { _TYPE = {}, _VAL = { 'a' } }, '' },
- { { _TYPE = {}, _VAL = { 'a' } }, '' },
+ { 'a', '' },
+ { 'a', '' },
},
},
}, eval('parsed'))
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
- eq(1, eval('g:parsed[0]._VAL[0][0]._TYPE is v:msgpack_types.string'))
- eq(1, eval('g:parsed[0]._VAL[1][0]._TYPE is v:msgpack_types.string'))
+ eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[0][0])'))
+ eq(eval('v:t_string'), eval('type(g:parsed[0]._VAL[1][0])'))
end)
- it('restores MAP with MAP key as special dictionary', function()
+ it('restores MAP with MAP key as special dict', function()
parse_eq({ { _TYPE = {}, _VAL = { { {}, '' } } } }, { '\129\128\196\n' })
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
end)
@@ -511,7 +510,7 @@ describe('msgpackparse() function', function()
)
end)
- it('fails to parse a dictionary', function()
+ it('fails to parse a dict', function()
eq(
'Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse({})')
@@ -765,7 +764,7 @@ describe('msgpackdump() function', function()
)
end)
- it('fails to dump a dictionary', function()
+ it('fails to dump a dict', function()
eq('Vim(call):E686: Argument of msgpackdump() must be a List', exc_exec('call msgpackdump({})'))
end)
@@ -802,7 +801,7 @@ describe('msgpackdump() function', function()
it('can dump NULL string', function()
dump_eq({ '\196\n' }, '[$XXX_UNEXISTENT_VAR_XXX]')
- dump_eq({ '\196\n' }, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
+ dump_eq({ '\196\n' }, '[v:_null_blob]')
dump_eq({ '\160' }, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
end)
@@ -814,7 +813,7 @@ describe('msgpackdump() function', function()
eq({ '\144' }, eval('msgpackdump([v:_null_list])'))
end)
- it('can dump NULL dictionary', function()
+ it('can dump NULL dict', function()
eq({ '\128' }, eval('msgpackdump([v:_null_dict])'))
end)
end)
diff --git a/test/functional/vimscript/printf_spec.lua b/test/functional/vimscript/printf_spec.lua
index 3c66e07618..1fd5c3c9b6 100644
--- a/test/functional/vimscript/printf_spec.lua
+++ b/test/functional/vimscript/printf_spec.lua
@@ -84,10 +84,13 @@ describe('printf()', function()
end
api.nvim_del_var('__result')
end
+ check_printf('v:_null_string', true)
check_printf('v:_null_list', true)
check_printf('v:_null_dict', true)
+ check_printf('v:_null_blob', true)
check_printf('[]')
check_printf('{}')
+ check_printf('0z')
check_printf('function("tr", ["a"])')
end)
end)
diff --git a/test/functional/vimscript/string_spec.lua b/test/functional/vimscript/string_spec.lua
index 32aa04c0d0..4df9104e1e 100644
--- a/test/functional/vimscript/string_spec.lua
+++ b/test/functional/vimscript/string_spec.lua
@@ -170,9 +170,9 @@ describe('string() function', function()
)
end)
- it('does not show errors when dumping partials referencing the same dictionary', function()
+ it('does not show errors when dumping partials referencing the same dict', function()
command('let d = {}')
- -- Regression for “eval/typval_encode: Dump empty dictionary before
+ -- Regression for “eval/typval_encode: Dump empty dict before
-- checking for refcycle”, results in error.
eq(
"[function('tr', {}), function('tr', {})]",
@@ -256,7 +256,7 @@ describe('string() function', function()
end)
describe('used to represent dictionaries', function()
- it('dumps empty dictionary', function()
+ it('dumps empty dict', function()
eq('{}', eval('string({})'))
end)
@@ -267,7 +267,7 @@ describe('string() function', function()
eq("[{}, function('tr', {})]", eval('string([d, function("tr", d)])'))
end)
- it('dumps non-empty dictionary', function()
+ it('dumps non-empty dict', function()
eq("{'t''est': 1}", fn.string({ ["t'est"] = 1 }))
end)