aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
committerJosh Rahm <joshuarahm@gmail.com>2025-02-05 23:09:29 +0000
commitd5f194ce780c95821a855aca3c19426576d28ae0 (patch)
treed45f461b19f9118ad2bb1f440a7a08973ad18832 /test
parentc5d770d311841ea5230426cc4c868e8db27300a8 (diff)
parent44740e561fc93afe3ebecfd3618bda2d2abeafb0 (diff)
downloadrneovim-rahm.tar.gz
rneovim-rahm.tar.bz2
rneovim-rahm.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309HEADrahm
Diffstat (limited to 'test')
-rw-r--r--test/README.md160
-rw-r--r--test/benchmark/decor_spec.lua140
-rw-r--r--test/benchmark/text_spec.lua52
-rw-r--r--test/client/rpc_stream.lua (renamed from test/client/msgpack_rpc_stream.lua)49
-rw-r--r--test/client/session.lua58
-rw-r--r--test/client/uv_stream.lua105
-rw-r--r--test/functional/api/autocmd_spec.lua133
-rw-r--r--test/functional/api/buffer_updates_spec.lua3
-rw-r--r--test/functional/api/command_spec.lua9
-rw-r--r--test/functional/api/deprecated_spec.lua21
-rw-r--r--test/functional/api/extmark_spec.lua20
-rw-r--r--test/functional/api/highlight_spec.lua23
-rw-r--r--test/functional/api/server_requests_spec.lua16
-rw-r--r--test/functional/api/version_spec.lua18
-rw-r--r--test/functional/api/vim_spec.lua160
-rw-r--r--test/functional/api/window_spec.lua62
-rw-r--r--test/functional/autocmd/autocmd_spec.lua24
-rw-r--r--test/functional/autocmd/completedone_spec.lua2
-rw-r--r--test/functional/autocmd/dirchanged_spec.lua9
-rw-r--r--test/functional/autocmd/focus_spec.lua8
-rw-r--r--test/functional/autocmd/termxx_spec.lua4
-rw-r--r--test/functional/core/channels_spec.lua7
-rw-r--r--test/functional/core/exit_spec.lua6
-rw-r--r--test/functional/core/fileio_spec.lua13
-rw-r--r--test/functional/core/job_spec.lua84
-rw-r--r--test/functional/core/log_spec.lua2
-rw-r--r--test/functional/core/main_spec.lua117
-rw-r--r--test/functional/core/remote_spec.lua18
-rw-r--r--test/functional/core/startup_spec.lua129
-rw-r--r--test/functional/editor/completion_spec.lua69
-rw-r--r--test/functional/editor/defaults_spec.lua99
-rw-r--r--test/functional/editor/mode_normal_spec.lua8
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua43
-rw-r--r--test/functional/ex_cmds/wundo_spec.lua16
-rw-r--r--test/functional/fixtures/CMakeLists.txt3
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua15
-rw-r--r--test/functional/fixtures/printargs-test.c2
-rw-r--r--test/functional/fixtures/shell-test.c17
-rw-r--r--test/functional/fixtures/streams-test.c3
-rw-r--r--test/functional/legacy/cmdline_spec.lua70
-rw-r--r--test/functional/legacy/highlight_spec.lua2
-rw-r--r--test/functional/legacy/messages_spec.lua41
-rw-r--r--test/functional/legacy/signs_spec.lua9
-rw-r--r--test/functional/legacy/substitute_spec.lua6
-rw-r--r--test/functional/legacy/window_cmd_spec.lua4
-rw-r--r--test/functional/lua/diagnostic_spec.lua249
-rw-r--r--test/functional/lua/filetype_spec.lua14
-rw-r--r--test/functional/lua/fs_spec.lua228
-rw-r--r--test/functional/lua/func_memoize_spec.lua142
-rw-r--r--test/functional/lua/hl_spec.lua31
-rw-r--r--test/functional/lua/json_spec.lua39
-rw-r--r--test/functional/lua/loader_spec.lua18
-rw-r--r--test/functional/lua/system_spec.lua48
-rw-r--r--test/functional/lua/text_spec.lua16
-rw-r--r--test/functional/lua/thread_spec.lua20
-rw-r--r--test/functional/lua/ui_event_spec.lua177
-rw-r--r--test/functional/lua/uri_spec.lua8
-rw-r--r--test/functional/lua/vim_spec.lua13
-rw-r--r--test/functional/lua/watch_spec.lua3
-rw-r--r--test/functional/lua/with_spec.lua17
-rw-r--r--test/functional/options/defaults_spec.lua16
-rw-r--r--test/functional/options/winfixbuf_spec.lua74
-rw-r--r--test/functional/plugin/health_spec.lua12
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua54
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua61
-rw-r--r--test/functional/plugin/lsp/folding_range_spec.lua647
-rw-r--r--test/functional/plugin/lsp/handler_spec.lua42
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua10
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua2
-rw-r--r--test/functional/plugin/lsp/testutil.lua13
-rw-r--r--test/functional/plugin/lsp/utils_spec.lua62
-rw-r--r--test/functional/plugin/lsp_spec.lua419
-rw-r--r--test/functional/plugin/man_spec.lua26
-rw-r--r--test/functional/provider/clipboard_spec.lua2
-rw-r--r--test/functional/script/luacats_grammar_spec.lua4
-rw-r--r--test/functional/shada/marks_spec.lua10
-rw-r--r--test/functional/shada/shada_spec.lua18
-rw-r--r--test/functional/terminal/altscreen_spec.lua12
-rw-r--r--test/functional/terminal/api_spec.lua8
-rw-r--r--test/functional/terminal/buffer_spec.lua136
-rw-r--r--test/functional/terminal/channel_spec.lua14
-rw-r--r--test/functional/terminal/clipboard_spec.lua2
-rw-r--r--test/functional/terminal/cursor_spec.lua403
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua12
-rw-r--r--test/functional/terminal/highlight_spec.lua105
-rw-r--r--test/functional/terminal/mouse_spec.lua82
-rw-r--r--test/functional/terminal/scrollback_spec.lua44
-rw-r--r--test/functional/terminal/tui_spec.lua375
-rw-r--r--test/functional/terminal/window_spec.lua30
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua10
-rw-r--r--test/functional/testnvim.lua281
-rw-r--r--test/functional/testnvim/exec_lua.lua148
-rw-r--r--test/functional/testterm.lua12
-rw-r--r--test/functional/treesitter/fold_spec.lua76
-rw-r--r--test/functional/treesitter/highlight_spec.lua823
-rw-r--r--test/functional/treesitter/inspect_tree_spec.lua86
-rw-r--r--test/functional/treesitter/language_spec.lua4
-rw-r--r--test/functional/treesitter/node_spec.lua28
-rw-r--r--test/functional/treesitter/parser_spec.lua347
-rw-r--r--test/functional/treesitter/query_spec.lua69
-rw-r--r--test/functional/treesitter/testutil.lua25
-rw-r--r--test/functional/ui/cmdline_spec.lua122
-rw-r--r--test/functional/ui/cursor_spec.lua56
-rw-r--r--test/functional/ui/decorations_spec.lua401
-rw-r--r--test/functional/ui/diff_spec.lua20
-rw-r--r--test/functional/ui/float_spec.lua384
-rw-r--r--test/functional/ui/hlstate_spec.lua10
-rw-r--r--test/functional/ui/inccommand_user_spec.lua44
-rw-r--r--test/functional/ui/input_spec.lua4
-rw-r--r--test/functional/ui/linematch_spec.lua28
-rw-r--r--test/functional/ui/messages_spec.lua798
-rw-r--r--test/functional/ui/mode_spec.lua40
-rw-r--r--test/functional/ui/multigrid_spec.lua2
-rw-r--r--test/functional/ui/output_spec.lua4
-rw-r--r--test/functional/ui/popupmenu_spec.lua604
-rw-r--r--test/functional/ui/screen.lua58
-rw-r--r--test/functional/ui/screen_basic_spec.lua59
-rw-r--r--test/functional/ui/sign_spec.lua202
-rw-r--r--test/functional/ui/statuscolumn_spec.lua177
-rw-r--r--test/functional/ui/statusline_spec.lua505
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua33
-rw-r--r--test/functional/ui/title_spec.lua57
-rw-r--r--test/functional/vimscript/ctx_functions_spec.lua7
-rw-r--r--test/functional/vimscript/getchar_spec.lua95
-rw-r--r--test/functional/vimscript/null_spec.lua2
-rw-r--r--test/functional/vimscript/timer_spec.lua65
-rw-r--r--test/old/testdir/gen_opt_test.vim39
-rw-r--r--test/old/testdir/runnvim.vim3
-rw-r--r--test/old/testdir/runtest.vim4
-rw-r--r--test/old/testdir/setup.vim3
-rw-r--r--test/old/testdir/test_autocmd.vim28
-rw-r--r--test/old/testdir/test_bufwintabinfo.vim12
-rw-r--r--test/old/testdir/test_cmdline.vim33
-rw-r--r--test/old/testdir/test_compiler.vim637
-rw-r--r--test/old/testdir/test_debugger.vim5
-rw-r--r--test/old/testdir/test_diffmode.vim479
-rw-r--r--test/old/testdir/test_digraph.vim10
-rw-r--r--test/old/testdir/test_filetype.vim151
-rw-r--r--test/old/testdir/test_functions.vim138
-rw-r--r--test/old/testdir/test_highlight.vim4
-rw-r--r--test/old/testdir/test_indent.vim76
-rw-r--r--test/old/testdir/test_ins_complete.vim308
-rw-r--r--test/old/testdir/test_let.vim18
-rw-r--r--test/old/testdir/test_matchfuzzy.vim62
-rw-r--r--test/old/testdir/test_messages.vim47
-rw-r--r--test/old/testdir/test_normal.vim21
-rw-r--r--test/old/testdir/test_options.vim59
-rw-r--r--test/old/testdir/test_perl.vim5
-rw-r--r--test/old/testdir/test_popup.vim230
-rw-r--r--test/old/testdir/test_preview.vim59
-rw-r--r--test/old/testdir/test_python3.vim5
-rw-r--r--test/old/testdir/test_pyx3.vim5
-rw-r--r--test/old/testdir/test_ruby.vim11
-rw-r--r--test/old/testdir/test_shift.vim807
-rw-r--r--test/old/testdir/test_spell.vim12
-rw-r--r--test/old/testdir/test_stacktrace.vim142
-rw-r--r--test/old/testdir/test_statusline.vim4
-rw-r--r--test/old/testdir/test_tagjump.vim4
-rw-r--r--test/old/testdir/test_termdebug.vim6
-rw-r--r--test/old/testdir/test_user_func.vim74
-rw-r--r--test/old/testdir/test_visual.vim72
-rw-r--r--test/old/testdir/test_window_cmd.vim51
-rw-r--r--test/old/testdir/test_winfixbuf.vim18
-rw-r--r--test/testutil.lua35
-rw-r--r--test/unit/fixtures/multiqueue.c5
-rw-r--r--test/unit/fixtures/multiqueue.h4
-rw-r--r--test/unit/fixtures/posix.h6
-rw-r--r--test/unit/fixtures/vterm_test.c789
-rw-r--r--test/unit/fixtures/vterm_test.h45
-rw-r--r--test/unit/mbyte_spec.lua6
-rw-r--r--test/unit/optionstr_spec.lua4
-rw-r--r--test/unit/strings_spec.lua26
-rw-r--r--test/unit/vterm_spec.lua392
173 files changed, 13194 insertions, 3023 deletions
diff --git a/test/README.md b/test/README.md
index d1b053fca3..5b225980a2 100644
--- a/test/README.md
+++ b/test/README.md
@@ -138,6 +138,163 @@ Debugging tests
Then put `screen:snapshot_util()` anywhere in your test. See the comments in
`test/functional/ui/screen.lua` for more info.
+Debugging Lua test code
+-----------------------
+
+Debugging Lua test code is a bit involved. Get your shopping list ready, you'll
+need to install and configure:
+
+1. [nvim-dap](https://github.com/mfussenegger/nvim-dap)
+2. [local-lua-debugger-vscode](https://github.com/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation#local-lua-debugger-vscode)
+3. [nlua](https://github.com/mfussenegger/nlua)
+4. [one-small-step-for-vimkind](https://github.com/jbyuki/one-small-step-for-vimkind) (called `osv`)
+5. A `nbusted` command in `$PATH`. This command can be a copy of `busted` with
+ `exec '/usr/bin/lua5.1'"` replaced with `"exec '/usr/bin/nlua'"` (or the
+ path to your `nlua`)
+
+
+The setup roughly looks like this:
+
+```
+ ┌─────────────────────────┐
+ │ nvim used for debugging │◄────┐
+ └─────────────────────────┘ │
+ │ │
+ ▼ │
+ ┌─────────────────┐ │
+ │ local-lua-debug │ │
+ └─────────────────┘ │
+ │ │
+ ▼ │
+ ┌─────────┐ │
+ │ nbusted │ │
+ └─────────┘ │
+ │ │
+ ▼ │
+ ┌───────────┐ │
+ │ test-case │ │
+ └───────────┘ │
+ │ │
+ ▼ │
+ ┌────────────────────┐ │
+ │ nvim test-instance │ │
+ └────────────────────┘ │
+ │ ┌─────┐ │
+ └──►│ osv │─────────────────┘
+ └─────┘
+```
+
+
+With these installed you can use a configuration like this:
+
+
+```lua
+local dap = require("dap")
+
+
+local function free_port()
+ local tcp = vim.loop.new_tcp()
+ assert(tcp)
+ tcp:bind('127.0.0.1', 0)
+ local port = tcp:getsockname().port
+ tcp:shutdown()
+ tcp:close()
+ return port
+end
+
+
+local name = "nvim-test-case" -- arbitrary name
+local config = {
+ name = name,
+
+ -- value of type must match the key used in `dap.adapters["local-lua"] = ...` from step 2)
+ type = "local-lua",
+
+ request = "launch",
+ cwd = "${workspaceFolder}",
+ program = {
+ command = "nbusted",
+ },
+ args = {
+ "--ignore-lua",
+ "--lazy",
+ "--helper=test/functional/preload.lua",
+ "--lpath=build/?.lua",
+ "--lpath=?.lua",
+
+ -- path to file to debug, could be replaced with a hardcoded string
+ function()
+ return vim.api.nvim_buf_get_name(0)
+ end,
+
+ -- You can filter to specific test-case by adding:
+ -- '--filter="' .. test_case_name .. '"',
+ },
+ env = {
+ OSV_PORT = free_port
+ }
+}
+
+-- Whenever the config is used it needs to launch a second debug session that attaches to `osv`
+-- This makes it possible to step into `exec_lua` code blocks
+setmetatable(config, {
+
+ __call = function(c)
+ ---@param session dap.Session
+ dap.listeners.after.event_initialized["nvim_debug"] = function(session)
+ if session.config.name ~= name then
+ return
+ end
+ dap.listeners.after.event_initialized["nvim_debug"] = nil
+ vim.defer_fn(function()
+ dap.run({
+ name = "attach-osv",
+ type = "nlua", -- value must match the `dap.adapters` definition key for osv
+ request = "attach",
+ port = session.config.env.OSV_PORT,
+ })
+ end, 500)
+ end
+
+ return c
+ end,
+})
+
+```
+
+You can either add this configuration to your `dap.configurations.lua` list as
+described in `:help dap-configuration` or create it dynamically in a
+user-command or function and call it directly via `dap.run(config)`. The latter
+is useful if you use tree-sitter to find the test case around a cursor location
+with a query like the following and set the `--filter` property to it.
+
+```query
+(function_call
+ name: (identifier) @name (#any-of? @name "describe" "it")
+ arguments: (arguments
+ (string) @str
+ )
+)
+```
+
+Limitations:
+
+- You need to add the following boilerplate to each spec file where you want to
+ be able to stop at breakpoints within the test-case code:
+
+```
+if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
+ require("lldebugger").start()
+end
+```
+
+This is a [local-lua-debugger
+limitation](https://github.com/tomblind/local-lua-debugger-vscode?tab=readme-ov-file#busted)
+
+- You cannot step into code of files which get baked into the nvim binary like
+ the `shared.lua`.
+
+
Filtering Tests
---------------
@@ -379,3 +536,6 @@ Number; !must be defined to function properly):
- `NVIM_TEST_MAXTRACE` (U) (N): specifies maximum number of trace lines to
keep. Default is 1024.
+
+- `OSV_PORT`: (F): launches `osv` listening on the given port within nvim test
+ instances.
diff --git a/test/benchmark/decor_spec.lua b/test/benchmark/decor_spec.lua
new file mode 100644
index 0000000000..1b7e763a09
--- /dev/null
+++ b/test/benchmark/decor_spec.lua
@@ -0,0 +1,140 @@
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+local exec_lua = n.exec_lua
+
+describe('decor perf', function()
+ before_each(n.clear)
+
+ it('can handle long lines', function()
+ Screen.new(100, 101)
+
+ local result = exec_lua [==[
+ local ephemeral_pattern = {
+ { 0, 4, 'Comment', 11 },
+ { 0, 3, 'Keyword', 12 },
+ { 1, 2, 'Label', 12 },
+ { 0, 1, 'String', 21 },
+ { 1, 3, 'Function', 21 },
+ { 2, 10, 'Label', 8 },
+ }
+
+ local regular_pattern = {
+ { 4, 5, 'String', 12 },
+ { 1, 4, 'Function', 2 },
+ }
+
+ for _, list in ipairs({ ephemeral_pattern, regular_pattern }) do
+ for _, p in ipairs(list) do
+ p[3] = vim.api.nvim_get_hl_id_by_name(p[3])
+ end
+ end
+
+ local text = ('abcdefghijklmnopqrstuvwxyz0123'):rep(333)
+ local line_len = #text
+ vim.api.nvim_buf_set_lines(0, 0, 0, false, { text })
+
+ local ns = vim.api.nvim_create_namespace('decor_spec.lua')
+ vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+
+ local ps, pe
+ local function add_pattern(pattern, ephemeral)
+ ps = vim.uv.hrtime()
+ local i = 0
+ while i < line_len - 10 do
+ for _, p in ipairs(pattern) do
+ vim.api.nvim_buf_set_extmark(0, ns, 0, i + p[1], {
+ end_row = 0,
+ end_col = i + p[2],
+ hl_group = p[3],
+ priority = p[4],
+ ephemeral = ephemeral,
+ })
+ end
+ i = i + 5
+ end
+ pe = vim.uv.hrtime()
+ end
+
+ vim.api.nvim_set_decoration_provider(ns, {
+ on_win = function()
+ return true
+ end,
+ on_line = function()
+ add_pattern(ephemeral_pattern, true)
+ end,
+ })
+
+ add_pattern(regular_pattern, false)
+
+ local total = {}
+ local provider = {}
+ for i = 1, 100 do
+ local tic = vim.uv.hrtime()
+ vim.cmd'redraw!'
+ local toc = vim.uv.hrtime()
+ table.insert(total, toc - tic)
+ table.insert(provider, pe - ps)
+ end
+
+ return { total, provider }
+ ]==]
+
+ local total, provider = unpack(result)
+ table.sort(total)
+ table.sort(provider)
+
+ local ms = 1 / 1000000
+ local function fmt(stats)
+ return string.format(
+ 'min, 25%%, median, 75%%, max:\n\t%0.1fms,\t%0.1fms,\t%0.1fms,\t%0.1fms,\t%0.1fms',
+ stats[1] * ms,
+ stats[1 + math.floor(#stats * 0.25)] * ms,
+ stats[1 + math.floor(#stats * 0.5)] * ms,
+ stats[1 + math.floor(#stats * 0.75)] * ms,
+ stats[#stats] * ms
+ )
+ end
+
+ print('\nTotal ' .. fmt(total) .. '\nDecoration provider: ' .. fmt(provider))
+ end)
+
+ it('can handle full screen of highlighting', function()
+ Screen.new(100, 51)
+
+ local result = exec_lua(function()
+ local long_line = 'local a={' .. ('a=5,'):rep(22) .. '}'
+ local lines = {}
+ for _ = 1, 50 do
+ table.insert(lines, long_line)
+ end
+ vim.api.nvim_buf_set_lines(0, 0, 0, false, lines)
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+ vim.treesitter.start(0, 'lua')
+
+ local total = {}
+ for _ = 1, 100 do
+ local tic = vim.uv.hrtime()
+ vim.cmd 'redraw!'
+ local toc = vim.uv.hrtime()
+ table.insert(total, toc - tic)
+ end
+
+ return { total }
+ end)
+
+ local total = unpack(result)
+ table.sort(total)
+
+ local ms = 1 / 1000000
+ local res = string.format(
+ 'min, 25%%, median, 75%%, max:\n\t%0.1fms,\t%0.1fms,\t%0.1fms,\t%0.1fms,\t%0.1fms',
+ total[1] * ms,
+ total[1 + math.floor(#total * 0.25)] * ms,
+ total[1 + math.floor(#total * 0.5)] * ms,
+ total[1 + math.floor(#total * 0.75)] * ms,
+ total[#total] * ms
+ )
+ print('\nTotal ' .. res)
+ end)
+end)
diff --git a/test/benchmark/text_spec.lua b/test/benchmark/text_spec.lua
new file mode 100644
index 0000000000..9cfeaf765b
--- /dev/null
+++ b/test/benchmark/text_spec.lua
@@ -0,0 +1,52 @@
+describe('vim.text', function()
+ --- @param t number[]
+ local function mean(t)
+ assert(#t > 0)
+ local sum = 0
+ for _, v in ipairs(t) do
+ sum = sum + v
+ end
+ return sum / #t
+ end
+
+ --- @param t number[]
+ local function median(t)
+ local len = #t
+ if len % 2 == 0 then
+ return t[len / 2]
+ end
+ return t[(len + 1) / 2]
+ end
+
+ --- @param f fun(t: number[]): table<number, number|string|table>
+ local function measure(f, input, N)
+ local stats = {} ---@type number[]
+ for _ = 1, N do
+ local tic = vim.uv.hrtime()
+ f(input)
+ local toc = vim.uv.hrtime()
+ stats[#stats + 1] = (toc - tic) / 1000000
+ end
+ table.sort(stats)
+ print(
+ string.format(
+ '\nN: %d, Min: %0.6f ms, Max: %0.6f ms, Median: %0.6f ms, Mean: %0.6f ms',
+ N,
+ math.min(unpack(stats)),
+ math.max(unpack(stats)),
+ median(stats),
+ mean(stats)
+ )
+ )
+ end
+
+ local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16)
+
+ it('hexencode', function()
+ measure(vim.text.hexencode, input, 100)
+ end)
+
+ it('hexdecode', function()
+ measure(vim.text.hexdecode, output, 100)
+ end)
+end)
diff --git a/test/client/msgpack_rpc_stream.lua b/test/client/rpc_stream.lua
index 7131940a58..9f2672bcf9 100644
--- a/test/client/msgpack_rpc_stream.lua
+++ b/test/client/rpc_stream.lua
@@ -1,34 +1,41 @@
+---
+--- Reading/writing of msgpack over any of the stream types from `uv_stream.lua`.
+--- Does not implement the RPC protocol, see `session.lua` for that.
+---
+
local mpack = vim.mpack
local Response = {}
Response.__index = Response
-function Response.new(msgpack_rpc_stream, request_id)
+function Response.new(rpc_stream, request_id)
return setmetatable({
- _msgpack_rpc_stream = msgpack_rpc_stream,
+ _rpc_stream = rpc_stream,
_request_id = request_id,
}, Response)
end
function Response:send(value, is_error)
- local data = self._msgpack_rpc_stream._session:reply(self._request_id)
+ local data = self._rpc_stream._session:reply(self._request_id)
if is_error then
- data = data .. self._msgpack_rpc_stream._pack(value)
- data = data .. self._msgpack_rpc_stream._pack(mpack.NIL)
+ data = data .. self._rpc_stream._pack(value)
+ data = data .. self._rpc_stream._pack(mpack.NIL)
else
- data = data .. self._msgpack_rpc_stream._pack(mpack.NIL)
- data = data .. self._msgpack_rpc_stream._pack(value)
+ data = data .. self._rpc_stream._pack(mpack.NIL)
+ data = data .. self._rpc_stream._pack(value)
end
- self._msgpack_rpc_stream._stream:write(data)
+ self._rpc_stream._stream:write(data)
end
---- @class test.MsgpackRpcStream
+--- Nvim msgpack RPC stream.
+---
+--- @class test.RpcStream
--- @field private _stream test.Stream
--- @field private __pack table
-local MsgpackRpcStream = {}
-MsgpackRpcStream.__index = MsgpackRpcStream
+local RpcStream = {}
+RpcStream.__index = RpcStream
-function MsgpackRpcStream.new(stream)
+function RpcStream.new(stream)
return setmetatable({
_stream = stream,
_pack = mpack.Packer(),
@@ -50,10 +57,10 @@ function MsgpackRpcStream.new(stream)
},
}),
}),
- }, MsgpackRpcStream)
+ }, RpcStream)
end
-function MsgpackRpcStream:write(method, args, response_cb)
+function RpcStream:write(method, args, response_cb)
local data
if response_cb then
assert(type(response_cb) == 'function')
@@ -66,10 +73,10 @@ function MsgpackRpcStream:write(method, args, response_cb)
self._stream:write(data)
end
-function MsgpackRpcStream:read_start(request_cb, notification_cb, eof_cb)
+function RpcStream:read_start(on_request, on_notification, on_eof)
self._stream:read_start(function(data)
if not data then
- return eof_cb()
+ return on_eof()
end
local type, id_or_cb, method_or_error, args_or_result
local pos = 1
@@ -78,9 +85,9 @@ function MsgpackRpcStream:read_start(request_cb, notification_cb, eof_cb)
type, id_or_cb, method_or_error, args_or_result, pos = self._session:receive(data, pos)
if type == 'request' or type == 'notification' then
if type == 'request' then
- request_cb(method_or_error, args_or_result, Response.new(self, id_or_cb))
+ on_request(method_or_error, args_or_result, Response.new(self, id_or_cb))
else
- notification_cb(method_or_error, args_or_result)
+ on_notification(method_or_error, args_or_result)
end
elseif type == 'response' then
if method_or_error == mpack.NIL then
@@ -94,12 +101,12 @@ function MsgpackRpcStream:read_start(request_cb, notification_cb, eof_cb)
end)
end
-function MsgpackRpcStream:read_stop()
+function RpcStream:read_stop()
self._stream:read_stop()
end
-function MsgpackRpcStream:close(signal)
+function RpcStream:close(signal)
self._stream:close(signal)
end
-return MsgpackRpcStream
+return RpcStream
diff --git a/test/client/session.lua b/test/client/session.lua
index f1f46c5efe..a5839e012a 100644
--- a/test/client/session.lua
+++ b/test/client/session.lua
@@ -1,12 +1,18 @@
+---
+--- Nvim msgpack-RPC protocol session. Manages requests/notifications/responses.
+---
+
local uv = vim.uv
-local MsgpackRpcStream = require('test.client.msgpack_rpc_stream')
+local RpcStream = require('test.client.rpc_stream')
+--- Nvim msgpack-RPC protocol session. Manages requests/notifications/responses.
+---
--- @class test.Session
---- @field private _pending_messages string[]
---- @field private _msgpack_rpc_stream test.MsgpackRpcStream
+--- @field private _pending_messages string[] Requests/notifications received from the remote end.
+--- @field private _rpc_stream test.RpcStream
--- @field private _prepare uv.uv_prepare_t
--- @field private _timer uv.uv_timer_t
---- @field private _is_running boolean
+--- @field private _is_running boolean true during `Session:run()` scope.
--- @field exec_lua_setup boolean
local Session = {}
Session.__index = Session
@@ -51,9 +57,10 @@ local function coroutine_exec(func, ...)
end))
end
+--- Creates a new msgpack-RPC session.
function Session.new(stream)
return setmetatable({
- _msgpack_rpc_stream = MsgpackRpcStream.new(stream),
+ _rpc_stream = RpcStream.new(stream),
_pending_messages = {},
_prepare = uv.new_prepare(),
_timer = uv.new_timer(),
@@ -91,10 +98,13 @@ function Session:next_message(timeout)
return table.remove(self._pending_messages, 1)
end
+--- Sends a notification to the RPC endpoint.
function Session:notify(method, ...)
- self._msgpack_rpc_stream:write(method, { ... })
+ self._rpc_stream:write(method, { ... })
end
+--- Sends a request to the RPC endpoint.
+---
--- @param method string
--- @param ... any
--- @return boolean, table
@@ -114,8 +124,16 @@ function Session:request(method, ...)
return true, result
end
---- Runs the event loop.
+--- Processes incoming RPC requests/notifications until exhausted.
+---
+--- TODO(justinmk): luaclient2 avoids this via uvutil.cb_wait() + uvutil.add_idle_call()?
+---
+--- @param request_cb function Handles requests from the sever to the local end.
+--- @param notification_cb function Handles notifications from the sever to the local end.
+--- @param setup_cb function
+--- @param timeout number
function Session:run(request_cb, notification_cb, setup_cb, timeout)
+ --- Handles an incoming request.
local function on_request(method, args, response)
coroutine_exec(request_cb, method, args, function(status, result, flag)
if status then
@@ -126,6 +144,7 @@ function Session:run(request_cb, notification_cb, setup_cb, timeout)
end)
end
+ --- Handles an incoming notification.
local function on_notification(method, args)
coroutine_exec(notification_cb, method, args)
end
@@ -160,39 +179,45 @@ function Session:close(signal)
if not self._prepare:is_closing() then
self._prepare:close()
end
- self._msgpack_rpc_stream:close(signal)
+ self._rpc_stream:close(signal)
self.closed = true
end
+--- Sends a request to the RPC endpoint, without blocking (schedules a coroutine).
function Session:_yielding_request(method, args)
return coroutine.yield(function(co)
- self._msgpack_rpc_stream:write(method, args, function(err, result)
+ self._rpc_stream:write(method, args, function(err, result)
resume(co, err, result)
end)
end)
end
+--- Sends a request to the RPC endpoint, and blocks (polls event loop) until a response is received.
function Session:_blocking_request(method, args)
local err, result
+ -- Invoked when a request is received from the remote end.
local function on_request(method_, args_, response)
table.insert(self._pending_messages, { 'request', method_, args_, response })
end
+ -- Invoked when a notification is received from the remote end.
local function on_notification(method_, args_)
table.insert(self._pending_messages, { 'notification', method_, args_ })
end
- self._msgpack_rpc_stream:write(method, args, function(e, r)
+ self._rpc_stream:write(method, args, function(e, r)
err = e
result = r
uv.stop()
end)
+ -- Poll for incoming requests/notifications received from the remote end.
self:_run(on_request, on_notification)
return (err or self.eof_err), result
end
+--- Polls for incoming requests/notifications received from the remote end.
function Session:_run(request_cb, notification_cb, timeout)
if type(timeout) == 'number' then
self._prepare:start(function()
@@ -202,14 +227,21 @@ function Session:_run(request_cb, notification_cb, timeout)
self._prepare:stop()
end)
end
- self._msgpack_rpc_stream:read_start(request_cb, notification_cb, function()
+ self._rpc_stream:read_start(request_cb, notification_cb, function()
uv.stop()
- self.eof_err = { 1, 'EOF was received from Nvim. Likely the Nvim process crashed.' }
+
+ --- @diagnostic disable-next-line: invisible
+ local stderr = self._rpc_stream._stream.stderr --[[@as string?]]
+ -- See if `ProcStream.stderr` has anything useful.
+ stderr = '' ~= ((stderr or ''):match('^%s*(.*%S)') or '') and ' stderr:\n' .. stderr or ''
+
+ self.eof_err = { 1, 'EOF was received from Nvim. Likely the Nvim process crashed.' .. stderr }
end)
uv.run()
self._prepare:stop()
self._timer:stop()
- self._msgpack_rpc_stream:read_stop()
+ self._rpc_stream:read_stop()
end
+--- Nvim msgpack-RPC session.
return Session
diff --git a/test/client/uv_stream.lua b/test/client/uv_stream.lua
index adf002ba1e..6e1a6995be 100644
--- a/test/client/uv_stream.lua
+++ b/test/client/uv_stream.lua
@@ -1,3 +1,8 @@
+---
+--- Basic stream types.
+--- See `rpc_stream.lua` for the msgpack layer.
+---
+
local uv = vim.uv
--- @class test.Stream
@@ -6,6 +11,8 @@ local uv = vim.uv
--- @field read_stop fun(self)
--- @field close fun(self, signal?: string)
+--- Stream over given pipes.
+---
--- @class vim.StdioStream : test.Stream
--- @field private _in uv.uv_pipe_t
--- @field private _out uv.uv_pipe_t
@@ -45,6 +52,8 @@ function StdioStream:close()
self._out:close()
end
+--- Stream over a named pipe or TCP socket.
+---
--- @class test.SocketStream : test.Stream
--- @field package _stream_error? string
--- @field package _socket uv.uv_pipe_t
@@ -109,26 +118,54 @@ function SocketStream:close()
uv.close(self._socket)
end
---- @class test.ChildProcessStream : test.Stream
+--- Stream over child process stdio.
+---
+--- @class test.ProcStream : test.Stream
--- @field private _proc uv.uv_process_t
--- @field private _pid integer
--- @field private _child_stdin uv.uv_pipe_t
--- @field private _child_stdout uv.uv_pipe_t
+--- @field private _child_stderr uv.uv_pipe_t
+--- Collects stdout (if `collect_text=true`). Treats data as text (CRLF converted to LF).
+--- @field stdout string
+--- Collects stderr as raw data.
+--- @field stderr string
+--- Gets stderr+stdout as text (CRLF converted to LF).
+--- @field output fun(): string
+--- @field stdout_eof boolean
+--- @field stderr_eof boolean
+--- Collects text into the `stdout` field.
+--- @field collect_text boolean
+--- Exit code
--- @field status integer
--- @field signal integer
-local ChildProcessStream = {}
-ChildProcessStream.__index = ChildProcessStream
+local ProcStream = {}
+ProcStream.__index = ProcStream
+--- Starts child process specified by `argv`.
+---
--- @param argv string[]
--- @param env string[]?
--- @param io_extra uv.uv_pipe_t?
---- @return test.ChildProcessStream
-function ChildProcessStream.spawn(argv, env, io_extra)
+--- @return test.ProcStream
+function ProcStream.spawn(argv, env, io_extra)
local self = setmetatable({
- _child_stdin = uv.new_pipe(false),
- _child_stdout = uv.new_pipe(false),
+ collect_text = false,
+ output = function(self)
+ if not self.collect_text then
+ error('set collect_text=true')
+ end
+ return (self.stderr .. self.stdout):gsub('\r\n', '\n')
+ end,
+ stdout = '',
+ stderr = '',
+ stdout_eof = false,
+ stderr_eof = false,
+ _child_stdin = assert(uv.new_pipe(false)),
+ _child_stdout = assert(uv.new_pipe(false)),
+ _child_stderr = assert(uv.new_pipe(false)),
_exiting = false,
- }, ChildProcessStream)
+ }, ProcStream)
local prog = argv[1]
local args = {} --- @type string[]
for i = 2, #argv do
@@ -136,13 +173,14 @@ function ChildProcessStream.spawn(argv, env, io_extra)
end
--- @diagnostic disable-next-line:missing-fields
self._proc, self._pid = uv.spawn(prog, {
- stdio = { self._child_stdin, self._child_stdout, 1, io_extra },
+ stdio = { self._child_stdin, self._child_stdout, self._child_stderr, io_extra },
args = args,
--- @diagnostic disable-next-line:assign-type-mismatch
env = env,
}, function(status, signal)
- self.status = status
self.signal = signal
+ -- "Abort" exit may not set status; force to nonzero in that case.
+ self.status = (0 ~= (status or 0) or 0 == (signal or 0)) and status or (128 + (signal or 0))
end)
if not self._proc then
@@ -153,24 +191,54 @@ function ChildProcessStream.spawn(argv, env, io_extra)
return self
end
-function ChildProcessStream:write(data)
+function ProcStream:write(data)
self._child_stdin:write(data)
end
-function ChildProcessStream:read_start(cb)
- self._child_stdout:read_start(function(err, chunk)
- if err then
- error(err)
+function ProcStream:on_read(stream, cb, err, chunk)
+ if err then
+ error(err) -- stream read failed?
+ elseif chunk then
+ -- Always collect stderr, in case it gives useful info on failure.
+ if stream == 'stderr' then
+ self.stderr = self.stderr .. chunk --[[@as string]]
+ elseif stream == 'stdout' and self.collect_text then
+ -- Set `stdout` and convert CRLF => LF.
+ self.stdout = (self.stdout .. chunk):gsub('\r\n', '\n')
end
+ else
+ -- stderr_eof/stdout_eof
+ self[stream .. '_eof'] = true ---@type boolean
+ end
+
+ -- Handler provided by the caller.
+ if cb then
cb(chunk)
+ end
+end
+
+--- Collects output until the process exits.
+function ProcStream:wait()
+ while not (self.stdout_eof and self.stderr_eof and (self.status or self.signal)) do
+ uv.run('once')
+ end
+end
+
+function ProcStream:read_start(on_stdout, on_stderr)
+ self._child_stdout:read_start(function(err, chunk)
+ self:on_read('stdout', on_stdout, err, chunk)
+ end)
+ self._child_stderr:read_start(function(err, chunk)
+ self:on_read('stderr', on_stderr, err, chunk)
end)
end
-function ChildProcessStream:read_stop()
+function ProcStream:read_stop()
self._child_stdout:read_stop()
+ self._child_stderr:read_stop()
end
-function ChildProcessStream:close(signal)
+function ProcStream:close(signal)
if self._closed then
return
end
@@ -178,6 +246,7 @@ function ChildProcessStream:close(signal)
self:read_stop()
self._child_stdin:close()
self._child_stdout:close()
+ self._child_stderr:close()
if type(signal) == 'string' then
self._proc:kill('sig' .. signal)
end
@@ -189,6 +258,6 @@ end
return {
StdioStream = StdioStream,
- ChildProcessStream = ChildProcessStream,
+ ProcStream = ProcStream,
SocketStream = SocketStream,
}
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index 3f9883f43f..64b28e7bf7 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -273,54 +273,72 @@ describe('autocmd api', function()
eq({}, api.nvim_get_autocmds({ event = 'User', pattern = 'Test' }))
end)
- it('receives an args table', function()
+ local function test_autocmd_args(event)
+ local function get_amatch(pat)
+ return event == 'User' and pat or vim.fs.normalize(n.fn.fnamemodify(pat, ':p'))
+ end
+
local group_id = api.nvim_create_augroup('TestGroup', {})
-- Having an existing autocmd calling expand("<afile>") shouldn't change args #18964
- api.nvim_create_autocmd('User', {
+ api.nvim_create_autocmd(event, {
group = 'TestGroup',
pattern = 'Te*',
command = 'call expand("<afile>")',
})
- local autocmd_id = exec_lua [[
- return vim.api.nvim_create_autocmd("User", {
+ local autocmd_id = exec_lua(([[
+ return vim.api.nvim_create_autocmd(%q, {
group = "TestGroup",
pattern = "Te*",
callback = function(args)
vim.g.autocmd_args = args
end,
})
- ]]
+ ]]):format(event))
- api.nvim_exec_autocmds('User', { pattern = 'Test pattern' })
+ local exec_pat = 'Test pattern'
+ local amatch = get_amatch(exec_pat)
+ api.nvim_exec_autocmds(event, { pattern = exec_pat })
eq({
id = autocmd_id,
group = group_id,
- event = 'User',
- match = 'Test pattern',
- file = 'Test pattern',
+ event = event,
+ match = amatch,
+ file = exec_pat,
buf = 1,
}, api.nvim_get_var('autocmd_args'))
-- Test without a group
- autocmd_id = exec_lua [[
- return vim.api.nvim_create_autocmd("User", {
+ autocmd_id = exec_lua(([[
+ return vim.api.nvim_create_autocmd(%q, {
pattern = "*",
callback = function(args)
vim.g.autocmd_args = args
end,
})
- ]]
+ ]]):format(event))
- api.nvim_exec_autocmds('User', { pattern = 'some_pat' })
+ exec_pat = 'some_pat'
+ amatch = get_amatch(exec_pat)
+ api.nvim_exec_autocmds(event, { pattern = exec_pat })
eq({
id = autocmd_id,
group = nil,
- event = 'User',
- match = 'some_pat',
- file = 'some_pat',
+ event = event,
+ match = amatch,
+ file = exec_pat,
buf = 1,
}, api.nvim_get_var('autocmd_args'))
+ end
+
+ describe('receives correct args table', function()
+ it('for event that takes non-file pattern', function()
+ test_autocmd_args('User')
+ end)
+
+ it('for event that takes file pattern', function()
+ test_autocmd_args('BufEnter')
+ end)
end)
it('can receive arbitrary data', function()
@@ -881,6 +899,89 @@ describe('autocmd api', function()
eq([[:echo "Buffer"]], normalized_aus[1].command)
end)
end)
+
+ describe('id', function()
+ it('gets events by ID', function()
+ local id = api.nvim_create_autocmd('BufEnter', {
+ command = 'echo "hello"',
+ })
+ eq({
+ {
+ buflocal = false,
+ command = 'echo "hello"',
+ event = 'BufEnter',
+ id = id,
+ once = false,
+ pattern = '*',
+ },
+ }, api.nvim_get_autocmds({ id = id }))
+ end)
+
+ it('gets events by ID by other filters', function()
+ local group_name = 'NVIM_GET_AUTOCMDS_ID'
+ local group = api.nvim_create_augroup(group_name, { clear = true })
+ local id = api.nvim_create_autocmd('BufEnter', {
+ command = 'set number',
+ group = group,
+ })
+ api.nvim_create_autocmd('WinEnter', {
+ group = group,
+ command = 'set cot&',
+ })
+ eq({
+ {
+ buflocal = false,
+ command = 'set number',
+ event = 'BufEnter',
+ group = group,
+ group_name = group_name,
+ id = id,
+ once = false,
+ pattern = '*',
+ },
+ }, api.nvim_get_autocmds({ id = id, group = group }))
+ end)
+
+ it('gets events by ID and a specific event', function()
+ local id = api.nvim_create_autocmd('InsertEnter', { command = 'set number' })
+ api.nvim_create_autocmd('InsertEnter', { command = 'set wrap' })
+ eq({
+ {
+ buflocal = false,
+ command = 'set number',
+ event = 'InsertEnter',
+ id = id,
+ once = false,
+ pattern = '*',
+ },
+ }, api.nvim_get_autocmds({ id = id, event = 'InsertEnter' }))
+ end)
+
+ it('gets events by ID and a specific pattern', function()
+ local id = api.nvim_create_autocmd('InsertEnter', {
+ pattern = '*.c',
+ command = 'set number',
+ })
+ api.nvim_create_autocmd('InsertEnter', {
+ pattern = '*.c',
+ command = 'set wrap',
+ })
+ eq({
+ {
+ buflocal = false,
+ command = 'set number',
+ event = 'InsertEnter',
+ id = id,
+ once = false,
+ pattern = '*.c',
+ },
+ }, api.nvim_get_autocmds({ id = id, pattern = '*.c' }))
+ end)
+
+ it('empty result when id does not found', function()
+ eq({}, api.nvim_get_autocmds({ id = 255 }))
+ end)
+ end)
end)
describe('nvim_exec_autocmds', function()
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index 527394bfd1..489f601d31 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -879,7 +879,8 @@ describe('API: buffer events:', function()
it('when :terminal lines change', function()
local buffer_lines = {}
local expected_lines = {}
- fn.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '-n', '-c', 'set shortmess+=A' }, {
+ fn.jobstart({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '-n', '-c', 'set shortmess+=A' }, {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index a16c6a88e3..fabd9be6d6 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -651,6 +651,11 @@ describe('nvim_create_user_command', function()
api.nvim_set_current_buf(bufnr)
command('Hello')
assert_alive()
+ eq(
+ 'Invalid buffer id: 1234',
+ pcall_err(api.nvim_buf_create_user_command, 1234, 'Hello', '', {})
+ )
+ assert_alive()
end)
it('can use a Lua complete function', function()
@@ -771,5 +776,9 @@ describe('nvim_del_user_command', function()
command('Hello')
api.nvim_buf_del_user_command(0, 'Hello')
matches('Not an editor command: Hello', pcall_err(command, 'Hello'))
+ eq('Invalid command (not found): Hello', pcall_err(api.nvim_buf_del_user_command, 0, 'Hello'))
+ eq('Invalid command (not found): Bye', pcall_err(api.nvim_buf_del_user_command, 0, 'Bye'))
+ eq('Invalid buffer id: 1234', pcall_err(api.nvim_buf_del_user_command, 1234, 'Hello'))
+ assert_alive()
end)
end)
diff --git a/test/functional/api/deprecated_spec.lua b/test/functional/api/deprecated_spec.lua
new file mode 100644
index 0000000000..2efcfda873
--- /dev/null
+++ b/test/functional/api/deprecated_spec.lua
@@ -0,0 +1,21 @@
+-- Island of misfit toys.
+--- @diagnostic disable: deprecated
+
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+
+describe('deprecated', function()
+ before_each(n.clear)
+
+ describe('nvim_notify', function()
+ it('can notify a info message', function()
+ n.api.nvim_notify('hello world', 2, {})
+ end)
+
+ it('can be overridden', function()
+ n.command('lua vim.notify = function(...) return 42 end')
+ t.eq(42, n.api.nvim_exec_lua("return vim.notify('Hello world')", {}))
+ n.api.nvim_notify('hello world', 4, {})
+ end)
+ end)
+end)
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 43be0c0e43..8a4aea1efe 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -249,7 +249,7 @@ describe('API/extmarks', function()
set_extmark(ns, 2, 1, 0, { right_gravity = false })
eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
feed('u')
- eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
+ eq({ { 1, 0, 0 }, { 2, 0, 0 } }, get_extmarks(ns, { 0, 0 }, { -1, -1 }))
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
@@ -1731,7 +1731,7 @@ describe('API/extmarks', function()
-- mark with invalidate is removed
command('d2')
screen:expect([[
- S2^aaa bbb ccc |
+ {7:S2}^aaa bbb ccc |
{7: }aaa bbb ccc |*3
{7: } |
|
@@ -1739,9 +1739,9 @@ describe('API/extmarks', function()
-- mark is restored with undo_restore == true
command('silent undo')
screen:expect([[
- S1{7: }^aaa bbb ccc |
- S2S1aaa bbb ccc |
- S2{7: }aaa bbb ccc |
+ {7:S1 }^aaa bbb ccc |
+ {7:S2S1}aaa bbb ccc |
+ {7:S2 }aaa bbb ccc |
{7: }aaa bbb ccc |*2
|
]])
@@ -1794,6 +1794,16 @@ describe('API/extmarks', function()
eq({}, get_extmark_by_id(ns, 4, {}))
end)
+ it('no crash checking invalidated flag of sign pair end key #31856', function()
+ api.nvim_buf_set_lines(0, 0, 1, false, { '', '' })
+ api.nvim_set_option_value('signcolumn', 'auto:2', {})
+ set_extmark(ns, 1, 0, 0, { sign_text = 'S1', invalidate = true, end_row = 0 })
+ set_extmark(ns, 2, 1, 0, { sign_text = 'S2', end_row = 1 })
+ command('d')
+ api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ n.assert_alive()
+ end)
+
it('can set a URL', function()
local url1 = 'https://example.com'
local url2 = 'http://127.0.0.1'
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index dd0611f184..8f98ae3650 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -309,6 +309,15 @@ describe('API: set highlight', function()
eq({ underdotted = true }, api.nvim_get_hl_by_name('Test_hl', true))
end)
+ it('can set all underline cterm attributes #31385', function()
+ local ns = get_ns()
+ local attrs = { 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed' }
+ for _, attr in ipairs(attrs) do
+ api.nvim_set_hl(ns, 'Test_' .. attr, { cterm = { [attr] = true } })
+ eq({ [attr] = true }, api.nvim_get_hl_by_name('Test_' .. attr, false))
+ end
+ end)
+
it('can set a highlight in the global namespace', function()
api.nvim_set_hl(0, 'Test_hl', highlight2_config)
eq(
@@ -710,4 +719,18 @@ describe('API: set/get highlight namespace', function()
api.nvim_win_set_hl_ns(0, ns)
eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
end)
+
+ it('setting namespace takes priority over &winhighlight', function()
+ command('set winhighlight=Visual:Search')
+ n.insert('foobar')
+ local ns = api.nvim_create_namespace('')
+ api.nvim_win_set_hl_ns(0, ns)
+ eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
+ command('enew') -- switching buffer keeps namespace #30904
+ eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
+ command('set winhighlight=')
+ eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
+ command('set winhighlight=Visual:Search')
+ eq(ns, api.nvim_get_hl_ns({ winid = 0 }))
+ end)
end)
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index bdd340f6c6..c022ba28de 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -9,7 +9,6 @@ local nvim_prog, command, fn = n.nvim_prog, n.command, n.fn
local source, next_msg = n.source, n.next_msg
local ok = t.ok
local api = n.api
-local spawn, merge_args = n.spawn, n.merge_args
local set_session = n.set_session
local pcall_err = t.pcall_err
local assert_alive = n.assert_alive
@@ -281,10 +280,9 @@ describe('server -> client', function()
end)
describe('connecting to another (peer) nvim', function()
- local nvim_argv = merge_args(n.nvim_argv, { '--headless' })
local function connect_test(server, mode, address)
local serverpid = fn.getpid()
- local client = spawn(nvim_argv, false, nil, true)
+ local client = n.new_session(true)
set_session(client)
local clientpid = fn.getpid()
@@ -312,7 +310,7 @@ describe('server -> client', function()
end
it('via named pipe', function()
- local server = spawn(nvim_argv)
+ local server = n.new_session(false)
set_session(server)
local address = fn.serverlist()[1]
local first = string.sub(address, 1, 1)
@@ -321,7 +319,7 @@ describe('server -> client', function()
end)
it('via ipv4 address', function()
- local server = spawn(nvim_argv)
+ local server = n.new_session(false)
set_session(server)
local status, address = pcall(fn.serverstart, '127.0.0.1:')
if not status then
@@ -332,7 +330,7 @@ describe('server -> client', function()
end)
it('via ipv6 address', function()
- local server = spawn(nvim_argv)
+ local server = n.new_session(false)
set_session(server)
local status, address = pcall(fn.serverstart, '::1:')
if not status then
@@ -343,7 +341,7 @@ describe('server -> client', function()
end)
it('via hostname', function()
- local server = spawn(nvim_argv)
+ local server = n.new_session(false)
set_session(server)
local address = fn.serverstart('localhost:')
eq('localhost:', string.sub(address, 1, 10))
@@ -351,10 +349,10 @@ describe('server -> client', function()
end)
it('does not crash on receiving UI events', function()
- local server = spawn(nvim_argv)
+ local server = n.new_session(false)
set_session(server)
local address = fn.serverlist()[1]
- local client = spawn(nvim_argv, false, nil, true)
+ local client = n.new_session(true)
set_session(client)
local id = fn.sockconnect('pipe', address, { rpc = true })
diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua
index 617786eb2d..68c4ef7503 100644
--- a/test/functional/api/version_spec.lua
+++ b/test/functional/api/version_spec.lua
@@ -43,7 +43,7 @@ describe("api_info()['version']", function()
eq(0, fn.has('nvim-' .. major .. '.' .. minor .. '.' .. (patch + 1)))
eq(0, fn.has('nvim-' .. major .. '.' .. (minor + 1) .. '.' .. patch))
eq(0, fn.has('nvim-' .. (major + 1) .. '.' .. minor .. '.' .. patch))
- assert(build == nil or type(build) == 'string')
+ assert(build == vim.NIL or type(build) == 'string')
end)
end)
@@ -93,28 +93,28 @@ describe('api metadata', function()
local function clean_level_0(metadata)
for _, f in ipairs(metadata.functions) do
f.can_fail = nil
- f.async = nil
+ f.async = nil -- XXX: renamed to "fast".
f.receives_channel_id = nil
f.since = 0
end
end
- local api_info, compat, stable, api_level
+ local api_info --[[@type table]]
+ local compat --[[@type integer]]
+ local stable --[[@type integer]]
+ local api_level --[[@type integer]]
local old_api = {}
setup(function()
clear() -- Ensure a session before requesting api_info.
+ --[[@type { version: {api_compatible: integer, api_level: integer, api_prerelease: boolean} }]]
api_info = api.nvim_get_api_info()[2]
compat = api_info.version.api_compatible
api_level = api_info.version.api_level
- if api_info.version.api_prerelease then
- stable = api_level - 1
- else
- stable = api_level
- end
+ stable = api_info.version.api_prerelease and api_level - 1 or api_level
for level = compat, stable do
local path = ('test/functional/fixtures/api_level_' .. tostring(level) .. '.mpack')
- old_api[level] = read_mpack_file(path)
+ old_api[level] = read_mpack_file(path) --[[@type table]]
if old_api[level] == nil then
local errstr = 'missing metadata fixture for stable level ' .. level .. '. '
if level == api_level and not api_info.version.api_prerelease then
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 3f1e378bc1..3aa9ba49d5 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -96,12 +96,19 @@ describe('API', function()
assert_alive()
end)
- it('input is processed first when followed immediately by non-fast events', function()
+ it('input is processed first if followed immediately by non-fast events', function()
api.nvim_set_current_line('ab')
async_meths.nvim_input('x')
async_meths.nvim_exec_lua('_G.res1 = vim.api.nvim_get_current_line()', {})
async_meths.nvim_exec_lua('_G.res2 = vim.api.nvim_get_current_line()', {})
eq({ 'b', 'b' }, exec_lua('return { _G.res1, _G.res2 }'))
+ -- Also test with getchar()
+ async_meths.nvim_command('let g:getchar = 1 | call getchar() | let g:getchar = 0')
+ eq(1, api.nvim_get_var('getchar'))
+ async_meths.nvim_input('x')
+ async_meths.nvim_exec_lua('_G.res1 = vim.g.getchar', {})
+ async_meths.nvim_exec_lua('_G.res2 = vim.g.getchar', {})
+ eq({ 0, 0 }, exec_lua('return { _G.res1, _G.res2 }'))
end)
it('does not set CA_COMMAND_BUSY #7254', function()
@@ -695,7 +702,7 @@ describe('API', function()
pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 })
)
eq(
- 'Failed to evaluate dict expression',
+ 'Vim:E121: Undefined variable: foo',
pcall_err(request, 'nvim_call_dict_function', 'foo', 'f', { 1, 2 })
)
eq('dict not found', pcall_err(request, 'nvim_call_dict_function', '42', 'f', { 1, 2 }))
@@ -781,18 +788,6 @@ describe('API', function()
end)
end)
- describe('nvim_notify', function()
- it('can notify a info message', function()
- api.nvim_notify('hello world', 2, {})
- end)
-
- it('can be overridden', function()
- command('lua vim.notify = function(...) return 42 end')
- eq(42, api.nvim_exec_lua("return vim.notify('Hello world')", {}))
- api.nvim_notify('hello world', 4, {})
- end)
- end)
-
describe('nvim_input', function()
it('Vimscript error: does NOT fail, updates v:errmsg', function()
local status, _ = pcall(api.nvim_input, ':call bogus_fn()<CR>')
@@ -1770,6 +1765,11 @@ describe('API', function()
end)
it('validation', function()
+ eq("Unknown option 'foobar'", pcall_err(api.nvim_set_option_value, 'foobar', 'baz', {}))
+ eq(
+ "Unknown option 'foobar'",
+ pcall_err(api.nvim_set_option_value, 'foobar', 'baz', { win = api.nvim_get_current_win() })
+ )
eq(
"Invalid 'scope': expected 'local' or 'global'",
pcall_err(api.nvim_get_option_value, 'scrolloff', { scope = 'bogus' })
@@ -1952,6 +1952,16 @@ describe('API', function()
api.nvim_set_current_win(api.nvim_list_wins()[2])
eq(api.nvim_list_wins()[2], api.nvim_get_current_win())
end)
+
+ it('failure modes', function()
+ n.command('split')
+
+ eq('Invalid window id: 9999', pcall_err(api.nvim_set_current_win, 9999))
+
+ -- XXX: force nvim_set_current_win to fail somehow.
+ n.command("au WinLeave * throw 'foo'")
+ eq('WinLeave Autocommands for "*": foo', pcall_err(api.nvim_set_current_win, 1000))
+ end)
end)
describe('nvim_{get,set}_current_tabpage, nvim_list_tabpages', function()
@@ -1971,6 +1981,16 @@ describe('API', function()
eq(api.nvim_list_tabpages()[2], api.nvim_get_current_tabpage())
eq(api.nvim_list_wins()[2], api.nvim_get_current_win())
end)
+
+ it('failure modes', function()
+ n.command('tabnew')
+
+ eq('Invalid tabpage id: 999', pcall_err(api.nvim_set_current_tabpage, 999))
+
+ -- XXX: force nvim_set_current_tabpage to fail somehow.
+ n.command("au TabLeave * throw 'foo'")
+ eq('TabLeave Autocommands for "*": foo', pcall_err(api.nvim_set_current_tabpage, 1))
+ end)
end)
describe('nvim_get_mode', function()
@@ -2679,7 +2699,8 @@ describe('API', function()
-- :terminal with args + running process.
command('enew')
local progpath_esc = eval('shellescape(v:progpath)')
- fn.termopen(('%s -u NONE -i NONE'):format(progpath_esc), {
+ fn.jobstart(('%s -u NONE -i NONE'):format(progpath_esc), {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running?
@@ -3654,6 +3675,30 @@ describe('API', function()
async_meths.nvim_echo({ { 'msg\nmsg' }, { 'msg' } }, false, {})
eq('', exec_capture('messages'))
end)
+
+ it('can print error message', function()
+ async_meths.nvim_echo({ { 'Error\nMessage' } }, false, { err = true })
+ screen:expect([[
+ |
+ {1:~ }|*3
+ {3: }|
+ {9:Error} |
+ {9:Message} |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed(':messages<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*6
+ |
+ ]])
+ async_meths.nvim_echo({ { 'Error' }, { 'Message', 'Special' } }, false, { err = true })
+ screen:expect([[
+ ^ |
+ {1:~ }|*6
+ {9:Error}{16:Message} |
+ ]])
+ end)
end)
describe('nvim_open_term', function()
@@ -3760,7 +3805,7 @@ describe('API', function()
screen:expect {
grid = [[
|
- {1:~}{102: }{4: }{1: }|
+ {1:~}{4:^ }{1: }|
{1:~}{4: }{1: }|*4
{1:~ }|*3
{5:-- TERMINAL --} |
@@ -3776,7 +3821,7 @@ describe('API', function()
screen:expect {
grid = [[
|
- {1:~}{4:herrejösses!}{102: }{4: }{1: }|
+ {1:~}{4:herrejösses!^ }{1: }|
{1:~}{4: }{1: }|*4
{1:~ }|*3
{5:-- TERMINAL --} |
@@ -3955,8 +4000,8 @@ describe('API', function()
str = 'TextWithWarningHighlightTextWithUserHighlight',
width = 45,
highlights = {
- { start = 0, group = 'WarningMsg' },
- { start = 24, group = 'User1' },
+ { start = 0, group = 'WarningMsg', groups = { 'StatusLine', 'WarningMsg' } },
+ { start = 24, group = 'User1', groups = { 'StatusLine', 'User1' } },
},
},
api.nvim_eval_statusline(
@@ -3971,7 +4016,7 @@ describe('API', function()
str = 'TextWithNoHighlight',
width = 19,
highlights = {
- { start = 0, group = 'StatusLine' },
+ { start = 0, group = 'StatusLine', groups = { 'StatusLine' } },
},
}, api.nvim_eval_statusline('TextWithNoHighlight', { highlights = true }))
end)
@@ -3983,8 +4028,8 @@ describe('API', function()
str = 'TextWithNoHighlightTextWithWarningHighlight',
width = 43,
highlights = {
- { start = 0, group = 'StatusLineNC' },
- { start = 19, group = 'WarningMsg' },
+ { start = 0, group = 'StatusLineNC', groups = { 'StatusLineNC' } },
+ { start = 19, group = 'WarningMsg', groups = { 'StatusLineNC', 'WarningMsg' } },
},
},
api.nvim_eval_statusline(
@@ -4000,8 +4045,8 @@ describe('API', function()
str = 'TextWithNoHighlightTextWithWarningHighlight',
width = 43,
highlights = {
- { start = 0, group = 'TabLineFill' },
- { start = 19, group = 'WarningMsg' },
+ { start = 0, group = 'TabLineFill', groups = { 'TabLineFill' } },
+ { start = 19, group = 'WarningMsg', groups = { 'TabLineFill', 'WarningMsg' } },
},
},
api.nvim_eval_statusline(
@@ -4017,8 +4062,8 @@ describe('API', function()
str = 'TextWithNoHighlightTextWithWarningHighlight',
width = 43,
highlights = {
- { start = 0, group = 'WinBar' },
- { start = 19, group = 'WarningMsg' },
+ { start = 0, group = 'WinBar', groups = { 'WinBar' } },
+ { start = 19, group = 'WarningMsg', groups = { 'WinBar', 'WarningMsg' } },
},
},
api.nvim_eval_statusline(
@@ -4045,11 +4090,11 @@ describe('API', function()
str = '││bbaa 4 ',
width = 9,
highlights = {
- { group = 'CursorLineFold', start = 0 },
- { group = 'Normal', start = 6 },
- { group = 'ErrorMsg', start = 6 },
- { group = 'IncSearch', start = 8 },
- { group = 'Normal', start = 10 },
+ { group = 'CursorLineFold', start = 0, groups = { 'CursorLineFold' } },
+ { group = 'Normal', start = 6, groups = { 'Normal' } },
+ { group = 'ErrorMsg', start = 6, groups = { 'CursorLineSign', 'ErrorMsg' } },
+ { group = 'IncSearch', start = 8, groups = { 'CursorLineSign', 'IncSearch' } },
+ { group = 'Normal', start = 10, groups = { 'Normal' } },
},
}, api.nvim_eval_statusline(
'%C%s%=%l ',
@@ -4060,8 +4105,8 @@ describe('API', function()
str = ' 3 ',
width = 9,
highlights = {
- { group = 'LineNr', start = 0 },
- { group = 'ErrorMsg', start = 8 },
+ { group = 'LineNr', start = 0, groups = { 'LineNr' } },
+ { group = 'ErrorMsg', start = 8, groups = { 'LineNr', 'ErrorMsg' } },
},
},
api.nvim_eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true })
@@ -5359,8 +5404,53 @@ describe('API', function()
13 |
]],
})
- -- takes buffer line count from correct buffer with "win" and {0, -1} "range"
- api.nvim__redraw({ win = 0, range = { 0, -1 } })
+ end)
+
+ it('nvim__redraw range parameter', function()
+ Screen.new(10, 5)
+ fn.setline(1, fn.range(4))
+
+ exec_lua([[
+ _G.lines_list = {}
+ ns = vim.api.nvim_create_namespace('')
+ vim.api.nvim_set_decoration_provider(ns, {
+ on_win = function()
+ end,
+ on_line = function(_, _, _, line)
+ table.insert(_G.lines_list, line)
+ end,
+ })
+ function _G.get_lines()
+ local lines = _G.lines_list
+ _G.lines_list = {}
+ return lines
+ end
+ ]])
+
+ api.nvim__redraw({ flush = true, valid = false })
+ exec_lua('_G.get_lines()')
+
+ local actual_lines = {}
+ local function test(range)
+ api.nvim__redraw({ win = 0, range = range })
+ table.insert(actual_lines, exec_lua('return _G.get_lines()'))
+ end
+
+ test({ 0, -1 })
+ test({ 2, 2 ^ 31 })
+ test({ 2, 2 ^ 32 })
+ test({ 2 ^ 31 - 1, 2 })
+ test({ 2 ^ 32 - 1, 2 })
+
+ local expected_lines = {
+ { 0, 1, 2, 3 },
+ { 2, 3 },
+ { 2, 3 },
+ {},
+ {},
+ }
+ eq(expected_lines, actual_lines)
+
n.assert_alive()
end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 92999f383a..028f0beb38 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -359,6 +359,15 @@ describe('API/win', function()
eq(2, api.nvim_win_get_height(api.nvim_list_wins()[2]))
end)
+ it('failure modes', function()
+ command('split')
+ eq('Invalid window id: 999999', pcall_err(api.nvim_win_set_height, 999999, 10))
+ eq(
+ 'Wrong type for argument 2 when calling nvim_win_set_height, expecting Integer',
+ pcall_err(api.nvim_win_set_height, 0, 0.9)
+ )
+ end)
+
it('correctly handles height=1', function()
command('split')
api.nvim_set_current_win(api.nvim_list_wins()[1])
@@ -409,6 +418,15 @@ describe('API/win', function()
eq(2, api.nvim_win_get_width(api.nvim_list_wins()[2]))
end)
+ it('failure modes', function()
+ command('vsplit')
+ eq('Invalid window id: 999999', pcall_err(api.nvim_win_set_width, 999999, 10))
+ eq(
+ 'Wrong type for argument 2 when calling nvim_win_set_width, expecting Integer',
+ pcall_err(api.nvim_win_set_width, 0, 0.9)
+ )
+ end)
+
it('do not cause ml_get errors with foldmethod=expr #19989', function()
insert([[
aaaaa
@@ -488,6 +506,48 @@ describe('API/win', function()
assert_alive()
end)
+ describe('after closing', function()
+ local buf, win0, win1, win2
+
+ before_each(function()
+ win0 = api.nvim_get_current_win()
+ command('new')
+ buf = api.nvim_get_current_buf()
+ win1 = api.nvim_get_current_win()
+ command('set numberwidth=10')
+ command('split')
+ win2 = api.nvim_get_current_win()
+ command('set numberwidth=15')
+ command('enew')
+ api.nvim_set_current_win(win1)
+ command('normal ix')
+ command('enew')
+ api.nvim_set_current_win(win0)
+ eq(4, api.nvim_get_option_value('numberwidth', {}))
+ end)
+
+ -- at this point buffer `buf` is current in no windows. Closing shouldn't affect its defaults
+ it('0 windows', function()
+ api.nvim_set_current_buf(buf)
+ eq(10, api.nvim_get_option_value('numberwidth', {}))
+ end)
+
+ it('1 window', function()
+ api.nvim_win_close(win1, false)
+
+ api.nvim_set_current_buf(buf)
+ eq(10, api.nvim_get_option_value('numberwidth', {}))
+ end)
+
+ it('2 windows', function()
+ api.nvim_win_close(win1, false)
+ api.nvim_win_close(win2, false)
+
+ api.nvim_set_current_buf(buf)
+ eq(10, api.nvim_get_option_value('numberwidth', {}))
+ end)
+ end)
+
it('returns values for unset local options', function()
eq(-1, api.nvim_get_option_value('scrolloff', { win = 0, scope = 'local' }))
end)
@@ -1664,7 +1724,7 @@ describe('API/win', function()
autocmd BufWinEnter * ++once let fired = v:true
]])
eq(
- 'Failed to set buffer 2',
+ 'Vim:E37: No write since last change (add ! to override)',
pcall_err(api.nvim_open_win, api.nvim_create_buf(true, true), false, { split = 'left' })
)
eq(false, eval('fired'))
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index c62e4752e0..1b7275ebf6 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -160,7 +160,7 @@ describe('autocmd', function()
it('++once', function() -- :help autocmd-once
--
- -- ":autocmd ... ++once" executes its handler once, then removes the handler.
+ -- ":autocmd … ++once" executes its handler once, then removes the handler.
--
local expected = {
'Many1',
@@ -206,7 +206,7 @@ describe('autocmd', function()
)
--
- -- ":autocmd ... ++once" handlers can be deleted.
+ -- ":autocmd … ++once" handlers can be deleted.
--
expected = {}
command('let g:foo = []')
@@ -216,7 +216,7 @@ describe('autocmd', function()
eq(expected, eval('g:foo'))
--
- -- ":autocmd ... <buffer> ++once ++nested"
+ -- ":autocmd … <buffer> ++once ++nested"
--
expected = {
'OptionSet-Once',
@@ -250,6 +250,24 @@ describe('autocmd', function()
--- Autocommands ---]]),
fn.execute('autocmd Tabnew')
)
+
+ --
+ -- :autocmd does not recursively call ++once Lua handlers.
+ --
+ exec_lua [[vim.g.count = 0]]
+ eq(0, eval('g:count'))
+ exec_lua [[
+ vim.api.nvim_create_autocmd('User', {
+ once = true,
+ pattern = nil,
+ callback = function()
+ vim.g.count = vim.g.count + 1
+ vim.api.nvim_exec_autocmds('User', { pattern = nil })
+ end,
+ })
+ vim.api.nvim_exec_autocmds('User', { pattern = nil })
+ ]]
+ eq(1, eval('g:count'))
end)
it('internal `aucmd_win` window', function()
diff --git a/test/functional/autocmd/completedone_spec.lua b/test/functional/autocmd/completedone_spec.lua
index 33beb16db2..36dc73842d 100644
--- a/test/functional/autocmd/completedone_spec.lua
+++ b/test/functional/autocmd/completedone_spec.lua
@@ -32,7 +32,7 @@ describe('CompleteDone', function()
feed('<Esc>')
eq('cancel', eval('g:donereason'))
end)
- it('when overriden by another complete()', function()
+ it('when overridden by another complete()', function()
call('complete', call('col', '.'), { 'bar', 'baz' })
eq('cancel', eval('g:donereason'))
end)
diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua
index 1cde0e0552..9b572df568 100644
--- a/test/functional/autocmd/dirchanged_spec.lua
+++ b/test/functional/autocmd/dirchanged_spec.lua
@@ -351,11 +351,10 @@ describe('autocmd DirChanged and DirChangedPre', function()
eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
- local status, err = pcall(function()
- request('nvim_set_current_dir', '/doesnotexist')
- end)
- eq(false, status)
- eq('Failed to change directory', string.match(err, ': (.*)'))
+ eq(
+ 'Vim:E344: Can\'t find directory "/doesnotexist" in cdpath',
+ t.pcall_err(request, 'nvim_set_current_dir', '/doesnotexist')
+ )
eq({ directory = '/doesnotexist', scope = 'global', changed_window = false }, eval('g:evpre'))
eq(3, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index 7f6092bf48..177e8997cf 100644
--- a/test/functional/autocmd/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
@@ -47,7 +47,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -57,7 +57,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
feed_command('edit ' .. path)
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:xtest-foo }|
:edit xtest-foo |
@@ -68,7 +68,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
feed_data('\027[O')
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:xtest-foo }|
:edit xtest-foo |
@@ -83,7 +83,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
screen:expect {
grid = [[
- {1:l}ine 1 |
+ ^line 1 |
line 2 |
line 3 |
line 4 |
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index baf2bb6071..950ef2f58a 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -213,9 +213,11 @@ describe('autocmd TextChangedT', function()
end)
it('cannot delete terminal buffer', function()
- command([[autocmd TextChangedT * call nvim_input('<CR>') | bwipe!]])
+ command('autocmd TextChangedT * bwipe!')
tt.feed_data('a')
screen:expect({ any = 'E937: ' })
+ feed('<CR>')
+ command('autocmd! TextChangedT')
matches(
'^E937: Attempt to delete a buffer that is in use: term://',
api.nvim_get_vvar('errmsg')
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index dee13d19ae..7b10eb05ef 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -5,7 +5,6 @@ local clear, eq, eval, next_msg, ok, source = n.clear, t.eq, n.eval, n.next_msg,
local command, fn, api = n.command, n.fn, n.api
local matches = t.matches
local sleep = vim.uv.sleep
-local spawn, nvim_argv = n.spawn, n.nvim_argv
local get_session, set_session = n.get_session, n.set_session
local nvim_prog = n.nvim_prog
local is_os = t.is_os
@@ -33,10 +32,10 @@ describe('channels', function()
end)
pending('can connect to socket', function()
- local server = spawn(nvim_argv, nil, nil, true)
+ local server = n.new_session(true)
set_session(server)
local address = fn.serverlist()[1]
- local client = spawn(nvim_argv, nil, nil, true)
+ local client = n.new_session(true)
set_session(client)
source(init)
@@ -63,7 +62,7 @@ describe('channels', function()
it('dont crash due to garbage in rpc #23781', function()
local client = get_session()
- local server = spawn(nvim_argv, nil, nil, true)
+ local server = n.new_session(true)
set_session(server)
local address = fn.serverlist()[1]
set_session(client)
diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua
index 34c3eedbd2..65f6bc28a6 100644
--- a/test/functional/core/exit_spec.lua
+++ b/test/functional/core/exit_spec.lua
@@ -8,8 +8,6 @@ local feed = n.feed
local eval = n.eval
local eq = t.eq
local run = n.run
-local fn = n.fn
-local nvim_prog = n.nvim_prog
local pcall_err = t.pcall_err
local exec_capture = n.exec_capture
local poke_eventloop = n.poke_eventloop
@@ -69,8 +67,8 @@ describe(':cquit', function()
poke_eventloop()
assert_alive()
else
- fn.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline })
- eq(exit_code, eval('v:shell_error'))
+ local p = n.spawn_wait('--cmd', cmdline)
+ eq(exit_code, p.status)
end
end
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index cf9715f848..b1a8e21762 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -31,7 +31,6 @@ local feed_command = n.feed_command
local skip = t.skip
local is_os = t.is_os
local is_ci = t.is_ci
-local spawn = n.spawn
local set_session = n.set_session
describe('fileio', function()
@@ -51,12 +50,11 @@ describe('fileio', function()
rmdir('Xtest_backupdir with spaces')
end)
- local args = { nvim_prog, '--clean', '--cmd', 'set nofsync directory=Xtest_startup_swapdir' }
+ local args = { '--clean', '--cmd', 'set nofsync directory=Xtest_startup_swapdir' }
--- Starts a new nvim session and returns an attached screen.
- local function startup(extra_args)
- extra_args = extra_args or {}
- local argv = vim.iter({ args, '--embed', extra_args }):flatten():totable()
- local screen_nvim = spawn(argv)
+ local function startup()
+ local argv = vim.iter({ args, '--embed' }):flatten():totable()
+ local screen_nvim = n.new_session(false, { args = argv, merge = false })
set_session(screen_nvim)
local screen = Screen.new(70, 10)
screen:set_default_attr_ids({
@@ -100,7 +98,8 @@ describe('fileio', function()
eq('foozubbaz', trim(read_file('Xtest_startup_file1')))
-- 4. Exit caused by deadly signal (+ 'swapfile').
- local j = fn.jobstart(vim.iter({ args, '--embed' }):flatten():totable(), { rpc = true })
+ local j =
+ fn.jobstart(vim.iter({ nvim_prog, args, '--embed' }):flatten():totable(), { rpc = true })
fn.rpcrequest(
j,
'nvim_exec2',
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 618c294566..e833b5127d 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -65,6 +65,39 @@ describe('jobs', function()
]])
end)
+ it('validation', function()
+ matches(
+ "E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set",
+ pcall_err(command, "call jobstart(['cat', '-'], { 'pty': v:true, 'rpc': v:true })")
+ )
+ matches(
+ 'E475: Invalid argument: expected valid directory',
+ pcall_err(command, "call jobstart(['cat', '-'], { 'cwd': 9313843 })")
+ )
+ matches(
+ 'E475: Invalid argument: expected valid directory',
+ pcall_err(command, "call jobstart(['cat', '-'], { 'cwd': 'bogusssssss/bogus' })")
+ )
+ matches(
+ "E475: Invalid argument: 'term' must be Boolean",
+ pcall_err(command, "call jobstart(['cat', '-'], { 'term': 'bogus' })")
+ )
+ matches(
+ "E475: Invalid argument: 'term' must be Boolean",
+ pcall_err(command, "call jobstart(['cat', '-'], { 'term': 1 })")
+ )
+ command('set modified')
+ matches(
+ vim.pesc('jobstart(...,{term=true}) requires unmodified buffer'),
+ pcall_err(command, "call jobstart(['cat', '-'], { 'term': v:true })")
+ )
+
+ -- Non-failure cases:
+ command('set nomodified')
+ command("call jobstart(['cat', '-'], { 'term': v:true })")
+ command("call jobstart(['cat', '-'], { 'term': v:false })")
+ end)
+
it('must specify env option as a dict', function()
command('let g:job_opts.env = v:true')
local _, err = pcall(function()
@@ -940,6 +973,39 @@ describe('jobs', function()
feed('<CR>')
fn.jobstop(api.nvim_get_var('id'))
end)
+
+ it('does not set UI busy with zero timeout #31712', function()
+ local screen = Screen.new(50, 6)
+ command([[let g:id = jobstart(['sleep', '0.3'])]])
+ local busy = 0
+ screen._handle_busy_start = (function(orig)
+ return function()
+ orig(screen)
+ busy = busy + 1
+ end
+ end)(screen._handle_busy_start)
+ source([[
+ func PrintAndPoll()
+ echon "aaa\nbbb"
+ call jobwait([g:id], 0)
+ echon "\nccc"
+ endfunc
+ ]])
+ feed_command('call PrintAndPoll()')
+ screen:expect {
+ grid = [[
+ |
+ {3: }|
+ aaa |
+ bbb |
+ ccc |
+ {6:Press ENTER or type command to continue}^ |
+ ]],
+ }
+ feed('<CR>')
+ fn.jobstop(api.nvim_get_var('id'))
+ eq(0, busy)
+ end)
end)
pending('exit event follows stdout, stderr', function()
@@ -969,13 +1035,6 @@ describe('jobs', function()
eq({ 'notification', 'exit', { 0, 143 } }, next_msg())
end)
- it('cannot have both rpc and pty options', function()
- command('let g:job_opts.pty = v:true')
- command('let g:job_opts.rpc = v:true')
- local _, err = pcall(command, "let j = jobstart(['cat', '-'], g:job_opts)")
- matches("E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set", err)
- end)
-
it('does not crash when repeatedly failing to start shell', function()
source([[
set shell=nosuchshell
@@ -1198,7 +1257,7 @@ describe('jobs', function()
})
-- Wait for startup to complete, so that all terminal responses are received.
screen:expect([[
- {1: } |
+ ^ |
~ |*3
{1:[No Name] 0,0-1 All}|
|
@@ -1208,7 +1267,7 @@ describe('jobs', function()
feed(':q<CR>')
screen:expect([[
|
- [Process exited 0]{1: } |
+ [Process exited 0]^ |
|*4
{3:-- TERMINAL --} |
]])
@@ -1230,7 +1289,7 @@ describe('pty process teardown', function()
it('does not prevent/delay exit. #4798 #4900', function()
skip(fn.executable('sleep') == 0, 'missing "sleep" command')
-- Use a nested nvim (in :term) to test without --headless.
- fn.termopen({
+ fn.jobstart({
n.nvim_prog,
'-u',
'NONE',
@@ -1243,7 +1302,10 @@ describe('pty process teardown', function()
'+terminal',
'+!(sleep 300 &)',
'+qa',
- }, { env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } })
+ }, {
+ term = true,
+ env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
+ })
-- Exiting should terminate all descendants (PTY, its children, ...).
screen:expect([[
diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua
index 57dfd6364c..571bece833 100644
--- a/test/functional/core/log_spec.lua
+++ b/test/functional/core/log_spec.lua
@@ -46,7 +46,7 @@ describe('log', function()
env = env,
})
screen:expect([[
- {1: } |
+ ^ |
~ |*4
|
{3:-- TERMINAL --} |
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index a445423efc..65a7c556b8 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -9,7 +9,6 @@ local feed = n.feed
local eval = n.eval
local clear = n.clear
local fn = n.fn
-local nvim_prog_abs = n.nvim_prog_abs
local write_file = t.write_file
local is_os = t.is_os
local skip = t.skip
@@ -35,7 +34,7 @@ describe('command-line option', function()
it('treats - as stdin', function()
eq(nil, uv.fs_stat(fname))
fn.system({
- nvim_prog_abs(),
+ n.nvim_prog,
'-u',
'NONE',
'-i',
@@ -56,41 +55,39 @@ describe('command-line option', function()
eq(nil, uv.fs_stat(fname))
eq(true, not not dollar_fname:find('%$%w+'))
write_file(dollar_fname, ':call setline(1, "100500")\n:wqall!\n')
- fn.system({
- nvim_prog_abs(),
- '-u',
- 'NONE',
- '-i',
- 'NONE',
- '--headless',
+ local p = n.spawn_wait(
'--cmd',
'set noswapfile shortmess+=IFW fileformats=unix',
'-s',
dollar_fname,
- fname,
- })
- eq(0, eval('v:shell_error'))
+ fname
+ )
+ eq(0, p.status)
local attrs = uv.fs_stat(fname)
eq(#'100500\n', attrs.size)
end)
- it('does not crash when run completion in ex mode', function()
- fn.system({
- nvim_prog_abs(),
- '--clean',
- '-e',
- '-s',
- '--cmd',
- 'exe "norm! i\\<C-X>\\<C-V>"',
- })
- eq(0, eval('v:shell_error'))
+ it('does not crash when running completion in Ex mode', function()
+ local p =
+ n.spawn_wait('--clean', '-e', '-s', '--cmd', 'exe "norm! i\\<C-X>\\<C-V>"', '--cmd', 'qa!')
+ eq(0, p.status)
+ end)
+
+ it('does not crash when running completion from -l script', function()
+ local lua_fname = 'Xinscompl.lua'
+ write_file(lua_fname, [=[vim.cmd([[exe "norm! i\<C-X>\<C-V>"]])]=])
+ finally(function()
+ os.remove(lua_fname)
+ end)
+ local p = n.spawn_wait('--clean', '-l', lua_fname)
+ eq(0, p.status)
end)
it('does not crash after reading from stdin in non-headless mode', function()
skip(is_os('win'))
local screen = Screen.new(40, 8)
local args = {
- nvim_prog_abs(),
+ n.nvim_prog,
'-u',
'NONE',
'-i',
@@ -103,7 +100,8 @@ describe('command-line option', function()
-- Need to explicitly pipe to stdin so that the embedded Nvim instance doesn't try to read
-- data from the terminal #18181
- fn.termopen(string.format([[echo "" | %s]], table.concat(args, ' ')), {
+ fn.jobstart(string.format([[echo "" | %s]], table.concat(args, ' ')), {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
screen:expect(
@@ -120,7 +118,7 @@ describe('command-line option', function()
feed('i:cq<CR>')
screen:expect([[
|
- [Process exited 1]{2: } |
+ [Process exited 1]^ |
|*5
{5:-- TERMINAL --} |
]])
@@ -137,60 +135,49 @@ describe('command-line option', function()
]=]
end)
- it('errors out when trying to use nonexistent file with -s', function()
+ it('fails when trying to use nonexistent file with -s', function()
+ local p = n.spawn_wait(
+ '--cmd',
+ 'set noswapfile shortmess+=IFW fileformats=unix',
+ '--cmd',
+ 'language C',
+ '-s',
+ nonexistent_fname
+ )
eq(
'Cannot open for reading: "' .. nonexistent_fname .. '": no such file or directory\n',
- fn.system({
- nvim_prog_abs(),
- '-u',
- 'NONE',
- '-i',
- 'NONE',
- '--headless',
- '--cmd',
- 'set noswapfile shortmess+=IFW fileformats=unix',
- '--cmd',
- 'language C',
- '-s',
- nonexistent_fname,
- })
+ --- TODO(justinmk): using `p.output` because Nvim emits CRLF even on non-Win. Emit LF instead?
+ p:output()
)
- eq(2, eval('v:shell_error'))
+ eq(2, p.status)
end)
it('errors out when trying to use -s twice', function()
write_file(fname, ':call setline(1, "1")\n:wqall!\n')
write_file(dollar_fname, ':call setline(1, "2")\n:wqall!\n')
- eq(
- 'Attempt to open script file again: "-s ' .. dollar_fname .. '"\n',
- fn.system({
- nvim_prog_abs(),
- '-u',
- 'NONE',
- '-i',
- 'NONE',
- '--headless',
- '--cmd',
- 'set noswapfile shortmess+=IFW fileformats=unix',
- '--cmd',
- 'language C',
- '-s',
- fname,
- '-s',
- dollar_fname,
- fname_2,
- })
+ local p = n.spawn_wait(
+ '--cmd',
+ 'set noswapfile shortmess+=IFW fileformats=unix',
+ '--cmd',
+ 'language C',
+ '-s',
+ fname,
+ '-s',
+ dollar_fname,
+ fname_2
)
- eq(2, eval('v:shell_error'))
+ --- TODO(justinmk): using `p.output` because Nvim emits CRLF even on non-Win. Emit LF instead?
+ eq('Attempt to open script file again: "-s ' .. dollar_fname .. '"\n', p:output())
+ eq(2, p.status)
eq(nil, uv.fs_stat(fname_2))
end)
end)
it('nvim -v, :version', function()
matches('Run ":verbose version"', fn.execute(':version'))
- matches('Compilation: .*Run :checkhealth', fn.execute(':verbose version'))
- matches('Run "nvim %-V1 %-v"', fn.system({ nvim_prog_abs(), '-v' }))
- matches('Compilation: .*Run :checkhealth', fn.system({ nvim_prog_abs(), '-V1', '-v' }))
+ matches('fall%-back for %$VIM: .*Run :checkhealth', fn.execute(':verbose version'))
+ matches('Run "nvim %-V1 %-v"', n.spawn_wait('-v').stdout)
+ matches('fall%-back for %$VIM: .*Run :checkhealth', n.spawn_wait('-V1', '-v').stdout)
end)
if is_os('win') then
@@ -204,7 +191,7 @@ describe('command-line option', function()
eq(
'some text',
fn.system({
- nvim_prog_abs(),
+ n.nvim_prog,
'-es',
'+%print',
'+q',
diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua
index 6cc28ddeef..1cfa0535f6 100644
--- a/test/functional/core/remote_spec.lua
+++ b/test/functional/core/remote_spec.lua
@@ -10,10 +10,8 @@ local expect = n.expect
local fn = n.fn
local insert = n.insert
local nvim_prog = n.nvim_prog
-local new_argv = n.new_argv
local neq = t.neq
local set_session = n.set_session
-local spawn = n.spawn
local tmpname = t.tmpname
local write_file = t.write_file
@@ -32,8 +30,7 @@ describe('Remote', function()
describe('connect to server and', function()
local server
before_each(function()
- server = spawn(new_argv(), true)
- set_session(server)
+ server = n.clear()
end)
after_each(function()
@@ -49,7 +46,7 @@ describe('Remote', function()
-- to wait for the remote instance to exit and calling jobwait blocks
-- the event loop. If the server event loop is blocked, it can't process
-- our incoming --remote calls.
- local client_starter = spawn(new_argv(), false, nil, true)
+ local client_starter = n.new_session(true)
set_session(client_starter)
-- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
eq(
@@ -144,15 +141,8 @@ describe('Remote', function()
describe('exits with error on', function()
local function run_and_check_exit_code(...)
- local bogus_argv = new_argv(...)
-
- -- Create an nvim instance just to run the remote-invoking nvim. We want
- -- to wait for the remote instance to exit and calling jobwait blocks
- -- the event loop. If the server event loop is blocked, it can't process
- -- our incoming --remote calls.
- clear()
- -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
- eq({ 2 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], bogus_argv))
+ local p = n.spawn_wait { args = { ... } }
+ eq(2, p.status)
end
it('bogus subcommand', function()
run_and_check_exit_code('--remote-bogus')
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 7062211187..8ecd3dca97 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -55,7 +55,10 @@ describe('startup', function()
clear()
local screen
screen = Screen.new(84, 3)
- fn.termopen({ nvim_prog, '-u', 'NONE', '--server', eval('v:servername'), '--remote-ui' })
+ fn.jobstart(
+ { nvim_prog, '-u', 'NONE', '--server', eval('v:servername'), '--remote-ui' },
+ { term = true }
+ )
screen:expect([[
^Cannot attach UI of :terminal child to its parent. (Unset $NVIM to skip this check) |
|*2
@@ -74,22 +77,9 @@ describe('startup', function()
end)
it('--startuptime does not crash on error #31125', function()
- eq(
- "E484: Can't open file .",
- fn.system({
- nvim_prog,
- '-u',
- 'NONE',
- '-i',
- 'NONE',
- '--headless',
- '--startuptime',
- '.',
- '-c',
- '42cquit',
- })
- )
- eq(42, api.nvim_get_vvar('shell_error'))
+ local p = n.spawn_wait('--startuptime', '.', '-c', '42cquit')
+ eq("E484: Can't open file .", p.stderr)
+ eq(42, p.status)
end)
it('-D does not hang #12647', function()
@@ -98,7 +88,7 @@ describe('startup', function()
screen = Screen.new(60, 7)
-- not the same colors on windows for some reason
screen._default_attr_ids = nil
- local id = fn.termopen({
+ local id = fn.jobstart({
nvim_prog,
'-u',
'NONE',
@@ -108,6 +98,7 @@ describe('startup', function()
'set noruler',
'-D',
}, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -145,13 +136,18 @@ describe('startup', function()
vim.list_extend(args, { '-l', (script or 'test/functional/fixtures/startup.lua') })
vim.list_extend(args, lua_args or {})
local out = fn.system(args, input):gsub('\r\n', '\n')
- return eq(dedent(expected), out)
+ if type(expected) == 'function' then
+ return expected(out)
+ else
+ return eq(dedent(expected), out)
+ end
end
it('failure modes', function()
-- nvim -l <empty>
- matches('nvim%.?e?x?e?: Argument missing after: "%-l"', fn.system({ nvim_prog, '-l' }))
- eq(1, eval('v:shell_error'))
+ local proc = n.spawn_wait('-l')
+ matches('nvim%.?e?x?e?: Argument missing after: "%-l"', proc.stderr)
+ eq(1, proc.status)
end)
it('os.exit() sets Nvim exitcode', function()
@@ -178,13 +174,13 @@ describe('startup', function()
end)
it('Lua-error sets Nvim exitcode', function()
+ local proc = n.spawn_wait('-l', 'test/functional/fixtures/startup-fail.lua')
+ matches('E5113: .* my pearls!!', proc:output())
+ eq(0, proc.signal)
+ eq(1, proc.status)
+
eq(0, eval('v:shell_error'))
matches(
- 'E5113: .* my pearls!!',
- fn.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' })
- )
- eq(1, eval('v:shell_error'))
- matches(
'E5113: .* %[string "error%("whoa"%)"%]:1: whoa',
fn.system({ nvim_prog, '-l', '-' }, 'error("whoa")')
)
@@ -291,14 +287,30 @@ describe('startup', function()
eq(0, eval('v:shell_error'))
end)
- it('disables swapfile/shada/config/plugins', function()
+ it('disables swapfile/shada/config/plugins unless overridden', function()
+ local script = [[print(('updatecount=%d shadafile=%s loadplugins=%s scripts=%d'):format(
+ vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.getscriptinfo())))]]
+ finally(function()
+ os.remove('Xtest_shada')
+ end)
+
assert_l_out(
'updatecount=0 shadafile=NONE loadplugins=false scripts=1\n',
nil,
nil,
'-',
- [[print(('updatecount=%d shadafile=%s loadplugins=%s scripts=%d'):format(
- vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.getscriptinfo())))]]
+ script
+ )
+
+ -- User can override.
+ assert_l_out(
+ function(out)
+ return matches('updatecount=99 shadafile=Xtest_shada loadplugins=true scripts=2%d\n', out)
+ end,
+ { '+set updatecount=99', '-i', 'Xtest_shada', '+set loadplugins', '-u', 'NORC' },
+ nil,
+ '-',
+ script
)
end)
end)
@@ -343,7 +355,7 @@ describe('startup', function()
local screen = Screen.new(25, 3)
-- Remote UI connected by --embed.
-- TODO: a lot of tests in this file already use the new default color scheme.
- -- once we do the batch update of tests to use it, remove this workarond
+ -- once we do the batch update of tests to use it, remove this workaround
screen._default_attr_ids = nil
command([[echo has('ttyin') has('ttyout')]])
screen:expect([[
@@ -360,7 +372,7 @@ describe('startup', function()
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end
-- Running in :terminal
- fn.termopen({
+ fn.jobstart({
nvim_prog,
'-u',
'NONE',
@@ -371,6 +383,7 @@ describe('startup', function()
'-c',
'echo has("ttyin") has("ttyout")',
}, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -393,13 +406,14 @@ describe('startup', function()
os.remove('Xtest_startup_ttyout')
end)
-- Running in :terminal
- fn.termopen(
+ fn.jobstart(
(
[["%s" -u NONE -i NONE --cmd "%s"]]
.. [[ -c "call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')"]]
.. [[ -c q | cat -v]]
):format(nvim_prog, nvim_set),
{
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -424,7 +438,7 @@ describe('startup', function()
os.remove('Xtest_startup_ttyout')
end)
-- Running in :terminal
- fn.termopen(
+ fn.jobstart(
(
[[echo foo | ]] -- Input from a pipe.
.. [["%s" -u NONE -i NONE --cmd "%s"]]
@@ -432,6 +446,7 @@ describe('startup', function()
.. [[ -c q -- -]]
):format(nvim_prog, nvim_set),
{
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -454,13 +469,14 @@ describe('startup', function()
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
end
-- Running in :terminal
- fn.termopen(
+ fn.jobstart(
(
[[echo foo | ]]
.. [["%s" -u NONE -i NONE --cmd "%s"]]
.. [[ -c "echo has('ttyin') has('ttyout')"]]
):format(nvim_prog, nvim_set),
{
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -577,19 +593,21 @@ describe('startup', function()
eq(' encoding=utf-8\n', fn.system({ nvim_prog, '-n', '-es' }, { 'set encoding', '' }))
end)
- it('-es/-Es disables swapfile, user config #8540', function()
+ it('-es/-Es disables swapfile/shada/config #8540', function()
for _, arg in ipairs({ '-es', '-Es' }) do
local out = fn.system({
nvim_prog,
arg,
- '+set swapfile? updatecount? shadafile?',
+ '+set updatecount? shadafile? loadplugins?',
'+put =map(getscriptinfo(), {-> v:val.name})',
'+%print',
})
local line1 = string.match(out, '^.-\n')
-- updatecount=0 means swapfile was disabled.
- eq(' swapfile updatecount=0 shadafile=\n', line1)
- -- Standard plugins were loaded, but not user config.
+ eq(' updatecount=0 shadafile=NONE loadplugins\n', line1)
+ -- Standard plugins were loaded, but not user config. #31878
+ local nrlines = #vim.split(out, '\n')
+ ok(nrlines > 20, '>20', nrlines)
ok(string.find(out, 'man.lua') ~= nil)
ok(string.find(out, 'init.vim') == nil)
end
@@ -598,15 +616,15 @@ describe('startup', function()
it('fails on --embed with -es/-Es/-l', function()
matches(
'nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l',
- fn.system({ nvim_prog, '--embed', '-es' })
+ n.spawn_wait('--embed', '-es').stderr
)
matches(
'nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l',
- fn.system({ nvim_prog, '--embed', '-Es' })
+ n.spawn_wait('--embed', '-Es').stderr
)
matches(
'nvim[.exe]*: %-%-embed conflicts with %-es/%-Es/%-l',
- fn.system({ nvim_prog, '--embed', '-l', 'foo.lua' })
+ n.spawn_wait('--embed', '-l', 'foo.lua').stderr
)
end)
@@ -614,7 +632,7 @@ describe('startup', function()
local screen
screen = Screen.new(60, 6)
screen._default_attr_ids = nil
- local id = fn.termopen({
+ local id = fn.jobstart({
nvim_prog,
'-u',
'NONE',
@@ -625,6 +643,7 @@ describe('startup', function()
'--cmd',
'let g:foo = g:bar',
}, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -689,20 +708,8 @@ describe('startup', function()
end)
it('get command line arguments from v:argv', function()
- local out = fn.system({
- nvim_prog,
- '-u',
- 'NONE',
- '-i',
- 'NONE',
- '--headless',
- '--cmd',
- nvim_set,
- '-c',
- [[echo v:argv[-1:] len(v:argv) > 1]],
- '+q',
- })
- eq("['+q'] 1", out)
+ local p = n.spawn_wait('--cmd', nvim_set, '-c', [[echo v:argv[-1:] len(v:argv) > 1]], '+q')
+ eq("['+q'] 1", p.stderr)
end)
end)
@@ -1144,7 +1151,8 @@ describe('user config init', function()
local screen = Screen.new(50, 8)
screen._default_attr_ids = nil
- fn.termopen({ nvim_prog }, {
+ fn.jobstart({ nvim_prog }, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -1153,7 +1161,7 @@ describe('user config init', function()
-- `i` to enter Terminal mode, `a` to allow
feed('ia')
screen:expect([[
- |
+ ^ |
~ |*4
[No Name] 0,0-1 All|
|
@@ -1162,7 +1170,7 @@ describe('user config init', function()
feed(':echo g:exrc_file<CR>')
screen:expect(string.format(
[[
- |
+ ^ |
~ |*4
[No Name] 0,0-1 All|
%s%s|
@@ -1418,7 +1426,7 @@ describe('inccommand on ex mode', function()
clear()
local screen
screen = Screen.new(60, 10)
- local id = fn.termopen({
+ local id = fn.jobstart({
nvim_prog,
'-u',
'NONE',
@@ -1429,6 +1437,7 @@ describe('inccommand on ex mode', function()
'-E',
'test/README.md',
}, {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
fn.chansend(id, '%s/N')
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index 030181764d..7c68de272b 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -10,6 +10,7 @@ local fn = n.fn
local command = n.command
local api = n.api
local poke_eventloop = n.poke_eventloop
+local exec_lua = n.exec_lua
describe('completion', function()
local screen
@@ -1023,18 +1024,18 @@ describe('completion', function()
it("'ignorecase' 'infercase' CTRL-X CTRL-N #6451", function()
feed_command('set ignorecase infercase')
- feed_command('edit runtime/doc/backers.txt')
+ feed_command('edit runtime/doc/credits.txt')
feed('oX<C-X><C-N>')
screen:expect {
grid = [[
- *backers.txt* Nvim |
- Xnull^ |
- {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} |
+ *credits.txt* Nvim |
+ Xvi^ |
+ {12:Xvi }{101: } |
+ {4:Xvim }{101: } |
+ {4:X11 }{12: } NVIM REFERENCE MANUAL |
+ {4:Xnull }{12: } |
+ {4:Xoxomoon }{12: } |
+ {5:-- Keyword Local completion (^N^P) }{6:match 1 of 10} |
]],
}
end)
@@ -1265,7 +1266,7 @@ describe('completion', function()
command([[
call setline(1, ['aaaa'])
let ns_id = nvim_create_namespace('extmark')
- let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error'})
+ let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error' })
let mark = nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })
inoremap <C-x> <C-r>=Complete()<CR>
function Complete() abort
@@ -1302,5 +1303,53 @@ describe('completion', function()
aaaaa |
{5:-- INSERT --} |
]])
+ -- Also when completion leader is changed #31384
+ feed('<Esc>hi<C-N><C-P>a')
+ screen:expect({
+ grid = [[
+ {9:aa}a^aa |
+ {4:aaaa } |
+ {4:aaaaa } |
+ {5:-- Keyword completion (^N^P) }{19:Back at original} |
+ ]],
+ })
+ -- But still grows with end_right_gravity #31437
+ command(
+ "call nvim_buf_set_extmark(0, ns_id, 1, 0, { 'end_col':2, 'hl_group':'Error', 'end_right_gravity': 1 })"
+ )
+ feed('<Esc>ji<C-N>a')
+ screen:expect({
+ grid = [[
+ {9:aa}aaa |
+ {9:aaa}^aa |
+ aaaaa |
+ {5:-- INSERT --} |
+ ]],
+ })
+ end)
+
+ describe('nvim__complete_set', function()
+ it("fails when 'completeopt' does not include popup", function()
+ exec_lua([[
+ function _G.omni_test(findstart, base)
+ if findstart == 1 then
+ return vim.fn.col('.') - 1
+ end
+ return { { word = 'one' } }
+ end
+ vim.api.nvim_create_autocmd('CompleteChanged', {
+ callback = function()
+ local ok, err = pcall(vim.api.nvim__complete_set, 0, { info = '1info' })
+ if not ok then
+ vim.g.err_msg = err
+ end
+ end,
+ })
+ vim.opt.completeopt = 'menu,menuone'
+ vim.opt.omnifunc = 'v:lua.omni_test'
+ ]])
+ feed('S<C-X><C-O>')
+ eq('completeopt option does not include popup', api.nvim_get_var('err_msg'))
+ end)
end)
end)
diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua
index 82d285cc9a..ee6bfa1be9 100644
--- a/test/functional/editor/defaults_spec.lua
+++ b/test/functional/editor/defaults_spec.lua
@@ -32,7 +32,7 @@ describe('default', function()
describe('popupmenu', function()
it('can be disabled by user', function()
n.clear {
- args = { '+autocmd! nvim_popupmenu', '+aunmenu PopUp' },
+ args = { '+autocmd! nvim.popupmenu', '+aunmenu PopUp' },
}
local screen = Screen.new(40, 8)
n.insert([[
@@ -94,8 +94,103 @@ describe('default', function()
end)
describe('key mappings', function()
+ describe('Visual mode search mappings', function()
+ it('handle various chars properly', function()
+ n.clear({ args_rm = { '--cmd' } })
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = { foreground = Screen.colors.NvimDarkGray4 },
+ [2] = {
+ foreground = Screen.colors.NvimDarkGray3,
+ background = Screen.colors.NvimLightGray3,
+ },
+ [3] = {
+ foreground = Screen.colors.NvimLightGrey1,
+ background = Screen.colors.NvimDarkYellow,
+ },
+ [4] = {
+ foreground = Screen.colors.NvimDarkGrey1,
+ background = Screen.colors.NvimLightYellow,
+ },
+ })
+ n.api.nvim_buf_set_lines(0, 0, -1, true, {
+ [[testing <CR> /?\!1]],
+ [[testing <CR> /?\!2]],
+ [[testing <CR> /?\!3]],
+ [[testing <CR> /?\!4]],
+ })
+ n.feed('gg0vf!o*')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {4:^testing <CR> /?\!}2 |
+ {3:testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 2,1 All}|
+ /\Vtesting <CR> \/?\\! [2/4] |
+ ]])
+ n.feed('n')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {3:testing <CR> /?\!}2 |
+ {4:^testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 3,1 All}|
+ /\Vtesting <CR> \/?\\! [3/4] |
+ ]])
+ n.feed('G0vf!o#')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {3:testing <CR> /?\!}2 |
+ {4:^testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 3,1 All}|
+ ?\Vtesting <CR> /?\\! [3/4] |
+ ]])
+ n.feed('n')
+ screen:expect([[
+ {3:testing <CR> /?\!}1 |
+ {4:^testing <CR> /?\!}2 |
+ {3:testing <CR> /?\!}3 |
+ {3:testing <CR> /?\!}4 |
+ {1:~ }|*2
+ {2:[No Name] [+] 2,1 All}|
+ ?\Vtesting <CR> /?\\! [2/4] |
+ ]])
+ end)
+ end)
+
describe('unimpaired-style mappings', function()
- it('do not show a full stack trace #30625', function()
+ it('show the command ouptut when successful', function()
+ n.clear({ args_rm = { '--cmd' } })
+ local screen = Screen.new(40, 8)
+ n.fn.setqflist({
+ { filename = 'file1', text = 'item1' },
+ { filename = 'file2', text = 'item2' },
+ })
+
+ n.feed(']q')
+
+ screen:set_default_attr_ids({
+ [1] = { foreground = Screen.colors.NvimDarkGrey4 },
+ [2] = {
+ background = Screen.colors.NvimLightGray3,
+ foreground = Screen.colors.NvimDarkGrey3,
+ },
+ })
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*5
+ {2:file2 0,0-1 All}|
+ (2 of 2): item2 |
+ ]],
+ })
+ end)
+
+ it('do not show a full stack trace when unsuccessful #30625', function()
n.clear({ args_rm = { '--cmd' } })
local screen = Screen.new(40, 8)
screen:set_default_attr_ids({
diff --git a/test/functional/editor/mode_normal_spec.lua b/test/functional/editor/mode_normal_spec.lua
index 5237f51237..353a261edb 100644
--- a/test/functional/editor/mode_normal_spec.lua
+++ b/test/functional/editor/mode_normal_spec.lua
@@ -26,10 +26,10 @@ describe('Normal mode', function()
it('&showcmd does not crash with :startinsert #28419', function()
local screen = Screen.new(60, 17)
- fn.termopen(
- { n.nvim_prog, '--clean', '--cmd', 'startinsert' },
- { env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } }
- )
+ fn.jobstart({ n.nvim_prog, '--clean', '--cmd', 'startinsert' }, {
+ term = true,
+ env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
+ })
screen:expect({
grid = [[
^ |
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index 2820cc9663..f84fc140d2 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -12,12 +12,10 @@ local fn = n.fn
local nvim_prog = n.nvim_prog
local ok = t.ok
local rmdir = n.rmdir
-local new_argv = n.new_argv
local new_pipename = n.new_pipename
local pesc = vim.pesc
local os_kill = n.os_kill
local set_session = n.set_session
-local spawn = n.spawn
local async_meths = n.async_meths
local expect_msg_seq = n.expect_msg_seq
local pcall_err = t.pcall_err
@@ -56,7 +54,7 @@ describe("preserve and (R)ecover with custom 'directory'", function()
local nvim0
before_each(function()
- nvim0 = spawn(new_argv())
+ nvim0 = n.new_session(false)
set_session(nvim0)
rmdir(swapdir)
mkdir(swapdir)
@@ -76,7 +74,8 @@ describe("preserve and (R)ecover with custom 'directory'", function()
local function test_recover(swappath1)
-- Start another Nvim instance.
- local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true)
+ local nvim2 =
+ n.new_session(false, { args = { '-u', 'NONE', '-i', 'NONE', '--embed' }, merge = false })
set_session(nvim2)
exec(init)
@@ -115,7 +114,8 @@ describe("preserve and (R)ecover with custom 'directory'", function()
t.skip(t.is_os('win'))
local screen0 = Screen.new()
local child_server = new_pipename()
- fn.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, {
+ fn.jobstart({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
screen0:expect({ any = pesc('[No Name]') }) -- Wait for the child process to start.
@@ -140,7 +140,7 @@ describe('swapfile detection', function()
set swapfile fileformat=unix nomodified undolevels=-1 nohidden
]]
before_each(function()
- nvim0 = spawn(new_argv())
+ nvim0 = n.new_session(false)
set_session(nvim0)
rmdir(swapdir)
mkdir(swapdir)
@@ -167,12 +167,13 @@ describe('swapfile detection', function()
command('preserve')
-- Start another Nvim instance.
- local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true, nil, true)
+ local nvim2 =
+ n.new_session(true, { args = { '-u', 'NONE', '-i', 'NONE', '--embed' }, merge = false })
set_session(nvim2)
local screen2 = Screen.new(256, 40)
screen2._default_attr_ids = nil
exec(init)
- command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
+ command('autocmd! nvim.swapfile') -- Delete the default handler (which skips the dialog).
-- With shortmess+=F
command('set shortmess+=F')
@@ -219,6 +220,7 @@ describe('swapfile detection', function()
.. [[%.swp"]],
}
feed('e') -- Chose "Edit" at the swap dialog.
+ screen2:expect({ any = pesc('E5555: API call: Vim(edit):E325: ATTENTION') })
feed('<c-c>')
screen2:expect(expected_no_dialog)
@@ -249,7 +251,7 @@ describe('swapfile detection', function()
command('preserve') -- Make sure the swap file exists.
local nvimpid = fn.getpid()
- local nvim1 = spawn(new_argv(), true, nil, true)
+ local nvim1 = n.new_session(true)
set_session(nvim1)
local screen = Screen.new(75, 18)
exec(init)
@@ -271,11 +273,11 @@ describe('swapfile detection', function()
[1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg
})
- local nvim1 = spawn(new_argv(), true, nil, true)
+ local nvim1 = n.new_session(true)
set_session(nvim1)
screen:attach()
exec(init)
- command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
+ command('autocmd! nvim.swapfile') -- Delete the default handler (which skips the dialog).
feed(':split Xfile1\n')
-- The default SwapExists handler does _not_ skip this prompt.
screen:expect({
@@ -290,11 +292,11 @@ describe('swapfile detection', function()
]])
nvim1:close()
- local nvim2 = spawn(new_argv(), true, nil, true)
+ local nvim2 = n.new_session(true)
set_session(nvim2)
screen:attach()
exec(init)
- command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
+ command('autocmd! nvim.swapfile') -- Delete the default handler (which skips the dialog).
command('set more')
command('au bufadd * let foo_w = wincol()')
feed(':e Xfile1<CR>')
@@ -325,7 +327,7 @@ describe('swapfile detection', function()
exec(init)
if not swapexists then
- command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog).
+ command('autocmd! nvim.swapfile') -- Delete the default handler (which skips the dialog).
end
command('set nohidden')
@@ -446,9 +448,10 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
end)
it('(Q)uit at first file argument', function()
- local chan = fn.termopen(
+ local chan = fn.jobstart(
{ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', init_dir, '--cmd', init_set, testfile },
{
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
}
)
@@ -468,7 +471,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
end)
it('(A)bort at second file argument with -p', function()
- local chan = fn.termopen({
+ local chan = fn.jobstart({
nvim_prog,
'-u',
'NONE',
@@ -482,6 +485,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
otherfile,
testfile,
}, {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
retry(nil, nil, function()
@@ -508,7 +512,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
second %s /^ \zssecond$/
third %s /^ \zsthird$/]]):format(testfile, testfile, testfile)
)
- local chan = fn.termopen({
+ local chan = fn.jobstart({
nvim_prog,
'-u',
'NONE',
@@ -522,6 +526,7 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
'set tags=' .. otherfile,
'-tsecond',
}, {
+ term = true,
env = { VIMRUNTIME = os.getenv('VIMRUNTIME') },
})
retry(nil, nil, function()
@@ -532,10 +537,6 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
end)
api.nvim_chan_send(chan, 'q')
retry(nil, nil, function()
- eq('Press ENTER or type command to continue', eval("getline('$')->trim(' ', 2)"))
- end)
- api.nvim_chan_send(chan, '\r')
- retry(nil, nil, function()
eq(
{ '', '[Process exited 1]', '' },
eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")
diff --git a/test/functional/ex_cmds/wundo_spec.lua b/test/functional/ex_cmds/wundo_spec.lua
index 2299f33f06..9b81c6d06d 100644
--- a/test/functional/ex_cmds/wundo_spec.lua
+++ b/test/functional/ex_cmds/wundo_spec.lua
@@ -5,8 +5,6 @@ local n = require('test.functional.testnvim')()
local command = n.command
local clear = n.clear
local eval = n.eval
-local spawn = n.spawn
-local nvim_prog = n.nvim_prog
local set_session = n.set_session
describe(':wundo', function()
@@ -24,15 +22,11 @@ end)
describe('u_* functions', function()
it('safely fail on new, non-empty buffer', function()
- local session = spawn({
- nvim_prog,
- '-u',
- 'NONE',
- '-i',
- 'NONE',
- '--embed',
- '-c',
- 'set undodir=. undofile',
+ local session = n.new_session(false, {
+ args = {
+ '-c',
+ 'set undodir=. undofile',
+ },
})
set_session(session)
command('echo "True"') -- Should not error out due to crashed Neovim
diff --git a/test/functional/fixtures/CMakeLists.txt b/test/functional/fixtures/CMakeLists.txt
index 150407fe46..a388f9cb33 100644
--- a/test/functional/fixtures/CMakeLists.txt
+++ b/test/functional/fixtures/CMakeLists.txt
@@ -1,7 +1,4 @@
add_library(test_lib INTERFACE)
-if(MINGW)
- target_link_libraries(test_lib INTERFACE -municode)
-endif()
if(WIN32)
target_compile_definitions(test_lib INTERFACE MSWIN)
endif()
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index f813927f77..5d7ab2ad12 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -386,6 +386,21 @@ function tests.check_forward_content_modified()
}
end
+function tests.check_forward_server_cancelled()
+ skeleton {
+ on_init = function()
+ return { capabilities = {} }
+ end,
+ body = function()
+ expect_request('error_code_test', function()
+ return { code = -32802 }, nil, { method = 'error_code_test', client_id = 1 }
+ end)
+ expect_notification('finish')
+ notify('finish')
+ end,
+ }
+end
+
function tests.check_pending_request_tracked()
skeleton {
on_init = function(_)
diff --git a/test/functional/fixtures/printargs-test.c b/test/functional/fixtures/printargs-test.c
index 2c25cf8447..a1d3fdf76e 100644
--- a/test/functional/fixtures/printargs-test.c
+++ b/test/functional/fixtures/printargs-test.c
@@ -2,7 +2,7 @@
int main(int argc, char **argv)
{
- for (int i=1; i<argc; i++) {
+ for (int i = 1; i < argc; i++) {
printf("arg%d=%s;", i, argv[i]);
}
return 0;
diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c
index bd71e7d11b..f3e94a28da 100644
--- a/test/functional/fixtures/shell-test.c
+++ b/test/functional/fixtures/shell-test.c
@@ -1,11 +1,12 @@
+#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
-#include <stdint.h>
#ifdef _MSC_VER
-#include <Windows.h>
-#define usleep(usecs) Sleep(usecs/1000)
+# include <Windows.h>
+# define usleep(usecs) Sleep(usecs/1000)
#else
-#include <unistd.h>
+# include <unistd.h>
#endif
static void flush_wait(void)
@@ -56,7 +57,7 @@ int main(int argc, char **argv)
if (argc >= 2) {
if (strcmp(argv[1], "-t") == 0) {
if (argc < 3) {
- fprintf(stderr,"Missing prompt text for -t option\n");
+ fprintf(stderr, "Missing prompt text for -t option\n");
return 5;
} else {
fprintf(stderr, "%s $ ", argv[2]);
@@ -107,18 +108,18 @@ int main(int argc, char **argv)
char cmd[100];
int arg;
- while (1) {
+ while (true) {
fprintf(stderr, "interact $ ");
if (fgets(input, sizeof(input), stdin) == NULL) {
break; // EOF
}
- if(1 == sscanf(input, "%99s %d", cmd, &arg)) {
+ if (1 == sscanf(input, "%99s %d", cmd, &arg)) {
arg = 0;
}
if (strcmp(cmd, "exit") == 0) {
- return arg;
+ return arg;
} else {
fprintf(stderr, "command not found: %s\n", cmd);
}
diff --git a/test/functional/fixtures/streams-test.c b/test/functional/fixtures/streams-test.c
index 5a59abb33b..68e668d5fa 100644
--- a/test/functional/fixtures/streams-test.c
+++ b/test/functional/fixtures/streams-test.c
@@ -1,6 +1,5 @@
/// Helper program to exit and keep stdout open (like "xclip -i -loops 1").
#include <stdio.h>
-
#include <uv.h>
int main(int argc, char **argv)
@@ -8,7 +7,7 @@ int main(int argc, char **argv)
uv_loop_t *loop = uv_default_loop();
uv_process_t child_req;
- char * args[3];
+ char *args[3];
args[0] = "sleep";
args[1] = "10";
args[2] = NULL;
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
index bf146e1322..819b40323a 100644
--- a/test/functional/legacy/cmdline_spec.lua
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -159,6 +159,50 @@ describe('cmdline', function()
endfunc
]])
+ feed(':resize -3<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*2
+ {3:[No Name] }|
+ |*4
+ ]])
+
+ -- :resize now also changes 'cmdheight' accordingly
+ feed(':set cmdheight+=1<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {3:[No Name] }|
+ |*5
+ ]])
+
+ -- using more space moves the status line up
+ feed(':set cmdheight+=1<CR>')
+ screen:expect([[
+ ^ |
+ {3:[No Name] }|
+ |*6
+ ]])
+
+ -- reducing cmdheight moves status line down
+ feed(':set cmdheight-=3<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ {3:[No Name] }|
+ |*3
+ ]])
+
+ -- reducing window size and then setting cmdheight
+ feed(':resize -1<CR>')
+ feed(':set cmdheight=1<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {3:[No Name] }|
+ |
+ ]])
+
-- setting 'cmdheight' works after outputting two messages
feed(':call EchoTwo()')
screen:expect([[
@@ -185,6 +229,16 @@ describe('cmdline', function()
bar |
{6:Press ENTER or type command to continue}^ |
]])
+
+ -- window commands do not reduce 'cmdheight' to value lower than :set by user
+ feed('<CR>:wincmd _<CR>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*4
+ {3:[No Name] }|
+ :wincmd _ |
+ |
+ ]])
end)
-- oldtest: Test_cmdheight_tabline()
@@ -216,6 +270,22 @@ describe('cmdline', function()
longish |
]]
end)
+
+ -- oldtest: Test_rulerformat_function()
+ it("'rulerformat' can use %!", function()
+ local screen = Screen.new(40, 2)
+ exec([[
+ func TestRulerFn()
+ return '10,20%=30%%'
+ endfunc
+ ]])
+ api.nvim_set_option_value('ruler', true, {})
+ api.nvim_set_option_value('rulerformat', '%!TestRulerFn()', {})
+ screen:expect([[
+ ^ |
+ 10,20 30% |
+ ]])
+ end)
end)
describe('cmdwin', function()
diff --git a/test/functional/legacy/highlight_spec.lua b/test/functional/legacy/highlight_spec.lua
index e663931bd7..24d6abcc6b 100644
--- a/test/functional/legacy/highlight_spec.lua
+++ b/test/functional/legacy/highlight_spec.lua
@@ -29,8 +29,8 @@ describe(':highlight', function()
|
TermCursor {2:xxx} {18:cterm=}reverse |
{18:gui=}reverse |
- TermCursorNC xxx cleared |
NonText {1:xxx} {18:ctermfg=}12 |
+ {18:gui=}bold |
{6:-- More --}^ |
]])
feed('q')
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
index bc58551a34..db5e3f6857 100644
--- a/test/functional/legacy/messages_spec.lua
+++ b/test/functional/legacy/messages_spec.lua
@@ -82,7 +82,7 @@ describe('messages', function()
NoSuchFil^e |
three |
{1:~ }|*5
- from DebugSilent visual |
+ |
{9:E447: Can't find file "NoSuchFile" in path} |
]])
end)
@@ -689,4 +689,43 @@ describe('messages', function()
]])
os.remove('b.txt')
end)
+
+ -- oldtest: Test_messagesopt_wait()
+ it('&messagesopt "wait"', function()
+ screen = Screen.new(45, 6)
+ command('set cmdheight=1')
+
+ -- Check hit-enter prompt
+ command('set messagesopt=hit-enter,history:500')
+ feed(":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ screen:expect([[
+ |
+ {3: }|
+ foo |
+ bar |
+ baz |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<CR>')
+
+ -- Check no hit-enter prompt when "wait:" is set
+ command('set messagesopt=wait:500,history:500')
+ feed(":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ screen:expect({
+ grid = [[
+ |
+ {1:~ }|
+ {3: }|
+ foo |
+ bar |
+ baz |
+ ]],
+ timeout = 500,
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|*4
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua
index ac7c8cd0bc..af355f27e6 100644
--- a/test/functional/legacy/signs_spec.lua
+++ b/test/functional/legacy/signs_spec.lua
@@ -26,6 +26,9 @@ describe('signs', function()
-- oldtest: Test_sign_cursor_position()
it('are drawn correctly', function()
local screen = Screen.new(75, 6)
+ screen:add_extra_attr_ids({
+ [100] = { foreground = Screen.colors.Blue4, background = Screen.colors.Yellow },
+ })
exec([[
call setline(1, [repeat('x', 75), 'mmmm', 'yyyy'])
call cursor(2,1)
@@ -37,7 +40,7 @@ describe('signs', function()
screen:expect([[
{7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
{7: }xx |
- {10:=>}^mmmm |
+ {100:=>}^mmmm |
{7: }yyyy |
{1:~ }|
|
@@ -48,7 +51,7 @@ describe('signs', function()
screen:expect([[
{7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
{7: }xx |
- {10:-)}^mmmm |
+ {100:-)}^mmmm |
{7: }yyyy |
{1:~ }|
|
@@ -59,7 +62,7 @@ describe('signs', function()
screen:expect([[
{7: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
{7: }xx |
- {10:-)}{4:^mmmm }|
+ {100:-)}{4:^mmmm }|
{7: }yyyy |
{1:~ }|
|
diff --git a/test/functional/legacy/substitute_spec.lua b/test/functional/legacy/substitute_spec.lua
index 0081371f7f..30ff13140f 100644
--- a/test/functional/legacy/substitute_spec.lua
+++ b/test/functional/legacy/substitute_spec.lua
@@ -220,8 +220,10 @@ describe(':substitute', function()
{2:o}ne |
two |
three |
- {1:~ }|*4
- {6:replace with (y/n/a/q/l/^E/^Y)?}^ |
+ {1:~ }|*2
+ {3: }|
+ {6:replace with ? (y)es/(n)o/(a)ll/(q)uit/(l)ast/scroll up(^}|
+ {6:E)/down(^Y)}^ |
]])
end)
end)
diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua
index d68c780f49..fac982354c 100644
--- a/test/functional/legacy/window_cmd_spec.lua
+++ b/test/functional/legacy/window_cmd_spec.lua
@@ -120,7 +120,7 @@ describe('splitkeep', function()
row = 0,
col = 0,
}))
- vim.cmd("call termopen([&sh, &shcf, 'true'], { 'on_exit': 'C2' })")
+ vim.cmd("call jobstart([&sh, &shcf, 'true'], { 'term': v:true, 'on_exit': 'C2' })")
end
})]])
feed('j')
@@ -299,7 +299,7 @@ describe('splitkeep', function()
c |
{1:~ }|
{3:[No Name] }|
- |
+ :call win_move_statusline(win, 1) |
]])
end)
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index eb1ac3e6a1..a19f558ef2 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -5,6 +5,7 @@ local command = n.command
local clear = n.clear
local exec_lua = n.exec_lua
local eq = t.eq
+local neq = t.neq
local matches = t.matches
local api = n.api
local pcall_err = t.pcall_err
@@ -112,6 +113,18 @@ describe('vim.diagnostic', function()
)
end
+ function _G.get_virt_lines_extmarks(ns)
+ ns = vim.diagnostic.get_namespace(ns)
+ local virt_lines_ns = ns.user_data.virt_lines_ns
+ return vim.api.nvim_buf_get_extmarks(
+ _G.diagnostic_bufnr,
+ virt_lines_ns,
+ 0,
+ -1,
+ { details = true }
+ )
+ end
+
---@param ns integer
function _G.get_underline_extmarks(ns)
---@type integer
@@ -160,6 +173,11 @@ describe('vim.diagnostic', function()
'DiagnosticUnderlineOk',
'DiagnosticUnderlineWarn',
'DiagnosticUnnecessary',
+ 'DiagnosticVirtualLinesError',
+ 'DiagnosticVirtualLinesHint',
+ 'DiagnosticVirtualLinesInfo',
+ 'DiagnosticVirtualLinesOk',
+ 'DiagnosticVirtualLinesWarn',
'DiagnosticVirtualTextError',
'DiagnosticVirtualTextHint',
'DiagnosticVirtualTextInfo',
@@ -368,6 +386,9 @@ describe('vim.diagnostic', function()
end)
it('handles one namespace clearing highlights while the other still has highlights', function()
+ exec_lua(function()
+ vim.diagnostic.config({ virtual_text = true })
+ end)
-- 1 Error (1)
-- 1 Warning (2)
-- 1 Warning (2) + 1 Warning (1)
@@ -442,6 +463,10 @@ describe('vim.diagnostic', function()
end)
it('does not display diagnostics when disabled', function()
+ exec_lua(function()
+ vim.diagnostic.config({ virtual_text = true })
+ end)
+
eq(
{ 0, 2 },
exec_lua(function()
@@ -574,7 +599,7 @@ describe('vim.diagnostic', function()
vim.diagnostic.set(
_G.diagnostic_ns,
_G.diagnostic_bufnr,
- { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
+ { { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
)
vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
@@ -915,6 +940,10 @@ describe('vim.diagnostic', function()
describe('reset()', function()
it('diagnostic count is 0 and displayed diagnostics are 0 after call', function()
+ exec_lua(function()
+ vim.diagnostic.config({ virtual_text = true })
+ end)
+
-- 1 Error (1)
-- 1 Warning (2)
-- 1 Warning (2) + 1 Warning (1)
@@ -1005,7 +1034,7 @@ describe('vim.diagnostic', function()
vim.diagnostic.set(
_G.diagnostic_ns,
_G.diagnostic_bufnr,
- { { lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
+ { { message = '', lnum = 0, end_lnum = 0, col = 0, end_col = 0 } }
)
vim.cmd('bwipeout! ' .. _G.diagnostic_bufnr)
@@ -2105,6 +2134,139 @@ describe('vim.diagnostic', function()
end)
)
end)
+
+ it('can filter diagnostics by returning nil when formatting', function()
+ local result = exec_lua(function()
+ vim.diagnostic.config {
+ virtual_text = {
+ format = function(diagnostic)
+ if diagnostic.code == 'foo_err' then
+ return nil
+ end
+ return diagnostic.message
+ end,
+ },
+ }
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('An error here!', 0, 0, 0, 0, 'foo_server', 'foo_err'),
+ _G.make_error('An error there!', 1, 1, 1, 1, 'bar_server', 'bar_err'),
+ })
+
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ return extmarks
+ end)
+
+ eq(1, #result)
+ eq(' An error there!', result[1][4].virt_text[3][1])
+ end)
+
+ it('can only show virtual_text for the current line', function()
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+
+ vim.diagnostic.config({ virtual_text = { current_line = true } })
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'),
+ _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'),
+ })
+
+ local extmarks = _G.get_virt_text_extmarks(_G.diagnostic_ns)
+ return extmarks
+ end)
+
+ eq(1, #result)
+ eq(' Error here!', result[1][4].virt_text[3][1])
+ end)
+ end)
+
+ describe('handlers.virtual_lines', function()
+ it('includes diagnostic code and message', function()
+ local result = exec_lua(function()
+ vim.diagnostic.config({ virtual_lines = true })
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Missed symbol `,`', 0, 0, 0, 0, 'lua_ls', 'miss-symbol'),
+ })
+
+ local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
+ return extmarks[1][4].virt_lines
+ end)
+
+ eq('miss-symbol: Missed symbol `,`', result[1][3][1])
+ end)
+
+ it('adds space to the left of the diagnostic', function()
+ local error_offset = 5
+ local result = exec_lua(function()
+ vim.diagnostic.config({ virtual_lines = true })
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error here!', 0, error_offset, 0, error_offset, 'foo_server'),
+ })
+
+ local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
+ return extmarks[1][4].virt_lines
+ end)
+
+ eq(error_offset, result[1][1][1]:len())
+ end)
+
+ it('highlights diagnostics in multiple lines by default', function()
+ local result = exec_lua(function()
+ vim.diagnostic.config({ virtual_lines = true })
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'),
+ _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'),
+ })
+
+ local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
+ return extmarks
+ end)
+
+ eq(2, #result)
+ eq('Error here!', result[1][4].virt_lines[1][3][1])
+ eq('Another error there!', result[2][4].virt_lines[1][3][1])
+ end)
+
+ it('can highlight diagnostics only in the current line', function()
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_cursor(0, { 1, 0 })
+
+ vim.diagnostic.config({ virtual_lines = { current_line = true } })
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error here!', 0, 0, 0, 0, 'foo_server'),
+ _G.make_error('Another error there!', 1, 0, 1, 0, 'foo_server'),
+ })
+
+ local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
+ return extmarks
+ end)
+
+ eq(1, #result)
+ eq('Error here!', result[1][4].virt_lines[1][3][1])
+ end)
+
+ it('supports a format function for diagnostic messages', function()
+ local result = exec_lua(function()
+ vim.diagnostic.config({
+ virtual_lines = {
+ format = function()
+ return 'Error here!'
+ end,
+ },
+ })
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Invalid syntax', 0, 0, 0, 0),
+ })
+ local extmarks = _G.get_virt_lines_extmarks(_G.diagnostic_ns)
+ return extmarks[1][4].virt_lines
+ end)
+ eq('Error here!', result[1][3][1])
+ end)
end)
describe('set()', function()
@@ -2116,7 +2278,11 @@ describe('vim.diagnostic', function()
end)
it('can perform updates after insert_leave', function()
- exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
+ exec_lua(function()
+ vim.diagnostic.config({ virtual_text = true })
+ vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
+ end)
+
api.nvim_input('o')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
@@ -2257,7 +2423,10 @@ describe('vim.diagnostic', function()
end)
it('can perform updates while in insert mode, if desired', function()
- exec_lua [[vim.api.nvim_set_current_buf( _G.diagnostic_bufnr)]]
+ exec_lua(function()
+ vim.diagnostic.config({ virtual_text = true })
+ vim.api.nvim_set_current_buf(_G.diagnostic_bufnr)
+ end)
api.nvim_input('o')
eq({ mode = 'i', blocking = false }, api.nvim_get_mode())
@@ -2291,6 +2460,10 @@ describe('vim.diagnostic', function()
end)
it('can set diagnostics without displaying them', function()
+ exec_lua(function()
+ vim.diagnostic.config({ virtual_text = true })
+ end)
+
eq(
0,
exec_lua(function()
@@ -3212,6 +3385,74 @@ describe('vim.diagnostic', function()
end)
end)
+ describe('setqflist()', function()
+ it('updates existing diagnostics quickfix if one already exists', function()
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+
+ vim.fn.setqflist({}, ' ', { title = 'Diagnostics' })
+ local diagnostics_qf_id = vim.fn.getqflist({ id = 0 }).id
+
+ vim.diagnostic.setqflist({ title = 'Diagnostics' })
+ local qf_id = vim.fn.getqflist({ id = 0, nr = '$' }).id
+
+ return { diagnostics_qf_id, qf_id }
+ end)
+
+ eq(result[1], result[2])
+ end)
+
+ it('navigates to existing diagnostics quickfix if one already exists and open=true', function()
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+
+ vim.fn.setqflist({}, ' ', { title = 'Diagnostics' })
+ local diagnostics_qf_id = vim.fn.getqflist({ id = 0 }).id
+
+ vim.fn.setqflist({}, ' ', { title = 'Other' })
+
+ vim.diagnostic.setqflist({ title = 'Diagnostics', open = true })
+ local qf_id = vim.fn.getqflist({ id = 0 }).id
+
+ return { diagnostics_qf_id, qf_id }
+ end)
+
+ eq(result[1], result[2])
+ end)
+
+ it('sets new diagnostics quickfix as active when open=true', function()
+ local result = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+
+ vim.fn.setqflist({}, ' ', { title = 'Other' })
+ local other_qf_id = vim.fn.getqflist({ id = 0 }).id
+
+ vim.diagnostic.setqflist({ title = 'Diagnostics', open = true })
+ local qf_id = vim.fn.getqflist({ id = 0 }).id
+
+ return { other_qf_id, qf_id }
+ end)
+
+ neq(result[1], result[2])
+ end)
+
+ it('opens quickfix window when open=true', function()
+ local qf_winid = exec_lua(function()
+ vim.api.nvim_win_set_buf(0, _G.diagnostic_bufnr)
+
+ vim.diagnostic.set(_G.diagnostic_ns, _G.diagnostic_bufnr, {
+ _G.make_error('Error', 1, 1, 1, 1),
+ })
+
+ vim.diagnostic.setqflist({ open = true })
+
+ return vim.fn.getqflist({ winid = 0 }).winid
+ end)
+
+ neq(0, qf_winid)
+ end)
+ end)
+
describe('match()', function()
it('matches a string', function()
local msg = 'ERROR: george.txt:19:84:Two plus two equals five'
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index b6011d5268..b75ff75b05 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -199,7 +199,19 @@ describe('filetype.lua', function()
finally(function()
uv.fs_unlink('Xfiletype/.config/git')
end)
- clear({ args = { '--clean', 'Xfiletype/.config/git/config' } })
+ local args = { '--clean', 'Xfiletype/.config/git/config' }
+ clear({ args = args })
eq('gitconfig', api.nvim_get_option_value('filetype', {}))
+ table.insert(args, 2, '--cmd')
+ table.insert(args, 3, "autocmd BufRead * call expand('<afile>')")
+ clear({ args = args })
+ eq('gitconfig', api.nvim_get_option_value('filetype', {}))
+ end)
+
+ it('works with :doautocmd BufRead #31306', function()
+ clear({ args = { '--clean' } })
+ eq('', api.nvim_get_option_value('filetype', {}))
+ command('doautocmd BufRead README.md')
+ eq('markdown', api.nvim_get_option_value('filetype', {}))
end)
end)
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
index f0d49205e7..33af25f629 100644
--- a/test/functional/lua/fs_spec.lua
+++ b/test/functional/lua/fs_spec.lua
@@ -17,6 +17,8 @@ local mkdir = t.mkdir
local nvim_prog_basename = is_os('win') and 'nvim.exe' or 'nvim'
+local link_limit = is_os('win') and 64 or (is_os('mac') or is_os('bsd')) and 33 or 41
+
local test_basename_dirname_eq = {
'~/foo/',
'~/foo',
@@ -152,7 +154,7 @@ describe('vim.fs', function()
)
end)
- it('works with opts.depth and opts.skip', function()
+ it('works with opts.depth, opts.skip and opts.follow', function()
io.open('testd/a1', 'w'):close()
io.open('testd/b1', 'w'):close()
io.open('testd/c1', 'w'):close()
@@ -166,10 +168,10 @@ describe('vim.fs', function()
io.open('testd/a/b/c/b4', 'w'):close()
io.open('testd/a/b/c/c4', 'w'):close()
- local function run(dir, depth, skip)
- return exec_lua(function()
- local r = {}
- local skip_f
+ local function run(dir, depth, skip, follow)
+ return exec_lua(function(follow_)
+ local r = {} --- @type table<string, string>
+ local skip_f --- @type function
if skip then
skip_f = function(n0)
if vim.tbl_contains(skip or {}, n0) then
@@ -177,11 +179,11 @@ describe('vim.fs', function()
end
end
end
- for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f }) do
+ for name, type_ in vim.fs.dir(dir, { depth = depth, skip = skip_f, follow = follow_ }) do
r[name] = type_
end
return r
- end)
+ end, follow)
end
local exp = {}
@@ -197,6 +199,7 @@ describe('vim.fs', function()
exp['a/b2'] = 'file'
exp['a/c2'] = 'file'
exp['a/b'] = 'directory'
+ local lexp = vim.deepcopy(exp)
eq(exp, run('testd', 2))
@@ -213,6 +216,29 @@ describe('vim.fs', function()
exp['a/b/c/c4'] = 'file'
eq(exp, run('testd', 999))
+
+ vim.uv.fs_symlink(vim.uv.fs_realpath('testd/a'), 'testd/l', { junction = true, dir = true })
+ lexp['l'] = 'link'
+ eq(lexp, run('testd', 2, nil, false))
+
+ lexp['l/a2'] = 'file'
+ lexp['l/b2'] = 'file'
+ lexp['l/c2'] = 'file'
+ lexp['l/b'] = 'directory'
+ eq(lexp, run('testd', 2, nil, true))
+ end)
+
+ it('follow=true handles symlink loop', function()
+ local cwd = 'testd/a/b/c'
+ local symlink = cwd .. '/link_loop' ---@type string
+ vim.uv.fs_symlink(vim.uv.fs_realpath(cwd), symlink, { junction = true, dir = true })
+
+ eq(
+ link_limit,
+ exec_lua(function()
+ return #vim.iter(vim.fs.dir(cwd, { depth = math.huge, follow = true })):totable()
+ end)
+ )
end)
end)
@@ -228,6 +254,53 @@ describe('vim.fs', function()
eq({ nvim_dir }, vim.fs.find(name, { path = parent, upward = true, type = 'directory' }))
end)
+ it('follows symlinks', function()
+ local build_dir = test_source_path .. '/build' ---@type string
+ local symlink = test_source_path .. '/build_link' ---@type string
+ vim.uv.fs_symlink(build_dir, symlink, { junction = true, dir = true })
+
+ finally(function()
+ vim.uv.fs_unlink(symlink)
+ end)
+
+ eq(
+ { nvim_prog, symlink .. '/bin/' .. nvim_prog_basename },
+ vim.fs.find(nvim_prog_basename, {
+ path = test_source_path,
+ type = 'file',
+ limit = 2,
+ follow = true,
+ })
+ )
+
+ eq(
+ { nvim_prog },
+ vim.fs.find(nvim_prog_basename, {
+ path = test_source_path,
+ type = 'file',
+ limit = 2,
+ follow = false,
+ })
+ )
+ end)
+
+ it('follow=true handles symlink loop', function()
+ local cwd = test_source_path ---@type string
+ local symlink = test_source_path .. '/loop_link' ---@type string
+ vim.uv.fs_symlink(cwd, symlink, { junction = true, dir = true })
+
+ finally(function()
+ vim.uv.fs_unlink(symlink)
+ end)
+
+ eq(link_limit, #vim.fs.find(nvim_prog_basename, {
+ path = test_source_path,
+ type = 'file',
+ limit = math.huge,
+ follow = true,
+ }))
+ end)
+
it('accepts predicate as names', function()
local opts = { path = nvim_dir, upward = true, type = 'directory' }
eq(
@@ -273,14 +346,14 @@ describe('vim.fs', function()
end)
it('works with a single marker', function()
- eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
+ eq(test_source_path, exec_lua([[return vim.fs.root(0, 'CMakePresets.json')]]))
end)
it('works with multiple markers', function()
local bufnr = api.nvim_get_current_buf()
eq(
vim.fs.joinpath(test_source_path, 'test/functional/fixtures'),
- exec_lua([[return vim.fs.root(..., {'CMakeLists.txt', '.git'})]], bufnr)
+ exec_lua([[return vim.fs.root(..., {'CMakeLists.txt', 'CMakePresets.json'})]], bufnr)
)
end)
@@ -295,26 +368,26 @@ describe('vim.fs', function()
end)
it('works with a filename argument', function()
- eq(test_source_path, exec_lua([[return vim.fs.root(..., '.git')]], nvim_prog))
+ eq(test_source_path, exec_lua([[return vim.fs.root(..., 'CMakePresets.json')]], nvim_prog))
end)
it('works with a relative path', function()
eq(
test_source_path,
- exec_lua([[return vim.fs.root(..., '.git')]], vim.fs.basename(nvim_prog))
+ exec_lua([[return vim.fs.root(..., 'CMakePresets.json')]], vim.fs.basename(nvim_prog))
)
end)
it('uses cwd for unnamed buffers', function()
command('new')
- eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
+ eq(test_source_path, exec_lua([[return vim.fs.root(0, 'CMakePresets.json')]]))
end)
it("uses cwd for buffers with non-empty 'buftype'", function()
command('new')
command('set buftype=nofile')
command('file lua://')
- eq(test_source_path, exec_lua([[return vim.fs.root(0, '.git')]]))
+ eq(test_source_path, exec_lua([[return vim.fs.root(0, 'CMakePresets.json')]]))
end)
end)
@@ -323,6 +396,20 @@ describe('vim.fs', function()
eq('foo/bar/baz', vim.fs.joinpath('foo', 'bar', 'baz'))
eq('foo/bar/baz', vim.fs.joinpath('foo', '/bar/', '/baz'))
end)
+ it('rewrites backslashes on Windows', function()
+ if is_os('win') then
+ eq('foo/bar/baz/zub/', vim.fs.joinpath([[foo]], [[\\bar\\\\baz]], [[zub\]]))
+ else
+ eq([[foo/\\bar\\\\baz/zub\]], vim.fs.joinpath([[foo]], [[\\bar\\\\baz]], [[zub\]]))
+ end
+ end)
+ it('strips redundant slashes', function()
+ if is_os('win') then
+ eq('foo/bar/baz/zub/', vim.fs.joinpath([[foo//]], [[\\bar\\\\baz]], [[zub\]]))
+ else
+ eq('foo/bar/baz/zub/', vim.fs.joinpath([[foo]], [[//bar////baz]], [[zub/]]))
+ end
+ end)
end)
describe('normalize()', function()
@@ -347,8 +434,8 @@ describe('vim.fs', function()
end)
-- Opts required for testing posix paths and win paths
- local posix_opts = is_os('win') and { win = false } or {}
- local win_opts = is_os('win') and {} or { win = true }
+ local posix_opts = { win = false }
+ local win_opts = { win = true }
it('preserves leading double slashes in POSIX paths', function()
eq('//foo', vim.fs.normalize('//foo', posix_opts))
@@ -359,6 +446,29 @@ describe('vim.fs', function()
eq('/foo/bar', vim.fs.normalize('/foo//bar////', posix_opts))
end)
+ it('normalizes drive letter', function()
+ eq('C:/', vim.fs.normalize('C:/', win_opts))
+ eq('C:/', vim.fs.normalize('c:/', win_opts))
+ eq('D:/', vim.fs.normalize('d:/', win_opts))
+ eq('C:', vim.fs.normalize('C:', win_opts))
+ eq('C:', vim.fs.normalize('c:', win_opts))
+ eq('D:', vim.fs.normalize('d:', win_opts))
+ eq('C:/foo/test', vim.fs.normalize('C:/foo/test/', win_opts))
+ eq('C:/foo/test', vim.fs.normalize('c:/foo/test/', win_opts))
+ eq('D:foo/test', vim.fs.normalize('D:foo/test/', win_opts))
+ eq('D:foo/test', vim.fs.normalize('d:foo/test/', win_opts))
+ end)
+
+ it('always treats paths as case-sensitive #31833', function()
+ eq('TEST', vim.fs.normalize('TEST', win_opts))
+ eq('test', vim.fs.normalize('test', win_opts))
+ eq('C:/FOO/test', vim.fs.normalize('C:/FOO/test', win_opts))
+ eq('C:/foo/test', vim.fs.normalize('C:/foo/test', win_opts))
+ eq('//SERVER/SHARE/FOO/BAR', vim.fs.normalize('//SERVER/SHARE/FOO/BAR', win_opts))
+ eq('//server/share/foo/bar', vim.fs.normalize('//server/share/foo/bar', win_opts))
+ eq('C:/FOO/test', vim.fs.normalize('c:/FOO/test', win_opts))
+ end)
+
it('allows backslashes on unix-based os', function()
eq('/home/user/hello\\world', vim.fs.normalize('/home/user/hello\\world', posix_opts))
end)
@@ -454,4 +564,92 @@ describe('vim.fs', function()
end)
end)
end)
+
+ describe('abspath()', function()
+ local cwd = assert(t.fix_slashes(assert(vim.uv.cwd())))
+ local home = t.fix_slashes(assert(vim.uv.os_homedir()))
+
+ it('works', function()
+ eq(cwd .. '/foo', vim.fs.abspath('foo'))
+ eq(cwd .. '/././foo', vim.fs.abspath('././foo'))
+ eq(cwd .. '/.././../foo', vim.fs.abspath('.././../foo'))
+ end)
+
+ it('works with absolute paths', function()
+ if is_os('win') then
+ eq([[C:/foo]], vim.fs.abspath([[C:\foo]]))
+ eq([[C:/foo/../.]], vim.fs.abspath([[C:\foo\..\.]]))
+ eq('//foo/bar', vim.fs.abspath('\\\\foo\\bar'))
+ else
+ eq('/foo/../.', vim.fs.abspath('/foo/../.'))
+ eq('/foo/bar', vim.fs.abspath('/foo/bar'))
+ end
+ end)
+
+ it('expands ~', function()
+ eq(home .. '/foo', vim.fs.abspath('~/foo'))
+ eq(home .. '/./.././foo', vim.fs.abspath('~/./.././foo'))
+ end)
+
+ if is_os('win') then
+ it('works with drive-specific cwd on Windows', function()
+ local cwd_drive = cwd:match('^%w:')
+
+ eq(cwd .. '/foo', vim.fs.abspath(cwd_drive .. 'foo'))
+ end)
+ end
+ end)
+
+ describe('relpath()', function()
+ it('works', function()
+ local cwd = assert(t.fix_slashes(assert(vim.uv.cwd())))
+ local my_dir = vim.fs.joinpath(cwd, 'foo')
+
+ eq(nil, vim.fs.relpath('/var/lib', '/var'))
+ eq(nil, vim.fs.relpath('/var/lib', '/bin'))
+ eq(nil, vim.fs.relpath(my_dir, 'bin'))
+ eq(nil, vim.fs.relpath(my_dir, './bin'))
+ eq(nil, vim.fs.relpath(my_dir, '././'))
+ eq(nil, vim.fs.relpath(my_dir, '../'))
+ eq(nil, vim.fs.relpath('/var/lib', '/'))
+ eq(nil, vim.fs.relpath('/var/lib', '//'))
+ eq(nil, vim.fs.relpath(' ', '/var'))
+ eq(nil, vim.fs.relpath(' ', '/var'))
+ eq('.', vim.fs.relpath('/var/lib', '/var/lib'))
+ eq('lib', vim.fs.relpath('/var/', '/var/lib'))
+ eq('var/lib', vim.fs.relpath('/', '/var/lib'))
+ eq('bar/package.json', vim.fs.relpath('/foo/test', '/foo/test/bar/package.json'))
+ eq('foo/bar', vim.fs.relpath(cwd, 'foo/bar'))
+ eq('foo/bar', vim.fs.relpath('.', vim.fs.joinpath(cwd, 'foo/bar')))
+ eq('bar', vim.fs.relpath('foo', 'foo/bar'))
+ eq(nil, vim.fs.relpath('/var/lib', '/var/library/foo'))
+
+ if is_os('win') then
+ eq(nil, vim.fs.relpath('/', ' '))
+ eq(nil, vim.fs.relpath('/', 'var'))
+ else
+ local cwd_rel_root = cwd:sub(2)
+ eq(cwd_rel_root .. '/ ', vim.fs.relpath('/', ' '))
+ eq(cwd_rel_root .. '/var', vim.fs.relpath('/', 'var'))
+ end
+
+ if is_os('win') then
+ eq(nil, vim.fs.relpath('c:/aaaa/', '/aaaa/cccc'))
+ eq(nil, vim.fs.relpath('c:/aaaa/', './aaaa/cccc'))
+ eq(nil, vim.fs.relpath('c:/aaaa/', 'aaaa/cccc'))
+ eq(nil, vim.fs.relpath('c:/blah\\blah', 'd:/games'))
+ eq(nil, vim.fs.relpath('c:/games', 'd:/games'))
+ eq(nil, vim.fs.relpath('c:/games', 'd:/games/foo'))
+ eq(nil, vim.fs.relpath('c:/aaaa/bbbb', 'c:/aaaa'))
+ eq('cccc', vim.fs.relpath('c:/aaaa/', 'c:/aaaa/cccc'))
+ eq('aaaa/bbbb', vim.fs.relpath('C:/', 'c:\\aaaa\\bbbb'))
+ eq('bar/package.json', vim.fs.relpath('C:\\foo\\test', 'C:\\foo\\test\\bar\\package.json'))
+ eq('baz', vim.fs.relpath('\\\\foo\\bar', '\\\\foo\\bar\\baz'))
+ eq(nil, vim.fs.relpath('a/b/c', 'a\\b'))
+ eq('d', vim.fs.relpath('a/b/c', 'a\\b\\c\\d'))
+ eq('.', vim.fs.relpath('\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz'))
+ eq(nil, vim.fs.relpath('C:\\foo\\test', 'C:\\foo\\Test\\bar\\package.json'))
+ end
+ end)
+ end)
end)
diff --git a/test/functional/lua/func_memoize_spec.lua b/test/functional/lua/func_memoize_spec.lua
new file mode 100644
index 0000000000..ca518ab88d
--- /dev/null
+++ b/test/functional/lua/func_memoize_spec.lua
@@ -0,0 +1,142 @@
+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('vim.func._memoize', function()
+ before_each(clear)
+
+ it('caches function results based on their parameters', function()
+ exec_lua([[
+ _G.count = 0
+
+ local adder = vim.func._memoize('concat', function(arg1, arg2)
+ _G.count = _G.count + 1
+ return arg1 + arg2
+ end)
+
+ collectgarbage('stop')
+ adder(3, -4)
+ adder(3, -4)
+ adder(3, -4)
+ adder(3, -4)
+ adder(3, -4)
+ collectgarbage('restart')
+ ]])
+
+ eq(1, exec_lua([[return _G.count]]))
+ end)
+
+ it('caches function results using a weak table by default', function()
+ exec_lua([[
+ _G.count = 0
+
+ local adder = vim.func._memoize('concat-2', function(arg1, arg2)
+ _G.count = _G.count + 1
+ return arg1 + arg2
+ end)
+
+ adder(3, -4)
+ collectgarbage()
+ adder(3, -4)
+ collectgarbage()
+ adder(3, -4)
+ ]])
+
+ eq(3, exec_lua([[return _G.count]]))
+ end)
+
+ it('can cache using a strong table', function()
+ exec_lua([[
+ _G.count = 0
+
+ local adder = vim.func._memoize('concat-2', function(arg1, arg2)
+ _G.count = _G.count + 1
+ return arg1 + arg2
+ end, false)
+
+ adder(3, -4)
+ collectgarbage()
+ adder(3, -4)
+ collectgarbage()
+ adder(3, -4)
+ ]])
+
+ eq(1, exec_lua([[return _G.count]]))
+ end)
+
+ it('can clear a single cache entry', function()
+ exec_lua([[
+ _G.count = 0
+
+ local adder = vim.func._memoize(function(arg1, arg2)
+ return tostring(arg1) .. '%%' .. tostring(arg2)
+ end, function(arg1, arg2)
+ _G.count = _G.count + 1
+ return arg1 + arg2
+ end)
+
+ collectgarbage('stop')
+ adder(3, -4)
+ adder(3, -4)
+ adder(3, -4)
+ adder(3, -4)
+ adder(3, -4)
+ adder:clear(3, -4)
+ adder(3, -4)
+ collectgarbage('restart')
+ ]])
+
+ eq(2, exec_lua([[return _G.count]]))
+ end)
+
+ it('can clear the entire cache', function()
+ exec_lua([[
+ _G.count = 0
+
+ local adder = vim.func._memoize(function(arg1, arg2)
+ return tostring(arg1) .. '%%' .. tostring(arg2)
+ end, function(arg1, arg2)
+ _G.count = _G.count + 1
+ return arg1 + arg2
+ end)
+
+ collectgarbage('stop')
+ adder(1, 2)
+ adder(3, -4)
+ adder(1, 2)
+ adder(3, -4)
+ adder(1, 2)
+ adder(3, -4)
+ adder:clear()
+ adder(1, 2)
+ adder(3, -4)
+ collectgarbage('restart')
+ ]])
+
+ eq(4, exec_lua([[return _G.count]]))
+ end)
+
+ it('can cache functions that return nil', function()
+ exec_lua([[
+ _G.count = 0
+
+ local adder = vim.func._memoize('concat', function(arg1, arg2)
+ _G.count = _G.count + 1
+ return nil
+ end)
+
+ collectgarbage('stop')
+ adder(1, 2)
+ adder(1, 2)
+ adder(1, 2)
+ adder(1, 2)
+ adder:clear()
+ adder(1, 2)
+ collectgarbage('restart')
+ ]])
+
+ eq(2, exec_lua([[return _G.count]]))
+ end)
+end)
diff --git a/test/functional/lua/hl_spec.lua b/test/functional/lua/hl_spec.lua
index 89881973bf..512f6be48f 100644
--- a/test/functional/lua/hl_spec.lua
+++ b/test/functional/lua/hl_spec.lua
@@ -104,6 +104,33 @@ describe('vim.hl.range', function()
|
]])
end)
+
+ it('removes highlight after given `timeout`', function()
+ local timeout = 100
+ exec_lua(function()
+ local ns = vim.api.nvim_create_namespace('')
+ vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { timeout = timeout })
+ end)
+ screen:expect({
+ grid = [[
+ {10:^asdfghjkl}{100:$} |
+ {10:«口=口»}{100:$} |
+ {10:qwertyuiop}{100:$} |
+ {10:口口=口口}{1:$} |
+ zxcvbnm{1:$} |
+ |
+ ]],
+ timeout = timeout,
+ })
+ screen:expect([[
+ ^asdfghjkl{1:$} |
+ «口=口»{1:$} |
+ qwertyuiop{1:$} |
+ 口口=口口{1:$} |
+ zxcvbnm{1:$} |
+ |
+ ]])
+ end)
end)
describe('vim.hl.on_yank', function()
@@ -144,7 +171,7 @@ describe('vim.hl.on_yank', function()
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
end)
- local ns = api.nvim_create_namespace('hlyank')
+ local ns = api.nvim_create_namespace('nvim.hlyank')
local win = api.nvim_get_current_win()
eq({ win }, api.nvim__ns_get(ns).wins)
command('wincmd w')
@@ -158,7 +185,7 @@ describe('vim.hl.on_yank', function()
vim.api.nvim_buf_set_mark(0, ']', 1, 1, {})
vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } })
end)
- local ns = api.nvim_create_namespace('hlyank')
+ local ns = api.nvim_create_namespace('nvim.hlyank')
eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1])
command('wincmd w')
exec_lua(function()
diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua
index a6e814d739..e4a1df1d4c 100644
--- a/test/functional/lua/json_spec.lua
+++ b/test/functional/lua/json_spec.lua
@@ -152,6 +152,45 @@ describe('vim.json.encode()', function()
clear()
end)
+ it('escape_slash', function()
+ -- With slash
+ eq('"Test\\/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = true })]]))
+ eq(
+ 'Test/',
+ exec_lua([[return vim.json.decode(vim.json.encode('Test/', { escape_slash = true }))]])
+ )
+
+ -- Without slash
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/')]]))
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/', {})]]))
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/', { _invalid = true })]]))
+ eq('"Test/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = false })]]))
+ eq(
+ '"Test/"',
+ exec_lua([[return vim.json.encode('Test/', { _invalid = true, escape_slash = false })]])
+ )
+ eq(
+ 'Test/',
+ exec_lua([[return vim.json.decode(vim.json.encode('Test/', { escape_slash = false }))]])
+ )
+
+ -- Checks for for global side-effects
+ eq(
+ '"Test/"',
+ exec_lua([[
+ vim.json.encode('Test/', { escape_slash = true })
+ return vim.json.encode('Test/')
+ ]])
+ )
+ eq(
+ '"Test\\/"',
+ exec_lua([[
+ vim.json.encode('Test/', { escape_slash = false })
+ return vim.json.encode('Test/', { escape_slash = true })
+ ]])
+ )
+ end)
+
it('dumps strings', function()
eq('"Test"', exec_lua([[return vim.json.encode('Test')]]))
eq('""', exec_lua([[return vim.json.encode('')]]))
diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua
index 8508f2aa14..20d3a940b2 100644
--- a/test/functional/lua/loader_spec.lua
+++ b/test/functional/lua/loader_spec.lua
@@ -10,7 +10,17 @@ local eq = t.eq
describe('vim.loader', function()
before_each(clear)
- it('can work in compatibility with --luamod-dev #27413', function()
+ it('can be disabled', function()
+ exec_lua(function()
+ local orig_loader = _G.loadfile
+ vim.loader.enable()
+ assert(orig_loader ~= _G.loadfile)
+ vim.loader.enable(false)
+ assert(orig_loader == _G.loadfile)
+ end)
+ end)
+
+ it('works with --luamod-dev #27413', function()
clear({ args = { '--luamod-dev' } })
exec_lua(function()
vim.loader.enable()
@@ -31,7 +41,7 @@ describe('vim.loader', function()
end)
end)
- it('handles changing files (#23027)', function()
+ it('handles changing files #23027', function()
exec_lua(function()
vim.loader.enable()
end)
@@ -63,7 +73,7 @@ describe('vim.loader', function()
)
end)
- it('handles % signs in modpath (#24491)', function()
+ it('handles % signs in modpath #24491', function()
exec_lua [[
vim.loader.enable()
]]
@@ -82,7 +92,7 @@ describe('vim.loader', function()
eq(2, exec_lua('return loadfile(...)()', tmp2))
end)
- it('correct indent on error message (#29809)', function()
+ it('indents error message #29809', function()
local errmsg = exec_lua [[
vim.loader.enable()
local _, errmsg = pcall(require, 'non_existent_module')
diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua
index afbada007d..6c320376c9 100644
--- a/test/functional/lua/system_spec.lua
+++ b/test/functional/lua/system_spec.lua
@@ -18,8 +18,7 @@ local function system_sync(cmd, opts)
local res = obj:wait()
-- Check the process is no longer running
- local proc = vim.api.nvim_get_proc(obj.pid)
- assert(not proc, 'process still exists')
+ assert(not vim.api.nvim_get_proc(obj.pid), 'process still exists')
return res
end)
@@ -27,23 +26,23 @@ end
local function system_async(cmd, opts)
return exec_lua(function()
- _G.done = false
+ local done = false
+ local res --- @type vim.SystemCompleted?
local obj = vim.system(cmd, opts, function(obj)
- _G.done = true
- _G.ret = obj
+ done = true
+ res = obj
end)
local ok = vim.wait(10000, function()
- return _G.done
+ return done
end)
assert(ok, 'process did not exit')
-- Check the process is no longer running
- local proc = vim.api.nvim_get_proc(obj.pid)
- assert(not proc, 'process still exists')
+ assert(not vim.api.nvim_get_proc(obj.pid), 'process still exists')
- return _G.ret
+ return res
end)
end
@@ -114,10 +113,39 @@ describe('vim.system', function()
end)
if t.is_os('win') then
- it('can resolve windows command extentions.', function()
+ it('can resolve windows command extensions', function()
t.write_file('test.bat', 'echo hello world')
system_sync({ 'chmod', '+x', 'test.bat' })
system_sync({ './test' })
end)
end
+
+ it('always captures all content of stdout/stderr #30846', function()
+ t.skip(n.fn.executable('git') == 0, 'missing "git" command')
+ t.skip(n.fn.isdirectory('.git') == 0, 'missing ".git" directory')
+ eq(
+ 0,
+ exec_lua(function()
+ local done = 0
+ local fail = 0
+ for _ = 1, 200 do
+ vim.system(
+ { 'git', 'show', ':0:test/functional/plugin/lsp_spec.lua' },
+ { text = true },
+ function(o)
+ if o.code ~= 0 or #o.stdout == 0 then
+ fail = fail + 1
+ end
+ done = done + 1
+ end
+ )
+ end
+
+ local ok = vim.wait(10000, function()
+ return done == 200
+ end, 200)
+ return fail + (ok and 0 or 1)
+ end)
+ )
+ end)
end)
diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua
index be471bfd62..dd08a6ec04 100644
--- a/test/functional/lua/text_spec.lua
+++ b/test/functional/lua/text_spec.lua
@@ -26,5 +26,21 @@ describe('vim.text', function()
eq(output, vim.text.hexencode(input))
eq(input, vim.text.hexdecode(output))
end)
+
+ it('errors on invalid input', function()
+ -- Odd number of hex characters
+ do
+ local res, err = vim.text.hexdecode('ABC')
+ eq(nil, res)
+ eq('string must have an even number of hex characters', err)
+ end
+
+ -- Non-hexadecimal input
+ do
+ local res, err = vim.text.hexdecode('nothex')
+ eq(nil, res)
+ eq('string must contain only hex characters', err)
+ end
+ end)
end)
end)
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
index 310705fd97..8ca4bdc4f5 100644
--- a/test/functional/lua/thread_spec.lua
+++ b/test/functional/lua/thread_spec.lua
@@ -19,6 +19,26 @@ describe('thread', function()
screen = Screen.new(50, 10)
end)
+ it('handle non-string error', function()
+ exec_lua [[
+ local thread = vim.uv.new_thread(function()
+ error()
+ end)
+ vim.uv.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {3: }|
+ {9:Error in luv thread:} |
+ {9:[NULL]} |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+ assert_alive()
+ end)
+
it('entry func is executed in protected mode', function()
exec_lua [[
local thread = vim.uv.new_thread(function()
diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua
index c8616e3e11..ddb10127e4 100644
--- a/test/functional/lua/ui_event_spec.lua
+++ b/test/functional/lua/ui_event_spec.lua
@@ -106,20 +106,15 @@ describe('vim.ui_attach', function()
end)
it('does not crash on exit', function()
- fn.system({
- n.nvim_prog,
- '-u',
- 'NONE',
- '-i',
- 'NONE',
+ local p = n.spawn_wait(
'--cmd',
[[ lua ns = vim.api.nvim_create_namespace 'testspace' ]],
'--cmd',
[[ lua vim.ui_attach(ns, {ext_popupmenu=true}, function() end) ]],
'--cmd',
- 'quitall!',
- })
- eq(0, n.eval('v:shell_error'))
+ 'quitall!'
+ )
+ eq(0, p.status)
end)
it('can receive accurate message kinds even if they are history', function()
@@ -173,18 +168,67 @@ describe('vim.ui_attach', function()
vim.ui_attach(ns, { ext_messages = true }, function(ev)
if ev == 'msg_show' then
vim.schedule(function() vim.cmd.redraw() end)
- else
- vim.cmd.redraw()
+ elseif ev:find('cmdline') then
+ _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0)
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, { tostring(_G.cmdline) })
+ vim.cmd('redraw')
end
- _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0)
end
)]])
+ screen:expect([[
+ ^ |
+ {1:~ }|*4
+ ]])
feed(':')
- n.assert_alive()
- eq(2, exec_lua('return _G.cmdline'))
- n.assert_alive()
+ screen:expect({
+ grid = [[
+ ^1 |
+ {1:~ }|*4
+ ]],
+ cmdline = { {
+ content = { { '' } },
+ firstc = ':',
+ pos = 0,
+ } },
+ })
feed('version<CR><CR>v<Esc>')
- n.assert_alive()
+ screen:expect({
+ grid = [[
+ ^2 |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
+ feed([[:call confirm("Save changes?", "&Yes\n&No\n&Cancel")<CR>]])
+ screen:expect({
+ grid = [[
+ ^4 |
+ {1:~ }|*4
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 10,
+ pos = 0,
+ prompt = '[Y]es, (N)o, (C)ancel: ',
+ },
+ },
+ messages = {
+ {
+ content = { { '\nSave changes?\n', 6, 10 } },
+ history = false,
+ kind = 'confirm',
+ },
+ },
+ })
+ feed('n')
+ screen:expect({
+ grid = [[
+ ^4 |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
end)
it("preserved 'incsearch/command' screen state after :redraw from ext_cmdline", function()
@@ -261,30 +305,15 @@ describe('vim.ui_attach', function()
lled in a fast event context |
{1:~ }|
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 7 } },
+ content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 6 } },
+ history = true,
kind = 'emsg',
},
},
})
- -- No fast context for prompt message kinds
- feed(':%s/Function/Replacement/c<cr>')
- screen:expect({
- grid = [[
- ^E122: {10:Function} Foo already exists, add !|
- to replace it |
- replace with Replacement (y/n/a/q/l/^E/^|
- Y)? |
- {1:~ }|
- ]],
- messages = {
- {
- content = { { 'replace with Replacement (y/n/a/q/l/^E/^Y)?', 6, 19 } },
- kind = 'confirm_sub',
- },
- },
- })
end)
end)
@@ -316,30 +345,36 @@ describe('vim.ui_attach', function()
vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] })
end)
]])
+ local s1 = [[
+ ^ |
+ {1:~ }|*4
+ ]]
+ screen:expect(s1)
+ feed('QQQQQQ<CR>')
screen:expect({
grid = [[
- ^ |
- {1:~ }|*4
- ]],
- })
- feed('ifoo')
- screen:expect({
- grid = [[
- foo^ |
- {1:~ }|*4
- ]],
- showmode = { { '-- INSERT --', 5, 12 } },
- })
- feed('<esc>:1mes clear<cr>:mes<cr>')
- screen:expect({
- grid = [[
- foo |
- {3: }|
- {9:Excessive errors in vim.ui_attach() call}|
- {9:back from ns: 1.} |
+ {9:obal 'err' (a nil value)} |
+ {9:stack traceback:} |
+ {9: [string "<nvim>"]:2: in function}|
+ {9: <[string "<nvim>"]:1>} |
{100:Press ENTER or type command to continue}^ |
]],
+ messages = {
+ {
+ content = { { 'Press ENTER or type command to continue', 100, 18 } },
+ history = true,
+ kind = 'return_prompt',
+ },
+ },
})
+ feed(':1mes clear<CR>:mes<CR>')
+ screen:expect([[
+ |
+ {3: }|
+ {9:Excessive errors in vim.ui_attach() call}|
+ {9:back from ns: 1.} |
+ {100:Press ENTER or type command to continue}^ |
+ ]])
feed('<cr>')
-- Also when scheduled
exec_lua([[
@@ -348,16 +383,17 @@ describe('vim.ui_attach', function()
end)
]])
screen:expect({
- any = 'fo^o',
+ grid = s1,
messages = {
{
content = {
{
'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>',
9,
- 7,
+ 6,
},
},
+ history = true,
kind = 'lua_error',
},
{
@@ -365,26 +401,35 @@ describe('vim.ui_attach', function()
{
'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>',
9,
- 7,
+ 6,
},
},
+ history = true,
kind = 'lua_error',
},
{
- content = { { 'Press ENTER or type command to continue', 100, 19 } },
+ content = { { 'Press ENTER or type command to continue', 100, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
})
feed('<esc>:1mes clear<cr>:mes<cr>')
- screen:expect({
- grid = [[
- foo |
- {3: }|
- {9:Excessive errors in vim.ui_attach() call}|
- {9:back from ns: 2.} |
- {100:Press ENTER or type command to continue}^ |
- ]],
- })
+ screen:expect([[
+ |
+ {3: }|
+ {9:Excessive errors in vim.ui_attach() call}|
+ {9:back from ns: 2.} |
+ {100:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ it('sourcing invalid file does not crash #32166', function()
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace("")
+ vim.ui_attach(ns, { ext_messages = true }, function() end)
+ ]])
+ feed((':luafile %s<CR>'):format(testlog))
+ n.assert_alive()
end)
end)
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index 258b96bc43..d706f8b78b 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -252,4 +252,12 @@ describe('URI methods', function()
end
)
end)
+
+ describe('encode to uri', function()
+ it('rfc2732 including brackets', function()
+ exec_lua("str = '[:]'")
+ exec_lua("rfc = 'rfc2732'")
+ eq('[%3a]', exec_lua('return vim.uri_encode(str, rfc)'))
+ end)
+ end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 3cfbfe167a..55e5158596 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -3435,7 +3435,6 @@ stack traceback:
end)
it('can discard input', function()
- clear()
-- discard every other normal 'x' command
exec_lua [[
n_key = 0
@@ -3461,7 +3460,6 @@ stack traceback:
end)
it('callback invalid return', function()
- clear()
-- second key produces an error which removes the callback
exec_lua [[
n_call = 0
@@ -3955,6 +3953,17 @@ stack traceback:
eq(win2, val)
end)
+ it('failure modes', function()
+ matches(
+ 'nvim_exec2%(%): Vim:E492: Not an editor command: fooooo',
+ pcall_err(exec_lua, [[vim.api.nvim_win_call(0, function() vim.cmd 'fooooo' end)]])
+ )
+ eq(
+ 'Error executing lua: [string "<nvim>"]:0: fooooo',
+ pcall_err(exec_lua, [[vim.api.nvim_win_call(0, function() error('fooooo') end)]])
+ )
+ end)
+
it('does not cause ml_get errors with invalid visual selection', function()
-- Add lines to the current buffer and make another window looking into an empty buffer.
exec_lua [[
diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua
index ad16df8a7c..3b109b70d5 100644
--- a/test/functional/lua/watch_spec.lua
+++ b/test/functional/lua/watch_spec.lua
@@ -91,8 +91,7 @@ describe('vim._watch', function()
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')
+ skip(true, 'weird failure since macOS 14 CI, see bbf208784ca279178ba0075b60d3e9c80f11da7a')
else
skip(
is_os('bsd'),
diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua
index 6127e83619..92e798e7f3 100644
--- a/test/functional/lua/with_spec.lua
+++ b/test/functional/lua/with_spec.lua
@@ -1621,4 +1621,21 @@ describe('vim._with', function()
matches('Invalid buffer', get_error('{ buf = -1 }, function() end'))
matches('Invalid window', get_error('{ win = -1 }, function() end'))
end)
+
+ it('no double-free when called from :filter browse oldfiles #31501', function()
+ exec_lua([=[
+ vim.api.nvim_create_autocmd('BufEnter', {
+ callback = function()
+ vim._with({ lockmarks = true }, function() end)
+ end,
+ })
+ vim.cmd([[
+ let v:oldfiles = ['Xoldfile']
+ call nvim_input('1<CR>')
+ noswapfile filter /Xoldfile/ browse oldfiles
+ ]])
+ ]=])
+ n.assert_alive()
+ eq('Xoldfile', fn.bufname('%'))
+ end)
end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index e7f47ef4e9..a82279e775 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -14,7 +14,6 @@ local api = n.api
local command = n.command
local clear = n.clear
local exc_exec = n.exc_exec
-local exec_lua = n.exec_lua
local eval = n.eval
local eq = t.eq
local ok = t.ok
@@ -929,17 +928,12 @@ describe('stdpath()', function()
assert_alive() -- Check for crash. #8393
-- Check that Nvim rejects invalid APPNAMEs
- -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
local function test_appname(testAppname, expected_exitcode)
- local lua_code = string.format(
- [[
- local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '--listen', 'x', '+qall!' }, { env = { NVIM_APPNAME = %q } })
- return vim.fn.jobwait({ child }, %d)[1]
- ]],
- testAppname,
- 3000
- )
- eq(expected_exitcode, exec_lua(lua_code))
+ local p = n.spawn_wait({
+ args = { '--listen', 'x', '+qall!' },
+ env = { NVIM_APPNAME = testAppname },
+ })
+ eq(expected_exitcode, p.status)
end
-- Invalid appnames:
test_appname('a/../b', 1)
diff --git a/test/functional/options/winfixbuf_spec.lua b/test/functional/options/winfixbuf_spec.lua
index 124f194b5a..a01650ea71 100644
--- a/test/functional/options/winfixbuf_spec.lua
+++ b/test/functional/options/winfixbuf_spec.lua
@@ -1,55 +1,51 @@
local n = require('test.functional.testnvim')()
+local t = require('test.testutil')
local clear = n.clear
local exec_lua = n.exec_lua
-describe("Nvim API calls with 'winfixbuf'", function()
+describe("'winfixbuf'", function()
before_each(function()
clear()
end)
- it("Calling vim.api.nvim_win_set_buf with 'winfixbuf'", function()
- local results = exec_lua([[
- local function _setup_two_buffers()
- local buffer = vim.api.nvim_create_buf(true, true)
-
- vim.api.nvim_create_buf(true, true) -- Make another buffer
-
- local current_window = 0
- vim.api.nvim_set_option_value("winfixbuf", true, {win=current_window})
-
- return buffer
- end
-
- local other_buffer = _setup_two_buffers()
- local current_window = 0
- local results, _ = pcall(vim.api.nvim_win_set_buf, current_window, other_buffer)
-
- return results
+ ---@return integer
+ local function setup_winfixbuf()
+ return exec_lua([[
+ local buffer = vim.api.nvim_create_buf(true, true)
+ vim.api.nvim_create_buf(true, true) -- Make another buffer
+ vim.wo.winfixbuf = true
+ return buffer
]])
-
- assert(results == false)
+ end
+
+ it('nvim_win_set_buf on non-current buffer', function()
+ local other_buf = setup_winfixbuf()
+ t.eq(
+ "Vim:E1513: Cannot switch buffer. 'winfixbuf' is enabled",
+ t.pcall_err(n.api.nvim_win_set_buf, 0, other_buf)
+ )
end)
- it("Calling vim.api.nvim_set_current_buf with 'winfixbuf'", function()
- local results = exec_lua([[
- local function _setup_two_buffers()
- local buffer = vim.api.nvim_create_buf(true, true)
-
- vim.api.nvim_create_buf(true, true) -- Make another buffer
-
- local current_window = 0
- vim.api.nvim_set_option_value("winfixbuf", true, {win=current_window})
-
- return buffer
- end
-
- local other_buffer = _setup_two_buffers()
- local results, _ = pcall(vim.api.nvim_set_current_buf, other_buffer)
+ it('nvim_set_current_buf on non-current buffer', function()
+ local other_buf = setup_winfixbuf()
+ t.eq(
+ "Vim:E1513: Cannot switch buffer. 'winfixbuf' is enabled",
+ t.pcall_err(n.api.nvim_set_current_buf, other_buf)
+ )
+ end)
- return results
- ]])
+ it('nvim_win_set_buf on current buffer', function()
+ setup_winfixbuf()
+ local curbuf = n.api.nvim_get_current_buf()
+ n.api.nvim_win_set_buf(0, curbuf)
+ t.eq(curbuf, n.api.nvim_get_current_buf())
+ end)
- assert(results == false)
+ it('nvim_set_current_buf on current buffer', function()
+ setup_winfixbuf()
+ local curbuf = n.api.nvim_get_current_buf()
+ n.api.nvim_set_current_buf(curbuf)
+ t.eq(curbuf, n.api.nvim_get_current_buf())
end)
end)
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 753da64522..406b5c3c16 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -66,6 +66,18 @@ describe(':checkhealth', function()
eq({}, getcompletion('', 'checkhealth'))
assert_alive()
end)
+
+ it('vim.g.health', function()
+ clear()
+ command("let g:health = {'style':'float'}")
+ command('checkhealth lsp')
+ eq(
+ 'editor',
+ exec_lua([[
+ return vim.api.nvim_win_get_config(0).relative
+ ]])
+ )
+ end)
end)
describe('vim.health', function()
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index 39b6ddc105..4e90c2fd1b 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -216,6 +216,43 @@ describe('vim.lsp.completion: item conversion', function()
})
end)
+ it('uses filterText as word if label/newText would not match', function()
+ local items = {
+ {
+ filterText = '<module',
+ insertTextFormat = 2,
+ kind = 10,
+ label = 'module',
+ sortText = 'module',
+ textEdit = {
+ newText = '<module>$1</module>$0',
+ range = {
+ start = {
+ character = 0,
+ line = 0,
+ },
+ ['end'] = {
+ character = 0,
+ line = 0,
+ },
+ },
+ },
+ },
+ }
+ assert_completion_matches('<mo', items, {
+ {
+ abbr = 'module',
+ word = '<module',
+ },
+ })
+ assert_completion_matches('', items, {
+ {
+ abbr = 'module',
+ word = 'module',
+ },
+ })
+ end)
+
it('fuzzy matches on label when filterText is missing', function()
assert_completion_matches('fo', {
{ label = 'foo' },
@@ -731,9 +768,10 @@ describe('vim.lsp.completion: item conversion', function()
)
end)
+--- @param name string
--- @param completion_result lsp.CompletionList
--- @return integer
-local function create_server(completion_result)
+local function create_server(name, completion_result)
return exec_lua(function()
local server = _G._create_server({
capabilities = {
@@ -751,7 +789,7 @@ local function create_server(completion_result)
local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_win_set_buf(0, bufnr)
return vim.lsp.start({
- name = 'dummy',
+ name = name,
cmd = server.cmd,
on_attach = function(client, bufnr0)
vim.lsp.completion.enable(true, client.id, bufnr0, {
@@ -800,7 +838,7 @@ describe('vim.lsp.completion: protocol', function()
end
it('fetches completions and shows them using complete on trigger', function()
- create_server({
+ create_server('dummy', {
isIncomplete = false,
items = {
{
@@ -892,7 +930,7 @@ describe('vim.lsp.completion: protocol', function()
end)
it('merges results from multiple clients', function()
- create_server({
+ create_server('dummy1', {
isIncomplete = false,
items = {
{
@@ -900,7 +938,7 @@ describe('vim.lsp.completion: protocol', function()
},
},
})
- create_server({
+ create_server('dummy2', {
isIncomplete = false,
items = {
{
@@ -933,7 +971,7 @@ describe('vim.lsp.completion: protocol', function()
},
},
}
- local client_id = create_server(completion_list)
+ local client_id = create_server('dummy', completion_list)
exec_lua(function()
_G.called = false
@@ -970,7 +1008,7 @@ describe('vim.lsp.completion: protocol', function()
end)
it('enable(…,{convert=fn}) custom word/abbr format', function()
- create_server({
+ create_server('dummy', {
isIncomplete = false,
items = {
{
@@ -1012,7 +1050,7 @@ describe('vim.lsp.completion: integration', function()
exec_lua(function()
vim.o.completeopt = 'menuone,noselect'
end)
- create_server(completion_list)
+ create_server('dummy', completion_list)
feed('i world<esc>0ih<c-x><c-o>')
retry(nil, nil, function()
eq(
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 5afbe22793..4ecb056d01 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -89,7 +89,7 @@ describe('vim.lsp.diagnostic', function()
return extmarks
end
- client_id = assert(vim.lsp.start_client {
+ client_id = assert(vim.lsp.start({
cmd_env = {
NVIM_LUA_NOTRACK = '1',
},
@@ -101,7 +101,7 @@ describe('vim.lsp.diagnostic', function()
'--headless',
},
offset_encoding = 'utf-16',
- })
+ }, { attach = false }))
end)
fake_uri = 'file:///fake/uri'
@@ -209,10 +209,16 @@ describe('vim.lsp.diagnostic', function()
before_each(function()
exec_lua(create_server_definition)
exec_lua(function()
+ _G.requests = 0
_G.server = _G._create_server({
capabilities = {
diagnosticProvider = {},
},
+ handlers = {
+ [vim.lsp.protocol.Methods.textDocument_diagnostic] = function()
+ _G.requests = _G.requests + 1
+ end,
+ },
})
function _G.get_extmarks(bufnr, client_id0)
@@ -373,5 +379,56 @@ describe('vim.lsp.diagnostic', function()
end)
)
end)
+
+ it('handles server cancellation', function()
+ eq(
+ 1,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic({
+ code = vim.lsp.protocol.ErrorCodes.ServerCancelled,
+ -- Empty data defaults to retriggering request
+ data = {},
+ message = '',
+ }, {}, {
+ method = vim.lsp.protocol.Methods.textDocument_diagnostic,
+ client_id = client_id,
+ })
+
+ return _G.requests
+ end)
+ )
+
+ eq(
+ 2,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic({
+ code = vim.lsp.protocol.ErrorCodes.ServerCancelled,
+ data = { retriggerRequest = true },
+ message = '',
+ }, {}, {
+ method = vim.lsp.protocol.Methods.textDocument_diagnostic,
+ client_id = client_id,
+ })
+
+ return _G.requests
+ end)
+ )
+
+ eq(
+ 2,
+ exec_lua(function()
+ vim.lsp.diagnostic.on_diagnostic({
+ code = vim.lsp.protocol.ErrorCodes.ServerCancelled,
+ data = { retriggerRequest = false },
+ message = '',
+ }, {}, {
+ method = vim.lsp.protocol.Methods.textDocument_diagnostic,
+ client_id = client_id,
+ })
+
+ return _G.requests
+ end)
+ )
+ end)
end)
end)
diff --git a/test/functional/plugin/lsp/folding_range_spec.lua b/test/functional/plugin/lsp/folding_range_spec.lua
new file mode 100644
index 0000000000..7e68a598d2
--- /dev/null
+++ b/test/functional/plugin/lsp/folding_range_spec.lua
@@ -0,0 +1,647 @@
+local t = require('test.testutil')
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+local t_lsp = require('test.functional.plugin.lsp.testutil')
+
+local eq = t.eq
+local tempname = t.tmpname
+
+local clear_notrace = t_lsp.clear_notrace
+local create_server_definition = t_lsp.create_server_definition
+
+local api = n.api
+local exec_lua = n.exec_lua
+local insert = n.insert
+local command = n.command
+local feed = n.feed
+
+describe('vim.lsp.folding_range', function()
+ local text = [[// foldLevel() {{{2
+/// @return fold level at line number "lnum" in the current window.
+static int foldLevel(linenr_T lnum)
+{
+ // While updating the folds lines between invalid_top and invalid_bot have
+ // an undefined fold level. Otherwise update the folds first.
+ if (invalid_top == 0) {
+ checkupdate(curwin);
+ } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {
+ return prev_lnum_lvl;
+ } else if (lnum >= invalid_top && lnum <= invalid_bot) {
+ return -1;
+ }
+
+ // Return quickly when there is no folding at all in this window.
+ if (!hasAnyFolding(curwin)) {
+ return 0;
+ }
+
+ return foldLevelWin(curwin, lnum);
+}]]
+
+ local result = {
+ {
+ endLine = 19,
+ kind = 'region',
+ startCharacter = 1,
+ startLine = 3,
+ },
+ {
+ endCharacter = 2,
+ endLine = 7,
+ kind = 'region',
+ startCharacter = 25,
+ startLine = 6,
+ },
+ {
+ endCharacter = 2,
+ endLine = 9,
+ kind = 'region',
+ startCharacter = 55,
+ startLine = 8,
+ },
+ {
+ endCharacter = 2,
+ endLine = 11,
+ kind = 'region',
+ startCharacter = 58,
+ startLine = 10,
+ },
+ {
+ endCharacter = 2,
+ endLine = 16,
+ kind = 'region',
+ startCharacter = 31,
+ startLine = 15,
+ },
+ {
+ endCharacter = 68,
+ endLine = 1,
+ kind = 'comment',
+ startCharacter = 2,
+ startLine = 0,
+ },
+ {
+ endCharacter = 64,
+ endLine = 5,
+ kind = 'comment',
+ startCharacter = 4,
+ startLine = 4,
+ },
+ }
+
+ local bufnr ---@type integer
+ local client_id ---@type integer
+
+ clear_notrace()
+ before_each(function()
+ clear_notrace()
+
+ exec_lua(create_server_definition)
+ bufnr = n.api.nvim_get_current_buf()
+ client_id = exec_lua(function()
+ _G.server = _G._create_server({
+ capabilities = {
+ foldingRangeProvider = true,
+ },
+ handlers = {
+ ['textDocument/foldingRange'] = function(_, _, callback)
+ callback(nil, result)
+ end,
+ },
+ })
+
+ vim.api.nvim_win_set_buf(0, bufnr)
+
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd })
+ end)
+ command('set foldmethod=expr foldcolumn=1 foldlevel=999')
+ insert(text)
+ end)
+ after_each(function()
+ api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
+ end)
+
+ describe('setup()', function()
+ ---@type integer
+ local bufnr_set_expr
+ ---@type integer
+ local bufnr_never_set_expr
+
+ local function buf_autocmd_num(bufnr_to_check)
+ return exec_lua(function()
+ return #vim.api.nvim_get_autocmds({ buffer = bufnr_to_check, event = 'LspNotify' })
+ end)
+ end
+
+ before_each(function()
+ command([[setlocal foldexpr=v:lua.vim.lsp.foldexpr()]])
+ exec_lua(function()
+ bufnr_set_expr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(bufnr_set_expr)
+ end)
+ insert(text)
+ command('write ' .. tempname(false))
+ command([[setlocal foldexpr=v:lua.vim.lsp.foldexpr()]])
+ exec_lua(function()
+ bufnr_never_set_expr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(bufnr_never_set_expr)
+ end)
+ insert(text)
+ api.nvim_win_set_buf(0, bufnr_set_expr)
+ end)
+
+ it('only create event hooks where foldexpr has been set', function()
+ eq(1, buf_autocmd_num(bufnr))
+ eq(1, buf_autocmd_num(bufnr_set_expr))
+ eq(0, buf_autocmd_num(bufnr_never_set_expr))
+ end)
+
+ it('does not create duplicate event hooks after reloaded', function()
+ command('edit')
+ eq(1, buf_autocmd_num(bufnr_set_expr))
+ end)
+
+ it('cleans up event hooks when buffer is unloaded', function()
+ command('bdelete')
+ eq(0, buf_autocmd_num(bufnr_set_expr))
+ end)
+ end)
+
+ describe('expr()', function()
+ --- @type test.functional.ui.screen
+ local screen
+ before_each(function()
+ screen = Screen.new(80, 45)
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { bold = true, foreground = Screen.colors.Blue1 },
+ [3] = { bold = true, reverse = true },
+ [4] = { reverse = true },
+ })
+ command([[set foldexpr=v:lua.vim.lsp.foldexpr()]])
+ command([[split]])
+ end)
+
+ it('can compute fold levels', function()
+ ---@type table<integer, string>
+ local foldlevels = {}
+ for i = 1, 21 do
+ foldlevels[i] = exec_lua('return vim.lsp.foldexpr(' .. i .. ')')
+ end
+ eq({
+ [1] = '>1',
+ [2] = '<1',
+ [3] = '0',
+ [4] = '>1',
+ [5] = '>2',
+ [6] = '<2',
+ [7] = '>2',
+ [8] = '<2',
+ [9] = '>2',
+ [10] = '<2',
+ [11] = '>2',
+ [12] = '<2',
+ [13] = '1',
+ [14] = '1',
+ [15] = '1',
+ [16] = '>2',
+ [17] = '<2',
+ [18] = '1',
+ [19] = '1',
+ [20] = '<1',
+ [21] = '0',
+ }, foldlevels)
+ end)
+
+ it('updates folds in all windows', function()
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+
+ it('persists wherever foldexpr is set', function()
+ command([[setlocal foldexpr=]])
+ feed('<C-w><C-w>zx')
+ screen:expect({
+ grid = [[
+{1: }// foldLevel() {{{2 |
+{1: }/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1: }{ |
+{1: } // While updating the folds lines between invalid_top and invalid_bot have |
+{1: } // an undefined fold level. Otherwise update the folds first. |
+{1: } if (invalid_top == 0) { |
+{1: } checkupdate(curwin); |
+{1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1: } return prev_lnum_lvl; |
+{1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1: } return -1; |
+{1: } } |
+{1: } |
+{1: } // Return quickly when there is no folding at all in this window. |
+{1: } if (!hasAnyFolding(curwin)) { |
+{1: } return 0; |
+{1: } } |
+{1: } |
+{1: } return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+
+ it('synchronizes changed rows with their previous foldlevels', function()
+ command('1,2d')
+ screen:expect({
+ grid = [[
+{1: }^static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{2:~ }|*2
+{3:[No Name] [+] }|
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{2:~ }|*2
+{4:[No Name] [+] }|
+ |
+]],
+ })
+ end)
+
+ it('clears folds when sole client detaches', function()
+ exec_lua(function()
+ vim.lsp.buf_detach_client(bufnr, client_id)
+ end)
+ screen:expect({
+ grid = [[
+{1: }// foldLevel() {{{2 |
+{1: }/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1: }{ |
+{1: } // While updating the folds lines between invalid_top and invalid_bot have |
+{1: } // an undefined fold level. Otherwise update the folds first. |
+{1: } if (invalid_top == 0) { |
+{1: } checkupdate(curwin); |
+{1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1: } return prev_lnum_lvl; |
+{1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1: } return -1; |
+{1: } } |
+{1: } |
+{1: } // Return quickly when there is no folding at all in this window. |
+{1: } if (!hasAnyFolding(curwin)) { |
+{1: } return 0; |
+{1: } } |
+{1: } |
+{1: } return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+{1: }// foldLevel() {{{2 |
+{1: }/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1: }{ |
+{1: } // While updating the folds lines between invalid_top and invalid_bot have |
+{1: } // an undefined fold level. Otherwise update the folds first. |
+{1: } if (invalid_top == 0) { |
+{1: } checkupdate(curwin); |
+{1: } } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1: } return prev_lnum_lvl; |
+{1: } } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1: } return -1; |
+{1: } } |
+{1: } |
+{1: } // Return quickly when there is no folding at all in this window. |
+{1: } if (!hasAnyFolding(curwin)) { |
+{1: } return 0; |
+{1: } } |
+{1: } |
+{1: } return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+
+ it('remains valid after the client re-attaches.', function()
+ exec_lua(function()
+ vim.lsp.buf_detach_client(bufnr, client_id)
+ vim.lsp.buf_attach_client(bufnr, client_id)
+ end)
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:[No Name] [+] }|
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }} |
+{4:[No Name] [+] }|
+ |
+ ]],
+ })
+ end)
+ end)
+
+ describe('foldtext()', function()
+ --- @type test.functional.ui.screen
+ local screen
+ before_each(function()
+ screen = Screen.new(80, 23)
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
+ [3] = { bold = true, foreground = Screen.colors.Blue1 },
+ [4] = { bold = true, reverse = true },
+ [5] = { reverse = true },
+ })
+ command(
+ [[set foldexpr=v:lua.vim.lsp.foldexpr() foldtext=v:lua.vim.lsp.foldtext() foldlevel=1]]
+ )
+ end)
+
+ it('shows the first folded line if `collapsedText` does not exist', function()
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:+}{2: // While updating the folds lines between invalid_top and invalid_bot have···}|
+{1:+}{2: if (invalid_top == 0) {······················································}|
+{1:+}{2: } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {························}|
+{1:+}{2: } else if (lnum >= invalid_top && lnum <= invalid_bot) {·····················}|
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:+}{2: if (!hasAnyFolding(curwin)) {················································}|
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*6
+ |
+ ]],
+ })
+ end)
+ end)
+
+ describe('foldclose()', function()
+ --- @type test.functional.ui.screen
+ local screen
+ before_each(function()
+ screen = Screen.new(80, 23)
+ screen:set_default_attr_ids({
+ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue },
+ [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey },
+ [3] = { bold = true, foreground = Screen.colors.Blue1 },
+ [4] = { bold = true, reverse = true },
+ [5] = { reverse = true },
+ })
+ command([[set foldexpr=v:lua.vim.lsp.foldexpr()]])
+ end)
+
+ it('closes all folds of one kind immediately', function()
+ exec_lua(function()
+ vim.lsp.foldclose('comment')
+ end)
+ screen:expect({
+ grid = [[
+{1:+}{2:+-- 2 lines: foldLevel()······················································}|
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:+}{2:+--- 2 lines: While updating the folds lines between invalid_top and invalid_b}|
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*3
+ |
+ ]],
+ })
+ end)
+
+ it('closes the smallest fold first', function()
+ exec_lua(function()
+ vim.lsp.foldclose('region')
+ end)
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:+}{2:+-- 17 lines: {································································}|
+{1: }^} |
+{3:~ }|*17
+ |
+ ]],
+ })
+ command('4foldopen')
+ screen:expect({
+ grid = [[
+{1:-}// foldLevel() {{{2 |
+{1:│}/// @return fold level at line number "lnum" in the current window. |
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:-} // While updating the folds lines between invalid_top and invalid_bot have |
+{1:2} // an undefined fold level. Otherwise update the folds first. |
+{1:+}{2:+--- 2 lines: if (invalid_top == 0) {·········································}|
+{1:+}{2:+--- 2 lines: } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {···········}|
+{1:+}{2:+--- 2 lines: } else if (lnum >= invalid_top && lnum <= invalid_bot) {········}|
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:+}{2:+--- 2 lines: if (!hasAnyFolding(curwin)) {···································}|
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*5
+ |
+ ]],
+ })
+ end)
+
+ it('is defered when the buffer is not up-to-date', function()
+ exec_lua(function()
+ vim.lsp.foldclose('comment')
+ vim.lsp.util.buf_versions[bufnr] = 0
+ end)
+ screen:expect({
+ grid = [[
+{1:+}{2:+-- 2 lines: foldLevel()······················································}|
+{1: }static int foldLevel(linenr_T lnum) |
+{1:-}{ |
+{1:+}{2:+--- 2 lines: While updating the folds lines between invalid_top and invalid_b}|
+{1:-} if (invalid_top == 0) { |
+{1:2} checkupdate(curwin); |
+{1:-} } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) { |
+{1:2} return prev_lnum_lvl; |
+{1:-} } else if (lnum >= invalid_top && lnum <= invalid_bot) { |
+{1:2} return -1; |
+{1:│} } |
+{1:│} |
+{1:│} // Return quickly when there is no folding at all in this window. |
+{1:-} if (!hasAnyFolding(curwin)) { |
+{1:2} return 0; |
+{1:│} } |
+{1:│} |
+{1:│} return foldLevelWin(curwin, lnum); |
+{1: }^} |
+{3:~ }|*3
+ |
+ ]],
+ })
+ end)
+ end)
+end)
diff --git a/test/functional/plugin/lsp/handler_spec.lua b/test/functional/plugin/lsp/handler_spec.lua
deleted file mode 100644
index 4b05b676a8..0000000000
--- a/test/functional/plugin/lsp/handler_spec.lua
+++ /dev/null
@@ -1,42 +0,0 @@
-local t = require('test.testutil')
-local n = require('test.functional.testnvim')()
-
-local eq = t.eq
-local exec_lua = n.exec_lua
-local pcall_err = t.pcall_err
-local matches = t.matches
-
-describe('lsp-handlers', function()
- describe('vim.lsp._with_extend', function()
- it('should return a table with the default keys', function()
- eq(
- { 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(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, function()
- return vim.lsp._with_extend('test', { hello = 'world' }, { invalid = true })
- end)
- )
- end)
- end)
-end)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index f60e159d64..0bca1fa4ca 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -23,7 +23,7 @@ before_each(function()
-- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
--- @diagnostic disable-next-line:duplicate-set-field
- function _G.test_register(bufnr, id, offset_encoding, line_ending)
+ function _G.test_register(bufnr, id, position_encoding, line_ending)
local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline)
@@ -38,7 +38,7 @@ before_each(function()
firstline,
lastline,
new_lastline,
- offset_encoding,
+ position_encoding,
line_ending
)
@@ -63,15 +63,15 @@ local function test_edit(
prev_buffer,
edit_operations,
expected_text_changes,
- offset_encoding,
+ position_encoding,
line_ending
)
- offset_encoding = offset_encoding or 'utf-16'
+ position_encoding = position_encoding or 'utf-16'
line_ending = line_ending or '\n'
api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer)
exec_lua(function()
- return _G.test_register(0, 'test1', offset_encoding, line_ending)
+ return _G.test_register(0, 'test1', position_encoding, line_ending)
end)
for _, edit in ipairs(edit_operations) do
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index 280bd27207..9912bf2063 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -456,7 +456,7 @@ describe('semantic token highlighting', function()
vim.notify = function(...)
table.insert(_G.notifications, 1, { ... })
end
- return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }, { attach = false })
end)
eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
diff --git a/test/functional/plugin/lsp/testutil.lua b/test/functional/plugin/lsp/testutil.lua
index a36cbac568..95fc22b96b 100644
--- a/test/functional/plugin/lsp/testutil.lua
+++ b/test/functional/plugin/lsp/testutil.lua
@@ -182,16 +182,17 @@ function M.test_rpc_server(config)
)
end
local client = setmetatable({}, {
- __index = function(_, name)
+ __index = function(t, name)
-- Workaround for not being able to yield() inside __index for Lua 5.1 :(
-- Otherwise I would just return the value here.
- return function(...)
+ return function(arg1, ...)
+ local ismethod = arg1 == t
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]
+ local client = _G.TEST_RPC_CLIENT
+ if type(client[name]) == 'function' then
+ return client[name](ismethod and client or arg1, ...)
end
+ return client[name]
end, ...)
end
end,
diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua
index 813b8de812..1e3e759e0b 100644
--- a/test/functional/plugin/lsp/utils_spec.lua
+++ b/test/functional/plugin/lsp/utils_spec.lua
@@ -5,6 +5,8 @@ local Screen = require('test.functional.ui.screen')
local feed = n.feed
local eq = t.eq
local exec_lua = n.exec_lua
+local command, api = n.command, n.api
+local pcall_err = t.pcall_err
describe('vim.lsp.util', function()
before_each(n.clear)
@@ -265,6 +267,66 @@ describe('vim.lsp.util', function()
eq(56, opts.height)
end)
+
+ describe('vim.lsp.util.open_floating_preview', function()
+ local var_name = 'lsp_floating_preview'
+ local curbuf = api.nvim_get_current_buf()
+
+ it('clean bufvar after fclose', function()
+ exec_lua(function()
+ vim.lsp.util.open_floating_preview({ 'test' }, '', { height = 5, width = 2 })
+ end)
+ eq(true, api.nvim_win_is_valid(api.nvim_buf_get_var(curbuf, var_name)))
+ command('fclose')
+ eq(
+ 'Key not found: lsp_floating_preview',
+ pcall_err(api.nvim_buf_get_var, curbuf, var_name)
+ )
+ end)
+
+ it('clean bufvar after CursorMoved', function()
+ local result = exec_lua(function()
+ vim.lsp.util.open_floating_preview({ 'test' }, '', { height = 5, width = 2 })
+ local winnr = vim.b[vim.api.nvim_get_current_buf()].lsp_floating_preview
+ local result = vim.api.nvim_win_is_valid(winnr)
+ vim.api.nvim_feedkeys(vim.keycode('G'), 'txn', false)
+ return result
+ end)
+ eq(true, result)
+ eq(
+ 'Key not found: lsp_floating_preview',
+ pcall_err(api.nvim_buf_get_var, curbuf, var_name)
+ )
+ end)
+ end)
+ end)
+ end)
+
+ it('open_floating_preview zindex greater than current window', function()
+ local screen = Screen.new()
+ exec_lua(function()
+ vim.api.nvim_open_win(0, true, {
+ relative = 'editor',
+ border = 'single',
+ height = 11,
+ width = 51,
+ row = 2,
+ col = 2,
+ })
+ vim.keymap.set('n', 'K', function()
+ vim.lsp.util.open_floating_preview({ 'foo' }, '', { border = 'single' })
+ end, {})
end)
+ feed('K')
+ screen:expect([[
+ ┌───────────────────────────────────────────────────┐|
+ │{4:^ }│|
+ │┌───┐{11: }│|
+ ││{4:foo}│{11: }│|
+ │└───┘{11: }│|
+ │{11:~ }│|*7
+ └───────────────────────────────────────────────────┘|
+ |
+ ]])
end)
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 5222216faf..db3ab8ed98 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -95,7 +95,7 @@ describe('LSP', function()
exec_lua(function()
_G.lsp = require('vim.lsp')
function _G.test__start_client()
- return vim.lsp.start_client {
+ return vim.lsp.start({
cmd_env = {
NVIM_LOG_FILE = fake_lsp_logfile,
NVIM_APPNAME = 'nvim_lsp_test',
@@ -112,7 +112,7 @@ describe('LSP', function()
name = 'test_folder',
},
},
- }
+ }, { attach = false })
end
_G.TEST_CLIENT1 = _G.test__start_client()
end)
@@ -232,7 +232,7 @@ describe('LSP', function()
-- client is a dummy object which will queue up commands to be run
-- once the server initializes. It can't accept lua callbacks or
-- other types that may be unserializable for now.
- client.stop()
+ client:stop()
end,
-- If the program timed out, then code will be nil.
on_exit = function(code, signal)
@@ -254,8 +254,8 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_init = function(client)
- client.notify('test')
- client.stop()
+ client:notify('test')
+ client:stop()
end,
on_exit = function(code, signal)
eq(101, code, 'exit code') -- See fake-lsp-server.lua
@@ -275,7 +275,7 @@ describe('LSP', function()
test_rpc_server({
test_name = 'basic_init_did_change_configuration',
on_init = function(client, _)
- client.stop()
+ client:stop()
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -333,9 +333,9 @@ describe('LSP', function()
test_name = 'basic_init',
on_init = function(client)
eq(0, client.server_capabilities().textDocumentSync.change)
- client.request('shutdown')
- client.notify('exit')
- client.stop()
+ client:request('shutdown')
+ client:notify('exit')
+ client:stop()
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -377,7 +377,7 @@ describe('LSP', function()
end,
on_init = function(_client)
client = _client
- client.notify('finish')
+ client:notify('finish')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -395,7 +395,7 @@ describe('LSP', function()
return vim.lsp.buf_is_attached(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
end)
)
- client.stop()
+ client:stop()
end
end,
}
@@ -430,7 +430,7 @@ describe('LSP', function()
return vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID)
end)
)
- client.notify('finish')
+ client:notify('finish')
end,
on_handler = function(_, _, ctx)
if ctx.method == 'finish' then
@@ -439,7 +439,7 @@ describe('LSP', 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()
+ client:stop()
end
end,
}
@@ -466,13 +466,20 @@ describe('LSP', function()
true,
exec_lua(function()
local keymap --- @type table<string,any>
+ local called = false
+ local origin = vim.lsp.buf.hover
+ vim.lsp.buf.hover = function()
+ called = true
+ end
vim._with({ buf = _G.BUFFER }, function()
keymap = vim.fn.maparg('K', 'n', false, true)
end)
- return keymap.callback == vim.lsp.buf.hover
+ keymap.callback()
+ vim.lsp.buf.hover = origin
+ return called
end)
)
- client.stop()
+ client:stop()
end
end,
on_exit = function(_, _)
@@ -480,13 +487,13 @@ describe('LSP', function()
eq('', get_buf_option('omnifunc'))
eq('', get_buf_option('formatexpr'))
eq(
- '',
+ true,
exec_lua(function()
local keymap --- @type string
vim._with({ buf = _G.BUFFER }, function()
keymap = vim.fn.maparg('K', 'n', false, false)
end)
- return keymap
+ return keymap:match('<Lua %d+: .+/runtime/lua/vim/lsp%.lua:%d+>') ~= nil
end)
)
end,
@@ -524,7 +531,7 @@ describe('LSP', function()
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()
+ client:stop()
end
end,
on_exit = function(_, _)
@@ -554,7 +561,7 @@ describe('LSP', function()
eq('tfu', get_buf_option('tagfunc'))
eq('ofu', get_buf_option('omnifunc'))
eq('fex', get_buf_option('formatexpr'))
- client.stop()
+ client:stop()
end
end,
on_exit = function(_, _)
@@ -711,10 +718,10 @@ describe('LSP', function()
ctx.method,
result
)
- client.notify('workspace/configuration', server_result)
+ client:notify('workspace/configuration', server_result)
end
if ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -756,7 +763,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_check_capabilities',
on_init = function(client)
- client.stop()
+ client:stop()
local full_kind = exec_lua(function()
return require 'vim.lsp.protocol'.TextDocumentSyncKind.Full
end)
@@ -798,7 +805,7 @@ describe('LSP', function()
vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
end)
else
- client.stop()
+ client:stop()
end
end,
}
@@ -898,7 +905,7 @@ describe('LSP', function()
end)
end)
else
- client.stop()
+ client:stop()
end
end,
})
@@ -929,20 +936,20 @@ describe('LSP', function()
vim.api.nvim_exec_autocmds('BufWritePost', { buffer = _G.BUFFER, modeline = false })
end)
else
- client.stop()
+ client:stop()
end
end,
}
end)
- it('client.supports_methods() should validate capabilities', function()
+ it('client:supports_methods() should validate capabilities', function()
local expected_handlers = {
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
}
test_rpc_server {
test_name = 'capabilities_for_client_supports_method',
on_init = function(client)
- client.stop()
+ client:stop()
local expected_sync_capabilities = {
change = 1,
openClose = true,
@@ -958,11 +965,11 @@ describe('LSP', function()
eq(true, client.server_capabilities().codeLensProvider.resolveProvider)
-- known methods for resolved capabilities
- eq(true, client.supports_method('textDocument/hover'))
- eq(false, client.supports_method('textDocument/definition'))
+ eq(true, client:supports_method('textDocument/hover'))
+ eq(false, client:supports_method('textDocument/definition'))
-- unknown methods are assumed to be supported.
- eq(true, client.supports_method('unknown-method'))
+ eq(true, client:supports_method('unknown-method'))
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -989,7 +996,7 @@ describe('LSP', function()
end)
end,
on_init = function(client)
- client.stop()
+ client:stop()
exec_lua(function()
vim.lsp.buf.type_definition()
end)
@@ -1018,7 +1025,7 @@ describe('LSP', function()
end)
end,
on_init = function(client)
- client.stop()
+ client:stop()
exec_lua(function()
vim.lsp.buf.type_definition()
end)
@@ -1042,7 +1049,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'check_forward_request_cancelled',
on_init = function(_client)
- _client.request('error_code_test')
+ _client:request('error_code_test')
client = _client
end,
on_exit = function(code, signal)
@@ -1053,7 +1060,40 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
+ end
+ end,
+ }
+ end)
+
+ it('should forward ServerCancelled to callback', function()
+ local expected_handlers = {
+ { NIL, {}, { method = 'finish', client_id = 1 } },
+ {
+ { code = -32802 },
+ NIL,
+ { method = 'error_code_test', bufnr = 1, client_id = 1, version = 0 },
+ },
+ }
+ local client --- @type vim.lsp.Client
+ test_rpc_server {
+ test_name = 'check_forward_server_cancelled',
+ on_init = function(_client)
+ _client:request('error_code_test')
+ client = _client
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, 'exit code')
+ eq(0, signal, 'exit signal')
+ eq(0, #expected_handlers, 'did not call expected handler')
+ end,
+ on_handler = function(err, _, ctx)
+ eq(table.remove(expected_handlers), { err, _, ctx }, 'expected handler')
+ if ctx.method ~= 'finish' then
+ client:notify('finish')
+ end
+ if ctx.method == 'finish' then
+ client:stop()
end
end,
}
@@ -1072,7 +1112,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'check_forward_content_modified',
on_init = function(_client)
- _client.request('error_code_test')
+ _client:request('error_code_test')
client = _client
end,
on_exit = function(code, signal)
@@ -1082,12 +1122,11 @@ describe('LSP', function()
end,
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, _, ctx }, 'expected handler')
- -- if ctx.method == 'error_code_test' then client.notify("finish") end
if ctx.method ~= 'finish' then
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1103,13 +1142,13 @@ describe('LSP', function()
test_name = 'check_pending_request_tracked',
on_init = function(_client)
client = _client
- client.request('slow_request')
+ client:request('slow_request')
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')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1123,10 +1162,10 @@ describe('LSP', function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq(nil, request)
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1141,14 +1180,14 @@ describe('LSP', function()
test_name = 'check_cancel_request_tracked',
on_init = function(_client)
client = _client
- client.request('slow_request')
- client.cancel_request(2)
+ client:request('slow_request')
+ client:cancel_request(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')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1162,7 +1201,7 @@ describe('LSP', function()
end)
eq(nil, request)
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1178,19 +1217,19 @@ describe('LSP', function()
test_name = 'check_tracked_requests_cleared',
on_init = function(_client)
client = _client
- client.request('slow_request')
+ client:request('slow_request')
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)
+ client:cancel_request(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')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1204,10 +1243,10 @@ describe('LSP', function()
return _G.TEST_RPC_CLIENT.requests[2]
end)
eq(nil, request)
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1225,11 +1264,11 @@ describe('LSP', function()
command('let g:requests = 0')
command('autocmd LspRequest * let g:requests+=1')
client = _client
- client.request('slow_request')
+ client:request('slow_request')
eq(1, eval('g:requests'))
- client.cancel_request(2)
+ client:cancel_request(2)
eq(2, eval('g:requests'))
- client.notify('release')
+ client:notify('release')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1240,10 +1279,10 @@ describe('LSP', function()
on_handler = function(err, _, ctx)
eq(table.remove(expected_handlers), { err, {}, ctx }, 'expected handler')
if ctx.method == 'slow_request' then
- client.notify('finish')
+ client:notify('finish')
end
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1277,7 +1316,7 @@ describe('LSP', function()
end)
eq(full_kind, client.server_capabilities().textDocumentSync.change)
eq(true, client.server_capabilities().textDocumentSync.openClose)
- client.notify('finish')
+ client:notify('finish')
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1286,7 +1325,7 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1333,11 +1372,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1378,11 +1417,11 @@ describe('LSP', function()
end,
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1428,11 +1467,11 @@ describe('LSP', function()
'boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1479,11 +1518,11 @@ describe('LSP', function()
'boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1529,7 +1568,7 @@ describe('LSP', function()
end,
on_init = function(_client)
client = _client
- eq(true, client.supports_method('textDocument/inlayHint'))
+ eq(true, client:supports_method('textDocument/inlayHint'))
exec_lua(function()
assert(vim.lsp.buf_attach_client(_G.BUFFER, _G.TEST_RPC_CLIENT_ID))
end)
@@ -1545,11 +1584,11 @@ describe('LSP', function()
end)
end
if ctx.method == 'textDocument/inlayHint' then
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1598,11 +1637,11 @@ describe('LSP', function()
'123boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1652,11 +1691,11 @@ describe('LSP', function()
'123boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1699,11 +1738,11 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
n.command('normal! 1Go')
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1752,11 +1791,11 @@ describe('LSP', function()
'boop',
})
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -1806,15 +1845,29 @@ describe('LSP', function()
})
vim.api.nvim_command(_G.BUFFER .. 'bwipeout')
end)
- client.notify('finish')
+ client:notify('finish')
end
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
end)
+
+ it('vim.lsp.start when existing client has no workspace_folders', function()
+ exec_lua(create_server_definition)
+ eq(
+ { 2, 'foo', 'foo' },
+ exec_lua(function()
+ local server = _G._create_server()
+ vim.lsp.start { cmd = server.cmd, name = 'foo' }
+ vim.lsp.start { cmd = server.cmd, name = 'foo', root_dir = 'bar' }
+ local foos = vim.lsp.get_clients()
+ return { #foos, foos[1].name, foos[2].name }
+ end)
+ )
+ end)
end)
describe('parsing tests', function()
@@ -1830,7 +1883,7 @@ describe('LSP', function()
on_setup = function() end,
on_init = function(_client)
client = _client
- client.stop(true)
+ client:stop(true)
end,
on_exit = function(code, signal)
eq(0, code, 'exit code')
@@ -1882,7 +1935,7 @@ describe('LSP', function()
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), { err, result, ctx }, 'expected handler')
if ctx.method == 'finish' then
- client.stop()
+ client:stop()
end
end,
}
@@ -2348,7 +2401,7 @@ describe('LSP', function()
test_rpc_server {
test_name = 'basic_init',
on_init = function(client, _)
- client.stop()
+ client:stop()
end,
-- If the program timed out, then code will be nil.
on_exit = function(code, signal)
@@ -3448,6 +3501,19 @@ describe('LSP', function()
end)
)
end)
+ it('handles empty line', function()
+ exec_lua(function()
+ _G.contents = {
+ '',
+ }
+ end)
+ eq(
+ { 20, 1 },
+ exec_lua(function()
+ return { vim.lsp.util._make_floating_popup_size(_G.contents, { width = 20 }) }
+ end)
+ )
+ end)
end)
describe('lsp.util.trim.trim_empty_lines', function()
@@ -3499,7 +3565,7 @@ describe('LSP', function()
}
return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'zig', { '(' })
end)
- -- Note that although the higlight positions below are 0-indexed, the 2nd parameter
+ -- Note that although the highlight positions below are 0-indexed, the 2nd parameter
-- corresponds to the 3rd line because the first line is the ``` from the
-- Markdown block.
local expected = { 3, 4, 3, 11 }
@@ -4284,7 +4350,7 @@ describe('LSP', function()
end)
)
end
- client.stop()
+ client:stop()
end
end,
}
@@ -4331,7 +4397,7 @@ describe('LSP', function()
return type(vim.lsp.commands['dummy2'])
end)
)
- client.stop()
+ client:stop()
end
end,
}
@@ -4372,7 +4438,7 @@ describe('LSP', function()
vim.lsp.buf.code_action()
end)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
})
@@ -4447,7 +4513,7 @@ describe('LSP', function()
return type(vim.lsp.commands['executed_type_annotate'])
end)
)
- client.stop()
+ client:stop()
end
end,
}
@@ -4564,7 +4630,7 @@ describe('LSP', function()
end)
eq({ command = 'Dummy', title = 'Lens1' }, cmd)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4653,7 +4719,7 @@ describe('LSP', function()
end)
eq({ command = 'Dummy', title = 'Lens2' }, response)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4762,7 +4828,7 @@ describe('LSP', function()
return notify_msg
end)
eq('[LSP] Format request failed, no matching language servers.', notify_msg)
- client.stop()
+ client:stop()
end,
}
end)
@@ -4795,7 +4861,7 @@ describe('LSP', function()
end)
eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4836,7 +4902,7 @@ describe('LSP', function()
end)
eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4883,7 +4949,7 @@ describe('LSP', function()
end)
eq(nil, notify_msg)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -4930,7 +4996,7 @@ describe('LSP', function()
end)
eq({ handler_called = true }, result)
elseif ctx.method == 'shutdown' then
- client.stop()
+ client:stop()
end
end,
}
@@ -5145,8 +5211,8 @@ describe('LSP', function()
local win = vim.api.nvim_get_current_win()
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' })
vim.api.nvim_win_set_cursor(win, { 3, 6 })
- local client_id1 = assert(vim.lsp.start({ name = 'dummy', cmd = server1.cmd }))
- local client_id2 = assert(vim.lsp.start({ name = 'dummy', cmd = server2.cmd }))
+ local client_id1 = assert(vim.lsp.start({ name = 'dummy1', cmd = server1.cmd }))
+ local client_id2 = assert(vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }))
local response
vim.lsp.buf.definition({
on_list = function(r)
@@ -5477,7 +5543,7 @@ describe('LSP', function()
result[#result + 1] = {
method = method,
fname = fname,
- supported = client.supports_method(method, { bufnr = bufnr }),
+ supported = client:supports_method(method, { bufnr = bufnr }),
}
end
@@ -6059,15 +6125,6 @@ describe('LSP', function()
end
eq(is_os('mac') or is_os('win'), check_registered(nil)) -- start{_client}() defaults to make_client_capabilities().
- eq(false, check_registered(vim.empty_dict()))
- eq(
- false,
- check_registered({
- workspace = {
- ignoreMe = true,
- },
- })
- )
eq(
false,
check_registered({
@@ -6090,4 +6147,154 @@ describe('LSP', function()
)
end)
end)
+
+ describe('vim.lsp.config() and vim.lsp.enable()', function()
+ it('can merge settings from "*"', function()
+ eq(
+ {
+ name = 'foo',
+ cmd = { 'foo' },
+ root_markers = { '.git' },
+ },
+ exec_lua(function()
+ vim.lsp.config('*', { root_markers = { '.git' } })
+ vim.lsp.config('foo', { cmd = { 'foo' } })
+
+ return vim.lsp.config['foo']
+ end)
+ )
+ end)
+
+ it('sets up an autocmd', function()
+ eq(
+ 1,
+ exec_lua(function()
+ vim.lsp.config('foo', {
+ cmd = { 'foo' },
+ root_markers = { '.foorc' },
+ })
+ vim.lsp.enable('foo')
+ return #vim.api.nvim_get_autocmds({
+ group = 'nvim.lsp.enable',
+ event = 'FileType',
+ })
+ end)
+ )
+ end)
+
+ it('attaches to buffers', function()
+ exec_lua(create_server_definition)
+
+ local tmp1 = t.tmpname(true)
+ local tmp2 = t.tmpname(true)
+
+ exec_lua(function()
+ local server = _G._create_server({
+ handlers = {
+ initialize = function(_, _, callback)
+ callback(nil, { capabilities = {} })
+ end,
+ },
+ })
+
+ vim.lsp.config('foo', {
+ cmd = server.cmd,
+ filetypes = { 'foo' },
+ root_markers = { '.foorc' },
+ })
+
+ vim.lsp.config('bar', {
+ cmd = server.cmd,
+ filetypes = { 'bar' },
+ root_markers = { '.foorc' },
+ })
+
+ vim.lsp.enable('foo')
+ vim.lsp.enable('bar')
+
+ vim.cmd.edit(tmp1)
+ vim.bo.filetype = 'foo'
+ _G.foo_buf = vim.api.nvim_get_current_buf()
+
+ vim.cmd.edit(tmp2)
+ vim.bo.filetype = 'bar'
+ _G.bar_buf = vim.api.nvim_get_current_buf()
+ end)
+
+ eq(
+ { 1, 'foo', 1, 'bar' },
+ exec_lua(function()
+ local foos = vim.lsp.get_clients({ bufnr = assert(_G.foo_buf) })
+ local bars = vim.lsp.get_clients({ bufnr = assert(_G.bar_buf) })
+ return { #foos, foos[1].name, #bars, bars[1].name }
+ end)
+ )
+ end)
+
+ it('does not attach to buffers more than once if no root_dir', function()
+ exec_lua(create_server_definition)
+
+ local tmp1 = t.tmpname(true)
+
+ eq(
+ 1,
+ exec_lua(function()
+ local server = _G._create_server({
+ handlers = {
+ initialize = function(_, _, callback)
+ callback(nil, { capabilities = {} })
+ end,
+ },
+ })
+
+ vim.lsp.config('foo', { cmd = server.cmd, filetypes = { 'foo' } })
+ vim.lsp.enable('foo')
+
+ vim.cmd.edit(assert(tmp1))
+ vim.bo.filetype = 'foo'
+ vim.bo.filetype = 'foo'
+
+ return #vim.lsp.get_clients({ bufnr = vim.api.nvim_get_current_buf() })
+ end)
+ )
+ end)
+
+ it('supports async function for root_dir', function()
+ exec_lua(create_server_definition)
+
+ local tmp1 = t.tmpname(true)
+ exec_lua(function()
+ local server = _G._create_server({
+ handlers = {
+ initialize = function(_, _, callback)
+ callback(nil, { capabilities = {} })
+ end,
+ },
+ })
+
+ vim.lsp.config('foo', {
+ cmd = server.cmd,
+ filetypes = { 'foo' },
+ root_dir = function(cb)
+ vim.system({ 'sleep', '0' }, {}, function()
+ cb('some_dir')
+ end)
+ end,
+ })
+ vim.lsp.enable('foo')
+
+ vim.cmd.edit(assert(tmp1))
+ vim.bo.filetype = 'foo'
+ end)
+
+ retry(nil, 1000, function()
+ eq(
+ 'some_dir',
+ exec_lua(function()
+ return vim.lsp.get_clients({ bufnr = vim.api.nvim_get_current_buf() })[1].root_dir
+ end)
+ )
+ end)
+ end)
+ end)
end)
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index 8906e60dce..c1dbc6dac3 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -21,13 +21,12 @@ local function get_search_history(name)
local man = require('man')
local res = {}
--- @diagnostic disable-next-line:duplicate-set-field
- man.find_path = function(sect, name0)
+ man._find_path = function(name0, sect)
table.insert(res, { sect, name0 })
return nil
end
- local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args)
- assert(not ok)
- assert(rv and rv:match('no manual entry'))
+ local err = man.open_page(-1, { tab = 0 }, args)
+ assert(err and err:match('no manual entry'))
return res
end)
end
@@ -225,7 +224,7 @@ describe(':Man', function()
matches('^/.+', 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(
+ ('Error detected while processing command line:\r\n' .. 'man.lua: no manual entry for %s'):format(
pesc(actual_file)
),
fn.system(args, { '' })
@@ -235,8 +234,8 @@ describe(':Man', function()
it('tries variants with spaces, underscores #22503', function()
eq({
- { '', 'NAME WITH SPACES' },
- { '', 'NAME_WITH_SPACES' },
+ { vim.NIL, 'NAME WITH SPACES' },
+ { vim.NIL, 'NAME_WITH_SPACES' },
}, get_search_history('NAME WITH SPACES'))
eq({
{ '3', 'some other man' },
@@ -255,12 +254,21 @@ describe(':Man', function()
{ 'n', 'some_other_man' },
}, get_search_history('n some other man'))
eq({
- { '', '123some other man' },
- { '', '123some_other_man' },
+ { vim.NIL, '123some other man' },
+ { vim.NIL, '123some_other_man' },
}, get_search_history('123some other man'))
eq({
{ '1', 'other_man' },
{ '1', 'other_man' },
}, get_search_history('other_man(1)'))
end)
+
+ it('can complete', function()
+ eq(
+ true,
+ exec_lua(function()
+ return #require('man').man_complete('f', 'Man f') > 0
+ end)
+ )
+ end)
end)
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 722442acbd..2b54ea93e0 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -544,7 +544,7 @@ describe('clipboard (with fake clipboard.vim)', function()
]])
feed('gg^<C-v>') -- Goto start of top line enter visual block mode
feed('3ljy^k') -- yank 4x2 block & goto initial location
- feed('P') -- Paste it infront
+ feed('P') -- Paste it before cursor
expect([[
aabbaabbcc
ddeeddeeff
diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua
index 8bc55879d4..6e73f6894b 100644
--- a/test/functional/script/luacats_grammar_spec.lua
+++ b/test/functional/script/luacats_grammar_spec.lua
@@ -118,9 +118,9 @@ describe('luacats grammar', function()
type = '"rfc2396" | "rfc2732" | "rfc3986" | nil',
})
- test('@param offset_encoding "utf-8" | "utf-16" | "utf-32" | nil', {
+ test('@param position_encoding "utf-8" | "utf-16" | "utf-32" | nil', {
kind = 'param',
- name = 'offset_encoding',
+ name = 'position_encoding',
type = '"utf-8" | "utf-16" | "utf-32" | nil',
})
diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua
index d680f0b83b..837978dee1 100644
--- a/test/functional/shada/marks_spec.lua
+++ b/test/functional/shada/marks_spec.lua
@@ -218,7 +218,7 @@ describe('ShaDa support code', function()
-- -c temporary sets lnum to zero to make `+/pat` work, so calling setpcmark()
-- during -c used to add item with zero lnum to jump list.
it('does not create incorrect file for non-existent buffers when writing from -c', function()
- local argv = n.new_argv {
+ local p = n.spawn_wait {
args_rm = {
'-i',
'--embed', -- no --embed
@@ -232,12 +232,13 @@ describe('ShaDa support code', function()
'qall',
},
}
- eq('', fn.system(argv))
+ eq('', p:output())
+ eq(0, p.status)
eq(0, exc_exec('rshada'))
end)
it('does not create incorrect file for non-existent buffers opened from -c', function()
- local argv = n.new_argv {
+ local p = n.spawn_wait {
args_rm = {
'-i',
'--embed', -- no --embed
@@ -251,7 +252,8 @@ describe('ShaDa support code', function()
'autocmd VimEnter * qall',
},
}
- eq('', fn.system(argv))
+ eq('', p:output())
+ eq(0, p.status)
eq(0, exc_exec('rshada'))
end)
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index 5debdc6c77..78fe19b984 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -6,8 +6,7 @@ local uv = vim.uv
local paths = t.paths
local api, nvim_command, fn, eq = n.api, n.command, n.fn, t.eq
-local write_file, spawn, set_session, nvim_prog, exc_exec =
- t.write_file, n.spawn, n.set_session, n.nvim_prog, n.exc_exec
+local write_file, set_session, exc_exec = t.write_file, n.set_session, n.exc_exec
local is_os = t.is_os
local skip = t.skip
@@ -254,7 +253,7 @@ describe('ShaDa support code', function()
it('does not crash when ShaDa file directory is not writable', function()
skip(is_os('win'))
- fn.mkdir(dirname, '', 0)
+ fn.mkdir(dirname, '', '0')
eq(0, fn.filewritable(dirname))
reset { shadafile = dirshada, args = { '--cmd', 'set shada=' } }
api.nvim_set_option_value('shada', "'10", {})
@@ -270,10 +269,10 @@ end)
describe('ShaDa support code', function()
it('does not write NONE file', function()
- local session = spawn(
- { nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', '--headless', '--cmd', 'qall' },
- true
- )
+ local session = n.new_session(false, {
+ merge = false,
+ args = { '-u', 'NONE', '-i', 'NONE', '--embed', '--headless', '--cmd', 'qall' },
+ })
session:close()
eq(nil, uv.fs_stat('NONE'))
eq(nil, uv.fs_stat('NONE.tmp.a'))
@@ -281,7 +280,10 @@ describe('ShaDa support code', function()
it('does not read NONE file', function()
write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-')
- local session = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', '--headless' }, true)
+ local session = n.new_session(
+ false,
+ { merge = false, args = { '-u', 'NONE', '-i', 'NONE', '--embed', '--headless' } }
+ )
set_session(session)
eq('', fn.getreg('a'))
session:close()
diff --git a/test/functional/terminal/altscreen_spec.lua b/test/functional/terminal/altscreen_spec.lua
index 4a61e0203d..839e37f541 100644
--- a/test/functional/terminal/altscreen_spec.lua
+++ b/test/functional/terminal/altscreen_spec.lua
@@ -35,13 +35,13 @@ describe(':terminal altscreen', function()
line6 |
line7 |
line8 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
enter_altscreen()
screen:expect([[
|*5
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
eq(10, api.nvim_buf_line_count(0))
@@ -68,7 +68,7 @@ describe(':terminal altscreen', function()
line6 |
line7 |
line8 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
feed('<c-\\><c-n>gg')
@@ -103,7 +103,7 @@ describe(':terminal altscreen', function()
line14 |
line15 |
line16 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -132,7 +132,7 @@ describe(':terminal altscreen', function()
screen:expect([[
|*2
rows: 4, cols: 50 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end
@@ -160,7 +160,7 @@ describe(':terminal altscreen', function()
line5 |
line6 |
line7 |
- line8 |
+ ^line8 |
{3:-- TERMINAL --} |
]])
end)
diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index b550df80c3..a8e5367176 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -33,7 +33,7 @@ describe('api', function()
it('qa! RPC request during insert-mode', function()
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@@ -45,7 +45,7 @@ describe('api', function()
-- Wait for socket creation.
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*4
]] .. socket_name .. [[ |
{3:-- TERMINAL --} |
@@ -57,7 +57,7 @@ describe('api', function()
tt.feed_data('i[tui] insert-mode')
-- Wait for stdin to be processed.
screen:expect([[
- [tui] insert-mode{1: } |
+ [tui] insert-mode^ |
{4:~ }|*4
{3:-- INSERT --} |
{3:-- TERMINAL --} |
@@ -73,7 +73,7 @@ describe('api', function()
[tui] insert-mode |
[socket 1] this is more t |
han 25 columns |
- [socket 2] input{1: } |
+ [socket 2] input^ |
{4:~ } |
{3:-- INSERT --} |
{3:-- TERMINAL --} |
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 05258a9e50..4635259e33 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -89,7 +89,7 @@ describe(':terminal buffer', function()
feed('<c-\\><c-n>')
screen:expect([[
tty ready |
- {2:^ } |
+ ^ |
|*5
]])
end)
@@ -109,7 +109,7 @@ describe(':terminal buffer', function()
feed('<c-\\><c-n>dd')
screen:expect([[
tty ready |
- {2:^ } |
+ ^ |
|*4
{8:E21: Cannot make changes, 'modifiable' is off} |
]])
@@ -122,7 +122,7 @@ describe(':terminal buffer', function()
screen:expect([[
^tty ready |
appended tty ready |*2
- {2: } |
+ |
|*2
:let @a = "appended " . @a |
]])
@@ -142,7 +142,7 @@ describe(':terminal buffer', function()
screen:expect([[
^tty ready |
appended tty ready |
- {2: } |
+ |
|*3
:put a |
]])
@@ -151,7 +151,7 @@ describe(':terminal buffer', function()
screen:expect([[
tty ready |
appended tty ready |*2
- {2: } |
+ |
|
^ |
:6put a |
@@ -198,7 +198,7 @@ describe(':terminal buffer', function()
{4:~ }|
{5:========== }|
rows: 2, cols: 50 |
- {2: } |
+ |
{18:========== }|
|
]])
@@ -234,7 +234,7 @@ describe(':terminal buffer', function()
command('set rightleft')
screen:expect([[
ydaer ytt|
- {1:a}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
|*4
{3:-- TERMINAL --} |
]])
@@ -277,7 +277,7 @@ describe(':terminal buffer', function()
screen:expect {
grid = [[
tty ready |
- {2:^ } |
+ ^ |
|*4
{3:-- (terminal) --} |
]],
@@ -288,7 +288,7 @@ describe(':terminal buffer', function()
screen:expect {
grid = [[
tty ready |
- {2: } |
+ |
|*4
:let g:x = 17^ |
]],
@@ -298,7 +298,7 @@ describe(':terminal buffer', function()
screen:expect {
grid = [[
tty ready |
- {1: } |
+ ^ |
|*4
{3:-- TERMINAL --} |
]],
@@ -351,7 +351,7 @@ describe(':terminal buffer', function()
end)
it('TermRequest synchronization #27572', function()
- command('autocmd! nvim_terminal TermRequest')
+ command('autocmd! nvim.terminal TermRequest')
local term = exec_lua([[
_G.input = {}
local term = vim.api.nvim_open_term(0, {
@@ -378,7 +378,7 @@ describe(':terminal buffer', function()
}, exec_lua('return _G.input'))
end)
- it('no heap-buffer-overflow when using termopen(echo) #3161', function()
+ it('no heap-buffer-overflow when using jobstart("echo",{term=true}) #3161', function()
local testfilename = 'Xtestfile-functional-terminal-buffers_spec'
write_file(testfilename, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa')
finally(function()
@@ -387,8 +387,8 @@ describe(':terminal buffer', function()
feed_command('edit ' .. testfilename)
-- Move cursor away from the beginning of the line
feed('$')
- -- Let termopen() modify the buffer
- feed_command('call termopen("echo")')
+ -- Let jobstart(…,{term=true}) modify the buffer
+ feed_command([[call jobstart("echo", {'term':v:true})]])
assert_alive()
feed_command('bdelete!')
end)
@@ -400,18 +400,31 @@ describe(':terminal buffer', function()
assert_alive()
end)
- it('truncates number of composing characters to 5', function()
+ it('truncates the size of grapheme clusters', function()
local chan = api.nvim_open_term(0, {})
local composing = ('a̳'):sub(2)
- api.nvim_chan_send(chan, 'a' .. composing:rep(8))
+ api.nvim_chan_send(chan, 'a' .. composing:rep(20))
retry(nil, nil, function()
- eq('a' .. composing:rep(5), api.nvim_get_current_line())
+ eq('a' .. composing:rep(14), api.nvim_get_current_line())
end)
end)
+ it('handles extended grapheme clusters', function()
+ local screen = Screen.new(50, 7)
+ feed 'i'
+ local chan = api.nvim_open_term(0, {})
+ api.nvim_chan_send(chan, '🏴‍☠️ yarrr')
+ screen:expect([[
+ 🏴‍☠️ yarrr^ |
+ |*5
+ {5:-- TERMINAL --} |
+ ]])
+ eq('🏴‍☠️ yarrr', api.nvim_get_current_line())
+ end)
+
it('handles split UTF-8 sequences #16245', function()
local screen = Screen.new(50, 7)
- fn.termopen({ testprg('shell-test'), 'UTF-8' })
+ fn.jobstart({ testprg('shell-test'), 'UTF-8' }, { term = true })
screen:expect([[
^å |
ref: å̲ |
@@ -422,6 +435,19 @@ describe(':terminal buffer', function()
]])
end)
+ it('handles unprintable chars', function()
+ local screen = Screen.new(50, 7)
+ feed 'i'
+ local chan = api.nvim_open_term(0, {})
+ api.nvim_chan_send(chan, '\239\187\191') -- '\xef\xbb\xbf'
+ screen:expect([[
+ {18:<feff>}^ |
+ |*5
+ {5:-- TERMINAL --} |
+ ]])
+ eq('\239\187\191', api.nvim_get_current_line())
+ end)
+
it("handles bell respecting 'belloff' and 'visualbell'", function()
local screen = Screen.new(50, 7)
local chan = api.nvim_open_term(0, {})
@@ -531,16 +557,19 @@ describe('terminal input', function()
'--cmd',
'set notermguicolors',
'-c',
- 'while 1 | redraw | echo keytrans(getcharstr()) | endwhile',
+ 'while 1 | redraw | echo keytrans(getcharstr(-1, #{simplify: 0})) | endwhile',
})
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] 0,0-1 All}|
|
{3:-- TERMINAL --} |
]])
- for _, key in ipairs({
+ local keys = {
+ '<Tab>',
+ '<CR>',
+ '<Esc>',
'<M-Tab>',
'<M-CR>',
'<M-Esc>',
@@ -568,18 +597,36 @@ describe('terminal input', function()
'<S-End>',
'<C-End>',
'<End>',
- '<C-LeftMouse>',
- '<C-LeftRelease>',
- '<2-LeftMouse>',
- '<2-LeftRelease>',
- '<S-RightMouse>',
- '<S-RightRelease>',
- '<2-RightMouse>',
- '<2-RightRelease>',
- '<M-MiddleMouse>',
- '<M-MiddleRelease>',
- '<2-MiddleMouse>',
- '<2-MiddleRelease>',
+ '<C-LeftMouse><0,0>',
+ '<C-LeftDrag><0,1>',
+ '<C-LeftRelease><0,1>',
+ '<2-LeftMouse><0,1>',
+ '<2-LeftDrag><0,0>',
+ '<2-LeftRelease><0,0>',
+ '<M-MiddleMouse><0,0>',
+ '<M-MiddleDrag><0,1>',
+ '<M-MiddleRelease><0,1>',
+ '<2-MiddleMouse><0,1>',
+ '<2-MiddleDrag><0,0>',
+ '<2-MiddleRelease><0,0>',
+ '<S-RightMouse><0,0>',
+ '<S-RightDrag><0,1>',
+ '<S-RightRelease><0,1>',
+ '<2-RightMouse><0,1>',
+ '<2-RightDrag><0,0>',
+ '<2-RightRelease><0,0>',
+ '<S-X1Mouse><0,0>',
+ '<S-X1Drag><0,1>',
+ '<S-X1Release><0,1>',
+ '<2-X1Mouse><0,1>',
+ '<2-X1Drag><0,0>',
+ '<2-X1Release><0,0>',
+ '<S-X2Mouse><0,0>',
+ '<S-X2Drag><0,1>',
+ '<S-X2Release><0,1>',
+ '<2-X2Mouse><0,1>',
+ '<2-X2Drag><0,0>',
+ '<2-X2Release><0,0>',
'<S-ScrollWheelUp>',
'<S-ScrollWheelDown>',
'<ScrollWheelUp>',
@@ -588,15 +635,22 @@ describe('terminal input', function()
'<S-ScrollWheelRight>',
'<ScrollWheelLeft>',
'<ScrollWheelRight>',
- }) do
+ }
+ -- FIXME: The escape sequence to enable kitty keyboard mode doesn't work on Windows
+ if not is_os('win') then
+ table.insert(keys, '<C-I>')
+ table.insert(keys, '<C-M>')
+ table.insert(keys, '<C-[>')
+ end
+ for _, key in ipairs(keys) do
feed(key)
screen:expect(([[
|
{4:~ }|*3
{5:[No Name] 0,0-1 All}|
- %s{1: }{MATCH: *}|
+ %s^ {MATCH: *}|
{3:-- TERMINAL --} |
- ]]):format(key))
+ ]]):format(key:gsub('<%d+,%d+>$', '')))
end
end)
end)
@@ -624,7 +678,7 @@ if is_os('win') then
> :: appended :: tty ready |
> :: tty ready |
> :: appended :: tty ready |
- ^> {2: } |
+ ^> |
:let @a = @a . "\n:: appended " . @a . "\n\n" |
]])
-- operator count is also taken into consideration
@@ -635,7 +689,7 @@ if is_os('win') then
> :: appended :: tty ready |
> :: tty ready |
> :: appended :: tty ready |
- ^> {2: } |
+ ^> |
:let @a = @a . "\n:: appended " . @a . "\n\n" |
]])
end)
@@ -649,7 +703,7 @@ if is_os('win') then
|
> :: tty ready |
> :: appended :: tty ready |
- > {2: } |
+ > |
|
^ |
:put a |
@@ -662,14 +716,14 @@ if is_os('win') then
> :: appended :: tty ready |
> :: tty ready |
> :: appended :: tty ready |
- ^> {2: } |
+ ^> |
:6put a |
]])
end)
end)
end
-describe('termopen()', function()
+describe('termopen() (deprecated alias to `jobstart(…,{term=true})`)', function()
before_each(clear)
it('disallowed when textlocked and in cmdwin buffer', function()
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 9912c1ff7b..bb97411f43 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -75,8 +75,8 @@ describe('terminal channel is closed and later released if', function()
eq(chans - 1, eval('len(nvim_list_chans())'))
end)
- it('opened by termopen(), exited, and deleted by pressing a key', function()
- command([[let id = termopen('echo')]])
+ it('opened by jobstart(…,{term=true}), exited, and deleted by pressing a key', function()
+ command([[let id = jobstart('echo',{'term':v:true})]])
local chans = eval('len(nvim_list_chans())')
-- wait for process to exit
screen:expect({ any = '%[Process exited 0%]' })
@@ -96,8 +96,8 @@ describe('terminal channel is closed and later released if', function()
end)
-- This indirectly covers #16264
- it('opened by termopen(), exited, and deleted by :bdelete', function()
- command([[let id = termopen('echo')]])
+ it('opened by jobstart(…,{term=true}), exited, and deleted by :bdelete', function()
+ command([[let id = jobstart('echo', {'term':v:true})]])
local chans = eval('len(nvim_list_chans())')
-- wait for process to exit
screen:expect({ any = '%[Process exited 0%]' })
@@ -124,7 +124,7 @@ it('chansend sends lines to terminal channel in proper order', function()
screen._default_attr_ids = nil
local shells = is_os('win') and { 'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop' } or { 'sh' }
for _, sh in ipairs(shells) do
- command([[let id = termopen(']] .. sh .. [[')]])
+ command([[let id = jobstart(']] .. sh .. [[', {'term':v:true})]])
command([[call chansend(id, ['echo "hello"', 'echo "world"', ''])]])
screen:expect {
any = [[echo "hello".*echo "world"]],
@@ -149,7 +149,7 @@ describe('no crash when TermOpen autocommand', function()
})
end)
- it('processes job exit event when using termopen()', function()
+ it('processes job exit event when using jobstart(…,{term=true})', function()
command([[autocmd TermOpen * call input('')]])
async_meths.nvim_command('terminal foobar')
screen:expect {
@@ -179,7 +179,7 @@ describe('no crash when TermOpen autocommand', function()
assert_alive()
end)
- it('wipes buffer and processes events when using termopen()', function()
+ it('wipes buffer and processes events when using jobstart(…,{term=true})', function()
command([[autocmd TermOpen * bwipe! | call input('')]])
async_meths.nvim_command('terminal foobar')
screen:expect {
diff --git a/test/functional/terminal/clipboard_spec.lua b/test/functional/terminal/clipboard_spec.lua
index 4a1a0e29fd..f0ce407eaa 100644
--- a/test/functional/terminal/clipboard_spec.lua
+++ b/test/functional/terminal/clipboard_spec.lua
@@ -56,7 +56,7 @@ describe(':terminal', function()
return string.format('\027]52;;%s\027\\', arg)
end
- fn.termopen({ testprg('shell-test'), '-t', osc52(encoded) })
+ fn.jobstart({ testprg('shell-test'), '-t', osc52(encoded) }, { term = true })
retry(nil, 1000, function()
eq(text, exec_lua([[ return vim.g.clipboard_data ]]))
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index f223cdd417..83408e41b3 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -1,13 +1,12 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
-local Screen = require('test.functional.ui.screen')
local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear
local testprg, command = n.testprg, n.command
local eq, eval = t.eq, n.eval
local matches = t.matches
-local poke_eventloop = n.poke_eventloop
+local call = n.call
local hide_cursor = tt.hide_cursor
local show_cursor = tt.show_cursor
local is_os = t.is_os
@@ -16,16 +15,27 @@ local skip = t.skip
describe(':terminal cursor', function()
local screen
+ local terminal_mode_idx ---@type number
+
before_each(function()
clear()
screen = tt.setup_screen()
+
+ if terminal_mode_idx == nil then
+ for i, v in ipairs(screen._mode_info) do
+ if v.name == 'terminal' then
+ terminal_mode_idx = i
+ end
+ end
+ assert(terminal_mode_idx)
+ end
end)
it('moves the screen cursor when focused', function()
tt.feed_data('testing cursor')
screen:expect([[
tty ready |
- testing cursor{1: } |
+ testing cursor^ |
|*4
{3:-- TERMINAL --} |
]])
@@ -35,7 +45,7 @@ describe(':terminal cursor', function()
feed('<c-\\><c-n>')
screen:expect([[
tty ready |
- {2:^ } |
+ ^ |
|*5
]])
end)
@@ -49,7 +59,7 @@ describe(':terminal cursor', function()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }^rows: 6, cols: 46 |
- {7: 3 }{2: } |
+ {7: 3 } |
{7: 4 } |
{7: 5 } |
{7: 6 } |
@@ -61,7 +71,7 @@ describe(':terminal cursor', function()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }^rows: 6, cols: 46 |
- {7: 3 }{2: } |
+ {7: 3 } |
{7: 4 } |
{7: 5 } |
{7: 6 } |
@@ -72,7 +82,7 @@ describe(':terminal cursor', function()
screen:expect([[
{7: 1 }tty ready |
{7: 2 }rows: 6, cols: 46 |
- {7: 3 }{1: } |
+ {7: 3 }^ |
{7: 4 } |
{7: 5 } |
{7: 6 } |
@@ -82,8 +92,8 @@ describe(':terminal cursor', function()
end)
describe('when invisible', function()
- it('is not highlighted and is detached from screen cursor', function()
- skip(is_os('win'))
+ it('is not highlighted', function()
+ skip(is_os('win'), '#31587')
hide_cursor()
screen:expect([[
tty ready |
@@ -93,59 +103,259 @@ describe(':terminal cursor', function()
show_cursor()
screen:expect([[
tty ready |
- {1: } |
+ ^ |
|*4
{3:-- TERMINAL --} |
]])
-- same for when the terminal is unfocused
feed('<c-\\><c-n>')
hide_cursor()
+ screen:expect({
+ grid = [[
+ tty ready |
+ ^ |
+ |*5
+ ]],
+ unchanged = true,
+ })
+ show_cursor()
+ screen:expect({
+ grid = [[
+ tty ready |
+ ^ |
+ |*5
+ ]],
+ unchanged = true,
+ })
+ end)
+
+ it('becomes visible when exiting Terminal mode', function()
+ skip(is_os('win'), '#31587')
+ hide_cursor()
+ screen:expect([[
+ tty ready |
+ |*5
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<c-\\><c-n>')
screen:expect([[
tty ready |
^ |
|*5
]])
- show_cursor()
+ feed('i')
screen:expect([[
tty ready |
- {2:^ } |
|*5
+ {3:-- TERMINAL --} |
]])
end)
end)
-end)
-describe('cursor with customized highlighting', function()
- local screen
+ it('can be modified by application #3681 #31685', function()
+ skip(is_os('win'), '#31587')
- before_each(function()
- clear()
- command('highlight TermCursor ctermfg=45 ctermbg=46 cterm=NONE')
- command('highlight TermCursorNC ctermfg=55 ctermbg=56 cterm=NONE')
- screen = Screen.new(50, 7, { rgb = false })
- screen:set_default_attr_ids({
- [1] = { foreground = 45, background = 46 },
- [2] = { foreground = 55, background = 56 },
- [3] = { bold = true },
+ local states = {
+ [1] = { blink = true, shape = 'block' },
+ [2] = { blink = false, shape = 'block' },
+ [3] = { blink = true, shape = 'horizontal' },
+ [4] = { blink = false, shape = 'horizontal' },
+ [5] = { blink = true, shape = 'vertical' },
+ [6] = { blink = false, shape = 'vertical' },
+ }
+
+ for k, v in pairs(states) do
+ tt.feed_csi(('%d q'):format(k))
+ screen:expect({
+ grid = [[
+ tty ready |
+ ^ |
+ |*4
+ {3:-- TERMINAL --} |
+ ]],
+ condition = function()
+ if v.blink then
+ eq(500, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
+ else
+ eq(0, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
+ end
+
+ eq(v.shape, screen._mode_info[terminal_mode_idx].cursor_shape)
+
+ -- Cell percentages are hard coded for each shape in terminal.c
+ if v.shape == 'horizontal' then
+ eq(20, screen._mode_info[terminal_mode_idx].cell_percentage)
+ elseif v.shape == 'vertical' then
+ eq(25, screen._mode_info[terminal_mode_idx].cell_percentage)
+ end
+ end,
+ })
+ end
+
+ feed([[<C-\><C-N>]])
+
+ screen:expect([[
+ tty ready |
+ ^ |
+ |*5
+ ]])
+
+ -- Cursor returns to default on TermLeave
+ eq(500, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
+ eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
+ end)
+
+ it('can be modified per terminal', function()
+ skip(is_os('win'), '#31587')
+
+ -- Set cursor to vertical bar with blink
+ tt.feed_csi('5 q')
+ screen:expect({
+ grid = [[
+ tty ready |
+ ^ |
+ |*4
+ {3:-- TERMINAL --} |
+ ]],
+ condition = function()
+ eq(500, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
+ eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
+ end,
+ })
+
+ tt.hide_cursor()
+ screen:expect({
+ grid = [[
+ tty ready |
+ |
+ |*4
+ {3:-- TERMINAL --} |
+ ]],
+ condition = function()
+ eq(500, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
+ eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
+ end,
})
- command('call termopen(["' .. testprg('tty-test') .. '"])')
+
+ -- Exit terminal mode to reset terminal cursor settings to default and
+ -- create a new terminal window
+ feed([[<C-\><C-N>]])
+ command('set statusline=~~~')
+ command('new')
+ call('jobstart', { testprg('tty-test') }, { term = true })
feed('i')
- poke_eventloop()
+ screen:expect({
+ grid = [[
+ tty ready |
+ ^ |
+ {17:~~~ }|
+ rows: 2, cols: 50 |
+ |
+ {18:~~~ }|
+ {3:-- TERMINAL --} |
+ ]],
+ condition = function()
+ -- New terminal, cursor resets to defaults
+ eq(500, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
+ eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
+ end,
+ })
+
+ -- Set cursor to underline, no blink
+ tt.feed_csi('4 q')
+ screen:expect({
+ grid = [[
+ tty ready |
+ ^ |
+ {17:~~~ }|
+ rows: 2, cols: 50 |
+ |
+ {18:~~~ }|
+ {3:-- TERMINAL --} |
+ ]],
+ condition = function()
+ eq(0, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
+ eq('horizontal', screen._mode_info[terminal_mode_idx].cursor_shape)
+ end,
+ })
+
+ -- Switch back to first terminal, cursor should still be hidden
+ command('wincmd p')
+ screen:expect({
+ grid = [[
+ tty ready |
+ |
+ {18:~~~ }|
+ rows: 2, cols: 50 |
+ |
+ {17:~~~ }|
+ {3:-- TERMINAL --} |
+ ]],
+ condition = function()
+ eq(500, screen._mode_info[terminal_mode_idx].blinkon)
+ eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
+ eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
+ end,
+ })
end)
- it('overrides the default highlighting', function()
+ it('can be positioned arbitrarily', function()
+ clear()
+ screen = tt.setup_child_nvim({
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ n.nvim_set .. ' noshowmode',
+ })
+ screen:expect([[
+ ^ |
+ ~ |*4
+ |
+ {3:-- TERMINAL --} |
+ ]])
+
+ feed('i<Tab>')
screen:expect([[
- tty ready |
- {1: } |
- |*4
+ ^ |
+ ~ |*4
+ |
{3:-- TERMINAL --} |
]])
- feed('<c-\\><c-n>')
+ end)
+
+ it('preserves guicursor value on TermLeave #31612', function()
+ eq(3, screen._mode_info[terminal_mode_idx].hl_id)
+
+ -- Change 'guicursor' while terminal mode is active
+ command('set guicursor+=t:Error')
+
+ local error_hl_id = call('hlID', 'Error')
+
+ screen:expect({
+ condition = function()
+ eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
+ end,
+ })
+
+ -- Exit terminal mode
+ feed([[<C-\><C-N>]])
+
screen:expect([[
tty ready |
- {2:^ } |
+ ^ |
|*5
]])
+
+ eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
end)
end)
@@ -171,19 +381,10 @@ describe('buffer cursor position is correct in terminal without number column',
}, {
cols = 70,
})
- screen:set_default_attr_ids({
- [1] = { foreground = 253, background = 11 },
- [2] = { reverse = true },
- [3] = { bold = true },
- [4] = { background = 11 },
- })
- -- Also check for real cursor position, as it is used for stuff like input methods
- screen._handle_busy_start = function() end
- screen._handle_busy_stop = function() end
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :{2:^ } |
+ :^ |
{3:-- TERMINAL --} |
]])
end
@@ -200,7 +401,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :aaaaaaaa{2:^ } |
+ :aaaaaaaa^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 9 }, eval('nvim_win_get_cursor(0)'))
@@ -208,7 +409,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :aaaaaaa^a{4: } |
+ :aaaaaaa^a |
|
]])
eq({ 6, 8 }, eval('nvim_win_get_cursor(0)'))
@@ -219,7 +420,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :aaaaaa{2:^a}a |
+ :aaaaaa^aa |
{3:-- TERMINAL --} |
]])
eq({ 6, 7 }, eval('nvim_win_get_cursor(0)'))
@@ -227,7 +428,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :aaaaa^a{4:a}a |
+ :aaaaa^aaa |
|
]])
eq({ 6, 6 }, eval('nvim_win_get_cursor(0)'))
@@ -238,7 +439,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :a{2:^a}aaaaaa |
+ :a^aaaaaaa |
{3:-- TERMINAL --} |
]])
eq({ 6, 2 }, eval('nvim_win_get_cursor(0)'))
@@ -246,7 +447,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :^a{4:a}aaaaaa |
+ :^aaaaaaaa |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -263,7 +464,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µµµµµµµµ{2:^ } |
+ :µµµµµµµµ^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 17 }, eval('nvim_win_get_cursor(0)'))
@@ -271,7 +472,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µµµµµµµ^µ{4: } |
+ :µµµµµµµ^µ |
|
]])
eq({ 6, 15 }, eval('nvim_win_get_cursor(0)'))
@@ -282,7 +483,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µµµµµµ{2:^µ}µ |
+ :µµµµµµ^µµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
@@ -290,7 +491,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µµµµµ^µ{4:µ}µ |
+ :µµµµµ^µµµ |
|
]])
eq({ 6, 11 }, eval('nvim_win_get_cursor(0)'))
@@ -301,7 +502,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µ{2:^µ}µµµµµµ |
+ :µ^µµµµµµµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 3 }, eval('nvim_win_get_cursor(0)'))
@@ -309,7 +510,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :^µ{4:µ}µµµµµµ |
+ :^µµµµµµµµ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -326,7 +527,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳{2:^ } |
+ :µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 33 }, eval('nvim_win_get_cursor(0)'))
@@ -334,7 +535,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳{4: } |
+ :µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳ |
|
]])
eq({ 6, 29 }, eval('nvim_win_get_cursor(0)'))
@@ -346,7 +547,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µ̳µ̳µ̳µ̳µ̳µ̳{2:^µ̳}µ̳ |
+ :µ̳µ̳µ̳µ̳µ̳µ̳^µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@@ -354,7 +555,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µ̳µ̳µ̳µ̳µ̳^µ̳{4:µ̳}µ̳ |
+ :µ̳µ̳µ̳µ̳µ̳^µ̳µ̳µ̳ |
|
]])
eq({ 6, 21 }, eval('nvim_win_get_cursor(0)'))
@@ -366,7 +567,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :µ̳{2:^µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
+ :µ̳^µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 5 }, eval('nvim_win_get_cursor(0)'))
@@ -374,7 +575,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :^µ̳{4:µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
+ :^µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -391,7 +592,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :哦哦哦哦哦哦哦哦{2:^ } |
+ :哦哦哦哦哦哦哦哦^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@@ -399,7 +600,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :哦哦哦哦哦哦哦^哦{4: } |
+ :哦哦哦哦哦哦哦^哦 |
|
]])
eq({ 6, 22 }, eval('nvim_win_get_cursor(0)'))
@@ -410,7 +611,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :哦哦哦哦哦哦{2:^哦}哦 |
+ :哦哦哦哦哦哦^哦哦 |
{3:-- TERMINAL --} |
]])
eq({ 6, 19 }, eval('nvim_win_get_cursor(0)'))
@@ -418,7 +619,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :哦哦哦哦哦^哦{4:哦}哦 |
+ :哦哦哦哦哦^哦哦哦 |
|
]])
eq({ 6, 16 }, eval('nvim_win_get_cursor(0)'))
@@ -429,7 +630,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :哦{2:^哦}哦哦哦哦哦哦 |
+ :哦^哦哦哦哦哦哦哦 |
{3:-- TERMINAL --} |
]])
eq({ 6, 4 }, eval('nvim_win_get_cursor(0)'))
@@ -437,7 +638,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :^哦{4:哦}哦哦哦哦哦哦 |
+ :^哦哦哦哦哦哦哦哦 |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -450,7 +651,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :aaaaaaaa {2:^ } |
+ :aaaaaaaa ^ |
{3:-- TERMINAL --} |
]])
matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
@@ -459,7 +660,7 @@ describe('buffer cursor position is correct in terminal without number column',
screen:expect([[
|*4
Entering Ex mode. Type "visual" to go to Normal mode. |
- :aaaaaaaa ^ {4: } |
+ :aaaaaaaa ^ |
|
]])
eq({ 6, 12 }, eval('nvim_win_get_cursor(0)'))
@@ -488,30 +689,20 @@ describe('buffer cursor position is correct in terminal with number column', fun
}, {
cols = 70,
})
- screen:set_default_attr_ids({
- [1] = { foreground = 253, background = 11 },
- [2] = { reverse = true },
- [3] = { bold = true },
- [4] = { background = 11 },
- [7] = { foreground = 130 },
- })
- -- Also check for real cursor position, as it is used for stuff like input methods
- screen._handle_busy_start = function() end
- screen._handle_busy_stop = function() end
screen:expect([[
{7: 1 } |
{7: 2 } |
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:{2:^ } |
+ {7: 6 }:^ |
{3:-- TERMINAL --} |
]])
end
before_each(function()
clear()
- command('set number')
+ command('au TermOpen * set number')
end)
describe('in a line with no multibyte chars or trailing spaces,', function()
@@ -527,7 +718,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:aaaaaaaa{2:^ } |
+ {7: 6 }:aaaaaaaa^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 9 }, eval('nvim_win_get_cursor(0)'))
@@ -538,7 +729,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:aaaaaaa^a{4: } |
+ {7: 6 }:aaaaaaa^a |
|
]])
eq({ 6, 8 }, eval('nvim_win_get_cursor(0)'))
@@ -552,7 +743,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:aaaaaa{2:^a}a |
+ {7: 6 }:aaaaaa^aa |
{3:-- TERMINAL --} |
]])
eq({ 6, 7 }, eval('nvim_win_get_cursor(0)'))
@@ -563,7 +754,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:aaaaa^a{4:a}a |
+ {7: 6 }:aaaaa^aaa |
|
]])
eq({ 6, 6 }, eval('nvim_win_get_cursor(0)'))
@@ -577,7 +768,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:a{2:^a}aaaaaa |
+ {7: 6 }:a^aaaaaaa |
{3:-- TERMINAL --} |
]])
eq({ 6, 2 }, eval('nvim_win_get_cursor(0)'))
@@ -588,7 +779,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:^a{4:a}aaaaaa |
+ {7: 6 }:^aaaaaaaa |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -608,7 +799,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µµµµµµµµ{2:^ } |
+ {7: 6 }:µµµµµµµµ^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 17 }, eval('nvim_win_get_cursor(0)'))
@@ -619,7 +810,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µµµµµµµ^µ{4: } |
+ {7: 6 }:µµµµµµµ^µ |
|
]])
eq({ 6, 15 }, eval('nvim_win_get_cursor(0)'))
@@ -633,7 +824,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µµµµµµ{2:^µ}µ |
+ {7: 6 }:µµµµµµ^µµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 13 }, eval('nvim_win_get_cursor(0)'))
@@ -644,7 +835,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µµµµµ^µ{4:µ}µ |
+ {7: 6 }:µµµµµ^µµµ |
|
]])
eq({ 6, 11 }, eval('nvim_win_get_cursor(0)'))
@@ -658,7 +849,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µ{2:^µ}µµµµµµ |
+ {7: 6 }:µ^µµµµµµµ |
{3:-- TERMINAL --} |
]])
eq({ 6, 3 }, eval('nvim_win_get_cursor(0)'))
@@ -669,7 +860,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:^µ{4:µ}µµµµµµ |
+ {7: 6 }:^µµµµµµµµ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -689,7 +880,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳{2:^ } |
+ {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 33 }, eval('nvim_win_get_cursor(0)'))
@@ -700,7 +891,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳{4: } |
+ {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳µ̳^µ̳ |
|
]])
eq({ 6, 29 }, eval('nvim_win_get_cursor(0)'))
@@ -715,7 +906,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳{2:^µ̳}µ̳ |
+ {7: 6 }:µ̳µ̳µ̳µ̳µ̳µ̳^µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@@ -726,7 +917,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µ̳µ̳µ̳µ̳µ̳^µ̳{4:µ̳}µ̳ |
+ {7: 6 }:µ̳µ̳µ̳µ̳µ̳^µ̳µ̳µ̳ |
|
]])
eq({ 6, 21 }, eval('nvim_win_get_cursor(0)'))
@@ -741,7 +932,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:µ̳{2:^µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
+ {7: 6 }:µ̳^µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
{3:-- TERMINAL --} |
]])
eq({ 6, 5 }, eval('nvim_win_get_cursor(0)'))
@@ -752,7 +943,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:^µ̳{4:µ̳}µ̳µ̳µ̳µ̳µ̳µ̳ |
+ {7: 6 }:^µ̳µ̳µ̳µ̳µ̳µ̳µ̳µ̳ |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -772,7 +963,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:哦哦哦哦哦哦哦哦{2:^ } |
+ {7: 6 }:哦哦哦哦哦哦哦哦^ |
{3:-- TERMINAL --} |
]])
eq({ 6, 25 }, eval('nvim_win_get_cursor(0)'))
@@ -783,7 +974,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:哦哦哦哦哦哦哦^哦{4: } |
+ {7: 6 }:哦哦哦哦哦哦哦^哦 |
|
]])
eq({ 6, 22 }, eval('nvim_win_get_cursor(0)'))
@@ -797,7 +988,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:哦哦哦哦哦哦{2:^哦}哦 |
+ {7: 6 }:哦哦哦哦哦哦^哦哦 |
{3:-- TERMINAL --} |
]])
eq({ 6, 19 }, eval('nvim_win_get_cursor(0)'))
@@ -808,7 +999,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:哦哦哦哦哦^哦{4:哦}哦 |
+ {7: 6 }:哦哦哦哦哦^哦哦哦 |
|
]])
eq({ 6, 16 }, eval('nvim_win_get_cursor(0)'))
@@ -822,7 +1013,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:哦{2:^哦}哦哦哦哦哦哦 |
+ {7: 6 }:哦^哦哦哦哦哦哦哦 |
{3:-- TERMINAL --} |
]])
eq({ 6, 4 }, eval('nvim_win_get_cursor(0)'))
@@ -833,7 +1024,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:^哦{4:哦}哦哦哦哦哦哦 |
+ {7: 6 }:^哦哦哦哦哦哦哦哦 |
|
]])
eq({ 6, 1 }, eval('nvim_win_get_cursor(0)'))
@@ -849,7 +1040,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:aaaaaaaa {2:^ } |
+ {7: 6 }:aaaaaaaa ^ |
{3:-- TERMINAL --} |
]])
matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
@@ -861,7 +1052,7 @@ describe('buffer cursor position is correct in terminal with number column', fun
{7: 3 } |
{7: 4 } |
{7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
- {7: 6 }:aaaaaaaa ^ {4: } |
+ {7: 6 }:aaaaaaaa ^ |
|
]])
eq({ 6, 12 }, eval('nvim_win_get_cursor(0)'))
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 5ebe7bd4fc..c29a1e9cd4 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -175,8 +175,8 @@ local function test_terminal_with_fake_shell(backslash)
api.nvim_set_option_value('shellxquote', '', {}) -- win: avoid extra quotes
end)
- it('with no argument, acts like termopen()', function()
- command('autocmd! nvim_terminal TermClose')
+ it('with no argument, acts like jobstart(…,{term=true})', function()
+ command('autocmd! nvim.terminal TermClose')
feed_command('terminal')
screen:expect([[
^ready $ |
@@ -196,7 +196,7 @@ local function test_terminal_with_fake_shell(backslash)
]])
end)
- it("with no argument, but 'shell' has arguments, acts like termopen()", function()
+ it("with no argument, but 'shell' has arguments, acts like jobstart(…,{term=true})", function()
api.nvim_set_option_value('shell', shell_path .. ' INTERACT', {})
feed_command('terminal')
screen:expect([[
@@ -246,7 +246,7 @@ local function test_terminal_with_fake_shell(backslash)
end)
it('ignores writes if the backing stream closes', function()
- command('autocmd! nvim_terminal TermClose')
+ command('autocmd! nvim.terminal TermClose')
feed_command('terminal')
feed('iiXXXXXXX')
poke_eventloop()
@@ -258,14 +258,14 @@ local function test_terminal_with_fake_shell(backslash)
end)
it('works with findfile()', function()
- command('autocmd! nvim_terminal TermClose')
+ command('autocmd! nvim.terminal TermClose')
feed_command('terminal')
eq('term://', string.match(eval('bufname("%")'), '^term://'))
eq('scripts/shadacat.py', eval('findfile("scripts/shadacat.py", ".")'))
end)
it('works with :find', function()
- command('autocmd! nvim_terminal TermClose')
+ command('autocmd! nvim.terminal TermClose')
feed_command('terminal')
screen:expect([[
^ready $ |
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 7822a27b93..0afbd010f7 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -6,7 +6,6 @@ local tt = require('test.functional.testterm')
local feed, clear = n.feed, n.clear
local api = n.api
local testprg, command = n.testprg, n.command
-local nvim_prog_abs = n.nvim_prog_abs
local fn = n.fn
local nvim_set = n.nvim_set
local is_os = t.is_os
@@ -33,11 +32,11 @@ describe(':terminal highlight', function()
[12] = { bold = true, underdouble = true },
[13] = { italic = true, undercurl = true },
})
- command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
+ command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
- {10: } |
+ ^ |
|*4
{5:-- TERMINAL --} |
]])
@@ -61,7 +60,7 @@ describe(':terminal highlight', function()
skip(is_os('win'))
screen:expect(sub([[
tty ready |
- {NUM:text}text{10: } |
+ {NUM:text}text^ |
|*4
{5:-- TERMINAL --} |
]]))
@@ -84,7 +83,7 @@ describe(':terminal highlight', function()
line6 |
line7 |
line8 |
- {10: } |
+ ^ |
{5:-- TERMINAL --} |
]])
feed('<c-\\><c-n>gg')
@@ -150,8 +149,8 @@ it(':terminal highlight has lower precedence than editor #9964', function()
},
})
-- Child nvim process in :terminal (with cterm colors).
- fn.termopen({
- nvim_prog_abs(),
+ fn.jobstart({
+ n.nvim_prog,
'-n',
'-u',
'NORC',
@@ -163,6 +162,7 @@ it(':terminal highlight has lower precedence than editor #9964', function()
'+norm! ichild nvim',
'+norm! oline 2',
}, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -195,12 +195,12 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
local screen = Screen.new(50, 7)
screen:set_default_attr_ids({
[1] = { background = Screen.colors.Grey90 }, -- CursorLine, CursorColumn
- [2] = { reverse = true }, -- TermCursor
+ [2] = { reverse = true },
[3] = { bold = true }, -- ModeMsg
[4] = { background = Screen.colors.Grey90, reverse = true },
[5] = { background = Screen.colors.Red },
})
- command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
+ command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
screen:expect([[
^tty ready |
|*6
@@ -234,7 +234,7 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
foobar foobar foobar foobar foobar foobar foobar f|
oobar foobar foobar foobar foobar foobar foobar fo|
obar foobar foobar foobar foobar foobar foobar foo|
- bar foobar{2: } |
+ bar foobar^ |
{3:-- TERMINAL --} |
]])
-- Leaving terminal mode restores old values.
@@ -248,46 +248,60 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi
{1:bar fooba^r }|
|
]])
- -- CursorLine and CursorColumn are combined with TermCursorNC.
- command('highlight TermCursorNC gui=reverse')
+
+ -- Skip the rest of these tests on Windows #31587
+ if is_os('win') then
+ return
+ end
+
+ -- CursorLine and CursorColumn are combined with terminal colors.
+ tt.set_reverse()
+ tt.feed_data(' foobar')
+ tt.clear_attrs()
screen:expect([[
tty ready{1: } |
foobar f{1:o}obar foobar foobar foobar foobar foobar |
foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
obar foob{1:a}r foobar foobar foobar foobar foobar foo|
- {1:bar fooba^r}{4: }{1: }|
+ {1:bar fooba^r}{4: foobar}{1: }|
|
]])
- feed('2gg11|')
+ feed('2gg15|')
screen:expect([[
- tty ready {1: } |
- {1: foobar fo^obar foobar foobar foobar foobar foobar }|
- foobar foo{1:b}ar foobar foobar foobar foobar foobar f|
- oobar foob{1:a}r foobar foobar foobar foobar foobar fo|
- obar fooba{1:r} foobar foobar foobar foobar foobar foo|
- bar foobar{4: } |
+ tty ready {1: } |
+ {1: foobar foobar^ foobar foobar foobar foobar foobar }|
+ foobar foobar {1:f}oobar foobar foobar foobar foobar f|
+ oobar foobar f{1:o}obar foobar foobar foobar foobar fo|
+ obar foobar fo{1:o}bar foobar foobar foobar foobar foo|
+ bar foobar{2: foo}{4:b}{2:ar} |
|
]])
- -- TermCursorNC has higher precedence.
- command('highlight TermCursorNC gui=NONE guibg=Red')
+
+ -- Set bg color to red
+ tt.feed_csi('48;2;255:0:0m')
+ tt.feed_data(' foobar')
+ tt.clear_attrs()
+ feed('2gg20|')
+
+ -- Terminal color has higher precedence
screen:expect([[
- tty ready {1: } |
- {1: foobar fo^obar foobar foobar foobar foobar foobar }|
- foobar foo{1:b}ar foobar foobar foobar foobar foobar f|
- oobar foob{1:a}r foobar foobar foobar foobar foobar fo|
- obar fooba{1:r} foobar foobar foobar foobar foobar foo|
- bar foobar{5: } |
+ tty ready {1: } |
+ {1: foobar foobar foob^ar foobar foobar foobar foobar }|
+ foobar foobar fooba{1:r} foobar foobar foobar foobar f|
+ oobar foobar foobar{1: }foobar foobar foobar foobar fo|
+ obar foobar foobar {1:f}oobar foobar foobar foobar foo|
+ bar foobar{2: foobar}{5: foobar} |
|
]])
feed('G$')
screen:expect([[
- tty ready{1: } |
- foobar f{1:o}obar foobar foobar foobar foobar foobar |
- foobar fo{1:o}bar foobar foobar foobar foobar foobar f|
- oobar foo{1:b}ar foobar foobar foobar foobar foobar fo|
- obar foob{1:a}r foobar foobar foobar foobar foobar foo|
- {1:bar fooba^r}{5: }{1: }|
+ tty ready {1: } |
+ foobar foobar foobar f{1:o}obar foobar foobar foobar |
+ foobar foobar foobar fo{1:o}bar foobar foobar foobar f|
+ oobar foobar foobar foo{1:b}ar foobar foobar foobar fo|
+ obar foobar foobar foob{1:a}r foobar foobar foobar foo|
+ {1:bar foobar}{4: foobar}{5: fooba^r}{1: }|
|
]])
end)
@@ -300,18 +314,17 @@ describe(':terminal highlight forwarding', function()
screen = Screen.new(50, 7)
screen:set_rgb_cterm(true)
screen:set_default_attr_ids({
- [1] = { { reverse = true }, { reverse = true } },
- [2] = { { bold = true }, { bold = true } },
- [3] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
- [4] = { { foreground = tonumber('0xff8000') }, {} },
+ [1] = { { bold = true }, { bold = true } },
+ [2] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } },
+ [3] = { { foreground = tonumber('0xff8000') }, {} },
})
- command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
+ command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
- {1: } |
+ ^ |
|*4
- {2:-- TERMINAL --} |
+ {1:-- TERMINAL --} |
]])
end)
@@ -326,9 +339,9 @@ describe(':terminal highlight forwarding', function()
screen:expect {
grid = [[
tty ready |
- {3:text}{4:color}text{1: } |
+ {2:text}{3:color}text^ |
|*4
- {2:-- TERMINAL --} |
+ {1:-- TERMINAL --} |
]],
}
end)
@@ -351,11 +364,11 @@ describe(':terminal highlight with custom palette', function()
[9] = { bold = true },
})
api.nvim_set_var('terminal_color_3', '#123456')
- command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
+ command(("enew | call jobstart(['%s'], {'term':v:true})"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
- {7: } |
+ ^ |
|*4
{9:-- TERMINAL --} |
]])
@@ -369,7 +382,7 @@ describe(':terminal highlight with custom palette', function()
tt.feed_data('text')
screen:expect([[
tty ready |
- {1:text}text{7: } |
+ {1:text}text^ |
|*4
{9:-- TERMINAL --} |
]])
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index 38d6b83417..5898484449 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -32,7 +32,7 @@ describe(':terminal mouse', function()
line28 |
line29 |
line30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -107,7 +107,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -121,7 +121,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- "#{1: } |
+ "#^ |
{3:-- TERMINAL --} |
]])
feed('<LeftDrag><2,2>')
@@ -131,7 +131,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- @##{1: } |
+ @##^ |
{3:-- TERMINAL --} |
]])
feed('<LeftDrag><3,2>')
@@ -141,7 +141,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- @$#{1: } |
+ @$#^ |
{3:-- TERMINAL --} |
]])
feed('<LeftRelease><3,2>')
@@ -151,7 +151,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- #$#{1: } |
+ #$#^ |
{3:-- TERMINAL --} |
]])
end)
@@ -165,7 +165,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- `!!{1: } |
+ `!!^ |
{3:-- TERMINAL --} |
]])
end)
@@ -179,7 +179,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- "#{1: } |
+ "#^ |
{3:-- TERMINAL --} |
]])
feed('<ScrollWheelUp><1,2>')
@@ -189,7 +189,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- `"#{1: } |
+ `"#^ |
{3:-- TERMINAL --} |
]])
feed('<LeftDrag><2,2>')
@@ -199,7 +199,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- @##{1: } |
+ @##^ |
{3:-- TERMINAL --} |
]])
feed('<ScrollWheelUp><2,2>')
@@ -209,7 +209,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- `##{1: } |
+ `##^ |
{3:-- TERMINAL --} |
]])
feed('<LeftRelease><2,2>')
@@ -219,7 +219,7 @@ describe(':terminal mouse', function()
line29 |
line30 |
mouse enabled |
- ###{1: } |
+ ###^ |
{3:-- TERMINAL --} |
]])
end)
@@ -237,7 +237,7 @@ describe(':terminal mouse', function()
{7: 13 }line30 |
{7: 14 }mouse enabled |
{7: 15 }rows: 6, cols: 46 |
- {7: 16 }{2: } |
+ {7: 16 } |
|
]])
-- If click on the coordinate (0,1) of the region of the terminal
@@ -249,7 +249,7 @@ describe(':terminal mouse', function()
{7: 13 }line30 |
{7: 14 }mouse enabled |
{7: 15 }rows: 6, cols: 46 |
- {7: 16 } !"{1: } |
+ {7: 16 } !"^ |
{3:-- TERMINAL --} |
]])
end)
@@ -261,7 +261,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
- {1: } |
+ ^ |
========== |
{3:-- TERMINAL --} |
]])
@@ -271,7 +271,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
- {2:^ } |
+ ^ |
========== |
|
]])
@@ -280,7 +280,7 @@ describe(':terminal mouse', function()
mouse enabled |
rows: 5, cols: 50 |
rows: 4, cols: 50 |
- {2:^ } |
+ ^ |
========== |
|*2
]])
@@ -293,7 +293,7 @@ describe(':terminal mouse', function()
line30 │{4:~ }|
mouse enabled │{4:~ }|
rows: 5, cols: 24 │{4:~ }|
- {1: } │{4:~ }|
+ ^ │{4:~ }|
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -303,7 +303,7 @@ describe(':terminal mouse', function()
line30 │{4:~ }|
mouse enabled │{4:~ }|
rows: 5, cols: 24 │{4:~ }|
- {2:^ } │{4:~ }|
+ ^ │{4:~ }|
========== ========== |
|
]])
@@ -313,7 +313,7 @@ describe(':terminal mouse', function()
mouse enabled │{4:~ }|
rows: 5, cols: 24 │{4:~ }|
rows: 5, cols: 23 │{4:~ }|
- {2:^ } │{4:~ }|
+ ^ │{4:~ }|
========== ========== |
|
]])
@@ -327,7 +327,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
feed('<LeftMouse><0,0>')
@@ -337,7 +337,7 @@ describe(':terminal mouse', function()
line30 |
mouse enabled |
rows: 5, cols: 50 |
- {2:^ } |
+ ^ |
|
]])
command('set showtabline=2 tabline=TABLINE | startinsert')
@@ -347,7 +347,7 @@ describe(':terminal mouse', function()
mouse enabled |
rows: 5, cols: 50 |
rows: 4, cols: 50 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
feed('<LeftMouse><0,0>')
@@ -357,7 +357,7 @@ describe(':terminal mouse', function()
mouse enabled |
rows: 5, cols: 50 |
rows: 4, cols: 50 |
- {2:^ } |
+ ^ |
|
]])
command('setlocal winbar= | startinsert')
@@ -367,7 +367,7 @@ describe(':terminal mouse', function()
rows: 5, cols: 50 |
rows: 4, cols: 50 |
rows: 5, cols: 50 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
feed('<LeftMouse><0,0>')
@@ -377,7 +377,7 @@ describe(':terminal mouse', function()
rows: 5, cols: 50 |
rows: 4, cols: 50 |
rows: 5, cols: 50 |
- {2:^ } |
+ ^ |
|
]])
end)
@@ -391,7 +391,7 @@ describe(':terminal mouse', function()
line29 │line29 |
line30 │line30 |
rows: 5, cols: 25 │rows: 5, cols: 25 |
- {2:^ } │{2: } |
+ ^ │ |
========== ========== |
:vsp |
]])
@@ -401,7 +401,7 @@ describe(':terminal mouse', function()
{4:~ }│line30 |
{4:~ }│rows: 5, cols: 25 |
{4:~ }│rows: 5, cols: 24 |
- {4:~ }│{2: } |
+ {4:~ }│ |
========== ========== |
:enew | set number |
]])
@@ -411,7 +411,7 @@ describe(':terminal mouse', function()
{7: 28 }line │line30 |
{7: 29 }line │rows: 5, cols: 25 |
{7: 30 }line │rows: 5, cols: 24 |
- {7: 31 }^ │{2: } |
+ {7: 31 }^ │ |
========== ========== |
|
]])
@@ -421,7 +421,7 @@ describe(':terminal mouse', function()
{7: 28 }line │line30 |
{7: 29 }line │rows: 5, cols: 25 |
{7: 30 }line │rows: 5, cols: 24 |
- {7: 31 } │{1: } |
+ {7: 31 } │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -434,7 +434,7 @@ describe(':terminal mouse', function()
{7: 28 }line │rows: 5, cols: 25 |
{7: 29 }line │rows: 5, cols: 24 |
{7: 30 }line │mouse enabled |
- {7: 31 } │{1: } |
+ {7: 31 } │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -447,7 +447,7 @@ describe(':terminal mouse', function()
{7: 22 }line │rows: 5, cols: 25 |
{7: 23 }line │rows: 5, cols: 24 |
{7: 24 }line │mouse enabled |
- {7: 25 }line │{1: } |
+ {7: 25 }line │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -457,7 +457,7 @@ describe(':terminal mouse', function()
{7: 27 }line │rows: 5, cols: 25 |
{7: 28 }line │rows: 5, cols: 24 |
{7: 29 }line │mouse enabled |
- {7: 30 }line │{1: } |
+ {7: 30 }line │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -468,7 +468,7 @@ describe(':terminal mouse', function()
{7: 17 }line │rows: 5, cols: 25 |
{7: 18 }line │rows: 5, cols: 24 |
{7: 19 }line │mouse enabled |
- {7: 20 }line │{1: } |
+ {7: 20 }line │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -483,7 +483,7 @@ describe(':terminal mouse', function()
{7: 2 }linelinelinelineline │rows: 5, cols: 25 |
{7: 3 }linelinelinelineline │rows: 5, cols: 24 |
{7: 4 }linelinelinelineline │mouse enabled |
- {7: 5 }linelinelinelineline │{1: } |
+ {7: 5 }linelinelinelineline │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -493,7 +493,7 @@ describe(':terminal mouse', function()
{7: 2 }nelinelineline │rows: 5, cols: 25 |
{7: 3 }nelinelineline │rows: 5, cols: 24 |
{7: 4 }nelinelineline │mouse enabled |
- {7: 5 }nelinelineline │{1: } |
+ {7: 5 }nelinelineline │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -504,7 +504,7 @@ describe(':terminal mouse', function()
{7: 2 }nelinelinelineline │rows: 5, cols: 25 |
{7: 3 }nelinelinelineline │rows: 5, cols: 24 |
{7: 4 }nelinelinelineline │mouse enabled |
- {7: 5 }nelinelinelineline │{1: } |
+ {7: 5 }nelinelinelineline │^ |
========== ========== |
{3:-- TERMINAL --} |
]])
@@ -517,7 +517,7 @@ describe(':terminal mouse', function()
{7: 28 }l^ine │rows: 5, cols: 25 |
{7: 29 }line │rows: 5, cols: 24 |
{7: 30 }line │mouse enabled |
- {7: 31 } │{2: } |
+ {7: 31 } │ |
========== ========== |
|
]])
@@ -531,7 +531,7 @@ describe(':terminal mouse', function()
{7: 28 }line │rows: 5, cols: 25 |
{7: 29 }line │rows: 5, cols: 24 |
{7: 30 }line │mouse enabled |
- {7: 31 }^ │{2: } |
+ {7: 31 }^ │ |
========== ========== |
|
]])
@@ -541,7 +541,7 @@ describe(':terminal mouse', function()
rows: 5, cols: 24 │rows: 5, cols: 24 |
mouse enabled │mouse enabled |
rows: 5, cols: 25 │rows: 5, cols: 25 |
- {2:^ } │{2: } |
+ ^ │ |
========== ========== |
:bn |
]])
@@ -551,7 +551,7 @@ describe(':terminal mouse', function()
{7: 28 }line │mouse enabled |
{7: 29 }line │rows: 5, cols: 25 |
{7: 30 }line │rows: 5, cols: 24 |
- {7: 31 }^ │{2: } |
+ {7: 31 }^ │ |
========== ========== |
:bn |
]])
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 1751db1aa9..804c5367eb 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -39,7 +39,7 @@ describe(':terminal scrollback', function()
line28 |
line29 |
line30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -67,7 +67,7 @@ describe(':terminal scrollback', function()
line2 |
line3 |
line4 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -84,7 +84,7 @@ describe(':terminal scrollback', function()
line3 |
line4 |
line5 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
eq(7, api.nvim_buf_line_count(0))
@@ -102,7 +102,7 @@ describe(':terminal scrollback', function()
line5 |
line6 |
line7 |
- line8{1: } |
+ line8^ |
{3:-- TERMINAL --} |
]])
@@ -135,7 +135,7 @@ describe(':terminal scrollback', function()
line5 |
line6 |
line7 |
- ^line8{2: } |
+ ^line8 |
|
]])
end)
@@ -151,7 +151,7 @@ describe(':terminal scrollback', function()
line3 |
line4 |
rows: 5, cols: 28 |
- {2:^ } |
+ ^ |
|
]])
end
@@ -168,7 +168,7 @@ describe(':terminal scrollback', function()
screen:expect([[
rows: 5, cols: 28 |
rows: 3, cols: 26 |
- {2:^ } |
+ ^ |
|
]])
eq(8, api.nvim_buf_line_count(0))
@@ -201,7 +201,7 @@ describe(':terminal scrollback', function()
screen:expect([[
tty ready |
rows: 4, cols: 30 |
- {1: } |
+ ^ |
|
{3:-- TERMINAL --} |
]])
@@ -220,7 +220,7 @@ describe(':terminal scrollback', function()
screen:expect([[
rows: 4, cols: 30 |
rows: 3, cols: 30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
eq(4, api.nvim_buf_line_count(0))
@@ -235,7 +235,7 @@ describe(':terminal scrollback', function()
screen:expect([[
rows: 4, cols: 30 |
rows: 3, cols: 30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -252,14 +252,14 @@ describe(':terminal scrollback', function()
line2 |
line3 |
line4 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
screen:try_resize(screen._width, screen._height - 3)
screen:expect([[
line4 |
rows: 3, cols: 30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
eq(7, api.nvim_buf_line_count(0))
@@ -278,7 +278,7 @@ describe(':terminal scrollback', function()
line4 |
rows: 3, cols: 30 |
rows: 4, cols: 30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end
@@ -300,7 +300,7 @@ describe(':terminal scrollback', function()
rows: 3, cols: 30 |
rows: 4, cols: 30 |
rows: 7, cols: 30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
eq(9, api.nvim_buf_line_count(0))
@@ -337,7 +337,7 @@ describe(':terminal scrollback', function()
rows: 4, cols: 30 |
rows: 7, cols: 30 |
rows: 11, cols: 30 |
- {1: } |
+ ^ |
|
{3:-- TERMINAL --} |
]])
@@ -355,14 +355,16 @@ describe(':terminal prints more lines than the screen height and exits', functio
it('will push extra lines to scrollback', function()
clear()
local screen = Screen.new(30, 7, { rgb = false })
- command(("call termopen(['%s', '10']) | startinsert"):format(testprg('tty-test')))
+ command(
+ ("call jobstart(['%s', '10'], {'term':v:true}) | startinsert"):format(testprg('tty-test'))
+ )
screen:expect([[
line6 |
line7 |
line8 |
line9 |
|
- [Process exited 0]{2: } |
+ [Process exited 0]^ |
{5:-- TERMINAL --} |
]])
feed('<cr>')
@@ -454,7 +456,7 @@ describe("'scrollback' option", function()
39: line |
40: line |
|
- ${1: } |
+ $^ |
{3:-- TERMINAL --} |
]],
}
@@ -493,7 +495,7 @@ describe("'scrollback' option", function()
line28 |
line29 |
line30 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
local term_height = 6 -- Actual terminal screen height, not the scrollback
@@ -623,7 +625,7 @@ describe('pending scrollback line handling', function()
local bufnr = vim.api.nvim_create_buf(false, true)
local args = ...
vim.api.nvim_buf_call(bufnr, function()
- vim.fn.termopen(args)
+ vim.fn.jobstart(args, { term = true })
end)
vim.api.nvim_win_set_buf(0, bufnr)
vim.cmd('startinsert')
@@ -634,7 +636,7 @@ describe('pending scrollback line handling', function()
screen:expect [[
hi |*4
|
- [Process exited 0]{2: } |
+ [Process exited 0]^ |
{3:-- TERMINAL --} |
]]
assert_alive()
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index ded0cd99d3..a2dc3c500f 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -26,7 +26,6 @@ local api = n.api
local is_ci = t.is_ci
local is_os = t.is_os
local new_pipename = n.new_pipename
-local spawn_argv = n.spawn_argv
local set_session = n.set_session
local write_file = t.write_file
local eval = n.eval
@@ -59,7 +58,7 @@ describe('TUI', function()
'colorscheme vim',
})
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -105,7 +104,7 @@ describe('TUI', function()
-- Need buffer rows to provoke the behavior.
feed_data(':edit test/functional/fixtures/bigfile.txt\n')
screen:expect([[
- {1:0}000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
+ ^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; |
0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; |
0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; |
@@ -155,7 +154,7 @@ describe('TUI', function()
{8:FAIL 0} |
{8:FAIL 1} |
{8:FAIL 2} |
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -170,7 +169,7 @@ describe('TUI', function()
{8:FAIL 1} |
{8:FAIL 2} |
|*2
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -186,7 +185,7 @@ describe('TUI', function()
{8:FAIL 3} |
{8:FAIL 4} |
{8:FAIL 5} |
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -199,7 +198,7 @@ describe('TUI', function()
{8:FAIL 3} |
{8:FAIL 4} |
{8:FAIL 5} |
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -210,7 +209,7 @@ describe('TUI', function()
{8:FAIL 3} |
{8:FAIL 4} |
{8:FAIL 5} |
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -221,7 +220,7 @@ describe('TUI', function()
:call ManyErr() |
{8:Error detected while processing function ManyErr:} |
{11:line 2:} |
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -237,7 +236,7 @@ describe('TUI', function()
{8:FAIL 2} |
{8:FAIL 3} |
{8:FAIL 4} |
- {10:-- More --}{1: } |
+ {10:-- More --}^ |
{3:-- TERMINAL --} |
]],
}
@@ -245,7 +244,7 @@ describe('TUI', function()
feed_data('\003')
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*6
{5:[No Name] }|
|
@@ -259,7 +258,7 @@ describe('TUI', function()
screen:expect([[
abc |
test1 |
- test2{1: } |
+ test2^ |
{4:~ }|
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -269,7 +268,7 @@ describe('TUI', function()
screen:expect([[
abc |
test1 |
- test{1:2} |
+ test^2 |
{4:~ }|
{5:[No Name] [+] }|
|
@@ -287,14 +286,14 @@ describe('TUI', function()
alt-j |
alt-k |
alt-l |
- {1: } |
+ ^ |
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
]])
feed_data('gg')
screen:expect([[
- {1:a}lt-d |
+ ^alt-d |
alt-f |
alt-g |
alt-h |
@@ -309,7 +308,7 @@ describe('TUI', function()
-- ALT+j inserts "ê". Nvim does not (#3982).
feed_data('i\022\027j')
screen:expect([[
- <M-j>{1: } |
+ <M-j>^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -329,7 +328,7 @@ describe('TUI', function()
)
feed_data('\027[27u;')
screen:expect([[
- ESCsemicolo{1:n} |
+ ESCsemicolo^n |
{4:~ }|*3
{5:[No Name] [+] }|
|
@@ -343,7 +342,7 @@ describe('TUI', function()
it('interprets <Esc><Nul> as <M-C-Space> #17198', function()
feed_data('i\022\027\000')
screen:expect([[
- <M-C-Space>{1: } |
+ <M-C-Space>^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -357,7 +356,7 @@ describe('TUI', function()
feed_data('\022\022') -- ctrl+v
feed_data('\022\013') -- ctrl+m
screen:expect([[
- {6:^G^V^M}{1: } |
+ {6:^G^V^M}^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -376,7 +375,7 @@ describe('TUI', function()
{}
)
screen:expect([[
- {11: 1 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 1 }^0----1----2----3----4│{11: 1 }0----1----2----3----|
{11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
@@ -391,7 +390,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'down', '', 0, 0, 7)
end
screen:expect([[
- {11: 2 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----|
+ {11: 2 }^0----1----2----3----4│{11: 1 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 4 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 5 }0----1----2----3----4│{11: 4 }0----1----2----3----|
@@ -406,7 +405,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'down', '', 0, 0, 47)
end
screen:expect([[
- {11: 2 }{1:0}----1----2----3----4│{11: 2 }0----1----2----3----|
+ {11: 2 }^0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
{11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----|
{11: 5 }0----1----2----3----4│{11: 5 }0----1----2----3----|
@@ -421,7 +420,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'right', '', 0, 0, 7)
end
screen:expect([[
- {11: 2 }{1:-}---1----2----3----4-│{11: 2 }0----1----2----3----|
+ {11: 2 }^----1----2----3----4-│{11: 2 }0----1----2----3----|
{11: 3 }----1----2----3----4-│{11: 3 }0----1----2----3----|
{11: 4 }----1----2----3----4-│{11: 4 }0----1----2----3----|
{11: 5 }----1----2----3----4-│{11: 5 }0----1----2----3----|
@@ -436,7 +435,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'right', '', 0, 0, 47)
end
screen:expect([[
- {11: 2 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
+ {11: 2 }^----1----2----3----4-│{11: 2 }----1----2----3----4|
{11: 3 }----1----2----3----4-│{11: 3 }----1----2----3----4|
{11: 4 }----1----2----3----4-│{11: 4 }----1----2----3----4|
{11: 5 }----1----2----3----4-│{11: 5 }----1----2----3----4|
@@ -451,7 +450,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'down', 'S', 0, 0, 7)
end
screen:expect([[
- {11: 5 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4|
+ {11: 5 }^----1----2----3----4-│{11: 2 }----1----2----3----4|
{11: 6 }----1----2----3----4-│{11: 3 }----1----2----3----4|
{11: 7 }----1----2----3----4-│{11: 4 }----1----2----3----4|
{11: 8 }----1----2----3----4-│{11: 5 }----1----2----3----4|
@@ -466,7 +465,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'down', 'S', 0, 0, 47)
end
screen:expect([[
- {11: 5 }{1:-}---1----2----3----4-│{11: 5 }----1----2----3----4|
+ {11: 5 }^----1----2----3----4-│{11: 5 }----1----2----3----4|
{11: 6 }----1----2----3----4-│{11: 6 }----1----2----3----4|
{11: 7 }----1----2----3----4-│{11: 7 }----1----2----3----4|
{11: 8 }----1----2----3----4-│{11: 8 }----1----2----3----4|
@@ -481,7 +480,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'right', 'S', 0, 0, 7)
end
screen:expect([[
- {11: 5 }{1:-}---6----7----8----9 │{11: 5 }----1----2----3----4|
+ {11: 5 }^----6----7----8----9 │{11: 5 }----1----2----3----4|
{11: 6 }----6----7----8----9 │{11: 6 }----1----2----3----4|
{11: 7 }----6----7----8----9 │{11: 7 }----1----2----3----4|
{11: 8 }----6----7----8----9 │{11: 8 }----1----2----3----4|
@@ -496,7 +495,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'right', 'S', 0, 0, 47)
end
screen:expect([[
- {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 5 }^----6----7----8----9 │{11: 5 }5----6----7----8----|
{11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
{11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
{11: 8 }----6----7----8----9 │{11: 8 }5----6----7----8----|
@@ -512,7 +511,7 @@ describe('TUI', function()
end
screen:expect([[
{11: 4 }----6----7----8----9 │{11: 5 }5----6----7----8----|
- {11: 5 }{1:-}---6----7----8----9 │{11: 6 }5----6----7----8----|
+ {11: 5 }^----6----7----8----9 │{11: 6 }5----6----7----8----|
{11: 6 }----6----7----8----9 │{11: 7 }5----6----7----8----|
{11: 7 }----6----7----8----9 │{11: 8 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
@@ -527,7 +526,7 @@ describe('TUI', function()
end
screen:expect([[
{11: 4 }----6----7----8----9 │{11: 4 }5----6----7----8----|
- {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----|
+ {11: 5 }^----6----7----8----9 │{11: 5 }5----6----7----8----|
{11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----|
{11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
@@ -542,7 +541,7 @@ describe('TUI', function()
end
screen:expect([[
{11: 4 }5----6----7----8----9│{11: 4 }5----6----7----8----|
- {11: 5 }5{1:-}---6----7----8----9│{11: 5 }5----6----7----8----|
+ {11: 5 }5^----6----7----8----9│{11: 5 }5----6----7----8----|
{11: 6 }5----6----7----8----9│{11: 6 }5----6----7----8----|
{11: 7 }5----6----7----8----9│{11: 7 }5----6----7----8----|
{5:[No Name] [+] }{1:[No Name] [+] }|
@@ -557,7 +556,7 @@ describe('TUI', function()
end
screen:expect([[
{11: 4 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
- {11: 5 }5{1:-}---6----7----8----9│{11: 5 }-5----6----7----8---|
+ {11: 5 }5^----6----7----8----9│{11: 5 }-5----6----7----8---|
{11: 6 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
{11: 7 }5----6----7----8----9│{11: 7 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
@@ -574,7 +573,7 @@ describe('TUI', function()
{11: 1 }5----6----7----8----9│{11: 4 }-5----6----7----8---|
{11: 2 }5----6----7----8----9│{11: 5 }-5----6----7----8---|
{11: 3 }5----6----7----8----9│{11: 6 }-5----6----7----8---|
- {11: 4 }5{1:-}---6----7----8----9│{11: 7 }-5----6----7----8---|
+ {11: 4 }5^----6----7----8----9│{11: 7 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
@@ -589,7 +588,7 @@ describe('TUI', function()
{11: 1 }5----6----7----8----9│{11: 1 }-5----6----7----8---|
{11: 2 }5----6----7----8----9│{11: 2 }-5----6----7----8---|
{11: 3 }5----6----7----8----9│{11: 3 }-5----6----7----8---|
- {11: 4 }5{1:-}---6----7----8----9│{11: 4 }-5----6----7----8---|
+ {11: 4 }5^----6----7----8----9│{11: 4 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
@@ -604,7 +603,7 @@ describe('TUI', function()
{11: 1 }0----1----2----3----4│{11: 1 }-5----6----7----8---|
{11: 2 }0----1----2----3----4│{11: 2 }-5----6----7----8---|
{11: 3 }0----1----2----3----4│{11: 3 }-5----6----7----8---|
- {11: 4 }0----1----2----3----{1:4}│{11: 4 }-5----6----7----8---|
+ {11: 4 }0----1----2----3----^4│{11: 4 }-5----6----7----8---|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
@@ -619,7 +618,7 @@ describe('TUI', function()
{11: 1 }0----1----2----3----4│{11: 1 }0----1----2----3----|
{11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----|
{11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----|
- {11: 4 }0----1----2----3----{1:4}│{11: 4 }0----1----2----3----|
+ {11: 4 }0----1----2----3----^4│{11: 4 }0----1----2----3----|
{5:[No Name] [+] }{1:[No Name] [+] }|
|
{3:-- TERMINAL --} |
@@ -645,7 +644,7 @@ describe('TUI', function()
aunmenu PopUp
" Delete the default MenuPopup event handler.
- autocmd! nvim_popupmenu
+ 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>
@@ -660,7 +659,7 @@ describe('TUI', function()
api.nvim_input_mouse('right', 'press', '', 0, 0, 4)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }{13: foo }{4: }|
{4:~ }{13: bar }{4: }|
{4:~ }{13: baz }{4: }|
@@ -680,7 +679,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'up', '', 0, 0, 4)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }{14: foo }{4: }|
{4:~ }{13: bar }{4: }|
{4:~ }{13: baz }{4: }|
@@ -694,7 +693,7 @@ describe('TUI', function()
api.nvim_input_mouse('move', '', '', 0, 3, 6)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }{13: foo }{4: }|
{4:~ }{13: bar }{4: }|
{4:~ }{14: baz }{4: }|
@@ -708,7 +707,7 @@ describe('TUI', function()
api.nvim_input_mouse('wheel', 'down', '', 0, 3, 6)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }{13: foo }{4: }|
{4:~ }{14: bar }{4: }|
{4:~ }{13: baz }{4: }|
@@ -722,7 +721,7 @@ describe('TUI', function()
api.nvim_input_mouse('left', 'press', '', 0, 2, 6)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }|*3
{5:[No Name] [+] }|
:let g:menustr = 'bar' |
@@ -740,7 +739,7 @@ describe('TUI', function()
api.nvim_input_mouse('right', 'press', '', 0, 2, 44)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }|*2
{4:~ }{13: foo }{4: }|
{5:[No Name] [+] }{13: bar }{5: }|
@@ -753,7 +752,7 @@ describe('TUI', function()
api.nvim_input_mouse('right', 'drag', '', 0, 5, 47)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }|*2
{4:~ }{13: foo }{4: }|
{5:[No Name] [+] }{13: bar }{5: }|
@@ -766,7 +765,7 @@ describe('TUI', function()
api.nvim_input_mouse('right', 'release', '', 0, 5, 47)
end
screen:expect([[
- {1:p}opup menu test |
+ ^popup menu test |
{4:~ }|*3
{5:[No Name] [+] }|
:let g:menustr = 'baz' |
@@ -805,7 +804,7 @@ describe('TUI', function()
feed_data(fn.nr2char(57415)) -- KP_EQUAL
screen:expect([[
0123456789./*-+ |
- ={1: } |
+ =^ |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -814,7 +813,7 @@ describe('TUI', function()
feed_data(fn.nr2char(57417)) -- KP_LEFT
screen:expect([[
0123456789./*-+ |
- {1:=} |
+ ^= |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -823,7 +822,7 @@ describe('TUI', function()
feed_data(fn.nr2char(57418)) -- KP_RIGHT
screen:expect([[
0123456789./*-+ |
- ={1: } |
+ =^ |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -831,7 +830,7 @@ describe('TUI', function()
]])
feed_data(fn.nr2char(57419)) -- KP_UP
screen:expect([[
- 0{1:1}23456789./*-+ |
+ 0^123456789./*-+ |
= |
{4:~ }|*2
{5:[No Name] [+] }|
@@ -841,7 +840,7 @@ describe('TUI', function()
feed_data(fn.nr2char(57420)) -- KP_DOWN
screen:expect([[
0123456789./*-+ |
- ={1: } |
+ =^ |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -850,7 +849,7 @@ describe('TUI', function()
feed_data(fn.nr2char(57425)) -- KP_INSERT
screen:expect([[
0123456789./*-+ |
- ={1: } |
+ =^ |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- REPLACE --} |
@@ -859,7 +858,7 @@ describe('TUI', function()
feed_data('\027[27u') -- ESC
screen:expect([[
0123456789./*-+ |
- {1:=} |
+ ^= |
{4:~ }|*2
{5:[No Name] [+] }|
|
@@ -867,7 +866,7 @@ describe('TUI', function()
]])
feed_data('\027[57417;5u') -- CTRL + KP_LEFT
screen:expect([[
- {1:0}123456789./*-+ |
+ ^0123456789./*-+ |
= |
{4:~ }|*2
{5:[No Name] [+] }|
@@ -876,7 +875,7 @@ describe('TUI', function()
]])
feed_data('\027[57418;2u') -- SHIFT + KP_RIGHT
screen:expect([[
- 0123456789{1:.}/*-+ |
+ 0123456789^./*-+ |
= |
{4:~ }|*2
{5:[No Name] [+] }|
@@ -885,7 +884,7 @@ describe('TUI', function()
]])
feed_data(fn.nr2char(57426)) -- KP_DELETE
screen:expect([[
- 0123456789{1:/}*-+ |
+ 0123456789^/*-+ |
= |
{4:~ }|*2
{5:[No Name] [+] }|
@@ -894,7 +893,7 @@ describe('TUI', function()
]])
feed_data(fn.nr2char(57423)) -- KP_HOME
screen:expect([[
- {1:0}123456789/*-+ |
+ ^0123456789/*-+ |
= |
{4:~ }|*2
{5:[No Name] [+] }|
@@ -903,7 +902,7 @@ describe('TUI', function()
]])
feed_data(fn.nr2char(57424)) -- KP_END
screen:expect([[
- 0123456789/*-{1:+} |
+ 0123456789/*-^+ |
= |
{4:~ }|*2
{5:[No Name] [+] }|
@@ -921,7 +920,7 @@ describe('TUI', function()
)
screen:expect([[
{12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}|
- {1: } |
+ ^ |
{4:~ }|*2
{5:[No Name] }|
|
@@ -930,7 +929,7 @@ describe('TUI', function()
feed_data('\027[57421;5u') -- CTRL + KP_PAGE_UP
screen:expect([[
{12: + [No Name] }{3: + [No Name] }{12: [No Name] }{1: }{12:X}|
- 0123456789/*-{1:+} |
+ 0123456789/*-^+ |
= |
{4:~ }|
{5:[No Name] [+] }|
@@ -940,7 +939,7 @@ describe('TUI', function()
feed_data('\027[57422;5u') -- CTRL + KP_PAGE_DOWN
screen:expect([[
{12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}|
- {1: } |
+ ^ |
{4:~ }|*2
{5:[No Name] }|
|
@@ -961,7 +960,7 @@ describe('TUI', function()
feed_data('\022\027[57379;48u') -- Shift + Alt + Ctrl + Super + Meta + F16
screen:expect([[
<D-j><T-k><T-D-CR><M-T-C-S-D-BS> |
- <D-F13><T-F14><T-D-F15><M-T-C-S-D-F16>{1: } |
+ <D-F13><T-F14><T-D-F15><M-T-C-S-D-F16>^ |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -973,7 +972,7 @@ describe('TUI', function()
-- "bracketed paste"
feed_data('i""\027i\027[200~')
screen:expect([[
- "{1:"} |
+ "^" |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -982,7 +981,7 @@ describe('TUI', function()
feed_data('pasted from terminal')
expect_child_buf_lines({ '"pasted from terminal"' })
screen:expect([[
- "pasted from terminal{1:"} |
+ "pasted from terminal^" |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -994,7 +993,7 @@ describe('TUI', function()
feed_data('\027[27u') -- ESC: go to Normal mode.
wait_for_mode('n')
screen:expect([[
- "pasted from termina{1:l}" |
+ "pasted from termina^l" |
{4:~ }|*3
{5:[No Name] [+] }|
|
@@ -1005,7 +1004,7 @@ describe('TUI', function()
expect_child_buf_lines({ '"pasted from terminapasted from terminalpasted from terminall"' })
screen:expect([[
"pasted from terminapasted from terminalpasted fro|
- m termina{1:l}l" |
+ m termina^ll" |
{4:~ }|*2
{5:[No Name] [+] }|
|
@@ -1027,7 +1026,7 @@ describe('TUI', function()
this is line 1 |
this is line 2 |
line 3 is here |
- {1: } |
+ ^ |
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
@@ -1037,7 +1036,7 @@ describe('TUI', function()
screen:expect([[
this{16: is line 1} |
{16:this is line 2} |
- {16:line}{1: }3 is here |
+ {16:line}^ 3 is here |
|
{5:[No Name] [+] }|
{3:-- SELECT --} |
@@ -1047,7 +1046,7 @@ describe('TUI', function()
feed_data('just paste it™')
feed_data('\027[201~')
screen:expect([[
- thisjust paste it{1:™}3 is here |
+ thisjust paste it^™3 is here |
|
{4:~ }|*2
{5:[No Name] [+] }|
@@ -1084,7 +1083,7 @@ describe('TUI', function()
feed_data('i')
screen:expect([[
tty ready |
- {1: } |
+ ^ |
|*2
{19:^^^^^^^ }|
{3:-- TERMINAL --} |*2
@@ -1094,7 +1093,7 @@ describe('TUI', function()
feed_data('\027[201~')
screen:expect([[
tty ready |
- hallo{1: } |
+ hallo^ |
|*2
{19:^^^^^^^ }|
{3:-- TERMINAL --} |*2
@@ -1111,7 +1110,7 @@ describe('TUI', function()
local expected_grid1 = [[
line 1 |
ESC:{6:^[} / CR: |
- {1:x} |
+ ^x |
{4:~ }|
{5:[No Name] [+] 3,1 All}|
|
@@ -1126,7 +1125,7 @@ describe('TUI', function()
ESC:{6:^[} / CR: |
xline 1 |
ESC:{6:^[} / CR: |
- {1:x} |
+ ^x |
{5:[No Name] [+] 5,1 Bot}|
|
{3:-- TERMINAL --} |
@@ -1165,7 +1164,7 @@ describe('TUI', function()
|
{4:~ }|*2
{5:[No Name] [+] }|
- :"{1:"} |
+ :"^" |
{3:-- TERMINAL --} |
]])
-- "bracketed paste"
@@ -1179,7 +1178,7 @@ describe('TUI', function()
|
{4:~ }|*2
{5:[No Name] [+] }|
- :"line 1{1:"} |
+ :"line 1^" |
{3:-- TERMINAL --} |
]])
-- Dot-repeat/redo.
@@ -1188,7 +1187,7 @@ describe('TUI', function()
feed_data('.')
screen:expect([[
foo |*2
- {1: } |
+ ^ |
{4:~ }|
{5:[No Name] [+] }|
|
@@ -1235,7 +1234,7 @@ describe('TUI', function()
wait_for_mode('n')
screen:expect([[
foo |
- {1: } |
+ ^ |
{4:~ }|*2
{5:[No Name] [+] }|
|
@@ -1249,7 +1248,7 @@ describe('TUI', function()
{5: }|
{8:paste: Error executing lua: [string "<nvim>"]:4: f}|
{8:ake fail} |
- {10:Press ENTER or type command to continue}{1: } |
+ {10:Press ENTER or type command to continue}^ |
{3:-- TERMINAL --} |
]])
-- Remaining chunks are discarded after vim.paste() failure.
@@ -1265,7 +1264,7 @@ describe('TUI', function()
feed_data('.')
screen:expect([[
foo |*2
- {1: } |
+ ^ |
{4:~ }|
{5:[No Name] [+] }|
|
@@ -1275,7 +1274,7 @@ describe('TUI', function()
feed_data('ityped input...\027[27u')
screen:expect([[
foo |*2
- typed input..{1:.} |
+ typed input..^. |
{4:~ }|
{5:[No Name] [+] }|
|
@@ -1288,7 +1287,7 @@ describe('TUI', function()
foo |
typed input...line A |
line B |
- {1: } |
+ ^ |
{5:[No Name] [+] }|
|
{3:-- TERMINAL --} |
@@ -1352,7 +1351,7 @@ describe('TUI', function()
{5: }|
{8:paste: Error executing lua: Vim:E21: Cannot make c}|
{8:hanges, 'modifiable' is off} |
- {10:Press ENTER or type command to continue}{1: } |
+ {10:Press ENTER or type command to continue}^ |
{3:-- TERMINAL --} |
]])
feed_data('\n') -- <Enter> to dismiss hit-enter prompt
@@ -1361,7 +1360,7 @@ describe('TUI', function()
screen:expect([[
success 1 |
success 2 |
- {1: } |
+ ^ |
{4:~ }|
{5:[No Name] [+] }|
|
@@ -1380,7 +1379,7 @@ describe('TUI', function()
expected = expected .. ' end'
screen:expect([[
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz|
- zzzzzzzzzzzzzz end{1: } |
+ zzzzzzzzzzzzzz end^ |
{4:~ }|*2
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -1399,7 +1398,7 @@ describe('TUI', function()
|
{4:~ }|*3
{5:[No Name] }|
- :<{1: } |
+ :<^ |
{3:-- TERMINAL --} |
]])
end)
@@ -1420,7 +1419,7 @@ describe('TUI', function()
item 2997 |
item 2998 |
item 2999 |
- item 3000 end{1: } |
+ item 3000 end^ |
{5:[No Name] [+] 3000,14 Bot}|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
@@ -1433,7 +1432,7 @@ describe('TUI', function()
item 2997 |
item 2998 |
item 2999 |
- item 3000 en{1:d}d |
+ item 3000 en^dd |
{5:[No Name] [+] 5999,13 Bot}|
|
{3:-- TERMINAL --} |
@@ -1457,7 +1456,7 @@ describe('TUI', function()
|
pasted from terminal (1) |
{6:^[}[200~ |
- {1: } |
+ ^ |
{5:[No Name] [+] }|
{3:-- INSERT --} |
{3:-- TERMINAL --} |
@@ -1472,7 +1471,7 @@ describe('TUI', function()
-- Send "stop paste" sequence.
feed_data('\027[201~')
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
{3:-- INSERT --} |
@@ -1487,7 +1486,7 @@ describe('TUI', function()
feed_data('\027[2')
feed_data('00~pasted from terminal\027[201~')
screen:expect([[
- pasted from terminal{1: } |
+ pasted from terminal^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -1502,7 +1501,7 @@ describe('TUI', function()
feed_data('\027[200~pasted from terminal\027[20')
feed_data('1~')
screen:expect([[
- pasted from terminal{1: } |
+ pasted from terminal^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -1524,7 +1523,7 @@ describe('TUI', function()
wait_for_mode('i')
feed_data('\027[200~pasted') -- phase 1
screen:expect([[
- pasted{1: } |
+ pasted^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -1532,7 +1531,7 @@ describe('TUI', function()
]])
feed_data(' from terminal') -- phase 2
screen:expect([[
- pasted from terminal{1: } |
+ pasted from terminal^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -1568,7 +1567,7 @@ describe('TUI', function()
feed_data('\028\014') -- crtl+\ ctrl+N
feed_data(':set termguicolors?\n')
screen:expect([[
- {5:^}{6:G} |
+ {6:^^G} |
{2:~ }|*3
{3:[No Name] [+] }|
notermguicolors |
@@ -1577,7 +1576,7 @@ describe('TUI', function()
feed_data(':set termguicolors\n')
screen:expect([[
- {7:^}{8:G} |
+ {8:^^G} |
{9:~}{10: }|*3
{3:[No Name] [+] }|
:set termguicolors |
@@ -1586,7 +1585,7 @@ describe('TUI', function()
feed_data(':set notermguicolors\n')
screen:expect([[
- {5:^}{6:G} |
+ {6:^^G} |
{2:~ }|*3
{3:[No Name] [+] }|
:set notermguicolors |
@@ -1634,7 +1633,7 @@ describe('TUI', function()
child_exec_lua('vim.cmd.terminal(...)', testprg('tty-test'))
screen:expect {
grid = [[
- {1:t}ty ready |
+ ^tty ready |
|*3
{2:^^^^^^^ }|
|
@@ -1646,7 +1645,7 @@ describe('TUI', function()
)
screen:expect {
grid = [[
- {1:t}ty ready |
+ ^tty ready |
{4:text}{5:color}text |
|*2
{2:^^^^^^^ }|
@@ -1658,7 +1657,7 @@ describe('TUI', function()
feed_data(':set notermguicolors\n')
screen:expect {
grid = [[
- {1:t}ty ready |
+ ^tty ready |
{4:text}colortext |
|*2
{6:^^^^^^^}{7: }|
@@ -1681,7 +1680,7 @@ describe('TUI', function()
child_session:request('nvim_set_hl', 0, 'Visual', { undercurl = true })
feed_data('ifoobar\027V')
screen:expect([[
- {5:fooba}{1:r} |
+ {5:fooba}^r |
{4:~ }|*3
{2:[No Name] [+] }|
{3:-- VISUAL LINE --} |
@@ -1689,7 +1688,7 @@ describe('TUI', function()
]])
child_session:request('nvim_set_hl', 0, 'Visual', { underdouble = true })
screen:expect([[
- {6:fooba}{1:r} |
+ {6:fooba}^r |
{4:~ }|*3
{2:[No Name] [+] }|
{3:-- VISUAL LINE --} |
@@ -1777,7 +1776,7 @@ describe('TUI', function()
child_session:request('nvim_set_option_value', 'listchars', 'eol:$', { win = 0 })
feed_data('gg')
local singlewidth_screen = [[
- {13:℃}{12:℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
+ {12:^℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
{12:℃℃℃℃℃℃℃℃℃℃}{15:$}{12: }|
℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃|
℃℃℃℃℃℃℃℃℃℃{4:$} |
@@ -1788,7 +1787,7 @@ describe('TUI', function()
-- When grid assumes "℃" to be double-width but host terminal assumes it to be single-width,
-- the second cell of "℃" is a space and the attributes of the "℃" are applied to it.
local doublewidth_screen = [[
- {13:℃}{12: ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
+ {12:^℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
{12:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }|
{12:℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ }{15:$}{12: }|
℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ ℃ {4:@@@@}|
@@ -1821,7 +1820,7 @@ describe('TUI', function()
child_session:request('nvim_set_option_value', 'listchars', 'eol:$', { win = 0 })
feed_data('gg')
local singlewidth_screen = [[
- {13:✓}{12:✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓}|
+ {12:^✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓}|
{12:✓✓✓✓✓✓✓✓✓✓}{15:$}{12: }|
✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓|
✓✓✓✓✓✓✓✓✓✓{4:$} |
@@ -1832,7 +1831,7 @@ describe('TUI', function()
-- When grid assumes "✓" to be double-width but host terminal assumes it to be single-width,
-- the second cell of "✓" is a space and the attributes of the "✓" are applied to it.
local doublewidth_screen = [[
- {13:✓}{12: ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }|
+ {12:^✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }|
{12:✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }|
{12:✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ }{15:$}{12: }|
✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ {4:@@@@}|
@@ -1870,7 +1869,7 @@ describe('TUI', function()
-- Close the :intro message and redraw the lines.
feed_data('\n')
screen:expect([[
- {13:Ꝩ}{12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}|
+ {12:^ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}|
{12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}|*310
{12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ℃ }|
b |
@@ -1912,7 +1911,7 @@ describe('TUI', function()
-- Close the :intro message and redraw the lines.
feed_data('\n')
screen:expect([[
- {1:Ꝩ}ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ|
+ ^ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ|
ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ|*325
{3:-- TERMINAL --} |
]])
@@ -1925,7 +1924,7 @@ describe('TUI', function()
feed_data ':set visualbell\n'
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
:set visualbell |
@@ -1939,7 +1938,7 @@ describe('TUI', function()
feed_data 'i'
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
{3:-- INSERT --} |
@@ -1954,7 +1953,7 @@ describe('TUI', function()
grid = [[
Vim: Caught deadly signal 'SIGTERM' |
|*2
- [Process exited 1]{1: } |
+ [Process exited 1]^ |
|*2
{3:-- TERMINAL --} |
]],
@@ -1981,7 +1980,7 @@ describe('TUI', function()
[5] = { bold = true },
})
screen:expect([[
- {1: } |
+ ^ |
{2:~}{3: }|*3
{4:[No Name] }|
|
@@ -1989,7 +1988,7 @@ describe('TUI', function()
]])
feed_data('i')
screen:expect([[
- {1: } |
+ ^ |
{2:~}{3: }|*3
{4:[No Name] }|
{5:-- INSERT --} |
@@ -2000,7 +1999,7 @@ describe('TUI', function()
it('redraws on SIGWINCH even if terminal size is unchanged #23411', function()
child_session:request('nvim_echo', { { 'foo' } }, false, {})
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
foo |
@@ -2008,7 +2007,7 @@ describe('TUI', function()
]])
exec_lua([[vim.uv.kill(vim.fn.jobpid(vim.bo.channel), 'sigwinch')]])
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -2031,7 +2030,7 @@ describe('TUI', function()
]])
feed_data('\003')
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
Type :qa and press <Enter> to exit Nvim |
@@ -2046,7 +2045,7 @@ describe('TUI', function()
{1:foo} |
{4:~ }|*3
{5:[No Name] [+] }|
- /foo{1: } |
+ /foo^ |
{3:-- TERMINAL --} |
]])
screen:sleep(10)
@@ -2055,7 +2054,7 @@ describe('TUI', function()
foo |
{4:~ }|*3
{5:[No Name] [+] }|
- /foob{1: } |
+ /foob^ |
{3:-- TERMINAL --} |
]])
screen:sleep(10)
@@ -2064,7 +2063,7 @@ describe('TUI', function()
foo |
{4:~ }|*3
{5:[No Name] [+] }|
- /fooba{1: } |
+ /fooba^ |
{3:-- TERMINAL --} |
]])
end)
@@ -2114,7 +2113,7 @@ describe('TUI', function()
[5] = { bold = true, reverse = true },
[6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen },
})
- fn.termopen({
+ fn.jobstart({
nvim_prog,
'--clean',
'--cmd',
@@ -2124,6 +2123,7 @@ describe('TUI', function()
'--cmd',
'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile',
}, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -2146,7 +2146,7 @@ describe('TUI', function()
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)
- fn.termopen({
+ fn.jobstart({
nvim_prog,
'--clean',
'--cmd',
@@ -2154,6 +2154,7 @@ describe('TUI', function()
'--cmd',
'sleep 10',
}, {
+ term = true,
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
},
@@ -2194,7 +2195,7 @@ describe('TUI', function()
local screen = tt.setup_child_nvim({ '--clean', '-l', script_file })
screen:expect {
grid = [[
- {1: } |
+ ^ |
~ |*3
[No Name] 0,0-1 All|
|
@@ -2207,7 +2208,7 @@ describe('TUI', function()
Xargv0nvim |
--embed |
--clean |
- {1:X}argv0nvim |
+ ^Xargv0nvim |
[No Name] [+] 5,1 Bot|
4 more lines |
{3:-- TERMINAL --} |
@@ -2233,7 +2234,7 @@ describe('TUI', function()
:q |
abc |
|
- [Process exited 0]{1: } |
+ [Process exited 0]^ |
|
{3:-- TERMINAL --} |
]])
@@ -2254,7 +2255,7 @@ describe('TUI', function()
})
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -2264,7 +2265,7 @@ describe('TUI', function()
command([[call chansend(b:terminal_job_id, "\<C-h>")]])
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
<C-h> |
@@ -2287,7 +2288,7 @@ describe('TUI', function()
}, { cols = 80 })
screen:expect {
grid = [[
- {1:1}st line |
+ ^1st line |
|*2
2nd line |
{5:[No Name] [+] 1,1 All}|
@@ -2300,7 +2301,7 @@ describe('TUI', function()
grid = [[
1st line |
|
- {1: } |
+ ^ |
2nd line |
{5:[No Name] [+] 1,161 All}|
|
@@ -2320,7 +2321,7 @@ describe('TUI', function()
}, { extra_rows = 10, cols = 66 })
screen:expect {
grid = [[
- |
+ ^ |
aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12
aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@|
[No Name] [+] 1,0-1 Top|
@@ -2339,7 +2340,7 @@ describe('TUI', function()
-- 500-cell limit, so the buffer is flushed after these spaces.
screen:expect {
grid = [[
- |
+ ^ |
aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabb|*12
aabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba@@@|
[No Name] [+] 1,0-1 Top|
@@ -2366,7 +2367,7 @@ describe('TUI', function()
screen:expect {
grid = [[
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
~ |*3
[No Name] [+] 1,1 All|
|
@@ -2378,7 +2379,8 @@ describe('TUI', function()
feed_data(':set columns=12\n')
screen:expect {
grid = [[
- aaaaaaaaaaaa |*4
+ ^aaaaaaaaaaaa |
+ aaaaaaaaaaaa |*3
< [+] 1,1 |
|
-- TERMINAL -- |
@@ -2416,7 +2418,7 @@ describe('TUI UIEnter/UILeave', function()
})
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -2426,7 +2428,7 @@ describe('TUI UIEnter/UILeave', function()
feed_data(':echo g:evs\n')
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
['VimEnter', 'UIEnter'] |
@@ -2457,7 +2459,7 @@ describe('TUI FocusGained/FocusLost', function()
})
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -2479,7 +2481,7 @@ describe('TUI FocusGained/FocusLost', function()
retry(2, 3 * screen.timeout, function()
feed_data('\027[I')
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
gained |
@@ -2488,7 +2490,7 @@ describe('TUI FocusGained/FocusLost', function()
feed_data('\027[O')
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
lost |
@@ -2502,7 +2504,7 @@ describe('TUI FocusGained/FocusLost', function()
feed_data('i')
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
:set noshowmode |
@@ -2512,7 +2514,7 @@ describe('TUI FocusGained/FocusLost', function()
retry(2, 3 * screen.timeout, function()
feed_data('\027[I')
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
gained |
@@ -2520,7 +2522,7 @@ describe('TUI FocusGained/FocusLost', function()
]])
feed_data('\027[O')
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
lost |
@@ -2538,7 +2540,7 @@ describe('TUI FocusGained/FocusLost', function()
|
{4:~ }|*3
{5:[No Name] }|
- :{1: } |
+ :^ |
{3:-- TERMINAL --} |
]])
feed_data('\027[O')
@@ -2547,7 +2549,7 @@ describe('TUI FocusGained/FocusLost', function()
|
{4:~ }|*3
{5:[No Name] }|
- :{1: } |
+ :^ |
{3:-- TERMINAL --} |
]],
unchanged = true,
@@ -2590,7 +2592,7 @@ describe('TUI FocusGained/FocusLost', function()
-- Wait for terminal to be ready.
screen:expect {
grid = [[
- {1:r}eady $ zia |
+ ^ready $ zia |
|
[Process exited 0] |
|*2
@@ -2602,7 +2604,7 @@ describe('TUI FocusGained/FocusLost', function()
feed_data('\027[I')
screen:expect {
grid = [[
- {1:r}eady $ zia |
+ ^ready $ zia |
|
[Process exited 0] |
|*2
@@ -2614,7 +2616,7 @@ describe('TUI FocusGained/FocusLost', function()
feed_data('\027[O')
screen:expect([[
- {1:r}eady $ zia |
+ ^ready $ zia |
|
[Process exited 0] |
|*2
@@ -2634,7 +2636,7 @@ describe('TUI FocusGained/FocusLost', function()
msg3 |
msg4 |
msg5 |
- {10:Press ENTER or type command to continue}{1: } |
+ {10:Press ENTER or type command to continue}^ |
{3:-- TERMINAL --} |
]],
}
@@ -2647,7 +2649,7 @@ describe('TUI FocusGained/FocusLost', function()
msg3 |
msg4 |
msg5 |
- {10:Press ENTER or type command to continue}{1: } |
+ {10:Press ENTER or type command to continue}^ |
{3:-- TERMINAL --} |
]],
unchanged = true,
@@ -2690,7 +2692,7 @@ describe("TUI 't_Co' (terminal colors)", function()
screen:expect(string.format(
[[
- {1: } |
+ ^ |
%s|*4
|
{3:-- TERMINAL --} |
@@ -2701,7 +2703,7 @@ describe("TUI 't_Co' (terminal colors)", function()
feed_data(':echo &t_Co\n')
screen:expect(string.format(
[[
- {1: } |
+ ^ |
%s|*4
%-3s |
{3:-- TERMINAL --} |
@@ -3028,7 +3030,7 @@ describe('TUI', function()
-- Wait for TUI to start.
feed_data('Gitext')
screen:expect([[
- text{1: } |
+ text^ |
{4:~ }|*4
{3:-- INSERT --} |
{3:-- TERMINAL --} |
@@ -3045,7 +3047,7 @@ describe('TUI', function()
nvim_tui()
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@@ -3055,7 +3057,7 @@ describe('TUI', function()
screen:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@@ -3181,7 +3183,6 @@ describe('TUI', function()
local req = args.data
local payload = req:match('^\027P%+q([%x;]+)$')
if payload and vim.text.hexdecode(payload) == 'Ms' then
- vim.g.xtgettcap = 'Ms'
local resp = string.format('\027P1+r%s=%s\027\\', payload, vim.text.hexencode('\027]52;;\027\\'))
vim.api.nvim_chan_send(vim.bo[args.buf].channel, resp)
return true
@@ -3199,9 +3200,6 @@ describe('TUI', function()
}, {
env = {
VIMRUNTIME = os.getenv('VIMRUNTIME'),
-
- -- Only queries when SSH_TTY is set
- SSH_TTY = '/dev/pts/1',
},
})
@@ -3209,8 +3207,7 @@ describe('TUI', function()
local child_session = n.connect(child_server)
retry(nil, 1000, function()
- eq('Ms', eval("get(g:, 'xtgettcap', '')"))
- eq({ true, 'OSC 52' }, { child_session:request('nvim_eval', 'g:clipboard.name') })
+ eq({ true, { osc52 = true } }, { child_session:request('nvim_eval', 'g:termfeatures') })
end)
end)
end)
@@ -3305,13 +3302,39 @@ describe('TUI bg color', function()
'autocmd OptionSet background echo "did OptionSet, yay!"',
})
screen:expect([[
- {1: } |
+ ^ |
{3:~} |*3
{5:[No Name] 0,0-1 All}|
did OptionSet, yay! |
{3:-- TERMINAL --} |
]])
end)
+
+ it('sends theme update notifications when background changes #31652', function()
+ command('set background=dark') -- set outer Nvim background
+ local child_server = new_pipename()
+ local screen = tt.setup_child_nvim({
+ '--listen',
+ child_server,
+ '-u',
+ 'NONE',
+ '-i',
+ 'NONE',
+ '--cmd',
+ 'colorscheme vim',
+ '--cmd',
+ 'set noswapfile',
+ })
+ screen:expect({ any = '%[No Name%]' })
+ local child_session = n.connect(child_server)
+ retry(nil, nil, function()
+ eq({ true, 'dark' }, { child_session:request('nvim_eval', '&background') })
+ end)
+ command('set background=light') -- set outer Nvim background
+ retry(nil, nil, function()
+ eq({ true, 'light' }, { child_session:request('nvim_eval', '&background') })
+ end)
+ end)
end)
-- These tests require `tt` because --headless/--embed
@@ -3322,8 +3345,8 @@ describe('TUI as a client', function()
end)
it('connects to remote instance (with its own TUI)', function()
- local server_super = spawn_argv(false) -- equivalent to clear()
- local client_super = spawn_argv(true)
+ local server_super = n.new_session(false)
+ local client_super = n.new_session(true)
set_session(server_super)
local server_pipe = new_pipename()
@@ -3343,7 +3366,7 @@ describe('TUI as a client', function()
feed_data('iHello, World')
screen_server:expect {
grid = [[
- Hello, World{1: } |
+ Hello, World^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -3353,7 +3376,7 @@ describe('TUI as a client', function()
feed_data('\027')
screen_server:expect {
grid = [[
- Hello, Worl{1:d} |
+ Hello, Worl^d |
{4:~ }|*3
{5:[No Name] [+] }|
|
@@ -3370,7 +3393,7 @@ describe('TUI as a client', function()
screen_client:expect {
grid = [[
- Hello, Worl{1:d} |
+ Hello, Worl^d |
{4:~ }|*3
{5:[No Name] [+] }|
|
@@ -3383,7 +3406,7 @@ describe('TUI as a client', function()
feed_data('0:set lines=3\n')
screen_server:expect {
grid = [[
- {1:a}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{5:[No Name] [+] }|
|*4
{3:-- TERMINAL --} |
@@ -3397,8 +3420,8 @@ describe('TUI as a client', function()
end)
it('connects to remote instance (--headless)', function()
- local server = spawn_argv(false) -- equivalent to clear()
- local client_super = spawn_argv(true, { env = { NVIM_LOG_FILE = testlog } })
+ local server = n.new_session(false)
+ local client_super = n.new_session(true, { env = { NVIM_LOG_FILE = testlog } })
set_session(server)
local server_pipe = api.nvim_get_vvar('servername')
@@ -3414,7 +3437,7 @@ describe('TUI as a client', function()
screen_client:expect {
grid = [[
- Halloj{1:!} |
+ Halloj^! |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@@ -3428,7 +3451,7 @@ describe('TUI as a client', function()
grid = [[
Vim: Caught deadly signal 'SIGTERM' |
|*2
- [Process exited 1]{1: } |
+ [Process exited 1]^ |
|*2
{3:-- TERMINAL --} |
]],
@@ -3457,15 +3480,15 @@ describe('TUI as a client', function()
screen:expect([[
Remote ui failed to start: {MATCH:.*}|
|
- [Process exited 1]{1: } |
+ [Process exited 1]^ |
|*3
{3:-- TERMINAL --} |
]])
end)
local function test_remote_tui_quit(status)
- local server_super = spawn_argv(false) -- equivalent to clear()
- local client_super = spawn_argv(true)
+ local server_super = n.new_session(false)
+ local client_super = n.new_session(true)
set_session(server_super)
local server_pipe = new_pipename()
@@ -3483,7 +3506,7 @@ describe('TUI as a client', function()
})
screen_server:expect {
grid = [[
- {1: } |
+ ^ |
{4:~ }|*3
{5:[No Name] }|
|
@@ -3494,7 +3517,7 @@ describe('TUI as a client', function()
feed_data('iHello, World')
screen_server:expect {
grid = [[
- Hello, World{1: } |
+ Hello, World^ |
{4:~ }|*3
{5:[No Name] [+] }|
{3:-- INSERT --} |
@@ -3504,7 +3527,7 @@ describe('TUI as a client', function()
feed_data('\027')
screen_server:expect {
grid = [[
- Hello, Worl{1:d} |
+ Hello, Worl^d |
{4:~ }|*3
{5:[No Name] [+] }|
|
@@ -3521,7 +3544,7 @@ describe('TUI as a client', function()
screen_client:expect {
grid = [[
- Hello, Worl{1:d} |
+ Hello, Worl^d |
{4:~ }|*3
{5:[No Name] [+] }|
|
@@ -3536,7 +3559,7 @@ describe('TUI as a client', function()
screen_server:expect {
grid = [[
|
- [Process exited ]] .. status .. [[]{1: }{MATCH:%s+}|
+ [Process exited ]] .. status .. [[]^ {MATCH:%s+}|
|*4
{3:-- TERMINAL --} |
]],
@@ -3545,7 +3568,7 @@ describe('TUI as a client', function()
screen_client:expect {
grid = [[
|
- [Process exited ]] .. status .. [[]{1: }{MATCH:%s+}|
+ [Process exited ]] .. status .. [[]^ {MATCH:%s+}|
|*4
{3:-- TERMINAL --} |
]],
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index fdb606e959..a65d18de70 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -62,7 +62,7 @@ describe(':terminal window', function()
screen:expect([[
{7:1 }tty ready |
{7:2 }rows: 6, cols: 48 |
- {7:3 }{1: } |
+ {7:3 }^ |
{7:4 } |
{7:5 } |
{7:6 } |
@@ -73,7 +73,7 @@ describe(':terminal window', function()
{7:1 }tty ready |
{7:2 }rows: 6, cols: 48 |
{7:3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV|
- {7:4 }WXYZ{1: } |
+ {7:4 }WXYZ^ |
{7:5 } |
{7:6 } |
{3:-- TERMINAL --} |
@@ -87,7 +87,7 @@ describe(':terminal window', function()
{7: 2 }rows: 6, cols: 48 |
{7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
{7: 4 }PQRSTUVWXYZrows: 6, cols: 41 |
- {7: 5 }{1: } |
+ {7: 5 }^ |
{7: 6 } |
{3:-- TERMINAL --} |
]])
@@ -98,7 +98,7 @@ describe(':terminal window', function()
{7: 3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
{7: 4 }PQRSTUVWXYZrows: 6, cols: 41 |
{7: 5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN|
- {7: 6 }OPQRSTUVWXYZ{1: } |
+ {7: 6 }OPQRSTUVWXYZ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -110,7 +110,7 @@ describe(':terminal window', function()
screen:expect([[
{7:++1 }tty ready |
{7:++2 }rows: 6, cols: 45 |
- {7:++3 }{1: } |
+ {7:++3 }^ |
{7:++4 } |
{7:++5 } |
{7:++6 } |
@@ -123,7 +123,7 @@ describe(':terminal window', function()
{7:++6 } |
{7:++7 } |
{7:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS|
- {7:++9 }TUVWXYZ{1: } |
+ {7:++9 }TUVWXYZ^ |
{3:-- TERMINAL --} |
]])
feed_data('\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
@@ -133,7 +133,7 @@ describe(':terminal window', function()
{7:++ 9 }STUVWXYZ |
{7:++10 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR|
{7:++11 }STUVWXYZrows: 6, cols: 44 |
- {7:++12 }{1: } |
+ {7:++12 }^ |
{3:-- TERMINAL --} |
]])
end)
@@ -144,7 +144,7 @@ describe(':terminal window', function()
feed([[<C-\><C-N>]])
screen:expect([[
tty ready |
- {2:^ } |
+ ^ |
|*5
]])
feed(':set colorcolumn=20<CR>i')
@@ -153,7 +153,7 @@ describe(':terminal window', function()
it('wont show the color column', function()
screen:expect([[
tty ready |
- {1: } |
+ ^ |
|*4
{3:-- TERMINAL --} |
]])
@@ -170,7 +170,7 @@ describe(':terminal window', function()
line2 |
line3 |
line4 |
- {1: } |
+ ^ |
{3:-- TERMINAL --} |
]])
end)
@@ -184,7 +184,7 @@ describe(':terminal window', function()
line2 |
line3 |
line4 |
- {2: } |
+ |
|
]])
end)
@@ -206,7 +206,7 @@ describe(':terminal with multigrid', function()
[3:--------------------------------------------------]|
## grid 2
tty ready |
- {1: } |
+ ^ |
|*4
## grid 3
{3:-- TERMINAL --} |
@@ -223,7 +223,7 @@ describe(':terminal with multigrid', function()
## grid 2
tty ready |
rows: 10, cols: 20 |
- {1: } |
+ ^ |
|*7
## grid 3
{3:-- TERMINAL --} |
@@ -241,7 +241,7 @@ describe(':terminal with multigrid', function()
## grid 2
rows: 10, cols: 20 |
rows: 3, cols: 70 |
- {1: } |
+ ^ |
## grid 3
{3:-- TERMINAL --} |
]])
@@ -260,7 +260,7 @@ describe(':terminal with multigrid', function()
rows: 10, cols: 20 |
rows: 3, cols: 70 |
rows: 6, cols: 50 |
- {1: } |
+ ^ |
|
## grid 3
{3:-- TERMINAL --} |
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 272fc513af..dc22c87ca0 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -49,7 +49,7 @@ describe(':terminal', function()
========== |
tty ready |
rows: 5, cols: 50 |
- {2: } |
+ |
|*2
========== |
:2split |
@@ -61,7 +61,7 @@ describe(':terminal', function()
========== |
^tty ready |
rows: 5, cols: 50 |
- {2: } |
+ |
|*2
========== |
:wincmd p |
@@ -77,7 +77,7 @@ describe(':terminal', function()
command('bprevious')
screen:expect([[
tty ready |
- ^foo{2: } |
+ ^foo |
|*8
]])
end)
@@ -102,7 +102,7 @@ describe(':terminal', function()
screen:expect([[
tty ready |
rows: 7, cols: 47 |
- {2: } |
+ |
|*3
^ |
|
@@ -112,7 +112,7 @@ describe(':terminal', function()
tty ready |
rows: 7, cols: 47 |
rows: 4, cols: 41 |
- {2:^ } |
+ ^ |
|
]])
end)
diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua
index 60b2f872fc..59cb593cf7 100644
--- a/test/functional/testnvim.lua
+++ b/test/functional/testnvim.lua
@@ -4,7 +4,7 @@ local t = require('test.testutil')
local Session = require('test.client.session')
local uv_stream = require('test.client.uv_stream')
local SocketStream = uv_stream.SocketStream
-local ChildProcessStream = uv_stream.ChildProcessStream
+local ProcStream = uv_stream.ProcStream
local check_cores = t.check_cores
local check_logs = t.check_logs
@@ -48,6 +48,16 @@ M.nvim_argv = {
'unlet g:colors_name',
'--embed',
}
+if os.getenv('OSV_PORT') then
+ table.insert(M.nvim_argv, '--cmd')
+ table.insert(
+ M.nvim_argv,
+ string.format(
+ "lua require('osv').launch({ port = %s, blocking = true })",
+ os.getenv('OSV_PORT')
+ )
+ )
+end
-- Directory containing nvim.
M.nvim_dir = M.nvim_prog:gsub('[/\\][^/\\]+$', '')
@@ -308,24 +318,14 @@ function M.stop()
assert(session):stop()
end
-function M.nvim_prog_abs()
- -- system(['build/bin/nvim']) does not work for whatever reason. It must
- -- be executable searched in $PATH or something starting with / or ./.
- if M.nvim_prog:match('[/\\]') then
- return M.request('nvim_call_function', 'fnamemodify', { M.nvim_prog, ':p' })
- else
- return M.nvim_prog
- end
-end
-
-- Use for commands which expect nvim to quit.
-- The first argument can also be a timeout.
function M.expect_exit(fn_or_timeout, ...)
local eof_err_msg = 'EOF was received from Nvim. Likely the Nvim process crashed.'
if type(fn_or_timeout) == 'function' then
- eq(eof_err_msg, t.pcall_err(fn_or_timeout, ...))
+ t.matches(eof_err_msg, t.pcall_err(fn_or_timeout, ...))
else
- eq(
+ t.matches(
eof_err_msg,
t.pcall_err(function(timeout, fn, ...)
fn(...)
@@ -455,22 +455,6 @@ function M.check_close()
session = nil
end
---- @param argv string[]
---- @param merge boolean?
---- @param env string[]?
---- @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)
- if not keep then
- M.check_close()
- end
-
- local child_stream =
- ChildProcessStream.spawn(merge and M.merge_args(prepend_argv, argv) or argv, env, io_extra)
- return Session.new(child_stream)
-end
-
-- Creates a new Session connected by domain socket (named pipe) or TCP.
function M.connect(file_or_address)
local addr, port = string.match(file_or_address, '(.*):(%d+)')
@@ -479,61 +463,112 @@ function M.connect(file_or_address)
return Session.new(stream)
end
--- Starts (and returns) a new global Nvim session.
---
--- Parameters are interpreted as startup args, OR a map with these keys:
--- args: List: Args appended to the default `nvim_argv` set.
--- args_rm: List: Args removed from the default set. All cases are
--- removed, e.g. args_rm={'--cmd'} removes all cases of "--cmd"
--- (and its value) from the default set.
--- env: Map: Defines the environment of the new session.
---
--- Example:
--- clear('-e')
--- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}}
+--- Starts a new, global Nvim session and clears the current one.
+---
+--- Note: Use `new_session()` to start a session without replacing the current one.
+---
+--- Parameters are interpreted as startup args, OR a map with these keys:
+--- - args: List: Args appended to the default `nvim_argv` set.
+--- - args_rm: List: Args removed from the default set. All cases are
+--- removed, e.g. args_rm={'--cmd'} removes all cases of "--cmd"
+--- (and its value) from the default set.
+--- - env: Map: Defines the environment of the new session.
+---
+--- Example:
+--- ```
+--- clear('-e')
+--- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}}
+--- ```
+---
+--- @param ... string Nvim CLI args
+--- @return test.Session
+--- @overload fun(opts: test.session.Opts): test.Session
function M.clear(...)
- M.set_session(M.spawn_argv(false, ...))
+ M.set_session(M.new_session(false, ...))
return M.get_session()
end
---- same params as clear, but does returns the session instead
---- of replacing the default session
+--- Starts a new Nvim process with the given args and returns a msgpack-RPC session.
+---
+--- Does not replace the current global session, unlike `clear()`.
+---
+--- @param keep boolean (default: false) Don't close the current global session.
+--- @param ... string Nvim CLI args (or see overload)
--- @return test.Session
-function M.spawn_argv(keep, ...)
- local argv, env, io_extra = M.new_argv(...)
- return M.spawn(argv, nil, env, keep, io_extra)
+--- @overload fun(keep: boolean, opts: test.session.Opts): test.Session
+function M.new_session(keep, ...)
+ if not keep then
+ M.check_close()
+ end
+
+ local argv, env, io_extra = M._new_argv(...)
+
+ local proc = ProcStream.spawn(argv, env, io_extra)
+ return Session.new(proc)
end
---- @class test.new_argv.Opts
+--- Starts a (non-RPC, `--headless --listen "Tx"`) Nvim process, waits for exit, and returns result.
+---
+--- @param ... string Nvim CLI args, or `test.session.Opts` table.
+--- @return test.ProcStream
+--- @overload fun(opts: test.session.Opts): test.ProcStream
+function M.spawn_wait(...)
+ local opts = type(...) == 'string' and { args = { ... } } or ...
+ opts.args_rm = opts.args_rm and opts.args_rm or {}
+ table.insert(opts.args_rm, '--embed')
+ local argv, env, io_extra = M._new_argv(opts)
+ local proc = ProcStream.spawn(argv, env, io_extra)
+ proc.collect_text = true
+ proc:read_start()
+ proc:wait()
+ proc:close()
+ return proc
+end
+
+--- @class test.session.Opts
+--- Nvim CLI args
--- @field args? string[]
+--- Remove these args from the default `nvim_argv` args set. Ignored if `merge=false`.
--- @field args_rm? string[]
+--- (default: true) Merge `args` with the default set. Else use only the provided `args`.
+--- @field merge? boolean
+--- Environment variables
--- @field env? table<string,string>
+--- Used for stdin_fd, see `:help ui-option`
--- @field io_extra? uv.uv_pipe_t
---- Builds an argument list for use in clear().
+--- @private
---
---- @see clear() for parameters.
---- @param ... string
+--- Builds an argument list for use in `new_session()`, `clear()`, and `spawn_wait()`.
+---
+--- @param ... string Nvim CLI args, or `test.session.Opts` table.
--- @return string[]
--- @return string[]?
--- @return uv.uv_pipe_t?
-function M.new_argv(...)
- local args = { unpack(M.nvim_argv) }
- table.insert(args, '--headless')
- if _G._nvim_test_id then
- -- Set the server name to the test-id for logging. #8519
- table.insert(args, '--listen')
- table.insert(args, _G._nvim_test_id)
+--- @overload fun(opts: test.session.Opts): string[], string[]?, uv.uv_pipe_t?
+function M._new_argv(...)
+ --- @type test.session.Opts|string
+ local opts = select(1, ...)
+ local merge = type(opts) ~= 'table' and true or opts.merge ~= false
+
+ local args = merge and { unpack(M.nvim_argv) } or { M.nvim_prog }
+ if merge then
+ table.insert(args, '--headless')
+ if _G._nvim_test_id then
+ -- Set the server name to the test-id for logging. #8519
+ table.insert(args, '--listen')
+ table.insert(args, _G._nvim_test_id)
+ end
end
+
local new_args --- @type string[]
local io_extra --- @type uv.uv_pipe_t?
- local env --- @type string[]?
- --- @type test.new_argv.Opts|string
- local opts = select(1, ...)
+ local env --- @type string[]? List of "key=value" env vars.
+
if type(opts) ~= 'table' then
new_args = { ... }
else
- args = remove_args(args, opts.args_rm)
+ args = merge and remove_args(args, opts.args_rm) or args
if opts.env then
local env_opt = {} --- @type table<string,string>
for k, v in pairs(opts.env) do
@@ -800,81 +835,6 @@ function M.exec_capture(code)
return M.api.nvim_exec2(code, { output = true }).output
end
---- @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.
@@ -921,52 +881,7 @@ function M.exec_lua(code, ...)
end
assert(session, 'no Nvim session')
-
- if not session.exec_lua_setup then
- assert(
- session:request(
- '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
-
- local stat, rv = session:request(
- 'nvim_exec_lua',
- 'return { _G.__test_exec_lua:handler(...) }',
- { string.dump(code), get_upvalues(code), ... }
- )
-
- if not stat then
- error(rv[2])
- end
-
- --- @type any[], table<string,any>
- local ret, upvalues = unpack(rv)
-
- -- 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))
+ return require('test.functional.testnvim.exec_lua')(session, 2, code, ...)
end
function M.get_pathsep()
diff --git a/test/functional/testnvim/exec_lua.lua b/test/functional/testnvim/exec_lua.lua
new file mode 100644
index 0000000000..ddd9905ce7
--- /dev/null
+++ b/test/functional/testnvim/exec_lua.lua
@@ -0,0 +1,148 @@
+--- @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
+
+--- @param messages string[]
+--- @param ... ...
+local function add_print(messages, ...)
+ local msg = {} --- @type string[]
+ for i = 1, select('#', ...) do
+ msg[#msg + 1] = tostring(select(i, ...))
+ end
+ table.insert(messages, table.concat(msg, '\t'))
+end
+
+local invalid_types = {
+ ['thread'] = true,
+ ['function'] = true,
+ ['userdata'] = true,
+}
+
+--- @param r any[]
+local function check_returns(r)
+ for k, v in pairs(r) 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)
+ ),
+ 2
+ )
+ end
+ end
+end
+
+local M = {}
+
+--- This is run in the context of the remote Nvim instance.
+--- @param bytecode string
+--- @param upvalues table<string,any>
+--- @param ... any[]
+--- @return any[] result
+--- @return table<string,any> upvalues
+--- @return string[] messages
+function M.handler(bytecode, upvalues, ...)
+ local messages = {} --- @type string[]
+ local orig_print = _G.print
+
+ function _G.print(...)
+ add_print(messages, ...)
+ return orig_print(...)
+ end
+
+ local f = assert(loadstring(bytecode))
+
+ set_upvalues(f, upvalues)
+
+ -- Run in pcall so we can return any print messages
+ local ret = { pcall(f, ...) } --- @type any[]
+
+ _G.print = orig_print
+
+ local new_upvalues = get_upvalues(f)
+
+ -- Check return value types for better error messages
+ check_returns(ret)
+
+ return ret, new_upvalues, messages
+end
+
+--- @param session test.Session
+--- @param lvl integer
+--- @param code function
+--- @param ... ...
+local function run(session, lvl, code, ...)
+ local stat, rv = session:request(
+ 'nvim_exec_lua',
+ [[return { require('test.functional.testnvim.exec_lua').handler(...) }]],
+ { string.dump(code), get_upvalues(code), ... }
+ )
+
+ if not stat then
+ error(rv[2], 2)
+ end
+
+ --- @type any[], table<string,any>, string[]
+ local ret, upvalues, messages = unpack(rv)
+
+ for _, m in ipairs(messages) do
+ print(m)
+ end
+
+ if not ret[1] then
+ error(ret[2], 2)
+ end
+
+ -- Update upvalues
+ if next(upvalues) then
+ local caller = debug.getinfo(lvl)
+ local i = 0
+
+ -- On PUC-Lua, if the function is a tail call, then func will be nil.
+ -- In this case we need to use the caller.
+ while not caller.func do
+ i = i + 1
+ caller = debug.getinfo(lvl + i)
+ end
+ set_upvalues(caller.func, upvalues)
+ end
+
+ return unpack(ret, 2, table.maxn(ret))
+end
+
+return setmetatable(M, {
+ __call = function(_, ...)
+ return run(...)
+ end,
+})
diff --git a/test/functional/testterm.lua b/test/functional/testterm.lua
index 3aadcc59a7..17209d947e 100644
--- a/test/functional/testterm.lua
+++ b/test/functional/testterm.lua
@@ -29,6 +29,10 @@ function M.feed_termcode(data)
M.feed_data('\027' .. data)
end
+function M.feed_csi(data)
+ M.feed_termcode('[' .. data)
+end
+
function M.make_lua_executor(session)
return function(code, ...)
local status, rv = session:request('nvim_exec_lua', code, { ... })
@@ -78,6 +82,9 @@ end
function M.set_undercurl()
M.feed_termcode('[4:3m')
end
+function M.set_reverse()
+ M.feed_termcode('[7m')
+end
function M.set_strikethrough()
M.feed_termcode('[9m')
end
@@ -108,7 +115,6 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
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')
@@ -135,7 +141,7 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
})
api.nvim_command('enew')
- api.nvim_call_function('termopen', { cmd, env and { env = env } or nil })
+ api.nvim_call_function('jobstart', { cmd, { term = true, env = (env and env or nil) } })
api.nvim_input('<CR>')
local vim_errmsg = api.nvim_eval('v:errmsg')
if vim_errmsg and '' ~= vim_errmsg then
@@ -154,7 +160,7 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts)
local empty_line = (' '):rep(cols)
local expected = {
'tty ready' .. (' '):rep(cols - 9),
- '{1: }' .. (' '):rep(cols - 1),
+ '^' .. (' '):rep(cols),
empty_line,
empty_line,
empty_line,
diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua
index e38e58ff92..ac58df4bba 100644
--- a/test/functional/treesitter/fold_spec.lua
+++ b/test/functional/treesitter/fold_spec.lua
@@ -5,6 +5,7 @@ local Screen = require('test.functional.ui.screen')
local clear = n.clear
local eq = t.eq
local insert = n.insert
+local write_file = t.write_file
local exec_lua = n.exec_lua
local command = n.command
local feed = n.feed
@@ -767,4 +768,79 @@ t2]])
]],
}
end)
+
+ it("doesn't call get_parser too often when parser is not available", function()
+ -- spy on vim.treesitter.get_parser() to keep track of how many times it is called
+ exec_lua(function()
+ _G.count = 0
+ vim.treesitter.get_parser = (function(wrapped)
+ return function(...)
+ _G.count = _G.count + 1
+ return wrapped(...)
+ end
+ end)(vim.treesitter.get_parser)
+ end)
+
+ insert(test_text)
+ command [[
+ set filetype=some_filetype_without_treesitter_parser
+ set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=0
+ ]]
+
+ -- foldexpr will return '0' for all lines
+ local levels = get_fold_levels() ---@type integer[]
+ eq(19, #levels)
+ for lnum, level in ipairs(levels) do
+ eq('0', level, string.format("foldlevel[%d] == %s; expected '0'", lnum, level))
+ end
+
+ eq(
+ 1,
+ exec_lua [[ return _G.count ]],
+ 'count should not be as high as the # of lines; actually only once for the buffer.'
+ )
+ end)
+
+ it('can detect a new parser and refresh folds accordingly', function()
+ local name = t.tmpname()
+ write_file(name, test_text)
+ command('edit ' .. name)
+ command [[
+ set filetype=some_filetype_without_treesitter_parser
+ set foldmethod=expr foldexpr=v:lua.vim.treesitter.foldexpr() foldcolumn=1 foldlevel=0
+ ]]
+
+ -- foldexpr will return '0' for all lines
+ local levels = get_fold_levels() ---@type integer[]
+ eq(19, #levels)
+ for lnum, level in ipairs(levels) do
+ eq('0', level, string.format("foldlevel[%d] == %s; expected '0'", lnum, level))
+ end
+
+ -- reload buffer as c filetype to simulate new parser being found
+ feed('GA// vim: ft=c<Esc>')
+ command([[write | edit]])
+
+ eq({
+ [1] = '>1',
+ [2] = '1',
+ [3] = '1',
+ [4] = '1',
+ [5] = '>2',
+ [6] = '2',
+ [7] = '2',
+ [8] = '1',
+ [9] = '1',
+ [10] = '>2',
+ [11] = '2',
+ [12] = '2',
+ [13] = '2',
+ [14] = '2',
+ [15] = '>3',
+ [16] = '3',
+ [17] = '3',
+ [18] = '2',
+ [19] = '1',
+ }, get_fold_levels())
+ end)
end)
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 5c6be869c6..7f0a3cb342 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -12,6 +12,7 @@ local fn = n.fn
local eq = t.eq
local hl_query_c = [[
+ ; query
(ERROR) @error
"if" @keyword
@@ -65,40 +66,40 @@ static int nlua_schedule(lua_State *const lstate)
}]]
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) |
+ {18:^/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} nlua_schedule(lua_State *{6:const} lstate) |
{ |
- {4:if} (lua_type(lstate, {5:1}) != LUA_TFUNCTION |
+ {15:if} (lua_type(lstate, {26:1}) != LUA_TFUNCTION |
|| lstate != lstate) { |
- lua_pushliteral(lstate, {5:"vim.schedule: expected function"}); |
- {4:return} lua_error(lstate); |
+ lua_pushliteral(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} lua_error(lstate); |
} |
|
- LuaRef cb = nlua_ref(lstate, {5:1}); |
+ LuaRef cb = nlua_ref(lstate, {26:1}); |
|
multiqueue_put(main_loop.events, nlua_schedule_event, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26: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) |
+ {18:^/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6: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); |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
} |
|
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
|
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
} |
{1:~ }|*2
|
@@ -145,10 +146,10 @@ local injection_grid_c = [[
]]
local injection_grid_expected_c = [[
- {3:int} x = {5:INT_MAX}; |
- #define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) |
- #define foo {3:void} main() { \ |
- {4:return} {5:42}; \ |
+ {6:int} x = {26:INT_MAX}; |
+ #define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) |
+ #define foo {6:void} main() { \ |
+ {15:return} {26:42}; \ |
} |
^ |
{1:~ }|*11
@@ -161,20 +162,6 @@ describe('treesitter highlighting (C)', function()
before_each(function()
clear()
screen = Screen.new(65, 18)
- 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 },
- }
-
command [[ hi link @error ErrorMsg ]]
command [[ hi link @warning WarningMsg ]]
end)
@@ -246,124 +233,124 @@ describe('treesitter highlighting (C)', function()
feed('5Goc<esc>dd')
- screen:expect {
+ 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
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:^lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|*2
+ |
+ ]],
+ })
feed('7Go*/<esc>')
- screen:expect {
+ 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); |
- {8:*^/} |
- } |
- |
- {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:~ }|
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ {9:*^/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|
+ |
+ ]],
+ })
feed('3Go/*<esc>')
- screen:expect {
+ 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) |
- { |
- {2:/^*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {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}; |
- {8:}} |
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {18:/^*} |
+ {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {18: || lstate != lstate) {} |
+ {18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {18: return lua_error(lstate);} |
+ {18:*/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ {9:}} |
+ |
+ ]],
+ })
feed('gg$')
feed('~')
- screen:expect {
+ screen:expect({
grid = [[
- {2:/// Schedule Lua callback on main loop's event queu^E} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {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}; |
- {8:}} |
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queu^E} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {18:/*} |
+ {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {18: || lstate != lstate) {} |
+ {18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {18: return lua_error(lstate);} |
+ {18:*/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ {9:}} |
+ |
+ ]],
+ })
feed('re')
- screen:expect {
+ screen:expect({
grid = [[
- {2:/// Schedule Lua callback on main loop's event queu^e} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {2:/*} |
- {2: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
- {2: || lstate != lstate) {} |
- {2: lua_pushliteral(lstate, "vim.schedule: expected function");} |
- {2: return lua_error(lstate);} |
- {2:*/} |
- } |
- |
- {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}; |
- {8:}} |
- |
- ]],
- }
+ {18:/// Schedule Lua callback on main loop's event queu^e} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {18:/*} |
+ {18: if (lua_type(lstate, 1) != LUA_TFUNCTION} |
+ {18: || lstate != lstate) {} |
+ {18: lua_pushliteral(lstate, "vim.schedule: expected function");} |
+ {18: return lua_error(lstate);} |
+ {18:*/} |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ {9:}} |
+ |
+ ]],
+ })
end)
it('is updated with :sort', function()
@@ -372,83 +359,79 @@ describe('treesitter highlighting (C)', function()
local parser = vim.treesitter.get_parser(0, 'c')
vim.treesitter.highlighter.new(parser, { queries = { c = hl_query_c } })
end)
- screen:expect {
+ screen:expect({
grid = [[
- {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
- {3:bool} ext_widgets[kUIExtCount]; |
- {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- {3:bool} inclusive = ui_override(); |
- {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
- {3:UI} *ui = uis[i]; |
- width = {5:MIN}(ui->width, width); |
- height = {5:MIN}(ui->height, height); |
- foo = {5:BAR}(ui->bazaar, bazaar); |
- {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]],
- }
+ {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
+ {6:bool} ext_widgets[kUIExtCount]; |
+ {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ {6:bool} inclusive = ui_override(); |
+ {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
+ {6:UI} *ui = uis[i]; |
+ width = {26:MIN}(ui->width, width); |
+ height = {26:MIN}(ui->height, height); |
+ foo = {26:BAR}(ui->bazaar, bazaar); |
+ {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]],
+ })
feed ':sort<cr>'
- screen:expect {
+ screen:expect({
grid = [[
- ^ |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- {3:UI} *ui = uis[i]; |
- ext_widgets[i] = true; |
- foo = {5:BAR}(ui->bazaar, bazaar); |
- {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
- height = {5:MIN}(ui->height, height); |
- width = {5:MIN}(ui->width, width); |
- } |
- {3:bool} ext_widgets[kUIExtCount]; |
- {3:bool} inclusive = ui_override(); |
- {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
- {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
- {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
- } |*2
- {3:void} ui_refresh({3:void}) |
- :sort |
- ]],
- }
+ ^ |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ {6:UI} *ui = uis[i]; |
+ ext_widgets[i] = true; |
+ foo = {26:BAR}(ui->bazaar, bazaar); |
+ {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
+ height = {26:MIN}(ui->height, height); |
+ width = {26:MIN}(ui->width, width); |
+ } |
+ {6:bool} ext_widgets[kUIExtCount]; |
+ {6:bool} inclusive = ui_override(); |
+ {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
+ {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
+ {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
+ } |*2
+ {6:void} ui_refresh({6:void}) |
+ :sort |
+ ]],
+ })
- feed 'u'
+ feed 'u:<esc>'
- screen:expect {
+ screen:expect({
grid = [[
- {3:int} width = {5:INT_MAX}, height = {5:INT_MAX}; |
- {3:bool} ext_widgets[kUIExtCount]; |
- {4:for} ({3:UIExtension} i = {5:0}; ({3:int})i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- {3:bool} inclusive = ui_override(); |
- {4:for} ({3:size_t} i = {5:0}; i < ui_count; i++) { |
- {3:UI} *ui = uis[i]; |
- width = {5:MIN}(ui->width, width); |
- height = {5:MIN}(ui->height, height); |
- foo = {5:BAR}(ui->bazaar, bazaar); |
- {4:for} ({3:UIExtension} j = {5:0}; ({3:int})j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- 19 changes; before #2 {MATCH:.*}|
- ]],
- }
+ {6:int} width = {26:INT_MAX}, height = {26:INT_MAX}; |
+ {6:bool} ext_widgets[kUIExtCount]; |
+ {15:for} ({6:UIExtension} i = {26:0}; ({6:int})i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ {6:bool} inclusive = ui_override(); |
+ {15:for} ({6:size_t} i = {26:0}; i < ui_count; i++) { |
+ {6:UI} *ui = uis[i]; |
+ width = {26:MIN}(ui->width, width); |
+ height = {26:MIN}(ui->height, height); |
+ foo = {26:BAR}(ui->bazaar, bazaar); |
+ {15:for} ({6:UIExtension} j = {26:0}; ({6:int})j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]],
+ })
end)
it('supports with custom parser', function()
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.SeaGreen4 },
- }
-
insert(test_text_c)
screen:expect {
@@ -488,28 +471,28 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(parser, { queries = { c = '(identifier) @type' } })
end)
- screen:expect {
+ screen:expect({
grid = [[
- int {1:width} = {1:INT_MAX}, {1:height} = {1:INT_MAX}; |
- bool {1:ext_widgets}[{1:kUIExtCount}]; |
- for (UIExtension {1:i} = 0; (int)i < kUIExtCount; i++) { |
- ext_widgets[i] = true; |
- } |
- |
- bool {1:inclusive} = {1:ui_override}(); |
- for (size_t {1:i} = 0; i < ui_count; i++) { |
- UI *{1:ui} = {1:uis}[{1:i}]; |
- width = MIN(ui->width, width); |
- height = MIN(ui->height, height); |
- foo = BAR(ui->bazaar, bazaar); |
- for (UIExtension {1:j} = 0; (int)j < kUIExtCount; j++) { |
- ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
- } |
- } |
- ^} |
- |
- ]],
- }
+ int {6:width} = {6:INT_MAX}, {6:height} = {6:INT_MAX}; |
+ bool {6:ext_widgets}[{6:kUIExtCount}]; |
+ for (UIExtension {6:i} = 0; (int)i < kUIExtCount; i++) { |
+ ext_widgets[i] = true; |
+ } |
+ |
+ bool {6:inclusive} = {6:ui_override}(); |
+ for (size_t {6:i} = 0; i < ui_count; i++) { |
+ UI *{6:ui} = {6:uis}[{6:i}]; |
+ width = MIN(ui->width, width); |
+ height = MIN(ui->height, height); |
+ foo = BAR(ui->bazaar, bazaar); |
+ for (UIExtension {6:j} = 0; (int)j < kUIExtCount; j++) { |
+ ext_widgets[j] &= (ui->ui_ext[j] || inclusive); |
+ } |
+ } |
+ ^} |
+ |
+ ]],
+ })
end)
it('supports injected languages', function()
@@ -567,18 +550,18 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end)
- screen:expect {
+ screen:expect({
grid = [[
- {3:int} x = {5:INT_MAX}; |
- #define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) |
- #define foo {3:void} main() { \ |
- {4:return} {5:42}; \ |
- } |
- ^ |
- {1:~ }|*11
- |
- ]],
- }
+ {6:int} x = {26:INT_MAX}; |
+ #define {26:READ_STRING}(x, y) ({6:char} *)read_string((x), ({6:size_t})(y)) |
+ #define foo {6:void} main() { \ |
+ {15:return} {26:42}; \ |
+ } |
+ ^ |
+ {1:~ }|*11
+ |
+ ]],
+ })
end)
it('supports highlighting with custom highlight groups', function()
@@ -595,27 +578,27 @@ describe('treesitter highlighting (C)', function()
-- This will change ONLY the literal strings to look like comments
-- The only literal string is the "vim.schedule: expected function" in this test.
exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]]
- screen:expect {
+ screen:expect({
grid = [[
- {2:^/// Schedule Lua callback on main loop's event queue} |
- {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) |
- { |
- {4:if} ({11:lua_type}(lstate, {5:1}) != {5:LUA_TFUNCTION} |
- || {6:lstate} != {6:lstate}) { |
- {11:lua_pushliteral}(lstate, {2:"vim.schedule: expected function"}); |
- {4:return} {11:lua_error}(lstate); |
- } |
- |
- {7:LuaRef} cb = {11:nlua_ref}(lstate, {5:1}); |
- |
- multiqueue_put(main_loop.events, {11:nlua_schedule_event}, |
- {5:1}, ({3:void} *)({3:ptrdiff_t})cb); |
- {4:return} {5:0}; |
- } |
- {1:~ }|*2
- |
- ]],
- }
+ {18:^/// Schedule Lua callback on main loop's event queue} |
+ {6:static} {6:int} {25:nlua_schedule}({6:lua_State} *{6:const} lstate) |
+ { |
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {18:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|*2
+ |
+ ]],
+ })
screen:expect { unchanged = true }
end)
@@ -657,8 +640,8 @@ describe('treesitter highlighting (C)', function()
}
eq({
- { capture = 'constant', metadata = { priority = '101' }, lang = 'c' },
- { capture = 'type', metadata = {}, lang = 'c' },
+ { capture = 'constant', metadata = { priority = '101' }, lang = 'c', id = 14 },
+ { capture = 'type', metadata = {}, lang = 'c', id = 3 },
}, exec_lua [[ return vim.treesitter.get_captures_at_pos(0, 0, 2) ]])
end)
@@ -691,25 +674,25 @@ describe('treesitter highlighting (C)', function()
)
end)
- screen:expect {
+ screen:expect({
grid = [[
- {3:char}* x = {5:"Will somebody ever read this?"}; |
- ^ |
- {1:~ }|*15
- |
- ]],
- }
+ {6:char}* x = {26:"Will somebody ever read this?"}; |
+ ^ |
+ {1:~ }|*15
+ |
+ ]],
+ })
-- clearing specialization reactivates fallback
command [[ hi clear @foo.bar ]]
- screen:expect {
+ screen:expect({
grid = [[
- {5:char}* x = {5:"Will somebody ever read this?"}; |
- ^ |
- {1:~ }|*15
- |
- ]],
- }
+ {26:char}* x = {26:"Will somebody ever read this?"}; |
+ ^ |
+ {1:~ }|*15
+ |
+ ]],
+ })
end
)
@@ -740,27 +723,27 @@ describe('treesitter highlighting (C)', function()
})
end)
- screen:expect {
+ screen:expect({
grid = [[
- /// Schedule Lua callback on main loop's event queue |
- {4:R} int nlua_schedule(lua_State *const ) |
- { |
- if (lua_type(, 1) != LUA_TFUNCTION |
- || != ) { |
- lua_pushliteral(, "vim.schedule: expected function"); |
- return lua_error(); |
- } |
- |
- LuaRef cb = nlua_ref(, 1); |
- |
- {11:V}(main_loop.events, nlua_schedule_event, |
- 1, (void *)(ptrdiff_t)cb); |
- return 0; |
- ^} |
- {1:~ }|*2
- |
- ]],
- }
+ /// Schedule Lua callback on main loop's event queue |
+ {15:R} int nlua_schedule(lua_State *const ) |
+ { |
+ if (lua_type(, 1) != LUA_TFUNCTION |
+ || != ) { |
+ lua_pushliteral(, "vim.schedule: expected function"); |
+ return lua_error(); |
+ } |
+ |
+ LuaRef cb = nlua_ref(, 1); |
+ |
+ {25:V}(main_loop.events, nlua_schedule_event, |
+ 1, (void *)(ptrdiff_t)cb); |
+ return 0; |
+ ^} |
+ {1:~ }|*2
+ |
+ ]],
+ })
end)
it('@foo.bar groups has the correct fallback behavior', function()
@@ -801,16 +784,16 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end)
- screen:expect {
+ screen:expect({
grid = [[
- {5:int x = 4;} |
- {5:int y = 5;} |
- {5:int z = 6;} |
- ^ |
- {1:~ }|*13
- |
- ]],
- }
+ {26:int x = 4;} |
+ {26:int y = 5;} |
+ {26:int z = 6;} |
+ ^ |
+ {1:~ }|*13
+ |
+ ]],
+ })
end)
it('gives higher priority to more specific captures #27895', function()
@@ -830,14 +813,52 @@ describe('treesitter highlighting (C)', function()
vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
end)
- screen:expect {
+ screen:expect({
grid = [[
- void foo(int {4:*}{11:bar}); |
- ^ |
- {1:~ }|*15
- |
- ]],
- }
+ void foo(int {15:*}{25:bar}); |
+ ^ |
+ {1:~ }|*15
+ |
+ ]],
+ })
+ end)
+
+ it('highlights applied to first line of closed fold', function()
+ insert(hl_text_c)
+ exec_lua(function()
+ vim.treesitter.query.set('c', 'highlights', hl_query_c)
+ vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, 'c'))
+ end)
+ feed('ggjzfj')
+ command('set foldtext=')
+ screen:add_extra_attr_ids({
+ [100] = {
+ bold = true,
+ background = Screen.colors.LightGray,
+ foreground = Screen.colors.SeaGreen4,
+ },
+ [101] = { background = Screen.colors.LightGray, foreground = Screen.colors.DarkCyan },
+ })
+ screen:expect({
+ grid = [[
+ {18:/// Schedule Lua callback on main loop's event queue} |
+ {100:^static}{13: }{100:int}{13: }{101:nlua_schedule}{13:(}{100:lua_State}{13: *}{100:const}{13: lstate)················}|
+ {15:if} ({25:lua_type}(lstate, {26:1}) != {26:LUA_TFUNCTION} |
+ || {19:lstate} != {19:lstate}) { |
+ {25:lua_pushliteral}(lstate, {26:"vim.schedule: expected function"}); |
+ {15:return} {25:lua_error}(lstate); |
+ } |
+ |
+ {29:LuaRef} cb = {25:nlua_ref}(lstate, {26:1}); |
+ |
+ multiqueue_put(main_loop.events, {25:nlua_schedule_event}, |
+ {26:1}, ({6:void} *)({6:ptrdiff_t})cb); |
+ {15:return} {26:0}; |
+ } |
+ {1:~ }|*3
+ |
+ ]],
+ })
end)
end)
@@ -847,13 +868,6 @@ describe('treesitter highlighting (lua)', function()
before_each(function()
clear()
screen = Screen.new(65, 18)
- screen:set_default_attr_ids {
- [1] = { bold = true, foreground = Screen.colors.Blue },
- [2] = { foreground = Screen.colors.DarkCyan },
- [3] = { foreground = Screen.colors.Magenta },
- [4] = { foreground = Screen.colors.SlateBlue },
- [5] = { bold = true, foreground = Screen.colors.Brown },
- }
end)
it('supports language injections', function()
@@ -867,15 +881,15 @@ describe('treesitter highlighting (lua)', function()
vim.treesitter.start()
end)
- screen:expect {
+ screen:expect({
grid = [[
- {5:local} {2:ffi} {5:=} {4:require(}{3:'ffi'}{4:)} |
- {2:ffi}{4:.}{2:cdef}{4:(}{3:"}{4:int}{3: }{4:(}{5:*}{3:fun}{4:)(int,}{3: }{4:char}{3: }{5:*}{4:);}{3:"}{4:)} |
- ^ |
- {1:~ }|*14
- |
- ]],
- }
+ {15:local} {25:ffi} {15:=} {16:require(}{26:'ffi'}{16:)} |
+ {25:ffi}{16:.}{25:cdef}{16:(}{26:"}{16:int}{26: }{16:(}{15:*}{26:fun}{16:)(int,}{26: }{16:char}{26: }{15:*}{16:);}{26:"}{16:)} |
+ ^ |
+ {1:~ }|*14
+ |
+ ]],
+ })
end)
end)
@@ -885,16 +899,6 @@ describe('treesitter highlighting (help)', function()
before_each(function()
clear()
screen = Screen.new(40, 6)
- 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 },
- 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()
@@ -918,13 +922,18 @@ describe('treesitter highlighting (help)', function()
vim.treesitter.start()
end)
+ screen:add_extra_attr_ids({
+ [100] = { nocombine = true, underdouble = true },
+ [101] = { foreground = Screen.colors.Fuchsia, bold = true },
+ [102] = { underline = true, nocombine = true },
+ })
screen:expect({
grid = [[
- {h1_delim:^========================================}|
- {title:NVIM DOCUMENTATION} |
+ {100:^========================================}|
+ {101:NVIM DOCUMENTATION} |
|
- {h2_delim:----------------------------------------}|
- {title:ABOUT NVIM} |
+ {102:----------------------------------------}|
+ {101:ABOUT NVIM} |
|
]],
})
@@ -943,42 +952,42 @@ describe('treesitter highlighting (help)', function()
vim.treesitter.start()
end)
- screen:expect {
+ screen:expect({
grid = [[
- {1:>}{3:ruby} |
- {1: -- comment} |
- {1: local this_is = 'actually_lua'} |
- {1:<} |
- ^ |
- |
- ]],
- }
+ {18:>}{15:ruby} |
+ {18: -- comment} |
+ {18: local this_is = 'actually_lua'} |
+ {18:<} |
+ ^ |
+ |
+ ]],
+ })
n.api.nvim_buf_set_text(0, 0, 1, 0, 5, { 'lua' })
- screen:expect {
+ screen:expect({
grid = [[
- {1:>}{3:lua} |
- {1: -- comment} |
- {1: }{3:local}{1: }{4:this_is}{1: }{3:=}{1: }{5:'actually_lua'} |
- {1:<} |
- ^ |
- |
- ]],
- }
+ {18:>}{15:lua} |
+ {18: -- comment} |
+ {18: }{15:local}{18: }{25:this_is}{18: }{15:=}{18: }{26:'actually_lua'} |
+ {18:<} |
+ ^ |
+ |
+ ]],
+ })
n.api.nvim_buf_set_text(0, 0, 1, 0, 4, { 'ruby' })
- screen:expect {
+ screen:expect({
grid = [[
- {1:>}{3:ruby} |
- {1: -- comment} |
- {1: local this_is = 'actually_lua'} |
- {1:<} |
- ^ |
- |
- ]],
- }
+ {18:>}{15:ruby} |
+ {18: -- comment} |
+ {18: local this_is = 'actually_lua'} |
+ {18:<} |
+ ^ |
+ |
+ ]],
+ })
end)
it('correctly redraws injections subpriorities', function()
@@ -1003,16 +1012,16 @@ describe('treesitter highlighting (help)', function()
vim.treesitter.highlighter.new(parser)
end)
- screen:expect {
+ screen:expect({
grid = [=[
- {3:local} {4:s} {3:=} {5:[[} |
- {5: }{3:local}{5: }{4:also}{5: }{3:=}{5: }{4:lua} |
- {5:]]} |
- ^ |
- {2:~ }|
- |
- ]=],
- }
+ {15:local} {25:s} {15:=} {26:[[} |
+ {26: }{15:local}{26: }{25:also}{26: }{15:=}{26: }{25:lua} |
+ {26:]]} |
+ ^ |
+ {1:~ }|
+ |
+ ]=],
+ })
end)
end)
@@ -1022,12 +1031,6 @@ describe('treesitter highlighting (nested injections)', function()
before_each(function()
clear()
screen = Screen.new(80, 7)
- screen:set_default_attr_ids {
- [1] = { foreground = Screen.colors.SlateBlue },
- [2] = { bold = true, foreground = Screen.colors.Brown },
- [3] = { foreground = Screen.colors.Cyan4 },
- [4] = { foreground = Screen.colors.Fuchsia },
- }
end)
it('correctly redraws nested injections (GitHub #25252)', function()
@@ -1054,32 +1057,32 @@ vim.cmd([[
-- invalidate the language tree
feed('ggi--[[<ESC>04x')
- screen:expect {
+ screen:expect({
grid = [[
- {2:^function} {3:foo}{1:()} {1:print(}{4:"Lua!"}{1:)} {2:end} |
- |
- {2:local} {3:lorem} {2:=} {1:{} |
- {3:ipsum} {2:=} {1:{},} |
- {3:bar} {2:=} {1:{},} |
- {1:}} |
- |
- ]],
- }
+ {15:^function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} |
+ |
+ {15:local} {25:lorem} {15:=} {16:{} |
+ {25:ipsum} {15:=} {16:{},} |
+ {25:bar} {15:=} {16:{},} |
+ {16:}} |
+ |
+ ]],
+ })
-- spam newline insert/delete to invalidate Lua > Vim > Lua region
feed('3jo<ESC>ddko<ESC>ddko<ESC>ddko<ESC>ddk0')
- screen:expect {
+ screen:expect({
grid = [[
- {2:function} {3:foo}{1:()} {1:print(}{4:"Lua!"}{1:)} {2:end} |
- |
- {2:local} {3:lorem} {2:=} {1:{} |
- ^ {3:ipsum} {2:=} {1:{},} |
- {3:bar} {2:=} {1:{},} |
- {1:}} |
- |
- ]],
- }
+ {15:function} {25:foo}{16:()} {16:print(}{26:"Lua!"}{16:)} {15:end} |
+ |
+ {15:local} {25:lorem} {15:=} {16:{} |
+ ^ {25:ipsum} {15:=} {16:{},} |
+ {25:bar} {15:=} {16:{},} |
+ {16:}} |
+ |
+ ]],
+ })
end)
end)
@@ -1108,7 +1111,7 @@ describe('treesitter highlighting (markdown)', function()
})
screen:expect({
grid = [[
- {25:[}{100:This link text}{25:](}{101:https://example.com}{25:)} is|
+ {100:[This link text](}{101:https://example.com}{100:)} is|
a hyperlink^. |
{1:~ }|*3
|
@@ -1156,20 +1159,6 @@ it('starting and stopping treesitter highlight in init.lua works #29541', functi
eq('', api.nvim_get_vvar('errmsg'))
local screen = Screen.new(65, 18)
- 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
diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua
index 1f7d15cc96..68622140e4 100644
--- a/test/functional/treesitter/inspect_tree_spec.lua
+++ b/test/functional/treesitter/inspect_tree_spec.lua
@@ -120,14 +120,17 @@ describe('vim.treesitter.inspect_tree', function()
end)
it('updates source and tree buffer windows and closes them correctly', function()
+ local name = t.tmpname()
+ n.command('edit ' .. name)
insert([[
print()
]])
+ n.command('set filetype=lua | write')
-- 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, {
+ _G.source_win2 = vim.api.nvim_open_win(0, false, {
win = 0,
split = 'left',
})
@@ -135,40 +138,103 @@ describe('vim.treesitter.inspect_tree', function()
-- 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, {
+ _G.tree_win2 = vim.api.nvim_open_win(0, false, {
win = 0,
split = 'left',
})
- _G.tree_win_copy_2 = vim.api.nvim_open_win(0, false, {
+ _G.tree_win3 = 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)')
+ -- close original source window without closing tree views
+ exec_lua('vim.api.nvim_set_current_win(source_win)')
+ feed(':quit<CR>')
+ eq('', n.api.nvim_get_vvar('errmsg'))
+ eq(true, exec_lua('return vim.api.nvim_win_is_valid(tree_win)'))
+ eq(true, exec_lua('return vim.api.nvim_win_is_valid(tree_win2)'))
+ eq(true, exec_lua('return vim.api.nvim_win_is_valid(tree_win3)'))
-- navigates correctly to the remaining source buffer window
+ exec_lua('vim.api.nvim_set_current_win(tree_win)')
feed('<CR>')
eq('', n.api.nvim_get_vvar('errmsg'))
+ eq(true, exec_lua('return vim.api.nvim_get_current_win() == source_win2'))
-- close original tree window
exec_lua(function()
- vim.api.nvim_set_current_win(_G.tree_win_copy_1)
+ vim.api.nvim_set_current_win(_G.tree_win2)
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'))
+ eq(true, exec_lua('return vim.api.nvim_get_current_win() == source_win2'))
-- close source buffer window and all remaining tree windows
- t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)')
+ n.expect_exit(n.command, 'quit')
+ end)
- 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)'))
+ it('shows which nodes are missing', function()
+ insert([[
+ int main() {
+ if (a.) {
+ // ^ MISSING field_identifier here
+ if (1) d()
+ // ^ MISSING ";" here
+ }
+ }
+ ]])
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'c')
+ vim.treesitter.inspect_tree()
+ end)
+ feed('a')
+
+ expect_tree [[
+ (translation_unit ; [0, 0] - [8, 0]
+ (function_definition ; [0, 0] - [6, 1]
+ type: (primitive_type) ; [0, 0] - [0, 3]
+ declarator: (function_declarator ; [0, 4] - [0, 10]
+ declarator: (identifier) ; [0, 4] - [0, 8]
+ parameters: (parameter_list ; [0, 8] - [0, 10]
+ "(" ; [0, 8] - [0, 9]
+ ")")) ; [0, 9] - [0, 10]
+ body: (compound_statement ; [0, 11] - [6, 1]
+ "{" ; [0, 11] - [0, 12]
+ (if_statement ; [1, 4] - [5, 5]
+ "if" ; [1, 4] - [1, 6]
+ condition: (parenthesized_expression ; [1, 7] - [1, 11]
+ "(" ; [1, 7] - [1, 8]
+ (field_expression ; [1, 8] - [1, 10]
+ argument: (identifier) ; [1, 8] - [1, 9]
+ operator: "." ; [1, 9] - [1, 10]
+ field: (MISSING field_identifier)) ; [1, 10] - [1, 10]
+ ")") ; [1, 10] - [1, 11]
+ consequence: (compound_statement ; [1, 12] - [5, 5]
+ "{" ; [1, 12] - [1, 13]
+ (comment) ; [2, 4] - [2, 41]
+ (if_statement ; [3, 8] - [4, 36]
+ "if" ; [3, 8] - [3, 10]
+ condition: (parenthesized_expression ; [3, 11] - [3, 14]
+ "(" ; [3, 11] - [3, 12]
+ (number_literal) ; [3, 12] - [3, 13]
+ ")") ; [3, 13] - [3, 14]
+ consequence: (expression_statement ; [3, 15] - [4, 36]
+ (call_expression ; [3, 15] - [3, 18]
+ function: (identifier) ; [3, 15] - [3, 16]
+ arguments: (argument_list ; [3, 16] - [3, 18]
+ "(" ; [3, 16] - [3, 17]
+ ")")) ; [3, 17] - [3, 18]
+ (comment) ; [4, 8] - [4, 36]
+ (MISSING ";"))) ; [4, 36] - [4, 36]
+ "}")) ; [5, 4] - [5, 5]
+ "}"))) ; [6, 0] - [6, 1]
+ ]]
end)
end)
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index 120a15d7f9..a93b1063a1 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -117,6 +117,7 @@ describe('treesitter language API', function()
'<node translation_unit>',
exec_lua(function()
local langtree = vim.treesitter.get_parser(0, 'c')
+ langtree:parse()
local tree = langtree:tree_for_range({ 1, 3, 1, 3 })
return tostring(tree:root())
end)
@@ -133,6 +134,7 @@ describe('treesitter language API', function()
'<node translation_unit>',
exec_lua(function()
local langtree = vim.treesitter.get_parser(0, 'c')
+ langtree:parse()
local tree = langtree:tree_for_range({ 10, 10, 10, 10 })
return tostring(tree:root())
end)
@@ -149,6 +151,7 @@ describe('treesitter language API', function()
'<node primitive_type>',
exec_lua(function()
local langtree = vim.treesitter.get_parser(0, 'c')
+ langtree:parse()
local node = langtree:named_node_for_range({ 1, 3, 1, 3 })
return tostring(node)
end)
@@ -160,6 +163,7 @@ describe('treesitter language API', function()
exec_lua(function()
_G.langtree = vim.treesitter.get_parser(0, 'lua')
+ _G.langtree:parse()
_G.node = _G.langtree:node_for_range({ 0, 3, 0, 3 })
end)
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index c87a56b160..235bf7861c 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -20,6 +20,7 @@ describe('treesitter node API', function()
insert('F')
exec_lua(function()
vim.treesitter.start(0, 'lua')
+ vim.treesitter.get_parser(0):parse()
vim.treesitter.get_node():tree()
vim.treesitter.get_node():tree()
collectgarbage()
@@ -45,6 +46,7 @@ describe('treesitter node API', function()
-- this buffer doesn't have filetype set!
insert('local foo = function() end')
exec_lua(function()
+ vim.treesitter.get_parser(0, 'lua'):parse()
_G.node = vim.treesitter.get_node({
bufnr = 0,
pos = { 0, 6 }, -- on "foo"
@@ -161,32 +163,6 @@ describe('treesitter node API', function()
eq(3, lua_eval('child:byte_length()'))
end)
- it('child_containing_descendant() works', function()
- insert([[
- int main() {
- int x = 3;
- }]])
-
- 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()'))
- eq(lua_eval('statement:type()'), lua_eval('body:child_containing_descendant(value):type()'))
- eq(
- lua_eval('declarator:type()'),
- lua_eval('statement:child_containing_descendant(value):type()')
- )
- eq(vim.NIL, lua_eval('declarator:child_containing_descendant(value)'))
- end)
-
it('child_with_descendant() works', function()
insert([[
int main() {
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 2f8d204d36..eb4651a81d 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -1,5 +1,6 @@
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
+local ts_t = require('test.functional.treesitter.testutil')
local clear = n.clear
local dedent = t.dedent
@@ -8,6 +9,8 @@ local insert = n.insert
local exec_lua = n.exec_lua
local pcall_err = t.pcall_err
local feed = n.feed
+local run_query = ts_t.run_query
+local assert_alive = n.assert_alive
describe('treesitter parser API', function()
before_each(function()
@@ -88,6 +91,197 @@ describe('treesitter parser API', function()
eq(true, exec_lua('return parser:parse()[1] == tree2'))
end)
+ it('parses buffer asynchronously', function()
+ insert([[
+ int main() {
+ int x = 3;
+ }]])
+
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c')
+ _G.lang = vim.treesitter.language.inspect('c')
+ _G.parser:parse(nil, function(_, trees)
+ _G.tree = trees[1]
+ _G.root = _G.tree:root()
+ end)
+ vim.wait(100, function() end)
+ end)
+
+ eq('<tree>', exec_lua('return tostring(tree)'))
+ eq('<node translation_unit>', exec_lua('return tostring(root)'))
+ eq({ 0, 0, 3, 0 }, exec_lua('return {root:range()}'))
+
+ eq(1, exec_lua('return root:child_count()'))
+ exec_lua('child = root:child(0)')
+ eq('<node function_definition>', exec_lua('return tostring(child)'))
+ eq({ 0, 0, 2, 1 }, exec_lua('return {child:range()}'))
+
+ eq('function_definition', exec_lua('return child:type()'))
+ eq(true, exec_lua('return child:named()'))
+ eq('number', type(exec_lua('return child:symbol()')))
+ eq(true, exec_lua('return lang.symbols[child:type()]'))
+
+ exec_lua('anon = root:descendant_for_range(0,8,0,9)')
+ eq('(', exec_lua('return anon:type()'))
+ eq(false, exec_lua('return anon:named()'))
+ eq('number', type(exec_lua('return anon:symbol()')))
+ eq(false, exec_lua([=[return lang.symbols[string.format('"%s"', anon:type())]]=]))
+
+ exec_lua('descendant = root:descendant_for_range(1,2,1,12)')
+ eq('<node declaration>', exec_lua('return tostring(descendant)'))
+ eq({ 1, 2, 1, 12 }, exec_lua('return {descendant:range()}'))
+ eq(
+ '(declaration type: (primitive_type) declarator: (init_declarator declarator: (identifier) value: (number_literal)))',
+ exec_lua('return descendant:sexpr()')
+ )
+
+ feed('2G7|ay')
+ exec_lua(function()
+ _G.parser:parse(nil, function(_, trees)
+ _G.tree2 = trees[1]
+ _G.root2 = _G.tree2:root()
+ _G.descendant2 = _G.root2:descendant_for_range(1, 2, 1, 13)
+ end)
+ vim.wait(100, function() end)
+ end)
+ eq(false, exec_lua('return tree2 == tree1'))
+ eq(false, exec_lua('return root2 == root'))
+ eq('<node declaration>', exec_lua('return tostring(descendant2)'))
+ eq({ 1, 2, 1, 13 }, exec_lua('return {descendant2:range()}'))
+
+ eq(true, exec_lua('return child == child'))
+ -- separate lua object, but represents same node
+ eq(true, exec_lua('return child == root:child(0)'))
+ eq(false, exec_lua('return child == descendant2'))
+ eq(false, exec_lua('return child == nil'))
+ eq(false, exec_lua('return child == tree'))
+
+ eq('string', exec_lua('return type(child:id())'))
+ eq(true, exec_lua('return child:id() == child:id()'))
+ -- separate lua object, but represents same node
+ eq(true, exec_lua('return child:id() == root:child(0):id()'))
+ eq(false, exec_lua('return child:id() == descendant2:id()'))
+ eq(false, exec_lua('return child:id() == nil'))
+ eq(false, exec_lua('return child:id() == tree'))
+
+ -- unchanged buffer: return the same tree
+ eq(true, exec_lua('return parser:parse()[1] == tree2'))
+ end)
+
+ it('does not crash when editing large files', function()
+ insert([[printf("%s", "some text");]])
+ feed('yy49999p')
+
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c')
+ _G.done = false
+ vim.treesitter.start(0, 'c')
+ _G.parser:parse(nil, function()
+ _G.done = true
+ end)
+ while not _G.done do
+ -- Busy wait until async parsing has completed
+ vim.wait(100, function() end)
+ end
+ end)
+
+ eq(true, exec_lua([[return done]]))
+ exec_lua(function()
+ vim.api.nvim_input('Lxj')
+ end)
+ exec_lua(function()
+ vim.api.nvim_input('xj')
+ end)
+ exec_lua(function()
+ vim.api.nvim_input('xj')
+ end)
+ assert_alive()
+ end)
+
+ it('resets parsing state on tree changes', function()
+ insert([[vim.api.nvim_set_hl(0, 'test2', { bg = 'green' })]])
+ feed('yy1000p')
+
+ exec_lua(function()
+ vim.cmd('set ft=lua')
+
+ vim.treesitter.start(0)
+ local parser = assert(vim.treesitter.get_parser(0))
+
+ parser:parse(true, function() end)
+ vim.api.nvim_buf_set_lines(0, 1, -1, false, {})
+ parser:parse(true)
+ end)
+ end)
+
+ it('resets when buffer was editing during an async parse', function()
+ insert([[printf("%s", "some text");]])
+ feed('yy49999p')
+ feed('gg4jO// Comment<Esc>')
+
+ exec_lua(function()
+ _G.parser = vim.treesitter.get_parser(0, 'c')
+ _G.done = false
+ vim.treesitter.start(0, 'c')
+ _G.parser:parse(nil, function()
+ _G.done = true
+ end)
+ end)
+
+ exec_lua(function()
+ vim.api.nvim_input('ggdj')
+ end)
+
+ eq(false, exec_lua([[return done]]))
+ exec_lua(function()
+ while not _G.done do
+ -- Busy wait until async parsing finishes
+ vim.wait(100, function() end)
+ end
+ end)
+ eq(true, exec_lua([[return done]]))
+ eq('comment', exec_lua([[return parser:parse()[1]:root():named_child(2):type()]]))
+ eq({ 2, 0, 2, 10 }, exec_lua([[return {parser:parse()[1]:root():named_child(2):range()}]]))
+ end)
+
+ it('handles multiple async parse calls', function()
+ insert([[printf("%s", "some text");]])
+ feed('yy49999p')
+
+ exec_lua(function()
+ -- Spy on vim.schedule
+ local schedule = vim.schedule
+ vim.schedule = function(fn)
+ _G.schedules = _G.schedules + 1
+ schedule(fn)
+ end
+ _G.schedules = 0
+ _G.parser = vim.treesitter.get_parser(0, 'c')
+ for i = 1, 5 do
+ _G['done' .. i] = false
+ _G.parser:parse(nil, function()
+ _G['done' .. i] = true
+ end)
+ end
+ schedule(function()
+ _G.schedules_snapshot = _G.schedules
+ end)
+ end)
+
+ eq(2, exec_lua([[return schedules_snapshot]]))
+ eq(
+ { false, false, false, false, false },
+ exec_lua([[return { done1, done2, done3, done4, done5 }]])
+ )
+ exec_lua(function()
+ while not _G.done1 do
+ -- Busy wait until async parsing finishes
+ vim.wait(100, function() end)
+ end
+ end)
+ eq({ true, true, true, true, true }, exec_lua([[return { done1, done2, done3, done4, done5 }]]))
+ end)
+
local test_text = [[
void ui_refresh(void)
{
@@ -310,6 +504,15 @@ end]]
eq({ 0, 0, 0, 13 }, ret)
end)
+ it('can run async parses with string parsers', function()
+ local ret = exec_lua(function()
+ local parser = vim.treesitter.get_string_parser('int foo = 42;', 'c')
+ return { parser:parse(nil, function() end)[1]:root():range() }
+ end)
+
+ eq({ 0, 0, 0, 13 }, ret)
+ end)
+
it('allows to run queries with string parsers', function()
local txt = [[
int foo = 42;
@@ -430,7 +633,7 @@ int x = INT_MAX;
}, get_ranges())
n.feed('7ggI//<esc>')
- exec_lua([[parser:parse({6, 7})]])
+ exec_lua([[parser:parse({5, 6})]])
eq('table', exec_lua('return type(parser:children().c)'))
eq(2, exec_lua('return #parser:children().c:trees()'))
eq({
@@ -644,6 +847,109 @@ print()
end)
end)
+ describe('trim! directive', function()
+ it('can trim all whitespace', function()
+ -- luacheck: push ignore 611 613
+ insert([=[
+ print([[
+
+ f
+ helllo
+ there
+ asdf
+ asdfassd
+
+
+
+ ]])
+ print([[
+
+
+
+ ]])
+
+ print([[]])
+
+ print([[
+ ]])
+
+ print([[ hello 😃 ]])
+ ]=])
+ -- luacheck: pop
+
+ local query_text = [[
+ ; query
+ ((string_content) @str
+ (#trim! @str 1 1 1 1))
+ ]]
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'lua')
+ end)
+
+ eq({
+ { 'str', { 2, 12, 6, 10 } },
+ { 'str', { 11, 10, 11, 10 } },
+ { 'str', { 17, 10, 17, 10 } },
+ { 'str', { 19, 10, 19, 10 } },
+ { 'str', { 22, 15, 22, 25 } },
+ }, run_query('lua', query_text))
+ end)
+
+ it('trims only empty lines by default (backwards compatible)', function()
+ insert(dedent [[
+ ## Heading
+
+ With some text
+
+ ## And another
+
+ With some more here]])
+
+ local query_text = [[
+ ; query
+ ((section) @fold
+ (#trim! @fold))
+ ]]
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'markdown')
+ end)
+
+ eq({
+ { 'fold', { 0, 0, 2, 14 } },
+ { 'fold', { 4, 0, 6, 19 } },
+ }, run_query('markdown', query_text))
+ end)
+
+ it('can trim lines', function()
+ insert(dedent [[
+ - Fold list
+ - Fold list
+ - Fold list
+ - Fold list
+ - Fold list
+ - Fold list
+ ]])
+
+ local query_text = [[
+ ; query
+ ((list_item
+ (list)) @fold
+ (#trim! @fold 1 1 1 1))
+ ]]
+
+ exec_lua(function()
+ vim.treesitter.start(0, 'markdown')
+ end)
+
+ eq({
+ { 'fold', { 0, 0, 4, 13 } },
+ { 'fold', { 1, 2, 3, 15 } },
+ }, run_query('markdown', query_text))
+ end)
+ end)
+
it('tracks the root range properly (#22911)', function()
insert([[
int main() {
@@ -659,32 +965,19 @@ print()
vim.treesitter.start(0, 'c')
end)
- local function run_query()
- 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({
- { 'function', 0, 0, 2, 1 },
- { 'declaration', 1, 2, 1, 12 },
- }, run_query())
+ { 'function', { 0, 0, 2, 1 } },
+ { 'declaration', { 1, 2, 1, 12 } },
+ }, run_query('c', query0))
n.command 'normal ggO'
insert('int a;')
eq({
- { 'declaration', 0, 0, 0, 6 },
- { 'function', 1, 0, 3, 1 },
- { 'declaration', 2, 2, 2, 12 },
- }, run_query())
+ { 'declaration', { 0, 0, 0, 6 } },
+ { 'function', { 1, 0, 3, 1 } },
+ { 'declaration', { 2, 2, 2, 12 } },
+ }, run_query('c', query0))
end)
it('handles ranges when source is a multiline string (#20419)', function()
@@ -858,11 +1151,13 @@ print()
feed(':set ft=help<cr>')
exec_lua(function()
- vim.treesitter.get_parser(0, 'vimdoc', {
- injections = {
- vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))',
- },
- })
+ vim.treesitter
+ .get_parser(0, 'vimdoc', {
+ injections = {
+ vimdoc = '((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))',
+ },
+ })
+ :parse()
end)
end)
diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua
index 634f8af83d..6db0ffe5a0 100644
--- a/test/functional/treesitter/query_spec.lua
+++ b/test/functional/treesitter/query_spec.lua
@@ -86,7 +86,7 @@ void ui_refresh(void)
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)
+ vim.treesitter.query.parse('c', long_query)
end
collectgarbage('restart')
collectgarbage('collect')
@@ -96,8 +96,39 @@ void ui_refresh(void)
end
eq(1, q(1))
- -- cache is cleared by garbage collection even if valid "cquery" reference is kept around
- eq(1, q(100))
+ -- cache is retained even after garbage collection
+ eq(0, q(100))
+ end)
+
+ it('cache is cleared upon runtimepath changes, or setting query manually', function()
+ ---@return number
+ exec_lua(function()
+ _G.query_parse_count = _G.query_parse_count or 0
+ local parse = vim.treesitter.query.parse
+ vim.treesitter.query.parse = function(...)
+ _G.query_parse_count = _G.query_parse_count + 1
+ return parse(...)
+ end
+ end)
+
+ local function q(_n)
+ return exec_lua(function()
+ for _ = 1, _n, 1 do
+ vim.treesitter.query.get('c', 'highlights')
+ end
+ return _G.query_parse_count
+ end)
+ end
+
+ eq(1, q(10))
+ exec_lua(function()
+ vim.opt.rtp:prepend('/another/dir')
+ end)
+ eq(2, q(100))
+ exec_lua(function()
+ vim.treesitter.query.set('c', 'highlights', [[; test]])
+ end)
+ eq(3, q(100))
end)
it('supports query and iter by capture (iter_captures)', function()
@@ -781,6 +812,34 @@ void ui_refresh(void)
)
end)
+ it('supports "; extends" modeline in custom queries', function()
+ insert('int zeero = 0;')
+ local result = exec_lua(function()
+ vim.treesitter.query.set(
+ 'c',
+ 'highlights',
+ [[; extends
+ (identifier) @spell]]
+ )
+ local query = vim.treesitter.query.get('c', 'highlights')
+ local parser = vim.treesitter.get_parser(0, 'c')
+ local root = parser:parse()[1]:root()
+ local res = {}
+ for id, node in query:iter_captures(root, 0) do
+ table.insert(res, { query.captures[id], vim.treesitter.get_node_text(node, 0) })
+ end
+ return res
+ end)
+ eq({
+ { 'type.builtin', 'int' },
+ { 'variable', 'zeero' },
+ { 'spell', 'zeero' },
+ { 'operator', '=' },
+ { 'number', '0' },
+ { 'punctuation.delimiter', ';' },
+ }, result)
+ end)
+
describe('Query:iter_captures', function()
it('includes metadata for all captured nodes #23664', function()
insert([[
@@ -835,9 +894,9 @@ void ui_refresh(void)
local result = exec_lua(function()
local query0 = vim.treesitter.query.parse('c', query)
- local match_preds = query0.match_preds
+ local match_preds = query0._match_predicates
local called = 0
- function query0:match_preds(...)
+ function query0:_match_predicates(...)
called = called + 1
return match_preds(self, ...)
end
diff --git a/test/functional/treesitter/testutil.lua b/test/functional/treesitter/testutil.lua
new file mode 100644
index 0000000000..f8934f06c3
--- /dev/null
+++ b/test/functional/treesitter/testutil.lua
@@ -0,0 +1,25 @@
+local n = require('test.functional.testnvim')()
+
+local exec_lua = n.exec_lua
+
+local M = {}
+
+---@param language string
+---@param query_string string
+function M.run_query(language, query_string)
+ return exec_lua(function(lang, query_str)
+ local query = vim.treesitter.query.parse(lang, query_str)
+ local parser = vim.treesitter.get_parser()
+ local tree = parser:parse()[1]
+ local res = {}
+ for id, node, metadata in query:iter_captures(tree:root(), 0) do
+ table.insert(
+ res,
+ { query.captures[id], metadata[id] and metadata[id].range or { node:range() } }
+ )
+ end
+ return res
+ end, language, query_string)
+end
+
+return M
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 0221c1e0b0..ce7c9596bb 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -91,25 +91,27 @@ local function test_cmdline(linegrid)
{1:~ }|*3
|
]],
+ cmdline = { { abort = true } },
}
end)
it('works with input()', function()
feed(':call input("input", "default")<cr>')
- screen:expect {
+ screen:expect({
grid = [[
- ^ |
- {1:~ }|*3
- |
- ]],
+ ^ |
+ {1:~ }|*3
+ |
+ ]],
cmdline = {
{
- prompt = 'input',
content = { { 'default' } },
+ hl_id = 0,
pos = 7,
+ prompt = 'input',
},
},
- }
+ })
feed('<cr>')
screen:expect {
@@ -118,6 +120,7 @@ local function test_cmdline(linegrid)
{1:~ }|*3
|
]],
+ cmdline = { { abort = false } },
}
end)
@@ -210,6 +213,7 @@ local function test_cmdline(linegrid)
content = { { 'xx3' } },
pos = 3,
},
+ { abort = false },
},
}
@@ -220,6 +224,7 @@ local function test_cmdline(linegrid)
{1:~ }|*3
|
]],
+ cmdline = { { abort = true } },
}
end)
@@ -294,6 +299,7 @@ local function test_cmdline(linegrid)
{1:~ }|*3
|
]],
+ cmdline = { { abort = false } },
}
-- Try once more, to check buffer is reinitialized. #8007
@@ -324,6 +330,7 @@ local function test_cmdline(linegrid)
{1:~ }|*3
|
]],
+ cmdline = { { abort = false } },
}
end)
@@ -353,6 +360,7 @@ local function test_cmdline(linegrid)
{3:[Command Line] }|
|
]],
+ cmdline = { { abort = false } },
}
-- nested cmdline
@@ -404,6 +412,7 @@ local function test_cmdline(linegrid)
{3:[Command Line] }|
|
]],
+ cmdline = { [2] = { abort = true } },
}
feed('<c-c>')
@@ -452,6 +461,7 @@ local function test_cmdline(linegrid)
cmdline = {
{
prompt = 'secret:',
+ hl_id = 0,
content = { { '******' } },
pos = 6,
},
@@ -495,6 +505,7 @@ local function test_cmdline(linegrid)
cmdline = {
{
prompt = '>',
+ hl_id = 0,
content = {
{ '(', 30 },
{ 'a' },
@@ -797,11 +808,14 @@ local function test_cmdline(linegrid)
-- This used to send an invalid event where pos where larger than the total
-- length of content. Checked in _handle_cmdline_show.
feed('<esc>')
- screen:expect([[
- ^ |
- {1:~ }|*3
- |
- ]])
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*3
+ |
+ ]],
+ cmdline = { { abort = true } },
+ })
end)
it('does not move cursor to curwin #20309', function()
@@ -827,6 +841,30 @@ local function test_cmdline(linegrid)
} },
}
end)
+
+ it('show prompt hl_id', function()
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ |
+ ]])
+ feed(':echohl Error | call input("Prompt:")<CR>')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*3
+ |
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 242,
+ pos = 0,
+ prompt = 'Prompt:',
+ },
+ },
+ })
+ end)
end
-- the representation of cmdline and cmdline_block contents changed with ext_linegrid
@@ -1000,6 +1038,36 @@ describe('cmdline redraw', function()
]],
}
end)
+
+ it('silent prompt', function()
+ command([[nmap <silent> T :call confirm("Save changes?", "&Yes\n&No\n&Cancel")<CR>]])
+ feed('T')
+ screen:expect([[
+ |
+ {3: }|
+ |
+ {6:Save changes?} |
+ {6:[Y]es, (N)o, (C)ancel: }^ |
+ ]])
+ end)
+
+ it('substitute confirm prompt does not scroll', function()
+ screen:try_resize(75, screen._height)
+ command('call setline(1, "foo")')
+ command('set report=0')
+ feed(':%s/foo/bar/c<CR>')
+ screen:expect([[
+ {2:foo} |
+ {1:~ }|*3
+ {6:replace with bar? (y)es/(n)o/(a)ll/(q)uit/(l)ast/scroll up(^E)/down(^Y)}^ |
+ ]])
+ feed('y')
+ screen:expect([[
+ ^bar |
+ {1:~ }|*3
+ 1 substitution on 1 line |
+ ]])
+ end)
end)
describe('statusline is redrawn on entering cmdline', function()
@@ -1447,31 +1515,29 @@ describe('cmdheight=0', function()
it('when substitute text', function()
command('set cmdheight=0 noruler laststatus=3')
feed('ifoo<ESC>')
- screen:expect {
- grid = [[
+ screen:try_resize(screen._width, 7)
+ screen:expect([[
fo^o |
- {1:~ }|*3
+ {1:~ }|*5
{3:[No Name] [+] }|
- ]],
- }
+ ]])
feed(':%s/foo/bar/gc<CR>')
- screen:expect {
- grid = [[
+ screen:expect([[
{2:foo} |
- {1:~ }|*3
- {6:replace wi...q/l/^E/^Y)?}^ |
- ]],
- }
+ {3: }|
+ |*2
+ {6:replace with bar? (y)es/(}|
+ {6:n)o/(a)ll/(q)uit/(l)ast/s}|
+ {6:croll up(^E)/down(^Y)}^ |
+ ]])
feed('y')
- screen:expect {
- grid = [[
+ screen:expect([[
^bar |
- {1:~ }|*3
+ {1:~ }|*5
{3:[No Name] [+] }|
- ]],
- }
+ ]])
assert_alive()
end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index d7c0657820..825a90fbc8 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -190,6 +190,19 @@ describe('ui/cursor', function()
attr_lm = {},
short_name = 'sm',
},
+ [18] = {
+ blinkoff = 500,
+ blinkon = 500,
+ blinkwait = 0,
+ cell_percentage = 0,
+ cursor_shape = 'block',
+ name = 'terminal',
+ hl_id = 3,
+ id_lm = 3,
+ attr = { reverse = true },
+ attr_lm = { reverse = true },
+ short_name = 't',
+ },
}
screen:expect(function()
@@ -245,17 +258,20 @@ describe('ui/cursor', function()
end
end
if m.hl_id then
- m.hl_id = 66
+ m.hl_id = 65
m.attr = { background = Screen.colors.DarkGray }
end
if m.id_lm then
- m.id_lm = 73
+ m.id_lm = 72
+ m.attr_lm = {}
end
end
-- Assert the new expectation.
screen:expect(function()
- eq(expected_mode_info, screen._mode_info)
+ for i, v in ipairs(expected_mode_info) do
+ eq(v, screen._mode_info[i])
+ end
eq(true, screen._cursor_style_enabled)
eq('normal', screen.mode)
end)
@@ -361,4 +377,38 @@ describe('ui/cursor', function()
end
end)
end)
+
+ it(':sleep does not hide cursor when sleeping', function()
+ n.feed(':sleep 100m | echo 42\n')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*3
+ :sleep 100m | echo 42 |
+ ]],
+ timeout = 100,
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ 42 |
+ ]])
+ end)
+
+ it(':sleep! hides cursor when sleeping', function()
+ n.feed(':sleep! 100m | echo 42\n')
+ screen:expect({
+ grid = [[
+ |
+ {1:~ }|*3
+ :sleep! 100m | echo 42 |
+ ]],
+ timeout = 100,
+ })
+ screen:expect([[
+ ^ |
+ {1:~ }|*3
+ 42 |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index fbf16f3afe..7969dd5d3b 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -509,6 +509,69 @@ describe('decorations providers', function()
]]}
end)
+ it('can have virtual text of the style: eol_right_align', function()
+ insert(mulholland)
+ setup_provider [[
+ local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
+ local test_ns = api.nvim_create_namespace "mulholland"
+ function on_do(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
+ virt_text = {{'+'}, {'1234567890', 'ErrorMsg'}};
+ virt_text_pos='eol_right_align';
+ ephemeral = true;
+ })
+ end
+ end
+ ]]
+
+ screen:expect{grid=[[
+ // just to see if there was an accident |
+ // on Mulholland Drive +{2:1234567890}|
+ try_start(); +{2:1234567890}|
+ bufref_T save_buf; +{2:1234567890}|
+ switch_buffer(&save_buf, buf); +{2:12345678}|
+ posp = getmark(mark, false); +{2:1234567890}|
+ restore_buffer(&save_buf);^ +{2:1234567890}|
+ |
+ ]]}
+ end)
+
+ it('multiple eol_right_align', function()
+ insert(mulholland)
+ setup_provider [[
+ local hl = api.nvim_get_hl_id_by_name "ErrorMsg"
+ local test_ns = api.nvim_create_namespace "mulholland"
+ function on_do(event, ...)
+ if event == "line" then
+ local win, buf, line = ...
+ api.nvim_buf_set_extmark(buf, test_ns, line, 0, {
+ virt_text = {{'11111'}};
+ virt_text_pos='eol_right_align';
+ ephemeral = true;
+ })
+ api.nvim_buf_set_extmark(0, test_ns, line, 0, {
+ virt_text = {{'22222'}};
+ virt_text_pos='eol_right_align';
+ ephemeral = true;
+ })
+ end
+ end
+ ]]
+
+ screen:expect{grid=[[
+ // just to see if there was an accident |
+ // on Mulholland Drive 11111 22222|
+ try_start(); 11111 22222|
+ bufref_T save_buf; 11111 22222|
+ switch_buffer(&save_buf, buf); 11111 222|
+ posp = getmark(mark, false); 11111 22222|
+ restore_buffer(&save_buf);^ 11111 22222|
+ |
+ ]]}
+ end)
+
it('virtual text works with wrapped lines', function()
insert(mulholland)
feed('ggJj3JjJ')
@@ -631,7 +694,7 @@ describe('decorations providers', function()
{14: }hello97 |
{14: }hello98 |
{14: }hello99 |
- X ^hello100 |
+ {14:X }^hello100 |
{14: }hello101 |
{14: }hello102 |
{14: }hello103 |
@@ -744,6 +807,30 @@ describe('decorations providers', function()
]])
eq(2, exec_lua([[return _G.cnt]]))
end)
+
+ it('can do large changes to the marktree', function()
+ insert("line1 with a lot of text\nline2 with a lot of text")
+ setup_provider([[
+ function on_do(event, _, _, row)
+ if event == 'win' or (event == 'line' and row == 1) then
+ vim.api.nvim_buf_clear_namespace(0, ns1, 0, -1)
+ for i = 0,1 do
+ for j = 0,23 do
+ vim.api.nvim_buf_set_extmark(0, ns1, i, j, {hl_group='ErrorMsg', end_col = j+1})
+ end
+ end
+ end
+ end
+ ]])
+
+ -- Doesn't crash when modifying the marktree between line1 and line2
+ screen:expect([[
+ {2:line1 with a lot of text} |
+ {2:line2 with a lot of tex^t} |
+ {1:~ }|*5
+ |
+ ]])
+ end)
end)
local example_text = [[
@@ -810,6 +897,9 @@ describe('extmark decorations', function()
[42] = {undercurl = true, special = Screen.colors.Red};
[43] = {background = Screen.colors.Yellow, undercurl = true, special = Screen.colors.Red};
[44] = {background = Screen.colors.LightMagenta};
+ [45] = { background = Screen.colors.Red, special = Screen.colors.Red, foreground = Screen.colors.Red };
+ [46] = { background = Screen.colors.Blue, foreground = Screen.colors.Blue, special = Screen.colors.Red };
+ [47] = { background = Screen.colors.Green, foreground = Screen.colors.Blue, special = Screen.colors.Red };
}
ns = api.nvim_create_namespace 'test'
@@ -1900,6 +1990,46 @@ describe('extmark decorations', function()
]]}
end)
+ it('highlight can combine multiple groups', function()
+ screen:try_resize(50, 3)
+ command('hi Group1 guibg=Red guifg=Red guisp=Red')
+ command('hi Group2 guibg=Blue guifg=Blue')
+ command('hi Group3 guibg=Green')
+ insert([[example text]])
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row=1, hl_group = {} })
+ screen:expect([[
+ example tex^t |
+ {1:~ }|
+ |
+ ]])
+
+ api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row=1, hl_group = {'Group1'} })
+ screen:expect([[
+ {45:example tex^t} |
+ {1:~ }|
+ |
+ ]])
+ api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = {'Group1', 'Group2'} })
+ screen:expect([[
+ {46:example tex^t} |
+ {1:~ }|
+ |
+ ]])
+ api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 1, hl_group = {'Group1', 'Group2', 'Group3'}, hl_eol=true })
+ screen:expect([[
+ {47:example tex^t }|
+ {1:~ }|
+ |
+ ]])
+
+ eq('Invalid hl_group: hl_group item',
+ pcall_err(api.nvim_buf_set_extmark, 0, ns, 0, 0, { end_row = 1, hl_group = {'Group1', 'Group2', {'fail'}}, hl_eol=true }))
+ end)
+
+
it('highlight works after TAB with sidescroll #14201', function()
screen:try_resize(50, 3)
command('set nowrap')
@@ -2301,13 +2431,16 @@ describe('extmark decorations', function()
it('works with both hl_group and sign_hl_group', function()
screen:try_resize(50, 3)
+ screen:add_extra_attr_ids({
+ [100] = { background = Screen.colors.WebGray, foreground = Screen.colors.Blue, bold = true },
+ })
insert('abcdefghijklmn')
api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S', sign_hl_group='NonText', hl_group='Error', end_col=14})
- screen:expect{grid=[[
- {1:S }{4:abcdefghijklm^n} |
+ screen:expect([[
+ {100:S }{9:abcdefghijklm^n} |
{1:~ }|
|
- ]]}
+ ]])
end)
it('virt_text_repeat_linebreak repeats virtual text on wrapped lines', function()
@@ -5064,16 +5197,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S'})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S l2 |
+ {7:S }l2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add a single sign (with end row)', function()
@@ -5082,16 +5215,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row=1})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S l2 |
+ {7:S }l2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add a single sign and text highlight', function()
@@ -5099,16 +5232,16 @@ l5
feed 'gg'
api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text='S', hl_group='Todo', end_col=1})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S {100:l}2 |
+ {7:S }{100:l}2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
@@ -5119,16 +5252,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row = 2})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S l2 |
- S l3 |
+ {7:S }l2 |
+ {7:S }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add multiple signs (multiple extmarks)', function()
@@ -5138,16 +5271,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
api.nvim_buf_set_extmark(0, ns, 3, -1, {sign_text='S2', end_row = 4})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S1l2 |
+ {7:S1}l2 |
{7: }l3 |
- S2l4 |
- S2l5 |
+ {7:S2}l4 |
+ {7:S2}l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add multiple signs (multiple extmarks) 2', function()
@@ -5156,16 +5289,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 3, -1, {sign_text='S1'})
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row = 3})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S2{7: }l2 |
- S2{7: }l3 |
- S2S1l4 |
+ {7:S2 }l2 |
+ {7:S2 }l3 |
+ {7:S2S1}l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add multiple signs (multiple extmarks) 3', function()
@@ -5176,16 +5309,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S1', end_row=2})
api.nvim_buf_set_extmark(0, ns, 2, -1, {sign_text='S2', end_row=3})
- screen:expect{grid=[[
+ screen:expect([[
{7: }^l1 |
- S1{7: }l2 |
- S2S1l3 |
- S2{7: }l4 |
+ {7:S1 }l2 |
+ {7:S2S1}l3 |
+ {7:S2 }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add multiple signs (multiple extmarks) 4', function()
@@ -5195,16 +5328,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=0})
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row=1})
- screen:expect{grid=[[
- S1^l1 |
- S2l2 |
+ screen:expect([[
+ {7:S1}^l1 |
+ {7:S2}l2 |
{7: }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('works with old signs', function()
@@ -5219,16 +5352,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
api.nvim_buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
- screen:expect{grid=[[
- S4S1^l1 |
- S2x l2 |
- S5{7: }l3 |
+ screen:expect([[
+ {7:S4S1}^l1 |
+ {7:S2x }l2 |
+ {7:S5 }l3 |
{7: }l4 |
{7: }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('works with old signs (with range)', function()
@@ -5244,16 +5377,16 @@ l5
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
api.nvim_buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
- screen:expect{grid=[[
- S4S3S1^l1 |
- S3S2x l2 |
- S5S3{7: }l3 |
- S3{7: }l4 |
- S3{7: }l5 |
+ screen:expect([[
+ {7:S4S3S1}^l1 |
+ {7:S3S2x }l2 |
+ {7:S5S3 }l3 |
+ {7:S3 }l4 |
+ {7:S3 }l5 |
{7: } |
{1:~ }|*3
|
- ]]}
+ ]])
end)
it('can add a ranged sign (with start out of view)', function()
@@ -5264,14 +5397,14 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='X', end_row=3})
- screen:expect{grid=[[
- X {7: }^l3 |
- X {7: }l4 |
+ screen:expect([[
+ {7:X }^l3 |
+ {7:X }l4 |
{7: }l5 |
{7: } |
{1:~ }|*5
|
- ]]}
+ ]])
end)
it('can add lots of signs', function()
@@ -5293,11 +5426,11 @@ l5
api.nvim_buf_set_extmark(0, ns, i, -1, { sign_text='Z' })
end
- screen:expect{grid=[[
- Z Y X W {100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:h} |*8
- Z Y X W {100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:^h} |
+ screen:expect([[
+ {7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:h} |*8
+ {7:Z Y X W }{100:a} {100:b} {100:c} {100:d} {100:e} {100:f} {100:g} {100:^h} |
|
- ]]}
+ ]])
end)
it('works with priority #19716', function()
@@ -5313,20 +5446,20 @@ l5
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S5', priority=200})
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S1', priority=1})
- screen:expect{grid=[[
- S5S4O3S2S1^l1 |
+ screen:expect([[
+ {7:S5S4O3S2S1}^l1 |
{7: }l2 |
|
- ]]}
+ ]])
-- Check truncation works too
api.nvim_set_option_value('signcolumn', 'auto', {})
- screen:expect{grid=[[
- S5^l1 |
+ screen:expect([[
+ {7:S5}^l1 |
{7: }l2 |
|
- ]]}
+ ]])
end)
it('does not overflow with many old signs #23852', function()
@@ -5343,21 +5476,21 @@ l5
command([[exe 'sign place 07 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
command([[exe 'sign place 08 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
command([[exe 'sign place 09 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
- screen:expect{grid=[[
- O3O3O3O3O3O3O3O3O3^ |
+ screen:expect([[
+ {7:O3O3O3O3O3O3O3O3O3}^ |
{1:~ }|
|
- ]]}
+ ]])
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S1', priority=1})
screen:expect_unchanged()
api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S5', priority=200})
- screen:expect{grid=[[
- S5O3O3O3O3O3O3O3O3^ |
+ screen:expect([[
+ {7:S5O3O3O3O3O3O3O3O3}^ |
{1:~ }|
|
- ]]}
+ ]])
assert_alive()
end)
@@ -5383,12 +5516,12 @@ l5
api.nvim_buf_set_extmark(0, ns, 1, -1, {invalidate = true, sign_text='S3'})
feed('2Gdd')
- screen:expect{grid=[[
- S1l1 |
- S1^l3 |
- S1l4 |
+ screen:expect([[
+ {7:S1}l1 |
+ {7:S1}^l3 |
+ {7:S1}l4 |
|
- ]]}
+ ]])
end)
it('correct width with multiple overlapping signs', function()
@@ -5400,36 +5533,36 @@ l5
feed('gg')
local s1 = [[
- S2S1^l1 |
- S3S2l2 |
- S3S2l3 |
+ {7:S2S1}^l1 |
+ {7:S3S2}l2 |
+ {7:S3S2}l3 |
|
]]
- screen:expect{grid=s1}
+ screen:expect(s1)
-- Correct width when :move'ing a line with signs
command('move2')
- screen:expect{grid=[[
- S3{7: }l2 |
- S3S2S1^l1 |
+ screen:expect([[
+ {7:S3 }l2 |
+ {7:S3S2S1}^l1 |
{7: }l3 |
|
- ]]}
+ ]])
command('silent undo')
screen:expect{grid=s1}
command('d')
- screen:expect{grid=[[
- S3S2S1^l2 |
- S3S2{7: }l3 |
+ screen:expect([[
+ {7:S3S2S1}^l2 |
+ {7:S3S2 }l3 |
{7: }l4 |
|
- ]]}
+ ]])
command('d')
- screen:expect{grid=[[
- S3S2S1^l3 |
+ screen:expect([[
+ {7:S3S2S1}^l3 |
{7: }l4 |
{7: }l5 |
|
- ]]}
+ ]])
end)
it('correct width when adding and removing multiple signs', function()
@@ -5452,12 +5585,12 @@ l5
redraw!
call nvim_buf_del_extmark(0, ns, s1)
]])
- screen:expect{grid=[[
- S1^l1 |
- S1l2 |
- S1l3 |
+ screen:expect([[
+ {7:S1}^l1 |
+ {7:S1}l2 |
+ {7:S1}l3 |
|
- ]]}
+ ]])
end)
it('correct width when deleting lines', function()
@@ -5472,12 +5605,12 @@ l5
call nvim_buf_del_extmark(0, ns, s3)
norm 4Gdd
]])
- screen:expect{grid=[[
+ screen:expect([[
{7: }l3 |
- S2S1l5 |
+ {7:S2S1}l5 |
{7: }^ |
|
- ]]}
+ ]])
end)
it('correct width when splitting lines with signs on different columns', function()
@@ -5487,12 +5620,12 @@ l5
api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S1'})
api.nvim_buf_set_extmark(0, ns, 0, 1, {sign_text='S2'})
feed('a<cr><esc>')
- screen:expect{grid=[[
- S1l |
- S2^1 |
+ screen:expect([[
+ {7:S1}l |
+ {7:S2}^1 |
{7: }l2 |
|
- ]]}
+ ]])
end)
it('correct width after wiping a buffer', function()
@@ -5501,12 +5634,12 @@ l5
feed('gg')
local buf = api.nvim_get_current_buf()
api.nvim_buf_set_extmark(buf, ns, 0, 0, { sign_text = 'h' })
- screen:expect{grid=[[
- h ^l1 |
+ screen:expect([[
+ {7:h }^l1 |
{7: }l2 |
{7: }l3 |
|
- ]]}
+ ]])
api.nvim_win_set_buf(0, api.nvim_create_buf(false, true))
api.nvim_buf_delete(buf, {unload=true, force=true})
api.nvim_buf_set_lines(buf, 0, -1, false, {''})
@@ -5537,12 +5670,12 @@ l5
end)
]])
- screen:expect{grid=[[
- S1^l1 |
- S2l2 |
- S4l3 |
+ screen:expect([[
+ {7:S1}^l1 |
+ {7:S2}l2 |
+ {7:S4}l3 |
|
- ]]}
+ ]])
end)
it('no crash with sign after many marks #27137', function()
@@ -5553,11 +5686,11 @@ l5
end
api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text = 'S1'})
- screen:expect{grid=[[
- S1{9:^a} |
+ screen:expect([[
+ {7:S1}{9:^a} |
{1:~ }|*2
|
- ]]}
+ ]])
end)
it('correct sort order with multiple namespaces and same id', function()
@@ -5565,11 +5698,11 @@ l5
api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text = 'S1', id = 1})
api.nvim_buf_set_extmark(0, ns2, 0, 0, {sign_text = 'S2', id = 1})
- screen:expect{grid=[[
- S2S1^ |
+ screen:expect([[
+ {7:S2S1}^ |
{1:~ }|*8
|
- ]]}
+ ]])
end)
it('correct number of signs after deleting text (#27046)', function()
@@ -5586,12 +5719,12 @@ l5
api.nvim_buf_set_extmark(0, ns, 30, 0, {end_row = 30, end_col = 3, hl_group = 'Error'})
command('0d29')
- screen:expect{grid=[[
- S4S3S2S1{9:^foo} |
- S5{7: }{9:foo} |
+ screen:expect([[
+ {7:S4S3S2S1}{9:^foo} |
+ {7:S5 }{9:foo} |
{1:~ }|*7
29 fewer lines |
- ]]}
+ ]])
api.nvim_buf_clear_namespace(0, ns, 0, -1)
end)
@@ -5599,21 +5732,17 @@ l5
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
- |
- ]]
- })
+ screen:expect([[
+ {7:S1 }^ |
+ {1:~ }|*8
+ |
+ ]])
api.nvim_buf_del_extmark(0, ns, 1)
- screen:expect({
- grid = [[
- {8:1 }^ |
- {1:~ }|*8
- |
- ]]
- })
+ screen:expect([[
+ {8:1 }^ |
+ {1:~ }|*8
+ |
+ ]])
end)
it('supports emoji as signs', function()
@@ -5626,10 +5755,10 @@ l5
api.nvim_buf_set_extmark(0, ns, 4, 0, {sign_text='❤x'})
screen:expect([[
{7: }^l1 |
- 🧑‍🌾l2 |
- ❤️l3 |
- ❤ l4 |
- ❤xl5 |
+ {7:🧑‍🌾}l2 |
+ {7:❤️}l3 |
+ {7:❤ }l4 |
+ {7:❤x}l5 |
{7: } |
{1:~ }|*3
|
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index 95159011f1..dae373297a 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -2044,6 +2044,26 @@ it('diff mode overlapped diff blocks will be merged', function()
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
+
+ WriteDiffFiles3('a\nb\nc', 'd\ne', 'b\nf')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:d}{4: }│{7: }{27:^b}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:e}{4: }│{7: }{27:f}{4: }|
+ {7: }{22:c }│{7: }{23:---------}│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
+
+ WriteDiffFiles3('a\nb\nc', 'd\ne', 'b')
+ screen:expect([[
+ {7: }{27:a}{4: }│{7: }{27:d}{4: }│{7: }{27:^b}{4: }|
+ {7: }{27:b}{4: }│{7: }{27:e}{4: }│{7: }{23:---------}|
+ {7: }{22:c }│{7: }{23:---------}│{7: }{23:---------}|
+ {1:~ }│{1:~ }│{1:~ }|*15
+ {2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
+ |
+ ]])
end)
-- oldtest: Test_diff_topline_noscroll()
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 57ef9bcff6..15231e0f8c 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -1012,6 +1012,97 @@ describe('float window', function()
end)
end)
+ it('placed relative to tabline and laststatus', function()
+ local screen = Screen.new(20, 10)
+ screen:add_extra_attr_ids({ [100] = { bold = true, foreground = Screen.colors.Magenta } })
+ command('set showtabline=1 laststatus=1')
+ api.nvim_open_win(0, false, {
+ relative = 'laststatus',
+ border = 'single',
+ anchor = 'SE',
+ width = 5,
+ height = 1,
+ row = 0,
+ col = 1000,
+ })
+ local tabwin = api.nvim_open_win(0, false, {
+ relative = 'tabline',
+ border = 'single',
+ width = 5,
+ height = 1,
+ row = 0,
+ col = 1000,
+ })
+ screen:expect([[
+ ^ {2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ {1:~ }|*3
+ {1:~ }{2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ |
+ ]])
+ command('tabnew | tabnext')
+ screen:expect([[
+ {5: }{100:3}{5: Name] }{24: No Name]X}|
+ ^ {2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ {1:~ }|*2
+ {1:~ }{2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ |
+ ]])
+ command('vsplit')
+ screen:expect([[
+ {5: }{100:4}{5: Name] }{24: No Name]X}|
+ ^ {2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ {1:~ }{2:│}{1:~}|
+ {1:~ }{2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ {3:[No Name] }{2:<}|
+ |
+ ]])
+ command('quit')
+ api.nvim_win_set_config(tabwin, {
+ relative = 'tabline',
+ border = 'single',
+ width = 5,
+ height = 1,
+ row = 1,
+ col = 0,
+ })
+ screen:expect([[
+ {5: }{100:3}{5: Name] }{24: No Name]X}|
+ ^ |
+ {2:┌─────┐}{1: }|
+ {2:│}{4: }{2:│}{1: }|
+ {2:└─────┘}{1: }|
+ {1:~ }|
+ {1:~ }{2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ |
+ ]])
+ command('tabonly')
+ screen:expect([[
+ ^ |
+ {2:┌─────┐}{1: }|
+ {2:│}{4: }{2:│}{1: }|
+ {2:└─────┘}{1: }|
+ {1:~ }|*2
+ {1:~ }{2:┌─────┐}|
+ {1:~ }{2:│}{4: }{2:│}|
+ {1:~ }{2:└─────┘}|
+ |
+ ]])
+ end)
+
local function with_ext_multigrid(multigrid)
local screen, attrs
before_each(function()
@@ -1046,6 +1137,8 @@ describe('float window', function()
[26] = {blend = 80, background = Screen.colors.Gray0};
[27] = {foreground = Screen.colors.Black, background = Screen.colors.LightGrey};
[28] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey};
+ [29] = {background = Screen.colors.Yellow1, foreground = Screen.colors.Blue4};
+ [30] = {background = Screen.colors.Grey, foreground = Screen.colors.Blue4, bold = true};
}
screen:set_default_attr_ids(attrs)
end)
@@ -1451,14 +1544,14 @@ describe('float window', function()
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
- {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
+ {19: }{29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } |
{0:~ }|*3
## grid 3
|
## grid 4
- {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
+ {29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
{19: }{15:y }|
{19: }{15: }|
{15: }|
@@ -1466,9 +1559,9 @@ describe('float window', function()
else
screen:expect([[
- {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
+ {19: }{29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
- {19: }{14: 3 }{22: } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } |
+ {19: }{14: 3 }{22: } {29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } |
{0:~ }{19: }{15:y }{0: }|
{0:~ }{19: }{15: }{0: }|
{0:~ }{15: }{0: }|
@@ -1551,14 +1644,14 @@ describe('float window', function()
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
- {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
+ {19: }{29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
{19: }{14: 3 }{22: } |
{0:~ }|*3
## grid 3
|
## grid 4
- {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
+ {29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
{19: }{15:y }|
{19: }{15: }|
{15: }|
@@ -1566,9 +1659,9 @@ describe('float window', function()
else
screen:expect([[
- {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
+ {19: }{29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
{19: }{14: 2 }{22:y} |
- {19: }{14: 3 }{22: } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } |
+ {19: }{14: 3 }{22: } {29:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } |
{0:~ }{19: }{15:y }{0: }|
{0:~ }{19: }{15: }{0: }|
{0:~ }{15: }{0: }|
@@ -1616,31 +1709,34 @@ describe('float window', function()
feed('ix<cr>y<cr><esc>gg')
api.nvim_open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'})
if multigrid then
- screen:expect{grid=[[
- ## grid 1
- [2:----------------------------------------]|*6
- [3:----------------------------------------]|
- ## grid 2
- {20: 1}{19: }{22:^x}{21: }|
- {14: 2}{19: }{22:y} |
- {14: 3}{19: }{22: } |
- {0:~ }|*3
- ## grid 3
- |
- ## grid 4
- {15:x }|
- {15:y }|
- {15: }|*2
- ]], float_pos={[4] = {1001, "NW", 1, 4, 10, true}}}
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*6
+ [3:----------------------------------------]|
+ ## grid 2
+ {20: 1}{19: }{22:^x}{21: }|
+ {14: 2}{19: }{22:y} |
+ {14: 3}{19: }{22: } |
+ {0:~ }|*3
+ ## grid 3
+ |
+ ## grid 4
+ {15:x }|
+ {15:y }|
+ {15: }|*2
+ ]],
+ float_pos = { [4] = { 1001, "NW", 1, 4, 10, true, 50 } },
+ })
else
- screen:expect{grid=[[
+ screen:expect([[
{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
|
- ]]}
+ ]])
end
end)
@@ -2237,6 +2333,61 @@ describe('float window', function()
|
]]}
end
+
+ -- reuse before title pos
+ api.nvim_win_set_config(win, {title= 'new'})
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*6
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|*5
+ ## grid 3
+ |
+ ## grid 4
+ {5:╔══════}{11:new}{5:╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]],
+ float_pos = {
+ [4] = {1001, "NW", 1, 2, 5, true, 50};
+ },
+ 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 = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0};
+ },
+ win_viewport_margins = {
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ },
+ [4] = {
+ bottom = 1,
+ left = 1,
+ right = 1,
+ top = 1,
+ win = 1001
+ }
+ },
+ })
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔══════}{11:new}{5:╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ |
+ ]])
+ end
end)
it('border with footer', function()
@@ -2382,6 +2533,61 @@ describe('float window', function()
|
]]}
end
+
+ -- reuse before footer pos
+ api.nvim_win_set_config(win, { footer = 'new' })
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*6
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|*5
+ ## grid 3
+ |
+ ## grid 4
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚══════}{11:new}{5:╝}|
+ ]],
+ float_pos = {
+ [4] = {1001, "NW", 1, 2, 5, true, 50};
+ },
+ 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 = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0};
+ },
+ win_viewport_margins = {
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ },
+ [4] = {
+ bottom = 1,
+ left = 1,
+ right = 1,
+ top = 1,
+ win = 1001
+ }
+ },
+ })
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }{5:╔═════════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚══════}{11:new}{5:╝}{0: }|
+ |
+ ]])
+ end
end)
it('border with title and footer', function()
@@ -8542,6 +8748,131 @@ describe('float window', function()
|
]]}
end
+
+ --
+ -- Check that floats are positioned correctly after changing the zindexes.
+ --
+ command('fclose')
+ exec_lua([[
+ local win1, win3 = ...
+ vim.api.nvim_win_set_config(win1, { zindex = 400, title = 'win_400', title_pos = 'center', border = 'double' })
+ vim.api.nvim_win_set_config(win3, { zindex = 300, title = 'win_300', title_pos = 'center', border = 'single' })
+ ]], win1, win3)
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*6
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|*5
+ ## grid 3
+ |
+ ## grid 4
+ {5:╔══════}{11:win_400}{5:═══════╗}|
+ {5:║}{7: }{5:║}|
+ {5:║}{7:~ }{5:║}|*2
+ {5:╚════════════════════╝}|
+ ## grid 6
+ {5:┌──────}{11:win_300}{5:───────┐}|
+ {5:│}{8: }{5:│}|
+ {5:│}{8:~ }{5:│}|*2
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [4] = {1001, "NW", 1, 1, 5, true, 400};
+ [6] = {1003, "NW", 1, 3, 7, true, 300};
+ }, 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 = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ [6] = {win = 1003, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ }, win_viewport_margins={
+ [2] = { bottom = 0, left = 0, right = 0, top = 0, win = 1000 },
+ [4] = { bottom = 1, left = 1, right = 1, top = 1, win = 1001 },
+ [6] = { bottom = 1, left = 1, right = 1, top = 1, win = 1003 }
+ }})
+ else
+ screen:expect({
+ grid = [[
+ ^ |
+ {0:~ }{5:╔══════}{11:win_400}{5:═══════╗}{0: }|
+ {0:~ }{5:║}{7: }{5:║─┐}{0: }|
+ {0:~ }{5:║}{7:~ }{5:║}{8: }{5:│}{0: }|*2
+ {0:~ }{5:╚════════════════════╝}{8: }{5:│}{0: }|
+ {5:└────────────────────┘} |
+ ]]
+ })
+ end
+ exec_lua([[
+ local win1, win3 = ...
+ vim.api.nvim_win_set_config(win1, { zindex = 100, title='win_100' })
+ vim.api.nvim_win_set_config(win3, { zindex = 150, title='win_150' })
+ ]], win1, win3)
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*6
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|*5
+ ## grid 3
+ |
+ ## grid 4
+ {5:╔══════}{11:win_100}{5:═══════╗}|
+ {5:║}{7: }{5:║}|
+ {5:║}{7:~ }{5:║}|*2
+ {5:╚════════════════════╝}|
+ ## grid 6
+ {5:┌──────}{11:win_150}{5:───────┐}|
+ {5:│}{8: }{5:│}|
+ {5:│}{8:~ }{5:│}|*2
+ {5:└────────────────────┘}|
+ ]],
+ float_pos = {
+ [4] = {1001, "NW", 1, 1, 5, true, 100};
+ [6] = {1003, "NW", 1, 3, 7, true, 150};
+ },
+ 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 = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ [6] = {win = 1003, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+ },
+ win_viewport_margins = {
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000
+ },
+ [4] = {
+ bottom = 1,
+ left = 1,
+ right = 1,
+ top = 1,
+ win = 1001
+ },
+ [6] = {
+ bottom = 1,
+ left = 1,
+ right = 1,
+ top = 1,
+ win = 1003
+ }
+ },
+ })
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }{5:╔═┌──────}{11:win_150}{5:───────┐}{0: }|
+ {0:~ }{5:║}{7: }{5:│}{8: }{5:│}{0: }|
+ {0:~ }{5:║}{7:~}{5:│}{8:~ }{5:│}{0: }|*2
+ {0:~ }{5:╚═└────────────────────┘}{0: }|
+ |
+ ]])
+ end
end)
it('can use winbar', function()
@@ -9523,4 +9854,3 @@ describe('float window', function()
with_ext_multigrid(false)
end)
end)
-
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index f8f5ee9488..e10c79fa48 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -224,10 +224,10 @@ describe('ext_hlstate detailed highlights', function()
[6] = { { foreground = tonumber('0x40ffff'), fg_indexed = true }, { 5, 1 } },
[7] = { {}, { { hi_name = 'MsgArea', ui_name = 'MsgArea', kind = 'ui' } } },
})
- command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
+ command(("enew | call jobstart(['%s'],{'term':v:true})"):format(testprg('tty-test')))
screen:expect([[
^tty ready |
- {1: } |
+ |
|*5
{7: }|
]])
@@ -242,7 +242,7 @@ describe('ext_hlstate detailed highlights', function()
screen:expect([[
^tty ready |
x {5:y z} |
- {1: } |
+ |
|*4
{7: }|
]])
@@ -250,7 +250,7 @@ describe('ext_hlstate detailed highlights', function()
screen:expect([[
^tty ready |
x {2:y }{3:z} |
- {1: } |
+ |
|*4
{7: }|
]])
@@ -268,7 +268,7 @@ describe('ext_hlstate detailed highlights', function()
else
screen:expect([[
^tty ready |
- x {4:y}{2: }{3:z} |
+ x {2:y }{3:z} |
|*5
{7: }|
]])
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index 2d26d2c5e0..3eee9a6e07 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -253,6 +253,50 @@ describe("'inccommand' for user commands", function()
]]
end)
+ it("can preview 'nomodifiable' buffer", function()
+ exec_lua([[
+ vim.api.nvim_create_user_command("PreviewTest", function() end, {
+ preview = function(ev)
+ vim.bo.modifiable = true
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, {"cats"})
+ return 2
+ end,
+ })
+ ]])
+ command('set inccommand=split')
+
+ command('set nomodifiable')
+ eq(false, api.nvim_get_option_value('modifiable', { buf = 0 }))
+
+ feed(':PreviewTest')
+
+ screen:expect([[
+ cats |
+ {1:~ }|*8
+ {3:[No Name] [+] }|
+ |
+ {1:~ }|*4
+ {2:[Preview] }|
+ :PreviewTest^ |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
+ ^ |
+ {1:~ }|*7
+ |
+ ]])
+
+ eq(false, api.nvim_get_option_value('modifiable', { buf = 0 }))
+ end)
+
it('works with inccommand=nosplit', function()
command('set inccommand=nosplit')
feed(':Replace text cats')
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index 90e0b3e380..98312c42c9 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -368,7 +368,7 @@ describe('input non-printable chars', function()
"Xtest-overwrite" |
{9:WARNING: The file has been changed since reading it!!!} |
{6:Do you really want to write to it (y/n)?}u |
- {6:Do you really want to write to it (y/n)?} |
+ {6:Do you really want to write to it (y/n)?}{18:^E} |
{6:Do you really want to write to it (y/n)?}^ |
]])
@@ -379,7 +379,7 @@ describe('input non-printable chars', function()
"Xtest-overwrite" |
{9:WARNING: The file has been changed since reading it!!!} |
{6:Do you really want to write to it (y/n)?}u |
- {6:Do you really want to write to it (y/n)?} |
+ {6:Do you really want to write to it (y/n)?}{18:^E} |
{6:Do you really want to write to it (y/n)?}n |
{6:Press ENTER or type command to continue}^ |
]])
diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua
index b564c01eaa..3593604c49 100644
--- a/test/functional/ui/linematch_spec.lua
+++ b/test/functional/ui/linematch_spec.lua
@@ -1147,4 +1147,32 @@ describe('regressions', function()
},
}
end)
+
+ -- oldtest: Test_linematch_3diffs_sanity_check()
+ it('sanity check with 3 diff buffers', function()
+ clear()
+ screen = Screen.new(75, 20)
+ n.api.nvim_buf_set_lines(0, 0, -1, false, { 'abcd', 'def', 'hij' })
+ n.exec('rightbelow vnew')
+ n.api.nvim_buf_set_lines(0, 0, -1, false, { 'defq', 'hijk', 'nopq' })
+ n.exec('rightbelow vnew')
+ n.api.nvim_buf_set_lines(0, 0, -1, false, { 'hijklm', 'nopqr', 'stuv' })
+ n.exec([[
+ set diffopt+=linematch:60
+ windo diffthis | wincmd t
+ call feedkeys("Aq\<esc>")
+ call feedkeys("GAklm\<esc>")
+ call feedkeys("o")
+ ]])
+ screen:expect([[
+ {7: }{22:abcdq }│{7: }{23:----------------------}│{7: }{23:-----------------------}|
+ {7: }{4:def }│{7: }{4:def}{27:q}{4: }│{7: }{23:-----------------------}|
+ {7: }{4:hijk}{27:lm}{4: }│{7: }{4:hijk }│{7: }{4:hijk}{27:lm}{4: }|
+ {7: }{23:----------------------}│{7: }{4:nopq }│{7: }{4:nopq}{27:r}{4: }|
+ {7: }{4:^ }│{7: }{23:----------------------}│{7: }{27:stuv}{4: }|
+ {1:~ }│{1:~ }│{1:~ }|*13
+ {3:[No Name] [+] }{2:[No Name] [+] [No Name] [+] }|
+ {5:-- INSERT --} |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 734877d262..5c55dfe910 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -42,104 +42,130 @@ describe('ui/ext_messages', function()
it('msg_clear follows msg_show kind of confirm', function()
feed('iline 1<esc>')
feed(':call confirm("test")<cr>')
- screen:expect {
+ screen:expect({
grid = [[
- line ^1 |
- {1:~ }|*4
- ]],
+ line ^1 |
+ {1:~ }|*4
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 10,
+ pos = 0,
+ prompt = '[O]k: ',
+ },
+ },
messages = {
{
- content = { { '\ntest\n[O]k: ', 6, 11 } },
+ content = { { '\ntest\n', 6, 10 } },
+ history = false,
kind = 'confirm',
},
},
- }
-
+ })
feed('<cr>')
- screen:expect {
+ screen:expect({
grid = [[
- line ^1 |
- {1:~ }|*4
- ]],
- }
+ line ^1 |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
end)
- it('msg_show kind=confirm,confirm_sub,emsg,wmsg,quickfix', function()
+ it('msg_show kinds', function()
feed('iline 1\nline 2<esc>')
- -- kind=confirm
+ -- confirm is now cmdline prompt
feed(':echo confirm("test")<cr>')
- screen:expect {
+ screen:expect({
grid = [[
- line 1 |
- line ^2 |
- {1:~ }|*3
- ]],
+ line 1 |
+ line ^2 |
+ {1:~ }|*3
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 10,
+ pos = 0,
+ prompt = '[O]k: ',
+ },
+ },
messages = {
{
- content = { { '\ntest\n[O]k: ', 6, 11 } },
+ content = { { '\ntest\n', 6, 10 } },
+ history = false,
kind = 'confirm',
},
},
- }
- feed('<cr><cr>')
- screen:expect {
+ })
+ feed('<cr>')
+ screen:expect({
grid = [[
- line 1 |
- line ^2 |
- {1:~ }|*3
- ]],
+ line 1 |
+ line ^2 |
+ {1:~ }|*3
+ ]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { '\ntest\n[O]k: ', 6, 11 } },
+ content = { { '\ntest\n', 6, 10 } },
+ history = false,
kind = 'confirm',
},
{
content = { { '1' } },
+ history = false,
kind = 'echo',
},
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
- }
- feed('<cr><cr>')
+ })
+ feed('<cr>')
- -- kind=confirm_sub
+ -- :substitute confirm is now cmdline prompt
feed(':%s/i/X/gc<cr>')
- screen:expect {
+ screen:expect({
grid = [[
- l{2:i}ne 1 |
- l{10:i}ne ^2 |
- {1:~ }|*3
- ]],
- messages = {
+ l{2:^i}ne 1 |
+ l{10:i}ne 2 |
+ {1:~ }|*3
+ ]],
+ cmdline = {
{
- content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6, 19 } },
- kind = 'confirm_sub',
+ content = { { '' } },
+ hl_id = 18,
+ pos = 0,
+ prompt = 'replace with X? (y)es/(n)o/(a)ll/(q)uit/(l)ast/scroll up(^E)/down(^Y)',
},
},
- }
+ })
feed('nq')
-- kind=wmsg (editing readonly file)
command('write ' .. fname)
command('set readonly nohls')
feed('G$x')
- screen:expect {
+ screen:expect({
grid = [[
line 1 |
- line ^2 |
+ line^ |
{1:~ }|*3
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'W10: Warning: Changing a readonly file', 19, 27 } },
+ content = { { 'W10: Warning: Changing a readonly file', 19, 26 } },
+ history = true,
kind = 'wmsg',
},
},
- }
+ })
-- kind=wmsg ('wrapscan' after search reaches EOF)
feed('uG$/i<cr>')
@@ -149,9 +175,11 @@ describe('ui/ext_messages', function()
line 2 |
{1:~ }|*3
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'search hit BOTTOM, continuing at TOP', 19, 27 } },
+ content = { { 'search hit BOTTOM, continuing at TOP', 19, 26 } },
+ history = true,
kind = 'wmsg',
},
},
@@ -160,22 +188,21 @@ describe('ui/ext_messages', function()
-- kind=emsg after :throw
feed(':throw "foo"<cr>')
screen:expect {
- grid = [[
- l^ine 1 |
- line 2 |
- {1:~ }|*3
- ]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'Error detected while processing :', 9, 7 } },
+ content = { { 'Error detected while processing :', 9, 6 } },
+ history = true,
kind = 'emsg',
},
{
- content = { { 'E605: Exception not caught: foo', 9, 7 } },
- kind = '',
+ content = { { 'E605: Exception not caught: foo', 9, 6 } },
+ history = true,
+ kind = 'emsg',
},
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -191,13 +218,213 @@ describe('ui/ext_messages', function()
^line 2 |
{1:~ }|*3
]],
+ cmdline = { { abort = false } },
messages = {
{
content = { { '(2 of 2): line2' } },
+ history = true,
kind = 'quickfix',
},
},
}
+
+ -- search_cmd
+ feed('?line<cr>')
+ screen:expect({
+ grid = [[
+ ^line 1 |
+ line 2 |
+ {1:~ }|*3
+ ]],
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { '?line ' } },
+ history = false,
+ kind = 'search_cmd',
+ },
+ },
+ })
+
+ -- highlight
+ feed(':filter character highlight<CR>')
+ screen:expect({
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = {
+ { '\n@character ' },
+ { 'xxx', 26, 155 },
+ { ' ' },
+ { 'links to', 18, 5 },
+ { ' Character\n@character.special ' },
+ { 'xxx', 16, 156 },
+ { ' ' },
+ { 'links to', 18, 5 },
+ { ' SpecialChar' },
+ },
+ history = false,
+ kind = 'list_cmd',
+ },
+ },
+ })
+
+ -- undo
+ feed('uu')
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ messages = {
+ {
+ content = { { 'Already at oldest change' } },
+ history = true,
+ kind = 'undo',
+ },
+ },
+ })
+
+ feed('<C-r><C-r><C-r>')
+ screen:expect({
+ grid = [[
+ line 1 |
+ line^ |
+ {1:~ }|*3
+ ]],
+ messages = {
+ {
+ content = { { 'Already at newest change' } },
+ history = true,
+ kind = 'undo',
+ },
+ },
+ })
+
+ -- kind=completion
+ command('set noshowmode')
+ feed('i<C-n>')
+ screen:expect({
+ messages = {
+ {
+ content = { { 'The only match' } },
+ history = false,
+ kind = 'completion',
+ },
+ },
+ })
+ feed('<Esc>')
+ command('set showmode')
+
+ -- kind=echoerr for nvim_echo() err
+ feed(':call nvim_echo([["Error"], ["Message", "Special"]], 1, #{ err:1 })<CR>')
+ screen:expect({
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { 'Error', 9, 6 }, { 'Message', 16, 99 } },
+ history = true,
+ kind = 'echoerr',
+ },
+ },
+ })
+
+ -- kind=verbose for nvim_echo() verbose
+ feed(':call nvim_echo([["Verbose Message"]], 1, #{ verbose:1 })<CR>')
+ screen:expect({
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { 'Verbose Message' } },
+ history = true,
+ kind = 'verbose',
+ },
+ },
+ })
+
+ -- kind=verbose for :verbose messages
+ feed(':1verbose filter Diff[AC] hi<CR>')
+ screen:expect({
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = {
+ { '\nDiffAdd ' },
+ { 'xxx', 22, 30 },
+ { ' ' },
+ { 'ctermbg=', 18, 5 },
+ { '81 ' },
+ { 'guibg=', 18, 5 },
+ { 'LightBlue' },
+ },
+ history = false,
+ kind = 'list_cmd',
+ },
+ {
+ content = { { '\n\tLast set from Lua (run Nvim with -V1 for more details)' } },
+ history = false,
+ kind = 'verbose',
+ },
+ {
+ content = {
+ { '\nDiffChange ' },
+ { 'xxx', 4, 31 },
+ { ' ' },
+ { 'ctermbg=', 18, 5 },
+ { '225 ' },
+ { 'guibg=', 18, 5 },
+ { 'LightMagenta' },
+ },
+ history = false,
+ kind = 'list_cmd',
+ },
+ {
+ content = { { '\n\tLast set from Lua (run Nvim with -V1 for more details)' } },
+ history = false,
+ kind = 'verbose',
+ },
+ {
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
+ kind = 'return_prompt',
+ },
+ },
+ })
+
+ -- kind=shell for :!cmd messages
+ local cmd = t.is_os('win') and 'echo stdout& echo stderr>&2& exit 3'
+ or '{ echo stdout; echo stderr >&2; exit 3; }'
+ feed(('<CR>:!%s<CR>'):format(cmd))
+ screen:expect({
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { (':!%s\r\n[No write since last change]\n'):format(cmd) } },
+ history = false,
+ kind = '',
+ },
+ {
+ content = { { ('stdout%s\n'):format(t.is_os('win') and '\r' or '') } },
+ history = false,
+ kind = 'shell_out',
+ },
+ {
+ content = { { ('stderr%s\n'):format(t.is_os('win') and '\r' or ''), 9, 6 } },
+ history = false,
+ kind = 'shell_err',
+ },
+ {
+ content = { { '\nshell returned 3\n\n' } },
+ history = false,
+ kind = 'shell_ret',
+ },
+ {
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
+ kind = 'return_prompt',
+ },
+ },
+ })
end)
it(':echoerr', function()
@@ -207,10 +434,14 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- messages = { {
- content = { { 'raa', 9, 7 } },
- kind = 'echoerr',
- } },
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { 'raa', 9, 6 } },
+ history = true,
+ kind = 'echoerr',
+ },
+ },
}
-- cmdline in a later input cycle clears error message
@@ -233,17 +464,21 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'bork', 9, 7 } },
+ content = { { 'bork', 9, 6 } },
+ history = true,
kind = 'echoerr',
},
{
- content = { { 'fail', 9, 7 } },
+ content = { { 'fail', 9, 6 } },
+ history = true,
kind = 'echoerr',
},
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -255,21 +490,26 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'bork', 9, 7 } },
+ content = { { 'bork', 9, 6 } },
+ history = true,
kind = 'echoerr',
},
{
- content = { { 'fail', 9, 7 } },
+ content = { { 'fail', 9, 6 } },
+ history = true,
kind = 'echoerr',
},
{
- content = { { 'extrafail', 9, 7 } },
+ content = { { 'extrafail', 9, 6 } },
+ history = true,
kind = 'echoerr',
},
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -290,13 +530,17 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- messages = { {
- content = { { 'problem', 9, 7 } },
- kind = 'echoerr',
- } },
+ messages = {
+ {
+ content = { { 'problem', 9, 6 } },
+ history = true,
+ kind = 'echoerr',
+ },
+ },
cmdline = {
{
prompt = 'foo> ',
+ hl_id = 0,
content = { { '' } },
pos = 0,
},
@@ -309,6 +553,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
}
eq('solution', eval('x'))
@@ -318,16 +563,18 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
msg_history = {
- { kind = 'echoerr', content = { { 'raa', 9, 7 } } },
- { kind = 'echoerr', content = { { 'bork', 9, 7 } } },
- { kind = 'echoerr', content = { { 'fail', 9, 7 } } },
- { kind = 'echoerr', content = { { 'extrafail', 9, 7 } } },
- { kind = 'echoerr', content = { { 'problem', 9, 7 } } },
+ { kind = 'echoerr', content = { { 'raa', 9, 6 } } },
+ { kind = 'echoerr', content = { { 'bork', 9, 6 } } },
+ { kind = 'echoerr', content = { { 'fail', 9, 6 } } },
+ { kind = 'echoerr', content = { { 'extrafail', 9, 6 } } },
+ { kind = 'echoerr', content = { { 'problem', 9, 6 } } },
},
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -350,9 +597,11 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'bork\nfail', 9, 7 } },
+ content = { { 'bork\nfail', 9, 6 } },
+ history = true,
kind = 'echoerr',
},
},
@@ -364,15 +613,17 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
msg_history = {
{
- content = { { 'bork\nfail', 9, 7 } },
+ content = { { 'bork\nfail', 9, 6 } },
kind = 'echoerr',
},
},
@@ -390,8 +641,9 @@ describe('ui/ext_messages', function()
{10:line} 2 |
{1:~ }|*3
]],
+ cmdline = { { abort = false } },
messages = {
- { content = { { '/line W [1/2]' } }, kind = 'search_count' },
+ { content = { { '/line W [1/2]' } }, kind = 'search_count', history = false },
},
}
@@ -403,35 +655,7 @@ describe('ui/ext_messages', function()
{1:~ }|*3
]],
messages = {
- { content = { { '/line [2/2]' } }, kind = 'search_count' },
- },
- }
- end)
-
- it(':hi Group output', function()
- feed(':hi ErrorMsg<cr>')
- screen:expect {
- grid = [[
- ^ |
- {1:~ }|*4
- ]],
- messages = {
- {
- content = {
- { '\nErrorMsg ' },
- { 'xxx', 9, 7 },
- { ' ' },
- { 'ctermfg=', 18, 6 },
- { '15 ' },
- { 'ctermbg=', 18, 6 },
- { '1 ' },
- { 'guifg=', 18, 6 },
- { 'White ' },
- { 'guibg=', 18, 6 },
- { 'Red' },
- },
- kind = '',
- },
+ { content = { { '/line [2/2]' } }, kind = 'search_count', history = false },
},
}
end)
@@ -444,11 +668,13 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
- { content = { { 'x #1' } }, kind = '' },
- { content = { { 'y #2' } }, kind = '' },
+ { content = { { 'x #1' } }, kind = 'list_cmd', history = false },
+ { content = { { 'y #2' } }, kind = 'list_cmd', history = false },
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -463,7 +689,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { '-- INSERT --', 5, 12 } },
+ showmode = { { '-- INSERT --', 5, 11 } },
}
feed('alphpabet<cr>alphanum<cr>')
@@ -474,7 +700,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*2
]],
- showmode = { { '-- INSERT --', 5, 12 } },
+ showmode = { { '-- INSERT --', 5, 11 } },
}
feed('<c-x>')
@@ -485,7 +711,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*2
]],
- showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5, 12 } },
+ showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5, 11 } },
}
feed('<c-p>')
@@ -501,7 +727,7 @@ describe('ui/ext_messages', function()
items = { { 'alphpabet', '', '', '' }, { 'alphanum', '', '', '' } },
pos = 1,
},
- showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } },
+ showmode = { { '-- Keyword Local completion (^N^P) ', 5, 11 }, { 'match 1 of 2', 6, 18 } },
}
-- echomsg and showmode don't overwrite each other, this is the same
@@ -519,11 +745,14 @@ describe('ui/ext_messages', function()
items = { { 'alphpabet', '', '', '' }, { 'alphanum', '', '', '' } },
pos = 1,
},
- messages = { {
- content = { { 'stuff' } },
- kind = 'echomsg',
- } },
- showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } },
+ messages = {
+ {
+ content = { { 'stuff' } },
+ history = true,
+ kind = 'echomsg',
+ },
+ },
+ showmode = { { '-- Keyword Local completion (^N^P) ', 5, 11 }, { 'match 1 of 2', 6, 18 } },
}
feed('<c-p>')
@@ -539,11 +768,14 @@ describe('ui/ext_messages', function()
items = { { 'alphpabet', '', '', '' }, { 'alphanum', '', '', '' } },
pos = 0,
},
- messages = { {
- content = { { 'stuff' } },
- kind = 'echomsg',
- } },
- showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 2 of 2', 6, 19 } },
+ messages = {
+ {
+ content = { { 'stuff' } },
+ history = true,
+ kind = 'echomsg',
+ },
+ },
+ showmode = { { '-- Keyword Local completion (^N^P) ', 5, 11 }, { 'match 2 of 2', 6, 18 } },
}
feed('<esc>:messages<cr>')
@@ -554,13 +786,15 @@ describe('ui/ext_messages', function()
alphpabe^t |
{1:~ }|*2
]],
+ cmdline = { { abort = false } },
msg_history = { {
content = { { 'stuff' } },
kind = 'echomsg',
} },
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -574,7 +808,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5, 12 } },
+ showmode = { { 'recording @q', 5, 11 } },
}
feed('i')
@@ -583,7 +817,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { '-- INSERT --recording @q', 5, 12 } },
+ showmode = { { '-- INSERT --recording @q', 5, 11 } },
}
feed('<esc>')
@@ -592,7 +826,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5, 12 } },
+ showmode = { { 'recording @q', 5, 11 } },
}
feed('q')
@@ -611,7 +845,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5, 12 } },
+ showmode = { { 'recording @q', 5, 11 } },
mode = 'normal',
}
@@ -621,7 +855,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5, 12 } },
+ showmode = { { 'recording @q', 5, 11 } },
mode = 'insert',
}
@@ -631,7 +865,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { 'recording @q', 5, 12 } },
+ showmode = { { 'recording @q', 5, 11 } },
mode = 'normal',
}
@@ -653,7 +887,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- ruler = { { '0,0-1 All', 9, 62 } },
+ ruler = { { '0,0-1 All', 9, 61 } },
})
command('hi clear MsgArea')
feed('i')
@@ -662,7 +896,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- showmode = { { '-- INSERT --', 5, 12 } },
+ showmode = { { '-- INSERT --', 5, 11 } },
ruler = { { '0,1 All' } },
}
feed('abcde<cr>12345<esc>')
@@ -700,7 +934,7 @@ describe('ui/ext_messages', function()
{17:123}45 |
{1:~ }|*3
]],
- showmode = { { '-- VISUAL BLOCK --', 5, 12 } },
+ showmode = { { '-- VISUAL BLOCK --', 5, 11 } },
showcmd = { { '2x3' } },
ruler = { { '1,3 All' } },
})
@@ -752,10 +986,14 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- messages = { {
- content = { { 'howdy' } },
- kind = 'echomsg',
- } },
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { 'howdy' } },
+ history = true,
+ kind = 'echomsg',
+ },
+ },
}
-- always test a message without kind. If this one gets promoted to a
@@ -769,6 +1007,7 @@ describe('ui/ext_messages', function()
messages = {
{
content = { { 'Type :qa and press <Enter> to exit Nvim' } },
+ history = true,
kind = '',
},
},
@@ -780,10 +1019,14 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- messages = { {
- content = { { 'bork', 9, 7 } },
- kind = 'echoerr',
- } },
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { 'bork', 9, 6 } },
+ history = true,
+ kind = 'echoerr',
+ },
+ },
}
feed(':echo "xyz"<cr>')
@@ -792,10 +1035,14 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
- messages = { {
- content = { { 'xyz' } },
- kind = 'echo',
- } },
+ cmdline = { { abort = false } },
+ messages = {
+ {
+ content = { { 'xyz' } },
+ history = false,
+ kind = 'echo',
+ },
+ },
}
feed(':call nosuchfunction()<cr>')
@@ -804,9 +1051,11 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } },
+ content = { { 'E117: Unknown function: nosuchfunction', 9, 6 } },
+ history = true,
kind = 'emsg',
},
},
@@ -818,15 +1067,17 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
msg_history = {
{ kind = 'echomsg', content = { { 'howdy' } } },
{ kind = '', content = { { 'Type :qa and press <Enter> to exit Nvim' } } },
- { kind = 'echoerr', content = { { 'bork', 9, 7 } } },
- { kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } } },
+ { kind = 'echoerr', content = { { 'bork', 9, 6 } } },
+ { kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9, 6 } } },
},
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -851,11 +1102,14 @@ describe('ui/ext_messages', function()
}
feed('<cr>')
- screen:expect([[
- ^ |
- {1:~ }|*3
- |
- ]])
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*3
+ |
+ ]],
+ cmdline = { { abort = false } },
+ })
eq(1, eval('&cmdheight'))
feed(':set cmdheight=0')
@@ -874,10 +1128,13 @@ describe('ui/ext_messages', function()
},
}
feed('<cr>')
- screen:expect([[
- ^ |
- {1:~ }|*4
- ]])
+ screen:expect({
+ grid = [[
+ ^ |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
eq(0, eval('&cmdheight'))
end)
@@ -888,6 +1145,7 @@ describe('ui/ext_messages', function()
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
content = {
@@ -899,9 +1157,10 @@ stack traceback:
[C]: in function 'error'
[string ":lua"]:1: in main chunk]],
9,
- 7,
+ 6,
},
},
+ history = true,
kind = 'lua_error',
},
},
@@ -916,11 +1175,13 @@ stack traceback:
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
content = {
- { "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9, 7 },
+ { "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9, 6 },
},
+ history = true,
kind = 'rpc_error',
},
},
@@ -940,6 +1201,7 @@ stack traceback:
feed(':map<cr>')
screen:expect {
+ cmdline = { { abort = false } },
messages = {
{
content = {
@@ -947,7 +1209,8 @@ stack traceback:
{ '*', 18, 1 },
{ ' k' },
},
- kind = '',
+ history = false,
+ kind = 'list_cmd',
},
},
}
@@ -964,10 +1227,13 @@ stack traceback:
^ |
{1:~ }|*6
]],
- messages = { {
- content = { { 'wildmenu wildmode' } },
- kind = '',
- } },
+ messages = {
+ {
+ content = { { 'wildmenu wildmode\n' } },
+ history = false,
+ kind = 'wildlist',
+ },
+ },
cmdline = {
{
firstc = ':',
@@ -983,51 +1249,94 @@ stack traceback:
feed('ihelllo<esc>')
feed('z=')
- screen:expect {
+ screen:expect({
grid = [[
- {100:helllo} |
- {1:~ }|*3
- {1:^~ }|
- ]],
+ {100:^helllo} |
+ {1:~ }|*4
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 0,
+ pos = 0,
+ prompt = 'Type number and <Enter> or click with the mouse (q or empty cancels): ',
+ },
+ },
messages = {
{
- content = {
- {
- 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ',
- },
- },
- kind = '',
+ content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\n' } },
+ history = false,
+ kind = 'list_cmd',
},
},
- }
+ })
feed('1')
- screen:expect {
+ screen:expect({
grid = [[
- {100:helllo} |
- {1:~ }|*3
- {1:^~ }|
- ]],
+ {100:^helllo} |
+ {1:~ }|*4
+ ]],
+ cmdline = {
+ {
+ content = { { '1' } },
+ hl_id = 0,
+ pos = 1,
+ prompt = 'Type number and <Enter> or click with the mouse (q or empty cancels): ',
+ },
+ },
messages = {
{
- content = {
- {
- 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\nType number and <Enter> or click with the mouse (q or empty cancels): ',
- },
- },
- kind = '',
+ content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Hullo"\n' } },
+ history = false,
+ kind = 'list_cmd',
},
- { content = { { '1' } }, kind = '' },
},
- }
+ })
feed('<cr>')
- screen:expect {
+ screen:expect({
grid = [[
- ^Hello |
- {1:~ }|*4
- ]],
- }
+ ^Hello |
+ {1:~ }|*4
+ ]],
+ cmdline = { { abort = false } },
+ })
+
+ async_meths.nvim_command("let g:n = inputlist(['input0', 'input1'])")
+ screen:expect({
+ grid = [[
+ ^Hello |
+ {1:~ }|*4
+ ]],
+ cmdline = {
+ {
+ content = { { '' } },
+ hl_id = 0,
+ pos = 0,
+ prompt = 'Type number and <Enter> or click with the mouse (q or empty cancels): ',
+ },
+ },
+ messages = {
+ {
+ content = { { 'input0\ninput1\n' } },
+ history = false,
+ kind = 'list_cmd',
+ },
+ },
+ })
+
+ feed('42<CR>')
+ screen:expect({
+ grid = [[
+ ^Hello |
+ {1:~ }|*4
+ ]],
+ cmdline = { {
+ abort = false,
+ } },
+ })
+ eq(42, eval('g:n'))
end)
it('supports nvim_echo messages with multiple attrs', function()
@@ -1043,7 +1352,8 @@ stack traceback:
]],
messages = {
{
- content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } },
+ content = { { 'wow, ', 10, 8 }, { 'such\n\nvery ', 9, 6 }, { 'color', 8, 12 } },
+ history = true,
kind = 'echomsg',
},
},
@@ -1055,8 +1365,13 @@ stack traceback:
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
- { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = '' },
+ {
+ content = { { '\n 1 %a "[No Name]" line 1' } },
+ kind = 'list_cmd',
+ history = false,
+ },
},
}
@@ -1066,15 +1381,17 @@ stack traceback:
^ |
{1:~ }|*4
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
msg_history = {
{
- content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } },
+ content = { { 'wow, ', 10, 8 }, { 'such\n\nvery ', 9, 6 }, { 'color', 8, 12 } },
kind = 'echomsg',
},
},
@@ -1093,7 +1410,11 @@ stack traceback:
command('write ' .. fname)
screen:expect({
messages = {
- { content = { { string.format('"%s" [New] 0L, 0B written', fname) } }, kind = '' },
+ {
+ content = { { string.format('"%s" [New] 0L, 0B written', fname) } },
+ kind = 'bufwrite',
+ history = true,
+ },
},
})
end)
@@ -1105,13 +1426,25 @@ stack traceback:
screen_showmode(...)
showmode = showmode + 1
end
+ local s1 = [[
+ ^ |
+ {1:~ }|*4
+ ]]
+ screen:expect(s1)
+ eq(showmode, 0)
+ feed('i')
screen:expect({
- grid = [[
- ^ |
- {1:~ }|*4
- ]],
+ grid = s1,
+ showmode = { { '-- INSERT --', 5, 11 } },
})
- eq(showmode, 1)
+ eq(showmode, 2)
+ command('set noshowmode')
+ feed('<Esc>')
+ screen:expect(s1)
+ eq(showmode, 3)
+ feed('i')
+ screen:expect_unchanged()
+ eq(showmode, 3)
end)
it('emits single message for multiline print())', function()
@@ -1120,6 +1453,7 @@ stack traceback:
messages = {
{
content = { { 'foo\nbar\nbaz' } },
+ history = true,
kind = 'lua_print',
},
},
@@ -1133,6 +1467,7 @@ stack traceback:
messages = {
{
content = { { '{\n foo = "bar"\n}' } },
+ history = true,
kind = 'lua_print',
},
},
@@ -1140,6 +1475,36 @@ stack traceback:
exec_lua([[vim.print({ foo = "bar" })]])
screen:expect_unchanged()
end)
+
+ it('ruler redraw does not crash due to double grid_line_start()', function()
+ exec_lua([[
+ local ns = vim.api.nvim_create_namespace('')
+ vim.ui_attach(ns, { ext_messages = true }, function(event, ...)
+ if event == 'msg_ruler' then
+ vim.api.nvim__redraw({ flush = true })
+ end
+ end)
+ vim.o.ruler = true
+ vim.o.laststatus = 0
+ ]])
+ feed('i')
+ n.assert_alive()
+ end)
+
+ it(':digraph contains newlines', function()
+ command('digraph')
+ screen:expect({
+ condition = function()
+ local nl = 0
+ eq('list_cmd', screen.messages[1].kind)
+ for _, chunk in ipairs(screen.messages[1].content) do
+ nl = nl + (chunk[2]:find('\n') and 1 or 0)
+ end
+ eq(682, nl)
+ screen.messages = {}
+ end,
+ })
+ end)
end)
describe('ui/builtin messages', function()
@@ -1719,7 +2084,7 @@ describe('ui/ext_messages', function()
{1:~ }type :help iccf{18:<Enter>} for information {1: }|
{1:~ }|*5
]]
- local showmode = { { '-- INSERT --', 5, 12 } }
+ local showmode = { { '-- INSERT --', 5, 11 } }
screen:expect(introscreen)
-- <c-l> (same as :mode) does _not_ clear intro message
@@ -1792,9 +2157,11 @@ describe('ui/ext_messages', function()
type :help iccf{18:<Enter>} for information |
|*5
]],
+ cmdline = { { abort = false } },
messages = {
{
- content = { { 'Press ENTER or type command to continue', 6, 19 } },
+ content = { { 'Press ENTER or type command to continue', 6, 18 } },
+ history = false,
kind = 'return_prompt',
},
},
@@ -1874,8 +2241,9 @@ describe('ui/ext_messages', function()
{1:~ }|*10
{3:[No Name] }|
]],
+ cmdline = { { abort = false } },
messages = {
- { content = { { ' cmdheight=0' } }, kind = '' },
+ { content = { { ' cmdheight=0' } }, kind = 'list_cmd', history = false },
},
})
@@ -1890,8 +2258,9 @@ describe('ui/ext_messages', function()
{1:~ }|*9
{3:[No Name] }|
]],
+ cmdline = { { abort = false } },
messages = {
- { content = { { ' laststatus=3' } }, kind = '' },
+ { content = { { ' laststatus=3' } }, kind = 'list_cmd', history = false },
},
})
@@ -1910,8 +2279,9 @@ describe('ui/ext_messages', function()
{1:~ }|*10
{3:[No Name] }|
]],
+ cmdline = { { abort = false } },
messages = {
- { content = { { ' cmdheight=0' } }, kind = '' },
+ { content = { { ' cmdheight=0' } }, kind = 'list_cmd', history = false },
},
})
end)
@@ -2015,7 +2385,7 @@ describe('ui/msg_puts_printf', function()
)
cmd = cmd .. '"' .. nvim_prog .. '" -u NONE -i NONE -Es -V1'
- command([[call termopen(']] .. cmd .. [[')]])
+ command([[call jobstart(']] .. cmd .. [[',{'term':v:true})]])
screen:expect([[
^Exモードに入ります。ノー |
マルモードに戻るには "vis|
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index 8c6a284cd6..01f4dda227 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -94,6 +94,46 @@ describe('ui mode_change event', function()
}
end)
+ -- oldtest: Test_mouse_shape_indent_norm_with_gq()
+ it('is restored to Normal mode after "gq" indents using :normal #12309', function()
+ screen:try_resize(60, 6)
+ n.exec([[
+ func Indent()
+ exe "normal! \<Ignore>"
+ return 0
+ endfunc
+
+ setlocal indentexpr=Indent()
+ call setline(1, [repeat('a', 80), repeat('b', 80)])
+ ]])
+
+ feed('ggVG')
+ screen:expect {
+ grid = [[
+ {17:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {17:aaaaaaaaaaaaaaaaaaaa} |
+ ^b{17:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}|
+ {17:bbbbbbbbbbbbbbbbbbbb} |
+ {1:~ }|
+ {5:-- VISUAL LINE --} |
+ ]],
+ mode = 'visual',
+ }
+
+ feed('gq')
+ screen:expect {
+ grid = [[
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ aaaaaaaaaaaaaaaaaaaa |
+ ^bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ bbbbbbbbbbbbbbbbbbbb |
+ {1:~ }|
+ |
+ ]],
+ mode = 'normal',
+ }
+ end)
+
it('works in insert mode', function()
feed('i')
screen:expect {
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 3afda0c4af..cac7174cb6 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -1094,7 +1094,7 @@ describe('ext_multigrid', function()
end)
it('supports mouse', function()
- command('autocmd! nvim_popupmenu') -- Delete the default MenuPopup event handler.
+ command('autocmd! nvim.popupmenu') -- Delete the default MenuPopup event handler.
insert('some text\nto be clicked')
screen:expect{grid=[[
## grid 1
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index b5a09d814c..37e0e1344b 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -34,7 +34,7 @@ describe('shell command :!', function()
n.nvim_set .. ' notermguicolors',
})
screen:expect([[
- {1: } |
+ ^ |
{4:~ }|*4
|
{3:-- TERMINAL --} |
@@ -78,7 +78,7 @@ describe('shell command :!', function()
29999: foo |
30000: foo |
|
- {10:Press ENTER or type command to continue}{1: } |
+ {10:Press ENTER or type command to continue}^ |
{3:-- TERMINAL --} |
]],
{
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 8fe8975b4a..4c5b1d2bd2 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -841,7 +841,7 @@ describe('ui/ext_popupmenu', function()
aunmenu PopUp
" Delete the default MenuPopup event handler.
- autocmd! nvim_popupmenu
+ 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>
@@ -1162,6 +1162,8 @@ describe('builtin popupmenu', function()
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search
[8] = { foreground = Screen.colors.Red },
+ [9] = { foreground = Screen.colors.Yellow, background = Screen.colors.Green },
+ [10] = { foreground = Screen.colors.White, background = Screen.colors.Green },
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
@@ -1542,6 +1544,81 @@ describe('builtin popupmenu', function()
end)
if not multigrid then
+ describe('popup and preview window do not overlap', function()
+ before_each(function()
+ screen:try_resize(53, 20)
+ end)
+
+ -- oldtest: Test_popup_and_previewwindow_dump_pedit()
+ it('with :pedit', function()
+ exec([[
+ set previewheight=9
+ silent! pedit
+ call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
+ exec "norm! G\<C-E>\<C-E>"
+ ]])
+ feed('o')
+ n.poke_eventloop()
+ feed('<C-X><C-N>')
+ screen:expect([[
+ ab0 |
+ ab1 |
+ ab2 |
+ ab3 |
+ ab4 |
+ ab5 |
+ ab6 |
+ ab7 |
+ ab8 |
+ {s:ab0 }{c: }{3:ew][+] }|
+ {n:ab1 }{c: } |
+ {n:ab2 }{c: } |
+ {n:ab3 }{c: } |
+ {n:ab4 }{s: } |
+ {n:ab5 }{s: } |
+ {n:ab6 }{s: } |
+ ab0^ |
+ {1:~ }|
+ {4:[No Name] [+] }|
+ {2:-- Keyword Local completion (^N^P) }{5:match 1 of 10} |
+ ]])
+ end)
+
+ -- oldtest: Test_popup_and_previewwindow_dump_pbuffer()
+ it('with :pbuffer', function()
+ exec([[
+ set previewheight=9
+ silent! pbuffer
+ call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
+ exec "norm! G\<C-E>\<C-E>\<C-E>"
+ ]])
+ feed('o')
+ n.poke_eventloop()
+ feed('<C-X><C-N>')
+ screen:expect([[
+ ab0 |
+ ab1 |
+ ab2 |
+ ab3 |
+ ab4 |
+ ab5 |
+ ab6 |
+ ab7 |
+ ab8 |
+ {s:ab0 }{c: }{3:ew][+] }|
+ {n:ab1 }{c: } |
+ {n:ab2 }{c: } |
+ {n:ab3 }{s: } |
+ {n:ab4 }{s: } |
+ {n:ab5 }{s: } |
+ ab0^ |
+ {1:~ }|*2
+ {4:[No Name] [+] }|
+ {2:-- Keyword Local completion (^N^P) }{5:match 1 of 10} |
+ ]])
+ end)
+ end)
+
-- oldtest: Test_pum_with_preview_win()
it('preview window opened during completion', function()
exec([[
@@ -1603,7 +1680,7 @@ describe('builtin popupmenu', function()
end)
end
- describe('floating window preview #popup', function()
+ describe('floating window preview popup', function()
it('pum popup preview', function()
--row must > 10
screen:try_resize(40, 11)
@@ -1616,14 +1693,29 @@ describe('builtin popupmenu', function()
endfunc
set omnifunc=Omni_test
set completeopt=menu,popup
-
funct Set_info()
let comp_info = complete_info()
if comp_info['selected'] == 2
call nvim__complete_set(comp_info['selected'], {"info": "3info"})
endif
endfunc
- autocmd CompleteChanged * call Set_info()
+ funct TsHl()
+ let comp_info = complete_info()
+ if get(comp_info, 'previewbufnr', 0) > 0
+ call v:lua.vim.treesitter.start(comp_info['preview_bufnr'], 'markdown')
+ endif
+ if comp_info['selected'] == 0
+ call nvim__complete_set(comp_info['selected'], {"info": "```lua\nfunction test()\n print('foo')\nend\n```"})
+ endif
+ endfunc
+ augroup Group
+ au!
+ autocmd CompleteChanged * :call Set_info()
+ augroup END
+ funct TestTs()
+ autocmd! Group
+ autocmd CompleteChanged * call TsHl()
+ endfunc
]])
feed('Gi<C-x><C-o>')
--floating preview in right
@@ -1684,25 +1776,26 @@ describe('builtin popupmenu', function()
}
end
- -- info window position should be adjusted when new leader add
- feed('<C-P>o')
+ -- delete one character make the pum width smaller than before
+ -- info window position should be adjusted when popupmenu width changed
+ feed('<BS>')
if multigrid then
- screen:expect {
+ screen:expect({
grid = [[
- ## grid 1
- [2:----------------------------------------]|*10
- [3:----------------------------------------]|
- ## grid 2
- o^ |
- {1:~ }|*9
- ## grid 3
- {2:-- }{8:Back at original} |
- ## grid 4
- {n:1info}|
- {n: }|
- ## grid 5
- {n:one }|
- ]],
+ ## grid 1
+ [2:----------------------------------------]|*10
+ [3:----------------------------------------]|
+ ## grid 2
+ on^ |
+ {1:~ }|*9
+ ## grid 3
+ {2:-- }{5:match 1 of 3} |
+ ## grid 4
+ {n:1info}|
+ {n: }|
+ ## grid 5
+ {s:one }|
+ ]],
float_pos = {
[5] = { -1, 'NW', 2, 1, 0, false, 100 },
[4] = { 1001, 'NW', 1, 1, 15, false, 50 },
@@ -1713,7 +1806,7 @@ describe('builtin popupmenu', function()
topline = 0,
botline = 2,
curline = 0,
- curcol = 1,
+ curcol = 2,
linecount = 1,
sum_scroll_delta = 0,
},
@@ -1727,22 +1820,88 @@ describe('builtin popupmenu', function()
sum_scroll_delta = 0,
},
},
- }
+ win_viewport_margins = {
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000,
+ },
+ [4] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1001,
+ },
+ },
+ })
else
- screen:expect {
+ screen:expect({
grid = [[
- o^ |
- {n:one 1info}{1: }|
- {1:~ }{n: }{1: }|
- {1:~ }|*7
- {2:-- }{8:Back at original} |
- ]],
- }
+ on^ |
+ {s:one }{n:1info}{1: }|
+ {1:~ }{n: }{1: }|
+ {1:~ }|*7
+ {2:-- }{5:match 1 of 3} |
+ ]],
+ })
+ end
+
+ -- when back to original the preview float should be closed.
+ feed('<C-P>')
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*10
+ [3:----------------------------------------]|
+ ## grid 2
+ on^ |
+ {1:~ }|*9
+ ## grid 3
+ {2:-- }{8:Back at original} |
+ ## grid 5
+ {n:one }|
+ ]],
+ float_pos = {
+ [5] = { -1, 'NW', 2, 1, 0, false, 100 },
+ },
+ win_viewport = {
+ [2] = {
+ win = 1000,
+ topline = 0,
+ botline = 2,
+ curline = 0,
+ curcol = 2,
+ linecount = 1,
+ sum_scroll_delta = 0,
+ },
+ },
+ win_viewport_margins = {
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000,
+ },
+ },
+ })
+ else
+ screen:expect({
+ grid = [[
+ on^ |
+ {n:one }{1: }|
+ {1:~ }|*8
+ {2:-- }{8:Back at original} |
+ ]],
+ })
end
-- test nvim__complete_set_info
- feed('<ESC>cc<C-X><C-O><C-N><C-N>')
- vim.uv.sleep(10)
+ feed('<ESC>S<C-X><C-O><C-N><C-N>')
if multigrid then
screen:expect {
grid = [[
@@ -1758,13 +1917,13 @@ describe('builtin popupmenu', function()
{n:one }|
{n:two }|
{s:looooooooooooooong }|
- ## grid 6
+ ## grid 7
{n:3info}|
{n: }|
]],
float_pos = {
[5] = { -1, 'NW', 2, 1, 0, false, 100 },
- [6] = { 1002, 'NW', 1, 1, 19, false, 50 },
+ [7] = { 1003, 'NW', 1, 1, 19, false, 50 },
},
win_viewport = {
[2] = {
@@ -1776,8 +1935,8 @@ describe('builtin popupmenu', function()
linecount = 1,
sum_scroll_delta = 0,
},
- [6] = {
- win = 1002,
+ [7] = {
+ win = 1003,
topline = 0,
botline = 2,
curline = 0,
@@ -1819,12 +1978,12 @@ describe('builtin popupmenu', function()
{s: one }|
{n: two }|
{n: looooooooooooooong }|
- ## grid 7
+ ## grid 8
{n:1info}|
{n: }|
]],
float_pos = {
- [7] = { 1003, 'NW', 1, 1, 14, false, 50 },
+ [8] = { 1004, 'NW', 1, 1, 14, false, 50 },
[5] = { -1, 'NW', 2, 1, 19, false, 100 },
},
win_viewport = {
@@ -1837,8 +1996,8 @@ describe('builtin popupmenu', function()
linecount = 1,
sum_scroll_delta = 0,
},
- [7] = {
- win = 1003,
+ [8] = {
+ win = 1004,
topline = 0,
botline = 2,
curline = 0,
@@ -1860,6 +2019,90 @@ describe('builtin popupmenu', function()
]],
}
end
+ feed('<C-E><Esc>')
+
+ -- works when scroll with treesitter highlight
+ command('call TestTs()')
+ feed('S<C-x><C-o>')
+ if multigrid then
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [2:----------------------------------------]|*10
+ [3:----------------------------------------]|
+ ## grid 2
+ one^ |
+ {1:~ }|*9
+ ## grid 3
+ {2:-- }{5:match 1 of 3} |
+ ## grid 5
+ {s:one }|
+ {n:two }|
+ {n:looooooooooooooong }|
+ ## grid 9
+ {n:```lua }|
+ {n:function test()}|
+ {n: print('foo') }|
+ {n:end }|
+ {n:``` }|
+ {n: }|
+ ]],
+ float_pos = {
+ [5] = { -1, 'NW', 2, 1, 0, false, 100 },
+ [9] = { 1005, 'NW', 1, 1, 19, false, 50 },
+ },
+ win_viewport = {
+ [2] = {
+ win = 1000,
+ topline = 0,
+ botline = 2,
+ curline = 0,
+ curcol = 3,
+ linecount = 1,
+ sum_scroll_delta = 0,
+ },
+ [9] = {
+ win = 1005,
+ topline = 0,
+ botline = 6,
+ curline = 0,
+ curcol = 0,
+ linecount = 5,
+ sum_scroll_delta = 0,
+ },
+ },
+ win_viewport_margins = {
+ [2] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1000,
+ },
+ [9] = {
+ bottom = 0,
+ left = 0,
+ right = 0,
+ top = 0,
+ win = 1005,
+ },
+ },
+ })
+ else
+ screen:expect({
+ grid = [[
+ one^ |
+ {s:one }{n:```lua }{1: }|
+ {n:two function test()}{1: }|
+ {n:looooooooooooooong print('foo') }{1: }|
+ {1:~ }{n:end }{1: }|
+ {1:~ }{n:``` }{1: }|
+ {1:~ }{n: }{1: }|
+ {1:~ }|*3
+ {2:-- }{5:match 1 of 3} |
+ ]],
+ })
+ end
end)
end)
@@ -3846,7 +4089,7 @@ describe('builtin popupmenu', function()
set mouse=a mousemodel=popup
" Delete the default MenuPopup event handler.
- autocmd! nvim_popupmenu
+ autocmd! nvim.popupmenu
aunmenu PopUp
menu PopUp.foo :let g:menustr = 'foo'<CR>
menu PopUp.bar :let g:menustr = 'bar'<CR>
@@ -4703,7 +4946,7 @@ describe('builtin popupmenu', function()
it(':popup command', function()
exec([[
" Delete the default MenuPopup event handler.
- autocmd! nvim_popupmenu
+ autocmd! nvim.popupmenu
func ChangeMenu()
aunmenu PopUp.&Paste
@@ -4863,7 +5106,7 @@ describe('builtin popupmenu', function()
exec([[
set mousemodel=popup_setpos
" Delete the default MenuPopup event handler.
- autocmd! nvim_popupmenu
+ autocmd! nvim.popupmenu
aunmenu *
source $VIMRUNTIME/menu.vim
call setline(1, join(range(20)))
@@ -5172,6 +5415,45 @@ describe('builtin popupmenu', function()
feed('<C-E><Esc>')
end)
+ -- oldtest: Test_pum_highlights_match_with_abbr()
+ it('can highlight matched text with abbr', function()
+ exec([[
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'foobar', 'abbr': "foobar\t\t!" },
+ \ { 'word': 'foobaz', 'abbr': "foobaz\t\t!" },
+ \]}
+ endfunc
+
+ set omnifunc=Omni_test
+ set completeopt=menuone,noinsert
+ hi PmenuMatchSel guifg=Blue guibg=Grey
+ hi PmenuMatch guifg=Blue guibg=Plum1
+ ]])
+ feed('i<C-X><C-O>')
+ screen:expect([[
+ ^ |
+ {s:foobar ! }{1: }|
+ {n:foobaz ! }{1: }|
+ {1:~ }|*16
+ {2:-- }{5:match 1 of 2} |
+ ]])
+ feed('foo')
+ screen:expect([[
+ foo^ |
+ {ms:foo}{s:bar ! }{1: }|
+ {mn:foo}{n:baz ! }{1: }|
+ {1:~ }|*16
+ {2:-- }{5:match 1 of 2} |
+ ]])
+
+ feed('<C-E><Esc>')
+ end)
+
-- oldtest: Test_pum_user_abbr_hlgroup()
it('custom abbr_hlgroup override', function()
exec([[
@@ -5419,6 +5701,240 @@ describe('builtin popupmenu', function()
]])
feed('<C-E><ESC>')
end)
+
+ -- oldtest: Test_pum_matchins_highlight()
+ it('with ComplMatchIns highlight', function()
+ exec([[
+ let g:change = 0
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ if g:change == 0
+ return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ endif
+ return [#{word: "foo", info: "info"}, #{word: "bar"}, #{word: "你好"}]
+ endfunc
+ set omnifunc=Omni_test
+ hi ComplMatchIns guifg=red
+ ]])
+
+ feed('Sαβγ <C-X><C-O>')
+ screen:expect([[
+ αβγ {8:foo}^ |
+ {1:~ }{s: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+
+ feed('Sαβγ <C-X><C-O><C-N>')
+ screen:expect([[
+ αβγ {8:bar}^ |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{s: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 2 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+
+ feed('Sαβγ <C-X><C-O><C-N><C-N>')
+ screen:expect([[
+ αβγ {8:你好}^ |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{s: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 3 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+
+ -- restore after accept
+ feed('Sαβγ <C-X><C-O><C-Y>')
+ screen:expect([[
+ αβγ foo^ |
+ {1:~ }|*18
+ {2:-- INSERT --} |
+ ]])
+ feed('<Esc>')
+
+ -- restore after cancel completion
+ feed('Sαβγ <C-X><C-O><Space>')
+ screen:expect([[
+ αβγ foo ^ |
+ {1:~ }|*18
+ {2:-- INSERT --} |
+ ]])
+ feed('<Esc>')
+
+ -- text after the inserted text shouldn't be highlighted
+ feed('0ea <C-X><C-O>')
+ screen:expect([[
+ αβγ {8:foo}^ foo |
+ {1:~ }{s: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-P>')
+ screen:expect([[
+ αβγ ^ foo |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{8:Back at original} |
+ ]])
+ feed('<C-P>')
+ screen:expect([[
+ αβγ {8:你好}^ foo |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{s: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 3 of 3} |
+ ]])
+ feed('<C-Y>')
+ screen:expect([[
+ αβγ 你好^ foo |
+ {1:~ }|*18
+ {2:-- INSERT --} |
+ ]])
+ feed('<Esc>')
+
+ feed(':let g:change=1<CR>S<C-X><C-O>')
+ screen:expect([[
+ info |
+ {1:~ }|*2
+ {3:[Scratch] [Preview] }|
+ {8:foo}^ |
+ {s:foo }{1: }|
+ {n:bar }{1: }|
+ {n:你好 }{1: }|
+ {1:~ }|*10
+ {4:[No Name] [+] }|
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<Esc>')
+ end)
+
+ -- oldtest: Test_pum_matchins_highlight_combine()
+ it('with ComplMatchIns, Normal and CursorLine highlights', function()
+ exec([[
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ endfunc
+ set omnifunc=Omni_test
+ hi Normal guibg=blue
+ hi CursorLine guibg=green guifg=white
+ set cursorline
+ call setline(1, 'aaa bbb')
+ ]])
+
+ -- when ComplMatchIns is not set, CursorLine applies normally
+ feed('0ea <C-X><C-O>')
+ screen:expect([[
+ {10:aaa foo^ bbb }|
+ {1:~ }{s: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E>')
+ screen:expect([[
+ {10:aaa ^ bbb }|
+ {1:~ }|*18
+ {2:-- INSERT --} |
+ ]])
+ feed('<BS><Esc>')
+
+ -- when ComplMatchIns is set, it is applied over CursorLine
+ command('hi ComplMatchIns guifg=Yellow')
+ feed('0ea <C-X><C-O>')
+ screen:expect([[
+ {10:aaa }{9:foo}{10:^ bbb }|
+ {1:~ }{s: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-P>')
+ screen:expect([[
+ {10:aaa ^ bbb }|
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{8:Back at original} |
+ ]])
+ feed('<C-P>')
+ screen:expect([[
+ {10:aaa }{9:你好}{10:^ bbb }|
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{s: 你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{5:match 3 of 3} |
+ ]])
+ feed('<C-E>')
+ screen:expect([[
+ {10:aaa ^ bbb }|
+ {1:~ }|*18
+ {2:-- INSERT --} |
+ ]])
+ feed('<Esc>')
+
+ -- Does not highlight the compl leader
+ command('set cot+=menuone,noselect')
+ feed('S<C-X><C-O>')
+ local pum_start = [[
+ {10:^ }|
+ {n:foo }{1: }|
+ {n:bar }{1: }|
+ {n:你好 }{1: }|
+ {1:~ }|*15
+ {2:-- }{8:Back at original} |
+ ]]
+ screen:expect(pum_start)
+ feed('f<C-N>')
+ screen:expect([[
+ {10:f}{9:oo}{10:^ }|
+ {s:foo }{1: }|
+ {1:~ }|*17
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><ESC>')
+
+ command('set cot+=fuzzy')
+ feed('S<C-X><C-O>')
+ screen:expect(pum_start)
+ feed('f<C-N>')
+ screen:expect([[
+ {10:foo^ }|
+ {s:foo }{1: }|
+ {1:~ }|*17
+ {2:-- }{5:match 1 of 3} |
+ ]])
+ feed('<C-E><Esc>')
+
+ command('set cot-=fuzzy')
+ feed('Sf<C-N>')
+ screen:expect([[
+ {10:f^ }|
+ {1:~ }|*18
+ {2:-- }{6:Pattern not found} |
+ ]])
+ feed('<C-E><Esc>')
+ end)
end
end
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 8e15e6c35f..6a8e7df6a0 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -37,10 +37,10 @@
-- Tests will often share a group of extra attribute sets to expect(). Those can be
-- defined at the beginning of a test:
--
--- screen:add_extra_attr_ids {
+-- screen:add_extra_attr_ids({
-- [100] = { background = Screen.colors.Plum1, underline = true },
-- [101] = { background = Screen.colors.Red1, bold = true, underline = true },
--- }
+-- })
--
-- To help write screen tests, see Screen:snapshot_util().
-- To debug screen tests, see Screen:redraw_debug().
@@ -79,6 +79,7 @@ end
--- @field win_position table<integer,table<string,integer>>
--- @field float_pos table<integer,table>
--- @field cmdline table<integer,table>
+--- @field cmdline_hide_level integer?
--- @field cmdline_block table[]
--- @field hl_groups table<string,integer>
--- @field messages table<integer,table>
@@ -454,7 +455,7 @@ end
--- screen:expect(grid, [attr_ids])
--- screen:expect(condition)
--- or keyword args (supports more options):
---- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end}
+--- screen:expect({ grid=[[...]], cmdline={...}, condition=function() ... end })
---
--- @param expected string|function|test.function.ui.screen.Expect
--- @param attr_ids? table<integer,table<string,any>>
@@ -654,6 +655,12 @@ screen:redraw_debug() to show all intermediate screen states.]]
end
end
+ -- Only test the abort state of a cmdline level once.
+ if self.cmdline_hide_level ~= nil then
+ self.cmdline[self.cmdline_hide_level] = nil
+ self.cmdline_hide_level = nil
+ end
+
if expected.hl_groups ~= nil then
for name, id in pairs(expected.hl_groups) do
local expected_hl = attr_state.ids[id]
@@ -967,11 +974,11 @@ function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
self._cursor_style_enabled = cursor_style_enabled
for _, item in pairs(mode_info) do
-- attr IDs are not stable, but their value should be
- if item.attr_id ~= nil then
+ if item.attr_id ~= nil and self._attr_table[item.attr_id] ~= nil then
item.attr = self._attr_table[item.attr_id][1]
item.attr_id = nil
end
- if item.attr_id_lm ~= nil then
+ if item.attr_id_lm ~= nil and self._attr_table[item.attr_id_lm] ~= nil then
item.attr_lm = self._attr_table[item.attr_id_lm][1]
item.attr_id_lm = nil
end
@@ -1296,7 +1303,7 @@ function Screen:_handle_popupmenu_hide()
self.popupmenu = nil
end
-function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level)
+function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level, hl_id)
if firstc == '' then
firstc = nil
end
@@ -1320,11 +1327,13 @@ function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level
firstc = firstc,
prompt = prompt,
indent = indent,
+ hl_id = prompt and hl_id,
}
end
-function Screen:_handle_cmdline_hide(level)
- self.cmdline[level] = nil
+function Screen:_handle_cmdline_hide(level, abort)
+ self.cmdline[level] = { abort = abort }
+ self.cmdline_hide_level = level
end
function Screen:_handle_cmdline_special_char(char, shift, level)
@@ -1360,12 +1369,12 @@ function Screen:_handle_wildmenu_hide()
self.wildmenu_items, self.wildmenu_pos = nil, nil
end
-function Screen:_handle_msg_show(kind, chunks, replace_last)
+function Screen:_handle_msg_show(kind, chunks, replace_last, history)
local pos = #self.messages
if not replace_last or pos == 0 then
pos = pos + 1
end
- self.messages[pos] = { kind = kind, content = chunks }
+ self.messages[pos] = { kind = kind, content = chunks, history = history }
end
function Screen:_handle_msg_clear()
@@ -1468,7 +1477,9 @@ function Screen:_extstate_repr(attr_state)
local cmdline = {}
for i, entry in pairs(self.cmdline) do
entry = shallowcopy(entry)
- entry.content = self:_chunks_repr(entry.content, attr_state)
+ if entry.content ~= nil then
+ entry.content = self:_chunks_repr(entry.content, attr_state)
+ end
cmdline[i] = entry
end
@@ -1479,7 +1490,11 @@ function Screen:_extstate_repr(attr_state)
local messages = {}
for i, entry in ipairs(self.messages) do
- messages[i] = { kind = entry.kind, content = self:_chunks_repr(entry.content, attr_state) }
+ messages[i] = {
+ kind = entry.kind,
+ content = self:_chunks_repr(entry.content, attr_state),
+ history = entry.history,
+ }
end
local msg_history = {}
@@ -1713,21 +1728,24 @@ function Screen:_print_snapshot()
end
end
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')
+ attrstr = ('screen:' .. fn_name .. '({\n' .. table.concat(attrstrs, '\n') .. '\n})\n\n')
end
- local result = ('%sscreen:expect({\n grid = [[\n %s\n ]]'):format(
- attrstr,
- kwargs.grid:gsub('\n', '\n ')
- )
+ local extstr = ''
for _, k in ipairs(ext_keys) do
if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then
- result = result .. ', ' .. k .. '=' .. fmt_ext_state(k, ext_state[k])
+ extstr = extstr .. '\n ' .. k .. ' = ' .. fmt_ext_state(k, ext_state[k]) .. ','
end
end
- result = result .. '\n})'
- return result
+ return ('%sscreen:expect(%s%s%s%s%s'):format(
+ attrstr,
+ #extstr > 0 and '{\n grid = [[\n ' or '[[\n',
+ #extstr > 0 and kwargs.grid:gsub('\n', '\n ') or kwargs.grid,
+ #extstr > 0 and '\n ]],' or '\n]]',
+ extstr,
+ #extstr > 0 and '\n})' or ')'
+ )
end
function Screen:print_snapshot()
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index f39e9ecc33..295c40b9b6 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -2,7 +2,7 @@ local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
-local spawn, set_session, clear = n.spawn, n.set_session, n.clear
+local set_session, clear = n.set_session, n.clear
local feed, command = n.feed, n.command
local exec = n.exec
local insert = n.insert
@@ -26,7 +26,7 @@ describe('screen', function()
}
before_each(function()
- local screen_nvim = spawn(nvim_argv)
+ local screen_nvim = n.new_session(false, { args = nvim_argv, merge = false })
set_session(screen_nvim)
screen = Screen.new()
end)
@@ -645,6 +645,59 @@ local function screen_tests(linegrid)
|
]])
end)
+
+ it('clamps &cmdheight for current tabpage', function()
+ command('set cmdheight=10 laststatus=2')
+ screen:expect([[
+ ^ |
+ {0:~ }|*2
+ {1:[No Name] }|
+ |*10
+ ]])
+ screen:try_resize(53, 8)
+ screen:expect([[
+ ^ |
+ {1:[No Name] }|
+ |*6
+ ]])
+ eq(6, api.nvim_get_option_value('cmdheight', {}))
+ end)
+
+ it('clamps &cmdheight for another tabpage #31380', function()
+ command('tabnew')
+ command('set cmdheight=9 laststatus=2')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|*2
+ {1:[No Name] }|
+ |*9
+ ]])
+ command('tabprev')
+ screen:expect([[
+ {2: [No Name] }{4: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|*10
+ {1:[No Name] }|
+ |
+ ]])
+ screen:try_resize(53, 8)
+ screen:expect([[
+ {2: [No Name] }{4: [No Name] }{3: }{4:X}|
+ ^ |
+ {0:~ }|*4
+ {1:[No Name] }|
+ |
+ ]])
+ command('tabnext')
+ screen:expect([[
+ {4: [No Name] }{2: [No Name] }{3: }{4:X}|
+ ^ |
+ {1:[No Name] }|
+ |*5
+ ]])
+ eq(5, api.nvim_get_option_value('cmdheight', {}))
+ end)
end)
describe('press enter', function()
@@ -713,7 +766,7 @@ describe('Screen default colors', function()
'colorscheme vim',
'--embed',
}
- local screen_nvim = spawn(nvim_argv)
+ local screen_nvim = n.new_session(false, { args = nvim_argv, merge = false })
set_session(screen_nvim)
screen = Screen.new(53, 14, { rgb = true, ext_termcolors = termcolors or nil })
end
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 7874c04c39..ff03d86979 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -14,6 +14,10 @@ describe('Signs', function()
screen = Screen.new()
screen:add_extra_attr_ids {
[100] = { bold = true, foreground = Screen.colors.Magenta1 },
+ [101] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Yellow1 },
+ [102] = { foreground = Screen.colors.Brown, background = Screen.colors.Yellow },
+ [103] = { background = Screen.colors.Yellow, reverse = true },
+ [104] = { reverse = true, foreground = Screen.colors.Grey100, background = Screen.colors.Red },
}
end)
@@ -27,8 +31,8 @@ describe('Signs', function()
sign place 2 line=2 name=piet2 buffer=1
]])
screen:expect([[
- {10:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a |
- {10:𠜎̀́̂̃̄̅}b |
+ {101:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a |
+ {101:𠜎̀́̂̃̄̅}b |
{7: }^ |
{1:~ }|*10
|
@@ -45,9 +49,9 @@ describe('Signs', function()
sign place 3 line=1 name=pietx buffer=1
]])
screen:expect([[
- {10:>!}a |
+ {101:>!}a |
{7: }b |
- {10:>>}c |
+ {101:>>}c |
{7: }^ |
{1:~ }|*9
|
@@ -80,13 +84,13 @@ describe('Signs', function()
]])
screen:expect([[
{7: }{21:^a }|
- {10:>>}b |
+ {101:>>}b |
{7: }c |
{7: } |
{1:~ }|*2
{3:[No Name] [+] }|
{7: }{21:a }|
- {10:>>}b |
+ {101:>>}b |
{7: }c |
{7: } |
{1:~ }|
@@ -110,10 +114,10 @@ describe('Signs', function()
sign place 6 line=4 name=pietxx buffer=1
]])
screen:expect([[
- {10:>>}{8: 1 }a |
+ {101:>>}{8: 1 }a |
{7: }{8: 2 }{9:b }|
{7: }{13: 3 }c |
- {10:>>}{13: 4 }{9:^ }|
+ {101:>>}{13: 4 }{9:^ }|
{1:~ }|*9
|
]])
@@ -132,33 +136,33 @@ describe('Signs', function()
set cursorline
]])
screen:expect([[
- {10:>>}a |
- {10:>>}b |
+ {101:>>}a |
+ {101:>>}b |
{9:>>}{21:^c }|
{1:~ }|*10
|
]])
feed('k')
screen:expect([[
- {10:>>}a |
+ {101:>>}a |
{9:>>}{21:^b }|
- {10:>>}c |
+ {101:>>}c |
{1:~ }|*10
|
]])
exec('set nocursorline')
screen:expect([[
- {10:>>}a |
- {10:>>}^b |
- {10:>>}c |
+ {101:>>}a |
+ {101:>>}^b |
+ {101:>>}c |
{1:~ }|*10
|
]])
exec('set cursorline cursorlineopt=line')
screen:expect([[
- {10:>>}a |
- {10:>>}{21:^b }|
- {10:>>}c |
+ {101:>>}a |
+ {101:>>}{21:^b }|
+ {101:>>}c |
{1:~ }|*10
|
]])
@@ -166,13 +170,14 @@ describe('Signs', function()
exec('hi! link SignColumn IncSearch')
feed('Go<esc>2G')
screen:expect([[
- {10:>>}a |
- {9:>>}^b |
- {10:>>}c |
+ {103:>>}a |
+ {104:>>}^b |
+ {103:>>}c |
{2: } |
{1:~ }|*9
|
]])
+
-- Check that 'statuscolumn' cursorline/signcolumn highlights are the same (#21726)
exec('set statuscolumn=%s')
screen:expect_unchanged()
@@ -196,7 +201,7 @@ describe('Signs', function()
screen:expect([[
{7: }{8: 1 }a |
{7: }{8: 2 }b |
- WW{10:>>}{8: 3 }c |
+ {7:WW}{101:>>}{8: 3 }c |
{7: }{8: 4 }^ |
{1:~ }|*9
|
@@ -209,9 +214,9 @@ describe('Signs', function()
sign place 3 line=2 name=pietError buffer=1
]])
screen:expect([[
- {9:XX}{10:>>}{8: 1 }a |
- {10:>>}{9:XX}{8: 2 }b |
- WW{10:>>}{8: 3 }c |
+ {9:XX}{101:>>}{8: 1 }a |
+ {101:>>}{9:XX}{8: 2 }b |
+ {7:WW}{101:>>}{8: 3 }c |
{7: }{8: 4 }^ |
{1:~ }|*9
|
@@ -220,8 +225,8 @@ describe('Signs', function()
exec('set signcolumn=yes:1')
screen:expect([[
{9:XX}{8: 1 }a |
- {10:>>}{8: 2 }b |
- WW{8: 3 }c |
+ {101:>>}{8: 2 }b |
+ {7:WW}{8: 3 }c |
{7: }{8: 4 }^ |
{1:~ }|*9
|
@@ -229,9 +234,9 @@ describe('Signs', function()
-- "auto:3" accommodates all the signs we defined so far.
exec('set signcolumn=auto:3')
local s3 = [[
- {9:XX}{10:>>}{7: }{8: 1 }a |
- {10:>>}{9:XX}{7: }{8: 2 }b |
- WW{10:>>}{9:XX}{8: 3 }c |
+ {9:XX}{101:>>}{7: }{8: 1 }a |
+ {101:>>}{9:XX}{7: }{8: 2 }b |
+ {7:WW}{101:>>}{9:XX}{8: 3 }c |
{7: }{8: 4 }^ |
{1:~ }|*9
|
@@ -240,9 +245,9 @@ describe('Signs', function()
-- Check "yes:9".
exec('set signcolumn=yes:9')
screen:expect([[
- {9:XX}{10:>>}{7: }{8: 1 }a |
- {10:>>}{9:XX}{7: }{8: 2 }b |
- WW{10:>>}{9:XX}{7: }{8: 3 }c |
+ {9:XX}{101:>>}{7: }{8: 1 }a |
+ {101:>>}{9:XX}{7: }{8: 2 }b |
+ {7:WW}{101:>>}{9:XX}{7: }{8: 3 }c |
{7: }{8: 4 }^ |
{1:~ }|*9
|
@@ -255,8 +260,8 @@ describe('Signs', function()
exec('3move1')
exec('2d')
screen:expect([[
- {9:XX}{10:>>}{8: 1 }a |
- {10:>>}{9:XX}{8: 2 }^b |
+ {9:XX}{101:>>}{8: 1 }a |
+ {101:>>}{9:XX}{8: 2 }^b |
{7: }{8: 3 } |
{1:~ }|*10
|
@@ -264,8 +269,8 @@ describe('Signs', function()
-- character deletion does not delete signs.
feed('x')
screen:expect([[
- {9:XX}{10:>>}{8: 1 }a |
- {10:>>}{9:XX}{8: 2 }^ |
+ {9:XX}{101:>>}{8: 1 }a |
+ {101:>>}{9:XX}{8: 2 }^ |
{7: }{8: 3 } |
{1:~ }|*10
|
@@ -301,7 +306,7 @@ describe('Signs', function()
exec('sign define pietSearch text=>> texthl=Search')
exec('sign place 1 line=1 name=pietSearch buffer=1')
screen:expect([[
- {10:>>}{7: }{8: 1 }a |
+ {101:>>}{7: }{8: 1 }a |
{7: }{8: 2 }b |
{7: }{8: 3 }c |
{7: }{8: 4 }^ |
@@ -316,7 +321,7 @@ describe('Signs', function()
sign place 4 line=1 name=pietSearch buffer=1
]])
screen:expect([[
- {10:>>>>>>>>}{8: 1 }a |
+ {101:>>>>>>>>}{8: 1 }a |
{7: }{8: 2 }b |
{7: }{8: 3 }c |
{7: }{8: 4 }^ |
@@ -328,7 +333,7 @@ describe('Signs', function()
screen:expect_unchanged()
exec('sign unplace 4')
screen:expect([[
- {10:>>>>>>}{8: 1 }a |
+ {101:>>>>>>}{8: 1 }a |
{7: }{8: 2 }b |
{7: }{8: 3 }c |
{7: }{8: 4 }^ |
@@ -345,7 +350,7 @@ describe('Signs', function()
sign place 8 line=1 name=pietSearch buffer=1
]])
screen:expect([[
- {10:>>>>>>>>>>}{8: 1 }a |
+ {101:>>>>>>>>>>}{8: 1 }a |
{7: }{8: 2 }b |
{7: }{8: 3 }c |
{7: }{8: 4 }^ |
@@ -375,7 +380,7 @@ describe('Signs', function()
-- single column with 1 sign with text and one sign without
exec('sign place 1 line=1 name=pietSearch buffer=1')
screen:expect([[
- {10:>>}{8: 1 }a |
+ {101:>>}{8: 1 }a |
{7: }{8: 2 }b |
{7: }{8: 3 }c |
{7: }{8: 4 }^ |
@@ -396,7 +401,7 @@ describe('Signs', function()
-- line number should be drawn if sign has no text
-- no signcolumn, line number for "a" is Search, for "b" is Error, for "c" is LineNr
screen:expect([[
- {10: >> }a |
+ {101: >> }a |
{9: 2 }b |
{8: 3 }c |
{8: 4 }^ |
@@ -406,7 +411,7 @@ describe('Signs', function()
-- number column on wrapped part of a line should be empty
feed('gg100aa<Esc>')
screen:expect([[
- {10: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {101: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{9: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{9: }aa^a |
{9: 2 }b |
@@ -423,7 +428,7 @@ describe('Signs', function()
-- number column on virtual lines should be empty
screen:expect([[
{8: }VIRT LINES |
- {10: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {101: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{9: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{9: }aa^a |
{9: 2 }b |
@@ -439,7 +444,7 @@ describe('Signs', function()
exec('sign place 100000 line=1 name=piet buffer=1')
feed(':sign place<cr>')
screen:expect([[
- {10:>>} |
+ {101:>>} |
{1:~ }|*6
{3: }|
:sign place |
@@ -452,7 +457,7 @@ describe('Signs', function()
feed('<cr>')
screen:expect([[
- {10:>>}^ |
+ {101:>>}^ |
{1:~ }|*12
|
]])
@@ -470,7 +475,7 @@ describe('Signs', function()
{7: }a |
{7: }^c |
{7: }d |
- >>e |
+ {7:>>}e |
{1:~ }|*9
|
]])
@@ -498,7 +503,7 @@ describe('Signs', function()
{7: }b |
{7: }c |
{7: }d |
- >>e |
+ {7:>>}e |
{1:~ }|*7
|
]])
@@ -550,7 +555,7 @@ describe('Signs', function()
exec('silent undo')
screen:expect([[
{7: }1 |
- S1^2 |
+ {7:S1}^2 |
{7: }3 |
{7: }4 |
{1:~ }|*9
@@ -575,23 +580,19 @@ describe('Signs', function()
sign place 2 line=9 name=S2
]])
-- Now placed at end of buffer
- local s1 = {
- grid = [[
- S2^ |
- {1:~ }|*12
- |
- ]],
- }
+ local s1 = [[
+ {7:S2}^ |
+ {1:~ }|*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^ |
- {1:~ }|*12
- |
- ]],
- })
+ screen:expect([[
+ {7:S2S1}^ |
+ {1:~ }|*12
+ |
+ ]])
-- Unplacing the sign does not crash by decrementing tracked signs below zero
exec('sign unplace 1')
screen:expect(s1)
@@ -607,4 +608,77 @@ describe('Signs', function()
eq(6, infos[1].textoff)
eq(6, infos[2].textoff)
end)
+
+ it('auto width updated in all windows after sign placed in on_win #31438', function()
+ exec_lua([[
+ vim.cmd.call('setline(1, range(1, 500))')
+ vim.cmd('wincmd s | wincmd v | wincmd j | wincmd v')
+
+ _G.log, _G.needs_clear = {}, false
+ local ns_id, mark_id = vim.api.nvim_create_namespace('test'), nil
+
+ -- Add decoration which possibly clears all extmarks and adds one on line 499
+ local on_win = function(_, winid, bufnr, toprow, botrow)
+ if _G.needs_clear then
+ vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
+ _G.needs_clear = false
+ end
+
+ if toprow < 499 and 499 <= botrow then
+ mark_id = vim.api.nvim_buf_set_extmark(bufnr, ns_id, 499, 0, { id = mark_id, sign_text = '!', invalidate = true })
+ end
+ end
+ vim.api.nvim_set_decoration_provider(ns_id, { on_win = on_win })
+ ]])
+ screen:expect([[
+ 1 │1 |
+ 2 │2 |
+ 3 │3 |
+ 4 │4 |
+ 5 │5 |
+ 6 │6 |
+ {2:[No Name] [+] [No Name] [+] }|
+ ^1 │1 |
+ 2 │2 |
+ 3 │3 |
+ 4 │4 |
+ 5 │5 |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('G')
+ screen:expect([[
+ {7: }1 │{7: }1 |
+ {7: }2 │{7: }2 |
+ {7: }3 │{7: }3 |
+ {7: }4 │{7: }4 |
+ {7: }5 │{7: }5 |
+ {7: }6 │{7: }6 |
+ {2:[No Name] [+] [No Name] [+] }|
+ {7: }496 │{7: }1 |
+ {7: }497 │{7: }2 |
+ {7: }498 │{7: }3 |
+ {7: }499 │{7: }4 |
+ {7:! }^500 │{7: }5 |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed(':lua log, needs_clear = {}, true<CR>')
+ screen:expect([[
+ {7: }1 │{7: }1 |
+ {7: }2 │{7: }2 |
+ {7: }3 │{7: }3 |
+ {7: }4 │{7: }4 |
+ {7: }5 │{7: }5 |
+ {7: }6 │{7: }6 |
+ {2:[No Name] [+] [No Name] [+] }|
+ {7: }496 │{7: }1 |
+ {7: }497 │{7: }2 |
+ {7: }498 │{7: }3 |
+ {7: }499 │{7: }4 |
+ {7:! }^500 │{7: }5 |
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ :lua log, needs_clear = {}, true |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 268e7173e6..328e212a22 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -13,8 +13,6 @@ local api = n.api
local pcall_err = t.pcall_err
local assert_alive = n.assert_alive
-local mousemodels = { 'extend', 'popup', 'popup_setpos' }
-
describe('statuscolumn', function()
local screen
before_each(function()
@@ -229,15 +227,28 @@ describe('statuscolumn', function()
{1: }{8:8│}aaaaa |
|
]])
+ -- Last segment and fillchar are highlighted properly
+ command("set stc=%#Error#%{v:relnum?'Foo':'FooBar'}")
+ screen:expect([[
+ {9:Foo }aaaaa |*4
+ {9:FooBar}^aaaaa |
+ {9:Foo }aaaaa |*8
+ |
+ ]])
end)
it('works with wrapped lines, signs and folds', function()
- command([[set stc=%C%s%=%{v:virtnum?'':v:lnum}│\ ]])
- command("call setline(1,repeat([repeat('aaaaa',10)],16))")
screen:add_extra_attr_ids {
[100] = { foreground = Screen.colors.Red, background = Screen.colors.LightGray },
+ [101] = { background = Screen.colors.Gray90, bold = true },
+ [102] = { foreground = Screen.colors.Brown, background = Screen.colors.Grey },
+ [103] = { bold = true, background = Screen.colors.Grey, foreground = Screen.colors.Blue1 },
}
- command('hi! CursorLine guifg=Red guibg=NONE')
+ command([[set cursorline stc=%C%s%=%{v:virtnum?'':v:lnum}│\ ]])
+ command("call setline(1,repeat([repeat('aaaaa',10)],16))")
+ command('hi! CursorLine gui=bold')
+ command('sign define num1 numhl=Special')
+ command('sign place 1 line=8 name=num1 buffer=1')
screen:expect([[
{8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{8: │ }a |
@@ -247,8 +258,8 @@ describe('statuscolumn', function()
{8: │ }a |
{8: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{8: │ }a |
- {8: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
- {8: │ }a |
+ {29: 8│ }{101:^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {29: │ }{101:a }|
{8: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{8: │ }a |
{8:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:@@@}|
@@ -256,7 +267,8 @@ describe('statuscolumn', function()
]])
command([[set stc=%C%s%=%l│\ ]])
screen:expect_unchanged()
- command('set signcolumn=auto:2 foldcolumn=auto')
+ command('hi! CursorLine guifg=Red guibg=NONE gui=NONE')
+ command('set nocursorline signcolumn=auto:2 foldcolumn=auto')
command('sign define piet1 text=>> texthl=LineNr')
command('sign define piet2 text=>! texthl=NonText')
command('sign place 1 line=4 name=piet1 buffer=1')
@@ -264,11 +276,11 @@ describe('statuscolumn', function()
command('sign place 3 line=6 name=piet1 buffer=1')
command('sign place 4 line=6 name=piet2 buffer=1')
screen:expect([[
- {8:>>}{7: }{8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {102:>>}{7: }{8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │ }aaaaa |
- {1:>!}{7: }{8: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {103:>!}{7: }{8: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │ }aaaaa |
- {1:>!}{8:>> 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {103:>!}{102:>>}{8: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │ }aaaaa |
{7: }{8: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │ }aaaaa |
@@ -283,11 +295,11 @@ describe('statuscolumn', function()
-- Check that alignment works properly with signs after %=
command([[set stc=%C%=%{v:virtnum?'':v:lnum}│%s\ ]])
screen:expect([[
- {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{102:>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
- {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 5│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
- {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 6│}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
{7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
@@ -300,11 +312,11 @@ describe('statuscolumn', function()
]])
command('set cursorline')
screen:expect([[
- {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{102:>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
- {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 5│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
- {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 6│}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
{7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaa |
@@ -318,11 +330,11 @@ describe('statuscolumn', function()
-- v:lnum is the same value on wrapped lines
command([[set stc=%C%=%{v:lnum}│%s\ ]])
screen:expect([[
- {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{102:>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 4│}{7: }{8: }aaaaaa |
- {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 5│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 5│}{7: }{8: }aaaaaa |
- {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 6│}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 6│}{7: }{8: }aaaaaa |
{7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 7│}{7: }{8: }aaaaaa |
@@ -336,11 +348,11 @@ describe('statuscolumn', function()
-- v:relnum is the same value on wrapped lines
command([[set stc=%C%=\ %{v:relnum}│%s\ ]])
screen:expect([[
- {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{102:>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 4│}{7: }{8: }aaaaaaa |
- {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 3│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 3│}{7: }{8: }aaaaaaa |
- {7: }{8: 2│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 2│}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 2│}{7: }{8: }aaaaaaa |
{7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: 1│}{7: }{8: }aaaaaaa |
@@ -353,11 +365,11 @@ describe('statuscolumn', function()
]])
command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]])
screen:expect([[
- {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{102:>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaa |
- {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 3│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaa |
- {7: }{8: 2│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 2│}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaa |
{7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaa |
@@ -378,11 +390,11 @@ 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([[
- {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 4│}{102:>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
- {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 3│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
- {7: }{8: 2│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 2│}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
{7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa |
@@ -397,11 +409,11 @@ describe('statuscolumn', function()
command('set cpoptions+=n')
feed('Hgjg0')
screen:expect([[
- {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{15: 0│}{102:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{7: }{19:^aaaaaaaaaaaaaaaaaaaaa }|
- {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 3│}{103:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }aaaaaaaaaaaaaaaaaaaaa |
- {7: }{8: 2│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 2│}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }aaaaaaaaaaaaaaaaaaaaa |
{7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }aaaaaaaaaaaaaaaaaaaaa |
@@ -416,11 +428,11 @@ describe('statuscolumn', function()
command('sign unplace 2')
feed('J2gjg0')
screen:expect([[
- {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{15: 0│}{102:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{7: } {19:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}|
{7: } {19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{7: } {19:^aaaaaaaaaaaaaa }|
- {7: }{8: 1│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 1│}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: } aaaaaaaaaaaaaaaaaaaaa |
{7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: } aaaaaaaaaaaaaaaaaaaaa |
@@ -434,11 +446,11 @@ describe('statuscolumn', function()
command('set nobreakindent')
feed('$g0')
screen:expect([[
- {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+ {7: }{15: 0│}{102:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{7: }{19:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}|
{7: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{7: }{19:^aaaa }|
- {7: }{8: 1│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {7: }{8: 1│}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{103:>!}{102:>>}{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }aaaaaaaaaaaaaaaaaaaaa |
{7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
{7: }aaaaaaaaaaaaaaaaaaaaa |
@@ -460,11 +472,11 @@ describe('statuscolumn', function()
]])
command('set foldcolumn=0 signcolumn=number stc=%l')
screen:expect([[
- {8:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {102:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
{8: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
{8: }virt_line |
{8: }virt_line above |
- {8:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
+ {102:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
{8: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
{15: 8}{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
{8: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
@@ -580,13 +592,13 @@ 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: 8}^aaaaa |
{8: }{7: }{8: 9}aaaaa |
|
]])
end)
- for _, model in ipairs(mousemodels) do
+ for _, model in ipairs({ 'extend', 'popup', 'popup_setpos' }) do
describe('with mousemodel=' .. model, function()
before_each(function()
command('set mousemodel=' .. model)
@@ -645,23 +657,56 @@ 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 rightclick still opens popupmenu if there is no clickdef
+ if model == 'popup' then
+ api.nvim_set_option_value('statuscolumn', '%0@MyClickFunc@%=%l%TNoClick', {})
+ api.nvim_input_mouse('right', 'press', '', 0, 1, 0)
+ screen:expect([[
+ {5:[No Name] }|
+ {8: 4NoClick}^aaaaa |
+ {8: 5NoClick}aaaaa |
+ {8: 6NoClick}aaaaa |
+ {8: 7NoClick}aaaaa |
+ {8: 8NoClick}aaaaa |
+ {8: 9NoClick}aaaaa |
+ {8:10NoClick}aaaaa |
+ {8:11NoClick}aaaaa |
+ {8:12NoClick}aaaaa |
+ {8:13NoClick}aaaaa |
+ {8:14NoClick}aaaaa |
+ {3:[No Name] [+] }|
+ |
+ ]])
+ api.nvim_input_mouse('right', 'press', '', 0, 1, 3)
+ screen:expect([[
+ {5:[No Name] }|
+ {8: 4NoClick}^aaaaa |
+ {8: 5}{4: Inspect } |
+ {8: 6}{4: } |
+ {8: 7}{4: Paste } |
+ {8: 8}{4: Select All } |
+ {8: 9}{4: } |
+ {8:10}{4: How-to disable mouse } |
+ {8:11NoClick}aaaaa |
+ {8:12NoClick}aaaaa |
+ {8:13NoClick}aaaaa |
+ {8:14NoClick}aaaaa |
+ {3:[No Name] [+] }|
+ |
+ ]])
+ end
end)
it('clicks and highlights work with control characters', function()
api.nvim_set_option_value('statuscolumn', '\t%#NonText#\1%0@MyClickFunc@\t\1%T\t%##\1', {})
- screen:expect {
- grid = [[
- {1:^I}{0:^A^I^A^I}{1:^A}aaaaa |*4
- {1:^I}{0:^A^I^A^I}{1:^A}^aaaaa |
- {1:^I}{0:^A^I^A^I}{1:^A}aaaaa |*8
+ screen:expect([[
+ {8:^I}{1:^A^I^A^I}{8:^A}aaaaa |*4
+ {8:^I}{1:^A^I^A^I}{8:^A}^aaaaa |
+ {8:^I}{1:^A^I^A^I}{8:^A}aaaaa |*8
|
- ]],
- attr_ids = {
- [0] = { foreground = Screen.colors.Blue, bold = true }, -- NonText
- [1] = { foreground = Screen.colors.Brown }, -- LineNr
- },
- }
+ ]])
api.nvim_input_mouse('right', 'press', '', 0, 4, 3)
+ feed('<Esc>') -- Close popupmenu
eq('', eval('g:testvar'))
api.nvim_input_mouse('left', 'press', '', 0, 5, 8)
eq('', eval('g:testvar'))
@@ -707,6 +752,36 @@ describe('statuscolumn', function()
|
]])
end)
+
+ it('foldcolumn item can be clicked', function()
+ api.nvim_set_option_value('statuscolumn', '|%C|', {})
+ api.nvim_set_option_value('foldcolumn', '2', {})
+ api.nvim_set_option_value('mousetime', 0, {})
+ feed('ggzfjzfjzo')
+ local s1 = [[
+ {8:|}{7:-+}{8:|}{13:^+--- 2 lines: aaaaa·····························}|
+ {8:|}{7:│ }{8:|}aaaaa |
+ {8:|}{7: }{8:|}aaaaa |*11
+ |
+ ]]
+ screen:expect(s1)
+ api.nvim_input_mouse('left', 'press', '', 0, 0, 2)
+ screen:expect([[
+ {8:|}{7:--}{8:|}^aaaaa |
+ {8:|}{7:││}{8:|}aaaaa |
+ {8:|}{7:│ }{8:|}aaaaa |
+ {8:|}{7: }{8:|}aaaaa |*10
+ |
+ ]])
+ api.nvim_input_mouse('left', 'press', '', 0, 0, 1)
+ screen:expect(s1)
+ api.nvim_input_mouse('left', 'press', '', 0, 0, 1)
+ screen:expect([[
+ {8:|}{7:+ }{8:|}{13:^+-- 3 lines: aaaaa······························}|
+ {8:|}{7: }{8:|}aaaaa |*12
+ |
+ ]])
+ end)
end)
end
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index 1d0f181244..50e31ac6a9 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -507,268 +507,263 @@ describe('global statusline', function()
end)
end)
-it('statusline does not crash if it has Arabic characters #19447', function()
- clear()
- api.nvim_set_option_value('statusline', 'غً', {})
- api.nvim_set_option_value('laststatus', 2, {})
- command('redraw!')
- assert_alive()
-end)
+describe('statusline', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:add_extra_attr_ids {
+ [100] = { bold = true, reverse = true, foreground = Screen.colors.Blue },
+ [101] = { reverse = true, bold = true, foreground = Screen.colors.SlateBlue },
+ }
+ end)
-it('statusline is redrawn with :resize from <Cmd> mapping #19629', function()
- clear()
- local screen = Screen.new(40, 8)
- exec([[
- set laststatus=2
- nnoremap <Up> <cmd>resize -1<CR>
- nnoremap <Down> <cmd>resize +1<CR>
- ]])
- feed('<Up>')
- screen:expect([[
- ^ |
- {1:~ }|*4
- {3:[No Name] }|
- |*2
- ]])
- feed('<Down>')
- screen:expect([[
- ^ |
- {1:~ }|*5
- {3:[No Name] }|
- |
- ]])
-end)
+ it('does not crash if it has Arabic characters #19447', function()
+ api.nvim_set_option_value('statusline', 'غً', {})
+ api.nvim_set_option_value('laststatus', 2, {})
+ command('redraw!')
+ assert_alive()
+ end)
-it('showcmdloc=statusline does not show if statusline is too narrow', function()
- clear()
- local screen = Screen.new(40, 8)
- command('set showcmd')
- command('set showcmdloc=statusline')
- command('1vsplit')
- screen:expect([[
- ^ │ |
- {1:~}│{1:~ }|*5
- {3:< }{2:[No Name] }|
- |
- ]])
- feed('1234')
- screen:expect_unchanged()
-end)
+ it('is redrawn with :resize from <Cmd> mapping #19629', function()
+ exec([[
+ set laststatus=2
+ nnoremap <Up> <cmd>resize -1<CR>
+ nnoremap <Down> <cmd>resize +1<CR>
+ ]])
+ feed('<Up>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*4
+ {3:[No Name] }|
+ |*2
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {3:[No Name] }|
+ |
+ ]])
+ end)
-it('K_EVENT does not trigger a statusline redraw unnecessarily', function()
- clear()
- local _ = Screen.new(40, 8)
- -- does not redraw on vim.schedule (#17937)
- command([[
- set laststatus=2
- let g:counter = 0
- func Status()
- let g:counter += 1
- lua vim.schedule(function() end)
- return g:counter
- endfunc
- set statusline=%!Status()
- ]])
- sleep(50)
- eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
- -- also in insert mode
- feed('i')
- sleep(50)
- eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
- -- does not redraw on timer call (#14303)
- command([[
- let g:counter = 0
- func Timer(timer)
- endfunc
- call timer_start(1, 'Timer', {'repeat': 100})
- ]])
- sleep(50)
- eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
-end)
+ it('does not contain showmcd with showcmdloc=statusline when too narrow', function()
+ command('set showcmd')
+ command('set showcmdloc=statusline')
+ command('1vsplit')
+ screen:expect([[
+ ^ │ |
+ {1:~}│{1:~ }|*5
+ {3:< }{2:[No Name] }|
+ |
+ ]])
+ feed('1234')
+ screen:expect_unchanged()
+ end)
-it('statusline is redrawn on various state changes', function()
- clear()
- local screen = Screen.new(40, 4)
-
- -- recording state change #22683
- command('set ls=2 stl=%{repeat(reg_recording(),5)}')
- screen:expect([[
- ^ |
- {1:~ }|
- {3: }|
- |
- ]])
- feed('qQ')
- screen:expect([[
- ^ |
- {1:~ }|
- {3:QQQQQ }|
- {5:recording @Q} |
- ]])
- feed('q')
- screen:expect([[
- ^ |
- {1:~ }|
- {3: }|
- |
- ]])
-
- -- Visual mode change #23932
- command('set ls=2 stl=%{mode(1)}')
- screen:expect([[
- ^ |
- {1:~ }|
- {3:n }|
- |
- ]])
- feed('v')
- screen:expect([[
- ^ |
- {1:~ }|
- {3:v }|
- {5:-- VISUAL --} |
- ]])
- feed('V')
- screen:expect([[
- ^ |
- {1:~ }|
- {3:V }|
- {5:-- VISUAL LINE --} |
- ]])
- feed('<C-V>')
- screen:expect([[
- ^ |
- {1:~ }|
- {3:^V }|
- {5:-- VISUAL BLOCK --} |
- ]])
- feed('<Esc>')
- screen:expect([[
- ^ |
- {1:~ }|
- {3:n }|
- |
- ]])
-end)
+ it('does not redraw unnecessarily after K_EVENT', function()
+ -- does not redraw on vim.schedule (#17937)
+ command([[
+ set laststatus=2
+ let g:counter = 0
+ func Status()
+ let g:counter += 1
+ lua vim.schedule(function() end)
+ return g:counter
+ endfunc
+ set statusline=%!Status()
+ ]])
+ sleep(50)
+ eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
+ -- also in insert mode
+ feed('i')
+ sleep(50)
+ eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
+ -- does not redraw on timer call (#14303)
+ command([[
+ let g:counter = 0
+ func Timer(timer)
+ endfunc
+ call timer_start(1, 'Timer', {'repeat': 100})
+ ]])
+ sleep(50)
+ eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter'))
+ end)
-it('ruler is redrawn in cmdline with redrawstatus #22804', function()
- clear()
- local screen = Screen.new(40, 2)
- command([[
- let g:n = 'initial value'
- set ls=1 ru ruf=%{g:n}
- redraw
- let g:n = 'other value'
- redrawstatus
- ]])
- screen:expect([[
- ^ |
- other value |
- ]])
-end)
+ it('is redrawn on various state changes', function()
+ -- recording state change #22683
+ command('set ls=2 stl=%{repeat(reg_recording(),5)}')
+ local s1 = [[
+ ^ |
+ {1:~ }|*5
+ {3: }|
+ |
+ ]]
+ screen:expect(s1)
+ feed('qQ')
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {3:QQQQQ }|
+ {5:recording @Q} |
+ ]])
+ feed('q')
+ screen:expect(s1)
+
+ -- Visual mode change #23932
+ command('set ls=2 stl=%{mode(1)}')
+ local s2 = [[
+ ^ |
+ {1:~ }|*5
+ {3:n }|
+ |
+ ]]
+ screen:expect(s2)
+ feed('v')
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {3:v }|
+ {5:-- VISUAL --} |
+ ]])
+ feed('V')
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {3:V }|
+ {5:-- VISUAL LINE --} |
+ ]])
+ feed('<C-V>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {3:^V }|
+ {5:-- VISUAL BLOCK --} |
+ ]])
+ feed('<Esc>')
+ screen:expect(s2)
+ end)
-it('shows correct ruler in cmdline with no statusline', function()
- clear()
- local screen = Screen.new(30, 8)
- -- Use long ruler to check 'ruler' with 'rulerformat' set has correct width.
- command [[
- set ruler rulerformat=%{winnr()}longlonglong ls=0 winwidth=10
- split
- wincmd b
- vsplit
- wincmd t
- wincmd |
- mode
- ]]
- -- Window 1 is current. It has a statusline, so cmdline should show the
- -- last window's ruler, which has no statusline.
- command '1wincmd w'
- screen:expect [[
- ^ |
- {1:~ }|*2
- {3:[No Name] 1longlonglong }|
- │ |
- {1:~ }│{1:~ }|*2
- 3longlonglong |
- ]]
- -- Window 2 is current. It has no statusline, so cmdline should show its
- -- ruler instead.
- command '2wincmd w'
- screen:expect [[
- |
- {1:~ }|*2
- {2:[No Name] 1longlonglong }|
- ^ │ |
- {1:~ }│{1:~ }|*2
- 2longlonglong |
- ]]
- -- Window 3 is current. Cmdline should again show its ruler.
- command '3wincmd w'
- screen:expect [[
- |
- {1:~ }|*2
- {2:[No Name] 1longlonglong }|
- │^ |
- {1:~ }│{1:~ }|*2
- 3longlonglong |
- ]]
-end)
+ it('ruler is redrawn in cmdline with redrawstatus #22804', function()
+ command([[
+ let g:n = 'initial value'
+ set ls=1 ru ruf=%{g:n}
+ redraw
+ let g:n = 'other value'
+ redrawstatus
+ ]])
+ screen:expect([[
+ ^ |
+ {1:~ }|*6
+ other value |
+ ]])
+ end)
-it('uses "stl" and "stlnc" fillchars even if they are the same #19803', function()
- clear()
- local screen = Screen.new(53, 4)
- command('hi clear StatusLine')
- command('hi clear StatusLineNC')
- command('vsplit')
- screen:expect {
- grid = [[
- ^ │ |
- {1:~ }│{1:~ }|
- [No Name] [No Name] |
- |
- ]],
- }
-end)
+ it('hidden moves ruler to cmdline', function()
+ -- Use long ruler to check 'ruler' with 'rulerformat' set has correct width.
+ command [[
+ set ruler rulerformat=%{winnr()}longlonglong ls=0 winwidth=10
+ split
+ wincmd b
+ vsplit
+ wincmd t
+ wincmd |
+ mode
+ ]]
+ -- Window 1 is current. It has a statusline, so cmdline should show the
+ -- last window's ruler, which has no statusline.
+ command '1wincmd w'
+ screen:expect([[
+ ^ |
+ {1:~ }|*2
+ {3:[No Name] 1longlonglong }|
+ │ |
+ {1:~ }│{1:~ }|*2
+ 3longlonglong |
+ ]])
+ -- Window 2 is current. It has no statusline, so cmdline should show its
+ -- ruler instead.
+ command '2wincmd w'
+ screen:expect([[
+ |
+ {1:~ }|*2
+ {2:[No Name] 1longlonglong }|
+ ^ │ |
+ {1:~ }│{1:~ }|*2
+ 2longlonglong |
+ ]])
+ -- Window 3 is current. Cmdline should again show its ruler.
+ command '3wincmd w'
+ screen:expect([[
+ |
+ {1:~ }|*2
+ {2:[No Name] 1longlonglong }|
+ │^ |
+ {1:~ }│{1:~ }|*2
+ 3longlonglong |
+ ]])
+ end)
-it('showcmdloc=statusline works with vertical splits', function()
- clear()
- local screen = Screen.new(53, 4)
- command('rightbelow vsplit')
- command('set showcmd showcmdloc=statusline')
- feed('1234')
- screen:expect([[
- │^ |
- {1:~ }│{1:~ }|
- {2:[No Name] }{3:[No Name] 1234 }|
- |
- ]])
- feed('<Esc>')
- command('set laststatus=3')
- feed('1234')
- screen:expect([[
- │^ |
- {1:~ }│{1:~ }|
- {3:[No Name] 1234 }|
- |
- ]])
-end)
+ it('uses "stl" and "stlnc" fillchars even if they are the same #19803', function()
+ command('hi clear StatusLine')
+ command('hi clear StatusLineNC')
+ command('vsplit')
+ screen:expect([[
+ ^ │ |
+ {1:~ }│{1:~ }|*5
+ [No Name] [No Name] |
+ |
+ ]])
+ end)
-it('keymap is shown with vertical splits #27269', function()
- clear()
- local screen = Screen.new(53, 4)
- command('setlocal keymap=dvorak')
- command('rightbelow vsplit')
- screen:expect([[
- │^ |
- {1:~ }│{1:~ }|
- {2:[No Name] <en-dv> }{3:[No Name] <en-dv> }|
- |
- ]])
- command('set laststatus=3')
- screen:expect([[
- │^ |
- {1:~ }│{1:~ }|
- {3:[No Name] <en-dv> }|
- |
- ]])
+ it('showcmdloc=statusline works with vertical splits', function()
+ command('rightbelow vsplit')
+ command('set showcmd showcmdloc=statusline')
+ feed('1234')
+ screen:expect([[
+ │^ |
+ {1:~ }│{1:~ }|*5
+ {2:[No Name] }{3:[No Name] 1234 }|
+ |
+ ]])
+ feed('<Esc>')
+ command('set laststatus=3')
+ feed('1234')
+ screen:expect([[
+ │^ |
+ {1:~ }│{1:~ }|*5
+ {3:[No Name] 1234 }|
+ |
+ ]])
+ end)
+
+ it('keymap is shown with vertical splits #27269', function()
+ command('setlocal keymap=dvorak')
+ command('rightbelow vsplit')
+ screen:expect([[
+ │^ |
+ {1:~ }│{1:~ }|*5
+ {2:[No Name] <en-dv> }{3:[No Name] <en-dv> }|
+ |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │^ |
+ {1:~ }│{1:~ }|*5
+ {3:[No Name] <en-dv> }|
+ |
+ ]])
+ end)
+
+ it("nested call from nvim_eval_statusline() doesn't overwrite items #32259", function()
+ exec_lua('vim.o.laststatus = 2')
+ exec_lua([[vim.o.statusline = '%#Special#B:%{nvim_eval_statusline("%f", []).str}']])
+ screen:expect([[
+ ^ |
+ {1:~ }|*5
+ {101:B:[No Name] }|
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index 57d76e54df..80e38d974a 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -198,7 +198,7 @@ describe('Screen', function()
end)
end) -- a region of text (implicit concealing)
- it('cursor position is correct when entering Insert mode with cocu=ni #13916', function()
+ it('cursor position when entering Insert mode with cocu=ni #13916', function()
insert([[foobarfoobarfoobar]])
-- move to end of line
feed('$')
@@ -217,6 +217,37 @@ describe('Screen', function()
{4:-- INSERT --} |
]])
end)
+
+ it('cursor position when scrolling in Normal mode with cocu=n #31271', function()
+ insert(('foo\n'):rep(9) .. 'foofoobarfoofoo' .. ('\nfoo'):rep(9))
+ command('set concealcursor=n')
+ command('syn match Foo /bar/ conceal cchar=&')
+ feed('gg5<C-E>10gg$')
+ screen:expect([[
+ foo |*4
+ foofoo{1:&}foofo^o |
+ foo |*4
+ |
+ ]])
+ feed('zz')
+ screen:expect_unchanged()
+ feed('zt')
+ screen:expect([[
+ foofoo{1:&}foofo^o |
+ foo |*8
+ |
+ ]])
+ feed('zt')
+ screen:expect_unchanged()
+ feed('zb')
+ screen:expect([[
+ foo |*8
+ foofoo{1:&}foofo^o |
+ |
+ ]])
+ feed('zb')
+ screen:expect_unchanged()
+ end)
end) -- match and conceal
describe('let the conceal level be', function()
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
index 66eb15478b..2de1e71457 100644
--- a/test/functional/ui/title_spec.lua
+++ b/test/functional/ui/title_spec.lua
@@ -37,6 +37,63 @@ describe('title', function()
end)
end)
+ it('is updated in Insert mode', function()
+ api.nvim_set_option_value('title', true, {})
+ screen:expect(function()
+ eq('[No Name] - Nvim', screen.title)
+ end)
+ feed('ifoo')
+ screen:expect(function()
+ eq('[No Name] + - Nvim', screen.title)
+ end)
+ feed('<Esc>')
+ api.nvim_set_option_value('titlestring', '%m %f (%{mode(1)}) | nvim', {})
+ screen:expect(function()
+ eq('[+] [No Name] (n) | nvim', screen.title)
+ end)
+ feed('i')
+ screen:expect(function()
+ eq('[+] [No Name] (i) | nvim', screen.title)
+ end)
+ feed('<Esc>')
+ screen:expect(function()
+ eq('[+] [No Name] (n) | nvim', screen.title)
+ end)
+ end)
+
+ it('is updated in Cmdline mode', function()
+ api.nvim_set_option_value('title', true, {})
+ api.nvim_set_option_value('titlestring', '%f (%{mode(1)}) | nvim', {})
+ screen:expect(function()
+ eq('[No Name] (n) | nvim', screen.title)
+ end)
+ feed(':')
+ screen:expect(function()
+ eq('[No Name] (c) | nvim', screen.title)
+ end)
+ feed('<Esc>')
+ screen:expect(function()
+ eq('[No Name] (n) | nvim', screen.title)
+ end)
+ end)
+
+ it('is updated in Terminal mode', function()
+ api.nvim_set_option_value('title', true, {})
+ api.nvim_set_option_value('titlestring', '(%{mode(1)}) | nvim', {})
+ fn.jobstart({ n.testprg('shell-test'), 'INTERACT' }, { term = true })
+ screen:expect(function()
+ eq('(nt) | nvim', screen.title)
+ end)
+ feed('i')
+ screen:expect(function()
+ eq('(t) | nvim', screen.title)
+ end)
+ feed([[<C-\><C-N>]])
+ screen:expect(function()
+ eq('(nt) | nvim', screen.title)
+ end)
+ end)
+
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'
diff --git a/test/functional/vimscript/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua
index 873e4f820d..85a74c0ab6 100644
--- a/test/functional/vimscript/ctx_functions_spec.lua
+++ b/test/functional/vimscript/ctx_functions_spec.lua
@@ -188,7 +188,10 @@ describe('context functions', function()
function RestoreFuncs()
call ctxpop()
endfunction
+
+ let g:sid = expand('<SID>')
]])
+ local sid = api.nvim_get_var('sid')
eq('Hello, World!', exec_capture([[call Greet('World')]]))
eq(
@@ -200,11 +203,11 @@ describe('context functions', function()
call('DeleteSFuncs')
eq(
- 'function Greet, line 1: Vim(call):E117: Unknown function: s:greet',
+ ('function Greet, line 1: Vim(call):E117: Unknown function: %sgreet'):format(sid),
pcall_err(command, [[call Greet('World')]])
)
eq(
- 'function GreetAll, line 1: Vim(call):E117: Unknown function: s:greet_all',
+ ('function GreetAll, line 1: Vim(call):E117: Unknown function: %sgreet_all'):format(sid),
pcall_err(command, [[call GreetAll('World', 'One', 'Two', 'Three')]])
)
diff --git a/test/functional/vimscript/getchar_spec.lua b/test/functional/vimscript/getchar_spec.lua
new file mode 100644
index 0000000000..4ecf082f97
--- /dev/null
+++ b/test/functional/vimscript/getchar_spec.lua
@@ -0,0 +1,95 @@
+local n = require('test.functional.testnvim')()
+local Screen = require('test.functional.ui.screen')
+
+local clear = n.clear
+local exec = n.exec
+local feed = n.feed
+local async_command = n.async_meths.nvim_command
+local poke_eventloop = n.poke_eventloop
+
+describe('getchar()', function()
+ before_each(clear)
+
+ -- oldtest: Test_getchar_cursor_position()
+ it('cursor positioning', function()
+ local screen = Screen.new(40, 6)
+ exec([[
+ call setline(1, ['foobar', 'foobar', 'foobar'])
+ call cursor(3, 6)
+ ]])
+ screen:expect([[
+ foobar |*2
+ fooba^r |
+ {1:~ }|*2
+ |
+ ]])
+
+ -- Default: behaves like "msg" when immediately after printing a message,
+ -- even if :sleep moved cursor elsewhere.
+ for _, cmd in ipairs({
+ 'echo 1234 | call getchar()',
+ 'echo 1234 | call getchar(-1, {})',
+ "echo 1234 | call getchar(-1, #{cursor: 'msg'})",
+ 'echo 1234 | sleep 1m | call getchar()',
+ 'echo 1234 | sleep 1m | call getchar(-1, {})',
+ "echo 1234 | sleep 1m | call getchar(-1, #{cursor: 'msg'})",
+ }) do
+ async_command(cmd)
+ screen:expect([[
+ foobar |*3
+ {1:~ }|*2
+ 1234^ |
+ ]])
+ feed('a')
+ screen:expect([[
+ foobar |*2
+ fooba^r |
+ {1:~ }|*2
+ 1234 |
+ ]])
+ end
+
+ -- Default: behaves like "keep" when not immediately after printing a message.
+ for _, cmd in ipairs({
+ 'call getchar()',
+ 'call getchar(-1, {})',
+ "call getchar(-1, #{cursor: 'keep'})",
+ "echo 1234 | sleep 1m | call getchar(-1, #{cursor: 'keep'})",
+ }) do
+ async_command(cmd)
+ poke_eventloop()
+ screen:expect_unchanged()
+ feed('a')
+ poke_eventloop()
+ screen:expect_unchanged()
+ end
+
+ async_command("call getchar(-1, #{cursor: 'msg'})")
+ screen:expect([[
+ foobar |*3
+ {1:~ }|*2
+ ^1234 |
+ ]])
+ feed('a')
+ screen:expect([[
+ foobar |*2
+ fooba^r |
+ {1:~ }|*2
+ 1234 |
+ ]])
+
+ async_command("call getchar(-1, #{cursor: 'hide'})")
+ screen:expect([[
+ foobar |*3
+ {1:~ }|*2
+ 1234 |
+ ]])
+ feed('a')
+ screen:expect([[
+ foobar |*2
+ fooba^r |
+ {1:~ }|*2
+ 1234 |
+ ]])
+ end)
+end)
diff --git a/test/functional/vimscript/null_spec.lua b/test/functional/vimscript/null_spec.lua
index 9a27239a6d..afd50f7cf9 100644
--- a/test/functional/vimscript/null_spec.lua
+++ b/test/functional/vimscript/null_spec.lua
@@ -116,7 +116,7 @@ describe('NULL', function()
null_expr_test(
'is accepted as an empty list by inputlist()',
'[feedkeys("\\n"), inputlist(L)]',
- 'Type number and <Enter> or click with the mouse (q or empty cancels): ',
+ '',
{ 0, 0 }
)
null_expr_test(
diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index d1b8bfe5d9..3e4e6de35c 100644
--- a/test/functional/vimscript/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
@@ -94,12 +94,56 @@ describe('timers', function()
assert(0 <= diff and diff <= 4, 'expected (0 <= diff <= 4), got: ' .. tostring(diff))
end)
+ it('are triggered in inputlist() call #7857', function()
+ async_meths.nvim_exec2(
+ [[
+ call timer_start(5, 'MyHandler', {'repeat': -1})
+ let g:val = 0
+ let g:n = inputlist(['input0', 'input1'])
+ ]],
+ {}
+ )
+ retry(nil, nil, function()
+ local val = eval('g:val')
+ ok(val >= 2, '>= 2', tostring(val))
+ eq(0, eval("exists('g:n')"))
+ end)
+ feed('42<CR>')
+ eq(42, eval('g:n'))
+ end)
+
+ it('are triggered in confirm() call', function()
+ api.nvim_ui_attach(80, 24, {}) -- needed for confirm() to work
+ async_meths.nvim_exec2(
+ [[
+ call timer_start(5, 'MyHandler', {'repeat': -1})
+ let g:val = 0
+ let g:n = confirm('Are you sure?', "&Yes\n&No\n&Cancel")
+ ]],
+ {}
+ )
+ retry(nil, nil, function()
+ local val = eval('g:val')
+ ok(val >= 2, '>= 2', tostring(val))
+ eq(0, eval("exists('g:n')"))
+ end)
+ feed('c')
+ eq(3, eval('g:n'))
+ end)
+
it('are triggered in blocking getchar() call', function()
- command("call timer_start(5, 'MyHandler', {'repeat': -1})")
- async_meths.nvim_command('let g:val = 0 | let g:c = getchar()')
+ async_meths.nvim_exec2(
+ [[
+ call timer_start(5, 'MyHandler', {'repeat': -1})
+ let g:val = 0
+ let g:c = getchar()
+ ]],
+ {}
+ )
retry(nil, nil, function()
local val = eval('g:val')
ok(val >= 2, '>= 2', tostring(val))
+ eq(0, eval("exists('g:c')"))
eq(0, eval('getchar(1)'))
end)
feed('c')
@@ -126,39 +170,36 @@ describe('timers', function()
redraw
endfunc
]])
- async_meths.nvim_command('let g:c2 = getchar()')
+ async_meths.nvim_command("let g:c2 = getchar(-1, {'cursor': 'msg'})")
async_meths.nvim_command(
'call timer_start(' .. load_adjust(100) .. ", 'AddItem', {'repeat': -1})"
)
screen:expect([[
- ^ITEM 1 |
+ ITEM 1 |
ITEM 2 |
{1:~ }|*3
- |
+ ^ |
]])
async_meths.nvim_command('let g:cont = 1')
screen:expect([[
- ^ITEM 1 |
+ ITEM 1 |
ITEM 2 |
ITEM 3 |
{1:~ }|*2
- |
+ ^ |
]])
feed('3')
eq(51, eval('g:c2'))
- screen:expect {
- grid = [[
+ screen:expect([[
^ITEM 1 |
ITEM 2 |
ITEM 3 |
{1:~ }|*2
|
- ]],
- unchanged = true,
- }
+ ]])
end)
it('can be stopped', function()
diff --git a/test/old/testdir/gen_opt_test.vim b/test/old/testdir/gen_opt_test.vim
index be5a7e6ee4..f12ce8c7c4 100644
--- a/test/old/testdir/gen_opt_test.vim
+++ b/test/old/testdir/gen_opt_test.vim
@@ -87,7 +87,7 @@ let test_values = {
\ ['xxx', 'help,nofile']],
\ 'clipboard': [['', 'unnamed'], ['xxx', '\ze*', 'exclude:\\%(']],
\ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
- \ 'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
+ \ 'noinsert', 'noselect', 'fuzzy', 'preinsert', 'menu,longest'],
\ ['xxx', 'menu,,,longest,']],
\ 'encoding': [['utf8'], []],
\ 'foldcolumn': [[0, 1, 4, 'auto', 'auto:1', 'auto:9'], [-1, 13, 999]],
@@ -117,12 +117,11 @@ let test_values = {
"\ 'imstyle': [[0, 1], [-1, 2, 999]],
\ 'lines': [[2, 24, 1000], [-1, 0, 1]],
\ 'linespace': [[-1, 0, 2, 4, 999], ['']],
- \ 'msghistory': [[0, 1, 100, 10000], [-1, 10001]],
\ 'numberwidth': [[1, 4, 8, 10, 11, 20], [-1, 0, 21]],
\ 'regexpengine': [[0, 1, 2], [-1, 3, 999]],
\ 'report': [[0, 1, 2, 9999], [-1]],
- \ 'scroll': [[0, 1, 2, 20], [-1, 999]],
- \ 'scrolljump': [[-100, -1, 0, 1, 2, 20], [-101, 999]],
+ \ 'scroll': [[0, 1, 2, 15], [-1, 999]],
+ \ 'scrolljump': [[-100, -1, 0, 1, 2, 15], [-101, 999]],
\ 'scrolloff': [[0, 1, 8, 999], [-1]],
\ 'shiftwidth': [[0, 1, 8, 999], [-1]],
\ 'sidescroll': [[0, 1, 8, 999], [-1]],
@@ -146,8 +145,8 @@ let test_values = {
\ 'winwidth': [[1, 10, 999], [-1, 0]],
\
"\ string options
- \ 'ambiwidth': [['', 'single', 'double'], ['xxx']],
- \ 'background': [['', 'light', 'dark'], ['xxx']],
+ \ 'ambiwidth': [['single', 'double'], ['xxx']],
+ \ 'background': [['light', 'dark'], ['xxx']],
"\ 'backspace': [[0, 1, 2, 3, '', 'indent', 'eol', 'start', 'nostop',
"\ " 'eol,start', 'indent,eol,nostop'],
"\ " [-1, 4, 'xxx']],
@@ -187,7 +186,7 @@ let test_values = {
\ ['xxx']],
\ 'concealcursor': [['', 'n', 'v', 'i', 'c', 'nvic'], ['xxx']],
"\ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup',
- "\ " 'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'menu,longest'],
+ "\ " 'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'preinsert', 'menu,longest'],
"\ " ['xxx', 'menu,,,longest,']],
\ 'completeitemalign': [['abbr,kind,menu', 'menu,abbr,kind'],
\ ['', 'xxx', 'abbr', 'abbr,menu', 'abbr,menu,kind,abbr',
@@ -210,17 +209,19 @@ let test_values = {
\ 'icase', 'iwhite', 'iwhiteall', 'horizontal', 'vertical',
\ 'closeoff', 'hiddenoff', 'foldcolumn:0', 'foldcolumn:12',
\ 'followwrap', 'internal', 'indent-heuristic', 'algorithm:myers',
- \ 'algorithm:minimal', 'algorithm:patience',
- \ 'algorithm:histogram', 'icase,iwhite'],
- \ ['xxx', 'foldcolumn:xxx', 'algorithm:xxx', 'algorithm:']],
+ \ 'icase,iwhite', 'algorithm:minimal', 'algorithm:patience',
+ \ 'algorithm:histogram', 'linematch:5'],
+ \ ['xxx', 'foldcolumn:', 'foldcolumn:x', 'foldcolumn:xxx',
+ \ 'linematch:', 'linematch:x', 'linematch:xxx', 'algorithm:',
+ \ 'algorithm:xxx', 'context:', 'context:x', 'context:xxx']],
\ 'display': [['', 'lastline', 'truncate', 'uhex', 'lastline,uhex'],
\ ['xxx']],
- \ 'eadirection': [['', 'both', 'ver', 'hor'], ['xxx', 'ver,hor']],
+ \ 'eadirection': [['both', 'ver', 'hor'], ['xxx', 'ver,hor']],
"\ 'encoding': [['latin1'], ['xxx', '']],
\ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'],
\ ['xxx']],
\ 'fileencoding': [['', 'latin1', 'xxx'], []],
- \ 'fileformat': [['', 'dos', 'unix', 'mac'], ['xxx']],
+ \ 'fileformat': [['dos', 'unix', 'mac'], ['xxx']],
\ 'fileformats': [['', 'dos', 'dos,unix'], ['xxx']],
\ 'fillchars': [['', 'stl:x', 'stlnc:x', 'vert:x', 'fold:x', 'foldopen:x',
\ 'foldclose:x', 'foldsep:x', 'diff:x', 'eob:x', 'lastline:x',
@@ -264,10 +265,18 @@ let test_values = {
\ 'eol:\\u21b5', 'eol:\\U000021b5', 'eol:x,space:y'],
\ ['xxx', 'eol:']],
\ 'matchpairs': [['', '(:)', '(:),<:>'], ['xxx']],
+ \ 'messagesopt': [['hit-enter,history:1', 'hit-enter,history:10000',
+ \ 'history:100,wait:100', 'history:0,wait:0',
+ \ 'hit-enter,history:1,wait:1'],
+ \ ['xxx', 'history:500', 'hit-enter,history:-1',
+ \ 'hit-enter,history:10001', 'history:0,wait:10001',
+ \ 'hit-enter', 'history:10,wait:99999999999999999999',
+ \ 'history:99999999999999999999,wait:10', 'wait:10',
+ \ 'history:-10', 'history:10,wait:-10']],
\ 'mkspellmem': [['10000,100,12'], ['', 'xxx', '10000,100']],
\ 'mouse': [['', 'n', 'v', 'i', 'c', 'h', 'a', 'r', 'nvi'],
\ ['xxx', 'n,v,i']],
- \ 'mousemodel': [['', 'extend', 'popup', 'popup_setpos'], ['xxx']],
+ \ 'mousemodel': [['extend', 'popup', 'popup_setpos'], ['xxx']],
\ 'mouseshape': [['', 'n:arrow'], ['xxx']],
\ 'nrformats': [['', 'alpha', 'octal', 'hex', 'bin', 'unsigned', 'blank',
\ 'alpha,hex,bin'],
@@ -292,7 +301,7 @@ let test_values = {
\ 'sessionoptions': [['', 'blank', 'curdir', 'sesdir',
\ 'help,options,slash'],
\ ['xxx', 'curdir,sesdir']],
- \ 'showcmdloc': [['', 'last', 'statusline', 'tabline'], ['xxx']],
+ \ 'showcmdloc': [['last', 'statusline', 'tabline'], ['xxx']],
"\ 'signcolumn': [['', 'auto', 'no', 'yes', 'number'], ['xxx', 'no,yes']],
\ 'spellfile': [['', 'file.en.add', 'xxx.en.add,yyy.gb.add,zzz.ja.add',
\ '/tmp/dir\ with\ space/en.utf-8.add',
@@ -304,7 +313,7 @@ let test_values = {
\ 'spellsuggest': [['', 'best', 'double', 'fast', '100', 'timeout:100',
\ 'timeout:-1', 'file:/tmp/file', 'expr:Func()', 'double,33'],
\ ['xxx', '-1', 'timeout:', 'best,double', 'double,fast']],
- \ 'splitkeep': [['', 'cursor', 'screen', 'topline'], ['xxx']],
+ \ 'splitkeep': [['cursor', 'screen', 'topline'], ['xxx']],
\ 'statusline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']],
"\ 'swapsync': [['', 'sync', 'fsync'], ['xxx']],
\ 'switchbuf': [['', 'useopen', 'usetab', 'split', 'vsplit', 'newtab',
diff --git a/test/old/testdir/runnvim.vim b/test/old/testdir/runnvim.vim
index 578614c8a1..f5945aeaee 100644
--- a/test/old/testdir/runnvim.vim
+++ b/test/old/testdir/runnvim.vim
@@ -8,6 +8,7 @@ function s:logger.on_exit(id, data, event)
endfunction
let s:logger.env = #{VIMRUNTIME: $VIMRUNTIME}
+let s:logger.term = v:true
" Replace non-printable chars by special sequence, or "<%x>".
let s:escaped_char = {"\n": '\n', "\r": '\r', "\t": '\t'}
@@ -25,7 +26,7 @@ function Main()
set lines=25
set columns=80
enew
- let job = termopen(args, s:logger)
+ let job = jobstart(args, s:logger)
let results = jobwait([job], 5 * 60 * 1000)
" TODO(ZyX-I): Get colors
let screen = getline(1, '$')
diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim
index 058635c332..3d210695c4 100644
--- a/test/old/testdir/runtest.vim
+++ b/test/old/testdir/runtest.vim
@@ -55,6 +55,10 @@ silent! endwhile
" In the GUI we can always change the screen size.
if has('gui_running')
+ if has('gui_gtk')
+ " to keep screendump size unchanged
+ set guifont=Monospace\ 10
+ endif
set columns=80 lines=25
endif
diff --git a/test/old/testdir/setup.vim b/test/old/testdir/setup.vim
index e7b4bb1a88..61596fc83a 100644
--- a/test/old/testdir/setup.vim
+++ b/test/old/testdir/setup.vim
@@ -1,6 +1,5 @@
if exists('s:did_load')
" Align Nvim defaults to Vim.
- set backspace=
set commentstring=/*\ %s\ */
set complete=.,w,b,u,t,i
set define=^\\s*#\\s*define
@@ -66,7 +65,7 @@ mapclear
mapclear!
aunmenu *
tlunmenu *
-autocmd! nvim_popupmenu
+autocmd! nvim.popupmenu
" Undo the 'grepprg' and 'grepformat' setting in _defaults.lua.
set grepprg& grepformat&
diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim
index 64599c869a..d5f7c928de 100644
--- a/test/old/testdir/test_autocmd.vim
+++ b/test/old/testdir/test_autocmd.vim
@@ -1198,8 +1198,8 @@ func Test_OptionSet()
call assert_equal(g:opt[0], g:opt[1])
" 14: Setting option backspace through :let"
- let g:options = [['backspace', '', '', '', 'eol,indent,start', 'global', 'set']]
- let &bs = "eol,indent,start"
+ let g:options = [['backspace', 'indent,eol,start', 'indent,eol,start', 'indent,eol,start', '', 'global', 'set']]
+ let &bs = ''
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
@@ -4181,4 +4181,28 @@ func Test_autocmd_BufWinLeave_with_vsp()
exe "bw! " .. dummy
endfunc
+func Test_OptionSet_cmdheight()
+ set mouse=a laststatus=2
+ au OptionSet cmdheight :let &l:ch = v:option_new
+
+ resize -1
+ call assert_equal(2, &l:ch)
+ resize +1
+ call assert_equal(1, &l:ch)
+
+ call Ntest_setmouse(&lines - 1, 1)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call Ntest_setmouse(&lines - 2, 1)
+ call feedkeys("\<LeftDrag>", 'xt')
+ call assert_equal(2, &l:ch)
+
+ tabnew | resize +1
+ call assert_equal(1, &l:ch)
+ tabfirst
+ call assert_equal(2, &l:ch)
+
+ tabonly
+ set cmdheight& mouse& laststatus&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_bufwintabinfo.vim b/test/old/testdir/test_bufwintabinfo.vim
index 57492e07c9..0a4bd0b674 100644
--- a/test/old/testdir/test_bufwintabinfo.vim
+++ b/test/old/testdir/test_bufwintabinfo.vim
@@ -114,6 +114,18 @@ func Test_getbufwintabinfo()
wincmd t | only
endfunc
+function Test_get_wininfo_leftcol()
+ set nowrap
+ set winwidth=10
+ vsp
+ call setline(1, ['abcdefghijklmnopqrstuvwxyz'])
+ norm! 5zl
+ call assert_equal(5, getwininfo()[0].leftcol)
+ bwipe!
+ set wrap&
+ set winwidth&
+endfunc
+
function Test_get_buf_options()
let opts = bufnr()->getbufvar('&')
call assert_equal(v:t_dict, type(opts))
diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim
index 290af4a4ca..d4ad63d43e 100644
--- a/test/old/testdir/test_cmdline.vim
+++ b/test/old/testdir/test_cmdline.vim
@@ -291,8 +291,8 @@ func Test_changing_cmdheight()
call term_sendkeys(buf, ":resize -3\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_1', {})
- " using the space available doesn't change the status line
- call term_sendkeys(buf, ":set cmdheight+=3\<CR>")
+ " :resize now also changes 'cmdheight' accordingly
+ call term_sendkeys(buf, ":set cmdheight+=1\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_2', {})
" using more space moves the status line up
@@ -300,10 +300,10 @@ func Test_changing_cmdheight()
call VerifyScreenDump(buf, 'Test_changing_cmdheight_3', {})
" reducing cmdheight moves status line down
- call term_sendkeys(buf, ":set cmdheight-=2\<CR>")
+ call term_sendkeys(buf, ":set cmdheight-=3\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_4', {})
- " reducing window size and then setting cmdheight
+ " reducing window size and then setting cmdheight
call term_sendkeys(buf, ":resize -1\<CR>")
call term_sendkeys(buf, ":set cmdheight=1\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_5', {})
@@ -316,6 +316,10 @@ func Test_changing_cmdheight()
call term_sendkeys(buf, ":call EchoOne()\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_7', {})
+ " window commands do not reduce 'cmdheight' to value lower than :set by user
+ call term_sendkeys(buf, "\<CR>:wincmd _\<CR>")
+ call VerifyScreenDump(buf, 'Test_changing_cmdheight_8', {})
+
" clean up
call StopVimInTerminal(buf)
endfunc
@@ -4036,6 +4040,27 @@ func Test_rulerformat_position()
call StopVimInTerminal(buf)
endfunc
+" Test for using "%!" in 'rulerformat' to use a function
+func Test_rulerformat_function()
+ CheckScreendump
+
+ let lines =<< trim END
+ func TestRulerFn()
+ return '10,20%=30%%'
+ endfunc
+ END
+ call writefile(lines, 'Xrulerformat_function', 'D')
+
+ let buf = RunVimInTerminal('-S Xrulerformat_function', #{rows: 2, cols: 40})
+ call term_sendkeys(buf, ":set ruler rulerformat=%!TestRulerFn()\<CR>")
+ call term_sendkeys(buf, ":redraw!\<CR>")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_rulerformat_function', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_getcompletion_usercmd()
command! -nargs=* -complete=command TestCompletion echo <q-args>
diff --git a/test/old/testdir/test_compiler.vim b/test/old/testdir/test_compiler.vim
index 07b57b76d9..1310cbadfc 100644
--- a/test/old/testdir/test_compiler.vim
+++ b/test/old/testdir/test_compiler.vim
@@ -18,6 +18,8 @@ func Test_compiler()
endif
e Xfoo.pl
+ " Play nice with other tests.
+ defer setqflist([])
compiler perl
call assert_equal('perl', b:current_compiler)
call assert_fails('let g:current_compiler', 'E121:')
@@ -65,10 +67,10 @@ func Test_compiler_completion()
call assert_match('^"compiler ' .. clist .. '$', @:)
call feedkeys(":compiler p\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('"compiler pandoc pbx perl\( p[a-z_]\+\)\+ pylint pyunit', @:)
+ call assert_match('"compiler pandoc pbx perl\( p[a-z_]\+\)\+ pyunit', @:)
call feedkeys(":compiler! p\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('"compiler! pandoc pbx perl\( p[a-z_]\+\)\+ pylint pyunit', @:)
+ call assert_match('"compiler! pandoc pbx perl\( p[a-z_]\+\)\+ pyunit', @:)
endfunc
func Test_compiler_error()
@@ -78,3 +80,634 @@ func Test_compiler_error()
call assert_fails('compiler! doesnotexist', 'E666:')
unlet! g:current_compiler
endfunc
+
+func s:SpotBugsParseFilterMakePrg(dirname, makeprg)
+ let result = {}
+ let result.sourcepath = ''
+ let result.classfiles = []
+
+ " Get the argument after the rightmost occurrence of "-sourcepath".
+ let offset = strridx(a:makeprg, '-sourcepath')
+ if offset < 0
+ return result
+ endif
+ let offset += 1 + strlen('-sourcepath')
+ let result.sourcepath = matchstr(strpart(a:makeprg, offset), '.\{-}\ze[ \t]')
+ let offset += 1 + strlen(result.sourcepath)
+
+ " Get the class file arguments, dropping the pathname prefix.
+ let offset = stridx(a:makeprg, a:dirname, offset)
+ if offset < 0
+ return result
+ endif
+
+ while offset > -1
+ let candidate = matchstr(a:makeprg, '[^ \t]\{-}\.class\>', offset)
+ if empty(candidate)
+ break
+ endif
+ call add(result.classfiles, candidate)
+ let offset = stridx(a:makeprg, a:dirname, (1 + strlen(candidate) + offset))
+ endwhile
+
+ call sort(result.classfiles)
+ return result
+endfunc
+
+func Test_compiler_spotbugs_makeprg()
+ let save_shellslash = &shellslash
+ set shellslash
+
+ call assert_true(mkdir('Xspotbugs/src/tests/α/β/γ/δ', 'pR'))
+ call assert_true(mkdir('Xspotbugs/tests/α/β/γ/δ', 'pR'))
+
+ let lines =<< trim END
+ // EOL comment. /*
+ abstract class
+ 𐌂1 /* Multiline comment. */ {
+ /* Multiline comment. */ // EOL comment. /*
+ static final String COMMENT_A_LIKE = "/*";
+ { new Object() {/* Try globbing. */}; }
+ static { interface 𐌉𐌉1 {} }
+ static class 𐌂11 { interface 𐌉𐌉2 {} }
+ }
+ /* Multiline comment. */ // EOL comment. /*
+ final class 𐌂2 {
+ public static void main(String... aa) {
+ record 𐌓() {}
+ enum 𐌄 {}
+ }
+ } // class
+ END
+
+ " THE EXPECTED RESULTS.
+ let results = {}
+ let results['Xspotbugs/src/tests/𐌂1.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/𐌂1.java',
+ \ ':p:h:S')},
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/𐌂1$1.class',
+ \ 'Xspotbugs/tests/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/𐌂1.class',
+ \ 'Xspotbugs/tests/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/𐌂2.class']),
+ \ }
+ " No class file for an empty source file even with "-Xpkginfo:always".
+ let results['Xspotbugs/src/tests/package-info.java'] = {
+ \ 'Sourcepath': {-> ''},
+ \ 'classfiles': [],
+ \ }
+ let results['Xspotbugs/src/tests/α/𐌂1.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/𐌂1.java',
+ \ ':p:h:h:S')},
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/𐌂1.class',
+ \ 'Xspotbugs/tests/α/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/package-info.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/package-info.java',
+ \ ':p:h:S')},
+ \ 'classfiles': ['Xspotbugs/tests/α/package-info.class'],
+ \ }
+ let results['Xspotbugs/src/tests/α/β/𐌂1.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/𐌂1.java',
+ \ ':p:h:h:h:S')},
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/β/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/β/𐌂1.class',
+ \ 'Xspotbugs/tests/α/β/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/β/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/β/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/β/package-info.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/package-info.java',
+ \ ':p:h:S')},
+ \ 'classfiles': ['Xspotbugs/tests/α/β/package-info.class'],
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/𐌂1.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/𐌂1.java',
+ \ ':p:h:h:h:h:S')},
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂1.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/β/γ/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/package-info.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/package-info.java',
+ \ ':p:h:S')},
+ \ 'classfiles': ['Xspotbugs/tests/α/β/γ/package-info.class'],
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/δ/𐌂1.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/δ/𐌂1.java',
+ \ ':p:h:h:h:h:h:S')},
+ \ 'classfiles': sort([
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$1.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$1𐌉𐌉1.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$𐌂11$𐌉𐌉2.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1$𐌂11.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂1.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2$1𐌄.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2$1𐌓.class',
+ \ 'Xspotbugs/tests/α/β/γ/δ/𐌂2.class']),
+ \ }
+ let results['Xspotbugs/src/tests/α/β/γ/δ/package-info.java'] = {
+ \ 'Sourcepath': {-> fnamemodify('Xspotbugs/src/tests/α/β/γ/δ/package-info.java',
+ \ ':p:h:S')},
+ \ 'classfiles': ['Xspotbugs/tests/α/β/γ/δ/package-info.class'],
+ \ }
+
+ " MAKE CLASS FILES DISCOVERABLE!
+ let g:spotbugs_properties = {
+ \ 'sourceDirPath': ['src/tests'],
+ \ 'classDirPath': ['tests'],
+ \ }
+
+ call assert_true(has_key(s:SpotBugsParseFilterMakePrg('Xspotbugs', ''), 'sourcepath'))
+ call assert_true(has_key(s:SpotBugsParseFilterMakePrg('Xspotbugs', ''), 'classfiles'))
+
+ " Write 45 mock-up class files for 10 source files.
+ for [class_dir, src_dir, package] in [
+ \ ['Xspotbugs/tests/', 'Xspotbugs/src/tests/', ''],
+ \ ['Xspotbugs/tests/α/', 'Xspotbugs/src/tests/α/', 'package α;'],
+ \ ['Xspotbugs/tests/α/β/', 'Xspotbugs/src/tests/α/β/', 'package α.β;'],
+ \ ['Xspotbugs/tests/α/β/γ/', 'Xspotbugs/src/tests/α/β/γ/', 'package α.β.γ;'],
+ \ ['Xspotbugs/tests/α/β/γ/δ/', 'Xspotbugs/src/tests/α/β/γ/δ/', 'package α.β.γ.δ;']]
+ for class_file in ['𐌂1$1.class', '𐌂1$1𐌉𐌉1.class', '𐌂1$𐌂11$𐌉𐌉2.class',
+ \ '𐌂1$𐌂11.class', '𐌂1.class', '𐌂2$1𐌄.class', '𐌂2$1𐌓.class', '𐌂2.class']
+ call writefile(0zcafe.babe.0000.0041, class_dir .. class_file)
+ endfor
+ call writefile(0zcafe.babe.0000.0041, class_dir .. 'package-info.class')
+
+ " Write Java source files.
+ let type_file = src_dir .. '𐌂1.java'
+ call writefile(insert(copy(lines), package), type_file)
+ let package_file = src_dir .. 'package-info.java'
+ call writefile([package], src_dir .. 'package-info.java')
+
+ " Note that using "off" for the first _outer_ iteration is preferable
+ " because only then "hlexists()" may be 0 (see "compiler/spotbugs.vim").
+ for s in ['off', 'on']
+ execute 'syntax ' .. s
+
+ execute 'edit ' .. type_file
+ compiler spotbugs
+ let result = s:SpotBugsParseFilterMakePrg('Xspotbugs', &l:makeprg)
+ call assert_equal(results[type_file].Sourcepath(), result.sourcepath)
+ call assert_equal(results[type_file].classfiles, result.classfiles)
+ bwipeout
+
+ execute 'edit ' .. package_file
+ compiler spotbugs
+ let result = s:SpotBugsParseFilterMakePrg('Xspotbugs', &l:makeprg)
+ call assert_equal(results[package_file].Sourcepath(), result.sourcepath)
+ call assert_equal(results[package_file].classfiles, result.classfiles)
+ bwipeout
+ endfor
+ endfor
+
+ let &shellslash = save_shellslash
+endfunc
+
+func s:SpotBugsBeforeFileTypeTryPluginAndClearCache(state)
+ " Ponder over "extend(spotbugs#DefaultProperties(), g:spotbugs_properties)"
+ " in "ftplugin/java.vim".
+ let g:spotbugs#state = a:state
+ runtime autoload/spotbugs.vim
+endfunc
+
+func Test_compiler_spotbugs_properties()
+ let save_shellslash = &shellslash
+ set shellslash
+ setlocal makeprg=
+ filetype plugin on
+
+ call assert_true(mkdir('Xspotbugs/src', 'pR'))
+ call assert_true(mkdir('Xspotbugs/tests', 'pR'))
+ let type_file = 'Xspotbugs/src/𐌄.java'
+ let test_file = 'Xspotbugs/tests/𐌄$.java'
+ call writefile(['enum 𐌄{}'], type_file)
+ call writefile(['class 𐌄${}'], test_file)
+
+ " TEST INTEGRATION WITH A BOGUS COMPILER PLUGIN.
+ if !filereadable($VIMRUNTIME .. '/compiler/foo.vim') && !executable('foo')
+ let g:spotbugs_properties = {'compiler': 'foo'}
+ " XXX: In case this "if" block is no longer first.
+ call s:SpotBugsBeforeFileTypeTryPluginAndClearCache({
+ \ 'compiler': g:spotbugs_properties.compiler,
+ \ })
+ execute 'edit ' .. type_file
+ call assert_equal('java', &l:filetype)
+ " This variable will indefinitely keep the compiler name.
+ call assert_equal('foo', g:spotbugs#state.compiler)
+ " The "compiler" entry should be gone after FileType and default entries
+ " should only appear for a supported compiler.
+ call assert_false(has_key(g:spotbugs_properties, 'compiler'))
+ call assert_true(empty(g:spotbugs_properties))
+ " Query default implementations.
+ call assert_true(exists('*spotbugs#DefaultProperties'))
+ call assert_true(exists('*spotbugs#DefaultPreCompilerAction'))
+ call assert_true(exists('*spotbugs#DefaultPreCompilerTestAction'))
+ call assert_true(empty(spotbugs#DefaultProperties()))
+ " Get a ":message".
+ redir => out
+ call spotbugs#DefaultPreCompilerAction()
+ redir END
+ call assert_equal('Not supported: "foo"', out[stridx(out, 'Not') :])
+ " Get a ":message".
+ redir => out
+ call spotbugs#DefaultPreCompilerTestAction()
+ redir END
+ call assert_equal('Not supported: "foo"', out[stridx(out, 'Not') :])
+ " No ":autocmd"s without one of "PreCompiler*Action", "PostCompilerAction".
+ call assert_false(exists('#java_spotbugs'))
+ bwipeout
+ endif
+
+ let s:spotbugs_results = {
+ \ 'preActionDone': 0,
+ \ 'preTestActionDone': 0,
+ \ 'preTestLocalActionDone': 0,
+ \ 'postActionDone': 0,
+ \ 'preCommandArguments': '',
+ \ 'preTestCommandArguments': '',
+ \ 'postCommandArguments': '',
+ \ }
+ defer execute('unlet s:spotbugs_results')
+
+ func! g:SpotBugsPreAction() abort
+ let s:spotbugs_results.preActionDone = 1
+ " XXX: Notify the spotbugs compiler about success or failure.
+ cc
+ endfunc
+ defer execute('delfunction g:SpotBugsPreAction')
+
+ func! g:SpotBugsPreTestAction() abort
+ let s:spotbugs_results.preTestActionDone = 1
+ " XXX: Let see compilation fail.
+ throw 'Oops'
+ endfunc
+ defer execute('delfunction g:SpotBugsPreTestAction')
+
+ func! g:SpotBugsPreTestLocalAction() abort
+ let s:spotbugs_results.preTestLocalActionDone = 1
+ " XXX: Notify the spotbugs compiler about success or failure.
+ cc
+ endfunc
+ defer execute('delfunction g:SpotBugsPreTestLocalAction')
+
+ func! g:SpotBugsPostAction() abort
+ let s:spotbugs_results.postActionDone = 1
+ endfunc
+ defer execute('delfunction g:SpotBugsPostAction')
+
+ func! g:SpotBugsPreCommand(arguments) abort
+ let s:spotbugs_results.preActionDone = 1
+ let s:spotbugs_results.preCommandArguments = a:arguments
+ " XXX: Notify the spotbugs compiler about success or failure.
+ cc
+ endfunc
+ defer execute('delfunction g:SpotBugsPreCommand')
+
+ func! g:SpotBugsPreTestCommand(arguments) abort
+ let s:spotbugs_results.preTestActionDone = 1
+ let s:spotbugs_results.preTestCommandArguments = a:arguments
+ " XXX: Notify the spotbugs compiler about success or failure.
+ cc
+ endfunc
+ defer execute('delfunction g:SpotBugsPreTestCommand')
+
+ func! g:SpotBugsPostCommand(arguments) abort
+ let s:spotbugs_results.postActionDone = 1
+ let s:spotbugs_results.postCommandArguments = a:arguments
+ endfunc
+ defer execute('delfunction g:SpotBugsPostCommand')
+
+ func! g:SpotBugsPostCompilerActionExecutor(action) abort
+ try
+ " XXX: Notify the spotbugs compiler about success or failure.
+ cc
+ catch /\<E42:/
+ execute a:action
+ endtry
+ endfunc
+ defer execute('delfunction g:SpotBugsPostCompilerActionExecutor')
+
+ " TEST INTEGRATION WITH A SUPPORTED COMPILER PLUGIN.
+ if filereadable($VIMRUNTIME .. '/compiler/maven.vim')
+ let save_PATH = $PATH
+ if !executable('mvn')
+ if has('win32')
+ let $PATH = 'Xspotbugs;' .. $PATH
+ " This is what ":help executable()" suggests.
+ call writefile([], 'Xspotbugs/mvn.cmd')
+ else
+ let $PATH = 'Xspotbugs:' .. $PATH
+ call writefile([], 'Xspotbugs/mvn')
+ call setfperm('Xspotbugs/mvn', 'rwx------')
+ endif
+ endif
+
+ let g:spotbugs_properties = {
+ \ 'compiler': 'maven',
+ \ 'PreCompilerAction': function('g:SpotBugsPreAction'),
+ \ 'PreCompilerTestAction': function('g:SpotBugsPreTestAction'),
+ \ 'PostCompilerAction': function('g:SpotBugsPostAction'),
+ \ }
+ " XXX: In case this is a runner-up ":edit".
+ call s:SpotBugsBeforeFileTypeTryPluginAndClearCache({
+ \ 'compiler': g:spotbugs_properties.compiler,
+ \ })
+ execute 'edit ' .. type_file
+ call assert_equal('java', &l:filetype)
+ call assert_equal('maven', g:spotbugs#state.compiler)
+ call assert_false(has_key(g:spotbugs_properties, 'compiler'))
+ call assert_false(empty(g:spotbugs_properties))
+ " Query default implementations.
+ call assert_true(exists('*spotbugs#DefaultProperties'))
+ call assert_equal(sort([
+ \ 'PreCompilerAction',
+ \ 'PreCompilerTestAction',
+ \ 'PostCompilerAction',
+ \ 'sourceDirPath',
+ \ 'classDirPath',
+ \ 'testSourceDirPath',
+ \ 'testClassDirPath',
+ \ ]),
+ \ sort(keys(spotbugs#DefaultProperties())))
+ " Some ":autocmd"s with one of "PreCompiler*Action", "PostCompilerAction".
+ call assert_true(exists('#java_spotbugs'))
+ call assert_true(exists('#java_spotbugs#Syntax'))
+ call assert_true(exists('#java_spotbugs#User'))
+ call assert_equal(2, exists(':SpotBugsDefineBufferAutocmd'))
+ " SpotBugsDefineBufferAutocmd SigUSR1 User SigUSR1 User SigUSR1 User
+ " call assert_true(exists('#java_spotbugs#SigUSR1'))
+ SpotBugsDefineBufferAutocmd Signal User Signal User Signal User
+ call assert_true(exists('#java_spotbugs#Signal'))
+ call assert_true(exists('#java_spotbugs#Syntax'))
+ call assert_true(exists('#java_spotbugs#User'))
+ call assert_equal(2, exists(':SpotBugsRemoveBufferAutocmd'))
+ " SpotBugsRemoveBufferAutocmd SigUSR1 User SigUSR1 User UserGettingBored
+ " call assert_false(exists('#java_spotbugs#SigUSR1'))
+ SpotBugsRemoveBufferAutocmd Signal User Signal User UserGettingBored
+ call assert_false(exists('#java_spotbugs#Signal'))
+ call assert_true(exists('#java_spotbugs#Syntax'))
+ call assert_true(exists('#java_spotbugs#User'))
+
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+
+ doautocmd java_spotbugs Syntax
+ call assert_false(exists('#java_spotbugs#Syntax'))
+
+ " No match: "type_file !~# 'src/main/java'".
+ call assert_false(s:spotbugs_results.preActionDone)
+ " No match: "type_file !~# 'src/test/java'".
+ call assert_false(s:spotbugs_results.preTestActionDone)
+ " No pre-match, no post-action.
+ call assert_false(s:spotbugs_results.postActionDone)
+ " Without a match, confirm that ":compiler spotbugs" has NOT run.
+ call assert_true(empty(&l:makeprg))
+
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+ " Update path entries. (Note that we cannot use just "src" because there
+ " is another "src" directory nearer the filesystem root directory, i.e.
+ " "vim/vim/src/testdir/Xspotbugs/src", and "s:DispatchAction()" (see
+ " "ftplugin/java.vim") will match "vim/vim/src/testdir/Xspotbugs/tests"
+ " against "src".)
+ let g:spotbugs_properties.sourceDirPath = ['Xspotbugs/src']
+ let g:spotbugs_properties.classDirPath = ['Xspotbugs/src']
+ let g:spotbugs_properties.testSourceDirPath = ['tests']
+ let g:spotbugs_properties.testClassDirPath = ['tests']
+
+ doautocmd java_spotbugs User
+ " No match: "type_file !~# 'src/main/java'" (with old "*DirPath" values
+ " cached).
+ call assert_false(s:spotbugs_results.preActionDone)
+ " No match: "type_file !~# 'src/test/java'" (with old "*DirPath" values
+ " cached).
+ call assert_false(s:spotbugs_results.preTestActionDone)
+ " No pre-match, no post-action.
+ call assert_false(s:spotbugs_results.postActionDone)
+ " Without a match, confirm that ":compiler spotbugs" has NOT run.
+ call assert_true(empty(&l:makeprg))
+
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+ " XXX: Re-build ":autocmd"s from scratch with new values applied.
+ doautocmd FileType
+
+ call assert_true(exists('b:spotbugs_syntax_once'))
+ doautocmd java_spotbugs User
+ " A match: "type_file =~# 'Xspotbugs/src'" (with new "*DirPath" values
+ " cached).
+ call assert_true(s:spotbugs_results.preActionDone)
+ " No match: "type_file !~# 'tests'" (with new "*DirPath" values cached).
+ call assert_false(s:spotbugs_results.preTestActionDone)
+ " For a pre-match, a post-action.
+ call assert_true(s:spotbugs_results.postActionDone)
+
+ " With a match, confirm that ":compiler spotbugs" has run.
+ if has('win32')
+ call assert_match('^spotbugs\.bat\s', &l:makeprg)
+ else
+ call assert_match('^spotbugs\s', &l:makeprg)
+ endif
+
+ bwipeout
+ setlocal makeprg=
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionDone = 0
+ let s:spotbugs_results.preTestLocalActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+
+ execute 'edit ' .. test_file
+ " Prepare a buffer-local, incomplete variant of properties, relying on
+ " "ftplugin/java.vim" to take care of merging in unique entries, if any,
+ " from "g:spotbugs_properties".
+ let b:spotbugs_properties = {
+ \ 'PreCompilerTestAction': function('g:SpotBugsPreTestLocalAction'),
+ \ }
+ call assert_equal('java', &l:filetype)
+ call assert_true(exists('#java_spotbugs'))
+ call assert_true(exists('#java_spotbugs#Syntax'))
+ call assert_true(exists('#java_spotbugs#User'))
+ call assert_fails('doautocmd java_spotbugs Syntax', 'Oops')
+ call assert_false(exists('#java_spotbugs#Syntax'))
+ " No match: "test_file !~# 'Xspotbugs/src'".
+ call assert_false(s:spotbugs_results.preActionDone)
+ " A match: "test_file =~# 'tests'".
+ call assert_true(s:spotbugs_results.preTestActionDone)
+ call assert_false(s:spotbugs_results.preTestLocalActionDone)
+ " No action after pre-failure (the thrown "Oops" doesn't qualify for ":cc").
+ call assert_false(s:spotbugs_results.postActionDone)
+ " No ":compiler spotbugs" will be run after pre-failure.
+ call assert_true(empty(&l:makeprg))
+
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionDone = 0
+ let s:spotbugs_results.preTestLocalActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+ " XXX: Re-build ":autocmd"s from scratch with buffer-local values applied.
+ doautocmd FileType
+
+ call assert_true(exists('b:spotbugs_syntax_once'))
+ doautocmd java_spotbugs User
+ " No match: "test_file !~# 'Xspotbugs/src'".
+ call assert_false(s:spotbugs_results.preActionDone)
+ " A match: "test_file =~# 'tests'".
+ call assert_true(s:spotbugs_results.preTestLocalActionDone)
+ call assert_false(s:spotbugs_results.preTestActionDone)
+ " For a pre-match, a post-action.
+ call assert_true(s:spotbugs_results.postActionDone)
+
+ " With a match, confirm that ":compiler spotbugs" has run.
+ if has('win32')
+ call assert_match('^spotbugs\.bat\s', &l:makeprg)
+ else
+ call assert_match('^spotbugs\s', &l:makeprg)
+ endif
+
+ setlocal makeprg=
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionDone = 0
+ let s:spotbugs_results.preTestLocalActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+ let s:spotbugs_results.preCommandArguments = ''
+ let s:spotbugs_results.preTestCommandArguments = ''
+ let s:spotbugs_results.postCommandArguments = ''
+ " XXX: Compose the assigned "*Command"s with the default Maven "*Action"s.
+ let b:spotbugs_properties = {
+ \ 'compiler': 'maven',
+ \ 'DefaultPreCompilerTestCommand': function('g:SpotBugsPreTestCommand'),
+ \ 'DefaultPreCompilerCommand': function('g:SpotBugsPreCommand'),
+ \ 'DefaultPostCompilerCommand': function('g:SpotBugsPostCommand'),
+ \ 'PostCompilerActionExecutor': function('g:SpotBugsPostCompilerActionExecutor'),
+ \ 'augroupForPostCompilerAction': 'java_spotbugs_test',
+ \ 'sourceDirPath': ['Xspotbugs/src'],
+ \ 'classDirPath': ['Xspotbugs/src'],
+ \ 'testSourceDirPath': ['tests'],
+ \ 'testClassDirPath': ['tests'],
+ \ }
+ unlet g:spotbugs_properties
+ " XXX: Re-build ":autocmd"s from scratch with buffer-local values applied.
+ call s:SpotBugsBeforeFileTypeTryPluginAndClearCache({
+ \ 'compiler': b:spotbugs_properties.compiler,
+ \ 'commands': {
+ \ 'DefaultPreCompilerTestCommand':
+ \ b:spotbugs_properties.DefaultPreCompilerTestCommand,
+ \ 'DefaultPreCompilerCommand':
+ \ b:spotbugs_properties.DefaultPreCompilerCommand,
+ \ 'DefaultPostCompilerCommand':
+ \ b:spotbugs_properties.DefaultPostCompilerCommand,
+ \ },
+ \ })
+ doautocmd FileType
+
+ call assert_equal('maven', g:spotbugs#state.compiler)
+ call assert_equal(sort([
+ \ 'DefaultPreCompilerTestCommand',
+ \ 'DefaultPreCompilerCommand',
+ \ 'DefaultPostCompilerCommand',
+ \ ]),
+ \ sort(keys(g:spotbugs#state.commands)))
+ call assert_true(exists('b:spotbugs_syntax_once'))
+ doautocmd java_spotbugs User
+ " No match: "test_file !~# 'Xspotbugs/src'".
+ call assert_false(s:spotbugs_results.preActionDone)
+ call assert_true(empty(s:spotbugs_results.preCommandArguments))
+ " A match: "test_file =~# 'tests'".
+ call assert_true(s:spotbugs_results.preTestActionDone)
+ call assert_equal('test-compile', s:spotbugs_results.preTestCommandArguments)
+ " For a pre-match, a post-action.
+ call assert_true(s:spotbugs_results.postActionDone)
+ call assert_equal('%:S', s:spotbugs_results.postCommandArguments)
+
+ " With a match, confirm that ":compiler spotbugs" has run.
+ if has('win32')
+ call assert_match('^spotbugs\.bat\s', &l:makeprg)
+ else
+ call assert_match('^spotbugs\s', &l:makeprg)
+ endif
+
+ setlocal makeprg=
+ let s:spotbugs_results.preActionDone = 0
+ let s:spotbugs_results.preTestActionOtherDone = 0
+ let s:spotbugs_results.preTestLocalActionDone = 0
+ let s:spotbugs_results.postActionDone = 0
+ let s:spotbugs_results.preCommandArguments = ''
+ let s:spotbugs_results.preTestCommandArguments = ''
+ let s:spotbugs_results.postCommandArguments = ''
+
+ " When "PostCompilerActionExecutor", "Pre*Action" and/or "Pre*TestAction",
+ " and "Post*Action" are available, "#java_spotbugs_post" must be defined.
+ call assert_true(exists('#java_spotbugs_post'))
+ call assert_true(exists('#java_spotbugs_post#User'))
+ call assert_false(exists('#java_spotbugs_post#ShellCmdPost'))
+ call assert_false(exists('#java_spotbugs_test#ShellCmdPost'))
+
+ " Re-link a Funcref on the fly.
+ func! g:SpotBugsPreTestCommand(arguments) abort
+ let s:spotbugs_results.preTestActionOtherDone = 1
+ let s:spotbugs_results.preTestCommandArguments = a:arguments
+ " Define a once-only ":autocmd" for "#java_spotbugs_test#ShellCmdPost".
+ doautocmd java_spotbugs_post User
+ " XXX: Do NOT use ":cc" to notify the spotbugs compiler about success or
+ " failure, and assume the transfer of control to a ShellCmdPost command.
+ endfunc
+
+ doautocmd java_spotbugs User
+ " No match: "test_file !~# 'Xspotbugs/src'".
+ call assert_false(s:spotbugs_results.preActionDone)
+ call assert_true(empty(s:spotbugs_results.preCommandArguments))
+ " A match: "test_file =~# 'tests'".
+ call assert_true(s:spotbugs_results.preTestActionOtherDone)
+ call assert_equal('test-compile', s:spotbugs_results.preTestCommandArguments)
+ " For a pre-match, no post-action (without ":cc") UNLESS a ShellCmdPost
+ " event is consumed whose command will invoke "PostCompilerActionExecutor"
+ " and the latter will accept a post-compiler action argument.
+ call assert_false(s:spotbugs_results.postActionDone)
+ call assert_true(exists('#java_spotbugs_test#ShellCmdPost'))
+ doautocmd ShellCmdPost
+ call assert_false(exists('#java_spotbugs_test#ShellCmdPost'))
+ call assert_true(s:spotbugs_results.postActionDone)
+ call assert_equal('%:S', s:spotbugs_results.postCommandArguments)
+
+ " With a match, confirm that ":compiler spotbugs" has run.
+ if has('win32')
+ call assert_match('^spotbugs\.bat\s', &l:makeprg)
+ else
+ call assert_match('^spotbugs\s', &l:makeprg)
+ endif
+
+ bwipeout
+ setlocal makeprg=
+ let $PATH = save_PATH
+ endif
+
+ filetype plugin off
+ setlocal makeprg=
+ let &shellslash = save_shellslash
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_debugger.vim b/test/old/testdir/test_debugger.vim
index 3a469e8a17..5820b58247 100644
--- a/test/old/testdir/test_debugger.vim
+++ b/test/old/testdir/test_debugger.vim
@@ -6,10 +6,11 @@ source check.vim
func CheckCWD()
" Check that the longer lines don't wrap due to the length of the script name
- " in cwd
+ " in cwd. Need to subtract by 1 since Vim will still wrap the message if it
+ " just fits.
let script_len = len( getcwd() .. '/Xtest1.vim' )
let longest_line = len( 'Breakpoint in "" line 1' )
- if script_len > ( 75 - longest_line )
+ if script_len > ( 75 - longest_line - 1 )
throw 'Skipped: Your CWD has too many characters'
endif
endfunc
diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim
index 880286d329..ab64658bd0 100644
--- a/test/old/testdir/test_diffmode.vim
+++ b/test/old/testdir/test_diffmode.vim
@@ -1017,6 +1017,41 @@ func Test_diff_screen()
call WriteDiffFiles(buf, [], [0])
call VerifyBoth(buf, "Test_diff_22", "")
+ call WriteDiffFiles(buf, ['?a', '?b', '?c'], ['!b'])
+ call VerifyInternal(buf, 'Test_diff_23', " diffopt+=linematch:30")
+
+ call WriteDiffFiles(buf, ['',
+ \ 'common line',
+ \ 'common line',
+ \ '',
+ \ 'DEFabc',
+ \ 'xyz',
+ \ 'xyz',
+ \ 'xyz',
+ \ 'DEFabc',
+ \ 'DEFabc',
+ \ 'DEFabc',
+ \ 'common line',
+ \ 'common line',
+ \ 'DEF',
+ \ 'common line',
+ \ 'DEF',
+ \ 'something' ],
+ \ ['',
+ \ 'common line',
+ \ 'common line',
+ \ '',
+ \ 'ABCabc',
+ \ 'ABCabc',
+ \ 'ABCabc',
+ \ 'ABCabc',
+ \ 'common line',
+ \ 'common line',
+ \ 'common line',
+ \ 'something'])
+ call VerifyInternal(buf, 'Test_diff_24', " diffopt+=linematch:30")
+
+
" clean up
call StopVimInTerminal(buf)
call delete('Xdifile1')
@@ -1212,7 +1247,7 @@ func CloseoffSetup()
call setline(1, ['one', 'tow', 'three'])
diffthis
call assert_equal(1, &diff)
- only!
+ bw!
endfunc
func Test_diff_closeoff()
@@ -2004,6 +2039,12 @@ func Test_diff_overlapped_diff_blocks_will_be_merged()
call WriteDiffFiles3(buf, ["a", "b", "c"], ["a", "x", "c"], ["a", "b", "y", "c"])
call VerifyBoth(buf, "Test_diff_overlapped_3.37", "")
+ call WriteDiffFiles3(buf, ["a", "b", "c"], ["d", "e"], ["b", "f"])
+ call VerifyBoth(buf, "Test_diff_overlapped_3.38", "")
+
+ call WriteDiffFiles3(buf, ["a", "b", "c"], ["d", "e"], ["b"])
+ call VerifyBoth(buf, "Test_diff_overlapped_3.39", "")
+
call StopVimInTerminal(buf)
endfunc
@@ -2034,4 +2075,440 @@ func Test_diff_topline_noscroll()
call StopVimInTerminal(buf)
endfunc
+func Test_diffget_diffput_linematch()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call WriteDiffFiles(0, [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2', {})
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ " enable linematch
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call WriteDiffFiles(buf, ['',
+ \ 'common line',
+ \ 'common line',
+ \ '',
+ \ 'ABCabc',
+ \ 'ABCabc',
+ \ 'ABCabc',
+ \ 'ABCabc',
+ \ 'common line',
+ \ 'common line',
+ \ 'common line',
+ \ 'something' ],
+ \ ['',
+ \ 'common line',
+ \ 'common line',
+ \ '',
+ \ 'DEFabc',
+ \ 'xyz',
+ \ 'xyz',
+ \ 'xyz',
+ \ 'DEFabc',
+ \ 'DEFabc',
+ \ 'DEFabc',
+ \ 'common line',
+ \ 'common line',
+ \ 'DEF',
+ \ 'common line',
+ \ 'DEF',
+ \ 'something'])
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_1', {})
+
+ " get from window 1 from line 5 to 9
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, ":5,9diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_2', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get from window 2 from line 5 to 10
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, ":5,10diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_3', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get all from window 2
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, ":4,17diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_4', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get all from window 1
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, ":4,12diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_5', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get from window 1 using do 1 line 5
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "5gg")
+ call term_sendkeys(buf, ":diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_6', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get from window 1 using do 2 line 6
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "6gg")
+ call term_sendkeys(buf, ":diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_7', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get from window 1 using do 2 line 7
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "7gg")
+ call term_sendkeys(buf, ":diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_8', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get from window 1 using do 2 line 11
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "11gg")
+ call term_sendkeys(buf, ":diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_9', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " get from window 1 using do 2 line 12
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "12gg")
+ call term_sendkeys(buf, ":diffget\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_10', {})
+
+ " undo the last diffget
+ call term_sendkeys(buf, "u")
+
+ " put from window 1 using dp 1 line 5
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "5gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_11', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 1 using dp 2 line 6
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "6gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_12', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 1 using dp 2 line 7
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "7gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_13', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 1 using dp 2 line 11
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "11gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_14', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 1 using dp 2 line 12
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "12gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_15', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 2 using dp line 6
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "6gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_16', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 2 using dp line 8
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "8gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_17', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 2 using dp line 9
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "9gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_18', {})
+
+ " undo the last diffput
+ call term_sendkeys(buf, "1\<c-w>w")
+ call term_sendkeys(buf, "u")
+
+ " put from window 2 using dp line 17
+ call term_sendkeys(buf, "2\<c-w>w")
+ call term_sendkeys(buf, "17gg")
+ call term_sendkeys(buf, ":diffput\<CR>")
+ call VerifyScreenDump(buf, 'Test_diff_get_put_linematch_19', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_linematch_diff()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call WriteDiffFiles(0, [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2', {})
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ " enable linematch
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call WriteDiffFiles(buf, ['// abc d?',
+ \ '// d?',
+ \ '// d?' ],
+ \ ['!',
+ \ 'abc d!',
+ \ 'd!'])
+ call VerifyScreenDump(buf, 'Test_linematch_diff1', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_linematch_diff_iwhite()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call WriteDiffFiles(0, [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2', {})
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ " setup a diff with 2 files and set linematch:30, with ignore white
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call WriteDiffFiles(buf, ['void testFunction () {',
+ \ ' for (int i = 0; i < 10; i++) {',
+ \ ' for (int j = 0; j < 10; j++) {',
+ \ ' }',
+ \ ' }',
+ \ '}' ],
+ \ ['void testFunction () {',
+ \ ' // for (int j = 0; j < 10; i++) {',
+ \ ' // }',
+ \ '}'])
+ call VerifyScreenDump(buf, 'Test_linematch_diff_iwhite1', {})
+ call term_sendkeys(buf, ":set diffopt+=iwhiteall\<CR>")
+ call VerifyScreenDump(buf, 'Test_linematch_diff_iwhite2', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_linematch_diff_grouping()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call WriteDiffFiles(0, [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2', {})
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ " a diff that would result in multiple groups before grouping optimization
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call WriteDiffFiles(buf, ['!A',
+ \ '!B',
+ \ '!C' ],
+ \ ['?Z',
+ \ '?A',
+ \ '?B',
+ \ '?C',
+ \ '?A',
+ \ '?B',
+ \ '?B',
+ \ '?C'])
+ call VerifyScreenDump(buf, 'Test_linematch_diff_grouping1', {})
+ call WriteDiffFiles(buf, ['!A',
+ \ '!B',
+ \ '!C' ],
+ \ ['?A',
+ \ '?Z',
+ \ '?B',
+ \ '?C',
+ \ '?A',
+ \ '?B',
+ \ '?C',
+ \ '?C'])
+ call VerifyScreenDump(buf, 'Test_linematch_diff_grouping2', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_linematch_diff_scroll()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call WriteDiffFiles(0, [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2', {})
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ " a diff that would result in multiple groups before grouping optimization
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call WriteDiffFiles(buf, ['!A',
+ \ '!B',
+ \ '!C' ],
+ \ ['?A',
+ \ '?Z',
+ \ '?B',
+ \ '?C',
+ \ '?A',
+ \ '?B',
+ \ '?C',
+ \ '?C'])
+ " scroll down to show calculation of top fill and scroll to correct line in
+ " both windows
+ call VerifyScreenDump(buf, 'Test_linematch_diff_grouping_scroll0', {})
+ call term_sendkeys(buf, "3\<c-e>")
+ call VerifyScreenDump(buf, 'Test_linematch_diff_grouping_scroll1', {})
+ call term_sendkeys(buf, "3\<c-e>")
+ call VerifyScreenDump(buf, 'Test_linematch_diff_grouping_scroll2', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_linematch_line_limit_exceeded()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call WriteDiffFiles(0, [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2', {})
+ call term_sendkeys(buf, ":set autoread\<CR>\<c-w>w:set autoread\<CR>\<c-w>w")
+
+ call term_sendkeys(buf, ":set diffopt+=linematch:10\<CR>")
+ " a diff block will not be aligned with linematch because it's contents
+ " exceed 10 lines
+ call WriteDiffFiles(buf,
+ \ ['common line',
+ \ 'HIL',
+ \ '',
+ \ 'aABCabc',
+ \ 'aABCabc',
+ \ 'aABCabc',
+ \ 'aABCabc',
+ \ 'common line',
+ \ 'HIL',
+ \ 'common line',
+ \ 'something'],
+ \ ['common line',
+ \ 'DEF',
+ \ 'GHI',
+ \ 'something',
+ \ '',
+ \ 'aDEFabc',
+ \ 'xyz',
+ \ 'xyz',
+ \ 'xyz',
+ \ 'aDEFabc',
+ \ 'aDEFabc',
+ \ 'aDEFabc',
+ \ 'common line',
+ \ 'DEF',
+ \ 'GHI',
+ \ 'something else',
+ \ 'common line',
+ \ 'something'])
+ call VerifyScreenDump(buf, 'Test_linematch_line_limit_exceeded1', {})
+ " after increasing the count to 30, the limit is not exceeded, and the
+ " alignment algorithm will run on the largest diff block here
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call VerifyScreenDump(buf, 'Test_linematch_line_limit_exceeded2', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_linematch_3diffs()
+ CheckScreendump
+ call delete('.Xdifile1.swp')
+ call delete('.Xdifile2.swp')
+ call delete('.Xdifile3.swp')
+ call WriteDiffFiles3(0, [], [], [])
+ let buf = RunVimInTerminal('-d Xdifile1 Xdifile2 Xdifile3', {})
+ call term_sendkeys(buf, "1\<c-w>w:set autoread\<CR>")
+ call term_sendkeys(buf, "2\<c-w>w:set autoread\<CR>")
+ call term_sendkeys(buf, "3\<c-w>w:set autoread\<CR>")
+ call term_sendkeys(buf, ":set diffopt+=linematch:30\<CR>")
+ call WriteDiffFiles3(buf,
+ \ ["",
+ \ " common line",
+ \ " AAA",
+ \ " AAA",
+ \ " AAA"],
+ \ ["",
+ \ " common line",
+ \ " <<<<<<< HEAD",
+ \ " AAA",
+ \ " AAA",
+ \ " AAA",
+ \ " =======",
+ \ " BBB",
+ \ " BBB",
+ \ " BBB",
+ \ " >>>>>>> branch1"],
+ \ ["",
+ \ " common line",
+ \ " BBB",
+ \ " BBB",
+ \ " BBB"])
+ call VerifyScreenDump(buf, 'Test_linematch_3diffs1', {})
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+" this used to access invalid memory
+func Test_linematch_3diffs_sanity_check()
+ CheckScreendump
+ call delete('.Xfile_linematch1.swp')
+ call delete('.Xfile_linematch2.swp')
+ call delete('.Xfile_linematch3.swp')
+ let lines =<< trim END
+ set diffopt+=linematch:60
+ call feedkeys("Aq\<esc>")
+ call feedkeys("GAklm\<esc>")
+ call feedkeys("o")
+ END
+ call writefile(lines, 'Xlinematch_3diffs.vim', 'D')
+ call writefile(['abcd', 'def', 'hij'], 'Xfile_linematch1', 'D')
+ call writefile(['defq', 'hijk', 'nopq'], 'Xfile_linematch2', 'D')
+ call writefile(['hijklm', 'nopqr', 'stuv'], 'Xfile_linematch3', 'D')
+ call WriteDiffFiles3(0, [], [], [])
+ let buf = RunVimInTerminal('-d -S Xlinematch_3diffs.vim Xfile_linematch1 Xfile_linematch2 Xfile_linematch3', {})
+ call VerifyScreenDump(buf, 'Test_linematch_3diffs2', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_digraph.vim b/test/old/testdir/test_digraph.vim
index 8fbcd4d8ca..0a71cbba99 100644
--- a/test/old/testdir/test_digraph.vim
+++ b/test/old/testdir/test_digraph.vim
@@ -40,6 +40,9 @@ func Test_digraphs()
" Quadruple prime
call Put_Dig("'4")
call assert_equal("⁗", getline('.'))
+ " APPROACHES THE LIMIT
+ call Put_Dig(".=")
+ call assert_equal("≐", getline('.'))
" Not a digraph
call Put_Dig("a\<bs>")
call Put_Dig("\<bs>a")
@@ -250,9 +253,12 @@ func Test_digraphs_option()
call Put_Dig_BS("P","=")
call assert_equal(['Р']+repeat(["₽"],2)+['П'], getline(line('.')-3,line('.')))
" Not a digraph: this is different from <c-k>!
+ let _bs = &bs
+ set bs=
call Put_Dig_BS("a","\<bs>")
call Put_Dig_BS("\<bs>","a")
call assert_equal(['','a'], getline(line('.')-1,line('.')))
+ let &bs = _bs
" Grave
call Put_Dig_BS("a","!")
call Put_Dig_BS("!","e")
@@ -604,8 +610,10 @@ func Test_digraph_getlist_function()
" of digraphs returned.
call assert_equal(digraph_getlist()->len(), digraph_getlist(0)->len())
call assert_notequal(digraph_getlist()->len(), digraph_getlist(1)->len())
+ call assert_equal(digraph_getlist()->len(), digraph_getlist(v:false)->len())
+ call assert_notequal(digraph_getlist()->len(), digraph_getlist(v:true)->len())
- call assert_fails('call digraph_getlist(0z12)', 'E974: Using a Blob as a Number')
+ call assert_fails('call digraph_getlist(0z12)', 'E1212: Bool required for argument 1')
endfunc
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index 19b7d41552..9398cea786 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -108,12 +108,14 @@ func s:GetFilenameChecks() abort
\ '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'],
\ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file',
\ 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'],
+ \ 'apkbuild': ['APKBUILD'],
\ 'applescript': ['file.scpt'],
\ 'aptconf': ['apt.conf', '/.aptitude/config', 'any/.aptitude/config'],
\ 'arch': ['.arch-inventory', '=tagging-method'],
\ 'arduino': ['file.ino', 'file.pde'],
\ 'art': ['file.art'],
\ 'asciidoc': ['file.asciidoc', 'file.adoc'],
+ \ 'asm': ['file.s', 'file.S', 'file.a', 'file.A'],
\ 'asn': ['file.asn', 'file.asn1'],
\ 'asterisk': ['asterisk/file.conf', 'asterisk/file.conf-file', 'some-asterisk/file.conf', 'some-asterisk/file.conf-file'],
\ 'astro': ['file.astro'],
@@ -144,6 +146,7 @@ func s:GetFilenameChecks() abort
\ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE', 'WORKSPACE.bzlmod'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg', 'file.mdh', 'file.epro'],
+ \ 'c3': ['file.c3', 'file.c3i', 'file.c3t'],
\ 'cabal': ['file.cabal'],
\ 'cabalconfig': ['cabal.config', expand("$HOME/.config/cabal/config")] + s:WhenConfigHome('$XDG_CONFIG_HOME/cabal/config'),
\ 'cabalproject': ['cabal.project', 'cabal.project.local'],
@@ -151,6 +154,7 @@ func s:GetFilenameChecks() abort
\ 'calendar': ['calendar', '/.calendar/file', '/share/calendar/any/calendar.file', '/share/calendar/calendar.file', 'any/share/calendar/any/calendar.file', 'any/share/calendar/calendar.file'],
\ 'capnp': ['file.capnp'],
\ 'catalog': ['catalog', 'sgml.catalogfile', 'sgml.catalog', 'sgml.catalog-file'],
+ \ 'cdc': ['file.cdc'],
\ 'cdl': ['file.cdl'],
\ 'cdrdaoconf': ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao', 'any/etc/cdrdao.conf', 'any/etc/default/cdrdao', 'any/etc/defaults/cdrdao'],
\ 'cdrtoc': ['file.toc'],
@@ -188,13 +192,13 @@ func s:GetFilenameChecks() abort
\ 'crm': ['file.crm'],
\ 'crontab': ['crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'],
\ 'crystal': ['file.cr'],
- \ 'cs': ['file.cs', 'file.csx'],
+ \ 'cs': ['file.cs', 'file.csx', 'file.cake'],
\ 'csc': ['file.csc'],
\ 'csdl': ['file.csdl'],
\ 'csp': ['file.csp', 'file.fdr'],
\ 'css': ['file.css'],
- \ 'cterm': ['file.con'],
\ 'csv': ['file.csv'],
+ \ 'cterm': ['file.con'],
\ 'cucumber': ['file.feature'],
\ 'cuda': ['file.cu', 'file.cuh'],
\ 'cue': ['file.cue'],
@@ -209,11 +213,11 @@ func s:GetFilenameChecks() abort
\ 'dart': ['file.dart', 'file.drt'],
\ 'datascript': ['file.ds'],
\ 'dcd': ['file.dcd'],
+ \ 'deb822sources': ['/etc/apt/sources.list.d/file.sources', 'any/etc/apt/sources.list.d/file.sources'],
\ 'debchangelog': ['changelog.Debian', 'changelog.dch', 'NEWS.Debian', 'NEWS.dch', '/debian/changelog'],
- \ 'debcontrol': ['/debian/control', 'any/debian/control'],
+ \ 'debcontrol': ['/debian/control', 'any/debian/control', 'any/DEBIAN/control'],
\ 'debcopyright': ['/debian/copyright', 'any/debian/copyright'],
\ 'debsources': ['/etc/apt/sources.list', '/etc/apt/sources.list.d/file.list', 'any/etc/apt/sources.list', 'any/etc/apt/sources.list.d/file.list'],
- \ 'deb822sources': ['/etc/apt/sources.list.d/file.sources', 'any/etc/apt/sources.list.d/file.sources'],
\ 'def': ['file.def'],
\ 'denyhosts': ['denyhosts.conf'],
\ 'desc': ['file.desc'],
@@ -271,7 +275,7 @@ func s:GetFilenameChecks() abort
\ 'falcon': ['file.fal'],
\ 'fan': ['file.fan', 'file.fwt'],
\ 'faust': ['file.dsp', 'file.lib'],
- \ 'fennel': ['file.fnl'],
+ \ 'fennel': ['file.fnl', '.fennelrc', 'fennelrc'],
\ 'fetchmail': ['.fetchmailrc'],
\ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
\ 'firrtl': ['file.fir'],
@@ -295,12 +299,13 @@ func s:GetFilenameChecks() abort
\ 'gdscript': ['file.gd'],
\ 'gdshader': ['file.gdshader', 'file.shader'],
\ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'],
+ \ 'gel': ['file.gel'],
\ 'gemtext': ['file.gmi', 'file.gemini'],
\ 'gift': ['file.gift'],
\ 'gitattributes': ['file.git/info/attributes', '.gitattributes', '/.config/git/attributes', '/etc/gitattributes', '/usr/local/etc/gitattributes', 'some.git/info/attributes'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/attributes'),
\ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'],
\ 'gitconfig': ['file.git/config', 'file.git/config.worktree', 'file.git/worktrees/x/config.worktree', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/usr/local/etc/gitconfig', '/etc/gitconfig.d/file', 'any/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/config'),
- \ 'gitignore': ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/ignore') + ['.prettierignore'],
+ \ 'gitignore': ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'] + s:WhenConfigHome('$XDG_CONFIG_HOME/git/ignore') + ['.prettierignore', '.fdignore', '/.config/fd/ignore', '.ignore', '.rgignore', '.dockerignore', '.npmignore', '.vscodeignore'],
\ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'],
\ 'gitrebase': ['git-rebase-todo'],
\ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'],
@@ -349,11 +354,12 @@ func s:GetFilenameChecks() abort
\ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'],
\ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
\ 'html': ['file.html', 'file.htm', 'file.cshtml', 'file.component.html'],
- \ 'http': ['file.http'],
\ 'htmlm4': ['file.html.m4'],
\ 'httest': ['file.htt', 'file.htb'],
+ \ 'http': ['file.http'],
\ 'hurl': ['file.hurl'],
- \ 'hyprlang': ['hyprlock.conf', 'hyprland.conf', 'hypridle.conf', 'hyprpaper.conf'],
+ \ 'hy': ['file.hy', '.hy-history'],
+ \ 'hyprlang': ['hyprlock.conf', 'hyprland.conf', 'hypridle.conf', 'hyprpaper.conf', '/hypr/foo.conf'],
\ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'ibasic': ['file.iba', 'file.ibi'],
\ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'],
@@ -372,7 +378,7 @@ func s:GetFilenameChecks() abort
\ 'jal': ['file.jal', 'file.JAL'],
\ 'jam': ['file.jpl', 'file.jpr', 'JAM-file.file', 'JAM.file', 'Prl-file.file', 'Prl.file'],
\ 'janet': ['file.janet'],
- \ 'java': ['file.java', 'file.jav'],
+ \ 'java': ['file.java', 'file.jav', 'file.jsh'],
\ 'javacc': ['file.jj', 'file.jjt'],
\ 'javascript': ['file.js', 'file.jsm', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs', '.node_repl_history', '.bun_repl_history', 'deno_history.txt'],
\ 'javascript.glimmer': ['file.gjs'],
@@ -380,18 +386,19 @@ func s:GetFilenameChecks() abort
\ 'jess': ['file.clp'],
\ 'jgraph': ['file.jgr'],
\ 'jinja': ['file.jinja'],
- \ 'jj': ['file.jjdescription'],
- \ 'jq': ['file.jq'],
+ \ 'jjdescription': ['file.jjdescription'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock', 'pack.mcmeta', 'deno.lock'],
+ \ 'jq': ['file.jq'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock', 'pack.mcmeta', 'deno.lock', '.swcrc'],
\ 'json5': ['file.json5'],
- \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.jscsrc', '.vsconfig', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json', '.luaurc'],
+ \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.jscsrc', '.vsconfig', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json', '.luaurc', 'bun.lock', expand("$HOME/.config/VSCodium/User/settings.json")],
\ 'jsonl': ['file.jsonl'],
\ 'jsonnet': ['file.jsonnet', 'file.libsonnet'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
\ 'just': ['justfile', 'Justfile', '.justfile', 'config.just'],
+ \ 'karel': ['file.kl', 'file.KL'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file', 'Config.in', 'Config.in.host'],
\ 'kdl': ['file.kdl'],
\ 'kivy': ['file.kv'],
@@ -401,14 +408,15 @@ func s:GetFilenameChecks() abort
\ 'kscript': ['file.ks'],
\ 'kwt': ['file.k'],
\ 'lace': ['file.ace', 'file.ACE'],
+ \ 'lalrpop': ['file.lalrpop'],
\ 'latte': ['file.latte', 'file.lte'],
\ 'ld': ['file.ld', 'any/usr/lib/aarch64-xilinx-linux/ldscripts/aarch64elf32b.x'],
\ 'ldapconf': ['ldap.conf', '.ldaprc', 'ldaprc'],
\ 'ldif': ['file.ldif'],
\ 'lean': ['file.lean'],
\ 'ledger': ['file.ldg', 'file.ledger', 'file.journal'],
- \ 'less': ['file.less'],
\ 'leo': ['file.leo'],
+ \ 'less': ['file.less'],
\ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'],
\ 'lf': ['lfrc'],
\ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'],
@@ -419,13 +427,13 @@ func s:GetFilenameChecks() abort
\ 'lilo': ['lilo.conf', 'lilo.conf-file'],
\ 'lilypond': ['file.ly', 'file.ily'],
\ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf', '/etc/limits.conf', '/etc/limits.d/file.conf', '/etc/some-limits.conf', '/etc/some-limits.d/file.conf', 'any/etc/limits', 'any/etc/limits.conf', 'any/etc/limits.d/file.conf', 'any/etc/some-limits.conf', 'any/etc/some-limits.d/file.conf'],
- \ 'liquidsoap': ['file.liq'],
\ 'liquid': ['file.liquid'],
- \ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc', 'file.stsg', 'any/local/share/supertux2/config'],
+ \ 'liquidsoap': ['file.liq'],
+ \ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'],
- \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'livebook': ['file.livemd'],
+ \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'loginaccess': ['/etc/login.access', 'any/etc/login.access'],
\ 'logindefs': ['/etc/login.defs', 'any/etc/login.defs'],
\ 'logtalk': ['file.lgt'],
@@ -448,9 +456,9 @@ func s:GetFilenameChecks() abort
\ 'mallard': ['file.page'],
"\ 'man': ['file.man'],
\ 'manconf': ['/etc/man.conf', 'man.config', 'any/etc/man.conf'],
- \ 'map': ['file.map'],
\ 'maple': ['file.mv', 'file.mpl', 'file.mws'],
\ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
+ \ 'masm': ['file.masm'],
\ 'mason': ['file.mason', 'file.mhtml'],
\ 'master': ['file.mas', 'file.master'],
\ 'matlab': ['file.m'],
@@ -496,6 +504,7 @@ func s:GetFilenameChecks() abort
\ 'mmp': ['file.mmp'],
\ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'],
\ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig', 'file.lm3'],
+ \ 'mojo': ['file.mojo', 'file.🔥'],
\ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
\ 'moo': ['file.moo'],
\ 'moonscript': ['file.moon'],
@@ -504,10 +513,9 @@ func s:GetFilenameChecks() abort
\ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'],
\ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
\ 'msidl': ['file.odl', 'file.mof'],
- \ 'mss': ['file.mss'],
- \ 'msql': ['file.msql'],
- \ 'mojo': ['file.mojo', 'file.🔥'],
\ 'msmtp': ['.msmtprc'],
+ \ 'msql': ['file.msql'],
+ \ 'mss': ['file.mss'],
\ 'mupad': ['file.mu'],
\ 'mush': ['file.mush'],
\ 'mustache': ['file.mustache'],
@@ -527,6 +535,7 @@ func s:GetFilenameChecks() abort
\ 'n1ql': ['file.n1ql', 'file.nql'],
\ 'named': ['namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'],
\ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'],
+ \ 'nasm': ['file.nasm'],
\ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
\ 'ncf': ['file.ncf'],
\ 'neomuttlog': ['/home/user/.neomuttdebug1'],
@@ -540,6 +549,7 @@ func s:GetFilenameChecks() abort
\ 'nqc': ['file.nqc'],
\ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'],
\ 'nsis': ['file.nsi', 'file.nsh'],
+ \ 'ntriples': ['file.nt'],
\ 'nu': ['file.nu'],
\ 'obj': ['file.obj'],
\ 'objdump': ['file.objdump', 'file.cppobjdump'],
@@ -599,16 +609,18 @@ func s:GetFilenameChecks() abort
\ 'promela': ['file.pml'],
\ 'proto': ['file.proto'],
\ 'protocols': ['/etc/protocols', 'any/etc/protocols'],
+ \ 'prql': ['file.prql'],
\ 'ps1': ['file.ps1', 'file.psd1', 'file.psm1', 'file.pssc'],
\ 'ps1xml': ['file.ps1xml'],
\ 'psf': ['file.psf'],
\ 'psl': ['file.psl'],
+ \ 'ptx': ['file.ptx'],
\ 'pug': ['file.pug'],
\ 'puppet': ['file.pp'],
\ 'purescript': ['file.purs'],
\ 'pymanifest': ['MANIFEST.in'],
\ 'pyret': ['file.arr'],
- \ 'pyrex': ['file.pyx', 'file.pxd'],
+ \ 'pyrex': ['file.pyx', 'file.pxd', 'file.pxi', 'file.pyx+'],
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', '.python_history', '.jline-jython.history', 'file.ptl', 'file.pyi', 'SConstruct'],
\ 'ql': ['file.ql', 'file.qll'],
\ 'qml': ['file.qml', 'file.qbs'],
@@ -640,27 +652,27 @@ func s:GetFilenameChecks() abort
\ 'rnc': ['file.rnc'],
\ 'rng': ['file.rng'],
\ 'rnoweb': ['file.rnw', 'file.snw'],
- \ 'rpgle': ['file.rpgle', 'file.rpgleinc'],
\ 'robot': ['file.robot', 'file.resource'],
\ 'robots': ['robots.txt'],
\ 'roc': ['file.roc'],
\ 'ron': ['file.ron'],
\ 'routeros': ['file.rsc'],
\ 'rpcgen': ['file.x'],
+ \ 'rpgle': ['file.rpgle', 'file.rpgleinc'],
\ 'rpl': ['file.rpl'],
\ 'rrst': ['file.rrst', 'file.srst'],
\ 'rst': ['file.rst'],
\ 'rtf': ['file.rtf'],
\ 'ruby': ['.irbrc', 'irbrc', '.irb_history', 'irb_history', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile', 'Vagrantfile'],
\ 'rust': ['file.rs'],
+ \ 'sage': ['file.sage'],
\ 'salt': ['file.sls'],
\ 'samba': ['smb.conf'],
\ 'sas': ['file.sas'],
\ 'sass': ['file.sass'],
- \ 'sather': ['file.sa'],
\ 'sbt': ['file.sbt'],
\ 'scala': ['file.scala'],
- \ 'scheme': ['file.scm', 'file.ss', 'file.sld'],
+ \ 'scheme': ['file.scm', 'file.ss', 'file.sld', 'file.stsg', 'any/local/share/supertux2/config', '.lips_repl_history'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
\ 'scss': ['file.scss'],
@@ -673,19 +685,18 @@ func s:GetFilenameChecks() abort
\ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'],
\ 'sexplib': ['file.sexp'],
\ 'sh': ['.bashrc', '.bash_profile', '.bash-profile', '.bash_logout', '.bash-logout', '.bash_aliases', '.bash-aliases', '.bash_history', '.bash-history',
- \ '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh',
+ \ '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh',
\ '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile',
\ 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport', '.env', '.envrc', 'devscripts.conf',
\ '.devscripts', 'file.lo', 'file.la', 'file.lai'],
+ \ 'shaderslang': ['file.slang'],
\ 'sieve': ['file.siv', 'file.sieve'],
\ 'sil': ['file.sil'],
\ 'simula': ['file.sim'],
\ 'sinda': ['file.sin', 'file.s85'],
\ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'],
\ 'skill': ['file.il', 'file.ils', 'file.cdf'],
- \ 'cdc': ['file.cdc'],
\ 'slang': ['file.sl'],
- \ 'sage': ['file.sage'],
\ 'slice': ['file.ice'],
\ 'slint': ['file.slint'],
\ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'],
@@ -711,7 +722,6 @@ func s:GetFilenameChecks() abort
\ 'spyce': ['file.spy', 'file.spi'],
\ 'sql': ['file.tyb', 'file.tyc', 'file.pkb', 'file.pks', '.sqlite_history'],
\ 'sqlj': ['file.sqlj'],
- \ 'prql': ['file.prql'],
\ 'sqr': ['file.sqr', 'file.sqi'],
\ 'squid': ['squid.conf'],
\ 'squirrel': ['file.nut'],
@@ -777,14 +787,13 @@ func s:GetFilenameChecks() abort
\ 'any/etc/systemd/system/file.d/.#-file',
\ 'any/etc/systemd/system/file.d/file.conf'],
\ 'systemverilog': ['file.sv', 'file.svh'],
- \ 'trace32': ['file.cmm', 'file.t32'],
+ \ 'tablegen': ['file.td'],
\ 'tags': ['tags'],
\ 'tak': ['file.tak'],
\ 'tal': ['file.tal'],
\ 'taskdata': ['pending.data', 'completed.data', 'undo.data'],
\ 'taskedit': ['file.task'],
\ 'tcl': ['file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc', '.tclsh-history', '.xsctcmdhistory', '.xsdbcmdhistory'],
- \ 'tablegen': ['file.td'],
\ 'teal': ['file.tl'],
\ 'templ': ['file.templ'],
\ 'template': ['file.tmpl'],
@@ -804,7 +813,9 @@ func s:GetFilenameChecks() abort
\ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf', '.tmux-file.conf', '.tmux.conf', 'tmux-file.conf', 'tmux.conf', 'tmux.conf.local'],
\ 'toml': ['file.toml', 'Gopkg.lock', 'Pipfile', '/home/user/.cargo/config', '.black'],
\ 'tpp': ['file.tpp'],
+ \ 'trace32': ['file.cmm', 'file.t32'],
\ 'treetop': ['file.treetop'],
+ \ 'trig': ['file.trig'],
\ 'trustees': ['trustees.conf'],
\ 'tsalt': ['file.slt'],
\ 'tsscl': ['file.tsscl'],
@@ -816,12 +827,12 @@ func s:GetFilenameChecks() abort
\ 'typescript.glimmer': ['file.gts'],
\ 'typescriptreact': ['file.tsx'],
\ 'typespec': ['file.tsp'],
- \ 'ungrammar': ['file.ungram'],
\ 'uc': ['file.uc'],
\ 'udevconf': ['/etc/udev/udev.conf', 'any/etc/udev/udev.conf'],
\ 'udevperm': ['/etc/udev/permissions.d/file.permissions', 'any/etc/udev/permissions.d/file.permissions'],
\ 'udevrules': ['/etc/udev/rules.d/file.rules', '/usr/lib/udev/rules.d/file.rules', '/lib/udev/rules.d/file.rules'],
\ 'uil': ['file.uit', 'file.uil'],
+ \ 'ungrammar': ['file.ungram'],
\ 'unison': ['file.u', 'file.uu'],
\ 'updatedb': ['/etc/updatedb.conf', 'any/etc/updatedb.conf'],
\ 'upstart': ['/usr/share/upstart/file.conf', '/usr/share/upstart/file.override', '/etc/init/file.conf', '/etc/init/file.override', '/.init/file.conf', '/.init/file.override', '/.config/upstart/file.conf', '/.config/upstart/file.override', 'any/.config/upstart/file.conf', 'any/.config/upstart/file.override', 'any/.init/file.conf', 'any/.init/file.override', 'any/etc/init/file.conf', 'any/etc/init/file.override', 'any/usr/share/upstart/file.conf', 'any/usr/share/upstart/file.override'],
@@ -874,7 +885,7 @@ func s:GetFilenameChecks() abort
\ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui',
\ 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old',
\ 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr',
- \ 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi'],
+ \ 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi', 'file.slnx', 'Directory.Packages.props', 'Directory.Build.targets', 'Directory.Build.props'],
\ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'],
\ 'xpm': ['file.xpm'],
\ 'xpm2': ['file.xpm2'],
@@ -884,7 +895,7 @@ func s:GetFilenameChecks() abort
\ 'xslt': ['file.xsl', 'file.xslt'],
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
\ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock',
- \ '/home/user/.kube/config'],
+ \ '/home/user/.kube/config', '.condarc', 'condarc', 'pixi.lock'],
\ 'yang': ['file.yang'],
\ 'yuck': ['file.yuck'],
\ 'z8a': ['file.z8a'],
@@ -986,6 +997,7 @@ func s:GetScriptChecks() abort
\ 'expect': [['#!/path/expect']],
\ 'execline': [['#!/sbin/execlineb -S0'], ['#!/usr/bin/execlineb']],
\ 'gnuplot': [['#!/path/gnuplot']],
+ \ 'just': [['#!/path/just']],
\ 'make': [['#!/path/make']],
\ 'nix': [['#!/path/nix-shell']],
\ 'pike': [['#!/path/pike'],
@@ -1191,6 +1203,22 @@ func Test_cfg_file()
filetype off
endfunc
+func Test_cl_file()
+ filetype on
+
+ call writefile(['/*', ' * Xfile.cl', ' */', 'int f() {}'], 'Xfile.cl')
+ split Xfile.cl
+ call assert_equal('opencl', &filetype)
+ bwipe!
+
+ call writefile(['()'], 'Xfile.cl')
+ split Xfile.cl
+ call assert_equal('lisp', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_d_file()
filetype on
@@ -2273,6 +2301,43 @@ func Test_cls_file()
filetype off
endfunc
+func Test_cmd_file()
+ filetype on
+
+ call writefile(['--rom_model'], 'Xfile.cmd')
+ split Xfile.cmd
+ call assert_equal('lnk', &filetype)
+ bwipe!
+
+ call writefile(['/* comment */'], 'Xfile.cmd')
+ split Xfile.cmd
+ call assert_equal('rexx', &filetype)
+ bwipe!
+
+ call writefile(['REM comment'], 'Xfile.cmd')
+ split Xfile.cmd
+ call assert_equal('dosbatch', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
+func Test_sa_file()
+ filetype on
+
+ call writefile([';* XXX-a.sa: XXX for TI C6000 DSP *;', '.no_mdep'], 'Xfile.sa')
+ split Xfile.sa
+ call assert_equal('tiasm', &filetype)
+ bwipe!
+
+ call writefile(['-- comment'], 'Xfile.sa')
+ split Xfile.sa
+ call assert_equal('sather', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_sig_file()
filetype on
@@ -2737,6 +2802,24 @@ func Test_make_file()
filetype off
endfunc
+func Test_map_file()
+ filetype on
+
+ " TI linker map file
+ call writefile(['******************************************************************************', ' TMS320C6x Linker Unix v7.4.24 ', '******************************************************************************'], 'Xfile.map', 'D')
+ split Xfile.map
+ call assert_equal('lnkmap', &filetype)
+ bwipe!
+
+ " UMN mapserver config file
+ call writefile(['MAP', 'NAME "local-demo"', 'END'], 'Xfile.map', 'D')
+ split Xfile.map
+ call assert_equal('map', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_org_file()
filetype on
diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim
index 327ea98e1c..738a417b86 100644
--- a/test/old/testdir/test_functions.vim
+++ b/test/old/testdir/test_functions.vim
@@ -2390,6 +2390,85 @@ func Test_getchar()
call assert_equal("\<M-F2>", getchar(0))
call assert_equal(0, getchar(0))
+ call feedkeys("\<Tab>", '')
+ call assert_equal(char2nr("\<Tab>"), getchar())
+ call feedkeys("\<Tab>", '')
+ call assert_equal(char2nr("\<Tab>"), getchar(-1))
+ call feedkeys("\<Tab>", '')
+ call assert_equal(char2nr("\<Tab>"), getchar(-1, {}))
+ call feedkeys("\<Tab>", '')
+ call assert_equal(char2nr("\<Tab>"), getchar(-1, #{number: v:true}))
+ call assert_equal(0, getchar(0))
+ call assert_equal(0, getchar(1))
+ call assert_equal(0, getchar(0, #{number: v:true}))
+ call assert_equal(0, getchar(1, #{number: v:true}))
+
+ call feedkeys("\<Tab>", '')
+ call assert_equal("\<Tab>", getcharstr())
+ call feedkeys("\<Tab>", '')
+ call assert_equal("\<Tab>", getcharstr(-1))
+ call feedkeys("\<Tab>", '')
+ call assert_equal("\<Tab>", getcharstr(-1, {}))
+ call feedkeys("\<Tab>", '')
+ call assert_equal("\<Tab>", getchar(-1, #{number: v:false}))
+ call assert_equal('', getcharstr(0))
+ call assert_equal('', getcharstr(1))
+ call assert_equal('', getchar(0, #{number: v:false}))
+ call assert_equal('', getchar(1, #{number: v:false}))
+
+ " Nvim: <M-x> is never simplified
+ " for key in ["C-I", "C-X", "M-x"]
+ for key in ["C-I", "C-X"]
+ let lines =<< eval trim END
+ call feedkeys("\<*{key}>", '')
+ call assert_equal(char2nr("\<{key}>"), getchar())
+ call feedkeys("\<*{key}>", '')
+ call assert_equal(char2nr("\<{key}>"), getchar(-1))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal(char2nr("\<{key}>"), getchar(-1, {{}}))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal(char2nr("\<{key}>"), getchar(-1, {{'number': 1}}))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal(char2nr("\<{key}>"), getchar(-1, {{'simplify': 1}}))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<*{key}>", getchar(-1, {{'simplify': v:false}}))
+ call assert_equal(0, getchar(0))
+ call assert_equal(0, getchar(1))
+ END
+ call CheckLegacyAndVim9Success(lines)
+
+ let lines =<< eval trim END
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<{key}>", getcharstr())
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<{key}>", getcharstr(-1))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<{key}>", getcharstr(-1, {{}}))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<{key}>", getchar(-1, {{'number': 0}}))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<{key}>", getcharstr(-1, {{'simplify': 1}}))
+ call feedkeys("\<*{key}>", '')
+ call assert_equal("\<*{key}>", getcharstr(-1, {{'simplify': v:false}}))
+ call assert_equal('', getcharstr(0))
+ call assert_equal('', getcharstr(1))
+ END
+ call CheckLegacyAndVim9Success(lines)
+ endfor
+
+ call assert_fails('call getchar(1, 1)', 'E1206:')
+ call assert_fails('call getcharstr(1, 1)', 'E1206:')
+ call assert_fails('call getchar(1, #{cursor: "foo"})', 'E475:')
+ call assert_fails('call getcharstr(1, #{cursor: "foo"})', 'E475:')
+ call assert_fails('call getchar(1, #{cursor: 0z})', 'E976:')
+ call assert_fails('call getcharstr(1, #{cursor: 0z})', 'E976:')
+ call assert_fails('call getchar(1, #{simplify: 0z})', 'E974:')
+ call assert_fails('call getcharstr(1, #{simplify: 0z})', 'E974:')
+ call assert_fails('call getchar(1, #{number: []})', 'E745:')
+ call assert_fails('call getchar(1, #{number: {}})', 'E728:')
+ call assert_fails('call getcharstr(1, #{number: v:true})', 'E475:')
+ call assert_fails('call getcharstr(1, #{number: v:false})', 'E475:')
+
call setline(1, 'xxxx')
call Ntest_setmouse(1, 3)
let v:mouse_win = 9
@@ -2405,10 +2484,59 @@ func Test_getchar()
enew!
endfunc
+func Test_getchar_cursor_position()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ call setline(1, ['foobar', 'foobar', 'foobar'])
+ call cursor(3, 6)
+ nnoremap <F1> <Cmd>echo 1234<Bar>call getchar()<CR>
+ nnoremap <F2> <Cmd>call getchar()<CR>
+ nnoremap <F3> <Cmd>call getchar(-1, {})<CR>
+ nnoremap <F4> <Cmd>call getchar(-1, #{cursor: 'msg'})<CR>
+ nnoremap <F5> <Cmd>call getchar(-1, #{cursor: 'keep'})<CR>
+ nnoremap <F6> <Cmd>call getchar(-1, #{cursor: 'hide'})<CR>
+ END
+ call writefile(lines, 'XgetcharCursorPos', 'D')
+ let buf = RunVimInTerminal('-S XgetcharCursorPos', {'rows': 6})
+ call WaitForAssert({-> assert_equal([3, 6], term_getcursor(buf)[0:1])})
+
+ call term_sendkeys(buf, "\<F1>")
+ call WaitForAssert({-> assert_equal([6, 5], term_getcursor(buf)[0:1])})
+ call assert_true(term_getcursor(buf)[2].visible)
+ call term_sendkeys(buf, 'a')
+ call WaitForAssert({-> assert_equal([3, 6], term_getcursor(buf)[0:1])})
+ call assert_true(term_getcursor(buf)[2].visible)
+
+ for key in ["\<F2>", "\<F3>", "\<F4>"]
+ call term_sendkeys(buf, key)
+ call WaitForAssert({-> assert_equal([6, 1], term_getcursor(buf)[0:1])})
+ call assert_true(term_getcursor(buf)[2].visible)
+ call term_sendkeys(buf, 'a')
+ call WaitForAssert({-> assert_equal([3, 6], term_getcursor(buf)[0:1])})
+ call assert_true(term_getcursor(buf)[2].visible)
+ endfor
+
+ call term_sendkeys(buf, "\<F5>")
+ call TermWait(buf, 50)
+ call assert_equal([3, 6], term_getcursor(buf)[0:1])
+ call assert_true(term_getcursor(buf)[2].visible)
+ call term_sendkeys(buf, 'a')
+ call TermWait(buf, 50)
+ call assert_equal([3, 6], term_getcursor(buf)[0:1])
+ call assert_true(term_getcursor(buf)[2].visible)
+
+ call term_sendkeys(buf, "\<F6>")
+ call WaitForAssert({-> assert_false(term_getcursor(buf)[2].visible)})
+ call term_sendkeys(buf, 'a')
+ call WaitForAssert({-> assert_true(term_getcursor(buf)[2].visible)})
+ call assert_equal([3, 6], term_getcursor(buf)[0:1])
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_libcall_libcallnr()
- if !has('libcall')
- return
- endif
+ CheckFeature libcall
if has('win32')
let libc = 'msvcrt.dll'
@@ -2672,7 +2800,9 @@ endfunc
func Test_call()
call assert_equal(3, call('len', [123]))
call assert_equal(3, 'len'->call([123]))
- call assert_fails("call call('len', 123)", 'E714:')
+ call assert_equal(4, call({ x -> len(x) }, ['xxxx']))
+ call assert_equal(2, call(function('len'), ['xx']))
+ call assert_fails("call call('len', 123)", 'E1211:')
call assert_equal(0, call('', []))
call assert_equal(0, call('len', v:_null_list))
diff --git a/test/old/testdir/test_highlight.vim b/test/old/testdir/test_highlight.vim
index 0a64c63d30..56c7a9656f 100644
--- a/test/old/testdir/test_highlight.vim
+++ b/test/old/testdir/test_highlight.vim
@@ -785,8 +785,8 @@ func Test_1_highlight_Normalgroup_exists()
if !has('gui_running')
call assert_match('hi Normal\s*clear', hlNormal)
elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
- " expect is DEFAULT_FONT of gui_gtk_x11.c
- call assert_match('hi Normal\s*font=Monospace 10', hlNormal)
+ " expect is DEFAULT_FONT of gui_gtk_x11.c (any size)
+ call assert_match('hi Normal\s*font=Monospace\>', hlNormal)
elseif has('gui_motif')
" expect is DEFAULT_FONT of gui_x11.c
call assert_match('hi Normal\s*font=7x13', hlNormal)
diff --git a/test/old/testdir/test_indent.vim b/test/old/testdir/test_indent.vim
index dcacc11663..630beed810 100644
--- a/test/old/testdir/test_indent.vim
+++ b/test/old/testdir/test_indent.vim
@@ -1,5 +1,8 @@
" Test for various indent options
+source shared.vim
+source check.vim
+
func Test_preserveindent()
new
" Test for autoindent copying indent from the previous line
@@ -276,4 +279,77 @@ func Test_formatting_keeps_first_line_indent()
bwipe!
endfunc
+" Test for indenting with large amount, causes overflow
+func Test_indent_overflow_count()
+ throw 'skipped: TODO: '
+ new
+ setl sw=8
+ call setline(1, "abc")
+ norm! V2147483647>
+ " indents by INT_MAX
+ call assert_equal(2147483647, indent(1))
+ close!
+endfunc
+
+func Test_indent_overflow_count2()
+ throw 'skipped: Nvim does not support 64-bit number options'
+ new
+ " this only works, when long is 64bits
+ try
+ setl sw=0x180000000
+ catch /^Vim\%((\a\+)\)\=:E487:/
+ throw 'Skipped: value negative on this platform'
+ endtry
+ call setline(1, "\tabc")
+ norm! <<
+ call assert_equal(0, indent(1))
+ close!
+endfunc
+
+" Test that mouse shape is restored to Normal mode after using "gq" when
+" 'indentexpr' executes :normal.
+func Test_mouse_shape_indent_norm_with_gq()
+ CheckFeature mouseshape
+ CheckCanRunGui
+
+ let lines =<< trim END
+ func Indent()
+ exe "normal! \<Ignore>"
+ return 0
+ endfunc
+
+ setlocal indentexpr=Indent()
+ END
+ call writefile(lines, 'Xindentexpr.vim', 'D')
+
+ let lines =<< trim END
+ vim9script
+ var mouse_shapes = []
+
+ setline(1, [repeat('a', 80), repeat('b', 80)])
+
+ feedkeys('ggVG')
+ timer_start(50, (_) => {
+ mouse_shapes += [getmouseshape()]
+ timer_start(50, (_) => {
+ feedkeys('gq')
+ timer_start(50, (_) => {
+ mouse_shapes += [getmouseshape()]
+ timer_start(50, (_) => {
+ writefile(mouse_shapes, 'Xmouseshapes')
+ quit!
+ })
+ })
+ })
+ })
+ END
+ call writefile(lines, 'Xmouseshape.vim', 'D')
+
+ call RunVim([], [], "-g -S Xindentexpr.vim -S Xmouseshape.vim")
+ call WaitForAssert({-> assert_equal(['rightup-arrow', 'arrow'],
+ \ readfile('Xmouseshapes'))}, 300)
+
+ call delete('Xmouseshapes')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
index c02aa1db62..2fb1715634 100644
--- a/test/old/testdir/test_ins_complete.vim
+++ b/test/old/testdir/test_ins_complete.vim
@@ -253,6 +253,91 @@ func Test_CompleteDoneNone()
au! CompleteDone
endfunc
+func Test_CompleteDone_vevent_keys()
+ func OnDone()
+ let g:complete_word = get(v:event, 'complete_word', v:null)
+ let g:complete_type = get(v:event, 'complete_type', v:null)
+ endfunction
+
+ autocmd CompleteDone * :call OnDone()
+
+ func CompleteFunc(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "bar"}]
+ endfunc
+ set omnifunc=CompleteFunc
+ set completefunc=CompleteFunc
+ set completeopt+=menuone
+
+ new
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-O>\<C-N>\<C-Y>\<Esc>0", 'tx')
+ call assert_equal('bar', g:complete_word)
+ call assert_equal('omni', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<ESC>", 'tx')
+ call assert_equal('', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim visual v\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('vim', g:complete_word)
+ call assert_equal('keyword', g:complete_type)
+
+ call feedkeys("Shello vim\<CR>completion test\<CR>\<C-X>\<C-l>\<C-Y>", 'tx')
+ call assert_equal('completion test', g:complete_word)
+ call assert_equal('whole_line', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-U>\<C-Y>", 'tx')
+ call assert_equal('foo', g:complete_word)
+ call assert_equal('function', g:complete_type)
+
+ inoremap <buffer> <f3> <cmd>call complete(1, ["red", "blue"])<cr>
+ call feedkeys("S\<f3>\<C-Y>", 'tx')
+ call assert_equal('red', g:complete_word)
+ call assert_equal('eval', g:complete_type)
+
+ call feedkeys("S\<C-X>\<C-V>\<C-Y>", 'tx')
+ call assert_equal('!', g:complete_word)
+ call assert_equal('cmdline', g:complete_type)
+
+ call writefile([''], 'foo_test', 'D')
+ call feedkeys("Sfoo\<C-X>\<C-F>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('foo_test', g:complete_word)
+ call assert_equal('files', g:complete_type)
+
+ call writefile(['hello help'], 'test_case.txt', 'D')
+ set dictionary=test_case.txt
+ call feedkeys("ggdGSh\<C-X>\<C-K>\<C-Y>\<Esc>", 'tx')
+ call assert_equal('hello', g:complete_word)
+ call assert_equal('dictionary', g:complete_type)
+
+ set spell spelllang=en_us
+ call feedkeys("STheatre\<C-X>s\<C-Y>\<Esc>", 'tx')
+ call assert_equal('Theater', g:complete_word)
+ call assert_equal('spell', g:complete_type)
+
+ bwipe!
+ set completeopt& omnifunc& completefunc& spell& spelllang& dictionary&
+ autocmd! CompleteDone
+ delfunc OnDone
+ delfunc CompleteFunc
+ unlet g:complete_word
+ unlet g:complete_type
+endfunc
+
func Test_CompleteDoneDict()
au CompleteDonePre * :call <SID>CompleteDone_CheckCompletedItemDict(1)
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict(0)
@@ -1509,7 +1594,7 @@ func Test_complete_item_refresh_always()
set completefunc=Tcomplete
exe "normal! iup\<C-X>\<C-U>\<BS>\<BS>\<BS>\<BS>\<BS>"
call assert_equal('up', getline(1))
- call assert_equal(2, g:CallCount)
+ call assert_equal(6, g:CallCount)
set completeopt&
set completefunc&
bw!
@@ -2693,7 +2778,7 @@ func Test_complete_fuzzy_match()
if a:findstart
return col(".")
endif
- return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}]
+ return [#{word: "foo"}, #{word: "foobar"}, #{word: "fooBaz"}, #{word: "foobala"}, #{word: "你好吗"}, #{word: "我好"}]
endfunc
new
@@ -2752,6 +2837,26 @@ func Test_complete_fuzzy_match()
call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!')
call assert_equal('Tex', getline('.'))
+ " test case for nosort option
+ set cot=menuone,menu,noinsert,fuzzy,nosort
+ " "fooBaz" should have a higher score when the leader is "fb".
+ " With "nosort", "foobar" should still be shown first in the popup menu.
+ call feedkeys("S\<C-x>\<C-o>fb", 'tx')
+ call assert_equal('foobar', g:word)
+ call feedkeys("S\<C-x>\<C-o>好", 'tx')
+ call assert_equal("你好吗", g:word)
+
+ set cot+=noselect
+ call feedkeys("S\<C-x>\<C-o>好", 'tx')
+ call assert_equal(v:null, g:word)
+ call feedkeys("S\<C-x>\<C-o>好\<C-N>", 'tx')
+ call assert_equal('你好吗', g:word)
+
+ " "nosort" shouldn't enable fuzzy filtering when "fuzzy" isn't present.
+ set cot=menuone,noinsert,nosort
+ call feedkeys("S\<C-x>\<C-o>fooB\<C-Y>", 'tx')
+ call assert_equal('fooBaz', getline('.'))
+
" clean up
set omnifunc=
bw!
@@ -2785,4 +2890,203 @@ func Test_complete_fuzzy_match_tie()
set completeopt&
endfunc
+func Test_complete_info_matches()
+ let g:what = ['matches']
+ func ShownInfo()
+ let g:compl_info = complete_info(g:what)
+ return ''
+ endfunc
+ set completeopt+=noinsert
+
+ new
+ call setline(1, ['aaa', 'aab', 'aba', 'abb'])
+ inoremap <buffer><F5> <C-R>=ShownInfo()<CR>
+
+ call feedkeys("Go\<C-X>\<C-N>\<F5>\<Esc>dd", 'tx')
+ call assert_equal([
+ \ {'word': 'aaa', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'aab', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'aba', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'abb', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
+ \], g:compl_info['matches'])
+
+ call feedkeys("Goa\<C-X>\<C-N>b\<F5>\<Esc>dd", 'tx')
+ call assert_equal([
+ \ {'word': 'aba', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'abb', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
+ \], g:compl_info['matches'])
+
+ " items and matches both in what
+ let g:what = ['items', 'matches']
+ call feedkeys("Goa\<C-X>\<C-N>b\<F5>\<Esc>dd", 'tx')
+ call assert_equal([
+ \ {'word': 'aaa', 'menu': '', 'user_data': '', 'match': v:false, 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'aab', 'menu': '', 'user_data': '', 'match': v:false, 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'aba', 'menu': '', 'user_data': '', 'match': v:true, 'info': '', 'kind': '', 'abbr': ''},
+ \ {'word': 'abb', 'menu': '', 'user_data': '', 'match': v:true, 'info': '', 'kind': '', 'abbr': ''},
+ \], g:compl_info['items'])
+ call assert_false(has_key(g:compl_info, 'matches'))
+
+ bw!
+ unlet g:what
+ delfunc ShownInfo
+ set cot&
+endfunc
+
+func Test_complete_info_completed()
+ func ShownInfo()
+ let g:compl_info = complete_info(['completed'])
+ return ''
+ endfunc
+ set completeopt+=noinsert
+
+ new
+ call setline(1, ['aaa', 'aab', 'aba', 'abb'])
+ inoremap <buffer><F5> <C-R>=ShownInfo()<CR>
+
+ call feedkeys("Go\<C-X>\<C-N>\<F5>\<Esc>dd", 'tx')
+ call assert_equal({'word': 'aaa', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, g:compl_info['completed'])
+
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<F5>\<Esc>dd", 'tx')
+ call assert_equal({'word': 'aab', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, g:compl_info['completed'])
+
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>dd", 'tx')
+ call assert_equal({'word': 'abb', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, g:compl_info['completed'])
+
+ set completeopt+=noselect
+ call feedkeys("Go\<C-X>\<C-N>\<F5>\<Esc>dd", 'tx')
+ call assert_equal({}, g:compl_info)
+
+ bw!
+ delfunc ShownInfo
+ set cot&
+endfunc
+
+function Test_completeopt_preinsert()
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "fobar"}, #{word: "foobar"}, #{word: "你的"}, #{word: "你好世界"}]
+ endfunc
+ set omnifunc=Omni_test
+ set completeopt=menu,menuone,preinsert
+
+ new
+ call feedkeys("S\<C-X>\<C-O>f", 'tx')
+ call assert_equal("fobar", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("S\<C-X>\<C-O>foo", 'tx')
+ call assert_equal("foobar", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("S\<C-X>\<C-O>foo\<BS>\<BS>\<BS>", 'tx')
+ call assert_equal("", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ " delete a character and input new leader
+ call feedkeys("S\<C-X>\<C-O>foo\<BS>b", 'tx')
+ call assert_equal("fobar", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ " delete preinsert when prepare completion
+ call feedkeys("S\<C-X>\<C-O>f\<Space>", 'tx')
+ call assert_equal("f ", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("S\<C-X>\<C-O>你", 'tx')
+ call assert_equal("你的", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("S\<C-X>\<C-O>你好", 'tx')
+ call assert_equal("你好世界", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("Shello wo\<Left>\<Left>\<Left>\<C-X>\<C-O>f", 'tx')
+ call assert_equal("hello fobar wo", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("Shello wo\<Left>\<Left>\<Left>\<C-X>\<C-O>f\<BS>", 'tx')
+ call assert_equal("hello wo", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("Shello wo\<Left>\<Left>\<Left>\<C-X>\<C-O>foo", 'tx')
+ call assert_equal("hello foobar wo", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ call feedkeys("Shello wo\<Left>\<Left>\<Left>\<C-X>\<C-O>foo\<BS>b", 'tx')
+ call assert_equal("hello fobar wo", getline('.'))
+ call feedkeys("\<C-E>\<ESC>", 'tx')
+
+ " confirm
+ call feedkeys("S\<C-X>\<C-O>f\<C-Y>", 'tx')
+ call assert_equal("fobar", getline('.'))
+ call assert_equal(5, col('.'))
+
+ " cancel
+ call feedkeys("S\<C-X>\<C-O>fo\<C-E>", 'tx')
+ call assert_equal("fo", getline('.'))
+ call assert_equal(2, col('.'))
+
+ call feedkeys("S hello hero\<CR>h\<C-X>\<C-N>", 'tx')
+ call assert_equal("hello", getline('.'))
+ call assert_equal(1, col('.'))
+
+ call feedkeys("Sh\<C-X>\<C-N>\<C-Y>", 'tx')
+ call assert_equal("hello", getline('.'))
+ call assert_equal(5, col('.'))
+
+ " delete preinsert part
+ call feedkeys("S\<C-X>\<C-O>fo ", 'tx')
+ call assert_equal("fo ", getline('.'))
+ call assert_equal(3, col('.'))
+
+ call feedkeys("She\<C-X>\<C-N>\<C-U>", 'tx')
+ call assert_equal("", getline('.'))
+ call assert_equal(1, col('.'))
+
+ call feedkeys("She\<C-X>\<C-N>\<C-W>", 'tx')
+ call assert_equal("", getline('.'))
+ call assert_equal(1, col('.'))
+
+ " whole line
+ call feedkeys("Shello hero\<CR>\<C-X>\<C-L>", 'tx')
+ call assert_equal("hello hero", getline('.'))
+ call assert_equal(1, col('.'))
+
+ call feedkeys("Shello hero\<CR>he\<C-X>\<C-L>", 'tx')
+ call assert_equal("hello hero", getline('.'))
+ call assert_equal(2, col('.'))
+
+ call feedkeys("Shello hero\<CR>h\<C-X>\<C-N>er", 'tx')
+ call assert_equal("hero", getline('.'))
+ call assert_equal(3, col('.'))
+
+ " can not work with fuzzy
+ set cot+=fuzzy
+ call feedkeys("S\<C-X>\<C-O>", 'tx')
+ call assert_equal("fobar", getline('.'))
+ call assert_equal(5, col('.'))
+
+ " test for fuzzy and noinsert
+ set cot+=noinsert
+ call feedkeys("S\<C-X>\<C-O>fb", 'tx')
+ call assert_equal("fb", getline('.'))
+ call assert_equal(2, col('.'))
+
+ call feedkeys("S\<C-X>\<C-O>你", 'tx')
+ call assert_equal("你", getline('.'))
+ call assert_equal(1, col('.'))
+
+ call feedkeys("S\<C-X>\<C-O>fb\<C-Y>", 'tx')
+ call assert_equal("fobar", getline('.'))
+ call assert_equal(5, col('.'))
+
+ bw!
+ set cot&
+ set omnifunc&
+ delfunc Omni_test
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/test/old/testdir/test_let.vim b/test/old/testdir/test_let.vim
index 44852c1d38..22a3a35f87 100644
--- a/test/old/testdir/test_let.vim
+++ b/test/old/testdir/test_let.vim
@@ -436,6 +436,24 @@ func Test_let_heredoc_fails()
call assert_report('Caught exception: ' .. v:exception)
endtry
+ try
+ let v =<< trim trimm
+ trimm
+ call assert_report('No exception thrown')
+ catch /E221:/
+ catch
+ call assert_report('Caught exception: ' .. v:exception)
+ endtry
+
+ try
+ let v =<< trim trim evall
+ evall
+ call assert_report('No exception thrown')
+ catch /E221:/
+ catch
+ call assert_report('Caught exception: ' .. v:exception)
+ endtry
+
let text =<< trim END
func WrongSyntax()
let v =<< that there
diff --git a/test/old/testdir/test_matchfuzzy.vim b/test/old/testdir/test_matchfuzzy.vim
index 90f3366b23..0c982c19f1 100644
--- a/test/old/testdir/test_matchfuzzy.vim
+++ b/test/old/testdir/test_matchfuzzy.vim
@@ -23,6 +23,8 @@ func Test_matchfuzzy()
call assert_equal(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], matchfuzzy(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], 'aa'))
call assert_equal(256, matchfuzzy([repeat('a', 256)], repeat('a', 256))[0]->len())
call assert_equal([], matchfuzzy([repeat('a', 300)], repeat('a', 257)))
+ " full match has highest score
+ call assert_equal(['Cursor', 'lCursor'], matchfuzzy(["hello", "lCursor", "Cursor"], "Cursor"))
" matches with same score should not be reordered
let l = ['abc1', 'abc2', 'abc3']
call assert_equal(l, l->matchfuzzy('abc'))
@@ -98,15 +100,15 @@ endfunc
" Test for the matchfuzzypos() function
func Test_matchfuzzypos()
- call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'curl'], 'rl'))
- call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'one', 'curl'], 'rl'))
+ call assert_equal([['curl', 'world'], [[2,3], [2,3]], [178, 177]], matchfuzzypos(['world', 'curl'], 'rl'))
+ call assert_equal([['curl', 'world'], [[2,3], [2,3]], [178, 177]], matchfuzzypos(['world', 'one', 'curl'], 'rl'))
call assert_equal([['hello', 'hello world hello world'],
- \ [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [275, 257]],
+ \ [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [500, 382]],
\ matchfuzzypos(['hello world hello world', 'hello', 'world'], 'hello'))
- call assert_equal([['aaaaaaa'], [[0, 1, 2]], [191]], matchfuzzypos(['aaaaaaa'], 'aaa'))
- call assert_equal([['a b'], [[0, 3]], [219]], matchfuzzypos(['a b'], 'a b'))
- call assert_equal([['a b'], [[0, 3]], [219]], matchfuzzypos(['a b'], 'a b'))
- call assert_equal([['a b'], [[0]], [112]], matchfuzzypos(['a b'], ' a '))
+ call assert_equal([['aaaaaaa'], [[0, 1, 2]], [266]], matchfuzzypos(['aaaaaaa'], 'aaa'))
+ call assert_equal([['a b'], [[0, 3]], [269]], matchfuzzypos(['a b'], 'a b'))
+ call assert_equal([['a b'], [[0, 3]], [269]], matchfuzzypos(['a b'], 'a b'))
+ call assert_equal([['a b'], [[0]], [137]], matchfuzzypos(['a b'], ' a '))
call assert_equal([[], [], []], matchfuzzypos(['a b'], ' '))
call assert_equal([[], [], []], matchfuzzypos(['world', 'curl'], 'ab'))
let x = matchfuzzypos([repeat('a', 256)], repeat('a', 256))
@@ -115,33 +117,33 @@ func Test_matchfuzzypos()
call assert_equal([[], [], []], matchfuzzypos([], 'abc'))
" match in a long string
- call assert_equal([[repeat('x', 300) .. 'abc'], [[300, 301, 302]], [-135]],
+ call assert_equal([[repeat('x', 300) .. 'abc'], [[300, 301, 302]], [-60]],
\ matchfuzzypos([repeat('x', 300) .. 'abc'], 'abc'))
" preference for camel case match
- call assert_equal([['xabcxxaBc'], [[6, 7, 8]], [189]], matchfuzzypos(['xabcxxaBc'], 'abc'))
+ call assert_equal([['xabcxxaBc'], [[6, 7, 8]], [269]], matchfuzzypos(['xabcxxaBc'], 'abc'))
" preference for match after a separator (_ or space)
- call assert_equal([['xabx_ab'], [[5, 6]], [145]], matchfuzzypos(['xabx_ab'], 'ab'))
+ call assert_equal([['xabx_ab'], [[5, 6]], [195]], matchfuzzypos(['xabx_ab'], 'ab'))
" preference for leading letter match
- call assert_equal([['abcxabc'], [[0, 1]], [150]], matchfuzzypos(['abcxabc'], 'ab'))
+ call assert_equal([['abcxabc'], [[0, 1]], [200]], matchfuzzypos(['abcxabc'], 'ab'))
" preference for sequential match
- call assert_equal([['aobncedone'], [[7, 8, 9]], [158]], matchfuzzypos(['aobncedone'], 'one'))
+ call assert_equal([['aobncedone'], [[7, 8, 9]], [233]], matchfuzzypos(['aobncedone'], 'one'))
" best recursive match
- call assert_equal([['xoone'], [[2, 3, 4]], [168]], matchfuzzypos(['xoone'], 'one'))
+ call assert_equal([['xoone'], [[2, 3, 4]], [243]], matchfuzzypos(['xoone'], 'one'))
" match multiple words (separated by space)
- call assert_equal([['foo bar baz'], [[8, 9, 10, 0, 1, 2]], [369]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo'))
+ call assert_equal([['foo bar baz'], [[8, 9, 10, 0, 1, 2]], [519]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo'))
call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo', {'matchseq': 1}))
- call assert_equal([['foo bar baz'], [[0, 1, 2, 8, 9, 10]], [369]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz'))
- call assert_equal([['foo bar baz'], [[0, 1, 2, 3, 4, 5, 10]], [326]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz', {'matchseq': 1}))
+ call assert_equal([['foo bar baz'], [[0, 1, 2, 8, 9, 10]], [519]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz'))
+ call assert_equal([['foo bar baz'], [[0, 1, 2, 3, 4, 5, 10]], [476]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz', {'matchseq': 1}))
call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('one two'))
call assert_equal([[], [], []], ['foo bar']->matchfuzzypos(" \t "))
- call assert_equal([['grace'], [[1, 2, 3, 4, 2, 3, 4, 0, 1, 2, 3, 4]], [657]], ['grace']->matchfuzzypos('race ace grace'))
+ call assert_equal([['grace'], [[1, 2, 3, 4, 2, 3, 4, 0, 1, 2, 3, 4]], [1057]], ['grace']->matchfuzzypos('race ace grace'))
let l = [{'id' : 5, 'val' : 'crayon'}, {'id' : 6, 'val' : 'camera'}]
- call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [192]],
+ call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [267]],
\ matchfuzzypos(l, 'cam', {'text_cb' : {v -> v.val}}))
- call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [192]],
+ call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [267]],
\ matchfuzzypos(l, 'cam', {'key' : 'val'}))
call assert_equal([[], [], []], matchfuzzypos(l, 'day', {'text_cb' : {v -> v.val}}))
call assert_equal([[], [], []], matchfuzzypos(l, 'day', {'key' : 'val'}))
@@ -159,6 +161,18 @@ func Test_matchfuzzypos()
" Nvim doesn't have null functions
" call assert_fails("let x = matchfuzzypos(l, 'foo', {'text_cb' : test_null_function()})", 'E475:')
+ " case match
+ call assert_equal([['Match', 'match'], [[0, 1], [0, 1]], [202, 177]], matchfuzzypos(['match', 'Match'], 'Ma'))
+ call assert_equal([['match', 'Match'], [[0, 1], [0, 1]], [202, 177]], matchfuzzypos(['Match', 'match'], 'ma'))
+ " CamelCase has high weight even case match
+ call assert_equal(['MyTestCase', 'mytestcase'], matchfuzzy(['mytestcase', 'MyTestCase'], 'mtc'))
+ call assert_equal(['MyTestCase', 'mytestcase'], matchfuzzy(['MyTestCase', 'mytestcase'], 'mtc'))
+ call assert_equal(['MyTest', 'Mytest', 'mytest', ],matchfuzzy(['Mytest', 'mytest', 'MyTest'], 'MyT'))
+ call assert_equal(['CamelCaseMatchIngAlg', 'camelCaseMatchingAlg', 'camelcasematchingalg'],
+ \ matchfuzzy(['CamelCaseMatchIngAlg', 'camelcasematchingalg', 'camelCaseMatchingAlg'], 'CamelCase'))
+ call assert_equal(['CamelCaseMatchIngAlg', 'camelCaseMatchingAlg', 'camelcasematchingalg'],
+ \ matchfuzzy(['CamelCaseMatchIngAlg', 'camelcasematchingalg', 'camelCaseMatchingAlg'], 'CamelcaseM'))
+
let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}]
call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : 'name'})", 'E730:')
endfunc
@@ -209,12 +223,12 @@ func Test_matchfuzzypos_mbyte()
call assert_equal([['ンヹㄇヺヴ'], [[1, 3]], [88]], matchfuzzypos(['ンヹㄇヺヴ'], 'ヹヺ'))
" reverse the order of characters
call assert_equal([[], [], []], matchfuzzypos(['ンヹㄇヺヴ'], 'ヺヹ'))
- call assert_equal([['αβΩxxx', 'xαxβxΩx'], [[0, 1, 2], [1, 3, 5]], [222, 113]],
+ call assert_equal([['αβΩxxx', 'xαxβxΩx'], [[0, 1, 2], [1, 3, 5]], [252, 143]],
\ matchfuzzypos(['αβΩxxx', 'xαxβxΩx'], 'αβΩ'))
call assert_equal([['ππbbππ', 'πππbbbπππ', 'ππππbbbbππππ', 'πbπ'],
- \ [[0, 1], [0, 1], [0, 1], [0, 2]], [151, 148, 145, 110]],
+ \ [[0, 1], [0, 1], [0, 1], [0, 2]], [176, 173, 170, 135]],
\ matchfuzzypos(['πbπ', 'ππbbππ', 'πππbbbπππ', 'ππππbbbbππππ'], 'ππ'))
- call assert_equal([['ααααααα'], [[0, 1, 2]], [191]],
+ call assert_equal([['ααααααα'], [[0, 1, 2]], [216]],
\ matchfuzzypos(['ααααααα'], 'ααα'))
call assert_equal([[], [], []], matchfuzzypos(['ンヹㄇ', 'ŗŝţ'], 'fffifl'))
@@ -227,10 +241,10 @@ func Test_matchfuzzypos_mbyte()
call assert_equal([[], [], []], ['세 마리의 작은 돼지', '마리의', '마리의 작은', '작은 돼지']->matchfuzzypos('파란 하늘'))
" match in a long string
- call assert_equal([[repeat('ぶ', 300) .. 'ẼẼẼ'], [[300, 301, 302]], [-135]],
+ call assert_equal([[repeat('ぶ', 300) .. 'ẼẼẼ'], [[300, 301, 302]], [-110]],
\ matchfuzzypos([repeat('ぶ', 300) .. 'ẼẼẼ'], 'ẼẼẼ'))
" preference for camel case match
- call assert_equal([['xѳѵҁxxѳѴҁ'], [[6, 7, 8]], [189]], matchfuzzypos(['xѳѵҁxxѳѴҁ'], 'ѳѵҁ'))
+ call assert_equal([['xѳѵҁxxѳѴҁ'], [[6, 7, 8]], [219]], matchfuzzypos(['xѳѵҁxxѳѴҁ'], 'ѳѵҁ'))
" preference for match after a separator (_ or space)
call assert_equal([['xちだx_ちだ'], [[5, 6]], [145]], matchfuzzypos(['xちだx_ちだ'], 'ちだ'))
" preference for leading letter match
diff --git a/test/old/testdir/test_messages.vim b/test/old/testdir/test_messages.vim
index ac5184645f..bfead20142 100644
--- a/test/old/testdir/test_messages.vim
+++ b/test/old/testdir/test_messages.vim
@@ -216,6 +216,7 @@ endfunc
" Test more-prompt (see :help more-prompt).
func Test_message_more()
CheckRunVimInTerminal
+
let buf = RunVimInTerminal('', {'rows': 6})
call term_sendkeys(buf, ":call setline(1, range(1, 100))\n")
@@ -611,4 +612,50 @@ func Test_cmdheight_zero()
tabonly
endfunc
+func Test_messagesopt_history()
+ " After setting 'messagesopt' "history" to 2 and outputting a message 4 times
+ " with :echomsg, is the number of output lines of :messages 2?
+ set messagesopt=hit-enter,history:2
+ echomsg 'foo'
+ echomsg 'bar'
+ echomsg 'baz'
+ echomsg 'foobar'
+ call assert_equal(['baz', 'foobar'], GetMessages())
+
+ " When the number of messages is 10 and 'messagesopt' "history" is changed to
+ " 5, is the number of output lines of :messages 5?
+ set messagesopt=hit-enter,history:10
+ for num in range(1, 10)
+ echomsg num
+ endfor
+ set messagesopt=hit-enter,history:5
+ call assert_equal(5, len(GetMessages()))
+
+ " Check empty list
+ set messagesopt=hit-enter,history:0
+ call assert_true(empty(GetMessages()))
+
+ set messagesopt&
+endfunc
+
+func Test_messagesopt_wait()
+ CheckRunVimInTerminal
+
+ let buf = RunVimInTerminal('', {'rows': 6, 'cols': 45})
+ call term_sendkeys(buf, ":set cmdheight=1\n")
+
+ " Check hit-enter prompt
+ call term_sendkeys(buf, ":set messagesopt=hit-enter,history:500\n")
+ call term_sendkeys(buf, ":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+
+ " Check no hit-enter prompt when "wait:" is set
+ call term_sendkeys(buf, ":set messagesopt=wait:100,history:500\n")
+ call term_sendkeys(buf, ":echo 'foo' | echo 'bar' | echo 'baz'\n")
+ call WaitForAssert({-> assert_equal(' 0,0-1 All', term_getline(buf, 6))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim
index c89e73bada..1d9609cbe1 100644
--- a/test/old/testdir/test_normal.vim
+++ b/test/old/testdir/test_normal.vim
@@ -1338,11 +1338,27 @@ func Test_scroll_in_ex_mode()
call writefile(['done'], 'Xdone')
qa!
END
- call writefile(lines, 'Xscript')
+ call writefile(lines, 'Xscript', 'D')
call assert_equal(1, RunVim([], [], '--clean -X -Z -e -s -S Xscript'))
call assert_equal(['done'], readfile('Xdone'))
- call delete('Xscript')
+ call delete('Xdone')
+endfunc
+
+func Test_scroll_and_paste_in_ex_mode()
+ throw 'Skipped: does not work when Nvim is run from :!'
+ " This used to crash because of moving cursor to line 0.
+ let lines =<< trim END
+ v/foo/vi|YY9PYQ
+ v/bar/vi|YY9PYQ
+ v/bar/exe line('.') == 1 ? "vi|Y\<C-B>9PYQ" : "vi|YQ"
+ call writefile(['done'], 'Xdone')
+ qa!
+ END
+ call writefile(lines, 'Xscript', 'D')
+ call assert_equal(1, RunVim([], [], '-u NONE -i NONE -n -X -Z -e -s -S Xscript'))
+ call assert_equal(['done'], readfile('Xdone'))
+
call delete('Xdone')
endfunc
@@ -4303,4 +4319,5 @@ func Test_normal_go()
bwipe!
endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim
index b6bdb1be52..2479f0ca51 100644
--- a/test/old/testdir/test_options.vim
+++ b/test/old/testdir/test_options.vim
@@ -496,7 +496,7 @@ func Test_set_completion_string_values()
" but don't exhaustively validate their results.
call assert_equal('single', getcompletion('set ambw=', 'cmdline')[0])
call assert_match('light\|dark', getcompletion('set bg=', 'cmdline')[1])
- call assert_equal('indent', getcompletion('set backspace=', 'cmdline')[0])
+ call assert_equal('indent,eol,start', getcompletion('set backspace=', 'cmdline')[0])
call assert_equal('yes', getcompletion('set backupcopy=', 'cmdline')[1])
call assert_equal('backspace', getcompletion('set belloff=', 'cmdline')[1])
call assert_equal('min:', getcompletion('set briopt=', 'cmdline')[1])
@@ -504,7 +504,8 @@ func Test_set_completion_string_values()
call assert_equal('current', getcompletion('set browsedir=', 'cmdline')[1])
endif
call assert_equal('unload', getcompletion('set bufhidden=', 'cmdline')[1])
- call assert_equal('nowrite', getcompletion('set buftype=', 'cmdline')[1])
+ "call assert_equal('nowrite', getcompletion('set buftype=', 'cmdline')[1])
+ call assert_equal('help', getcompletion('set buftype=', 'cmdline')[1])
call assert_equal('internal', getcompletion('set casemap=', 'cmdline')[1])
if exists('+clipboard')
" call assert_match('unnamed', getcompletion('set clipboard=', 'cmdline')[1])
@@ -644,6 +645,10 @@ func Test_set_completion_string_values()
" call feedkeys(":set hl=8b i\<Left>\<Left>\<Tab>\<C-B>\"\<CR>", 'xt')
" call assert_equal("\"set hl=8bi i", @:)
+ " messagesopt
+ call assert_equal(['history:', 'hit-enter', 'wait:'],
+ \ getcompletion('set messagesopt+=', 'cmdline')->sort())
+
"
" Test flag lists
"
@@ -706,6 +711,10 @@ func Test_set_completion_string_values()
" Test empty option
set diffopt=
call assert_equal([], getcompletion('set diffopt-=', 'cmdline'))
+ " Test all possible values
+ call assert_equal(['filler', 'context:', 'iblank', 'icase', 'iwhite', 'iwhiteall', 'iwhiteeol', 'horizontal',
+ \ 'vertical', 'closeoff', 'hiddenoff', 'foldcolumn:', 'followwrap', 'internal', 'indent-heuristic', 'algorithm:', 'linematch:'],
+ \ getcompletion('set diffopt=', 'cmdline'))
set diffopt&
" Test escaping output
@@ -743,7 +752,6 @@ func Test_set_option_errors()
call assert_fails('set backupcopy=', 'E474:')
call assert_fails('set regexpengine=3', 'E474:')
call assert_fails('set history=10001', 'E474:')
- call assert_fails('set msghistory=10001', 'E474:')
call assert_fails('set numberwidth=21', 'E474:')
call assert_fails('set colorcolumn=-a', 'E474:')
call assert_fails('set colorcolumn=a', 'E474:')
@@ -757,7 +765,6 @@ func Test_set_option_errors()
endif
call assert_fails('set helpheight=-1', 'E487:')
call assert_fails('set history=-1', 'E487:')
- call assert_fails('set msghistory=-1', 'E487:')
call assert_fails('set report=-1', 'E487:')
call assert_fails('set shiftwidth=-1', 'E487:')
call assert_fails('set sidescroll=-1', 'E487:')
@@ -2252,16 +2259,57 @@ func Test_opt_default()
call assert_equal('vt', &formatoptions)
set formatoptions&vim
call assert_equal('tcq', &formatoptions)
+
+ call assert_equal('ucs-bom,utf-8,default,latin1', &fencs)
+ set fencs=latin1
+ set fencs&
+ call assert_equal('ucs-bom,utf-8,default,latin1', &fencs)
+ set fencs=latin1
+ set all&
+ call assert_equal('ucs-bom,utf-8,default,latin1', &fencs)
endfunc
" Test for the 'cmdheight' option
-func Test_cmdheight()
+func Test_opt_cmdheight()
%bw!
let ht = &lines
set cmdheight=9999
call assert_equal(1, winheight(0))
call assert_equal(ht - 1, &cmdheight)
set cmdheight&
+
+ " The status line should be taken into account.
+ set laststatus=2
+ set cmdheight=9999
+ call assert_equal(ht - 2, &cmdheight)
+ set cmdheight& laststatus=1 " Accommodate Nvim default
+
+ " The tabline should be taken into account only non-GUI.
+ set showtabline=2
+ set cmdheight=9999
+ if has('gui_running')
+ call assert_equal(ht - 1, &cmdheight)
+ else
+ call assert_equal(ht - 2, &cmdheight)
+ endif
+ set cmdheight& showtabline&
+
+ " The 'winminheight' should be taken into account.
+ set winheight=3 winminheight=3
+ split
+ set cmdheight=9999
+ call assert_equal(ht - 8, &cmdheight)
+ %bw!
+ set cmdheight& winminheight& winheight&
+
+ " Only the windows in the current tabpage are taken into account.
+ set winheight=3 winminheight=3 showtabline=0
+ split
+ tabnew
+ set cmdheight=9999
+ call assert_equal(ht - 3, &cmdheight)
+ %bw!
+ set cmdheight& winminheight& winheight& showtabline&
endfunc
" To specify a control character as an option value, '^' can be used
@@ -2476,6 +2524,7 @@ func Test_string_option_revert_on_failure()
\ ['lispoptions', 'expr:1', 'a123'],
\ ['listchars', 'tab:->', 'tab:'],
\ ['matchpairs', '<:>', '<:'],
+ \ ['messagesopt', 'hit-enter,history:100', 'a123'],
\ ['mkspellmem', '100000,1000,100', '100000'],
\ ['mouse', 'nvi', 'z'],
\ ['mousemodel', 'extend', 'a123'],
diff --git a/test/old/testdir/test_perl.vim b/test/old/testdir/test_perl.vim
index c08a042dae..2d7f8fdc10 100644
--- a/test/old/testdir/test_perl.vim
+++ b/test/old/testdir/test_perl.vim
@@ -316,7 +316,10 @@ VIM::DoCommand('let s ..= "B"')
perl << trim eof
VIM::DoCommand('let s ..= "E"')
eof
- call assert_equal('ABCDE', s)
+ perl << trimm
+VIM::DoCommand('let s ..= "F"')
+trimm
+ call assert_equal('ABCDEF', s)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim
index 601ba6c688..e4abf978ab 100644
--- a/test/old/testdir/test_popup.vim
+++ b/test/old/testdir/test_popup.vim
@@ -748,17 +748,11 @@ func Test_popup_and_preview_autocommand()
bw!
endfunc
-func Test_popup_and_previewwindow_dump()
+func s:run_popup_and_previewwindow_dump(lines, dumpfile)
CheckScreendump
CheckFeature quickfix
- let lines =<< trim END
- set previewheight=9
- silent! pedit
- call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
- exec "norm! G\<C-E>\<C-E>"
- END
- call writefile(lines, 'Xscript')
+ call writefile(a:lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
" wait for the script to finish
@@ -768,11 +762,30 @@ func Test_popup_and_previewwindow_dump()
call term_sendkeys(buf, "o")
call TermWait(buf, 50)
call term_sendkeys(buf, "\<C-X>\<C-N>")
- call VerifyScreenDump(buf, 'Test_popup_and_previewwindow_01', {})
+ call VerifyScreenDump(buf, a:dumpfile, {})
call term_sendkeys(buf, "\<Esc>u")
call StopVimInTerminal(buf)
- call delete('Xscript')
+endfunc
+
+func Test_popup_and_previewwindow_dump_pedit()
+ let lines =<< trim END
+ set previewheight=9
+ silent! pedit
+ call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
+ exec "norm! G\<C-E>\<C-E>"
+ END
+ call s:run_popup_and_previewwindow_dump(lines, 'Test_popup_and_previewwindow_pedit')
+endfunc
+
+func Test_popup_and_previewwindow_dump_pbuffer()
+ let lines =<< trim END
+ set previewheight=9
+ silent! pbuffer
+ call setline(1, map(repeat(["ab"], 10), "v:val .. v:key"))
+ exec "norm! G\<C-E>\<C-E>\<C-E>"
+ END
+ call s:run_popup_and_previewwindow_dump(lines, 'Test_popup_and_previewwindow_pbuffer')
endfunc
func Test_balloon_split()
@@ -1506,6 +1519,39 @@ func Test_pum_highlights_match()
call StopVimInTerminal(buf)
endfunc
+func Test_pum_highlights_match_with_abbr()
+ CheckScreendump
+ let lines =<< trim END
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'foobar', 'abbr': "foobar\t\t!" },
+ \ { 'word': 'foobaz', 'abbr': "foobaz\t\t!" },
+ \]}
+ endfunc
+
+ set omnifunc=Omni_test
+ set completeopt=menuone,noinsert
+ hi PmenuMatchSel ctermfg=6 ctermbg=7
+ hi PmenuMatch ctermfg=4 ctermbg=225
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call TermWait(buf)
+ call term_sendkeys(buf, "i\<C-X>\<C-O>")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "foo")
+ call VerifyScreenDump(buf, 'Test_pum_highlights_19', {})
+
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+ call TermWait(buf)
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_pum_user_abbr_hlgroup()
CheckScreendump
let lines =<< trim END
@@ -1675,4 +1721,168 @@ func Test_pum_completeitemalign()
call StopVimInTerminal(buf)
endfunc
+func Test_pum_keep_select()
+ CheckScreendump
+ let lines =<< trim END
+ set completeopt=menu,menuone,noinsert
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+ call TermWait(buf)
+
+ call term_sendkeys(buf, "ggSFab\<CR>Five\<CR>find\<CR>film\<CR>\<C-X>\<C-P>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_pum_keep_select_01', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+ call TermWait(buf, 50)
+
+ call term_sendkeys(buf, "S\<C-X>\<C-P>")
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, "F")
+ call VerifyScreenDump(buf, 'Test_pum_keep_select_02', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call TermWait(buf, 50)
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_pum_matchins_highlight()
+ CheckScreendump
+ let lines =<< trim END
+ let g:change = 0
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ if g:change == 0
+ return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ endif
+ return [#{word: "foo", info: "info"}, #{word: "bar"}, #{word: "你好"}]
+ endfunc
+ set omnifunc=Omni_test
+ hi ComplMatchIns ctermfg=red
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+
+ call TermWait(buf)
+ call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_01', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call TermWait(buf)
+ call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_02', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call TermWait(buf)
+ call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-N>\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_03', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ " restore after accept
+ call TermWait(buf)
+ call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " restore after cancel completion
+ call TermWait(buf)
+ call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " text after the inserted text shouldn't be highlighted
+ call TermWait(buf)
+ call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_07', {})
+ call term_sendkeys(buf, "\<C-P>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_08', {})
+ call term_sendkeys(buf, "\<C-P>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_09', {})
+ call term_sendkeys(buf, "\<C-Y>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_10', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call term_sendkeys(buf, ":let g:change=1\<CR>S\<C-X>\<C-O>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_11', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_pum_matchins_highlight_combine()
+ CheckScreendump
+ let lines =<< trim END
+ func Omni_test(findstart, base)
+ if a:findstart
+ return col(".")
+ endif
+ return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
+ endfunc
+ set omnifunc=Omni_test
+ hi Normal ctermbg=blue
+ hi CursorLine cterm=underline ctermbg=green
+ set cursorline
+ call setline(1, 'aaa bbb')
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+
+ " when ComplMatchIns is not set, CursorLine applies normally
+ call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_01', {})
+ call term_sendkeys(buf, "\<C-E>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_02', {})
+ call term_sendkeys(buf, "\<BS>\<Esc>")
+
+ " when ComplMatchIns is set, it is applied over CursorLine
+ call TermWait(buf)
+ call term_sendkeys(buf, ":hi ComplMatchIns ctermbg=red ctermfg=yellow\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_03', {})
+ call term_sendkeys(buf, "\<C-P>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_04', {})
+ call term_sendkeys(buf, "\<C-P>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_05', {})
+ call term_sendkeys(buf, "\<C-E>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_06', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Does not highlight the compl leader
+ call TermWait(buf)
+ call term_sendkeys(buf, ":set cot+=menuone,noselect\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "S\<C-X>\<C-O>f\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_07', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call term_sendkeys(buf, ":set cot+=fuzzy\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "S\<C-X>\<C-O>f\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_08', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+ call TermWait(buf)
+
+ call term_sendkeys(buf, ":set cot-=fuzzy\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "Sf\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_matchins_combine_09', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" this used to crash
+func Test_popup_completion_many_ctrlp()
+ new
+ let candidates=repeat(['a0'], 99)
+ call setline(1, candidates)
+ exe ":norm! VGg\<C-A>"
+ norm! G
+ call feedkeys("o" .. repeat("\<c-p>", 100), 'tx')
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_preview.vim b/test/old/testdir/test_preview.vim
index b7b908e761..422c50ac77 100644
--- a/test/old/testdir/test_preview.vim
+++ b/test/old/testdir/test_preview.vim
@@ -15,6 +15,20 @@ func Test_Psearch()
bwipe
endfunc
+func s:goto_preview_and_close()
+ " Go to the preview window
+ wincmd P
+ call assert_equal(1, &previewwindow)
+ call assert_equal('preview', win_gettype())
+
+ " Close preview window
+ wincmd z
+ call assert_equal(1, winnr('$'))
+ call assert_equal(0, &previewwindow)
+
+ call assert_fails('wincmd P', 'E441:')
+endfunc
+
func Test_window_preview()
CheckFeature quickfix
@@ -23,17 +37,48 @@ func Test_window_preview()
call assert_equal(2, winnr('$'))
call assert_equal(0, &previewwindow)
- " Go to the preview window
- wincmd P
- call assert_equal(1, &previewwindow)
- call assert_equal('preview', win_gettype())
+ call s:goto_preview_and_close()
+endfunc
+
+func Test_window_preview_from_pbuffer()
+ CheckFeature quickfix
+
+ call writefile(['/* some C code */'], 'Xpreview.c', 'D')
+ edit Xpreview.c
+ const buf_num = bufnr('%')
+ enew
+
+ call feedkeys(":pbuffer Xpre\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"pbuffer Xpreview.c", @:)
- " Close preview window
- wincmd z
call assert_equal(1, winnr('$'))
+ exe 'pbuffer ' . buf_num
+ call assert_equal(2, winnr('$'))
call assert_equal(0, &previewwindow)
- call assert_fails('wincmd P', 'E441:')
+ call s:goto_preview_and_close()
+
+ call assert_equal(1, winnr('$'))
+ pbuffer Xpreview.c
+ call assert_equal(2, winnr('$'))
+ call assert_equal(0, &previewwindow)
+
+ call s:goto_preview_and_close()
+endfunc
+
+func Test_window_preview_terminal()
+ CheckFeature quickfix
+ " CheckFeature terminal
+
+ " term ++curwin
+ term
+ const buf_num = bufnr('$')
+ call assert_equal(1, winnr('$'))
+ exe 'pbuffer' . buf_num
+ call assert_equal(2, winnr('$'))
+ call assert_equal(0, &previewwindow)
+
+ call s:goto_preview_and_close()
endfunc
func Test_window_preview_from_help()
diff --git a/test/old/testdir/test_python3.vim b/test/old/testdir/test_python3.vim
index c9dbc0b84e..2436587100 100644
--- a/test/old/testdir/test_python3.vim
+++ b/test/old/testdir/test_python3.vim
@@ -284,7 +284,10 @@ s+='B'
python3 << trim eof
s+='E'
eof
- call assert_equal('ABCDE', pyxeval('s'))
+ python3 << trimm
+s+='F'
+trimm
+ call assert_equal('ABCDEF', pyxeval('s'))
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_pyx3.vim b/test/old/testdir/test_pyx3.vim
index 89a3cc22ff..8dfeaff807 100644
--- a/test/old/testdir/test_pyx3.vim
+++ b/test/old/testdir/test_pyx3.vim
@@ -97,7 +97,10 @@ result+='B'
pyx << trim eof
result+='E'
eof
- call assert_equal('ABCDE', pyxeval('result'))
+ pyx << trimm
+result+='F'
+trimm
+ call assert_equal('ABCDEF', pyxeval('result'))
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_ruby.vim b/test/old/testdir/test_ruby.vim
index d4a3dc3301..94941da873 100644
--- a/test/old/testdir/test_ruby.vim
+++ b/test/old/testdir/test_ruby.vim
@@ -282,7 +282,7 @@ func Test_ruby_Vim_buffer_get()
call assert_match('Xfoo1$', rubyeval('Vim::Buffer[1].name'))
call assert_match('Xfoo2$', rubyeval('Vim::Buffer[2].name'))
call assert_fails('ruby print Vim::Buffer[3].name',
- \ "NoMethodError: undefined method `name' for nil")
+ \ "NoMethodError")
%bwipe
endfunc
@@ -364,7 +364,7 @@ func Test_ruby_Vim_evaluate_dict()
redir => l:out
ruby d = Vim.evaluate("d"); print d
redir END
- call assert_equal(['{"a"=>"foo", "b"=>123}'], split(l:out, "\n"))
+ call assert_equal(['{"a"=>"foo","b"=>123}'], split(substitute(l:out, '\s', '', 'g'), "\n"))
endfunc
" Test Vim::message({msg}) (display message {msg})
@@ -384,7 +384,7 @@ func Test_ruby_print()
call assert_equal('1.23', RubyPrint('1.23'))
call assert_equal('Hello World!', RubyPrint('"Hello World!"'))
call assert_equal('[1, 2]', RubyPrint('[1, 2]'))
- call assert_equal('{"k1"=>"v1", "k2"=>"v2"}', RubyPrint('({"k1" => "v1", "k2" => "v2"})'))
+ call assert_equal('{"k1"=>"v1","k2"=>"v2"}', substitute(RubyPrint('({"k1" => "v1", "k2" => "v2"})'), '\s', '', 'g'))
call assert_equal('true', RubyPrint('true'))
call assert_equal('false', RubyPrint('false'))
call assert_equal('', RubyPrint('nil'))
@@ -439,7 +439,10 @@ Vim.command('let s ..= "B"')
ruby << trim eof
Vim.command('let s ..= "E"')
eof
- call assert_equal('ABCDE', s)
+ruby << trimm
+Vim.command('let s ..= "F"')
+trimm
+ call assert_equal('ABCDEF', s)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_shift.vim b/test/old/testdir/test_shift.vim
index ec357dac88..f31c5a11e6 100644
--- a/test/old/testdir/test_shift.vim
+++ b/test/old/testdir/test_shift.vim
@@ -108,10 +108,809 @@ func Test_ex_shift_errors()
call assert_fails('>!', 'E477:')
call assert_fails('<!', 'E477:')
- " call assert_fails('2,1>', 'E493:')
- call assert_fails('execute "2,1>"', 'E493:')
- " call assert_fails('2,1<', 'E493:')
- call assert_fails('execute "2,1<"', 'E493:')
+ call assert_fails('2,1>', 'E493:')
+ call assert_fails('2,1<', 'E493:')
+endfunc
+
+" Test inserting a backspace at the start of a line.
+"
+" This is to verify the proper behavior of tabstop_start() as called from
+" ins_bs().
+"
+func Test_shift_ins_bs()
+ set backspace=indent,start
+ set softtabstop=11
+
+ call setline(1, repeat(" ", 33) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 22) . "word", getline(1))
+ call setline(1, repeat(" ", 23) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 22) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 11) . "word", getline(1))
+
+ set backspace& softtabstop&
+ bw!
+endfunc
+
+" Test inserting a backspace at the start of a line, with 'varsofttabstop'.
+"
+func Test_shift_ins_bs_vartabs()
+ CheckFeature vartabs
+ set backspace=indent,start
+ set varsofttabstop=13,11,7
+
+ call setline(1, repeat(" ", 44) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ call setline(1, repeat(" ", 39) . "word")
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 31) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 24) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal(repeat(" ", 13) . "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal( "word", getline(1))
+ exe "norm! I\<BS>"
+ call assert_equal( "word", getline(1))
+
+ set backspace& varsofttabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands.
+"
+func Test_shift_norm()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, " word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ norm! >>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 12) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 12) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, " word")
+
+ norm! >>
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 16) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 16) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands, with 'vartabstop'.
+"
+func Test_shift_norm_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, " word")
+
+ norm! >>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 60) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands with 'shiftround'.
+"
+func Test_shift_norm_round()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, "word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 25) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+
+ call setline(1, repeat(" ", 7) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ call setline(1, repeat(" ", 2) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ norm! >>
+ call assert_equal(repeat(" ", 35) . "word", getline(1))
+
+ norm! <<
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+
+ call setline(1, repeat(" ", 9) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ call setline(1, repeat(" ", 2) . "word")
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the >> and << normal-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_norm_round_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! I "
+ norm! >>
+ call assert_equal(repeat(" ", 58) . "word", getline(1))
+
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 58) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! <<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I "
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands.
+"
+" See ":help v_<" and ":help v_>". See also the last paragraph of "3. Simple
+" changes", ":help simple-change", immediately above "4. Complex changes",
+" ":help complex-change".
+"
+func Test_shift_vis()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, " word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ norm! V>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ norm! V2>
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+ norm! V3>
+ call assert_equal(repeat(" ", 32) . "word", getline(1))
+
+ norm! V<
+ call assert_equal(repeat(" ", 27) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, " word")
+
+ norm! V>
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ norm! V2>
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+ norm! V3>
+ call assert_equal(repeat(" ", 44) . "word", getline(1))
+
+ norm! V<
+ call assert_equal(repeat(" ", 37) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands, with 'vartabstop'.
+"
+" See ":help v_<" and ":help v_>". See also the last paragraph of "3. Simple
+" changes", ":help simple-change", immediately above "4. Complex changes",
+" ":help complex-change".
+"
+func Test_shift_vis_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, " word")
+
+ norm! V>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! V2>
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! V3>
+ call assert_equal(repeat(" ", 82) . "word", getline(1))
+
+ norm! V<
+ call assert_equal(repeat(" ", 71) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands with 'shiftround'.
+"
+func Test_shift_vis_round()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, "word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ exe "norm! I "
+ norm! V>
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ exe "norm! I "
+ norm! V2>
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ norm! V3>
+ call assert_equal(repeat(" ", 30) . "word", getline(1))
+
+ exe "norm! I "
+ norm! V2<
+ call assert_equal(repeat(" ", 25) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! V>
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ exe "norm! I "
+ norm! V2>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ norm! V3>
+ call assert_equal(repeat(" ", 42) . "word", getline(1))
+
+ exe "norm! I "
+ norm! V<
+ call assert_equal(repeat(" ", 42) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 35) . "word", getline(1))
+ norm! V2<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ call setline(1, " word")
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+
+ set expandtab& shiftround& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the V> and V< visual-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_vis_round_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ exe "norm! I "
+ norm! V>
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! V3>
+ call assert_equal(repeat(" ", 58) . "word", getline(1))
+
+ exe "norm! I "
+ norm! V2<
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! I "
+ norm! V3<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ norm! V3<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I "
+ norm! V<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands.
+"
+func Test_shift_ex()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, " word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ >
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ >>
+ call assert_equal(repeat(" ", 17) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 32) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 12) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, " word")
+
+ >
+ call assert_equal(repeat(" ", 9) . "word", getline(1))
+ >>
+ call assert_equal(repeat(" ", 23) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 44) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 16) . "word", getline(1))
+ <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands, with vartabstop.
+"
+func Test_shift_ex_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, " word")
+
+ >
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ >>
+ call assert_equal(repeat(" ", 49) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 82) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 38) . "word", getline(1))
+ <<
+ call assert_equal(repeat(" ", 2) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands with 'shiftround'.
+"
+func Test_shift_ex_round()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=5
+ set tabstop=7
+
+ call setline(1, "word")
+
+ " Shift by 'shiftwidth' right and left.
+
+ exe "norm! I "
+ >
+ call assert_equal(repeat(" ", 5) . "word", getline(1))
+ exe "norm! I "
+ >>
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ >>>
+ call assert_equal(repeat(" ", 30) . "word", getline(1))
+
+ exe "norm! I "
+ <<<<
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ >>
+ <<<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ exe "norm! I "
+ >
+ call assert_equal(repeat(" ", 7) . "word", getline(1))
+ exe "norm! I "
+ >>
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ >>>
+ call assert_equal(repeat(" ", 42) . "word", getline(1))
+
+ exe "norm! I "
+ <<<<
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I "
+ <<<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ >>
+ <<<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test the :> and :< ex-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_ex_round_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftround
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ exe "norm! I "
+ >
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ >>
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ >>>
+ call assert_equal(repeat(" ", 80) . "word", getline(1))
+
+ <<<<
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I "
+ <<
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ <
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftround& shiftwidth& vartabstop&
+ bw!
+endfunc
+
+" Test shifting lines with <C-T> and <C-D>.
+"
+func Test_shift_ins()
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=5
+ set tabstop=7
+
+ " Shift by 'shiftwidth' right and left.
+
+ call setline(1, repeat(" ", 7) . "word")
+ exe "norm! 9|i\<C-T>"
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! A\<C-T>"
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I \<C-T>"
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+
+ exe "norm! I \<C-D>"
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! 24|i\<C-D>"
+ call assert_equal(repeat(" ", 20) . "word", getline(1))
+ exe "norm! A\<C-D>"
+ call assert_equal(repeat(" ", 15) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! A\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 10) . "word", getline(1))
+ exe "norm! I\<C-D>\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ " Shift by 'tabstop' right and left.
+
+ set shiftwidth=0
+ call setline(1, "word")
+
+ call setline(1, repeat(" ", 9) . "word")
+ exe "norm! 11|i\<C-T>"
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! A\<C-T>"
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I \<C-T>"
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+
+ exe "norm! I \<C-D>"
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! 32|i\<C-D>"
+ call assert_equal(repeat(" ", 28) . "word", getline(1))
+ exe "norm! A\<C-D>"
+ call assert_equal(repeat(" ", 21) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! A\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 14) . "word", getline(1))
+ exe "norm! I\<C-D>\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& tabstop&
+ bw!
+endfunc
+
+" Test shifting lines with <C-T> and <C-D>, with 'vartabstop'.
+"
+func Test_shift_ins_vartabs()
+ CheckFeature vartabs
+ set expandtab " Don't want to worry about tabs vs. spaces in
+ " results.
+
+ set shiftwidth=0
+ set vartabstop=19,17,11
+
+ " Shift by 'vartabstop' right and left.
+
+ call setline(1, "word")
+
+ call setline(1, repeat(" ", 9) . "word")
+ exe "norm! 11|i\<C-T>"
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! A\<C-T>"
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I \<C-T>"
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+
+ exe "norm! I \<C-D>"
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! 51|i\<C-D>"
+ call assert_equal(repeat(" ", 47) . "word", getline(1))
+ exe "norm! A\<C-D>"
+ call assert_equal(repeat(" ", 36) . "word", getline(1))
+ exe "norm! I "
+ exe "norm! A\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 19) . "word", getline(1))
+ exe "norm! I\<C-D>\<C-D>\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+ exe "norm! I\<C-D>"
+ call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+ set expandtab& shiftwidth& vartabstop&
+ bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_spell.vim b/test/old/testdir/test_spell.vim
index bdd8a673fd..a5ae653369 100644
--- a/test/old/testdir/test_spell.vim
+++ b/test/old/testdir/test_spell.vim
@@ -471,7 +471,9 @@ func Test_spellsuggest_option_number()
\ .. "Change \"baord\" to:\n"
\ .. " 1 \"board\"\n"
\ .. " 2 \"bard\"\n"
- \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
+ "\ Nvim: Prompt message is sent to cmdline prompt.
+ "\ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
+ \ , a)
set spell spellsuggest=0
call assert_equal("\nSorry, no suggestions", execute('norm $z='))
@@ -509,7 +511,9 @@ func Test_spellsuggest_option_expr()
\ .. " 1 \"BARD\"\n"
\ .. " 2 \"BOARD\"\n"
\ .. " 3 \"BROAD\"\n"
- \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
+ "\ Nvim: Prompt message is sent to cmdline prompt.
+ "\ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
+ \ , a)
" With verbose, z= should show the score i.e. word length with
" our SpellSuggest() function.
@@ -521,7 +525,9 @@ func Test_spellsuggest_option_expr()
\ .. " 1 \"BARD\" (4 - 0)\n"
\ .. " 2 \"BOARD\" (5 - 0)\n"
\ .. " 3 \"BROAD\" (5 - 0)\n"
- \ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
+ "\ Nvim: Prompt message is sent to cmdline prompt.
+ "\ .. "Type number and <Enter> or click with the mouse (q or empty cancels): ", a)
+ \ , a)
set spell& spellsuggest& verbose&
bwipe!
diff --git a/test/old/testdir/test_stacktrace.vim b/test/old/testdir/test_stacktrace.vim
new file mode 100644
index 0000000000..9e1f51e1f6
--- /dev/null
+++ b/test/old/testdir/test_stacktrace.vim
@@ -0,0 +1,142 @@
+" Test for getstacktrace() and v:stacktrace
+
+source vim9.vim
+
+let s:thisfile = expand('%:p')
+let s:testdir = s:thisfile->fnamemodify(':h')
+
+func Filepath(name)
+ return s:testdir .. '/' .. a:name
+endfunc
+
+func AssertStacktrace(expect, actual)
+ call assert_equal(Filepath('runtest.vim'), a:actual[0]['filepath'])
+ call assert_equal(a:expect, a:actual[-len(a:expect):])
+endfunc
+
+func Test_getstacktrace()
+ let g:stacktrace = []
+ let lines1 =<< trim [SCRIPT]
+ " Xscript1
+ source Xscript2
+ func Xfunc1()
+ " Xfunc1
+ call Xfunc2()
+ endfunc
+ [SCRIPT]
+ let lines2 =<< trim [SCRIPT]
+ " Xscript2
+ func Xfunc2()
+ " Xfunc2
+ let g:stacktrace = getstacktrace()
+ endfunc
+ [SCRIPT]
+ call writefile(lines1, 'Xscript1', 'D')
+ call writefile(lines2, 'Xscript2', 'D')
+ source Xscript1
+ call Xfunc1()
+ call AssertStacktrace([
+ \ #{funcref: funcref('Test_getstacktrace'), lnum: 37, filepath: s:thisfile},
+ \ #{funcref: funcref('Xfunc1'), lnum: 5, filepath: Filepath('Xscript1')},
+ \ #{funcref: funcref('Xfunc2'), lnum: 4, filepath: Filepath('Xscript2')},
+ \ ], g:stacktrace)
+ unlet g:stacktrace
+endfunc
+
+func Test_getstacktrace_event()
+ let g:stacktrace = []
+ let lines1 =<< trim [SCRIPT]
+ " Xscript1
+ func Xfunc()
+ " Xfunc
+ let g:stacktrace = getstacktrace()
+ endfunc
+ augroup test_stacktrace
+ autocmd SourcePre * call Xfunc()
+ augroup END
+ [SCRIPT]
+ let lines2 =<< trim [SCRIPT]
+ " Xscript2
+ [SCRIPT]
+ call writefile(lines1, 'Xscript1', 'D')
+ call writefile(lines2, 'Xscript2', 'D')
+ source Xscript1
+ source Xscript2
+ call AssertStacktrace([
+ \ #{funcref: funcref('Test_getstacktrace_event'), lnum: 64, filepath: s:thisfile},
+ \ #{event: 'SourcePre Autocommands for "*"', lnum: 7, filepath: Filepath('Xscript1')},
+ \ #{funcref: funcref('Xfunc'), lnum: 4, filepath: Filepath('Xscript1')},
+ \ ], g:stacktrace)
+ augroup test_stacktrace
+ autocmd!
+ augroup END
+ unlet g:stacktrace
+endfunc
+
+func Test_vstacktrace()
+ let lines1 =<< trim [SCRIPT]
+ " Xscript1
+ source Xscript2
+ func Xfunc1()
+ " Xfunc1
+ call Xfunc2()
+ endfunc
+ [SCRIPT]
+ let lines2 =<< trim [SCRIPT]
+ " Xscript2
+ func Xfunc2()
+ " Xfunc2
+ throw 'Exception from Xfunc2'
+ endfunc
+ [SCRIPT]
+ call writefile(lines1, 'Xscript1', 'D')
+ call writefile(lines2, 'Xscript2', 'D')
+ source Xscript1
+ call assert_equal([], v:stacktrace)
+ try
+ call Xfunc1()
+ catch
+ let stacktrace = v:stacktrace
+ try
+ call Xfunc1()
+ catch
+ let stacktrace_inner = v:stacktrace
+ endtry
+ let stacktrace_after = v:stacktrace " should be restored by the exception stack to the previous one
+ endtry
+ call assert_equal([], v:stacktrace)
+ call AssertStacktrace([
+ \ #{funcref: funcref('Test_vstacktrace'), lnum: 97, filepath: s:thisfile},
+ \ #{funcref: funcref('Xfunc1'), lnum: 5, filepath: Filepath('Xscript1')},
+ \ #{funcref: funcref('Xfunc2'), lnum: 4, filepath: Filepath('Xscript2')},
+ \ ], stacktrace)
+ call AssertStacktrace([
+ \ #{funcref: funcref('Test_vstacktrace'), lnum: 101, filepath: s:thisfile},
+ \ #{funcref: funcref('Xfunc1'), lnum: 5, filepath: Filepath('Xscript1')},
+ \ #{funcref: funcref('Xfunc2'), lnum: 4, filepath: Filepath('Xscript2')},
+ \ ], stacktrace_inner)
+ call assert_equal(stacktrace, stacktrace_after)
+endfunc
+
+func Test_stacktrace_vim9()
+ let lines =<< trim [SCRIPT]
+ var stacktrace = getstacktrace()
+ assert_notequal([], stacktrace)
+ for d in stacktrace
+ assert_true(has_key(d, 'lnum'))
+ endfor
+ try
+ throw 'Exception from s:Func'
+ catch
+ assert_notequal([], v:stacktrace)
+ assert_equal(len(stacktrace), len(v:stacktrace))
+ for d in v:stacktrace
+ assert_true(has_key(d, 'lnum'))
+ endfor
+ endtry
+ call assert_equal([], v:stacktrace)
+ [SCRIPT]
+ call CheckDefSuccess(lines)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_statusline.vim b/test/old/testdir/test_statusline.vim
index c8162ced07..c9f79dfef7 100644
--- a/test/old/testdir/test_statusline.vim
+++ b/test/old/testdir/test_statusline.vim
@@ -220,6 +220,10 @@ func Test_statusline()
wincmd j
call assert_match('^\[Preview\],PRV\s*$', s:get_statusline())
pclose
+ pbuffer
+ wincmd j
+ call assert_match('^\[Preview\],PRV\s*$', s:get_statusline())
+ pclose
" %y: Type of file in the buffer, e.g., "[vim]". See 'filetype'.
" %Y: Type of file in the buffer, e.g., ",VIM". See 'filetype'.
diff --git a/test/old/testdir/test_tagjump.vim b/test/old/testdir/test_tagjump.vim
index 470c5c43b4..efc5e4cebe 100644
--- a/test/old/testdir/test_tagjump.vim
+++ b/test/old/testdir/test_tagjump.vim
@@ -1231,8 +1231,10 @@ func Test_tselect_listing()
2 FS v first Xfoo
typeref:typename:char
2
-Type number and <Enter> (q or empty cancels):
[DATA]
+" Type number and <Enter> (q or empty cancels):
+" Nvim: Prompt message is sent to cmdline prompt.
+
call assert_equal(expected, l)
call delete('Xtags')
diff --git a/test/old/testdir/test_termdebug.vim b/test/old/testdir/test_termdebug.vim
index eb88ea6f5f..6ff233fff0 100644
--- a/test/old/testdir/test_termdebug.vim
+++ b/test/old/testdir/test_termdebug.vim
@@ -391,7 +391,8 @@ endfunc
function Test_termdebug_save_restore_variables()
" saved mousemodel
- let &mousemodel=''
+ "let &mousemodel=''
+ let &mousemodel='extend'
" saved keys
nnoremap K :echo "hello world!"<cr>
@@ -414,7 +415,8 @@ function Test_termdebug_save_restore_variables()
quit!
call WaitForAssert({-> assert_equal(1, winnr('$'))})
- call assert_true(empty(&mousemodel))
+ "call assert_true(empty(&mousemodel))
+ call assert_equal(&mousemodel, 'extend')
call assert_true(empty(expected_map_minus))
call assert_equal(expected_map_K.rhs, maparg('K', 'n', 0, 1).rhs)
diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim
index 3c24412eb7..b1543c8f24 100644
--- a/test/old/testdir/test_user_func.vim
+++ b/test/old/testdir/test_user_func.vim
@@ -380,7 +380,7 @@ func Test_script_local_func()
" Try to call a script local function in global scope
let lines =<< trim [CODE]
:call assert_fails('call s:Xfunc()', 'E81:')
- :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:')
+ :call assert_fails('let x = call("<SID>Xfunc", [])', ['E81:', 'E117:'])
:call writefile(v:errors, 'Xresult')
:qall
@@ -421,12 +421,48 @@ func Test_func_def_error()
call assert_fails('exe l', 'E717:')
" Define an autoload function with an incorrect file name
- call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript')
+ call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript', 'D')
call assert_fails('source Xscript', 'E746:')
- call delete('Xscript')
" Try to list functions using an invalid search pattern
call assert_fails('function /\%(/', 'E53:')
+
+ " Use a script-local function to cover uf_name_exp.
+ func s:TestRedefine(arg1 = 1, arg2 = 10)
+ let caught_E122 = 0
+ try
+ func s:TestRedefine(arg1 = 1, arg2 = 10)
+ endfunc
+ catch /E122:/
+ let caught_E122 = 1
+ endtry
+ call assert_equal(1, caught_E122)
+
+ let caught_E127 = 0
+ try
+ func! s:TestRedefine(arg1 = 1, arg2 = 10)
+ endfunc
+ catch /E127:/
+ let caught_E127 = 1
+ endtry
+ call assert_equal(1, caught_E127)
+
+ " The failures above shouldn't cause heap-use-after-free here.
+ return [a:arg1 + a:arg2, expand('<stack>')]
+ endfunc
+
+ let stacks = []
+ " Call the function twice.
+ " Failing to redefine a function shouldn't clear its argument list.
+ for i in range(2)
+ let [val, stack] = s:TestRedefine(1000)
+ call assert_equal(1010, val)
+ call assert_match(expand('<SID>') .. 'TestRedefine\[20\]$', stack)
+ call add(stacks, stack)
+ endfor
+ call assert_equal(stacks[0], stacks[1])
+
+ delfunc s:TestRedefine
endfunc
" Test for deleting a function
@@ -910,4 +946,36 @@ func Test_func_curly_brace_invalid_name()
delfunc Fail
endfunc
+func Test_func_return_in_try_verbose()
+ func TryReturnList()
+ try
+ return [1, 2, 3]
+ endtry
+ endfunc
+ func TryReturnNumber()
+ try
+ return 123
+ endtry
+ endfunc
+ func TryReturnOverlongString()
+ try
+ return repeat('a', 9999)
+ endtry
+ endfunc
+
+ " This should not cause heap-use-after-free
+ call assert_match('\n:return \[1, 2, 3\] made pending\n',
+ \ execute('14verbose call TryReturnList()'))
+ " This should not cause stack-use-after-scope
+ call assert_match('\n:return 123 made pending\n',
+ \ execute('14verbose call TryReturnNumber()'))
+ " An overlong string is truncated
+ call assert_match('\n:return a\{100,}\.\.\.',
+ \ execute('14verbose call TryReturnOverlongString()'))
+
+ delfunc TryReturnList
+ delfunc TryReturnNumber
+ delfunc TryReturnOverlongString
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim
index e25327ddd4..328ac502bf 100644
--- a/test/old/testdir/test_visual.vim
+++ b/test/old/testdir/test_visual.vim
@@ -470,7 +470,7 @@ func Test_Visual_Block()
\ "\t{",
\ "\t}"], getline(1, '$'))
- close!
+ bw!
endfunc
" Test for 'p'ut in visual block mode
@@ -1082,7 +1082,7 @@ func Test_star_register()
delmarks < >
call assert_fails('*yank', 'E20:')
- close!
+ bw!
endfunc
" Test for changing text in visual mode with 'exclusive' selection
@@ -1098,7 +1098,7 @@ func Test_exclusive_selection()
call assert_equal('l one', getline(1))
set virtualedit&
set selection&
- close!
+ bw!
endfunc
" Test for starting linewise visual with a count.
@@ -1155,7 +1155,7 @@ func Test_visual_inner_block()
8,9d
call cursor(5, 1)
call assert_beeps('normal ViBiB')
- close!
+ bw!
endfunc
func Test_visual_put_in_block()
@@ -2718,4 +2718,68 @@ func Test_visual_block_cursor_insert_enter()
bwipe!
endfunc
+func Test_visual_block_exclusive_selection()
+ new
+ set selection=exclusive
+ call setline(1, ['asöd asdf', 'asdf asdf', 'as€d asdf', 'asdf asdf'])
+ call cursor(1, 1)
+ exe ":norm! \<c-v>eh3j~"
+ call assert_equal(['ASÖd asdf', 'ASDf asdf', 'AS€d asdf', 'ASDf asdf'], getline(1, '$'))
+ exe ":norm! 1v~"
+ call assert_equal(['asöd asdf', 'asdf asdf', 'as€d asdf', 'asdf asdf'], getline(1, '$'))
+ bwipe!
+ set selection&vim
+endfunc
+
+func Test_visual_block_exclusive_selection_adjusted()
+ new
+ " Test that the end-position of the visual selection is adjusted for exclusive selection
+ set selection=exclusive
+ call setline(1, ['asöd asdf ', 'asdf asdf ', 'as€d asdf ', 'asdf asdf '])
+ call cursor(1, 1)
+ " inclusive motion
+ exe ":norm! \<c-v>e3jy"
+ call assert_equal([0, 4, 5, 0], getpos("'>"))
+ " exclusive motion
+ exe ":norm! \<c-v>ta3jy"
+ call assert_equal([0, 4, 6, 0], getpos("'>"))
+ " another inclusive motion
+ exe ":norm! \<c-v>g_3jy"
+ call assert_equal([0, 4, 10, 0], getpos("'>"))
+
+ " Reset selection option to Vim default
+ set selection&vim
+ call cursor(1, 1)
+
+ " inclusive motion
+ exe ":norm! \<c-v>e3jy"
+ call assert_equal([0, 4, 4, 0], getpos("'>"))
+ " exclusive motion
+ exe ":norm! \<c-v>ta3jy"
+ call assert_equal([0, 4, 5, 0], getpos("'>"))
+ " another inclusive motion
+ exe ":norm! \<c-v>g_3jy"
+ call assert_equal([0, 4, 9, 0], getpos("'>"))
+ bwipe!
+ set selection&vim
+endfunc
+
+" the following caused a Heap-Overflow, because Vim was accessing outside of a
+" line end
+func Test_visual_pos_buffer_heap_overflow()
+ set virtualedit=all
+ args Xa Xb
+ all
+ call setline(1, ['', '', ''])
+ call cursor(3, 1)
+ wincmd w
+ call setline(1, 'foobar')
+ normal! $lv0
+ all
+ call setreg('"', 'baz')
+ normal! [P
+ set virtualedit=
+ bw! Xa Xb
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim
index 8048fa6ff8..24517f90cb 100644
--- a/test/old/testdir/test_window_cmd.vim
+++ b/test/old/testdir/test_window_cmd.vim
@@ -55,6 +55,26 @@ func Test_window_cmd_cmdwin_with_vsp()
set ls&vim
endfunc
+func Test_cmdheight_not_changed()
+ set cmdheight=2
+ set winminheight=0
+ augroup Maximize
+ autocmd WinEnter * wincmd _
+ augroup END
+ split
+ tabnew
+ tabfirst
+ call assert_equal(2, &cmdheight)
+
+ tabonly!
+ only
+ set winminheight& cmdheight&
+ augroup Maximize
+ au!
+ augroup END
+ augroup! Maximize
+endfunc
+
" Test for jumping to windows
func Test_window_jump()
new
@@ -1164,20 +1184,20 @@ func Run_noroom_for_newwindow_test(dir_arg)
let dir = (a:dir_arg == 'v') ? 'vert ' : ''
" Open as many windows as possible
- for i in range(500)
+ while v:true
try
exe dir . 'new'
catch /E36:/
break
endtry
- endfor
+ endwhile
- call writefile(['first', 'second', 'third'], 'Xfile1')
- call writefile([], 'Xfile2')
- call writefile([], 'Xfile3')
+ call writefile(['first', 'second', 'third'], 'Xnorfile1')
+ call writefile([], 'Xnorfile2')
+ call writefile([], 'Xnorfile3')
" Argument list related commands
- args Xfile1 Xfile2 Xfile3
+ args Xnorfile1 Xnorfile2 Xnorfile3
next
for cmd in ['sargument 2', 'snext', 'sprevious', 'sNext', 'srewind',
\ 'sfirst', 'slast']
@@ -1188,13 +1208,13 @@ func Run_noroom_for_newwindow_test(dir_arg)
" Buffer related commands
set modified
hide enew
- for cmd in ['sbuffer Xfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind',
+ for cmd in ['sbuffer Xnorfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind',
\ 'sbfirst', 'sblast', 'sball', 'sbmodified', 'sunhide']
call assert_fails(dir .. cmd, 'E36:')
endfor
" Window related commands
- for cmd in ['split', 'split Xfile2', 'new', 'new Xfile3', 'sview Xfile1',
+ for cmd in ['split', 'split Xnorfile2', 'new', 'new Xnorfile3', 'sview Xnorfile1',
\ 'sfind runtest.vim']
call assert_fails(dir .. cmd, 'E36:')
endfor
@@ -1217,7 +1237,8 @@ func Run_noroom_for_newwindow_test(dir_arg)
call assert_fails(dir .. 'lopen', 'E36:')
" Preview window
- call assert_fails(dir .. 'pedit Xfile2', 'E36:')
+ call assert_fails(dir .. 'pedit Xnorfile2', 'E36:')
+ call assert_fails(dir .. 'pbuffer', 'E36:')
call setline(1, 'abc')
call assert_fails(dir .. 'psearch abc', 'E36:')
endif
@@ -1225,15 +1246,15 @@ func Run_noroom_for_newwindow_test(dir_arg)
" Window commands (CTRL-W ^ and CTRL-W f)
if a:dir_arg == 'h'
call assert_fails('call feedkeys("\<C-W>^", "xt")', 'E36:')
- call setline(1, 'Xfile1')
+ call setline(1, 'Xnorfile1')
call assert_fails('call feedkeys("gg\<C-W>f", "xt")', 'E36:')
endif
enew!
" Tag commands (:stag, :stselect and :stjump)
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
- \ "second\tXfile1\t2",
- \ "third\tXfile1\t3",],
+ \ "second\tXnorfile1\t2",
+ \ "third\tXnorfile1\t3",],
\ 'Xtags')
set tags=Xtags
call assert_fails(dir .. 'stag second', 'E36:')
@@ -1255,9 +1276,9 @@ func Run_noroom_for_newwindow_test(dir_arg)
endif
%bwipe!
- call delete('Xfile1')
- call delete('Xfile2')
- call delete('Xfile3')
+ call delete('Xnorfile1')
+ call delete('Xnorfile2')
+ call delete('Xnorfile3')
only
endfunc
diff --git a/test/old/testdir/test_winfixbuf.vim b/test/old/testdir/test_winfixbuf.vim
index 1777bec184..f7986fdda3 100644
--- a/test/old/testdir/test_winfixbuf.vim
+++ b/test/old/testdir/test_winfixbuf.vim
@@ -2545,6 +2545,18 @@ func Test_pedit()
call assert_equal(l:other, bufnr())
endfunc
+" Allow :pbuffer because, unlike :buffer, it uses a separate window
+func Test_pbuffer()
+ call s:reset_all_buffers()
+
+ let l:other = s:make_buffer_pairs()
+
+ exe 'pbuffer ' . l:other
+
+ execute "normal \<C-w>w"
+ call assert_equal(l:other, bufnr())
+endfunc
+
" Fail :pop but :pop! is allowed
func Test_pop()
call s:reset_all_buffers()
@@ -2613,7 +2625,7 @@ EOF
try
pyxdo test_winfixbuf_Test_pythonx_pyxdo_set_buffer()
- catch /pynvim\.api\.common\.NvimError: E1513:/
+ catch /pynvim\.api\.common\.NvimError: Vim:E1513:/
let l:caught = 1
endtry
@@ -2644,7 +2656,7 @@ func Test_pythonx_pyxfile()
try
pyxfile file.py
- catch /pynvim\.api\.common\.NvimError: E1513:/
+ catch /pynvim\.api\.common\.NvimError: Vim:E1513:/
let l:caught = 1
endtry
@@ -2676,7 +2688,7 @@ import vim
buffer = vim.vars["_previous_buffer"]
vim.current.buffer = vim.buffers[buffer]
EOF
- catch /pynvim\.api\.common\.NvimError: E1513:/
+ catch /pynvim\.api\.common\.NvimError: Vim:E1513:/
let l:caught = 1
endtry
diff --git a/test/testutil.lua b/test/testutil.lua
index 00b30d74d5..e69dcae120 100644
--- a/test/testutil.lua
+++ b/test/testutil.lua
@@ -22,13 +22,6 @@ local M = {
paths = Paths,
}
---- @param p string
---- @return string
-local function relpath(p)
- p = vim.fs.normalize(p)
- return (p:gsub('^' .. uv.cwd, ''))
-end
-
--- @param path string
--- @return boolean
function M.isdir(path)
@@ -45,14 +38,15 @@ end
--- (Only on Windows) Replaces yucky "\\" slashes with delicious "/" slashes in a string, or all
--- string values in a table (recursively).
---
---- @param obj string|table
---- @return any
+--- @generic T: string|table
+--- @param obj T
+--- @return T|nil
function M.fix_slashes(obj)
if not M.is_os('win') then
return obj
end
if type(obj) == 'string' then
- local ret = obj:gsub('\\', '/')
+ local ret = string.gsub(obj, '\\', '/')
return ret
elseif type(obj) == 'table' then
--- @cast obj table<any,any>
@@ -394,21 +388,35 @@ end
local sysname = uv.os_uname().sysname:lower()
---- @param s 'win'|'mac'|'freebsd'|'openbsd'|'bsd'
+--- @param s 'win'|'mac'|'linux'|'freebsd'|'openbsd'|'bsd'
--- @return boolean
function M.is_os(s)
- if not (s == 'win' or s == 'mac' or s == 'freebsd' or s == 'openbsd' or s == 'bsd') then
+ if
+ not (s == 'win' or s == 'mac' or s == 'linux' or s == 'freebsd' or s == 'openbsd' or s == 'bsd')
+ then
error('unknown platform: ' .. tostring(s))
end
return not not (
(s == 'win' and (sysname:find('windows') or sysname:find('mingw')))
or (s == 'mac' and sysname == 'darwin')
+ or (s == 'linux' and sysname == 'linux')
or (s == 'freebsd' and sysname == 'freebsd')
or (s == 'openbsd' and sysname == 'openbsd')
or (s == 'bsd' and sysname:find('bsd'))
)
end
+local architecture = uv.os_uname().machine
+
+--- @param s 'x86_64'|'arm64'
+--- @return boolean
+function M.is_arch(s)
+ if not (s == 'x86_64' or s == 'arm64') then
+ error('unknown architecture: ' .. tostring(s))
+ end
+ return s == architecture
+end
+
local tmpname_id = 0
local tmpdir = os.getenv('TMPDIR') or os.getenv('TEMP')
local tmpdir_is_local = not not (tmpdir and tmpdir:find('Xtest'))
@@ -471,7 +479,8 @@ function M.check_cores(app, force) -- luacheck: ignore
-- "./Xtest-tmpdir/" => "Xtest%-tmpdir"
local local_tmpdir = nil
if tmpdir_is_local and tmpdir then
- local_tmpdir = vim.pesc(relpath(tmpdir):gsub('^[ ./]+', ''):gsub('%/+$', ''))
+ local_tmpdir =
+ vim.pesc(vim.fs.relpath(assert(vim.uv.cwd()), tmpdir):gsub('^[ ./]+', ''):gsub('%/+$', ''))
end
local db_cmd --- @type string
diff --git a/test/unit/fixtures/multiqueue.c b/test/unit/fixtures/multiqueue.c
index 149daca893..2003bc7a5a 100644
--- a/test/unit/fixtures/multiqueue.c
+++ b/test/unit/fixtures/multiqueue.c
@@ -1,8 +1,9 @@
-#include <string.h>
#include <stdlib.h>
-#include "nvim/event/multiqueue.h"
+#include <string.h>
+
#include "multiqueue.h"
+#include "nvim/event/multiqueue.h"
void ut_multiqueue_put(MultiQueue *self, const char *str)
{
diff --git a/test/unit/fixtures/multiqueue.h b/test/unit/fixtures/multiqueue.h
index 78a3a89063..37da1d4db9 100644
--- a/test/unit/fixtures/multiqueue.h
+++ b/test/unit/fixtures/multiqueue.h
@@ -1,4 +1,4 @@
#include "nvim/event/multiqueue.h"
-void ut_multiqueue_put(MultiQueue *queue, const char *str);
-const char *ut_multiqueue_get(MultiQueue *queue);
+void ut_multiqueue_put(MultiQueue *self, const char *str);
+const char *ut_multiqueue_get(MultiQueue *self);
diff --git a/test/unit/fixtures/posix.h b/test/unit/fixtures/posix.h
index f6f24cd9dc..0d16f8aac9 100644
--- a/test/unit/fixtures/posix.h
+++ b/test/unit/fixtures/posix.h
@@ -1,8 +1,8 @@
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <sys/wait.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
enum {
kPOSIXErrnoEINTR = EINTR,
diff --git a/test/unit/fixtures/vterm_test.c b/test/unit/fixtures/vterm_test.c
new file mode 100644
index 0000000000..6744305960
--- /dev/null
+++ b/test/unit/fixtures/vterm_test.c
@@ -0,0 +1,789 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "nvim/grid.h"
+#include "nvim/mbyte.h"
+#include "nvim/vterm/pen.h"
+#include "nvim/vterm/screen.h"
+#include "nvim/vterm/vterm_internal_defs.h"
+#include "vterm_test.h"
+
+int parser_text(const char bytes[], size_t len, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "text ");
+ size_t i;
+ for (i = 0; i < len; i++) {
+ unsigned char b = (unsigned char)bytes[i];
+ if (b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0)) {
+ break;
+ }
+ fprintf(f, i ? ",%x" : "%x", b);
+ }
+ fprintf(f, "\n");
+ fclose(f);
+
+ return (int)i;
+}
+
+static void printchars(const char *s, size_t len, FILE *f)
+{
+ while (len--) {
+ fprintf(f, "%c", (s++)[0]);
+ }
+}
+
+int parser_csi(const char *leader, const long args[], int argcount, const char *intermed,
+ char command, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "csi %02x", command);
+
+ if (leader && leader[0]) {
+ fprintf(f, " L=");
+ for (int i = 0; leader[i]; i++) {
+ fprintf(f, "%02x", leader[i]);
+ }
+ }
+
+ for (int i = 0; i < argcount; i++) {
+ char sep = i ? ',' : ' ';
+
+ if (args[i] == CSI_ARG_MISSING) {
+ fprintf(f, "%c*", sep);
+ } else {
+ fprintf(f, "%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : "");
+ }
+ }
+
+ if (intermed && intermed[0]) {
+ fprintf(f, " I=");
+ for (int i = 0; intermed[i]; i++) {
+ fprintf(f, "%02x", intermed[i]);
+ }
+ }
+
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+int parser_osc(int command, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "osc ");
+
+ if (frag.initial) {
+ if (command == -1) {
+ fprintf(f, "[");
+ } else {
+ fprintf(f, "[%d;", command);
+ }
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if (frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "dcs ");
+
+ if (frag.initial) {
+ fprintf(f, "[");
+ for (size_t i = 0; i < commandlen; i++) {
+ fprintf(f, "%c", command[i]);
+ }
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if (frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_apc(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "apc ");
+
+ if (frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if (frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_pm(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "pm ");
+
+ if (frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if (frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int parser_sos(VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sos ");
+
+ if (frag.initial) {
+ fprintf(f, "[");
+ }
+
+ printchars(frag.str, frag.len, f);
+
+ if (frag.final) {
+ fprintf(f, "]");
+ }
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 1;
+}
+
+int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "selection-set mask=%04X ", mask);
+ if (frag.initial) {
+ fprintf(f, "[");
+ }
+ printchars(frag.str, frag.len, f);
+ if (frag.final) {
+ fprintf(f, "]");
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+ return 1;
+}
+
+int selection_query(VTermSelectionMask mask, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "selection-query mask=%04X\n", mask);
+
+ fclose(f);
+ return 1;
+}
+
+static void print_schar(FILE *f, schar_T schar)
+{
+ char buf[MAX_SCHAR_SIZE];
+ schar_get(buf, schar);
+ StrCharInfo ci = utf_ptr2StrCharInfo(buf);
+ bool did = false;
+ while (*ci.ptr != 0) {
+ if (did) {
+ fprintf(f, ",");
+ }
+
+ if (ci.chr.len == 1 && ci.chr.value >= 0x80) {
+ fprintf(f, "??%x", ci.chr.value);
+ } else {
+ fprintf(f, "%x", ci.chr.value);
+ }
+ did = true;
+ ci = utf_ptr2StrCharInfo(ci.ptr + ci.chr.len);
+ }
+}
+
+bool want_state_putglyph;
+int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
+{
+ if (!want_state_putglyph) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "putglyph ");
+ print_schar(f, info->schar);
+ fprintf(f, " %d %d,%d", info->width, pos.row, pos.col);
+ if (info->protected_cell) {
+ fprintf(f, " prot");
+ }
+ if (info->dwl) {
+ fprintf(f, " dwl");
+ }
+ if (info->dhl) {
+ fprintf(f, " dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?");
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+bool want_state_movecursor;
+VTermPos state_pos;
+int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ state_pos = pos;
+
+ if (want_state_movecursor) {
+ fprintf(f, "movecursor %d,%d\n", pos.row, pos.col);
+ }
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_scrollrect;
+int state_scrollrect(VTermRect rect, int downward, int rightward, void *user)
+{
+ if (!want_state_scrollrect) {
+ return 0;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ fprintf(f, "scrollrect %d..%d,%d..%d => %+d,%+d\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ downward, rightward);
+
+ fclose(f);
+ return 1;
+}
+
+bool want_state_moverect;
+int state_moverect(VTermRect dest, VTermRect src, void *user)
+{
+ if (!want_state_moverect) {
+ return 0;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "moverect %d..%d,%d..%d -> %d..%d,%d..%d\n",
+ src.start_row, src.end_row, src.start_col, src.end_col,
+ dest.start_row, dest.end_row, dest.start_col, dest.end_col);
+
+ fclose(f);
+ return 1;
+}
+
+void print_color(const VTermColor *col)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ if (VTERM_COLOR_IS_RGB(col)) {
+ fprintf(f, "rgb(%d,%d,%d", col->rgb.red, col->rgb.green, col->rgb.blue);
+ } else if (VTERM_COLOR_IS_INDEXED(col)) {
+ fprintf(f, "idx(%d", col->indexed.idx);
+ } else {
+ fprintf(f, "invalid(%d", col->type);
+ }
+ if (VTERM_COLOR_IS_DEFAULT_FG(col)) {
+ fprintf(f, ",is_default_fg");
+ }
+ if (VTERM_COLOR_IS_DEFAULT_BG(col)) {
+ fprintf(f, ",is_default_bg");
+ }
+ fprintf(f, ")");
+ fclose(f);
+}
+
+static VTermValueType vterm_get_prop_type(VTermProp prop)
+{
+ switch (prop) {
+ case VTERM_PROP_CURSORVISIBLE:
+ return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_CURSORBLINK:
+ return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_ALTSCREEN:
+ return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_TITLE:
+ return VTERM_VALUETYPE_STRING;
+ case VTERM_PROP_ICONNAME:
+ return VTERM_VALUETYPE_STRING;
+ case VTERM_PROP_REVERSE:
+ return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_CURSORSHAPE:
+ return VTERM_VALUETYPE_INT;
+ case VTERM_PROP_MOUSE:
+ return VTERM_VALUETYPE_INT;
+ case VTERM_PROP_FOCUSREPORT:
+ return VTERM_VALUETYPE_BOOL;
+ case VTERM_PROP_THEMEUPDATES:
+ return VTERM_VALUETYPE_BOOL;
+
+ case VTERM_N_PROPS:
+ return 0;
+ }
+ return 0; // UNREACHABLE
+}
+
+bool want_state_settermprop;
+int state_settermprop(VTermProp prop, VTermValue *val, void *user)
+{
+ if (!want_state_settermprop) {
+ return 1;
+ }
+
+ int errcode = 0;
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ VTermValueType type = vterm_get_prop_type(prop);
+ switch (type) {
+ case VTERM_VALUETYPE_BOOL:
+ fprintf(f, "settermprop %d %s\n", prop, val->boolean ? "true" : "false");
+ errcode = 1;
+ goto end;
+ case VTERM_VALUETYPE_INT:
+ fprintf(f, "settermprop %d %d\n", prop, val->number);
+ errcode = 1;
+ goto end;
+ case VTERM_VALUETYPE_STRING:
+ fprintf(f, "settermprop %d %s\"%.*s\"%s\n", prop,
+ val->string.initial ? "[" : "", (int)val->string.len, val->string.str,
+ val->string.final ? "]" : "");
+ errcode = 0;
+ goto end;
+ case VTERM_VALUETYPE_COLOR:
+ fprintf(f, "settermprop %d ", prop);
+ print_color(&val->color);
+ fprintf(f, "\n");
+ errcode = 1;
+ goto end;
+ case VTERM_N_VALUETYPES:
+ goto end;
+ }
+
+end:
+ fclose(f);
+ return errcode;
+}
+
+bool want_state_erase;
+int state_erase(VTermRect rect, int selective, void *user)
+{
+ if (!want_state_erase) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+
+ fprintf(f, "erase %d..%d,%d..%d%s\n",
+ rect.start_row, rect.end_row, rect.start_col, rect.end_col,
+ selective ? " selective" : "");
+
+ fclose(f);
+ return 1;
+}
+
+struct {
+ int bold;
+ int underline;
+ int italic;
+ int blink;
+ int reverse;
+ int conceal;
+ int strike;
+ int font;
+ int small;
+ int baseline;
+ VTermColor foreground;
+ VTermColor background;
+} state_pen;
+
+int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
+{
+ switch (attr) {
+ case VTERM_ATTR_BOLD:
+ state_pen.bold = val->boolean;
+ break;
+ case VTERM_ATTR_UNDERLINE:
+ state_pen.underline = val->number;
+ break;
+ case VTERM_ATTR_ITALIC:
+ state_pen.italic = val->boolean;
+ break;
+ case VTERM_ATTR_BLINK:
+ state_pen.blink = val->boolean;
+ break;
+ case VTERM_ATTR_REVERSE:
+ state_pen.reverse = val->boolean;
+ break;
+ case VTERM_ATTR_CONCEAL:
+ state_pen.conceal = val->boolean;
+ break;
+ case VTERM_ATTR_STRIKE:
+ state_pen.strike = val->boolean;
+ break;
+ case VTERM_ATTR_FONT:
+ state_pen.font = val->number;
+ break;
+ case VTERM_ATTR_SMALL:
+ state_pen.small = val->boolean;
+ break;
+ case VTERM_ATTR_BASELINE:
+ state_pen.baseline = val->number;
+ break;
+ case VTERM_ATTR_FOREGROUND:
+ state_pen.foreground = val->color;
+ break;
+ case VTERM_ATTR_BACKGROUND:
+ state_pen.background = val->color;
+ break;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+bool want_state_scrollback;
+int state_sb_clear(void *user)
+{
+ if (!want_state_scrollback) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_clear\n");
+ fclose(f);
+
+ return 0;
+}
+
+bool want_screen_scrollback;
+int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
+{
+ if (!want_screen_scrollback) {
+ return 1;
+ }
+
+ int eol = cols;
+ while (eol && !cells[eol - 1].schar) {
+ eol--;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_pushline %d =", cols);
+ for (int c = 0; c < eol; c++) {
+ fprintf(f, " ");
+ print_schar(f, cells[c].schar);
+ }
+ fprintf(f, "\n");
+
+ fclose(f);
+
+ return 1;
+}
+
+int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
+{
+ if (!want_screen_scrollback) {
+ return 0;
+ }
+
+ // All lines of scrollback contain "ABCDE"
+ for (int col = 0; col < cols; col++) {
+ if (col < 5) {
+ cells[col].schar = schar_from_ascii((uint32_t)('A' + col));
+ } else {
+ cells[col].schar = 0;
+ }
+
+ cells[col].width = 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_popline %d\n", cols);
+ fclose(f);
+ return 1;
+}
+
+int screen_sb_clear(void *user)
+{
+ if (!want_screen_scrollback) {
+ return 1;
+ }
+
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "sb_clear\n");
+ fclose(f);
+ return 0;
+}
+
+void term_output(const char *s, size_t len, void *user)
+{
+ FILE *f = fopen(VTERM_TEST_FILE, "a");
+ fprintf(f, "output ");
+ for (size_t i = 0; i < len; i++) {
+ fprintf(f, "%x%s", (unsigned char)s[i], i < len - 1 ? "," : "\n");
+ }
+ fclose(f);
+}
+
+int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val)
+{
+ switch (attr) {
+ case VTERM_ATTR_BOLD:
+ val->boolean = state->pen.bold;
+ return 1;
+
+ case VTERM_ATTR_UNDERLINE:
+ val->number = state->pen.underline;
+ return 1;
+
+ case VTERM_ATTR_ITALIC:
+ val->boolean = state->pen.italic;
+ return 1;
+
+ case VTERM_ATTR_BLINK:
+ val->boolean = state->pen.blink;
+ return 1;
+
+ case VTERM_ATTR_REVERSE:
+ val->boolean = state->pen.reverse;
+ return 1;
+
+ case VTERM_ATTR_CONCEAL:
+ val->boolean = state->pen.conceal;
+ return 1;
+
+ case VTERM_ATTR_STRIKE:
+ val->boolean = state->pen.strike;
+ return 1;
+
+ case VTERM_ATTR_FONT:
+ val->number = state->pen.font;
+ return 1;
+
+ case VTERM_ATTR_FOREGROUND:
+ val->color = state->pen.fg;
+ return 1;
+
+ case VTERM_ATTR_BACKGROUND:
+ val->color = state->pen.bg;
+ return 1;
+
+ case VTERM_ATTR_SMALL:
+ val->boolean = state->pen.small;
+ return 1;
+
+ case VTERM_ATTR_BASELINE:
+ val->number = state->pen.baseline;
+ return 1;
+
+ case VTERM_ATTR_URI:
+ val->number = state->pen.uri;
+ return 1;
+
+ case VTERM_N_ATTRS:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b)
+{
+ if ((attrs & VTERM_ATTR_BOLD_MASK) && (a->pen.bold != b->pen.bold)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_UNDERLINE_MASK) && (a->pen.underline != b->pen.underline)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_ITALIC_MASK) && (a->pen.italic != b->pen.italic)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_BLINK_MASK) && (a->pen.blink != b->pen.blink)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_CONCEAL_MASK) && (a->pen.conceal != b->pen.conceal)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_SMALL_MASK) && (a->pen.small != b->pen.small)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_BASELINE_MASK) && (a->pen.baseline != b->pen.baseline)) {
+ return 1;
+ }
+ if ((attrs & VTERM_ATTR_URI_MASK) && (a->pen.uri != b->pen.uri)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos,
+ VTermAttrMask attrs)
+{
+ ScreenCell *target = getcell(screen, pos.row, pos.col);
+
+ // TODO(vterm): bounds check
+ extent->start_row = pos.row;
+ extent->end_row = pos.row + 1;
+
+ if (extent->start_col < 0) {
+ extent->start_col = 0;
+ }
+ if (extent->end_col < 0) {
+ extent->end_col = screen->cols;
+ }
+
+ int col;
+
+ for (col = pos.col - 1; col >= extent->start_col; col--) {
+ if (attrs_differ(attrs, target, getcell(screen, pos.row, col))) {
+ break;
+ }
+ }
+ extent->start_col = col + 1;
+
+ for (col = pos.col + 1; col < extent->end_col; col++) {
+ if (attrs_differ(attrs, target, getcell(screen, pos.row, col))) {
+ break;
+ }
+ }
+ extent->end_col = col - 1;
+
+ return 1;
+}
+
+/// Does not NUL-terminate the buffer
+size_t vterm_screen_get_text(const VTermScreen *screen, char *buffer, size_t len,
+ const VTermRect rect)
+{
+ size_t outpos = 0;
+ int padding = 0;
+
+#define PUT(bytes, thislen) \
+ if (true) { \
+ if (buffer && outpos + thislen <= len) \
+ memcpy((char *)buffer + outpos, bytes, thislen); \
+ outpos += thislen; \
+ } \
+
+ for (int row = rect.start_row; row < rect.end_row; row++) {
+ for (int col = rect.start_col; col < rect.end_col; col++) {
+ ScreenCell *cell = getcell(screen, row, col);
+
+ if (cell->schar == 0) {
+ // Erased cell, might need a space
+ padding++;
+ } else if (cell->schar == (uint32_t)-1) {
+ // Gap behind a double-width char, do nothing
+ } else {
+ while (padding) {
+ PUT(" ", 1);
+ padding--;
+ }
+ char buf[MAX_SCHAR_SIZE + 1];
+ size_t thislen = schar_get(buf, cell->schar);
+ PUT(buf, thislen);
+ }
+ }
+
+ if (row < rect.end_row - 1) {
+ PUT("\n", 1);
+ padding = 0;
+ }
+ }
+
+ return outpos;
+}
+
+int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos)
+{
+ // This cell is EOL if this and every cell to the right is black
+ for (; pos.col < screen->cols; pos.col++) {
+ ScreenCell *cell = getcell(screen, pos.row, pos.col);
+ if (cell->schar != 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos)
+{
+ *cursorpos = state->pos;
+}
+
+void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright)
+{
+ state->bold_is_highbright = bold_is_highbright;
+}
+
+/// Compares two colours. Returns true if the colors are equal, false otherwise.
+int vterm_color_is_equal(const VTermColor *a, const VTermColor *b)
+{
+ // First make sure that the two colours are of the same type (RGB/Indexed)
+ if (a->type != b->type) {
+ return false;
+ }
+
+ // Depending on the type inspect the corresponding members
+ if (VTERM_COLOR_IS_INDEXED(a)) {
+ return a->indexed.idx == b->indexed.idx;
+ } else if (VTERM_COLOR_IS_RGB(a)) {
+ return (a->rgb.red == b->rgb.red)
+ && (a->rgb.green == b->rgb.green)
+ && (a->rgb.blue == b->rgb.blue);
+ }
+
+ return 0;
+}
diff --git a/test/unit/fixtures/vterm_test.h b/test/unit/fixtures/vterm_test.h
new file mode 100644
index 0000000000..ef6463af6d
--- /dev/null
+++ b/test/unit/fixtures/vterm_test.h
@@ -0,0 +1,45 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "nvim/macros_defs.h"
+#include "nvim/vterm/vterm.h"
+
+EXTERN VTermPos state_pos;
+EXTERN bool want_state_putglyph INIT (=false);
+EXTERN bool want_state_movecursor INIT(= false);
+EXTERN bool want_state_erase INIT(= false);
+EXTERN bool want_state_scrollrect INIT(= false);
+EXTERN bool want_state_moverect INIT(= false);
+EXTERN bool want_state_settermprop INIT(= false);
+EXTERN bool want_state_scrollback INIT(= false);
+EXTERN bool want_screen_scrollback INIT(= false);
+int parser_text(const char bytes[], size_t len, void *user);
+int parser_csi(const char *leader, const long args[], int argcount, const char *intermed,
+ char command, void *user);
+int parser_osc(int command, VTermStringFragment frag, void *user);
+int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
+int parser_apc(VTermStringFragment frag, void *user);
+int parser_pm(VTermStringFragment frag, void *user);
+int parser_sos(VTermStringFragment frag, void *user);
+int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user);
+int selection_query(VTermSelectionMask mask, void *user);
+int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user);
+int state_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
+int state_scrollrect(VTermRect rect, int downward, int rightward, void *user);
+int state_moverect(VTermRect dest, VTermRect src, void *user);
+int state_settermprop(VTermProp prop, VTermValue *val, void *user);
+int state_erase(VTermRect rect, int selective, void *user);
+int state_setpenattr(VTermAttr attr, VTermValue *val, void *user);
+int state_sb_clear(void *user);
+void print_color(const VTermColor *col);
+int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user);
+int screen_sb_popline(int cols, VTermScreenCell *cells, void *user);
+int screen_sb_clear(void *user);
+void term_output(const char *s, size_t len, void *user);
+int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);
+int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
+size_t vterm_screen_get_text(const VTermScreen *screen, char *buffer, size_t len, VTermRect rect);
+int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);
+void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos);
+void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);
+int vterm_color_is_equal(const VTermColor *a, const VTermColor *b);
diff --git a/test/unit/mbyte_spec.lua b/test/unit/mbyte_spec.lua
index bdc111de2c..2c52aa9217 100644
--- a/test/unit/mbyte_spec.lua
+++ b/test/unit/mbyte_spec.lua
@@ -58,11 +58,11 @@ describe('mbyte', function()
lib.schar_get(buf, lib.utfc_ptr2schar(to_string(seq), firstc))
local str = ffi.string(buf)
if 1 > 2 then -- for debugging
- local tabel = {}
+ local tbl = {}
for i = 1, #str do
- table.insert(tabel, string.format('0x%02x', string.byte(str, i)))
+ table.insert(tbl, string.format('0x%02x', string.byte(str, i)))
end
- print('{ ' .. table.concat(tabel, ', ') .. ' }')
+ print('{ ' .. table.concat(tbl, ', ') .. ' }')
io.stdout:flush()
end
return { str, firstc[0] }
diff --git a/test/unit/optionstr_spec.lua b/test/unit/optionstr_spec.lua
index b9c9ceaa85..1f5b42485f 100644
--- a/test/unit/optionstr_spec.lua
+++ b/test/unit/optionstr_spec.lua
@@ -11,8 +11,8 @@ local check_ff_value = function(ff)
end
describe('check_ff_value', function()
- itp('views empty string as valid', function()
- eq(1, check_ff_value(''))
+ itp('views empty string as invalid', function()
+ eq(0, check_ff_value(''))
end)
itp('views "unix", "dos" and "mac" as valid', function()
diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua
index 25cdc27b28..2b7a4d6261 100644
--- a/test/unit/strings_spec.lua
+++ b/test/unit/strings_spec.lua
@@ -1,6 +1,7 @@
local t = require('test.unit.testutil')
local itp = t.gen_itp(it)
+local child_call_once = t.child_call_once
local cimport = t.cimport
local eq = t.eq
local ffi = t.ffi
@@ -8,6 +9,12 @@ local to_cstr = t.to_cstr
local strings = cimport('stdlib.h', './src/nvim/strings.h', './src/nvim/memory.h')
+local UVARNUM_TYPE
+
+child_call_once(function()
+ UVARNUM_TYPE = ffi.typeof('uvarnumber_T')
+end)
+
describe('vim_strsave_escaped()', function()
local vim_strsave_escaped = function(s, chars)
local res = strings.vim_strsave_escaped(to_cstr(s), to_cstr(chars))
@@ -140,13 +147,22 @@ end)
describe('vim_snprintf()', function()
local function a(expected, buf, bsize, fmt, ...)
- eq(#expected, strings.vim_snprintf(buf, bsize, fmt, ...))
+ local args = { ... }
+ local ctx = string.format('snprintf(buf, %d, "%s"', bsize, fmt)
+ for _, x in ipairs(args) do
+ ctx = ctx .. ', ' .. tostring(x)
+ end
+ ctx = ctx .. string.format(') = %s', expected)
+ eq(#expected, strings.vim_snprintf(buf, bsize, fmt, ...), ctx)
if bsize > 0 then
local actual = ffi.string(buf, math.min(#expected + 1, bsize))
eq(expected:sub(1, bsize - 1) .. '\0', actual)
end
end
+ local function uv(n)
+ return ffi.cast(UVARNUM_TYPE, n)
+ end
local function i(n)
return ffi.cast('int', n)
end
@@ -181,7 +197,7 @@ describe('vim_snprintf()', function()
a(' 1234567', buf, bsize, '%9ld', l(1234567))
a('1234567 ', buf, bsize, '%-9ld', l(1234567))
a('deadbeef', buf, bsize, '%x', u(0xdeadbeef))
- a('001100', buf, bsize, '%06b', u(12))
+ a('001100', buf, bsize, '%06b', uv(12))
a('one two', buf, bsize, '%s %s', 'one', 'two')
a('1.234000', buf, bsize, '%f', 1.234)
a('1.234000e+00', buf, bsize, '%e', 1.234)
@@ -223,10 +239,10 @@ describe('vim_snprintf()', function()
a('three one two', buf, bsize, '%3$s %1$s %2$s', 'one', 'two', 'three')
a('1234567', buf, bsize, '%1$d', i(1234567))
a('deadbeef', buf, bsize, '%1$x', u(0xdeadbeef))
- a('001100', buf, bsize, '%2$0*1$b', i(6), u(12))
- a('001100', buf, bsize, '%1$0.*2$b', u(12), i(6))
+ a('001100', buf, bsize, '%2$0*1$b', i(6), uv(12))
+ a('001100', buf, bsize, '%1$0.*2$b', uv(12), i(6))
a('one two', buf, bsize, '%1$s %2$s', 'one', 'two')
- a('001100', buf, bsize, '%06b', u(12))
+ a('001100', buf, bsize, '%06b', uv(12))
a('two one', buf, bsize, '%2$s %1$s', 'one', 'two')
a('1.234000', buf, bsize, '%1$f', 1.234)
a('1.234000e+00', buf, bsize, '%1$e', 1.234)
diff --git a/test/unit/vterm_spec.lua b/test/unit/vterm_spec.lua
index 4ea5d9c29a..c5293a21cb 100644
--- a/test/unit/vterm_spec.lua
+++ b/test/unit/vterm_spec.lua
@@ -17,7 +17,9 @@ local bit = require('bit')
--- @field VTERM_KEY_NONE integer
--- @field VTERM_KEY_TAB integer
--- @field VTERM_KEY_UP integer
---- @field VTERM_MAX_CHARS_PER_CELL integer
+--- @field VTERM_KEY_BACKSPACE integer
+--- @field VTERM_KEY_ESCAPE integer
+--- @field VTERM_KEY_DEL integer
--- @field VTERM_MOD_ALT integer
--- @field VTERM_MOD_CTRL integer
--- @field VTERM_MOD_SHIFT integer
@@ -29,6 +31,7 @@ local bit = require('bit')
--- @field parser_sos function
--- @field parser_text function
--- @field print_color function
+--- @field schar_get fun(any, any):integer
--- @field screen_sb_clear function
--- @field screen_sb_popline function
--- @field screen_sb_pushline function
@@ -44,6 +47,8 @@ local bit = require('bit')
--- @field state_setpenattr function
--- @field state_settermprop function
--- @field term_output function
+--- @field utf_ptr2char fun(any):integer
+--- @field utf_ptr2len fun(any):integer
--- @field vterm_input_write function
--- @field vterm_keyboard_end_paste function
--- @field vterm_keyboard_key function
@@ -62,7 +67,6 @@ local bit = require('bit')
--- @field vterm_screen_enable_reflow function
--- @field vterm_screen_get_attrs_extent function
--- @field vterm_screen_get_cell function
---- @field vterm_screen_get_chars fun(any, any, any, any):any
--- @field vterm_screen_get_text fun(any, any, any, any):any
--- @field vterm_screen_is_eol fun(any, any):any
--- @field vterm_screen_reset function
@@ -79,7 +83,20 @@ local bit = require('bit')
--- @field vterm_state_set_callbacks function
--- @field vterm_state_set_selection_callbacks function
--- @field vterm_state_set_unrecognised_fallbacks function
-local vterm = t.cimport('./src/vterm/vterm.h', './src/vterm/vterm_internal.h')
+local vterm = t.cimport(
+ './src/nvim/grid.h',
+ './src/nvim/mbyte.h',
+ './src/nvim/vterm/encoding.h',
+ './src/nvim/vterm/keyboard.h',
+ './src/nvim/vterm/mouse.h',
+ './src/nvim/vterm/parser.h',
+ './src/nvim/vterm/pen.h',
+ './src/nvim/vterm/screen.h',
+ './src/nvim/vterm/state.h',
+ './src/nvim/vterm/vterm.h',
+ './src/nvim/vterm/vterm_internal.h',
+ './test/unit/fixtures/vterm_test.h'
+)
--- @return string
local function read_rm()
@@ -298,16 +315,12 @@ local function screen_chars(start_row, start_col, end_row, end_col, expected, sc
rect['end_row'] = end_row
rect['end_col'] = end_col
- local len = vterm.vterm_screen_get_chars(screen, nil, 0, rect)
-
- local chars = t.ffi.new('uint32_t[?]', len)
- vterm.vterm_screen_get_chars(screen, chars, len, rect)
+ local len = vterm.vterm_screen_get_text(screen, nil, 0, rect)
- local actual = ''
- for i = 0, tonumber(len) - 1 do
- actual = actual .. string.char(chars[i])
- end
+ local text = t.ffi.new('unsigned char[?]', len)
+ vterm.vterm_screen_get_text(screen, text, len, rect)
+ local actual = t.ffi.string(text, len)
t.eq(expected, actual)
end
@@ -345,7 +358,7 @@ local function screen_row(row, expected, screen, end_col)
local text = t.ffi.new('unsigned char[?]', len)
vterm.vterm_screen_get_text(screen, text, len, rect)
- t.eq(expected, t.ffi.string(text))
+ t.eq(expected, t.ffi.string(text, len))
end
local function screen_cell(row, col, expected, screen)
@@ -353,17 +366,23 @@ local function screen_cell(row, col, expected, screen)
pos['row'] = row
pos['col'] = col
- local cell = t.ffi.new('VTermScreenCell')
+ local cell = t.ffi.new('VTermScreenCell') ---@type any
vterm.vterm_screen_get_cell(screen, pos, cell)
+ local buf = t.ffi.new('unsigned char[32]')
+ vterm.schar_get(buf, cell.schar)
+
local actual = '{'
- for i = 0, vterm.VTERM_MAX_CHARS_PER_CELL - 1 do
- if cell['chars'][i] ~= 0 then
- if i > 0 then
- actual = actual .. ','
- end
- actual = string.format('%s%02x', actual, cell['chars'][i])
+ local i = 0
+ while buf[i] > 0 do
+ local char = vterm.utf_ptr2char(buf + i)
+ local charlen = vterm.utf_ptr2len(buf + i)
+ if i > 0 then
+ actual = actual .. ','
end
+ local invalid = char >= 128 and charlen == 1
+ actual = string.format('%s%s%02x', actual, invalid and '?' or '', char)
+ i = i + charlen
end
actual = string.format('%s} width=%d attrs={', actual, cell['width'])
actual = actual .. (cell['attrs'].bold ~= 0 and 'B' or '')
@@ -489,6 +508,18 @@ local function strp_key(input_key)
return vterm.VTERM_KEY_ENTER
end
+ if input_key == 'bs' then
+ return vterm.VTERM_KEY_BACKSPACE
+ end
+
+ if input_key == 'del' then
+ return vterm.VTERM_KEY_DEL
+ end
+
+ if input_key == 'esc' then
+ return vterm.VTERM_KEY_ESCAPE
+ end
+
if input_key == 'f1' then
return vterm.VTERM_KEY_FUNCTION_0 + 1
end
@@ -958,8 +989,8 @@ describe('vterm', function()
-- Spare combining chars get truncated
reset(state, nil)
- push('e' .. string.rep('\xCC\x81', 10), vt)
- expect('putglyph 65,301,301,301,301,301 1 0,0') -- and nothing more
+ push('e' .. string.rep('\xCC\x81', 20), vt)
+ expect('putglyph 65,301,301,301,301,301,301,301,301,301,301,301,301,301,301 1 0,0') -- and nothing more
reset(state, nil)
push('e', vt)
@@ -969,6 +1000,34 @@ describe('vterm', function()
push('\xCC\x82', vt)
expect('putglyph 65,301,302 1 0,0')
+ -- emoji with ZWJ and variant selectors, as one chunk
+ reset(state, nil)
+ push('🏳️‍🌈🏳️‍⚧️🏴‍☠️', vt)
+ expect([[putglyph 1f3f3,fe0f,200d,1f308 2 0,0
+putglyph 1f3f3,fe0f,200d,26a7,fe0f 2 0,2
+putglyph 1f3f4,200d,2620,fe0f 2 0,4]])
+
+ -- emoji, one code point at a time
+ reset(state, nil)
+ push('🏳', vt)
+ expect('putglyph 1f3f3 2 0,0')
+ push('\xef\xb8\x8f', vt)
+ expect('putglyph 1f3f3,fe0f 2 0,0')
+ push('\xe2\x80\x8d', vt)
+ expect('putglyph 1f3f3,fe0f,200d 2 0,0')
+ push('🌈', vt)
+ expect('putglyph 1f3f3,fe0f,200d,1f308 2 0,0')
+
+ -- modifier can change width
+ push('❤', vt)
+ expect('putglyph 2764 1 0,2')
+ push('\xef\xb8\x8f', vt)
+ expect('putglyph 2764,fe0f 2 0,2')
+
+ -- also works batched
+ push('❤️', vt)
+ expect('putglyph 2764,fe0f 2 0,4')
+
-- DECSCA protected
reset(state, nil)
push('A\x1b[1"qB\x1b[2"qC', vt)
@@ -1090,7 +1149,7 @@ describe('vterm', function()
push('\x1b[0F', vt)
cursor(0, 0, state)
- -- Cursor Horizonal Absolute
+ -- Cursor Horizontal Absolute
push('\n', vt)
cursor(1, 0, state)
push('\x1b[20G', vt)
@@ -1664,12 +1723,6 @@ describe('vterm', function()
push('#', vt)
expect('putglyph 23 1 0,0')
- -- Designate G0=UK
- reset(state, nil)
- push('\x1b(A', vt)
- push('#', vt)
- expect('putglyph a3 1 0,0')
-
-- Designate G0=DEC drawing
reset(state, nil)
push('\x1b(0', vt)
@@ -2026,6 +2079,18 @@ describe('vterm', function()
mousebtn('u', 1, vt)
expect_output('\x1b[<0;301;301m')
+ -- Button 8 on SGR extended encoding mode
+ mousebtn('d', 8, vt)
+ expect_output('\x1b[<128;301;301M')
+ mousebtn('u', 8, vt)
+ expect_output('\x1b[<128;301;301m')
+
+ -- Button 9 on SGR extended encoding mode
+ mousebtn('d', 9, vt)
+ expect_output('\x1b[<129;301;301M')
+ mousebtn('u', 9, vt)
+ expect_output('\x1b[<129;301;301m')
+
-- DECRQM on SGR extended encoding mode
push('\x1b[?1005$p', vt)
expect_output('\x1b[?1005;2$y')
@@ -2041,6 +2106,18 @@ describe('vterm', function()
mousebtn('u', 1, vt)
expect_output('\x1b[3;301;301M')
+ -- Button 8 on rxvt extended encoding mode
+ mousebtn('d', 8, vt)
+ expect_output('\x1b[128;301;301M')
+ mousebtn('u', 8, vt)
+ expect_output('\x1b[3;301;301M')
+
+ -- Button 9 on rxvt extended encoding mode
+ mousebtn('d', 9, vt)
+ expect_output('\x1b[129;301;301M')
+ mousebtn('u', 9, vt)
+ expect_output('\x1b[3;301;301M')
+
-- DECRQM on rxvt extended encoding mode
push('\x1b[?1005$p', vt)
expect_output('\x1b[?1005;2$y')
@@ -2286,65 +2363,83 @@ describe('vterm', function()
local vt = init()
local state = wantstate(vt)
+ -- Disambiguate escape codes enabled
+ push('\x1b[>1u', vt)
+
-- Unmodified ASCII
- inchar(41, vt)
- expect('output 29')
- inchar(61, vt)
- expect('output 3d')
+ inchar(0x41, vt)
+ expect_output('A')
+ inchar(0x61, vt)
+ expect_output('a')
-- Ctrl modifier on ASCII letters
- inchar(41, vt, { C = true })
- expect('output 1b,5b,34,31,3b,35,75')
- inchar(61, vt, { C = true })
- expect('output 1b,5b,36,31,3b,35,75')
+ inchar(0x41, vt, { C = true })
+ expect_output('\x1b[97;6u')
+ inchar(0x61, vt, { C = true })
+ expect_output('\x1b[97;5u')
-- Alt modifier on ASCII letters
- inchar(41, vt, { A = true })
- expect('output 1b,29')
- inchar(61, vt, { A = true })
- expect('output 1b,3d')
+ inchar(0x41, vt, { A = true })
+ expect_output('\x1b[97;4u')
+ inchar(0x61, vt, { A = true })
+ expect_output('\x1b[97;3u')
-- Ctrl-Alt modifier on ASCII letters
- inchar(41, vt, { C = true, A = true })
- expect('output 1b,5b,34,31,3b,37,75')
- inchar(61, vt, { C = true, A = true })
- expect('output 1b,5b,36,31,3b,37,75')
-
- -- Special handling of Ctrl-I
- inchar(49, vt)
- expect('output 31')
- inchar(69, vt)
- expect('output 45')
- inchar(49, vt, { C = true })
- expect('output 1b,5b,34,39,3b,35,75')
- inchar(69, vt, { C = true })
- expect('output 1b,5b,36,39,3b,35,75')
- inchar(49, vt, { A = true })
- expect('output 1b,31')
- inchar(69, vt, { A = true })
- expect('output 1b,45')
- inchar(49, vt, { A = true, C = true })
- expect('output 1b,5b,34,39,3b,37,75')
- inchar(69, vt, { A = true, C = true })
- expect('output 1b,5b,36,39,3b,37,75')
+ inchar(0x41, vt, { C = true, A = true })
+ expect_output('\x1b[97;8u')
+ inchar(0x61, vt, { C = true, A = true })
+ expect_output('\x1b[97;7u')
+
+ -- Ctrl-I is disambiguated
+ inchar(0x49, vt)
+ expect_output('I')
+ inchar(0x69, vt)
+ expect_output('i')
+ inchar(0x49, vt, { C = true })
+ expect_output('\x1b[105;6u')
+ inchar(0x69, vt, { C = true })
+ expect_output('\x1b[105;5u')
+ inchar(0x49, vt, { A = true })
+ expect_output('\x1b[105;4u')
+ inchar(0x69, vt, { A = true })
+ expect_output('\x1b[105;3u')
+ inchar(0x49, vt, { A = true, C = true })
+ expect_output('\x1b[105;8u')
+ inchar(0x69, vt, { A = true, C = true })
+ expect_output('\x1b[105;7u')
+
+ -- Ctrl+Digits
+ for i = 0, 9 do
+ local c = 0x30 + i
+ inchar(c, vt)
+ expect_output(tostring(i))
+ inchar(c, vt, { C = true })
+ expect_output(string.format('\x1b[%d;5u', c))
+ inchar(c, vt, { C = true, S = true })
+ expect_output(string.format('\x1b[%d;6u', c))
+ inchar(c, vt, { C = true, A = true })
+ expect_output(string.format('\x1b[%d;7u', c))
+ inchar(c, vt, { C = true, A = true, S = true })
+ expect_output(string.format('\x1b[%d;8u', c))
+ end
-- Special handling of Space
- inchar(20, vt)
- expect('output 14')
- inchar(20, vt, { S = true })
- expect('output 14')
- inchar(20, vt, { C = true })
- expect('output 1b,5b,32,30,3b,35,75')
- inchar(20, vt, { C = true, S = true })
- expect('output 1b,5b,32,30,3b,35,75')
- inchar(20, vt, { A = true })
- expect('output 1b,14')
- inchar(20, vt, { S = true, A = true })
- expect('output 1b,14')
- inchar(20, vt, { C = true, A = true })
- expect('output 1b,5b,32,30,3b,37,75')
- inchar(20, vt, { S = true, C = true, A = true })
- expect('output 1b,5b,32,30,3b,37,75')
+ inchar(0x20, vt)
+ expect_output(' ')
+ inchar(0x20, vt, { S = true })
+ expect_output('\x1b[32;2u')
+ inchar(0x20, vt, { C = true })
+ expect_output('\x1b[32;5u')
+ inchar(0x20, vt, { C = true, S = true })
+ expect_output('\x1b[32;6u')
+ inchar(0x20, vt, { A = true })
+ expect_output('\x1b[32;3u')
+ inchar(0x20, vt, { S = true, A = true })
+ expect_output('\x1b[32;4u')
+ inchar(0x20, vt, { C = true, A = true })
+ expect_output('\x1b[32;7u')
+ inchar(0x20, vt, { S = true, C = true, A = true })
+ expect_output('\x1b[32;8u')
-- Cursor keys in reset (cursor) mode
inkey('up', vt)
@@ -2375,21 +2470,65 @@ describe('vterm', function()
inkey('up', vt, { C = true })
expect_output('\x1b[1;5A')
- -- Shift-Tab should be different
+ -- Tab
inkey('tab', vt)
expect_output('\x09')
inkey('tab', vt, { S = true })
- expect_output('\x1b[Z')
+ expect_output('\x1b[9;2u')
inkey('tab', vt, { C = true })
expect_output('\x1b[9;5u')
inkey('tab', vt, { A = true })
- expect_output('\x1b\x09')
+ expect_output('\x1b[9;3u')
inkey('tab', vt, { C = true, A = true })
expect_output('\x1b[9;7u')
+ -- Backspace
+ inkey('bs', vt)
+ expect_output('\x7f')
+ inkey('bs', vt, { S = true })
+ expect_output('\x1b[127;2u')
+ inkey('bs', vt, { C = true })
+ expect_output('\x1b[127;5u')
+ inkey('bs', vt, { A = true })
+ expect_output('\x1b[127;3u')
+ inkey('bs', vt, { C = true, A = true })
+ expect_output('\x1b[127;7u')
+
+ -- DEL
+ inkey('del', vt)
+ expect_output('\x1b[3~')
+ inkey('del', vt, { S = true })
+ expect_output('\x1b[3;2~')
+ inkey('del', vt, { C = true })
+ expect_output('\x1b[3;5~')
+ inkey('del', vt, { A = true })
+ expect_output('\x1b[3;3~')
+ inkey('del', vt, { C = true, A = true })
+ expect_output('\x1b[3;7~')
+
+ -- ESC
+ inkey('esc', vt)
+ expect_output('\x1b[27;1u')
+ inkey('esc', vt, { S = true })
+ expect_output('\x1b[27;2u')
+ inkey('esc', vt, { C = true })
+ expect_output('\x1b[27;5u')
+ inkey('esc', vt, { A = true })
+ expect_output('\x1b[27;3u')
+ inkey('esc', vt, { C = true, A = true })
+ expect_output('\x1b[27;7u')
+
-- Enter in linefeed mode
inkey('enter', vt)
expect_output('\x0d')
+ inkey('enter', vt, { S = true })
+ expect_output('\x1b[13;2u')
+ inkey('enter', vt, { C = true })
+ expect_output('\x1b[13;5u')
+ inkey('enter', vt, { A = true })
+ expect_output('\x1b[13;3u')
+ inkey('enter', vt, { C = true, A = true })
+ expect_output('\x1b[13;7u')
-- Enter in newline mode
push('\x1b[20h', vt)
@@ -2410,7 +2549,7 @@ describe('vterm', function()
-- Keypad in DECKPNM
inkey('kp0', vt)
- expect_output('0')
+ expect_output('\x1b[57399;1u')
-- Keypad in DECKPAM
push('\x1b=', vt)
@@ -2440,6 +2579,77 @@ describe('vterm', function()
expect_output('\x1b[I')
vterm.vterm_state_focus_out(state)
expect_output('\x1b[O')
+
+ -- Disambiguate escape codes disabled
+ push('\x1b[<u', vt)
+
+ -- Unmodified ASCII
+ inchar(0x41, vt)
+ expect_output('A')
+ inchar(0x61, vt)
+ expect_output('a')
+
+ -- Ctrl modifier on ASCII letters
+ inchar(0x41, vt, { C = true })
+ expect_output('\x01')
+ inchar(0x61, vt, { C = true })
+ expect_output('\x01')
+
+ -- Alt modifier on ASCII letters
+ inchar(0x41, vt, { A = true })
+ expect_output('\x1bA')
+ inchar(0x61, vt, { A = true })
+ expect_output('\x1ba')
+
+ -- Ctrl-Alt modifier on ASCII letters
+ inchar(0x41, vt, { C = true, A = true })
+ expect_output('\x1b\x01')
+ inchar(0x61, vt, { C = true, A = true })
+ expect_output('\x1b\x01')
+
+ -- Ctrl-I is ambiguous
+ inchar(0x49, vt)
+ expect_output('I')
+ inchar(0x69, vt)
+ expect_output('i')
+ inchar(0x49, vt, { C = true })
+ expect_output('\x09')
+ inchar(0x69, vt, { C = true })
+ expect_output('\x09')
+ inchar(0x49, vt, { A = true })
+ expect_output('\x1bI')
+ inchar(0x69, vt, { A = true })
+ expect_output('\x1bi')
+ inchar(0x49, vt, { A = true, C = true })
+ expect_output('\x1b\x09')
+ inchar(0x69, vt, { A = true, C = true })
+ expect_output('\x1b\x09')
+
+ -- Ctrl+Digits
+ inchar(0x30, vt, { C = true })
+ expect_output('0')
+ inchar(0x31, vt, { C = true })
+ expect_output('1')
+ inchar(0x32, vt, { C = true })
+ expect_output('\x00')
+ inchar(0x33, vt, { C = true })
+ expect_output('\x1b')
+ inchar(0x34, vt, { C = true })
+ expect_output('\x1c')
+ inchar(0x35, vt, { C = true })
+ expect_output('\x1d')
+ inchar(0x36, vt, { C = true })
+ expect_output('\x1e')
+ inchar(0x37, vt, { C = true })
+ expect_output('\x1f')
+ inchar(0x38, vt, { C = true })
+ expect_output('\x7f')
+ inchar(0x39, vt, { C = true })
+ expect_output('9')
+
+ -- Ctrl+/
+ inchar(0x2F, vt, { C = true })
+ expect_output('\x1f')
end)
itp('26state_query', function()
@@ -3042,7 +3252,7 @@ describe('vterm', function()
screen_cell(
0,
0,
- '{65,301,302,303,304,305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ '{65,301,302,303,304,305,306,307,308,309,30a} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
screen
)
@@ -3059,15 +3269,25 @@ describe('vterm', function()
screen_cell(
0,
0,
- '{65,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
+ '{65,301,301,301,301,301,301,301,301,301,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)',
screen
)
- -- Outputing CJK doublewidth in 80th column should wraparound to next line and not crash"
+ -- Outputting CJK doublewidth in 80th column should wraparound to next line and not crash"
reset(nil, screen)
push('\x1b[80G\xEF\xBC\x90', vt)
screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
screen_cell(1, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+
+ -- Outputting emoji with ZWJ and variant selectors
+ reset(nil, screen)
+ push('🏳️‍🌈🏳️‍⚧️🏴‍☠️', vt)
+
+ -- stylua: ignore start
+ screen_cell(0, 0, '{1f3f3,fe0f,200d,1f308} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 2, '{1f3f3,fe0f,200d,26a7,fe0f} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ screen_cell(0, 4, '{1f3f4,200d,2620,fe0f} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen)
+ -- stylua: ignore end
end)
pending('62screen_damage', function() end)
@@ -3121,7 +3341,7 @@ describe('vterm', function()
screen = wantscreen(vt, { b = true })
resize(20, 80, vt)
expect(
- 'sb_pushline 80 = 54 6F 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
+ 'sb_pushline 80 = 54 6f 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 ='
)
-- TODO(dundargoc): fix or remove
-- screen_row( 0 , "",screen)