aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/README.md45
-rw-r--r--test/benchmark/treesitter_spec.lua53
-rw-r--r--test/busted/outputHandlers/nvim.lua34
-rw-r--r--test/cmakeconfig/paths.lua.in (renamed from test/config/paths.lua.in)0
-rw-r--r--test/functional/api/autocmd_spec.lua1249
-rw-r--r--test/functional/api/buffer_spec.lua100
-rw-r--r--test/functional/api/buffer_updates_spec.lua5
-rw-r--r--test/functional/api/command_spec.lua305
-rw-r--r--test/functional/api/extmark_spec.lua279
-rw-r--r--test/functional/api/highlight_spec.lua103
-rw-r--r--test/functional/api/keymap_spec.lua78
-rw-r--r--test/functional/api/proc_spec.lua6
-rw-r--r--test/functional/api/server_requests_spec.lua8
-rw-r--r--test/functional/api/version_spec.lua3
-rw-r--r--test/functional/api/vim_spec.lua1286
-rw-r--r--test/functional/api/window_spec.lua44
-rw-r--r--test/functional/autocmd/autocmd_oldtest_spec.lua86
-rw-r--r--test/functional/autocmd/autocmd_spec.lua223
-rw-r--r--test/functional/autocmd/cursormoved_spec.lua1
-rw-r--r--test/functional/autocmd/dirchanged_spec.lua128
-rw-r--r--test/functional/autocmd/focus_spec.lua2
-rw-r--r--test/functional/autocmd/show_spec.lua183
-rw-r--r--test/functional/autocmd/signal_spec.lua6
-rw-r--r--test/functional/autocmd/termxx_spec.lua26
-rw-r--r--test/functional/autocmd/winscrolled_spec.lua103
-rw-r--r--test/functional/core/channels_spec.lua53
-rw-r--r--test/functional/core/fileio_spec.lua75
-rw-r--r--test/functional/core/job_spec.lua89
-rw-r--r--test/functional/core/log_spec.lua57
-rw-r--r--test/functional/core/main_spec.lua12
-rw-r--r--test/functional/core/remote_spec.lua142
-rw-r--r--test/functional/core/startup_spec.lua51
-rw-r--r--test/functional/editor/K_spec.lua23
-rw-r--r--test/functional/editor/completion_spec.lua60
-rw-r--r--test/functional/editor/ctrl_c_spec.lua (renamed from test/functional/ex_cmds/ctrl_c_spec.lua)54
-rw-r--r--test/functional/editor/jump_spec.lua143
-rw-r--r--test/functional/editor/langmap_spec.lua36
-rw-r--r--test/functional/editor/macro_spec.lua55
-rw-r--r--test/functional/editor/mark_spec.lua401
-rw-r--r--test/functional/editor/meta_key_spec.lua54
-rw-r--r--test/functional/editor/mode_cmdline_spec.lua105
-rw-r--r--test/functional/editor/mode_insert_spec.lua58
-rw-r--r--test/functional/editor/put_spec.lua26
-rw-r--r--test/functional/editor/tabpage_spec.lua28
-rw-r--r--test/functional/editor/undo_spec.lua67
-rw-r--r--test/functional/ex_cmds/cd_spec.lua2
-rw-r--r--test/functional/ex_cmds/cmd_map_spec.lua96
-rw-r--r--test/functional/ex_cmds/drop_spec.lua32
-rw-r--r--test/functional/ex_cmds/echo_spec.lua14
-rw-r--r--test/functional/ex_cmds/ls_spec.lua4
-rw-r--r--test/functional/ex_cmds/make_spec.lua6
-rw-r--r--test/functional/ex_cmds/map_spec.lua233
-rw-r--r--test/functional/ex_cmds/menu_spec.lua3
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua109
-rw-r--r--test/functional/ex_cmds/normal_spec.lua27
-rw-r--r--test/functional/ex_cmds/quickfix_commands_spec.lua13
-rw-r--r--test/functional/ex_cmds/script_spec.lua16
-rw-r--r--test/functional/ex_cmds/sign_spec.lua9
-rw-r--r--test/functional/ex_cmds/source_spec.lua20
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua3
-rw-r--r--test/functional/ex_cmds/verbose_spec.lua168
-rw-r--r--test/functional/fixtures/CMakeLists.txt4
-rw-r--r--test/functional/fixtures/api_level_9.mpackbin0 -> 30127 bytes
-rw-r--r--test/functional/fixtures/autoload/provider/python3.vim (renamed from test/functional/fixtures/autoload/provider/python.vim)2
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua256
-rw-r--r--test/functional/fixtures/lua/test_plug/health/init.lua9
-rw-r--r--test/functional/fixtures/lua/test_plug/submodule/health.lua9
-rw-r--r--test/functional/fixtures/lua/test_plug/submodule_empty/health.lua7
-rw-r--r--test/functional/fixtures/lua/test_plug/submodule_failed/health.lua7
-rw-r--r--test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua1
-rw-r--r--test/functional/helpers.lua115
-rw-r--r--test/functional/legacy/003_cindent_spec.lua4774
-rw-r--r--test/functional/legacy/008_autocommands_spec.lua3
-rw-r--r--test/functional/legacy/012_directory_spec.lua3
-rw-r--r--test/functional/legacy/031_close_commands_spec.lua3
-rw-r--r--test/functional/legacy/arglist_spec.lua47
-rw-r--r--test/functional/legacy/assert_spec.lua245
-rw-r--r--test/functional/legacy/autochdir_spec.lua94
-rw-r--r--test/functional/legacy/cdo_spec.lua228
-rw-r--r--test/functional/legacy/cmdline_spec.lua68
-rw-r--r--test/functional/legacy/cpoptions_spec.lua34
-rw-r--r--test/functional/legacy/delete_spec.lua58
-rw-r--r--test/functional/legacy/display_spec.lua90
-rw-r--r--test/functional/legacy/edit_spec.lua41
-rw-r--r--test/functional/legacy/eval_spec.lua2
-rw-r--r--test/functional/legacy/ex_mode_spec.lua125
-rw-r--r--test/functional/legacy/excmd_spec.lua188
-rw-r--r--test/functional/legacy/expand_spec.lua129
-rw-r--r--test/functional/legacy/file_perm_spec.lua43
-rw-r--r--test/functional/legacy/filechanged_spec.lua131
-rw-r--r--test/functional/legacy/fixeol_spec.lua11
-rw-r--r--test/functional/legacy/function_sort_spec.lua2
-rw-r--r--test/functional/legacy/listchars_spec.lua127
-rw-r--r--test/functional/legacy/mapping_spec.lua113
-rw-r--r--test/functional/legacy/memory_usage_spec.lua17
-rw-r--r--test/functional/legacy/messages_spec.lua421
-rw-r--r--test/functional/legacy/packadd_spec.lua507
-rw-r--r--test/functional/legacy/prompt_buffer_spec.lua19
-rw-r--r--test/functional/legacy/put_spec.lua45
-rw-r--r--test/functional/legacy/search_spec.lua32
-rw-r--r--test/functional/legacy/search_stat_spec.lua184
-rw-r--r--test/functional/legacy/searchpos_spec.lua35
-rw-r--r--test/functional/legacy/set_spec.lua30
-rw-r--r--test/functional/legacy/statusline_spec.lua71
-rw-r--r--test/functional/legacy/utf8_spec.lua2
-rw-r--r--test/functional/legacy/visual_mode_spec.lua44
-rw-r--r--test/functional/legacy/wordcount_spec.lua66
-rw-r--r--test/functional/lua/api_spec.lua7
-rw-r--r--test/functional/lua/buffer_updates_spec.lua50
-rw-r--r--test/functional/lua/command_line_completion_spec.lua8
-rw-r--r--test/functional/lua/diagnostic_spec.lua56
-rw-r--r--test/functional/lua/filetype_spec.lua24
-rw-r--r--test/functional/lua/fs_spec.lua101
-rw-r--r--test/functional/lua/highlight_spec.lua15
-rw-r--r--test/functional/lua/luaeval_spec.lua1
-rw-r--r--test/functional/lua/overrides_spec.lua38
-rw-r--r--test/functional/lua/thread_spec.lua408
-rw-r--r--test/functional/lua/ui_spec.lua16
-rw-r--r--test/functional/lua/uri_spec.lua2
-rw-r--r--test/functional/lua/vim_spec.lua461
-rw-r--r--test/functional/lua/xdiff_spec.lua42
-rw-r--r--test/functional/options/autochdir_spec.lua31
-rw-r--r--test/functional/options/cursorbind_spec.lua91
-rw-r--r--test/functional/options/defaults_spec.lua107
-rw-r--r--test/functional/options/keymap_spec.lua22
-rw-r--r--test/functional/options/mousescroll_spec.lua151
-rw-r--r--test/functional/options/num_options_spec.lua2
-rw-r--r--test/functional/options/pastetoggle_spec.lua86
-rw-r--r--test/functional/plugin/health_spec.lua35
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua42
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua48
-rw-r--r--test/functional/plugin/lsp/snippet_spec.lua134
-rw-r--r--test/functional/plugin/lsp_spec.lua815
-rw-r--r--test/functional/plugin/man_spec.lua14
-rw-r--r--test/functional/plugin/matchparen_spec.lua2
-rw-r--r--test/functional/plugin/shada_spec.lua8
-rw-r--r--test/functional/preload.lua28
-rw-r--r--test/functional/provider/clipboard_spec.lua16
-rw-r--r--test/functional/provider/nodejs_spec.lua4
-rw-r--r--test/functional/provider/perl_spec.lua4
-rw-r--r--test/functional/provider/provider_spec.lua4
-rw-r--r--test/functional/provider/python3_spec.lua51
-rw-r--r--test/functional/provider/python_spec.lua123
-rw-r--r--test/functional/shada/buffers_spec.lua15
-rw-r--r--test/functional/shada/history_spec.lua21
-rw-r--r--test/functional/shada/marks_spec.lua15
-rw-r--r--test/functional/shada/registers_spec.lua29
-rw-r--r--test/functional/shada/shada_spec.lua2
-rw-r--r--test/functional/shada/variables_spec.lua7
-rw-r--r--test/functional/terminal/api_spec.lua8
-rw-r--r--test/functional/terminal/buffer_spec.lua1
-rw-r--r--test/functional/terminal/channel_spec.lua87
-rw-r--r--test/functional/terminal/cursor_spec.lua60
-rw-r--r--test/functional/terminal/edit_spec.lua5
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua17
-rw-r--r--test/functional/terminal/helpers.lua10
-rw-r--r--test/functional/terminal/highlight_spec.lua25
-rw-r--r--test/functional/terminal/mouse_spec.lua30
-rw-r--r--test/functional/terminal/scrollback_spec.lua47
-rw-r--r--test/functional/terminal/tui_spec.lua260
-rw-r--r--test/functional/terminal/window_spec.lua1
-rw-r--r--test/functional/treesitter/highlight_spec.lua129
-rw-r--r--test/functional/treesitter/language_spec.lua12
-rw-r--r--test/functional/treesitter/parser_spec.lua55
-rw-r--r--test/functional/ui/bufhl_spec.lua28
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua13
-rw-r--r--test/functional/ui/cmdline_spec.lua263
-rw-r--r--test/functional/ui/cursor_spec.lua2
-rw-r--r--test/functional/ui/decorations_spec.lua484
-rw-r--r--test/functional/ui/diff_spec.lua1373
-rw-r--r--test/functional/ui/embed_spec.lua48
-rw-r--r--test/functional/ui/float_spec.lua975
-rw-r--r--test/functional/ui/fold_spec.lua65
-rw-r--r--test/functional/ui/highlight_spec.lua553
-rw-r--r--test/functional/ui/hlstate_spec.lua9
-rw-r--r--test/functional/ui/inccommand_spec.lua367
-rw-r--r--test/functional/ui/inccommand_user_spec.lua356
-rw-r--r--test/functional/ui/input_spec.lua240
-rw-r--r--test/functional/ui/messages_spec.lua339
-rw-r--r--test/functional/ui/mouse_spec.lua141
-rw-r--r--test/functional/ui/multibyte_spec.lua34
-rw-r--r--test/functional/ui/multigrid_spec.lua584
-rw-r--r--test/functional/ui/options_spec.lua57
-rw-r--r--test/functional/ui/output_spec.lua10
-rw-r--r--test/functional/ui/popupmenu_spec.lua434
-rw-r--r--test/functional/ui/screen.lua77
-rw-r--r--test/functional/ui/screen_basic_spec.lua250
-rw-r--r--test/functional/ui/searchhl_spec.lua409
-rw-r--r--test/functional/ui/sign_spec.lua34
-rw-r--r--test/functional/ui/statusline_spec.lua342
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua90
-rw-r--r--test/functional/ui/wildmode_spec.lua4
-rw-r--r--test/functional/ui/winbar_spec.lua580
-rw-r--r--test/functional/vimscript/api_functions_spec.lua3
-rw-r--r--test/functional/vimscript/eval_spec.lua2
-rw-r--r--test/functional/vimscript/executable_spec.lua15
-rw-r--r--test/functional/vimscript/execute_spec.lua4
-rw-r--r--test/functional/vimscript/functions_spec.lua2
-rw-r--r--test/functional/vimscript/has_spec.lua7
-rw-r--r--test/functional/vimscript/input_spec.lua14
-rw-r--r--test/functional/vimscript/lang_spec.lua1
-rw-r--r--test/functional/vimscript/let_spec.lua45
-rw-r--r--test/functional/vimscript/msgpack_functions_spec.lua6
-rw-r--r--test/functional/vimscript/reltime_spec.lua4
-rw-r--r--test/functional/vimscript/screenchar_spec.lua69
-rw-r--r--test/functional/vimscript/server_spec.lua55
-rw-r--r--test/functional/vimscript/setpos_spec.lua22
-rw-r--r--test/functional/vimscript/system_spec.lua109
-rw-r--r--test/functional/vimscript/timer_spec.lua10
-rw-r--r--test/helpers.lua105
-rw-r--r--test/symbolic/klee/nvim/keymap.c2
-rwxr-xr-xtest/symbolic/klee/run.sh2
-rw-r--r--test/symbolic/klee/viml_expressions_lexer.c2
-rw-r--r--test/symbolic/klee/viml_expressions_parser.c2
-rw-r--r--test/unit/buffer_spec.lua187
-rw-r--r--test/unit/fixtures/rbuffer.c2
-rw-r--r--test/unit/helpers.lua6
-rw-r--r--test/unit/keycodes_spec.lua (renamed from test/unit/keymap_spec.lua)25
-rw-r--r--test/unit/marktree_spec.lua44
-rw-r--r--test/unit/os/env_spec.lua4
-rw-r--r--test/unit/os/users_spec.lua12
-rw-r--r--test/unit/path_spec.lua16
-rw-r--r--test/unit/search_spec.lua24
-rw-r--r--test/unit/strings_spec.lua47
-rw-r--r--test/unit/tempfile_spec.lua12
-rw-r--r--test/unit/viml/expressions/parser_spec.lua1
226 files changed, 19018 insertions, 9029 deletions
diff --git a/test/README.md b/test/README.md
index cc630cb8bf..a67040e68c 100644
--- a/test/README.md
+++ b/test/README.md
@@ -91,25 +91,33 @@ or:
Debugging tests
---------------
+- Each test gets a test id which looks like "T123". This also appears in the
+ log file. Child processes spawned from a test appear in the logs with the
+ *parent* name followed by "/c". Example:
+ ```
+ DBG 2022-06-15T18:37:45.226 T57.58016.0 UI: flush
+ DBG 2022-06-15T18:37:45.226 T57.58016.0 inbuf_poll:442: blocking... events_enabled=0 events_pending=0
+ DBG 2022-06-15T18:37:45.227 T57.58016.0/c UI: stop
+ INF 2022-06-15T18:37:45.227 T57.58016.0/c os_exit:595: Nvim exit: 0
+ DBG 2022-06-15T18:37:45.229 T57.58016.0 read_cb:118: closing Stream (0x7fd5d700ea18): EOF (end of file)
+ INF 2022-06-15T18:37:45.229 T57.58016.0 on_process_exit:400: exited: pid=58017 status=0 stoptime=0
+ ```
- You can set `$GDB` to [run tests under gdbserver](https://github.com/neovim/neovim/pull/1527).
And if `$VALGRIND` is set it will pass `--vgdb=yes` to valgrind instead of
starting gdbserver directly.
-- Hanging tests often happen due to unexpected `:h press-enter` prompts. The
+- Hanging tests can happen due to unexpected "press-enter" prompts. The
default screen width is 50 columns. Commands that try to print lines longer
than 50 columns in the command-line, e.g. `:edit very...long...path`, will
- trigger the prompt. In this case, a shorter path or `:silent edit` should be
- used.
+ trigger the prompt. Try using a shorter path, or `:silent edit`.
- If you can't figure out what is going on, try to visualize the screen. Put
this at the beginning of your test:
-
- ```lua
- local Screen = require('test.functional.ui.screen')
- local screen = Screen.new()
- screen:attach()
- ```
-
- Afterwards, put `screen:snapshot_util()` at any position in your test. See the
- comment at the top of `test/functional/ui/screen.lua` for more.
+ ```lua
+ local Screen = require('test.functional.ui.screen')
+ local screen = Screen.new()
+ screen:attach()
+ ```
+ Then put `screen:snapshot_util()` anywhere in your test. See the comments in
+ `test/functional/ui/screen.lua` for more info.
Filtering Tests
---------------
@@ -247,12 +255,17 @@ Number; !must be defined to function properly):
- `BUSTED_ARGS` (F) (U): arguments forwarded to `busted`.
+- `CC` (U) (S): specifies which C compiler to use to preprocess files.
+ Currently only compilers with gcc-compatible arguments are supported.
+
- `GDB` (F) (D): makes nvim instances to be run under `gdbserver`. It will be
accessible on `localhost:7777`: use `gdb build/bin/nvim`, type `target remote
:7777` inside.
- `GDBSERVER_PORT` (F) (I): overrides port used for `GDB`.
+- `LOG_DIR` (FU) (S!): specifies where to seek for valgrind and ASAN log files.
+
- `VALGRIND` (F) (D): makes nvim instances to be run under `valgrind`. Log
files are named `valgrind-%p.log` in this case. Note that non-empty valgrind
log may fail tests. Valgrind arguments may be seen in
@@ -269,11 +282,7 @@ Number; !must be defined to function properly):
- `NVIM_LUA_NOTRACK` (F) (D): disable reference counting of Lua objects
-- `NVIM_PROG`, `NVIM_PRG` (F) (S): override path to Neovim executable (default
- to `build/bin/nvim`).
-
-- `CC` (U) (S): specifies which C compiler to use to preprocess files.
- Currently only compilers with gcc-compatible arguments are supported.
+- `NVIM_PRG` (F) (S): path to Nvim executable (default: `build/bin/nvim`).
- `NVIM_TEST_MAIN_CDEFS` (U) (1): makes `ffi.cdef` run in main process. This
raises a possibility of bugs due to conflicts in header definitions, despite
@@ -295,8 +304,6 @@ Number; !must be defined to function properly):
- `NVIM_TEST_RUN_FAILING_TESTS` (U) (1): makes `itp` run tests which are known
to fail (marked by setting third argument to `true`).
-- `LOG_DIR` (FU) (S!): specifies where to seek for valgrind and ASAN log files.
-
- `NVIM_TEST_CORE_*` (FU) (S): a set of environment variables which specify
where to search for core files. Are supposed to be defined all at once.
diff --git a/test/benchmark/treesitter_spec.lua b/test/benchmark/treesitter_spec.lua
new file mode 100644
index 0000000000..5ce128c54a
--- /dev/null
+++ b/test/benchmark/treesitter_spec.lua
@@ -0,0 +1,53 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+
+describe('treesitter perf', function()
+
+ setup(function()
+ clear()
+ end)
+
+ it('can handle large folds', function()
+ helpers.command'edit ./src/nvim/eval.c'
+ exec_lua[[
+ local parser = vim.treesitter.get_parser(0, "c", {})
+ vim.treesitter.highlighter.new(parser)
+
+ local function keys(k)
+ vim.api.nvim_feedkeys(k, 't', true)
+ end
+
+ vim.opt.foldmethod = "manual"
+ vim.opt.lazyredraw = false
+
+ vim.cmd '1000,7000fold'
+ vim.cmd '999'
+
+ local function mk_keys(n)
+ local acc = ""
+ for _ = 1, n do
+ acc = acc .. "j"
+ end
+ for _ = 1, n do
+ acc = acc .. "k"
+ end
+
+ return "qq" .. acc .. "q"
+ end
+
+ local start = vim.loop.hrtime()
+ keys(mk_keys(10))
+
+ for _ = 1, 100 do
+ keys "@q"
+ vim.cmd'redraw!'
+ end
+
+ return vim.loop.hrtime() - start
+ ]]
+
+ end)
+
+end)
diff --git a/test/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua
index 0e9801b94b..2ce32c3b7a 100644
--- a/test/busted/outputHandlers/nvim.lua
+++ b/test/busted/outputHandlers/nvim.lua
@@ -26,35 +26,35 @@ return function(options)
local repeatSuiteString = '\nRepeating all tests (run %d of %d) . . .\n\n'
local randomizeString = c.note('Note: Randomizing test order with a seed of %d.\n')
- local globalSetup = c.sect('[----------]') .. ' Global test environment setup.\n'
- local fileStartString = c.sect('[----------]') .. ' Running tests from ' .. c.file('%s') .. '\n'
- local runString = c.sect('[ RUN ]') .. ' ' .. c.test('%s') .. ': '
+ local globalSetup = c.sect('--------') .. ' Global test environment setup.\n'
+ local fileStartString = c.sect('--------') .. ' Running tests from ' .. c.file('%s') .. '\n'
+ local runString = c.sect('RUN ') .. ' ' .. c.test('%s') .. ': '
local successString = c.succ('OK') .. '\n'
local skippedString = c.skip('SKIP') .. '\n'
local failureString = c.fail('FAIL') .. '\n'
local errorString = c.errr('ERR') .. '\n'
- local fileEndString = c.sect('[----------]') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n'
- local globalTeardown = c.sect('[----------]') .. ' Global test environment teardown.\n'
- local suiteEndString = c.sect('[==========]') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n'
- local successStatus = c.succ('[ PASSED ]') .. ' ' .. c.nmbr('%d') .. ' %s.\n'
+ local fileEndString = c.sect('--------') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n'
+ local globalTeardown = c.sect('--------') .. ' Global test environment teardown.\n'
+ local suiteEndString = c.sect('========') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n'
+ local successStatus = c.succ('PASSED ') .. ' ' .. c.nmbr('%d') .. ' %s.\n'
local timeString = c.time('%.2f ms')
local summaryStrings = {
skipped = {
- header = c.skip('[ SKIPPED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
- test = c.skip('[ SKIPPED ]') .. ' %s\n',
+ header = c.skip('SKIPPED ') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
+ test = c.skip('SKIPPED ') .. ' %s\n',
footer = ' ' .. c.nmbr('%d') .. ' SKIPPED %s\n',
},
failure = {
- header = c.fail('[ FAILED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
- test = c.fail('[ FAILED ]') .. ' %s\n',
+ header = c.fail('FAILED ') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
+ test = c.fail('FAILED ') .. ' %s\n',
footer = ' ' .. c.nmbr('%d') .. ' FAILED %s\n',
},
error = {
- header = c.errr('[ ERROR ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
- test = c.errr('[ ERROR ]') .. ' %s\n',
+ header = c.errr('ERROR ') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n',
+ test = c.errr('ERROR ') .. ' %s\n',
footer = ' ' .. c.nmbr('%d') .. ' %s\n',
},
}
@@ -192,9 +192,11 @@ return function(options)
local tests = (testCount == 1 and 'test' or 'tests')
local files = (fileCount == 1 and 'file' or 'files')
io.write(globalTeardown)
- io.write(global_helpers.read_nvim_log(nil, true))
io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms))
io.write(getSummaryString())
+ if failureCount > 0 or errorCount > 0 then
+ io.write(global_helpers.read_nvim_log(nil, true))
+ end
io.flush()
return nil, true
@@ -217,7 +219,9 @@ return function(options)
end
handler.testStart = function(element, _parent)
- io.write(runString:format(handler.getFullName(element)))
+ local testid = _G._nvim_test_id or ''
+ local desc = ('%s %s'):format(testid, handler.getFullName(element))
+ io.write(runString:format(desc))
io.flush()
return nil, true
diff --git a/test/config/paths.lua.in b/test/cmakeconfig/paths.lua.in
index e3979981ba..e3979981ba 100644
--- a/test/config/paths.lua.in
+++ b/test/cmakeconfig/paths.lua.in
diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
new file mode 100644
index 0000000000..a923f5df0e
--- /dev/null
+++ b/test/functional/api/autocmd_spec.lua
@@ -0,0 +1,1249 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local neq = helpers.neq
+local exec_lua = helpers.exec_lua
+local matches = helpers.matches
+local meths = helpers.meths
+local source = helpers.source
+local pcall_err = helpers.pcall_err
+
+before_each(clear)
+
+describe('autocmd api', function()
+ describe('nvim_create_autocmd', function()
+ it('does not allow "command" and "callback" in the same autocmd', function()
+ local ok, _ = pcall(meths.create_autocmd, "BufReadPost", {
+ pattern = "*.py,*.pyi",
+ command = "echo 'Should Have Errored",
+ callback = "not allowed",
+ })
+
+ eq(false, ok)
+ end)
+
+ it('doesnt leak when you use ++once', function()
+ eq(1, exec_lua([[
+ local count = 0
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = function() count = count + 1 end,
+ once = true
+ })
+
+ vim.cmd "set filetype=txt"
+ vim.cmd "set filetype=python"
+
+ return count
+ ]], {}))
+ end)
+
+ it('allows passing buffer by key', function()
+ meths.set_var('called', 0)
+
+ meths.create_autocmd("FileType", {
+ command = "let g:called = g:called + 1",
+ buffer = 0,
+ })
+
+ meths.command "set filetype=txt"
+ eq(1, meths.get_var('called'))
+
+ -- switch to a new buffer
+ meths.command "new"
+ meths.command "set filetype=python"
+
+ eq(1, meths.get_var('called'))
+ end)
+
+ it('does not allow passing buffer and patterns', function()
+ local ok = pcall(meths.create_autocmd, "Filetype", {
+ command = "let g:called = g:called + 1",
+ buffer = 0,
+ pattern = "*.py",
+ })
+
+ eq(false, ok)
+ end)
+
+ it('does not allow passing invalid buffers', function()
+ local ok, msg = pcall(meths.create_autocmd, "Filetype", {
+ command = "let g:called = g:called + 1",
+ buffer = -1,
+ })
+
+ eq(false, ok)
+ matches('Invalid buffer id', msg)
+ end)
+
+ it('errors on non-functions for cb', function()
+ eq(false, pcall(exec_lua, [[
+ vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*.py,*.pyi",
+ callback = 5,
+ })
+ ]]))
+ end)
+
+ it('allow passing pattern and <buffer> in same pattern', function()
+ local ok = pcall(meths.create_autocmd, "BufReadPost", {
+ pattern = "*.py,<buffer>",
+ command = "echo 'Should Not Error'"
+ })
+
+ eq(true, ok)
+ end)
+
+ it('should handle multiple values as comma separated list', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*.py,*.pyi",
+ command = "echo 'Should Not Have Errored'"
+ })
+
+ -- We should have one autocmd for *.py and one for *.pyi
+ eq(2, #meths.get_autocmds { event = "BufReadPost" })
+ end)
+
+ it('should handle multiple values as array', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = { "*.py", "*.pyi", },
+ command = "echo 'Should Not Have Errored'"
+ })
+
+ -- We should have one autocmd for *.py and one for *.pyi
+ eq(2, #meths.get_autocmds { event = "BufReadPost" })
+ end)
+
+ describe('desc', function()
+ it('can add description to one autocmd', function()
+ local cmd = "echo 'Should Not Have Errored'"
+ local desc = "Can show description"
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ command = cmd,
+ desc = desc,
+ })
+
+ eq(desc, meths.get_autocmds { event = "BufReadPost" }[1].desc)
+ eq(cmd, meths.get_autocmds { event = "BufReadPost" }[1].command)
+ end)
+
+ it('can add description to one autocmd that uses a callback', function()
+ local desc = 'Can show description'
+ meths.set_var('desc', desc)
+
+ local result = exec_lua([[
+ local callback = function() print 'Should Not Have Errored' end
+ vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ callback = callback,
+ desc = vim.g.desc,
+ })
+ local aus = vim.api.nvim_get_autocmds({ event = 'BufReadPost' })
+ local first = aus[1]
+ return {
+ desc = first.desc,
+ cbtype = type(first.callback)
+ }
+ ]])
+
+ eq({ desc = desc, cbtype = 'function' }, result)
+ end)
+
+ it('will not add a description unless it was provided', function()
+ exec_lua([[
+ local callback = function() print 'Should Not Have Errored' end
+ vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ callback = callback,
+ })
+ ]])
+
+ eq(nil, meths.get_autocmds({ event = 'BufReadPost' })[1].desc)
+ end)
+
+ it('can add description to multiple autocmd', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = {"*.py", "*.pyi"},
+ command = "echo 'Should Not Have Errored'",
+ desc = "Can show description",
+ })
+
+ local aus = meths.get_autocmds { event = "BufReadPost" }
+ eq(2, #aus)
+ eq("Can show description", aus[1].desc)
+ eq("Can show description", aus[2].desc)
+ end)
+ end)
+
+ pending('script and verbose settings', function()
+ it('marks API client', function()
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*.py",
+ command = "echo 'Should Not Have Errored'",
+ desc = "Can show description",
+ })
+
+ local aus = meths.get_autocmds { event = "BufReadPost" }
+ eq(1, #aus, aus)
+ end)
+ end)
+
+ it('removes an autocommand if the callback returns true', function()
+ meths.set_var("some_condition", false)
+
+ exec_lua [[
+ vim.api.nvim_create_autocmd("User", {
+ pattern = "Test",
+ desc = "A test autocommand",
+ callback = function()
+ return vim.g.some_condition
+ end,
+ })
+ ]]
+
+ meths.exec_autocmds("User", {pattern = "Test"})
+
+ local aus = meths.get_autocmds({ event = 'User', pattern = 'Test' })
+ local first = aus[1]
+ eq(first.id, 1)
+
+ meths.set_var("some_condition", true)
+ meths.exec_autocmds("User", {pattern = "Test"})
+ eq({}, meths.get_autocmds({event = "User", pattern = "Test"}))
+ end)
+
+ it('receives an args table', function()
+ local res = exec_lua [[
+ local group_id = vim.api.nvim_create_augroup("TestGroup", {})
+ local autocmd_id = vim.api.nvim_create_autocmd("User", {
+ group = "TestGroup",
+ pattern = "Te*",
+ callback = function(args)
+ vim.g.autocmd_args = args
+ end,
+ })
+
+ return {group_id, autocmd_id}
+ ]]
+
+ meths.exec_autocmds("User", {pattern = "Test pattern"})
+ eq({
+ id = res[2],
+ group = res[1],
+ event = "User",
+ match = "Test pattern",
+ file = "Test pattern",
+ buf = 1,
+ }, meths.get_var("autocmd_args"))
+
+ -- Test without a group
+ res = exec_lua [[
+ local autocmd_id = vim.api.nvim_create_autocmd("User", {
+ pattern = "*",
+ callback = function(args)
+ vim.g.autocmd_args = args
+ end,
+ })
+
+ return {autocmd_id}
+ ]]
+
+ meths.exec_autocmds("User", {pattern = "some_pat"})
+ eq({
+ id = res[1],
+ group = nil,
+ event = "User",
+ match = "some_pat",
+ file = "some_pat",
+ buf = 1,
+ }, meths.get_var("autocmd_args"))
+
+ end)
+
+ it('can receive arbitrary data', function()
+ local function test(data)
+ eq(data, exec_lua([[
+ local input = ...
+ local output
+ vim.api.nvim_create_autocmd("User", {
+ pattern = "Test",
+ callback = function(args)
+ output = args.data
+ end,
+ })
+
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "Test",
+ data = input,
+ })
+
+ return output
+ ]], data))
+ end
+
+ test("Hello")
+ test(42)
+ test(true)
+ test({ "list" })
+ test({ foo = "bar" })
+ end)
+ end)
+
+ describe('nvim_get_autocmds', function()
+ describe('events', function()
+ it('should return one autocmd when there is only one for an event', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ eq(1, #aus)
+ end)
+
+ it('should return two autocmds when there are two for an event', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+ command [[au InsertEnter * :echo "2"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ eq(2, #aus)
+ end)
+
+ it('should return the same thing if you use string or list', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+ command [[au InsertEnter * :echo "2"]]
+
+ local string_aus = meths.get_autocmds { event = "InsertEnter" }
+ local array_aus = meths.get_autocmds { event = { "InsertEnter" } }
+ eq(string_aus, array_aus)
+ end)
+
+ it('should return two autocmds when there are two for an event', function()
+ command [[au! InsertEnter]]
+ command [[au! InsertLeave]]
+ command [[au InsertEnter * :echo "1"]]
+ command [[au InsertEnter * :echo "2"]]
+
+ local aus = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(2, #aus)
+ end)
+
+ it('should return different IDs for different autocmds', function()
+ command [[au! InsertEnter]]
+ command [[au! InsertLeave]]
+ command [[au InsertEnter * :echo "1"]]
+ source [[
+ call nvim_create_autocmd("InsertLeave", #{
+ \ command: ":echo 2",
+ \ })
+ ]]
+
+ local aus = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ local first = aus[1]
+ eq(first.id, nil)
+
+ -- TODO: Maybe don't have this number, just assert it's not nil
+ local second = aus[2]
+ neq(second.id, nil)
+
+ meths.del_autocmd(second.id)
+ local new_aus = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(1, #new_aus)
+ eq(first, new_aus[1])
+ end)
+
+ it('should return event name', function()
+ command [[au! InsertEnter]]
+ command [[au InsertEnter * :echo "1"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ eq({ { buflocal = false, command = ':echo "1"', event = "InsertEnter", once = false, pattern = "*" } }, aus)
+ end)
+
+ it('should work with buffer numbers', function()
+ command [[new]]
+ command [[au! InsertEnter]]
+ command [[au InsertEnter <buffer=1> :echo "1"]]
+ command [[au InsertEnter <buffer=2> :echo "2"]]
+
+ local aus = meths.get_autocmds { event = "InsertEnter", buffer = 0 }
+ eq({{
+ buffer = 2,
+ buflocal = true,
+ command = ':echo "2"',
+ event = 'InsertEnter',
+ once = false,
+ pattern = '<buffer=2>',
+ }}, aus)
+
+ aus = meths.get_autocmds { event = "InsertEnter", buffer = 1 }
+ eq({{
+ buffer = 1,
+ buflocal = true,
+ command = ':echo "1"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=1>",
+ }}, aus)
+
+ aus = meths.get_autocmds { event = "InsertEnter", buffer = { 1, 2 } }
+ eq({{
+ buffer = 1,
+ buflocal = true,
+ command = ':echo "1"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=1>",
+ }, {
+ buffer = 2,
+ buflocal = true,
+ command = ':echo "2"',
+ event = "InsertEnter",
+ once = false,
+ pattern = "<buffer=2>",
+ }}, aus)
+
+ eq("Invalid value for 'buffer': must be an integer or array of integers", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" }))
+ eq("Invalid value for 'buffer': must be an integer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } }))
+ eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } }))
+
+ local bufs = {}
+ for _ = 1, 257 do
+ table.insert(bufs, meths.create_buf(true, false))
+ end
+
+ eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs }))
+ end)
+
+ it('should return autocmds when group is specified by id', function()
+ local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
+ meths.create_autocmd("FileType", { group = auid, command = 'echo "1"' })
+ meths.create_autocmd("FileType", { group = auid, command = 'echo "2"' })
+
+ local aus = meths.get_autocmds { group = auid }
+ eq(2, #aus)
+
+ local aus2 = meths.get_autocmds { group = auid, event = "InsertEnter" }
+ eq(0, #aus2)
+ end)
+
+ it('should return autocmds when group is specified by name', function()
+ local auname = "nvim_test_augroup"
+ meths.create_augroup(auname, { clear = true })
+ meths.create_autocmd("FileType", { group = auname, command = 'echo "1"' })
+ meths.create_autocmd("FileType", { group = auname, command = 'echo "2"' })
+
+ local aus = meths.get_autocmds { group = auname }
+ eq(2, #aus)
+
+ local aus2 = meths.get_autocmds { group = auname, event = "InsertEnter" }
+ eq(0, #aus2)
+ end)
+
+ it('should respect nested', function()
+ local bufs = exec_lua [[
+ local count = 0
+ vim.api.nvim_create_autocmd("BufNew", {
+ once = false,
+ nested = true,
+ callback = function()
+ count = count + 1
+ if count > 5 then
+ return true
+ end
+
+ vim.cmd(string.format("new README_%s.md", count))
+ end
+ })
+
+ vim.cmd "new First.md"
+
+ return vim.api.nvim_list_bufs()
+ ]]
+
+ -- 1 for the first buffer
+ -- 2 for First.md
+ -- 3-7 for the 5 we make in the autocmd
+ eq({1, 2, 3, 4, 5, 6, 7}, bufs)
+ end)
+
+ it('can retrieve a callback from an autocmd', function()
+ local content = 'I Am A Callback'
+ meths.set_var('content', content)
+
+ local result = exec_lua([[
+ local cb = function() return vim.g.content end
+ vim.api.nvim_create_autocmd("User", {
+ pattern = "TestTrigger",
+ desc = "A test autocommand with a callback",
+ callback = cb,
+ })
+ local aus = vim.api.nvim_get_autocmds({ event = 'User', pattern = 'TestTrigger'})
+ local first = aus[1]
+ return {
+ cb = {
+ type = type(first.callback),
+ can_retrieve = first.callback() == vim.g.content
+ }
+ }
+ ]])
+
+ eq("function", result.cb.type)
+ eq(true, result.cb.can_retrieve)
+ end)
+
+ it('will return an empty string as the command for an autocmd that uses a callback', function()
+ local result = exec_lua([[
+ local callback = function() print 'I Am A Callback' end
+ vim.api.nvim_create_autocmd("BufWritePost", {
+ pattern = "*.py",
+ callback = callback,
+ })
+ local aus = vim.api.nvim_get_autocmds({ event = 'BufWritePost' })
+ local first = aus[1]
+ return {
+ command = first.command,
+ cbtype = type(first.callback)
+ }
+ ]])
+
+ eq({ command = "", cbtype = 'function' }, result)
+ end)
+ end)
+
+ describe('groups', function()
+ before_each(function()
+ command [[au! InsertEnter]]
+
+ command [[au InsertEnter * :echo "No Group"]]
+
+ command [[augroup GroupOne]]
+ command [[ au InsertEnter * :echo "GroupOne:1"]]
+ command [[augroup END]]
+
+ command [[augroup GroupTwo]]
+ command [[ au InsertEnter * :echo "GroupTwo:2"]]
+ command [[ au InsertEnter * :echo "GroupTwo:3"]]
+ command [[augroup END]]
+ end)
+
+ it('should return all groups if no group is specified', function()
+ local aus = meths.get_autocmds { event = "InsertEnter" }
+ if #aus ~= 4 then
+ eq({}, aus)
+ end
+
+ eq(4, #aus)
+ end)
+
+ it('should return only the group specified', function()
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ group = "GroupOne",
+ }
+
+ eq(1, #aus)
+ eq([[:echo "GroupOne:1"]], aus[1].command)
+ eq("GroupOne", aus[1].group_name)
+ end)
+
+ it('should return only the group specified, multiple values', function()
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ group = "GroupTwo",
+ }
+
+ eq(2, #aus)
+ eq([[:echo "GroupTwo:2"]], aus[1].command)
+ eq("GroupTwo", aus[1].group_name)
+ eq([[:echo "GroupTwo:3"]], aus[2].command)
+ eq("GroupTwo", aus[2].group_name)
+ end)
+ end)
+
+ describe('groups: 2', function()
+ it('raises error for undefined augroup name', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = "NotDefined",
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches('invalid augroup: NotDefined', code)
+ end)
+
+ it('raises error for undefined augroup id', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ -- Make sure the augroup is deleted
+ vim.api.nvim_del_augroup_by_id(1)
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = 1,
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches('invalid augroup: 1', code)
+ end)
+
+ it('raises error for invalid group type', function()
+ local success, code = unpack(meths.exec_lua([[
+ return {pcall(function()
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ group = true,
+ command = "echo 'hello'",
+ })
+ end)}
+ ]], {}))
+
+ eq(false, success)
+ matches("'group' must be a string or an integer", code)
+ end)
+ end)
+
+ describe('patterns', function()
+ before_each(function()
+ command [[au! InsertEnter]]
+
+ command [[au InsertEnter * :echo "No Group"]]
+ command [[au InsertEnter *.one :echo "GroupOne:1"]]
+ command [[au InsertEnter *.two :echo "GroupTwo:2"]]
+ command [[au InsertEnter *.two :echo "GroupTwo:3"]]
+ command [[au InsertEnter <buffer> :echo "Buffer"]]
+ end)
+
+ it('should should return for literal match', function()
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "*"
+ }
+
+ eq(1, #aus)
+ eq([[:echo "No Group"]], aus[1].command)
+ end)
+
+ it('should return for multiple matches', function()
+ -- vim.api.nvim_get_autocmds
+ local aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = { "*.one", "*.two" },
+ }
+
+ eq(3, #aus)
+ eq([[:echo "GroupOne:1"]], aus[1].command)
+ eq([[:echo "GroupTwo:2"]], aus[2].command)
+ eq([[:echo "GroupTwo:3"]], aus[3].command)
+ end)
+
+ it('should work for buffer autocmds', function()
+ local normalized_aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "<buffer=1>",
+ }
+
+ local raw_aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "<buffer>",
+ }
+
+ local zero_aus = meths.get_autocmds {
+ event = "InsertEnter",
+ pattern = "<buffer=0>",
+ }
+
+ eq(normalized_aus, raw_aus)
+ eq(normalized_aus, zero_aus)
+ eq([[:echo "Buffer"]], normalized_aus[1].command)
+ end)
+ end)
+ end)
+
+ describe('nvim_exec_autocmds', function()
+ it("can trigger builtin autocmds", function()
+ meths.set_var("autocmd_executed", false)
+
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*",
+ command = "let g:autocmd_executed = v:true",
+ })
+
+ eq(false, meths.get_var("autocmd_executed"))
+ meths.exec_autocmds("BufReadPost", {})
+ eq(true, meths.get_var("autocmd_executed"))
+ end)
+
+ it("can trigger multiple patterns", function()
+ meths.set_var("autocmd_executed", 0)
+
+ meths.create_autocmd("BufReadPost", {
+ pattern = "*",
+ command = "let g:autocmd_executed += 1",
+ })
+
+ meths.exec_autocmds("BufReadPost", { pattern = { "*.lua", "*.vim" } })
+ eq(2, meths.get_var("autocmd_executed"))
+
+ meths.create_autocmd("BufReadPre", {
+ pattern = { "bar", "foo" },
+ command = "let g:autocmd_executed += 10",
+ })
+
+ meths.exec_autocmds("BufReadPre", { pattern = { "foo", "bar", "baz", "frederick" }})
+ eq(22, meths.get_var("autocmd_executed"))
+ end)
+
+ it("can pass the buffer", function()
+ meths.set_var("buffer_executed", -1)
+ eq(-1, meths.get_var("buffer_executed"))
+
+ meths.create_autocmd("BufLeave", {
+ pattern = "*",
+ command = 'let g:buffer_executed = +expand("<abuf>")',
+ })
+
+ -- Doesn't execute for other non-matching events
+ meths.exec_autocmds("CursorHold", { buffer = 1 })
+ eq(-1, meths.get_var("buffer_executed"))
+
+ meths.exec_autocmds("BufLeave", { buffer = 1 })
+ eq(1, meths.get_var("buffer_executed"))
+ end)
+
+ it("can pass the filename, pattern match", function()
+ meths.set_var("filename_executed", 'none')
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.create_autocmd("BufEnter", {
+ pattern = "*.py",
+ command = 'let g:filename_executed = expand("<afile>")',
+ })
+
+ -- Doesn't execute for other non-matching events
+ meths.exec_autocmds("CursorHold", { buffer = 1 })
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.command('edit __init__.py')
+ eq('__init__.py', meths.get_var("filename_executed"))
+ end)
+
+ it('cannot pass buf and fname', function()
+ local ok = pcall(meths.exec_autocmds, "BufReadPre", { pattern = "literally_cannot_error.rs", buffer = 1 })
+ eq(false, ok)
+ end)
+
+ it("can pass the filename, exact match", function()
+ meths.set_var("filename_executed", 'none')
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.command('edit other_file.txt')
+ meths.command('edit __init__.py')
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.create_autocmd("CursorHoldI", {
+ pattern = "__init__.py",
+ command = 'let g:filename_executed = expand("<afile>")',
+ })
+
+ -- Doesn't execute for other non-matching events
+ meths.exec_autocmds("CursorHoldI", { buffer = 1 })
+ eq('none', meths.get_var("filename_executed"))
+
+ meths.exec_autocmds("CursorHoldI", { buffer = meths.get_current_buf() })
+ eq('__init__.py', meths.get_var("filename_executed"))
+
+ -- Reset filename
+ meths.set_var("filename_executed", 'none')
+
+ meths.exec_autocmds("CursorHoldI", { pattern = '__init__.py' })
+ eq('__init__.py', meths.get_var("filename_executed"))
+ end)
+
+ it("works with user autocmds", function()
+ meths.set_var("matched", 'none')
+
+ meths.create_autocmd("User", {
+ pattern = "TestCommand",
+ command = 'let g:matched = "matched"'
+ })
+
+ meths.exec_autocmds("User", { pattern = "OtherCommand" })
+ eq('none', meths.get_var('matched'))
+ meths.exec_autocmds("User", { pattern = "TestCommand" })
+ eq('matched', meths.get_var('matched'))
+ end)
+
+ it('can pass group by id', function()
+ meths.set_var("group_executed", false)
+
+ local auid = meths.create_augroup("nvim_test_augroup", { clear = true })
+ meths.create_autocmd("FileType", {
+ group = auid,
+ command = 'let g:group_executed = v:true',
+ })
+
+ eq(false, meths.get_var("group_executed"))
+ meths.exec_autocmds("FileType", { group = auid })
+ eq(true, meths.get_var("group_executed"))
+ end)
+
+ it('can pass group by name', function()
+ meths.set_var("group_executed", false)
+
+ local auname = "nvim_test_augroup"
+ meths.create_augroup(auname, { clear = true })
+ meths.create_autocmd("FileType", {
+ group = auname,
+ command = 'let g:group_executed = v:true',
+ })
+
+ eq(false, meths.get_var("group_executed"))
+ meths.exec_autocmds("FileType", { group = auname })
+ eq(true, meths.get_var("group_executed"))
+ end)
+ end)
+
+ describe('nvim_create_augroup', function()
+ before_each(function()
+ clear()
+
+ meths.set_var('executed', 0)
+ end)
+
+ local make_counting_autocmd = function(opts)
+ opts = opts or {}
+
+ local resulting = {
+ pattern = "*",
+ command = "let g:executed = g:executed + 1",
+ }
+
+ resulting.group = opts.group
+ resulting.once = opts.once
+
+ meths.create_autocmd("FileType", resulting)
+ end
+
+ local set_ft = function(ft)
+ ft = ft or "txt"
+ source(string.format("set filetype=%s", ft))
+ end
+
+ local get_executed_count = function()
+ return meths.get_var('executed')
+ end
+
+ it('can be added in a group', function()
+ local augroup = "TestGroup"
+ meths.create_augroup(augroup, { clear = true })
+ make_counting_autocmd { group = augroup }
+
+ set_ft("txt")
+ set_ft("python")
+
+ eq(2, get_executed_count())
+ end)
+
+ it('works getting called multiple times', function()
+ make_counting_autocmd()
+ set_ft()
+ set_ft()
+ set_ft()
+
+ eq(3, get_executed_count())
+ end)
+
+ it('handles ++once', function()
+ make_counting_autocmd {once = true}
+ set_ft('txt')
+ set_ft('help')
+ set_ft('txt')
+ set_ft('help')
+
+ eq(1, get_executed_count())
+ end)
+
+ it('errors on unexpected keys', function()
+ local success, code = pcall(meths.create_autocmd, "FileType", {
+ pattern = "*",
+ not_a_valid_key = "NotDefined",
+ })
+
+ eq(false, success)
+ matches('not_a_valid_key', code)
+ end)
+
+ it('can execute simple callback', function()
+ exec_lua([[
+ vim.g.executed = false
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = function() vim.g.executed = true end,
+ })
+ ]], {})
+
+
+ eq(true, exec_lua([[
+ vim.cmd "set filetype=txt"
+ return vim.g.executed
+ ]], {}))
+ end)
+
+ it('calls multiple lua callbacks for the same autocmd execution', function()
+ eq(4, exec_lua([[
+ local count = 0
+ local counter = function()
+ count = count + 1
+ end
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = counter,
+ })
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = counter,
+ })
+
+ vim.cmd "set filetype=txt"
+ vim.cmd "set filetype=txt"
+
+ return count
+ ]], {}))
+ end)
+
+ it('properly releases functions with ++once', function()
+ exec_lua([[
+ WeakTable = setmetatable({}, { __mode = "k" })
+
+ OnceCount = 0
+
+ MyVal = {}
+ WeakTable[MyVal] = true
+
+ vim.api.nvim_create_autocmd("FileType", {
+ pattern = "*",
+ callback = function()
+ OnceCount = OnceCount + 1
+ MyVal = {}
+ end,
+ once = true
+ })
+ ]])
+
+ command [[set filetype=txt]]
+ eq(1, exec_lua([[return OnceCount]], {}))
+
+ exec_lua([[collectgarbage()]], {})
+
+ command [[set filetype=txt]]
+ eq(1, exec_lua([[return OnceCount]], {}))
+
+ eq(0, exec_lua([[
+ local count = 0
+ for _ in pairs(WeakTable) do
+ count = count + 1
+ end
+
+ return count
+ ]]), "Should have no keys remaining")
+ end)
+
+ it('groups can be cleared', function()
+ local augroup = "TestGroup"
+ meths.create_augroup(augroup, { clear = true })
+ meths.create_autocmd("FileType", {
+ group = augroup,
+ command = "let g:executed = g:executed + 1"
+ })
+
+ set_ft("txt")
+ set_ft("txt")
+ eq(2, get_executed_count(), "should only count twice")
+
+ meths.create_augroup(augroup, { clear = true })
+ eq({}, meths.get_autocmds { group = augroup })
+
+ set_ft("txt")
+ set_ft("txt")
+ eq(2, get_executed_count(), "No additional counts")
+ end)
+
+ it('can delete non-existent groups with pcall', function()
+ eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_name, 'noexist')]])
+ eq('Vim:E367: No such group: "noexist"', pcall_err(meths.del_augroup_by_name, 'noexist'))
+
+ eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_id, -12342)]])
+ eq('Vim:E367: No such group: "--Deleted--"', pcall_err(meths.del_augroup_by_id, -12312))
+ end)
+
+ it('groups work with once', function()
+ local augroup = "TestGroup"
+
+ meths.create_augroup(augroup, { clear = true })
+ make_counting_autocmd { group = augroup, once = true }
+
+ set_ft("txt")
+ set_ft("python")
+
+ eq(1, get_executed_count())
+ end)
+
+ it('autocmds can be registered multiple times.', function()
+ local augroup = "TestGroup"
+
+ meths.create_augroup(augroup, { clear = true })
+ make_counting_autocmd { group = augroup, once = false }
+ make_counting_autocmd { group = augroup, once = false }
+ make_counting_autocmd { group = augroup, once = false }
+
+ set_ft("txt")
+ set_ft("python")
+
+ eq(3 * 2, get_executed_count())
+ end)
+
+ it('can be deleted', function()
+ local augroup = "WillBeDeleted"
+
+ meths.create_augroup(augroup, { clear = true })
+ meths.create_autocmd({"Filetype"}, {
+ pattern = "*",
+ command = "echo 'does not matter'",
+ })
+
+ -- Clears the augroup from before, which erases the autocmd
+ meths.create_augroup(augroup, { clear = true })
+
+ local result = #meths.get_autocmds { group = augroup }
+
+ eq(0, result)
+ end)
+
+ it('can be used for buffer local autocmds', function()
+ local augroup = "WillBeDeleted"
+
+ meths.set_var("value_set", false)
+
+ meths.create_augroup(augroup, { clear = true })
+ meths.create_autocmd("Filetype", {
+ pattern = "<buffer>",
+ command = "let g:value_set = v:true",
+ })
+
+ command "new"
+ command "set filetype=python"
+
+ eq(false, meths.get_var("value_set"))
+ end)
+
+ it('can accept vimscript functions', function()
+ source [[
+ let g:vimscript_executed = 0
+
+ function! MyVimscriptFunction() abort
+ let g:vimscript_executed = g:vimscript_executed + 1
+ endfunction
+
+ call nvim_create_autocmd("FileType", #{
+ \ pattern: ["python", "javascript"],
+ \ callback: "MyVimscriptFunction",
+ \ })
+
+ set filetype=txt
+ set filetype=python
+ set filetype=txt
+ set filetype=javascript
+ set filetype=txt
+ ]]
+
+ eq(2, meths.get_var("vimscript_executed"))
+ end)
+ end)
+
+ describe('augroup!', function()
+ it('legacy: should clear and not return any autocmds for delete groups', function()
+ command('augroup TEMP_A')
+ command(' autocmd! BufReadPost *.py :echo "Hello"')
+ command('augroup END')
+
+ command('augroup! TEMP_A')
+
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_A' }))
+
+ -- For some reason, augroup! doesn't clear the autocmds themselves, which is just wild
+ -- but we managed to keep this behavior.
+ eq(1, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('legacy: remove augroups that have no autocmds', function()
+ command('augroup TEMP_AB')
+ command('augroup END')
+
+ command('augroup! TEMP_AB')
+
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_AB' }))
+ eq(0, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('legacy: multiple remove and add augroup', function()
+ command('augroup TEMP_ABC')
+ command(' au!')
+ command(' autocmd BufReadPost *.py echo "Hello"')
+ command('augroup END')
+
+ command('augroup! TEMP_ABC')
+
+ -- Should still have one autocmd :'(
+ local aus = meths.get_autocmds { event = 'BufReadPost' }
+ eq(1, #aus, aus)
+
+ command('augroup TEMP_ABC')
+ command(' au!')
+ command(' autocmd BufReadPost *.py echo "Hello"')
+ command('augroup END')
+
+ -- Should now have two autocmds :'(
+ aus = meths.get_autocmds { event = 'BufReadPost' }
+ eq(2, #aus, aus)
+
+ command('augroup! TEMP_ABC')
+
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_ABC' }))
+ eq(2, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('api: should clear and not return any autocmds for delete groups by id', function()
+ command('augroup TEMP_ABCD')
+ command('autocmd! BufReadPost *.py :echo "Hello"')
+ command('augroup END')
+
+ local augroup_id = meths.create_augroup("TEMP_ABCD", { clear = false })
+ meths.del_augroup_by_id(augroup_id)
+
+ -- For good reason, we kill all the autocmds from del_augroup,
+ -- so now this works as expected
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_ABCD' }))
+ eq(0, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+
+ it('api: should clear and not return any autocmds for delete groups by name', function()
+ command('augroup TEMP_ABCDE')
+ command('autocmd! BufReadPost *.py :echo "Hello"')
+ command('augroup END')
+
+ meths.del_augroup_by_name("TEMP_ABCDE")
+
+ -- For good reason, we kill all the autocmds from del_augroup,
+ -- so now this works as expected
+ eq(false, pcall(meths.get_autocmds, { group = 'TEMP_ABCDE' }))
+ eq(0, #meths.get_autocmds { event = 'BufReadPost' })
+ end)
+ end)
+
+ describe('nvim_clear_autocmds', function()
+ it('should clear based on event + pattern', function()
+ command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"')
+ command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"')
+
+ local search = { event = "InsertEnter", pattern = "*.txt" }
+ local before_delete = meths.get_autocmds(search)
+ eq(1, #before_delete)
+
+ local before_delete_all = meths.get_autocmds { event = search.event }
+ eq(2, #before_delete_all)
+
+ meths.clear_autocmds(search)
+ local after_delete = meths.get_autocmds(search)
+ eq(0, #after_delete)
+
+ local after_delete_all = meths.get_autocmds { event = search.event }
+ eq(1, #after_delete_all)
+ end)
+
+ it('should clear based on event', function()
+ command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"')
+ command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"')
+
+ local search = { event = "InsertEnter"}
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+
+ meths.clear_autocmds(search)
+ local after_delete = meths.get_autocmds(search)
+ eq(0, #after_delete)
+ end)
+
+ it('should clear based on pattern', function()
+ command('autocmd InsertEnter *.TestPat1 :echo "Enter 1"')
+ command('autocmd InsertLeave *.TestPat1 :echo "Leave 1"')
+ command('autocmd InsertEnter *.TestPat2 :echo "Enter 2"')
+ command('autocmd InsertLeave *.TestPat2 :echo "Leave 2"')
+
+ local search = { pattern = "*.TestPat1"}
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+ local before_delete_events = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(4, #before_delete_events)
+
+ meths.clear_autocmds(search)
+ local after_delete = meths.get_autocmds(search)
+ eq(0, #after_delete)
+
+ local after_delete_events = meths.get_autocmds { event = { "InsertEnter", "InsertLeave" } }
+ eq(2, #after_delete_events)
+ end)
+
+ it('should allow clearing by buffer', function()
+ command('autocmd! InsertEnter')
+ command('autocmd InsertEnter <buffer> :echo "Enter Buffer"')
+ command('autocmd InsertEnter *.TestPat1 :echo "Enter Pattern"')
+
+ local search = { event = "InsertEnter" }
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+
+ meths.clear_autocmds { buffer = 0 }
+ local after_delete = meths.get_autocmds(search)
+ eq(1, #after_delete)
+ eq("*.TestPat1", after_delete[1].pattern)
+ end)
+
+ it('should allow clearing by buffer and group', function()
+ command('augroup TestNvimClearAutocmds')
+ command(' au!')
+ command(' autocmd InsertEnter <buffer> :echo "Enter Buffer"')
+ command(' autocmd InsertEnter *.TestPat1 :echo "Enter Pattern"')
+ command('augroup END')
+
+ local search = { event = "InsertEnter", group = "TestNvimClearAutocmds" }
+ local before_delete = meths.get_autocmds(search)
+ eq(2, #before_delete)
+
+ -- Doesn't clear without passing group.
+ meths.clear_autocmds { buffer = 0 }
+ local without_group = meths.get_autocmds(search)
+ eq(2, #without_group)
+
+ -- Doest clear with passing group.
+ meths.clear_autocmds { buffer = 0, group = search.group }
+ local with_group = meths.get_autocmds(search)
+ eq(1, #with_group)
+ end)
+ end)
+end)
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 688f3abba5..dc668e7201 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -227,8 +227,8 @@ describe('api/buf', function()
it('can get a single line with strict indexing', function()
set_lines(0, 1, true, {'line1.a'})
eq(1, line_count()) -- sanity
- eq(false, pcall(get_lines, 1, 2, true))
- eq(false, pcall(get_lines, -3, -2, true))
+ eq('Index out of bounds', pcall_err(get_lines, 1, 2, true))
+ eq('Index out of bounds', pcall_err(get_lines, -3, -2, true))
end)
it('can get a single line with non-strict indexing', function()
@@ -240,11 +240,11 @@ describe('api/buf', function()
it('can set and delete a single line with strict indexing', function()
set_lines(0, 1, true, {'line1.a'})
- eq(false, pcall(set_lines, 1, 2, true, {'line1.b'}))
- eq(false, pcall(set_lines, -3, -2, true, {'line1.c'}))
+ eq('Index out of bounds', pcall_err(set_lines, 1, 2, true, {'line1.b'}))
+ eq('Index out of bounds', pcall_err(set_lines, -3, -2, true, {'line1.c'}))
eq({'line1.a'}, get_lines(0, -1, true))
- eq(false, pcall(set_lines, 1, 2, true, {}))
- eq(false, pcall(set_lines, -3, -2, true, {}))
+ eq('Index out of bounds', pcall_err(set_lines, 1, 2, true, {}))
+ eq('Index out of bounds', pcall_err(set_lines, -3, -2, true, {}))
eq({'line1.a'}, get_lines(0, -1, true))
end)
@@ -302,9 +302,9 @@ describe('api/buf', function()
set_lines(0, -1, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, get_lines(0, -1, true)) --sanity
- eq(false, pcall(get_lines, 3, 4, true))
- eq(false, pcall(get_lines, 3, 10, true))
- eq(false, pcall(get_lines, -5, -5, true))
+ eq('Index out of bounds', pcall_err(get_lines, 3, 4, true))
+ eq('Index out of bounds', pcall_err(get_lines, 3, 10, true))
+ eq('Index out of bounds', pcall_err(get_lines, -5, -5, true))
-- empty or inverted ranges are not errors
eq({}, get_lines(3, -1, true))
eq({}, get_lines(-3, -4, true))
@@ -316,10 +316,10 @@ describe('api/buf', function()
eq({'c'}, get_lines(-2, 5, false))
eq({'a', 'b', 'c'}, get_lines(0, 6, false))
- eq(false, pcall(set_lines, 4, 6, true, {'d'}))
+ eq('Index out of bounds', pcall_err(set_lines, 4, 6, true, {'d'}))
set_lines(4, 6, false, {'d'})
eq({'a', 'b', 'c', 'd'}, get_lines(0, -1, true))
- eq(false, pcall(set_lines, -6, -6, true, {'e'}))
+ eq('Index out of bounds', pcall_err(set_lines, -6, -6, true, {'e'}))
set_lines(-6, -6, false, {'e'})
eq({'e', 'a', 'b', 'c', 'd'}, get_lines(0, -1, true))
end)
@@ -392,7 +392,7 @@ describe('api/buf', function()
end)
end)
- describe('nvim_buf_get_lines, nvim_buf_set_text', function()
+ describe('nvim_buf_set_text', function()
local get_lines, set_text = curbufmeths.get_lines, curbufmeths.set_text
it('works', function()
@@ -423,6 +423,17 @@ describe('api/buf', function()
-- will join multiple lines if needed
set_text(0, 6, 3, 4, {'bar'})
eq({'hello bar'}, get_lines(0, 1, true))
+
+ -- can use negative line numbers
+ set_text(-2, 0, -2, 5, {'goodbye'})
+ eq({'goodbye bar', ''}, get_lines(0, -1, true))
+
+ set_text(-1, 0, -1, 0, {'text'})
+ eq({'goodbye bar', 'text'}, get_lines(0, 2, true))
+
+ -- can append to a line
+ set_text(1, 4, -1, 4, {' and', 'more'})
+ eq({'goodbye bar', 'text and', 'more'}, get_lines(0, 3, true))
end)
it('works with undo', function()
@@ -506,12 +517,12 @@ describe('api/buf', function()
eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id2, {}))
eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id3, {}))
- -- marks should be shifted over by the correct number of bytes for multibyte
- -- chars
- set_text(0, 0, 0, 0, {'Ø'})
- eq({0, 3}, curbufmeths.get_extmark_by_id(ns, id1, {}))
- eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id2, {}))
- eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id3, {}))
+ -- marks should be shifted over by the correct number of bytes for multibyte
+ -- chars
+ set_text(0, 0, 0, 0, {'Ø'})
+ eq({0, 3}, curbufmeths.get_extmark_by_id(ns, id1, {}))
+ eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id2, {}))
+ eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id3, {}))
end)
it("correctly marks changed region for redraw #13890", function()
@@ -533,7 +544,60 @@ describe('api/buf', function()
|
]])
+ end)
+
+ it('errors on out-of-range', function()
+ insert([[
+ hello foo!
+ text]])
+ eq('start_row out of bounds', pcall_err(set_text, 2, 0, 3, 0, {}))
+ eq('start_row out of bounds', pcall_err(set_text, -3, 0, 0, 0, {}))
+ eq('end_row out of bounds', pcall_err(set_text, 0, 0, 2, 0, {}))
+ eq('end_row out of bounds', pcall_err(set_text, 0, 0, -3, 0, {}))
+ eq('start_col out of bounds', pcall_err(set_text, 1, 5, 1, 5, {}))
+ eq('end_col out of bounds', pcall_err(set_text, 1, 0, 1, 5, {}))
+ end)
+ it('errors when start is greater than end', function()
+ insert([[
+ hello foo!
+ text]])
+ eq('start is higher than end', pcall_err(set_text, 1, 0, 0, 0, {}))
+ eq('start is higher than end', pcall_err(set_text, 0, 1, 0, 0, {}))
+ end)
+ end)
+
+ describe('nvim_buf_get_text', function()
+ local get_text = curbufmeths.get_text
+
+ before_each(function()
+ insert([[
+ hello foo!
+ text]])
+ end)
+
+ it('works', function()
+ eq({'hello'}, get_text(0, 0, 0, 5, {}))
+ eq({'hello foo!'}, get_text(0, 0, 0, 42, {}))
+ eq({'foo!'}, get_text(0, 6, 0, 10, {}))
+ eq({'foo!', 'tex'}, get_text(0, 6, 1, 3, {}))
+ eq({'foo!', 'tex'}, get_text(-2, 6, -1, 3, {}))
+ eq({''}, get_text(0, 18, 0, 20, {}))
+ eq({'ext'}, get_text(-1, 1, -1, 4, {}))
+ end)
+
+ it('errors on out-of-range', function()
+ eq('Index out of bounds', pcall_err(get_text, 2, 0, 3, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, -3, 0, 0, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, 0, 0, 2, 0, {}))
+ eq('Index out of bounds', pcall_err(get_text, 0, 0, -3, 0, {}))
+ -- no ml_get errors should happen #19017
+ eq('', meths.get_vvar('errmsg'))
+ end)
+
+ it('errors when start is greater than end', function()
+ eq('start is higher than end', pcall_err(get_text, 1, 0, 0, 0, {}))
+ eq('start_col must be less than end_col', pcall_err(get_text, 0, 1, 0, 0, {}))
end)
end)
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index c9c9be5406..3d257e9477 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -96,6 +96,8 @@ local function reopenwithfolds(b)
end
describe('API: buffer events:', function()
+ before_each(clear)
+
it('when lines are added', function()
local b, tick = editoriginal(true)
@@ -785,7 +787,8 @@ describe('API: buffer events:', function()
local function lines_subset(first, second)
for i = 1,#first do
- if first[i] ~= second[i] then
+ -- need to ignore trailing spaces
+ if first[i]:gsub(' +$', '') ~= second[i]:gsub(' +$', '') then
return false
end
end
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index 6c2c136edc..7eb7ee73f9 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -16,8 +16,8 @@ local feed = helpers.feed
local funcs = helpers.funcs
describe('nvim_get_commands', function()
- local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, script_id=0, }
- local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', range=NIL, register=false, script_id=0, }
+ local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', preview=false, range=NIL, register=false, keepscript=false, script_id=0, }
+ local cmd_dict2 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='pwd', name='Pwd', nargs='?', preview=false, range=NIL, register=false, keepscript=false, script_id=0, }
before_each(clear)
it('gets empty list if no commands were defined', function()
@@ -59,12 +59,13 @@ describe('nvim_get_commands', function()
end)
it('gets various command attributes', function()
- local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, script_id=0, }
- local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, script_id=1, }
- local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, script_id=2, }
- local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, script_id=3, }
- local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', range=NIL, register=true, script_id=4, }
+ local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', preview=false, range='10', register=false, keepscript=false, script_id=0, }
+ local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', preview=false, range=NIL, register=false, keepscript=false, script_id=1, }
+ local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', preview=false, range=NIL, register=false, keepscript=false, script_id=2, }
+ local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', preview=false, range=NIL, register=false, keepscript=false, script_id=3, }
+ local cmd4 = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R4_just_great()', name='Cmd4', nargs='0', preview=false, range=NIL, register=true, keepscript=false, script_id=4, }
source([[
+ let s:foo = 1
command -complete=custom,ListUsers -nargs=+ Finger !finger <args>
]])
eq({Finger=cmd1}, meths.get_commands({builtin=false}))
@@ -72,12 +73,18 @@ describe('nvim_get_commands', function()
eq({Finger=cmd1, TestCmd=cmd0}, meths.get_commands({builtin=false}))
source([[
+ function! s:foo() abort
+ endfunction
command -bang -nargs=* Cmd2 call <SID>foo(<q-args>)
]])
source([[
+ function! s:ohyeah() abort
+ endfunction
command -bar -nargs=0 Cmd3 call <SID>ohyeah()
]])
source([[
+ function! s:just_great() abort
+ endfunction
command -register Cmd4 call <SID>just_great()
]])
-- TODO(justinmk): Order is stable but undefined. Sort before return?
@@ -85,11 +92,11 @@ describe('nvim_get_commands', function()
end)
end)
-describe('nvim_add_user_command', function()
+describe('nvim_create_user_command', function()
before_each(clear)
it('works with strings', function()
- meths.add_user_command('SomeCommand', 'let g:command_fired = <args>', {nargs = 1})
+ meths.create_user_command('SomeCommand', 'let g:command_fired = <args>', {nargs = 1})
meths.command('SomeCommand 42')
eq(42, meths.eval('g:command_fired'))
end)
@@ -97,7 +104,7 @@ describe('nvim_add_user_command', function()
it('works with Lua functions', function()
exec_lua [[
result = {}
- vim.api.nvim_add_user_command('CommandWithLuaCallback', function(opts)
+ vim.api.nvim_create_user_command('CommandWithLuaCallback', function(opts)
result = opts
end, {
nargs = "*",
@@ -107,51 +114,267 @@ describe('nvim_add_user_command', function()
]]
eq({
- args = "hello",
+ args = [[this is a\ test]],
+ fargs = {"this", "is", "a test"},
bang = false,
line1 = 1,
line2 = 1,
mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
range = 0,
count = 2,
reg = "",
- }, exec_lua [[
- vim.api.nvim_command('CommandWithLuaCallback hello')
+ }, exec_lua [=[
+ vim.api.nvim_command([[CommandWithLuaCallback this is a\ test]])
return result
- ]])
+ ]=])
eq({
- args = "",
+ args = [[this includes\ a backslash: \\]],
+ fargs = {"this", "includes a", "backslash:", "\\"},
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [=[
+ vim.api.nvim_command([[CommandWithLuaCallback this includes\ a backslash: \\]])
+ return result
+ ]=])
+
+ eq({
+ args = "a\\b",
+ fargs = {"a\\b"},
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [=[
+ vim.api.nvim_command('CommandWithLuaCallback a\\b')
+ return result
+ ]=])
+
+ eq({
+ args = 'h\tey ',
+ fargs = {[[h]], [[ey]]},
bang = true,
line1 = 10,
line2 = 10,
- mods = "botright",
+ mods = "confirm unsilent botright",
+ smods = {
+ browse = false,
+ confirm = true,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "botright",
+ tab = 0,
+ unsilent = true,
+ verbose = -1,
+ vertical = false,
+ },
range = 1,
count = 10,
reg = "",
- }, exec_lua [[
- vim.api.nvim_command('botright 10CommandWithLuaCallback!')
+ }, exec_lua [=[
+ vim.api.nvim_command('unsilent botright confirm 10CommandWithLuaCallback! h\tey ')
return result
- ]])
+ ]=])
eq({
- args = "",
+ args = "h",
+ fargs = {"h"},
bang = false,
line1 = 1,
line2 = 42,
mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
range = 1,
count = 42,
reg = "",
}, exec_lua [[
- vim.api.nvim_command('CommandWithLuaCallback 42')
+ vim.api.nvim_command('CommandWithLuaCallback 42 h')
return result
]])
+
+ eq({
+ args = "",
+ fargs = {}, -- fargs works without args
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithLuaCallback')
+ return result
+ ]])
+
+ -- f-args doesn't split when command nargs is 1 or "?"
+ exec_lua [[
+ result = {}
+ vim.api.nvim_create_user_command('CommandWithOneArg', function(opts)
+ result = opts
+ end, {
+ nargs = "?",
+ bang = true,
+ count = 2,
+ })
+ ]]
+
+ eq({
+ args = "hello I'm one argument",
+ fargs = {"hello I'm one argument"}, -- Doesn't split args
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ smods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithOneArg hello I\'m one argument')
+ return result
+ ]])
+
end)
it('can define buffer-local commands', function()
local bufnr = meths.create_buf(false, false)
- bufmeths.add_user_command(bufnr, "Hello", "", {})
+ bufmeths.create_user_command(bufnr, "Hello", "", {})
matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
meths.set_current_buf(bufnr)
meths.command("Hello")
@@ -160,7 +383,7 @@ describe('nvim_add_user_command', function()
it('can use a Lua complete function', function()
exec_lua [[
- vim.api.nvim_add_user_command('Test', '', {
+ vim.api.nvim_create_user_command('Test', '', {
nargs = "*",
complete = function(arg, cmdline, pos)
local options = {"aaa", "bbb", "ccc"}
@@ -180,20 +403,52 @@ describe('nvim_add_user_command', function()
feed('<C-U>Test b<Tab>')
eq('Test bbb', funcs.getcmdline())
end)
+
+ it('does not allow invalid command names', function()
+ matches("'name' must begin with an uppercase letter", pcall_err(exec_lua, [[
+ vim.api.nvim_create_user_command('test', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_create_user_command('t@', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_create_user_command('T@st', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_create_user_command('Test!', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_create_user_command('💩', 'echo "hi"', {})
+ ]]))
+ end)
+
+ it('smods can be used with nvim_cmd', function()
+ exec_lua[[
+ vim.api.nvim_create_user_command('MyEcho', function(opts)
+ vim.api.nvim_cmd({ cmd = 'echo', args = { '&verbose' }, mods = opts.smods }, {})
+ end, {})
+ ]]
+
+ eq("3", meths.cmd({ cmd = 'MyEcho', mods = { verbose = 3 } }, { output = true }))
+ end)
end)
describe('nvim_del_user_command', function()
before_each(clear)
it('can delete global commands', function()
- meths.add_user_command('Hello', 'echo "Hi"', {})
+ meths.create_user_command('Hello', 'echo "Hi"', {})
meths.command('Hello')
meths.del_user_command('Hello')
matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
end)
it('can delete buffer-local commands', function()
- bufmeths.add_user_command(0, 'Hello', 'echo "Hi"', {})
+ bufmeths.create_user_command(0, 'Hello', 'echo "Hi"', {})
meths.command('Hello')
bufmeths.del_user_command(0, 'Hello')
matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index a8f538b951..bc8d811c6d 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -110,6 +110,22 @@ describe('API/extmarks', function()
pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 }))
end)
+ it("can end extranges past final newline when strict mode is false", function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 1,
+ end_row = 1,
+ strict = false,
+ })
+ end)
+
+ it("can end extranges past final column when strict mode is false", function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 6,
+ end_row = 0,
+ strict = false,
+ })
+ end)
+
it('adds, updates and deletes marks', function()
local rv = set_extmark(ns, marks[1], positions[1][1], positions[1][2])
eq(marks[1], rv)
@@ -908,7 +924,7 @@ describe('API/extmarks', function()
eq(3, set_extmark(ns, 3, positions[2][1], positions[2][2]))
eq(4, set_extmark(ns, 0, positions[1][1], positions[1][2]))
- -- mixing manual and allocated id:s are not recommened, but it should
+ -- mixing manual and allocated id:s are not recommended, but it should
-- do something reasonable
eq(6, set_extmark(ns, 6, positions[2][1], positions[2][2]))
eq(7, set_extmark(ns, 0, positions[1][1], positions[1][2]))
@@ -1430,7 +1446,60 @@ describe('API/extmarks', function()
end_col = 0,
end_line = 1
})
- eq({ {1, 0, 0, { end_col = 0, end_row = 1 }} }, get_extmarks(ns, 0, -1, {details=true}))
+ eq({ {1, 0, 0, {
+ end_col = 0,
+ end_row = 1,
+ right_gravity = true,
+ end_right_gravity = false,
+ }} }, get_extmarks(ns, 0, -1, {details=true}))
+ end)
+
+ it('can get details', function()
+ set_extmark(ns, marks[1], 0, 0, {
+ end_col = 0,
+ end_row = 1,
+ right_gravity = false,
+ end_right_gravity = true,
+ priority = 0,
+ hl_eol = true,
+ hl_mode = "blend",
+ hl_group = "String",
+ virt_text = { { "text", "Statement" } },
+ virt_text_pos = "right_align",
+ virt_text_hide = true,
+ virt_lines = { { { "lines", "Statement" } }},
+ virt_lines_above = true,
+ virt_lines_leftcol = true,
+ })
+ set_extmark(ns, marks[2], 0, 0, {
+ priority = 0,
+ virt_text = { { "text", "Statement" } },
+ virt_text_win_col = 1,
+ })
+ eq({0, 0, {
+ end_col = 0,
+ end_row = 1,
+ right_gravity = false,
+ end_right_gravity = true,
+ priority = 0,
+ hl_eol = true,
+ hl_mode = "blend",
+ hl_group = "String",
+ virt_text = { { "text", "Statement" } },
+ virt_text_pos = "right_align",
+ virt_text_hide = true,
+ virt_lines = { { { "lines", "Statement" } }},
+ virt_lines_above = true,
+ virt_lines_leftcol = true,
+ } }, get_extmark_by_id(ns, marks[1], { details = true }))
+ eq({0, 0, {
+ right_gravity = true,
+ priority = 0,
+ virt_text = { { "text", "Statement" } },
+ virt_text_hide = false,
+ virt_text_pos = "win_col",
+ virt_text_win_col = 1,
+ } }, get_extmark_by_id(ns, marks[2], { details = true }))
end)
end)
@@ -1537,3 +1606,209 @@ describe('Extmarks buffer api with many marks', function()
eq({}, get_marks(ns2))
end)
end)
+
+describe('API/win_extmark', function()
+ local screen
+ local marks, line1, line2
+ local ns
+
+ before_each(function()
+ -- Initialize some namespaces and insert text into a buffer
+ marks = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
+
+ line1 = "non ui-watched line"
+ line2 = "ui-watched line"
+
+ clear()
+
+ insert(line1)
+ feed("o<esc>")
+ insert(line2)
+ ns = request('nvim_create_namespace', "extmark-ui")
+ end)
+
+ it('sends and only sends ui-watched marks to ui', function()
+ screen = Screen.new(20, 4)
+ screen:attach()
+ -- should send this
+ set_extmark(ns, marks[1], 1, 0, { ui_watched = true })
+ -- should not send this
+ set_extmark(ns, marks[2], 0, 0, { ui_watched = false })
+ screen:expect({
+ grid = [[
+ non ui-watched line |
+ ui-watched lin^e |
+ ~ |
+ |
+ ]],
+ extmarks = {
+ [2] = {
+ -- positioned at the end of the 2nd line
+ { {id = 1000}, 1, 1, 1, 16 },
+ }
+ },
+ })
+ end)
+
+ it('sends multiple ui-watched marks to ui', function()
+ screen = Screen.new(20, 4)
+ screen:attach()
+ -- should send all of these
+ set_extmark(ns, marks[1], 1, 0, { ui_watched = true, virt_text_pos = "overlay" })
+ set_extmark(ns, marks[2], 1, 2, { ui_watched = true, virt_text_pos = "overlay" })
+ set_extmark(ns, marks[3], 1, 4, { ui_watched = true, virt_text_pos = "overlay" })
+ set_extmark(ns, marks[4], 1, 6, { ui_watched = true, virt_text_pos = "overlay" })
+ set_extmark(ns, marks[5], 1, 8, { ui_watched = true })
+ screen:expect({
+ grid = [[
+ non ui-watched line |
+ ui-watched lin^e |
+ ~ |
+ |
+ ]],
+ extmarks = {
+ [2] = {
+ -- earlier notifications
+ { {id = 1000}, 1, 1, 1, 0 },
+ { {id = 1000}, 1, 1, 1, 0 }, { {id = 1000}, 1, 2, 1, 2 },
+ { {id = 1000}, 1, 1, 1, 0 }, { {id = 1000}, 1, 2, 1, 2 }, { {id = 1000}, 1, 3, 1, 4 },
+ { {id = 1000}, 1, 1, 1, 0 }, { {id = 1000}, 1, 2, 1, 2 }, { {id = 1000}, 1, 3, 1, 4 }, { {id = 1000}, 1, 4, 1, 6 },
+ -- final
+ -- overlay
+ { {id = 1000}, 1, 1, 1, 0 },
+ { {id = 1000}, 1, 2, 1, 2 },
+ { {id = 1000}, 1, 3, 1, 4 },
+ { {id = 1000}, 1, 4, 1, 6 },
+ -- eol
+ { {id = 1000}, 1, 5, 1, 16 },
+ }
+ },
+ })
+ end)
+
+ it('updates ui-watched marks', function()
+ screen = Screen.new(20, 4)
+ screen:attach()
+ -- should send this
+ set_extmark(ns, marks[1], 1, 0, { ui_watched = true })
+ -- should not send this
+ set_extmark(ns, marks[2], 0, 0, { ui_watched = false })
+ -- make some changes
+ insert(" update")
+ screen:expect({
+ grid = [[
+ non ui-watched line |
+ ui-watched linupdat^e|
+ e |
+ |
+ ]],
+ extmarks = {
+ [2] = {
+ -- positioned at the end of the 2nd line
+ { {id = 1000}, 1, 1, 1, 16 },
+ -- updated and wrapped to 3rd line
+ { {id = 1000}, 1, 1, 2, 2 },
+ }
+ }
+ })
+ feed("<c-e>")
+ screen:expect({
+ grid = [[
+ ui-watched linupdat^e|
+ e |
+ ~ |
+ |
+ ]],
+ extmarks = {
+ [2] = {
+ -- positioned at the end of the 2nd line
+ { {id = 1000}, 1, 1, 1, 16 },
+ -- updated and wrapped to 3rd line
+ { {id = 1000}, 1, 1, 2, 2 },
+ -- scrolled up one line, should be handled by grid scroll
+ }
+ }
+ })
+ end)
+
+ it('sends ui-watched to splits', function()
+ screen = Screen.new(20, 8)
+ screen:attach({ext_multigrid=true})
+ -- should send this
+ set_extmark(ns, marks[1], 1, 0, { ui_watched = true })
+ -- should not send this
+ set_extmark(ns, marks[2], 0, 0, { ui_watched = false })
+ command('split')
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [4:--------------------]|
+ [4:--------------------]|
+ [4:--------------------]|
+ [No Name] [+] |
+ [2:--------------------]|
+ [2:--------------------]|
+ [No Name] [+] |
+ [3:--------------------]|
+ ## grid 2
+ non ui-watched line |
+ ui-watched line |
+ ## grid 3
+ |
+ ## grid 4
+ non ui-watched line |
+ ui-watched lin^e |
+ ~ |
+ ]],
+ extmarks = {
+ [2] = {
+ -- positioned at the end of the 2nd line
+ { {id = 1000}, 1, 1, 1, 16 },
+ -- updated after split
+ { {id = 1000}, 1, 1, 1, 16 },
+ },
+ [4] = {
+ -- only after split
+ { {id = 1001}, 1, 1, 1, 16 },
+ }
+ }
+ })
+ -- make some changes
+ insert(" update")
+ screen:expect({
+ grid = [[
+ ## grid 1
+ [4:--------------------]|
+ [4:--------------------]|
+ [4:--------------------]|
+ [No Name] [+] |
+ [2:--------------------]|
+ [2:--------------------]|
+ [No Name] [+] |
+ [3:--------------------]|
+ ## grid 2
+ non ui-watched line |
+ ui-watched linupd@@@|
+ ## grid 3
+ |
+ ## grid 4
+ non ui-watched line |
+ ui-watched linupdat^e|
+ e |
+ ]],
+ extmarks = {
+ [2] = {
+ -- positioned at the end of the 2nd line
+ { {id = 1000}, 1, 1, 1, 16 },
+ -- updated after split
+ { {id = 1000}, 1, 1, 1, 16 },
+ },
+ [4] = {
+ { {id = 1001}, 1, 1, 1, 16 },
+ -- updated
+ { {id = 1001}, 1, 1, 2, 2 },
+ }
+ }
+ })
+ end)
+end)
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 21e3094f8e..933103046c 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -3,6 +3,7 @@ local clear, nvim = helpers.clear, helpers.nvim
local Screen = require('test.functional.ui.screen')
local eq, eval = helpers.eq, helpers.eval
local command = helpers.command
+local exec_capture = helpers.exec_capture
local meths = helpers.meths
local funcs = helpers.funcs
local pcall_err = helpers.pcall_err
@@ -27,8 +28,11 @@ describe('API: highlight',function()
bold = true,
italic = true,
reverse = true,
- undercurl = true,
underline = true,
+ undercurl = true,
+ underdouble = true,
+ underdotted = true,
+ underdashed = true,
strikethrough = true,
}
@@ -51,7 +55,7 @@ describe('API: highlight',function()
eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*'))
-- Test all highlight properties.
- command('hi NewHighlight gui=underline,bold,undercurl,italic,reverse,strikethrough')
+ command('hi NewHighlight gui=underline,bold,undercurl,underdouble,underdotted,underdashed,italic,reverse,strikethrough')
eq(expected_rgb2, nvim("get_hl_by_id", hl_id, true))
-- Test nil argument.
@@ -129,6 +133,13 @@ describe('API: highlight',function()
eq({ underline = true, standout = true, },
meths.get_hl_by_name('cursorline', 0));
+ -- Test cterm & Normal values. #18024 (tail) & #18980
+ -- Ensure Normal, and groups that match Normal return their fg & bg cterm values
+ meths.set_hl(0, 'Normal', {ctermfg = 17, ctermbg = 213})
+ meths.set_hl(0, 'NotNormal', {ctermfg = 17, ctermbg = 213})
+ -- Note colors are "cterm" values, not rgb-as-ints
+ eq({foreground = 17, background = 213}, nvim("get_hl_by_name", 'Normal', false))
+ eq({foreground = 17, background = 213}, nvim("get_hl_by_name", 'NotNormal', false))
end)
it('nvim_get_hl_id_by_name', function()
@@ -194,10 +205,15 @@ describe("API: set highlight", function()
reverse = true,
undercurl = true,
underline = true,
+ underdashed = true,
+ underdotted = true,
+ underdouble = true,
+ strikethrough = true,
cterm = {
italic = true,
reverse = true,
undercurl = true,
+ strikethrough = true,
}
}
local highlight3_result_gui = {
@@ -208,6 +224,10 @@ describe("API: set highlight", function()
reverse = true,
undercurl = true,
underline = true,
+ underdashed = true,
+ underdotted = true,
+ underdouble = true,
+ strikethrough = true,
}
local highlight3_result_cterm = {
background = highlight_color.ctermbg,
@@ -215,6 +235,7 @@ describe("API: set highlight", function()
italic = true,
reverse = true,
undercurl = true,
+ strikethrough = true,
}
local function get_ns()
@@ -237,6 +258,12 @@ describe("API: set highlight", function()
eq(highlight2_result, meths.get_hl_by_name('Test_hl', false))
end)
+ it ("can set empty cterm attr", function()
+ local ns = get_ns()
+ meths.set_hl(ns, 'Test_hl', { cterm = {} })
+ eq({}, meths.get_hl_by_name('Test_hl', false))
+ end)
+
it ("cterm attr defaults to gui attr", function()
local ns = get_ns()
meths.set_hl(ns, 'Test_hl', highlight1)
@@ -252,4 +279,76 @@ describe("API: set highlight", function()
eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true))
eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false))
end)
+
+ it ("can set a highlight in the global namespace", function()
+ meths.set_hl(0, 'Test_hl', highlight2_config)
+ eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse',
+ exec_capture('highlight Test_hl'))
+
+ meths.set_hl(0, 'Test_hl', { background = highlight_color.bg })
+ eq('Test_hl xxx guibg=#0032aa',
+ exec_capture('highlight Test_hl'))
+
+ meths.set_hl(0, 'Test_hl2', highlight3_config)
+ eq('Test_hl2 xxx cterm=undercurl,italic,reverse,strikethrough ctermfg=8 ctermbg=15 gui=bold,underline,undercurl,underdouble,underdotted,underdashed,italic,reverse,strikethrough guifg=#ff0000 guibg=#0032aa',
+ exec_capture('highlight Test_hl2'))
+
+ -- Colors are stored with the name they are defined, but
+ -- with canonical casing
+ meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue'})
+ eq('Test_hl3 xxx guifg=Blue guibg=Red',
+ exec_capture('highlight Test_hl3'))
+ end)
+
+ it ("can modify a highlight in the global namespace", function()
+ meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'})
+ eq('Test_hl3 xxx guifg=Blue guibg=Red',
+ exec_capture('highlight Test_hl3'))
+
+ meths.set_hl(0, 'Test_hl3', { bg = 'red' })
+ eq('Test_hl3 xxx guibg=Red',
+ exec_capture('highlight Test_hl3'))
+
+ meths.set_hl(0, 'Test_hl3', { ctermbg = 9, ctermfg = 12})
+ eq('Test_hl3 xxx ctermfg=12 ctermbg=9',
+ exec_capture('highlight Test_hl3'))
+
+ meths.set_hl(0, 'Test_hl3', { ctermbg = 'red' , ctermfg = 'blue'})
+ eq('Test_hl3 xxx ctermfg=12 ctermbg=9',
+ exec_capture('highlight Test_hl3'))
+
+ meths.set_hl(0, 'Test_hl3', { ctermbg = 9 })
+ eq('Test_hl3 xxx ctermbg=9',
+ exec_capture('highlight Test_hl3'))
+
+ eq("'redd' is not a valid color",
+ pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'}))
+
+ eq("'bleu' is not a valid color",
+ pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'}))
+
+ meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'})
+ eq('Test_hl3 xxx guifg=#ff00ff',
+ exec_capture('highlight Test_hl3'))
+
+ eq("'#FF00FF' is not a valid color",
+ pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'}))
+
+ for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do
+ meths.set_hl(0, 'Test_hl3', {fg = fg_val})
+ eq('Test_hl3 xxx cleared',
+ exec_capture('highlight Test_hl3'))
+ end
+
+ meths.set_hl(0, 'Test_hl3', {fg='#FF00FF', blend=50})
+ eq('Test_hl3 xxx guifg=#ff00ff blend=50',
+ exec_capture('highlight Test_hl3'))
+
+ end)
+
+ it ("correctly sets 'Normal' internal properties", function()
+ -- Normal has some special handling internally. #18024
+ meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'})
+ eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true))
+ end)
end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 450a76ddac..6bc6651e04 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -15,6 +15,9 @@ local pcall_err = helpers.pcall_err
local shallowcopy = helpers.shallowcopy
local sleep = helpers.sleep
+local sid_api_client = -9
+local sid_lua = -8
+
describe('nvim_get_keymap', function()
before_each(clear)
@@ -318,7 +321,7 @@ describe('nvim_get_keymap', function()
eq({space_table}, meths.get_keymap('n'))
end)
- it('can handle lua keymaps', function()
+ it('can handle lua mappings', function()
eq(0, exec_lua [[
GlobalCount = 0
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
@@ -333,14 +336,14 @@ describe('nvim_get_keymap', function()
return GlobalCount
]])
local mapargs = meths.get_keymap('n')
- assert.Truthy(type(mapargs[1].callback) == 'number', 'callback is not luaref number')
+ assert(type(mapargs[1].callback) == 'number', 'callback is not luaref number')
mapargs[1].callback = nil
eq({
lhs='asdf',
script=0,
silent=0,
expr=0,
- sid=0,
+ sid=sid_lua,
buffer=0,
nowait=0,
mode='n',
@@ -357,7 +360,7 @@ describe('nvim_get_keymap', function()
script=0,
silent=0,
expr=0,
- sid=0,
+ sid=sid_api_client,
buffer=0,
nowait=0,
mode='n',
@@ -400,7 +403,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.silent = not opts.silent and 0 or 1
to_return.nowait = not opts.nowait and 0 or 1
to_return.expr = not opts.expr and 0 or 1
- to_return.sid = not opts.sid and 0 or opts.sid
+ to_return.sid = not opts.sid and sid_api_client or opts.sid
to_return.buffer = not opts.buffer and 0 or opts.buffer
to_return.lnum = not opts.lnum and 0 or opts.lnum
to_return.desc = opts.desc
@@ -579,7 +582,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
it('can set mappings containing literal keycodes', function()
meths.set_keymap('n', '\n\r\n', 'rhs', {})
local expected = generate_mapargs('n', '<NL><CR><NL>', 'rhs')
- eq(expected, get_mapargs('n', '<C-j><CR><C-j>'))
+ eq(expected, get_mapargs('n', '<NL><CR><NL>'))
end)
it('can set mappings whose RHS is a <Nop>', function()
@@ -603,6 +606,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq({''}, curbufmeths.get_lines(0, -1, 0))
eq(generate_mapargs('i', 'lhs', '<NOP>', {}),
get_mapargs('i', 'lhs'))
+
+ -- a single ^V in RHS is also <Nop> (see :h map-empty-rhs)
+ meths.set_keymap('i', 'lhs', '\022', {})
+ command('normal ilhs')
+ eq({''}, curbufmeths.get_lines(0, -1, 0))
+ eq(generate_mapargs('i', 'lhs', '\022', {}),
+ get_mapargs('i', 'lhs'))
end)
it('treats an empty RHS in a mapping like a <Nop>', function()
@@ -625,7 +635,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
it('interprets control sequences in expr-quotes correctly when called '
..'inside vim', function()
command([[call nvim_set_keymap('i', "\<space>", "\<tab>", {})]])
- eq(generate_mapargs('i', '<Space>', '\t', {}),
+ eq(generate_mapargs('i', '<Space>', '\t', {sid=0}),
get_mapargs('i', '<Space>'))
feed('i ')
eq({'\t'}, curbufmeths.get_lines(0, -1, 0))
@@ -782,7 +792,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end)
- it (':map command shows lua keymap correctly', function()
+ it (':map command shows lua mapping correctly', function()
exec_lua [[
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
]]
@@ -790,7 +800,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
"^\nn asdf <Lua function %d+>"))
end)
- it ('mapcheck() returns lua keymap correctly', function()
+ it ('mapcheck() returns lua mapping correctly', function()
exec_lua [[
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
]]
@@ -798,16 +808,16 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
"^<Lua function %d+>"))
end)
- it ('maparg() returns lua keymap correctly', function()
+ it ('maparg() returns lua mapping correctly', function()
exec_lua [[
vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
]]
assert.truthy(string.match(funcs.maparg('asdf', 'n'),
"^<Lua function %d+>"))
local mapargs = funcs.maparg('asdf', 'n', false, true)
- assert.Truthy(type(mapargs.callback) == 'number', 'callback is not luaref number')
+ assert(type(mapargs.callback) == 'number', 'callback is not luaref number')
mapargs.callback = nil
- eq(generate_mapargs('n', 'asdf', nil, {}), mapargs)
+ eq(generate_mapargs('n', 'asdf', nil, {sid=sid_lua}), mapargs)
end)
it('can make lua expr mappings', function()
@@ -871,7 +881,28 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
end)
- it('can set descriptions on keymaps', function()
+ it('no double-free when unmapping simplifiable lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap('n', '<C-I>', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('<C-I>\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_del_keymap('n', '<C-I>')
+ ]]
+
+ feed('<C-I>\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap <C-I>'))
+ end)
+
+ it('can set descriptions on mappings', function()
meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
eq(generate_mapargs('n', 'lhs', 'rhs', {desc="map description"}), get_mapargs('n', 'lhs'))
eq("\nn lhs rhs\n map description",
@@ -1037,4 +1068,25 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
eq(1, exec_lua[[return GlobalCount]])
eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
end)
+
+ it('no double-free when unmapping simplifiable lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap(0, 'n', '<C-I>', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('<C-I>\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_buf_del_keymap(0, 'n', '<C-I>')
+ ]]
+
+ feed('<C-I>\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap <C-I>'))
+ end)
end)
diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua
index d828bdf948..0fbf58a8e7 100644
--- a/test/functional/api/proc_spec.lua
+++ b/test/functional/api/proc_spec.lua
@@ -63,9 +63,9 @@ describe('API', function()
local pid = funcs.getpid()
local pinfo = request('nvim_get_proc', pid)
eq((iswin() and 'nvim.exe' or 'nvim'), pinfo.name)
- eq(pinfo.pid, pid)
- eq(type(pinfo.ppid), 'number')
- neq(pinfo.ppid, pid)
+ eq(pid, pinfo.pid)
+ eq('number', type(pinfo.ppid))
+ neq(pid, pinfo.ppid)
end)
it('validates input', function()
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 309d9084c8..00a4dd041d 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -170,7 +170,7 @@ describe('server -> client', function()
if method == "notification" then
eq('done!', eval('rpcrequest('..cid..', "nested")'))
elseif method == "nested_done" then
- ok(false, 'this should never have been sent')
+ ok(false, 'never sent', 'sent')
end
end
@@ -181,12 +181,6 @@ describe('server -> client', function()
end)
describe('recursive (child) nvim client', function()
- if helpers.isCI('travis') and helpers.is_os('mac') then
- -- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
- pending("[Hangs on Travis macOS. #5002]", function() end)
- return
- end
-
before_each(function()
command("let vim = rpcstart('"..nvim_prog.."', ['-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--embed', '--headless'])")
neq(0, eval('vim'))
diff --git a/test/functional/api/version_spec.lua b/test/functional/api/version_spec.lua
index bf67d4788b..771192e9ab 100644
--- a/test/functional/api/version_spec.lua
+++ b/test/functional/api/version_spec.lua
@@ -33,9 +33,11 @@ describe("api_info()['version']", function()
local major = version['major']
local minor = version['minor']
local patch = version['patch']
+ local prerelease = version['prerelease']
eq("number", type(major))
eq("number", type(minor))
eq("number", type(patch))
+ eq("boolean", type(prerelease))
eq(1, funcs.has("nvim-"..major.."."..minor.."."..patch))
eq(0, funcs.has("nvim-"..major.."."..minor.."."..(patch + 1)))
eq(0, funcs.has("nvim-"..major.."."..(minor + 1).."."..patch))
@@ -91,6 +93,7 @@ describe("api metadata", function()
local api, compat, stable, api_level
local old_api = {}
setup(function()
+ clear() -- Ensure a session before requesting api_info.
api = meths.get_api_info()[2]
compat = api.version.api_compatible
api_level = api.version.api_level
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 22201e21a2..3724dbf820 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1,11 +1,13 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local lfs = require('lfs')
local fmt = string.format
local assert_alive = helpers.assert_alive
local NIL = helpers.NIL
local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq
local command = helpers.command
+local exec = helpers.exec
local eval = helpers.eval
local expect = helpers.expect
local funcs = helpers.funcs
@@ -23,6 +25,9 @@ local next_msg = helpers.next_msg
local tmpname = helpers.tmpname
local write_file = helpers.write_file
local exec_lua = helpers.exec_lua
+local exc_exec = helpers.exc_exec
+local insert = helpers.insert
+local expect_exit = helpers.expect_exit
local pcall_err = helpers.pcall_err
local format_string = helpers.format_string
@@ -120,9 +125,9 @@ describe('API', function()
-- Functions
nvim('exec', 'function Foo()\ncall setline(1,["xxx"])\nendfunction', false)
- eq(nvim('get_current_line'), '')
+ eq('', nvim('get_current_line'))
nvim('exec', 'call Foo()', false)
- eq(nvim('get_current_line'), 'xxx')
+ eq('xxx', nvim('get_current_line'))
-- Autocmds
nvim('exec','autocmd BufAdd * :let x1 = "Hello"', false)
@@ -333,6 +338,7 @@ describe('API', function()
describe('nvim_command_output', function()
it('does not induce hit-enter prompt', function()
+ nvim("ui_attach", 80, 20, {})
-- Induce a hit-enter prompt use nvim_input (non-blocking).
nvim('command', 'set cmdheight=1')
nvim('input', [[:echo "hi\nhi2"<CR>]])
@@ -535,6 +541,31 @@ describe('API', function()
end)
end)
+ describe('nvim_set_current_dir', function()
+ local start_dir
+
+ before_each(function()
+ clear()
+ funcs.mkdir("Xtestdir")
+ start_dir = funcs.getcwd()
+ end)
+
+ after_each(function()
+ helpers.rmdir("Xtestdir")
+ end)
+
+ it('works', function()
+ meths.set_current_dir("Xtestdir")
+ eq(funcs.getcwd(), start_dir .. helpers.get_pathsep() .. "Xtestdir")
+ end)
+
+ it('sets previous directory', function()
+ meths.set_current_dir("Xtestdir")
+ meths.exec('cd -', false)
+ eq(funcs.getcwd(), start_dir)
+ end)
+ end)
+
describe('nvim_exec_lua', function()
it('works', function()
meths.exec_lua('vim.api.nvim_set_var("test", 3)', {})
@@ -609,34 +640,374 @@ describe('API', function()
eq('Invalid phase: 4',
pcall_err(request, 'nvim_paste', 'foo', true, 4))
end)
- it('stream: multiple chunks form one undo-block', function()
- nvim('paste', '1/chunk 1 (start)\n', true, 1)
- nvim('paste', '1/chunk 2 (end)\n', true, 3)
- local expected1 = [[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- ]]
- expect(expected1)
- nvim('paste', '2/chunk 1 (start)\n', true, 1)
- nvim('paste', '2/chunk 2\n', true, 2)
- expect([[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- 2/chunk 1 (start)
- 2/chunk 2
- ]])
- nvim('paste', '2/chunk 3\n', true, 2)
- nvim('paste', '2/chunk 4 (end)\n', true, 3)
- expect([[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- 2/chunk 1 (start)
- 2/chunk 2
- 2/chunk 3
- 2/chunk 4 (end)
- ]])
- feed('u') -- Undo.
- expect(expected1)
+ local function run_streamed_paste_tests()
+ it('stream: multiple chunks form one undo-block', function()
+ nvim('paste', '1/chunk 1 (start)\n', true, 1)
+ nvim('paste', '1/chunk 2 (end)\n', true, 3)
+ local expected1 = [[
+ 1/chunk 1 (start)
+ 1/chunk 2 (end)
+ ]]
+ expect(expected1)
+ nvim('paste', '2/chunk 1 (start)\n', true, 1)
+ nvim('paste', '2/chunk 2\n', true, 2)
+ expect([[
+ 1/chunk 1 (start)
+ 1/chunk 2 (end)
+ 2/chunk 1 (start)
+ 2/chunk 2
+ ]])
+ nvim('paste', '2/chunk 3\n', true, 2)
+ nvim('paste', '2/chunk 4 (end)\n', true, 3)
+ expect([[
+ 1/chunk 1 (start)
+ 1/chunk 2 (end)
+ 2/chunk 1 (start)
+ 2/chunk 2
+ 2/chunk 3
+ 2/chunk 4 (end)
+ ]])
+ feed('u') -- Undo.
+ expect(expected1)
+ end)
+ it('stream: Insert mode', function()
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('i')
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('aaaaaabbbbbbccccccdddddd')
+ feed('<Esc>u')
+ expect('')
+ end)
+ describe('stream: Normal mode', function()
+ describe('on empty line', function()
+ before_each(function()
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ end)
+ after_each(function()
+ feed('u')
+ expect('')
+ end)
+ it('pasting one line', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('aaaaaabbbbbbccccccdddddd')
+ end)
+ it('pasting multiple lines', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ end)
+ describe('not at the end of a line', function()
+ before_each(function()
+ feed('i||<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('0')
+ end)
+ after_each(function()
+ feed('u')
+ expect('||')
+ end)
+ it('pasting one line', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('|aaaaaabbbbbbccccccdddddd|')
+ end)
+ it('pasting multiple lines', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ |aaaaaa
+ bbbbbb
+ cccccc
+ dddddd|]])
+ end)
+ end)
+ describe('at the end of a line', function()
+ before_each(function()
+ feed('i||<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('2|')
+ end)
+ after_each(function()
+ feed('u')
+ expect('||')
+ end)
+ it('pasting one line', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||aaaaaabbbbbbccccccdddddd')
+ end)
+ it('pasting multiple lines', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ ||aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ end)
+ end)
+ describe('stream: Visual mode', function()
+ describe('neither end at the end of a line', function()
+ before_each(function()
+ feed('i|xxx<CR>xxx|<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('3|vhk')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ |xxx
+ xxx|]])
+ end)
+ it('with non-empty chunks', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('|aaaaaabbbbbbccccccdddddd|')
+ end)
+ it('with empty first chunk', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('|bbbbbbccccccdddddd|')
+ end)
+ it('with all chunks empty', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', '', false, 2)
+ nvim('paste', '', false, 2)
+ nvim('paste', '', false, 3)
+ expect('||')
+ end)
+ end)
+ describe('cursor at the end of a line', function()
+ before_each(function()
+ feed('i||xxx<CR>xxx<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('3|vko')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ ||xxx
+ xxx]])
+ end)
+ it('with non-empty chunks', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||aaaaaabbbbbbccccccdddddd')
+ end)
+ it('with empty first chunk', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||bbbbbbccccccdddddd')
+ end)
+ end)
+ describe('other end at the end of a line', function()
+ before_each(function()
+ feed('i||xxx<CR>xxx<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ feed('3|vk')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ ||xxx
+ xxx]])
+ end)
+ it('with non-empty chunks', function()
+ nvim('paste', 'aaaaaa', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||aaaaaabbbbbbccccccdddddd')
+ end)
+ it('with empty first chunk', function()
+ nvim('paste', '', false, 1)
+ nvim('paste', 'bbbbbb', false, 2)
+ nvim('paste', 'cccccc', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect('||bbbbbbccccccdddddd')
+ end)
+ end)
+ end)
+ describe('stream: linewise Visual mode', function()
+ before_each(function()
+ feed('i123456789<CR>987654321<CR>123456789<Esc>')
+ -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
+ feed('afoo<Esc>u')
+ end)
+ after_each(function()
+ feed('u')
+ expect([[
+ 123456789
+ 987654321
+ 123456789]])
+ end)
+ describe('selecting the start of a file', function()
+ before_each(function()
+ feed('ggV')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd987654321
+ 123456789]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ 987654321
+ 123456789]])
+ end)
+ end)
+ describe('selecting the middle of a file', function()
+ before_each(function()
+ feed('2ggV')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ 123456789
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd123456789]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ 123456789
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ 123456789]])
+ end)
+ end)
+ describe('selecting the end of a file', function()
+ before_each(function()
+ feed('3ggV')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ 123456789
+ 987654321
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ 123456789
+ 987654321
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ ]])
+ end)
+ end)
+ describe('selecting the whole file', function()
+ before_each(function()
+ feed('ggVG')
+ end)
+ it('pasting text without final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd]])
+ end)
+ it('pasting text with final new line', function()
+ nvim('paste', 'aaaaaa\n', false, 1)
+ nvim('paste', 'bbbbbb\n', false, 2)
+ nvim('paste', 'cccccc\n', false, 2)
+ nvim('paste', 'dddddd\n', false, 3)
+ expect([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+ ]])
+ end)
+ end)
+ end)
+ end
+ describe('without virtualedit,', function()
+ run_streamed_paste_tests()
+ end)
+ describe('with virtualedit=onemore,', function()
+ before_each(function()
+ command('set virtualedit=onemore')
+ end)
+ run_streamed_paste_tests()
end)
it('non-streaming', function()
-- With final "\n".
@@ -711,6 +1082,43 @@ describe('API', function()
eeffgghh
iijjkkll]])
end)
+ it('when searching in Visual mode', function()
+ feed('v/')
+ nvim('paste', 'aabbccdd', true, -1)
+ eq('aabbccdd', funcs.getcmdline())
+ expect('')
+ end)
+ it('mappings are disabled in Cmdline mode', function()
+ command('cnoremap a b')
+ feed(':')
+ nvim('paste', 'a', true, -1)
+ eq('a', funcs.getcmdline())
+ end)
+ it('pasting with empty last chunk in Cmdline mode', function()
+ local screen = Screen.new(20, 4)
+ screen:attach()
+ feed(':')
+ nvim('paste', 'Foo', true, 1)
+ nvim('paste', '', true, 3)
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ :Foo^ |
+ ]])
+ end)
+ it('pasting text with control characters in Cmdline mode', function()
+ local screen = Screen.new(20, 4)
+ screen:attach()
+ feed(':')
+ nvim('paste', 'normal! \023\022\006\027', true, -1)
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ :normal! ^W^V^F^[^ |
+ ]])
+ end)
it('crlf=false does not break lines at CR, CRLF', function()
nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1)
expect('line 1\r\n\r\rline 2\nline 3\rline 4\r')
@@ -872,6 +1280,30 @@ describe('API', function()
command('lockvar lua')
eq('Key is locked: lua', pcall_err(meths.del_var, 'lua'))
eq('Key is locked: lua', pcall_err(meths.set_var, 'lua', 1))
+
+ exec([[
+ function Test()
+ endfunction
+ function s:Test()
+ endfunction
+ let g:Unknown_func = function('Test')
+ let g:Unknown_script_func = function('s:Test')
+ ]])
+ eq(NIL, meths.get_var('Unknown_func'))
+ eq(NIL, meths.get_var('Unknown_script_func'))
+
+ -- Check if autoload works properly
+ local pathsep = helpers.get_pathsep()
+ local xconfig = 'Xhome' .. pathsep .. 'Xconfig'
+ local xdata = 'Xhome' .. pathsep .. 'Xdata'
+ local autoload_folder = table.concat({xconfig, 'nvim', 'autoload'}, pathsep)
+ local autoload_file = table.concat({autoload_folder , 'testload.vim'}, pathsep)
+ mkdir_p(autoload_folder)
+ write_file(autoload_file , [[let testload#value = 2]])
+
+ clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_DATA_HOME=xdata } }
+ eq(2, meths.get_var('testload#value'))
+ rmdir('Xhome')
end)
it('nvim_get_vvar, nvim_set_vvar', function()
@@ -1008,6 +1440,46 @@ describe('API', function()
nvim('set_option_value', 'autoread', NIL, {scope = 'local'})
eq(NIL, nvim('get_option_value', 'autoread', {scope = 'local'}))
end)
+
+ it('set window options', function()
+ -- Same as to nvim_win_set_option
+ nvim('set_option_value', 'colorcolumn', '4,3', {win=0})
+ eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'}))
+ command("set modified hidden")
+ command("enew") -- edit new buffer, window option is preserved
+ eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'}))
+ end)
+
+ it('set local window options', function()
+ -- Different to nvim_win_set_option
+ nvim('set_option_value', 'colorcolumn', '4,3', {win=0, scope='local'})
+ eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'}))
+ command("set modified hidden")
+ command("enew") -- edit new buffer, window option is reset
+ eq('', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'}))
+ end)
+
+ it('get buffer or window-local options', function()
+ nvim('command', 'new')
+ local buf = nvim('get_current_buf').id
+ nvim('buf_set_option', buf, 'tagfunc', 'foobar')
+ eq('foobar', nvim('get_option_value', 'tagfunc', {buf = buf}))
+
+ local win = nvim('get_current_win').id
+ nvim('win_set_option', win, 'number', true)
+ eq(true, nvim('get_option_value', 'number', {win = win}))
+ end)
+
+ it('getting current buffer option does not adjust cursor #19381', function()
+ nvim('command', 'new')
+ local buf = nvim('get_current_buf').id
+ local win = nvim('get_current_win').id
+ insert('some text')
+ feed('0v$')
+ eq({1, 9}, nvim('win_get_cursor', win))
+ nvim('get_option_value', 'filetype', {buf = buf})
+ eq({1, 9}, nvim('win_get_cursor', win))
+ end)
end)
describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()
@@ -1093,7 +1565,20 @@ describe('API', function()
eq({mode='n', blocking=false}, nvim("get_mode"))
end)
+ it("during press-enter prompt without UI returns blocking=false", function()
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ command("echom 'msg1'")
+ command("echom 'msg2'")
+ command("echom 'msg3'")
+ command("echom 'msg4'")
+ command("echom 'msg5'")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ nvim("input", ":messages<CR>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+
it("during press-enter prompt returns blocking=true", function()
+ nvim("ui_attach", 80, 20, {})
eq({mode='n', blocking=false}, nvim("get_mode"))
command("echom 'msg1'")
command("echom 'msg2'")
@@ -1117,6 +1602,7 @@ describe('API', function()
-- TODO: bug #6247#issuecomment-286403810
it("batched with input", function()
+ nvim("ui_attach", 80, 20, {})
eq({mode='n', blocking=false}, nvim("get_mode"))
command("echom 'msg1'")
command("echom 'msg2'")
@@ -1152,6 +1638,18 @@ describe('API', function()
feed(':digraphs<cr>')
eq({mode='rm', blocking=true}, nvim("get_mode"))
end)
+
+ it('after <Nop> mapping returns blocking=false #17257', function()
+ command('nnoremap <F2> <Nop>')
+ feed('<F2>')
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
+
+ it('after empty string <expr> mapping returns blocking=false #17257', function()
+ command('nnoremap <expr> <F2> ""')
+ feed('<F2>')
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+ end)
end)
describe('RPC (K_EVENT)', function()
@@ -1367,18 +1865,18 @@ describe('API', function()
end)
describe('nvim_feedkeys', function()
- it('CSI escaping', function()
+ it('K_SPECIAL escaping', function()
local function on_setup()
-- notice the special char(…) \xe2\80\xa6
nvim('feedkeys', ':let x1="…"\n', '', true)
-- Both nvim_replace_termcodes and nvim_feedkeys escape \x80
local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true)
- nvim('feedkeys', inp, '', true) -- escape_csi=true
+ nvim('feedkeys', inp, '', true) -- escape_ks=true
- -- nvim_feedkeys with CSI escaping disabled
+ -- nvim_feedkeys with K_SPECIAL escaping disabled
inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true)
- nvim('feedkeys', inp, '', false) -- escape_csi=false
+ nvim('feedkeys', inp, '', false) -- escape_ks=false
helpers.stop()
end
@@ -1386,10 +1884,10 @@ describe('API', function()
-- spin the loop a bit
helpers.run(nil, nil, on_setup)
- eq(nvim('get_var', 'x1'), '…')
+ eq('…', nvim('get_var', 'x1'))
-- Because of the double escaping this is neq
- neq(nvim('get_var', 'x2'), '…')
- eq(nvim('get_var', 'x3'), '…')
+ neq('…', nvim('get_var', 'x2'))
+ eq('…', nvim('get_var', 'x3'))
end)
end)
@@ -2142,7 +2640,7 @@ describe('API', function()
it('does not cause heap-use-after-free on exit while setting options', function()
command('au OptionSet * q')
- command('silent! call nvim_create_buf(0, 1)')
+ expect_exit(command, 'silent! call nvim_create_buf(0, 1)')
end)
end)
@@ -2187,6 +2685,14 @@ describe('API', function()
eq({}, meths.get_runtime_file("foobarlang/", true))
end)
+ it('can handle bad patterns', function()
+ if helpers.pending_win32(pending) then return end
+
+ eq("Vim:E220: Missing }.", pcall_err(meths.get_runtime_file, "{", false))
+
+ eq('Vim(echo):E5555: API call: Vim:E220: Missing }.',
+ exc_exec("echo nvim_get_runtime_file('{', v:false)"))
+ end)
end)
describe('nvim_get_all_options_info', function()
@@ -2551,6 +3057,38 @@ describe('API', function()
'Should be truncated%<',
{ maxwidth = 15 }))
end)
+ it('supports ASCII fillchar', function()
+ eq({ str = 'a~~~b', width = 5 },
+ meths.eval_statusline('a%=b', { fillchar = '~', maxwidth = 5 }))
+ end)
+ it('supports single-width multibyte fillchar', function()
+ eq({ str = 'a━━━b', width = 5 },
+ meths.eval_statusline('a%=b', { fillchar = '━', maxwidth = 5 }))
+ end)
+ it('treats double-width fillchar as single-width', function()
+ eq({ str = 'a哦哦哦b', width = 5 },
+ meths.eval_statusline('a%=b', { fillchar = '哦', maxwidth = 5 }))
+ end)
+ it('treats control character fillchar as single-width', function()
+ eq({ str = 'a\031\031\031b', width = 5 },
+ meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 }))
+ end)
+ it('rejects multiple-character fillchar', function()
+ eq('fillchar must be a single character',
+ pcall_err(meths.eval_statusline, '', { fillchar = 'aa' }))
+ end)
+ it('rejects empty string fillchar', function()
+ eq('fillchar must be a single character',
+ pcall_err(meths.eval_statusline, '', { fillchar = '' }))
+ end)
+ it('rejects non-string fillchar', function()
+ eq('fillchar must be a single character',
+ pcall_err(meths.eval_statusline, '', { fillchar = 1 }))
+ end)
+ it('rejects invalid string', function()
+ eq('E539: Illegal character <}>',
+ pcall_err(meths.eval_statusline, '%{%}', {}))
+ end)
describe('highlight parsing', function()
it('works', function()
eq({
@@ -2605,6 +3143,678 @@ describe('API', function()
'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
{ use_tabline = true, highlights = true }))
end)
+ it('works with winbar', function()
+ eq({
+ str = 'TextWithNoHighlightTextWithWarningHighlight',
+ width = 43,
+ highlights = {
+ { start = 0, group = 'WinBar' },
+ { start = 19, group = 'WarningMsg' }
+ }
+ },
+ meths.eval_statusline(
+ 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
+ { use_winbar = true, highlights = true }))
+ end)
+ end)
+ end)
+ describe('nvim_parse_cmd', function()
+ it('works', function()
+ eq({
+ cmd = 'echo',
+ args = { 'foo' },
+ bang = false,
+ range = {},
+ count = -1,
+ reg = '',
+ addr = 'none',
+ magic = {
+ file = false,
+ bar = false
+ },
+ nargs = '*',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('echo foo', {}))
+ end)
+ it('works with ranges', function()
+ eq({
+ cmd = 'substitute',
+ args = { '/math.random/math.max/' },
+ bang = false,
+ range = { 4, 6 },
+ count = -1,
+ reg = '',
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = false
+ },
+ nargs = '*',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('4,6s/math.random/math.max/', {}))
+ end)
+ it('works with count', function()
+ eq({
+ cmd = 'buffer',
+ args = {},
+ bang = false,
+ range = { 1 },
+ count = 1,
+ reg = '',
+ addr = 'buf',
+ magic = {
+ file = false,
+ bar = true
+ },
+ nargs = '*',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('buffer 1', {}))
+ end)
+ it('works with register', function()
+ eq({
+ cmd = 'put',
+ args = {},
+ bang = false,
+ range = {},
+ count = -1,
+ reg = '+',
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = true
+ },
+ nargs = '0',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('put +', {}))
+ end)
+ it('works with range, count and register', function()
+ eq({
+ cmd = 'delete',
+ args = {},
+ bang = false,
+ range = { 3, 7 },
+ count = 7,
+ reg = '*',
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = true
+ },
+ nargs = '0',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('1,3delete * 5', {}))
+ end)
+ it('works with bang', function()
+ eq({
+ cmd = 'write',
+ args = {},
+ bang = true,
+ range = {},
+ count = -1,
+ reg = '',
+ addr = 'line',
+ magic = {
+ file = true,
+ bar = true
+ },
+ nargs = '?',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ },
+ }, meths.parse_cmd('w!', {}))
+ end)
+ it('works with modifiers', function()
+ eq({
+ cmd = 'split',
+ args = { 'foo.txt' },
+ bang = false,
+ range = {},
+ count = -1,
+ reg = '',
+ addr = '?',
+ magic = {
+ file = true,
+ bar = true
+ },
+ nargs = '?',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = true,
+ filter = {
+ pattern = "foo",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = true,
+ split = "topleft",
+ tab = 2,
+ unsilent = false,
+ verbose = 15,
+ vertical = false,
+ },
+ }, meths.parse_cmd('15verbose silent! aboveleft topleft tab filter /foo/ split foo.txt', {}))
+ eq({
+ cmd = 'split',
+ args = { 'foo.txt' },
+ bang = false,
+ range = {},
+ count = -1,
+ reg = '',
+ addr = '?',
+ magic = {
+ file = true,
+ bar = true
+ },
+ nargs = '?',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = true,
+ emsg_silent = false,
+ filter = {
+ pattern = "foo",
+ force = true
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "botright",
+ tab = 0,
+ unsilent = true,
+ verbose = 0,
+ vertical = false,
+ },
+ }, meths.parse_cmd('0verbose unsilent botright confirm filter! /foo/ split foo.txt', {}))
+ end)
+ it('works with user commands', function()
+ command('command -bang -nargs=+ -range -addr=lines MyCommand echo foo')
+ eq({
+ cmd = 'MyCommand',
+ args = { 'test', 'it' },
+ bang = true,
+ range = { 4, 6 },
+ count = -1,
+ reg = '',
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = false
+ },
+ nargs = '+',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('4,6MyCommand! test it', {}))
+ end)
+ it('works for commands separated by bar', function()
+ eq({
+ cmd = 'argadd',
+ args = { 'a.txt' },
+ bang = false,
+ range = {},
+ count = -1,
+ reg = '',
+ addr = 'arg',
+ magic = {
+ file = true,
+ bar = true
+ },
+ nargs = '*',
+ nextcmd = 'argadd b.txt',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('argadd a.txt | argadd b.txt', {}))
+ end)
+ it('works for nargs=1', function()
+ command('command -nargs=1 MyCommand echo <q-args>')
+ eq({
+ cmd = 'MyCommand',
+ args = { 'test it' },
+ bang = false,
+ range = {},
+ count = -1,
+ reg = '',
+ addr = 'none',
+ magic = {
+ file = false,
+ bar = false
+ },
+ nargs = '1',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('MyCommand test it', {}))
+ end)
+ it('errors for invalid command', function()
+ eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {}))
+ eq('Error while parsing command line', pcall_err(meths.parse_cmd, '" foo', {}))
+ eq('Error while parsing command line: E492: Not an editor command: Fubar',
+ pcall_err(meths.parse_cmd, 'Fubar', {}))
+ command('command! Fubar echo foo')
+ eq('Error while parsing command line: E477: No ! allowed',
+ pcall_err(meths.parse_cmd, 'Fubar!', {}))
+ eq('Error while parsing command line: E481: No range allowed',
+ pcall_err(meths.parse_cmd, '4,6Fubar', {}))
+ command('command! Foobar echo foo')
+ eq('Error while parsing command line: E464: Ambiguous use of user-defined command',
+ pcall_err(meths.parse_cmd, 'F', {}))
+ end)
+ it('does not interfere with printing line in Ex mode #19400', function()
+ local screen = Screen.new(60, 7)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, reverse = true}, -- MsgSeparator
+ })
+ screen:attach()
+ insert([[
+ foo
+ bar]])
+ feed('gQ1')
+ screen:expect([[
+ foo |
+ bar |
+ {0:~ }|
+ {0:~ }|
+ {1: }|
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :1^ |
+ ]])
+ eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {}))
+ feed('<CR>')
+ screen:expect([[
+ foo |
+ bar |
+ {1: }|
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :1 |
+ foo |
+ :^ |
+ ]])
+ end)
+ end)
+ describe('nvim_cmd', function()
+ it('works', function ()
+ meths.cmd({ cmd = "set", args = { "cursorline" } }, {})
+ eq(true, meths.get_option_value("cursorline", {}))
+ end)
+ it('captures output', function()
+ eq("foo", meths.cmd({ cmd = "echo", args = { '"foo"' } }, { output = true }))
+ end)
+ it('sets correct script context', function()
+ meths.cmd({ cmd = "set", args = { "cursorline" } }, {})
+ local str = meths.exec([[verbose set cursorline?]], true)
+ neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)"))
+ end)
+ it('works with range', function()
+ insert [[
+ line1
+ line2
+ line3
+ line4
+ you didn't expect this
+ line5
+ line6
+ ]]
+ meths.cmd({ cmd = "del", range = {2, 4} }, {})
+ expect [[
+ line1
+ you didn't expect this
+ line5
+ line6
+ ]]
+ end)
+ it('works with count', function()
+ insert [[
+ line1
+ line2
+ line3
+ line4
+ you didn't expect this
+ line5
+ line6
+ ]]
+ meths.cmd({ cmd = "del", range = { 2 }, count = 4 }, {})
+ expect [[
+ line1
+ line5
+ line6
+ ]]
+ end)
+ it('works with register', function()
+ insert [[
+ line1
+ line2
+ line3
+ line4
+ you didn't expect this
+ line5
+ line6
+ ]]
+ meths.cmd({ cmd = "del", range = { 2, 4 }, reg = 'a' }, {})
+ meths.exec("1put a", false)
+ expect [[
+ line1
+ line2
+ line3
+ line4
+ you didn't expect this
+ line5
+ line6
+ ]]
+ end)
+ it('works with bang', function ()
+ meths.create_user_command("Foo", 'echo "<bang>"', { bang = true })
+ eq("!", meths.cmd({ cmd = "Foo", bang = true }, { output = true }))
+ eq("", meths.cmd({ cmd = "Foo", bang = false }, { output = true }))
+ end)
+ it('works with modifiers', function()
+ meths.create_user_command("Foo", 'set verbose', {})
+ eq(" verbose=1", meths.cmd({ cmd = "Foo", mods = { verbose = 1 } }, { output = true }))
+ eq(0, meths.get_option_value("verbose", {}))
+ command('edit foo.txt | edit bar.txt')
+ eq(' 1 #h "foo.txt" line 1',
+ meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = false } } },
+ { output = true }))
+ eq(' 2 %a "bar.txt" line 1',
+ meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = true } } },
+ { output = true }))
+ end)
+ it('works with magic.file', function()
+ exec_lua([[
+ vim.api.nvim_create_user_command("Foo", function(opts)
+ vim.api.nvim_echo({{ opts.fargs[1] }}, false, {})
+ end, { nargs = 1 })
+ ]])
+ eq(lfs.currentdir(),
+ meths.cmd({ cmd = "Foo", args = { '%:p:h' }, magic = { file = true } },
+ { output = true }))
+ end)
+ it('splits arguments correctly', function()
+ meths.exec([[
+ function! FooFunc(...)
+ echo a:000
+ endfunction
+ ]], false)
+ meths.create_user_command("Foo", "call FooFunc(<f-args>)", { nargs = '+' })
+ eq([=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=],
+ meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}},
+ { output = true }))
+ eq([=[['test \ \\ \"""\', 'more\ tests\" ']]=],
+ meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } },
+ { output = true }))
+ end)
+ it('splits arguments correctly for Lua callback', function()
+ meths.exec_lua([[
+ local function FooFunc(opts)
+ vim.pretty_print(opts.fargs)
+ end
+
+ vim.api.nvim_create_user_command("Foo", FooFunc, { nargs = '+' })
+ ]], {})
+ eq([[{ "a quick", "brown fox", "jumps over the", "lazy dog" }]],
+ meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}},
+ { output = true }))
+ eq([[{ 'test \\ \\\\ \\"""\\', 'more\\ tests\\" ' }]],
+ meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } },
+ { output = true }))
+ end)
+ it('works with buffer names', function()
+ command("edit foo.txt | edit bar.txt")
+ meths.cmd({ cmd = "buffer", args = { "foo.txt" } }, {})
+ eq("foo.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t"))
+ meths.cmd({ cmd = "buffer", args = { "bar.txt" } }, {})
+ eq("bar.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t"))
+ end)
+ it('triggers CmdUndefined event if command is not found', function()
+ meths.exec_lua([[
+ vim.api.nvim_create_autocmd("CmdUndefined",
+ { pattern = "Foo",
+ callback = function()
+ vim.api.nvim_create_user_command("Foo", "echo 'foo'", {})
+ end
+ })
+ ]], {})
+ eq("foo", meths.cmd({ cmd = "Foo" }, { output = true }))
+ end)
+ it('errors if command is not implemented', function()
+ eq("Command not implemented: winpos", pcall_err(meths.cmd, { cmd = "winpos" }, {}))
+ end)
+ it('works with empty arguments list', function()
+ meths.cmd({ cmd = "update" }, {})
+ meths.cmd({ cmd = "buffer", count = 0 }, {})
+ end)
+ it('doesn\'t suppress errors when used in keymapping', function()
+ meths.exec_lua([[
+ vim.keymap.set("n", "[l",
+ function() vim.api.nvim_cmd({ cmd = "echo", args = {"foo"} }, {}) end)
+ ]], {})
+ feed("[l")
+ neq(nil, string.find(eval("v:errmsg"), "E5108:"))
end)
end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 4d2ffa316a..901d24327c 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
ok, feed, insert, eval, tabpage = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
@@ -73,8 +74,7 @@ describe('API/win', function()
eq('typing\n some dumb text', curbuf_contents())
end)
- it('does not leak memory when using invalid window ID with invalid pos',
- function()
+ it('does not leak memory when using invalid window ID with invalid pos', function()
eq('Invalid window id: 1', pcall_err(meths.win_set_cursor, 1, {"b\na"}))
end)
@@ -147,6 +147,46 @@ describe('API/win', function()
eq({2, 5}, window('get_cursor', win))
end)
+ it('updates cursorline and statusline ruler in non-current window', function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {background = Screen.colors.Grey90}, -- CursorLine
+ [3] = {bold = true, reverse = true}, -- StatusLine
+ [4] = {reverse = true}, -- StatusLineNC
+ })
+ screen:attach()
+ command('set ruler')
+ command('set cursorline')
+ insert([[
+ aaa
+ bbb
+ ccc
+ ddd]])
+ local oldwin = curwin()
+ command('vsplit')
+ screen:expect([[
+ aaa │aaa |
+ bbb │bbb |
+ ccc │ccc |
+ {2:dd^d }│{2:ddd }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 4,3 All}|
+ |
+ ]])
+ window('set_cursor', oldwin, {1, 0})
+ screen:expect([[
+ aaa │{2:aaa }|
+ bbb │bbb |
+ ccc │ccc |
+ {2:dd^d }│ddd |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 1,1 All}|
+ |
+ ]])
+ end)
end)
describe('{get,set}_height', function()
diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua
new file mode 100644
index 0000000000..ad3687d7b0
--- /dev/null
+++ b/test/functional/autocmd/autocmd_oldtest_spec.lua
@@ -0,0 +1,86 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local meths = helpers.meths
+local funcs = helpers.funcs
+
+local exec = function(str)
+ meths.exec(str, false)
+end
+
+describe('oldtests', function()
+ before_each(clear)
+
+ local exec_lines = function(str)
+ return funcs.split(funcs.execute(str), "\n")
+ end
+
+ local add_an_autocmd = function()
+ exec [[
+ augroup vimBarTest
+ au BufReadCmd * echo 'hello'
+ augroup END
+ ]]
+
+ eq(3, #exec_lines('au vimBarTest'))
+ eq(1, #meths.get_autocmds({ group = 'vimBarTest' }))
+ end
+
+ it('should recognize a bar before the {event}', function()
+ -- Good spacing
+ add_an_autocmd()
+ exec [[ augroup vimBarTest | au! | augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+ eq({}, meths.get_autocmds({ group = 'vimBarTest' }))
+
+ -- Sad spacing
+ add_an_autocmd()
+ exec [[ augroup vimBarTest| au!| augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+
+
+ -- test that a bar is recognized after the {event}
+ add_an_autocmd()
+ exec [[ augroup vimBarTest| au!BufReadCmd| augroup END ]]
+ eq(1, #exec_lines('au vimBarTest'))
+
+ add_an_autocmd()
+ exec [[ au! vimBarTest|echo 'hello' ]]
+ eq(1, #exec_lines('au vimBarTest'))
+ end)
+
+ it('should fire on unload buf', function()
+ funcs.writefile({'Test file Xxx1'}, 'Xxx1')
+ funcs.writefile({'Test file Xxx2'}, 'Xxx2')
+
+ local content = [[
+ func UnloadAllBufs()
+ let i = 1
+ while i <= bufnr('$')
+ if i != bufnr('%') && bufloaded(i)
+ exe i . 'bunload'
+ endif
+ let i += 1
+ endwhile
+ endfunc
+ au BufUnload * call UnloadAllBufs()
+ au VimLeave * call writefile(['Test Finished'], 'Xout')
+ set nohidden
+ edit Xxx1
+ split Xxx2
+ q
+ ]]
+
+ funcs.writefile(funcs.split(content, "\n"), 'Xtest')
+
+ funcs.delete('Xout')
+ funcs.system(meths.get_vvar('progpath') .. ' -u NORC -i NONE -N -S Xtest')
+ eq(1, funcs.filereadable('Xout'))
+
+ funcs.delete('Xxx1')
+ funcs.delete('Xxx2')
+ funcs.delete('Xtest')
+ funcs.delete('Xout')
+ end)
+end)
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 93d71a9e45..90254b7415 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -2,8 +2,10 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_visible = helpers.assert_visible
+local assert_alive = helpers.assert_alive
local dedent = helpers.dedent
local eq = helpers.eq
+local neq = helpers.neq
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
@@ -13,7 +15,9 @@ local funcs = helpers.funcs
local expect = helpers.expect
local command = helpers.command
local exc_exec = helpers.exc_exec
+local exec_lua = helpers.exec_lua
local curbufmeths = helpers.curbufmeths
+local retry = helpers.retry
local source = helpers.source
describe('autocmd', function()
@@ -56,6 +60,23 @@ describe('autocmd', function()
eq(expected, eval('g:evs'))
end)
+ it('first edit causes BufUnload on NoName', function()
+ local expected = {
+ {'BufUnload', ''},
+ {'BufDelete', ''},
+ {'BufWipeout', ''},
+ {'BufEnter', 'testfile1'},
+ }
+ command('let g:evs = []')
+ command('autocmd BufEnter * :call add(g:evs, ["BufEnter", expand("<afile>")])')
+ command('autocmd BufDelete * :call add(g:evs, ["BufDelete", expand("<afile>")])')
+ command('autocmd BufLeave * :call add(g:evs, ["BufLeave", expand("<afile>")])')
+ command('autocmd BufUnload * :call add(g:evs, ["BufUnload", expand("<afile>")])')
+ command('autocmd BufWipeout * :call add(g:evs, ["BufWipeout", expand("<afile>")])')
+ command('edit testfile1')
+ eq(expected, eval('g:evs'))
+ end)
+
it('WinClosed is non-recursive', function()
command('let g:triggered = 0')
command('autocmd WinClosed * :let g:triggered+=1 | :bdelete 2')
@@ -333,6 +354,87 @@ describe('autocmd', function()
pcall_err(command, "call nvim_set_current_win(g:winid)"))
end)
+ it("`aucmd_win` cannot be changed into a normal window #13699", function()
+ local screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {reverse = true},
+ [3] = {bold = true, reverse = true},
+ }
+
+ -- Create specific layout and ensure it's left unchanged.
+ -- Use nvim_buf_call on a hidden buffer so aucmd_win is used.
+ exec_lua [[
+ vim.cmd "wincmd s | wincmd _"
+ _G.buf = vim.api.nvim_create_buf(true, true)
+ vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd J" end)
+ ]]
+ screen:expect [[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ ]]
+ -- This used to crash after making aucmd_win a normal window via the above.
+ exec_lua [[
+ vim.cmd "tabnew | tabclose # | wincmd s | wincmd _"
+ vim.api.nvim_buf_call(_G.buf, function() vim.cmd "wincmd K" end)
+ ]]
+ assert_alive()
+ screen:expect_unchanged()
+
+ -- Ensure splitting still works from inside the aucmd_win.
+ exec_lua [[vim.api.nvim_buf_call(_G.buf, function() vim.cmd "split" end)]]
+ screen:expect [[
+ ^ |
+ {1:~ }|
+ {3:[No Name] }|
+ |
+ {1:~ }|
+ {2:[Scratch] }|
+ |
+ {1:~ }|
+ {2:[No Name] }|
+ |
+ ]]
+
+ -- After all of our messing around, aucmd_win should still be floating.
+ -- Use :only to ensure _G.buf is hidden again (so the aucmd_win is used).
+ eq("editor", exec_lua [[
+ vim.cmd "only"
+ vim.api.nvim_buf_call(_G.buf, function()
+ _G.config = vim.api.nvim_win_get_config(0)
+ end)
+ return _G.config.relative
+ ]])
+ end)
+
+ describe('closing last non-floating window in tab from `aucmd_win`', function()
+ before_each(function()
+ command('edit Xa.txt')
+ command('tabnew Xb.txt')
+ command('autocmd BufAdd Xa.txt 1close')
+ end)
+
+ it('gives E814 when there are no other floating windows', function()
+ eq('Vim(close):E814: Cannot close window, only autocmd window would remain',
+ pcall_err(command, 'doautoall BufAdd'))
+ end)
+
+ it('gives E814 when there are other floating windows', function()
+ meths.open_win(0, true, {width = 10, height = 10, relative = 'editor', row = 10, col = 10})
+ eq('Vim(close):E814: Cannot close window, only autocmd window would remain',
+ pcall_err(command, 'doautoall BufAdd'))
+ end)
+ end)
+
it(':doautocmd does not warn "No matching autocommands" #10689', function()
local screen = Screen.new(32, 3)
screen:attach()
@@ -354,4 +456,125 @@ describe('autocmd', function()
:doautocmd SessionLoadPost |
]]}
end)
+
+ describe('v:event is readonly #18063', function()
+ it('during ChanOpen event', function()
+ command('autocmd ChanOpen * let v:event.info.id = 0')
+ funcs.jobstart({'cat'})
+ retry(nil, nil, function()
+ eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg'))
+ end)
+ end)
+
+ it('during ChanOpen event', function()
+ command('autocmd ChanInfo * let v:event.info.id = 0')
+ meths.set_client_info('foo', {}, 'remote', {}, {})
+ retry(nil, nil, function()
+ eq('E46: Cannot change read-only variable "v:event.info"', meths.get_vvar('errmsg'))
+ end)
+ end)
+
+ it('during RecordingLeave event', function()
+ command([[autocmd RecordingLeave * let v:event.regname = '']])
+ eq('Vim(let):E46: Cannot change read-only variable "v:event.regname"',
+ pcall_err(command, 'normal! qqq'))
+ end)
+
+ it('during TermClose event', function()
+ command('autocmd TermClose * let v:event.status = 0')
+ command('terminal')
+ eq('Vim(let):E46: Cannot change read-only variable "v:event.status"',
+ pcall_err(command, 'bdelete!'))
+ end)
+ end)
+
+ describe('old_tests', function()
+ it('vimscript: WinNew ++once', function()
+ source [[
+ " Without ++once WinNew triggers twice
+ let g:did_split = 0
+ augroup Testing
+ au!
+ au WinNew * let g:did_split += 1
+ augroup END
+ split
+ split
+ call assert_equal(2, g:did_split)
+ call assert_true(exists('#WinNew'))
+ close
+ close
+
+ " With ++once WinNew triggers once
+ let g:did_split = 0
+ augroup Testing
+ au!
+ au WinNew * ++once let g:did_split += 1
+ augroup END
+ split
+ split
+ call assert_equal(1, g:did_split)
+ call assert_false(exists('#WinNew'))
+ close
+ close
+
+ call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+ ]]
+
+ meths.set_var('did_split', 0)
+
+ source [[
+ augroup Testing
+ au!
+ au WinNew * let g:did_split += 1
+ augroup END
+
+ split
+ split
+ ]]
+
+ eq(2, meths.get_var('did_split'))
+ eq(1, funcs.exists('#WinNew'))
+
+ -- Now with once
+ meths.set_var('did_split', 0)
+
+ source [[
+ augroup Testing
+ au!
+ au WinNew * ++once let g:did_split += 1
+ augroup END
+
+ split
+ split
+ ]]
+
+ eq(1, meths.get_var('did_split'))
+ eq(0, funcs.exists('#WinNew'))
+
+ -- call assert_fails('au WinNew * ++once ++once echo bad', 'E983:')
+ local ok, msg = pcall(source, [[
+ au WinNew * ++once ++once echo bad
+ ]])
+
+ eq(false, ok)
+ eq(true, not not string.find(msg, 'E983:'))
+ end)
+
+ it('should have autocmds in filetypedetect group', function()
+ source [[filetype on]]
+ neq({}, meths.get_autocmds { group = "filetypedetect" })
+ end)
+
+ it('should allow comma-separated patterns', function()
+ source [[
+ augroup TestingPatterns
+ au!
+ autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] echo 'hello'
+ autocmd BufReadCmd *.shada,*.shada.tmp.[a-z] echo 'hello'
+ augroup END
+ ]]
+
+ eq(4, #meths.get_autocmds { event = "BufReadCmd", group = "TestingPatterns" })
+ end)
+ end)
end)
diff --git a/test/functional/autocmd/cursormoved_spec.lua b/test/functional/autocmd/cursormoved_spec.lua
index 9641d4b096..85d8628d7e 100644
--- a/test/functional/autocmd/cursormoved_spec.lua
+++ b/test/functional/autocmd/cursormoved_spec.lua
@@ -35,6 +35,7 @@ describe('CursorMoved', function()
it("is not triggered by cursor movement prior to first CursorMoved instantiation", function()
source([[
let g:cursormoved = 0
+ autocmd! CursorMoved
autocmd CursorMoved * let g:cursormoved += 1
]])
eq(0, eval('g:cursormoved'))
diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua
index f4a1642ebf..45dc06b39b 100644
--- a/test/functional/autocmd/dirchanged_spec.lua
+++ b/test/functional/autocmd/dirchanged_spec.lua
@@ -8,7 +8,7 @@ local eval = h.eval
local request = h.request
local iswin = h.iswin
-describe('autocmd DirChanged', function()
+describe('autocmd DirChanged and DirChangedPre', function()
local curdir = string.gsub(lfs.currentdir(), '\\', '/')
local dirs = {
curdir .. '/Xtest-functional-autocmd-dirchanged.dir1',
@@ -26,31 +26,43 @@ describe('autocmd DirChanged', function()
before_each(function()
clear()
+ command('autocmd DirChangedPre * let [g:evpre, g:amatchpre, g:cdprecount] '
+ ..'= [copy(v:event), expand("<amatch>"), 1 + get(g:, "cdprecount", 0)]')
command('autocmd DirChanged * let [g:getcwd, g:ev, g:amatch, g:cdcount] '
- ..' = [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]')
+ ..'= [getcwd(), copy(v:event), expand("<amatch>"), 1 + get(g:, "cdcount", 0)]')
-- Normalize path separators.
+ command([[autocmd DirChangedPre * let g:evpre['directory'] = substitute(g:evpre['directory'], '\\', '/', 'g')]])
command([[autocmd DirChanged * let g:ev['cwd'] = substitute(g:ev['cwd'], '\\', '/', 'g')]])
- command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]])
+ command([[autocmd DirChanged * let g:getcwd = substitute(g:getcwd, '\\', '/', 'g')]])
end)
- it('sets v:event and <amatch>', function()
+ it('set v:event and <amatch>', function()
command('lcd '..dirs[1])
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
command('tcd '..dirs[2])
+ eq({directory=dirs[2], scope='tabpage', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='tabpage', changed_window=false}, eval('g:ev'))
+ eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
command('cd '..dirs[3])
+ eq({directory=dirs[3], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[3], scope='global', changed_window=false}, eval('g:ev'))
+ eq('global', eval('g:amatchpre'))
eq('global', eval('g:amatch'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
end)
- it('sets getcwd() during event #6260', function()
+ it('DirChanged set getcwd() during event #6260', function()
command('lcd '..dirs[1])
eq(dirs[1], eval('g:getcwd'))
@@ -61,7 +73,7 @@ describe('autocmd DirChanged', function()
eq(dirs[3], eval('g:getcwd'))
end)
- it('disallows recursion', function()
+ it('disallow recursion', function()
command('set shellslash')
-- Set up a _nested_ handler.
command('autocmd DirChanged * nested lcd '..dirs[3])
@@ -72,23 +84,36 @@ describe('autocmd DirChanged', function()
eq(dirs[3], eval('getcwd()'))
end)
- it('does not trigger if :cd fails', function()
+ it('only DirChangedPre is triggered if :cd fails', function()
command('let g:ev = {}')
+ command('let g:cdcount = 0')
local status1, err1 = pcall(function()
- command('lcd '..dirs[1] .. '/doesnotexist')
+ command('lcd '..dirs[1]..'/doesnotexist')
end)
+ eq({directory=dirs[1]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
+ eq(1, eval('g:cdprecount'))
+ eq(0, eval('g:cdcount'))
local status2, err2 = pcall(function()
- command('lcd '..dirs[2] .. '/doesnotexist')
+ command('lcd '..dirs[2]..'/doesnotexist')
end)
+ eq({directory=dirs[2]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
+ eq(2, eval('g:cdprecount'))
+ eq(0, eval('g:cdcount'))
local status3, err3 = pcall(function()
- command('lcd '..dirs[3] .. '/doesnotexist')
+ command('lcd '..dirs[3]..'/doesnotexist')
end)
+ eq({directory=dirs[3]..'/doesnotexist', scope='window', changed_window=false}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
+ eq(3, eval('g:cdprecount'))
+ eq(0, eval('g:cdcount'))
eq(false, status1)
eq(false, status2)
@@ -99,85 +124,121 @@ describe('autocmd DirChanged', function()
eq('E344:', string.match(err3, "E%d*:"))
end)
- it("is triggered by 'autochdir'", function()
+ it("are triggered by 'autochdir'", function()
command('set autochdir')
command('split '..dirs[1]..'/foo')
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('auto', eval('g:amatchpre'))
eq('auto', eval('g:amatch'))
+ eq(1, eval('g:cdprecount'))
+ eq(1, eval('g:cdcount'))
command('split '..dirs[2]..'/bar')
+ eq({directory=dirs[2], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=false}, eval('g:ev'))
eq('auto', eval('g:amatch'))
-
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
end)
- it('does not trigger if directory has not changed', function()
+ it('do not trigger if directory has not changed', function()
command('lcd '..dirs[1])
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('lcd '..dirs[1])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
if iswin() then
command('lcd '..win_dirs[1])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(1, eval('g:cdprecount'))
eq(1, eval('g:cdcount'))
end
command('tcd '..dirs[2])
+ eq({directory=dirs[2], scope='tabpage', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='tabpage', changed_window=false}, eval('g:ev'))
+ eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('tcd '..dirs[2])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
if iswin() then
command('tcd '..win_dirs[2])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(2, eval('g:cdprecount'))
eq(2, eval('g:cdcount'))
end
command('cd '..dirs[3])
+ eq({directory=dirs[3], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[3], scope='global', changed_window=false}, eval('g:ev'))
eq('global', eval('g:amatch'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('cd '..dirs[3])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
if iswin() then
command('cd '..win_dirs[3])
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(3, eval('g:cdprecount'))
eq(3, eval('g:cdcount'))
end
command('set autochdir')
command('split '..dirs[1]..'/foo')
+ eq({directory=dirs[1], scope='window', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='window', changed_window=false}, eval('g:ev'))
+ eq('auto', eval('g:amatchpre'))
eq('auto', eval('g:amatch'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
+ command('let g:evpre = {}')
command('let g:ev = {}')
command('split '..dirs[1]..'/bar')
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
if iswin() then
command('split '..win_dirs[1]..'/baz')
+ eq({}, eval('g:evpre'))
eq({}, eval('g:ev'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
end
end)
- it("is triggered by switching to win/tab with different CWD #6054", function()
+ it("are triggered by switching to win/tab with different CWD #6054", function()
command('lcd '..dirs[3]) -- window 3
command('split '..dirs[2]..'/foo') -- window 2
command('lcd '..dirs[2])
@@ -185,72 +246,105 @@ describe('autocmd DirChanged', function()
command('lcd '..dirs[1])
command('2wincmd w') -- window 2
+ eq({directory=dirs[2], scope='window', changed_window=true}, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=true}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
+ eq(4, eval('g:cdprecount'))
eq(4, eval('g:cdcount'))
command('tabnew') -- tab 2 (tab-local CWD)
+ eq(4, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(4, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tcd '..dirs[3])
command('tabnext') -- tab 1 (no tab-local CWD)
+ eq({directory=dirs[2], scope='window', changed_window=true}, eval('g:evpre'))
eq({cwd=dirs[2], scope='window', changed_window=true}, eval('g:ev'))
+ eq('window', eval('g:amatchpre'))
eq('window', eval('g:amatch'))
command('tabnext') -- tab 2
+ eq({directory=dirs[3], scope='tabpage', changed_window=true}, eval('g:evpre'))
eq({cwd=dirs[3], scope='tabpage', changed_window=true}, eval('g:ev'))
+ eq('tabpage', eval('g:amatchpre'))
eq('tabpage', eval('g:amatch'))
+ eq(7, eval('g:cdprecount'))
eq(7, eval('g:cdcount'))
command('tabnext') -- tab 1
command('3wincmd w') -- window 3
+ eq(9, eval('g:cdprecount'))
eq(9, eval('g:cdcount'))
command('tabnext') -- tab 2 (has the *same* CWD)
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
if iswin() then
command('tabnew') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tcd '..win_dirs[3])
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 1
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 2
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 1
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('lcd '..win_dirs[3]) -- window 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 2
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabnext') -- tab 1
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
command('tabprevious') -- tab 3
+ eq(9, eval('g:cdprecount')) -- same CWD, no DirChangedPre event
eq(9, eval('g:cdcount')) -- same CWD, no DirChanged event
end
end)
- it('is triggered by nvim_set_current_dir()', function()
+ it('are triggered by nvim_set_current_dir()', function()
request('nvim_set_current_dir', dirs[1])
+ eq({directory=dirs[1], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[1], scope='global', changed_window=false}, eval('g:ev'))
+ eq(1, eval('g:cdprecount'))
+ eq(1, eval('g:cdcount'))
request('nvim_set_current_dir', dirs[2])
+ eq({directory=dirs[2], scope='global', changed_window=false}, eval('g:evpre'))
eq({cwd=dirs[2], scope='global', changed_window=false}, eval('g:ev'))
+ 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({cwd=dirs[2], scope='global', changed_window=false}, eval('g:ev'))
+ eq({directory='/doesnotexist', scope='global', changed_window=false}, eval('g:evpre'))
+ eq(3, eval('g:cdprecount'))
+ eq(2, eval('g:cdcount'))
end)
- it('works when local to buffer', function()
+ it('work when local to buffer', function()
+ command('let g:triggeredpre = 0')
command('let g:triggered = 0')
+ command('autocmd DirChangedPre <buffer> let g:triggeredpre = 1')
command('autocmd DirChanged <buffer> let g:triggered = 1')
command('cd '..dirs[1])
+ eq(1, eval('g:triggeredpre'))
eq(1, eval('g:triggered'))
end)
end)
diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index 3f9a0ad09b..e3c9e1f9ee 100644
--- a/test/functional/autocmd/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
@@ -56,7 +56,7 @@ describe('autoread TUI FocusGained/FocusLost', function()
line 3 |
line 4 |
{5:xtest-foo }|
- "xtest-foo" 4L, 28C |
+ "xtest-foo" 4L, 28B |
{3:-- TERMINAL --} |
]]}
end)
diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua
new file mode 100644
index 0000000000..505bed834b
--- /dev/null
+++ b/test/functional/autocmd/show_spec.lua
@@ -0,0 +1,183 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local clear = helpers.clear
+local command = helpers.command
+local dedent = helpers.dedent
+local eq = helpers.eq
+local funcs = helpers.funcs
+local eval = helpers.eval
+local exec = helpers.exec
+local feed = helpers.feed
+
+describe(":autocmd", function()
+ before_each(function()
+ clear({'-u', 'NONE'})
+ end)
+
+ it("should not segfault when you just do autocmd", function()
+ command ":autocmd"
+ end)
+
+ it("should filter based on ++once", function()
+ command "autocmd! BufEnter"
+ command "autocmd BufEnter * :echo 'Hello'"
+ command [[augroup TestingOne]]
+ command [[ autocmd BufEnter * :echo "Line 1"]]
+ command [[ autocmd BufEnter * :echo "Line 2"]]
+ command [[augroup END]]
+
+ eq(dedent([[
+
+ --- Autocommands ---
+ BufEnter
+ * :echo 'Hello'
+ TestingOne BufEnter
+ * :echo "Line 1"
+ :echo "Line 2"]]),
+ funcs.execute('autocmd BufEnter'))
+ end)
+
+ it('should not show group information if interrupted', function()
+ local screen = Screen.new(50, 6)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ [2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [3] = {bold = true, foreground = Screen.colors.Magenta}, -- Title
+ })
+ screen:attach()
+ exec([[
+ set more
+ autocmd! BufEnter
+ augroup test_1
+ autocmd BufEnter A echo 'A'
+ autocmd BufEnter B echo 'B'
+ autocmd BufEnter C echo 'C'
+ autocmd BufEnter D echo 'D'
+ autocmd BufEnter E echo 'E'
+ autocmd BufEnter F echo 'F'
+ augroup END
+ autocmd! BufLeave
+ augroup test_1
+ autocmd BufLeave A echo 'A'
+ autocmd BufLeave B echo 'B'
+ autocmd BufLeave C echo 'C'
+ autocmd BufLeave D echo 'D'
+ autocmd BufLeave E echo 'E'
+ autocmd BufLeave F echo 'F'
+ augroup END
+ ]])
+ feed(':autocmd<CR>')
+ screen:expect([[
+ :autocmd |
+ {3:--- Autocommands ---} |
+ {3:test_1} {3:BufEnter} |
+ A echo 'A' |
+ B echo 'B' |
+ {2:-- More --}^ |
+ ]])
+ feed('q')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('should not show group information for deleted pattern', function()
+ exec([[
+ autocmd! BufEnter
+ augroup test_1
+ autocmd BufEnter A echo 'A'
+ autocmd BufEnter B echo 'B'
+ autocmd BufEnter C echo 'C'
+ augroup END
+ augroup test_2
+ autocmd BufEnter foo echo 'foo'
+ augroup END
+ augroup test_3
+ autocmd BufEnter D echo 'D'
+ autocmd BufEnter E echo 'E'
+ autocmd BufEnter F echo 'F'
+ augroup END
+
+ func Func()
+ autocmd! test_2 BufEnter
+ let g:output = execute('autocmd BufEnter')
+ endfunc
+
+ autocmd User foo call Func()
+ doautocmd User foo
+ ]])
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_1 BufEnter
+ A echo 'A'
+ B echo 'B'
+ C echo 'C'
+ test_3 BufEnter
+ D echo 'D'
+ E echo 'E'
+ F echo 'F']]), eval('g:output'))
+ end)
+
+ it('can filter by pattern #17973', function()
+ exec([[
+ autocmd! BufEnter
+ autocmd! User
+ augroup test_1
+ autocmd BufEnter A echo "A1"
+ autocmd BufEnter B echo "B1"
+ autocmd User A echo "A1"
+ autocmd User B echo "B1"
+ augroup END
+ augroup test_2
+ autocmd BufEnter A echo "A2"
+ autocmd BufEnter B echo "B2"
+ autocmd User A echo "A2"
+ autocmd User B echo "B2"
+ augroup END
+ augroup test_3
+ autocmd BufEnter A echo "A3"
+ autocmd BufEnter B echo "B3"
+ autocmd User A echo "A3"
+ autocmd User B echo "B3"
+ augroup END
+ ]])
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_1 User
+ A echo "A1"
+ test_2 User
+ A echo "A2"
+ test_3 User
+ A echo "A3"]]), funcs.execute('autocmd User A'))
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_1 BufEnter
+ B echo "B1"
+ test_2 BufEnter
+ B echo "B2"
+ test_3 BufEnter
+ B echo "B3"
+ test_1 User
+ B echo "B1"
+ test_2 User
+ B echo "B2"
+ test_3 User
+ B echo "B3"]]), funcs.execute('autocmd * B'))
+ eq(dedent([[
+
+ --- Autocommands ---
+ test_3 BufEnter
+ B echo "B3"
+ test_3 User
+ B echo "B3"]]), funcs.execute('autocmd test_3 * B'))
+ end)
+end)
diff --git a/test/functional/autocmd/signal_spec.lua b/test/functional/autocmd/signal_spec.lua
index 719adeaf1b..d4f65cc61d 100644
--- a/test/functional/autocmd/signal_spec.lua
+++ b/test/functional/autocmd/signal_spec.lua
@@ -30,6 +30,12 @@ describe('autocmd Signal', function()
eq({'notification', 'foo', {}}, next_msg())
end)
+ it('matches SIGWINCH', function()
+ command('autocmd Signal SIGWINCH call rpcnotify(1, "foo")')
+ posix_kill('WINCH', funcs.getpid())
+ eq({'notification', 'foo', {}}, next_msg())
+ end)
+
it('does not match unknown patterns', function()
command('autocmd Signal SIGUSR2 call rpcnotify(1, "foo")')
posix_kill('USR1', funcs.getpid())
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index 1e8f981437..859c2ebf44 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -1,21 +1,41 @@
local luv = require('luv')
local helpers = require('test.functional.helpers')(after_each)
-local clear, command, nvim, nvim_dir =
- helpers.clear, helpers.command, helpers.nvim, helpers.nvim_dir
+local clear, command, nvim, testprg =
+ helpers.clear, helpers.command, helpers.nvim, helpers.testprg
local eval, eq, neq, retry =
helpers.eval, helpers.eq, helpers.neq, helpers.retry
local ok = helpers.ok
local feed = helpers.feed
+local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
local iswin = helpers.iswin
describe('autocmd TermClose', function()
before_each(function()
clear()
- nvim('set_option', 'shell', nvim_dir .. '/shell-test')
+ nvim('set_option', 'shell', testprg('shell-test'))
command('set shellcmdflag=EXE shellredir= shellpipe= shellquote= shellxquote=')
end)
+
+ local function test_termclose_delete_own_buf()
+ command('autocmd TermClose * bdelete!')
+ command('terminal')
+ eq('Vim(bdelete):E937: Attempt to delete a buffer that is in use', pcall_err(command, 'bdelete!'))
+ assert_alive()
+ end
+
+ -- TODO: fixed after merging patches for `can_unload_buffer`?
+ pending('TermClose deleting its own buffer, altbuf = buffer 1 #10386', function()
+ test_termclose_delete_own_buf()
+ end)
+
+ it('TermClose deleting its own buffer, altbuf NOT buffer 1 #10386', function()
+ command('edit foo1')
+ test_termclose_delete_own_buf()
+ end)
+
it('triggers when fast-exiting terminal job stops', function()
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
diff --git a/test/functional/autocmd/winscrolled_spec.lua b/test/functional/autocmd/winscrolled_spec.lua
index 1ef5a37479..5c1b758961 100644
--- a/test/functional/autocmd/winscrolled_spec.lua
+++ b/test/functional/autocmd/winscrolled_spec.lua
@@ -3,60 +3,83 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
-local source = helpers.source
+local command = helpers.command
+local feed = helpers.feed
+local meths = helpers.meths
+local assert_alive = helpers.assert_alive
+
+before_each(clear)
describe('WinScrolled', function()
- before_each(clear)
+ local win_id
+
+ before_each(function()
+ win_id = meths.get_current_win().id
+ command(string.format('autocmd WinScrolled %d let g:matched = v:true', win_id))
+ command('let g:scrolled = 0')
+ command('autocmd WinScrolled * let g:scrolled += 1')
+ command([[autocmd WinScrolled * let g:amatch = str2nr(expand('<amatch>'))]])
+ command([[autocmd WinScrolled * let g:afile = str2nr(expand('<afile>'))]])
+ end)
+
+ after_each(function()
+ eq(true, eval('g:matched'))
+ eq(win_id, eval('g:amatch'))
+ eq(win_id, eval('g:afile'))
+ end)
it('is triggered by scrolling vertically', function()
- source([[
- set nowrap
- let width = winwidth(0)
- let line = '123' . repeat('*', width * 2)
- let lines = [line, line]
- call nvim_buf_set_lines(0, 0, -1, v:true, lines)
-
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- execute "normal! \<C-e>"
- ]])
+ local lines = {'123', '123'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ eq(0, eval('g:scrolled'))
+ feed('<C-E>')
eq(1, eval('g:scrolled'))
end)
it('is triggered by scrolling horizontally', function()
- source([[
- set nowrap
- let width = winwidth(0)
- let line = '123' . repeat('*', width * 2)
- let lines = [line, line]
- call nvim_buf_set_lines(0, 0, -1, v:true, lines)
-
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- execute "normal! zl"
- ]])
+ command('set nowrap')
+ local width = meths.win_get_width(0)
+ local line = '123' .. ('*'):rep(width * 2)
+ local lines = {line, line}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ eq(0, eval('g:scrolled'))
+ feed('zl')
eq(1, eval('g:scrolled'))
end)
- it('is triggered when the window scrolls in insert mode', function()
- source([[
- let height = winheight(0)
- let lines = map(range(height * 2), {_, i -> string(i)})
- call nvim_buf_set_lines(0, 0, -1, v:true, lines)
-
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- call feedkeys("LA\<CR><Esc>", "n")
- ]])
+ it('is triggered by horizontal scrolling from cursor move', function()
+ command('set nowrap')
+ local lines = {'', '', 'Foo'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ meths.win_set_cursor(0, {3, 0})
+ eq(0, eval('g:scrolled'))
+ feed('zl')
+ eq(1, eval('g:scrolled'))
+ feed('zl')
eq(2, eval('g:scrolled'))
+ feed('h')
+ eq(3, eval('g:scrolled'))
end)
- it('is triggered when the window is resized', function()
- source([[
- let g:scrolled = 0
- autocmd WinScrolled * let g:scrolled += 1
- wincmd v
- ]])
+ it('is triggered when the window scrolls in Insert mode', function()
+ local height = meths.win_get_height(0)
+ local lines = {}
+ for i = 1, height * 2 do
+ lines[i] = tostring(i)
+ end
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ feed('L')
+ eq(0, eval('g:scrolled'))
+ feed('A<CR><Esc>')
eq(1, eval('g:scrolled'))
end)
end)
+
+it('closing window in WinScrolled does not cause use-after-free #13265', function()
+ local lines = {'aaa', 'bbb'}
+ meths.buf_set_lines(0, 0, -1, true, lines)
+ command('vsplit')
+ command('autocmd WinScrolled * close')
+ feed('<C-E>')
+ assert_alive()
+end)
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index 93dec9fb35..ca52404d3b 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -10,6 +10,8 @@ local nvim_prog = helpers.nvim_prog
local is_os = helpers.is_os
local retry = helpers.retry
local expect_twostreams = helpers.expect_twostreams
+local assert_alive = helpers.assert_alive
+local pcall_err = helpers.pcall_err
describe('channels', function()
local init = [[
@@ -100,6 +102,38 @@ describe('channels', function()
eq({"notification", "exit", {3,0}}, next_msg())
end)
+ it('can use stdio channel and on_print callback', function()
+ source([[
+ let g:job_opts = {
+ \ 'on_stdout': function('OnEvent'),
+ \ 'on_stderr': function('OnEvent'),
+ \ 'on_exit': function('OnEvent'),
+ \ }
+ ]])
+ meths.set_var("nvim_prog", nvim_prog)
+ meths.set_var("code", [[
+ function! OnStdin(id, data, event) dict
+ echo string([a:id, a:data, a:event])
+ if a:data == ['']
+ quit
+ endif
+ endfunction
+ function! OnPrint(text) dict
+ call chansend(g:x, ['OnPrint:' .. a:text])
+ endfunction
+ let g:x = stdioopen({'on_stdin': funcref('OnStdin'), 'on_print':'OnPrint'})
+ call chansend(x, "hello")
+ ]])
+ command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)")
+ local id = eval("g:id")
+ ok(id > 0)
+
+ eq({ "notification", "stdout", {id, { "hello" } } }, next_msg())
+
+ command("call chansend(id, 'howdy')")
+ eq({"notification", "stdout", {id, {"OnPrint:[1, ['howdy'], 'stdin']"}}}, next_msg())
+ end)
+
local function expect_twoline(id, stream, line1, line2, nobr)
local msg = next_msg()
local joined = nobr and {line1..line2} or {line1, line2}
@@ -282,3 +316,22 @@ describe('channels', function()
eq({"notification", "exit", {id, 1, {''}}}, next_msg())
end)
end)
+
+describe('loopback', function()
+ before_each(function()
+ clear()
+ command("let chan = sockconnect('pipe', v:servername, {'rpc': v:true})")
+ end)
+
+ it('does not crash when sending raw data', function()
+ eq("Vim(call):Can't send raw data to rpc channel",
+ pcall_err(command, "call chansend(chan, 'test')"))
+ assert_alive()
+ end)
+
+ it('are released when closed', function()
+ local chans = eval('len(nvim_list_chans())')
+ command('call chanclose(chan)')
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+end)
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index c68bc18eed..a4d22685e8 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -1,27 +1,34 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_log = helpers.assert_log
+local assert_nolog = helpers.assert_nolog
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local ok = helpers.ok
local feed = helpers.feed
local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
local request = helpers.request
local retry = helpers.retry
local rmdir = helpers.rmdir
+local matches = helpers.matches
local mkdir = helpers.mkdir
local sleep = helpers.sleep
local read_file = helpers.read_file
+local tmpname = helpers.tmpname
local trim = helpers.trim
local currentdir = helpers.funcs.getcwd
local iswin = helpers.iswin
local assert_alive = helpers.assert_alive
+local expect_exit = helpers.expect_exit
+local write_file = helpers.write_file
describe('fileio', function()
before_each(function()
end)
after_each(function()
- command(':qall!')
+ expect_exit(command, ':qall!')
os.remove('Xtest_startup_shada')
os.remove('Xtest_startup_file1')
os.remove('Xtest_startup_file1~')
@@ -139,3 +146,69 @@ describe('fileio', function()
end)
end)
+describe('tmpdir', function()
+ local tmproot_pat = [=[.*[/\\]nvim%.[^/\\]+]=]
+ local testlog = 'Xtest_tmpdir_log'
+ local faketmp
+
+ before_each(function()
+ -- Fake /tmp dir so that we can mess it up.
+ faketmp = tmpname()
+ os.remove(faketmp)
+ mkdir(faketmp)
+ end)
+
+ after_each(function()
+ expect_exit(command, ':qall!')
+ os.remove(testlog)
+ end)
+
+ it('failure modes', function()
+ clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } })
+ assert_nolog('tempdir is not a directory', testlog)
+ assert_nolog('tempdir has invalid permissions', testlog)
+
+ -- Tempfiles typically look like: "…/nvim.<user>/xxx/0".
+ -- - "…/nvim.<user>/xxx/" is the per-process tmpdir, not shared with other Nvims.
+ -- - "…/nvim.<user>/" is the tmpdir root, shared by all Nvims (normally).
+ local tmproot = (funcs.tempname()):match(tmproot_pat)
+ ok(tmproot:len() > 4, 'tmproot like "nvim.foo"', tmproot)
+
+ -- Test how Nvim handles invalid tmpdir root (by hostile users or accidents).
+ --
+ -- "…/nvim.<user>/" is not a directory:
+ expect_exit(command, ':qall!')
+ rmdir(tmproot)
+ write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it.
+ clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } })
+ matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
+ -- Assert that broken tmpdir root was handled.
+ retry(nil, 1000, function()
+ assert_log('tempdir root not a directory', testlog, 100)
+ end)
+
+ -- "…/nvim.<user>/" has wrong permissions:
+ if iswin() then
+ return -- TODO(justinmk): need setfperm/getfperm on Windows. #8244
+ end
+ os.remove(testlog)
+ os.remove(tmproot)
+ mkdir(tmproot)
+ funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it.
+ clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } })
+ matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
+ -- Assert that broken tmpdir root was handled.
+ retry(nil, 1000, function()
+ assert_log('tempdir root has invalid permissions', testlog, 100)
+ end)
+ end)
+
+ it('too long', function()
+ local bigname = ('%s/%s'):format(faketmp, ('x'):rep(666))
+ mkdir(bigname)
+ clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=bigname, } })
+ matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir().
+ local len = (funcs.tempname()):len()
+ ok(len > 4 and len < 256, '4 < len < 256', tostring(len))
+ end)
+end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 5e127bce26..04fbb807be 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -1,9 +1,9 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, eq, eval, exc_exec, feed_command, feed, insert, neq, next_msg, nvim,
- nvim_dir, ok, source, write_file, mkdir, rmdir = helpers.clear,
+ testprg, ok, source, write_file, mkdir, rmdir = helpers.clear,
helpers.eq, helpers.eval, helpers.exc_exec, helpers.feed_command, helpers.feed,
helpers.insert, helpers.neq, helpers.next_msg, helpers.nvim,
- helpers.nvim_dir, helpers.ok, helpers.source,
+ helpers.testprg, helpers.ok, helpers.source,
helpers.write_file, helpers.mkdir, helpers.rmdir
local assert_alive = helpers.assert_alive
local command = helpers.command
@@ -16,6 +16,7 @@ local poke_eventloop = helpers.poke_eventloop
local iswin = helpers.iswin
local get_pathsep = helpers.get_pathsep
local pathroot = helpers.pathroot
+local exec_lua = helpers.exec_lua
local nvim_set = helpers.nvim_set
local expect_twostreams = helpers.expect_twostreams
local expect_msg_seq = helpers.expect_msg_seq
@@ -72,12 +73,20 @@ describe('jobs', function()
nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
end
- expect_msg_seq({
- {'notification', 'stdout', {0, {'hello world abc', ''}}},
- })
+ expect_msg_seq(
+ {
+ {'notification', 'stdout', {0, {'hello world abc'}}},
+ {'notification', 'stdout', {0, {'', ''}}},
+ },
+ {
+ {'notification', 'stdout', {0, {'hello world abc', ''}}},
+ {'notification', 'stdout', {0, {''}}}
+ }
+ )
end)
it('append environment with pty #env', function()
+ if helpers.pending_win32(pending) then return end
nvim('command', "let $VAR = 'abc'")
nvim('command', "let $TOTO = 'goodbye world'")
nvim('command', "let g:job_opts.pty = v:true")
@@ -87,9 +96,16 @@ describe('jobs', function()
else
nvim('command', [[call jobstart('echo $TOTO $VAR', g:job_opts)]])
end
- expect_msg_seq({
- {'notification', 'stdout', {0, {'hello world abc', ''}}},
- })
+ expect_msg_seq(
+ {
+ {'notification', 'stdout', {0, {'hello world abc'}}},
+ {'notification', 'stdout', {0, {'', ''}}},
+ },
+ {
+ {'notification', 'stdout', {0, {'hello world abc', ''}}},
+ {'notification', 'stdout', {0, {''}}}
+ }
+ )
end)
it('replace environment #env', function()
@@ -207,7 +223,7 @@ describe('jobs', function()
ok(string.find(err, "E475: Invalid argument: expected valid directory$") ~= nil)
end)
- it('produces error when using non-executable `cwd`', function()
+ it('error on non-executable `cwd`', function()
if iswin() then return end -- N/A for Windows
local dir = 'Xtest_not_executable_dir'
@@ -248,7 +264,7 @@ describe('jobs', function()
eq({'notification', 'exit', {0, 0}}, next_msg())
end)
- it('allows interactive commands', function()
+ it('interactive commands', function()
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
neq(0, eval('j'))
nvim('command', 'call jobsend(j, "abc\\n")')
@@ -294,13 +310,7 @@ describe('jobs', function()
nvim('command', "call jobstop(j)")
end)
- it("will not buffer data if it doesn't end in newlines", function()
- if helpers.isCI('travis') and os.getenv('CC') == 'gcc-4.9'
- and helpers.is_os('mac') then
- -- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
- pending("[Hangs on Travis macOS. #5002]")
- end
-
+ it("emits partial lines (does NOT buffer data lacking newlines)", function()
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobsend(j, "abc\\nxyz")')
eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg())
@@ -383,7 +393,7 @@ describe('jobs', function()
eq(NIL, meths.get_proc(pid))
end)
- it("do not survive the exit of nvim", function()
+ it("disposed on Nvim exit", function()
-- use sleep, which doesn't die on stdin close
nvim('command', "let g:j = jobstart(has('win32') ? ['ping', '-n', '1001', '127.0.0.1'] : ['sleep', '1000'], g:job_opts)")
local pid = eval('jobpid(g:j)')
@@ -651,6 +661,44 @@ describe('jobs', function()
)
end)
+ it('jobstart() environment: $NVIM, $NVIM_LISTEN_ADDRESS #11009', function()
+ local function get_env_in_child_job(envname, env)
+ return exec_lua([[
+ local envname, env = ...
+ local join = function(s) return vim.fn.join(s, '') end
+ local stdout = {}
+ local stderr = {}
+ local opt = {
+ env = env,
+ stdout_buffered = true,
+ stderr_buffered = true,
+ on_stderr = function(chan, data, name) stderr = data end,
+ on_stdout = function(chan, data, name) stdout = data end,
+ }
+ local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1',( '+echo "%s="..getenv("%s")'):format(envname, envname), '+qa!' }, opt)
+ vim.fn.jobwait({ j1 }, 10000)
+ return join({ join(stdout), join(stderr) })
+ ]],
+ envname,
+ env)
+ end
+
+ local addr = eval('v:servername')
+ ok((addr):len() > 0)
+ -- $NVIM is _not_ defined in the top-level Nvim process.
+ eq('', eval('$NVIM'))
+ -- jobstart() shares its v:servername with the child via $NVIM.
+ eq('NVIM='..addr, get_env_in_child_job('NVIM'))
+ -- $NVIM_LISTEN_ADDRESS is unset by server_init in the child.
+ eq('NVIM_LISTEN_ADDRESS=null', get_env_in_child_job('NVIM_LISTEN_ADDRESS'))
+ eq('NVIM_LISTEN_ADDRESS=null', get_env_in_child_job('NVIM_LISTEN_ADDRESS',
+ { NVIM_LISTEN_ADDRESS='Xtest_jobstart_env' }))
+ -- User can explicitly set $NVIM_LOG_FILE, $VIM, $VIMRUNTIME.
+ eq('NVIM_LOG_FILE=Xtest_jobstart_env',
+ get_env_in_child_job('NVIM_LOG_FILE', { NVIM_LOG_FILE='Xtest_jobstart_env' }))
+ os.remove('Xtest_jobstart_env')
+ end)
+
describe('jobwait', function()
before_each(function()
if iswin() then
@@ -1009,8 +1057,7 @@ describe('jobs', function()
return a:data
endfunction
]])
- local ext = iswin() and '.exe' or ''
- insert(nvim_dir..'/tty-test'..ext) -- Full path to tty-test.
+ insert(testprg('tty-test'))
nvim('command', 'let g:job_opts.pty = 1')
nvim('command', 'let exec = [expand("<cfile>:p")]')
nvim('command', "let j = jobstart(exec, g:job_opts)")
@@ -1043,7 +1090,7 @@ describe('jobs', function()
local other_jobid = eval("jobstart(['cat', '-'], g:job_opts)")
local other_pid = eval('jobpid(' .. other_jobid .. ')')
- -- Other job doesn't block first job from recieving SIGHUP on jobclose()
+ -- Other job doesn't block first job from receiving SIGHUP on jobclose()
command('call jobclose(j)')
-- Have to wait so that the SIGHUP can be processed by tty-test on time.
-- Can't wait for the next message in case this test fails, if it fails
diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua
new file mode 100644
index 0000000000..3b1ccd9559
--- /dev/null
+++ b/test/functional/core/log_spec.lua
@@ -0,0 +1,57 @@
+local helpers = require('test.functional.helpers')(after_each)
+local assert_log = helpers.assert_log
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local expect_exit = helpers.expect_exit
+local request = helpers.request
+local retry = helpers.retry
+
+describe('log', function()
+ local testlog = 'Xtest_logging'
+
+ after_each(function()
+ expect_exit(command, 'qa!')
+ os.remove(testlog)
+ end)
+
+ it('skipped before log_init', function()
+ -- This test is for _visibility_: adjust as needed, after checking for regression.
+ --
+ -- During startup some components may try to log before logging is setup.
+ -- That should be uncommon (ideally never)--and if there are MANY such
+ -- calls, that needs investigation.
+ clear()
+ eq(0, request('nvim__stats').log_skip)
+ clear{env={CDPATH='~doesnotexist'}}
+ assert(request('nvim__stats').log_skip <= 13)
+ end)
+
+ it('messages are formatted with name or test id', function()
+ -- Examples:
+ -- ERR 2022-05-29T12:30:03.800 T2 log_init:110: test log message
+ -- ERR 2022-05-29T12:30:03.814 T2/child log_init:110: test log message
+
+ clear({env={
+ NVIM_LOG_FILE=testlog,
+ -- TODO: remove this after nvim_log #7062 is merged.
+ __NVIM_TEST_LOG='1'
+ }})
+
+ local tid = _G._nvim_test_id
+ retry(nil, 1000, function()
+ assert_log(tid..'%.%d+%.%d +server_init:%d+: test log message', testlog, 100)
+ end)
+
+ exec_lua([[
+ local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1', '+foochild', '+qa!' }, vim.empty_dict())
+ vim.fn.jobwait({ j1 }, 10000)
+ ]])
+
+ -- Child Nvim spawned by jobstart() appends "/c" to parent name.
+ retry(nil, 1000, function()
+ assert_log('%.%d+%.%d/c +server_init:%d+: test log message', testlog, 100)
+ end)
+ end)
+end)
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index 37a9f0b836..f6fb859ccc 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -52,11 +52,15 @@ describe('Command-line option', function()
if helpers.pending_win32(pending) then return end
local screen = Screen.new(40, 8)
screen:attach()
- funcs.termopen({
+ local args = {
nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE',
- '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
- '-s', '-'
- })
+ '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix',
+ '-s', '-'
+ }
+
+ -- Need to explicitly pipe to stdin so that the embedded Nvim instance doesn't try to read
+ -- data from the terminal #18181
+ funcs.termopen(string.format([[echo "" | %s]], table.concat(args, " ")))
screen:expect([[
^ |
{1:~ }|
diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua
new file mode 100644
index 0000000000..d7bd075eb2
--- /dev/null
+++ b/test/functional/core/remote_spec.lua
@@ -0,0 +1,142 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local expect = helpers.expect
+local funcs = helpers.funcs
+local insert = helpers.insert
+local meths = helpers.meths
+local new_argv = helpers.new_argv
+local neq = helpers.neq
+local set_session = helpers.set_session
+local spawn = helpers.spawn
+local tmpname = helpers.tmpname
+local write_file = helpers.write_file
+
+describe('Remote', function()
+ local fname, other_fname
+ local contents = 'The call is coming from outside the process'
+ local other_contents = "A second file's contents"
+
+ before_each(function()
+ fname = tmpname() .. ' with spaces in the filename'
+ other_fname = tmpname()
+ write_file(fname, contents)
+ write_file(other_fname, other_contents)
+ end)
+
+ describe('connect to server and', function()
+ local server
+ before_each(function()
+ server = spawn(new_argv(), true)
+ set_session(server)
+ end)
+
+ after_each(function()
+ server:close()
+ end)
+
+ local function run_remote(...)
+ set_session(server)
+ local addr = funcs.serverlist()[1]
+ local client_argv = new_argv({args={'--server', addr, ...}})
+
+ -- 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.
+ local client_starter = spawn(new_argv(), false, nil, true)
+ set_session(client_starter)
+ local client_job_id = funcs.jobstart(client_argv)
+ eq({ 0 }, funcs.jobwait({client_job_id}))
+ client_starter:close()
+ set_session(server)
+ end
+
+ it('edit a single file', function()
+ run_remote('--remote', fname)
+ expect(contents)
+ eq(2, #funcs.getbufinfo())
+ end)
+
+ it('tab edit a single file with a non-changed buffer', function()
+ run_remote('--remote-tab', fname)
+ expect(contents)
+ eq(1, #funcs.gettabinfo())
+ end)
+
+ it('tab edit a single file with a changed buffer', function()
+ insert('hello')
+ run_remote('--remote-tab', fname)
+ expect(contents)
+ eq(2, #funcs.gettabinfo())
+ end)
+
+ it('edit multiple files', function()
+ run_remote('--remote', fname, other_fname)
+ expect(contents)
+ command('next')
+ expect(other_contents)
+ eq(3, #funcs.getbufinfo())
+ end)
+
+ it('send keys', function()
+ run_remote('--remote-send', ':edit '..fname..'<CR><C-W>v')
+ expect(contents)
+ eq(2, #funcs.getwininfo())
+ -- Only a single buffer as we're using edit and not drop like --remote does
+ eq(1, #funcs.getbufinfo())
+ end)
+
+ it('evaluate expressions', function()
+ run_remote('--remote-expr', 'setline(1, "Yo")')
+ expect('Yo')
+ end)
+ end)
+
+ it('creates server if not found', function()
+ clear('--remote', fname)
+ expect(contents)
+ eq(1, #funcs.getbufinfo())
+ -- Since we didn't pass silent, we should get a complaint
+ neq(nil, string.find(meths.exec('messages', true), 'E247'))
+ end)
+
+ it('creates server if not found with tabs', function()
+ clear('--remote-tab-silent', fname, other_fname)
+ expect(contents)
+ eq(2, #funcs.gettabinfo())
+ eq(2, #funcs.getbufinfo())
+ -- We passed silent, so no message should be issued about the server not being found
+ eq(nil, string.find(meths.exec('messages', true), 'E247'))
+ end)
+
+ pending('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()
+ local bogus_job_id = funcs.jobstart(bogus_argv)
+ eq({2}, funcs.jobwait({bogus_job_id}))
+ end
+ it('bogus subcommand', function()
+ run_and_check_exit_code('--remote-bogus')
+ end)
+
+ it('send without server', function()
+ run_and_check_exit_code('--remote-send', 'i')
+ end)
+
+ it('expr without server', function()
+ run_and_check_exit_code('--remote-expr', 'setline(1, "Yo")')
+ end)
+ it('wait subcommand', function()
+ run_and_check_exit_code('--remote-wait', fname)
+ end)
+ end)
+end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 2fa84e8313..4f9df4010e 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_alive = helpers.assert_alive
+local assert_log = helpers.assert_log
local clear = helpers.clear
local command = helpers.command
local ok = helpers.ok
@@ -23,6 +24,29 @@ local iswin = helpers.iswin
local startswith = helpers.startswith
local write_file = helpers.write_file
local meths = helpers.meths
+local alter_slashes = helpers.alter_slashes
+
+local testfile = 'Xtest_startuptime'
+after_each(function()
+ os.remove(testfile)
+end)
+
+describe('startup', function()
+ it('--clean', function()
+ clear()
+ ok(string.find(alter_slashes(meths.get_option('runtimepath')), funcs.stdpath('config'), 1, true) ~= nil)
+ clear('--clean')
+ ok(string.find(alter_slashes(meths.get_option('runtimepath')), funcs.stdpath('config'), 1, true) == nil)
+ end)
+
+ it('--startuptime', function()
+ clear({ args = {'--startuptime', testfile}})
+ retry(nil, 1000, function()
+ assert_log('sourcing', testfile, 100)
+ assert_log("require%('vim%._editor'%)", testfile, 100)
+ end)
+ end)
+end)
describe('startup', function()
before_each(function()
@@ -255,6 +279,7 @@ describe('startup', function()
it('does not crash when expanding cdpath during early_init', function()
clear{env={CDPATH='~doesnotexist'}}
+ assert_alive()
eq(',~doesnotexist', eval('&cdpath'))
end)
@@ -355,7 +380,7 @@ describe('startup', function()
end)
it("handles :packadd during startup", function()
- -- control group: opt/bonus is not availabe by default
+ -- control group: opt/bonus is not available by default
pack_clear [[
try
let g:x = bonus#secret()
@@ -398,7 +423,8 @@ describe('startup', function()
eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
local rtp = meths.get_option'rtp'
- ok(startswith(rtp, 'test/functional/fixtures/nvim,test/functional/fixtures/pack/*/start/*,test/functional/fixtures/start/*,test/functional/fixtures,test/functional/fixtures/middle,'), 'rtp='..rtp)
+ ok(startswith(rtp, 'test/functional/fixtures/nvim,test/functional/fixtures/pack/*/start/*,test/functional/fixtures/start/*,test/functional/fixtures,test/functional/fixtures/middle,'),
+ 'startswith(…)', 'rtp='..rtp)
end)
it("handles the correct order with opt packages and after/", function()
@@ -492,22 +518,24 @@ describe('sysinit', function()
it('fixed hang issue with -D (#12647)', function()
local screen
- screen = Screen.new(60, 6)
+ screen = Screen.new(60, 7)
screen:attach()
command([[let g:id = termopen('"]]..nvim_prog..
[[" -u NONE -i NONE --cmd "set noruler" -D')]])
screen:expect([[
^ |
Entering Debug mode. Type "cont" to continue. |
- cmd: augroup nvim_terminal |
+ nvim_exec() |
+ cmd: aunmenu * |
> |
- <" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All|
+ <" -u NONE -i NONE --cmd "set noruler" -D 1,1 All|
|
]])
command([[call chansend(g:id, "cont\n")]])
screen:expect([[
^ |
~ |
+ ~ |
[No Name] |
|
<" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All|
@@ -516,13 +544,6 @@ describe('sysinit', function()
end)
end)
-describe('clean', function()
- clear()
- ok(string.find(meths.get_option('runtimepath'), funcs.stdpath('config'), 1, true) ~= nil)
- clear('--clean')
- ok(string.find(meths.get_option('runtimepath'), funcs.stdpath('config'), 1, true) == nil)
-end)
-
describe('user config init', function()
local xhome = 'Xhome'
local pathsep = helpers.get_pathsep()
@@ -577,7 +598,7 @@ describe('user config init', function()
it('loads default lua config, but shows an error', function()
clear{ args_rm={'-u'}, env=xenv }
- feed('<cr>') -- confirm "Conflicting config ..." message
+ feed('<cr><c-c>') -- Dismiss "Conflicting config …" message.
eq(1, eval('g:lua_rc'))
matches('^E5422: Conflicting configs', meths.exec('messages', true))
end)
@@ -629,13 +650,13 @@ describe('runtime:', function()
eq(2, eval('g:lua_plugin'))
-- Check if plugin_file_path is listed in :scriptname
local scripts = meths.exec(':scriptnames', true)
- assert.Truthy(scripts:find(plugin_file_path))
+ assert(scripts:find(plugin_file_path))
-- Check if plugin_file_path is listed in startup profile
local profile_reader = io.open(profiler_file, 'r')
local profile_log = profile_reader:read('*a')
profile_reader:close()
- assert.Truthy(profile_log :find(plugin_file_path))
+ assert(profile_log:find(plugin_file_path))
os.remove(profiler_file)
rmdir(plugin_path)
diff --git a/test/functional/editor/K_spec.lua b/test/functional/editor/K_spec.lua
index 40f36491e4..8ad81ac3d6 100644
--- a/test/functional/editor/K_spec.lua
+++ b/test/functional/editor/K_spec.lua
@@ -33,6 +33,29 @@ describe('K', function()
feed('i'..test_file..'<ESC>K')
retry(nil, nil, function() eq(1, eval('filereadable("'..test_file..'")')) end)
eq({'fnord'}, eval("readfile('"..test_file.."')"))
+ -- Confirm that Neovim is still in terminal mode after K is pressed (#16692).
+ helpers.sleep(500)
+ eq('t', eval('mode()'))
+ feed('<space>') -- Any key, not just <space>, can be used here to escape.
+ eq('n', eval('mode()'))
+ end)
+
+ it("<esc> kills the buffer for a running 'keywordprg' command", function()
+ helpers.source('set keywordprg=less')
+ eval('writefile(["hello", "world"], "' .. test_file .. '")')
+ feed('i' .. test_file .. '<esc>K')
+ eq('t', eval('mode()'))
+ -- Confirm that an arbitrary keypress doesn't escape (i.e., the process is
+ -- still running). If the process were no longer running, an arbitrary
+ -- keypress would escape.
+ helpers.sleep(500)
+ feed('<space>')
+ eq('t', eval('mode()'))
+ -- Confirm that <esc> kills the buffer for the running command.
+ local bufnr = eval('bufnr()')
+ feed('<esc>')
+ eq('n', eval('mode()'))
+ helpers.neq(bufnr, eval('bufnr()'))
end)
end)
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index befad29922..e27da0947f 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -1193,4 +1193,64 @@ describe('completion', function()
eq('foobar', eval('g:word'))
feed('<esc>')
end)
+
+ it('is stopped by :stopinsert from timer #12976', function()
+ screen:try_resize(32,14)
+ command([[call setline(1, ['hello', 'hullo', 'heeee', ''])]])
+ feed('Gah<c-x><c-n>')
+ screen:expect([[
+ hello |
+ hullo |
+ heeee |
+ hello^ |
+ {2:hello }{0: }|
+ {1:hullo }{0: }|
+ {1:heeee }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {3:-- }{4:match 1 of 3} |
+ ]])
+ command([[call timer_start(100, { -> execute('stopinsert') })]])
+ helpers.sleep(200)
+ feed('k') -- cursor should move up in Normal mode
+ screen:expect([[
+ hello |
+ hullo |
+ heee^e |
+ hello |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('does not crash if text is changed by first call to complete function #17489', function()
+ source([[
+ func Complete(findstart, base) abort
+ if a:findstart
+ let col = col('.')
+ call complete_add('#')
+ return col - 1
+ else
+ return []
+ endif
+ endfunc
+
+ set completeopt=longest
+ set completefunc=Complete
+ ]])
+ feed('ifoo#<C-X><C-U>')
+ assert_alive()
+ end)
end)
diff --git a/test/functional/ex_cmds/ctrl_c_spec.lua b/test/functional/editor/ctrl_c_spec.lua
index f65d9f0d01..60131bf2a4 100644
--- a/test/functional/ex_cmds/ctrl_c_spec.lua
+++ b/test/functional/editor/ctrl_c_spec.lua
@@ -2,16 +2,20 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, source = helpers.clear, helpers.feed, helpers.source
local command = helpers.command
+local sleep = helpers.sleep
describe("CTRL-C (mapped)", function()
+ local screen
+
before_each(function()
clear()
+ screen = Screen.new(52, 6)
+ screen:attach()
end)
it("interrupts :global", function()
-- Crashes luajit.
- if helpers.skip_fragile(pending,
- helpers.isCI('travis') or helpers.isCI('appveyor')) then
+ if helpers.skip_fragile(pending) then
return
end
@@ -21,14 +25,6 @@ describe("CTRL-C (mapped)", function()
]])
command("silent edit! test/functional/fixtures/bigfile.txt")
- local screen = Screen.new(52, 6)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {foreground = Screen.colors.White,
- background = Screen.colors.Red},
- [1] = {bold = true,
- foreground = Screen.colors.SeaGreen}
- })
screen:expect([[
^0000;<control>;Cc;0;BN;;;;;N;NULL;;;; |
@@ -57,4 +53,42 @@ describe("CTRL-C (mapped)", function()
end
end
end)
+
+ it('interrupts :sleep', function()
+ command('nnoremap <C-C> <Nop>')
+ feed(':sleep 100<CR>')
+ -- wait for :sleep to start
+ sleep(10)
+ feed('foo<C-C>')
+ -- wait for input buffer to be flushed
+ sleep(10)
+ feed('i')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ end)
+
+ it('interrupts recursive mapping', function()
+ command('nnoremap <C-C> <Nop>')
+ command('nmap <F2> <Ignore><F2>')
+ feed('<F2>')
+ sleep(10)
+ feed('foo<C-C>')
+ -- wait for input buffer to be flushed
+ sleep(10)
+ feed('i')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ end)
end)
diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua
index d09c20f226..63f522fe6e 100644
--- a/test/functional/editor/jump_spec.lua
+++ b/test/functional/editor/jump_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
@@ -7,6 +8,7 @@ local funcs = helpers.funcs
local feed = helpers.feed
local exec_capture = helpers.exec_capture
local write_file = helpers.write_file
+local curbufmeths = helpers.curbufmeths
describe('jumplist', function()
local fname1 = 'Xtest-functional-normal-jump'
@@ -137,3 +139,144 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
exec_capture('jumps'))
end)
end)
+
+describe("jumpoptions=view", function()
+ local file1 = 'Xtestfile-functional-editor-jumps'
+ local file2 = 'Xtestfile-functional-editor-jumps-2'
+ local function content()
+ local c = {}
+ for i=1,30 do
+ c[i] = i .. " line"
+ end
+ return table.concat(c, "\n")
+ end
+ before_each(function()
+ clear()
+ write_file(file1, content(), false, false)
+ write_file(file2, content(), false, false)
+ command('set jumpoptions=view')
+ end)
+ after_each(function()
+ os.remove(file1)
+ os.remove(file2)
+ end)
+
+ it('restores the view', function()
+ local screen = Screen.new(5, 8)
+ screen:attach()
+ command("edit " .. file1)
+ feed("12Gztj")
+ feed("gg<C-o>")
+ screen:expect([[
+ 12 line |
+ ^13 line |
+ 14 line |
+ 15 line |
+ 16 line |
+ 17 line |
+ 18 line |
+ |
+ ]])
+ end)
+
+ it('restores the view across files', function()
+ local screen = Screen.new(5, 5)
+ screen:attach()
+ command("args " .. file1 .. " " .. file2)
+ feed("12Gzt")
+ command("next")
+ feed("G")
+ screen:expect([[
+ 27 line |
+ 28 line |
+ 29 line |
+ ^30 line |
+ |
+ ]])
+ feed("<C-o><C-o>")
+ screen:expect([[
+ ^12 line |
+ 13 line |
+ 14 line |
+ 15 line |
+ |
+ ]])
+ end)
+
+ it('restores the view across files with <C-^>', function()
+ local screen = Screen.new(5, 5)
+ screen:attach()
+ command("args " .. file1 .. " " .. file2)
+ feed("12Gzt")
+ command("next")
+ feed("G")
+ screen:expect([[
+ 27 line |
+ 28 line |
+ 29 line |
+ ^30 line |
+ |
+ ]])
+ feed("<C-^>")
+ screen:expect([[
+ ^12 line |
+ 13 line |
+ 14 line |
+ 15 line |
+ |
+ ]])
+ end)
+
+ it('falls back to standard behavior when view can\'t be recovered', function()
+ local screen = Screen.new(5, 8)
+ screen:attach()
+ command("edit " .. file1)
+ feed("7GzbG")
+ curbufmeths.set_lines(0, 2, true, {})
+ -- Move to line 7, and set it as the last line visible on the view with zb, meaning to recover
+ -- the view it needs to put the cursor 7 lines from the top line. Then go to the end of the
+ -- file, delete 2 lines before line 7, meaning the jump/mark is moved 2 lines up to line 5.
+ -- Therefore when trying to jump back to it it's not possible to set a 7 line offset from the
+ -- mark position to the top line, since there's only 5 lines from the mark position to line 0.
+ -- Therefore falls back to standard behavior which is centering the view/line.
+ feed("<C-o>")
+ screen:expect([[
+ 4 line |
+ 5 line |
+ 6 line |
+ ^7 line |
+ 8 line |
+ 9 line |
+ 10 line |
+ |
+ ]])
+ end)
+
+ it('falls back to standard behavior for a mark without a view', function()
+ local screen = Screen.new(5, 8)
+ screen:attach()
+ command('edit ' .. file1)
+ feed('10ggzzvwy')
+ screen:expect([[
+ 7 line |
+ 8 line |
+ 9 line |
+ ^10 line |
+ 11 line |
+ 12 line |
+ 13 line |
+ |
+ ]])
+ feed('`]')
+ screen:expect([[
+ 7 line |
+ 8 line |
+ 9 line |
+ 10 ^line |
+ 11 line |
+ 12 line |
+ 13 line |
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/editor/langmap_spec.lua b/test/functional/editor/langmap_spec.lua
index e4349a22e7..b1070ecddc 100644
--- a/test/functional/editor/langmap_spec.lua
+++ b/test/functional/editor/langmap_spec.lua
@@ -30,7 +30,7 @@ describe("'langmap'", function()
command('nmapclear')
end)
it("'langnoremap' is by default ON", function()
- eq(eval('&langnoremap'), 1)
+ eq(1, eval('&langnoremap'))
end)
it("Results of maps are not converted when 'langnoremap' ON.",
function()
@@ -71,19 +71,19 @@ describe("'langmap'", function()
feed('<C-w>s')
local origwin = curwin()
feed('<C-w>i')
- neq(curwin(), origwin)
+ neq(origwin, curwin())
-- Works when setting a mark
feed('yy3p3gg0mwgg0mi')
- eq(call('getpos', "'i"), {0, 3, 1, 0})
- eq(call('getpos', "'w"), {0, 1, 1, 0})
+ eq({0, 3, 1, 0}, call('getpos', "'i"))
+ eq({0, 1, 1, 0}, call('getpos', "'w"))
feed('3dd')
-- Works when moving to a mark
feed("'i")
- eq(call('getpos', '.'), {0, 1, 1, 0})
+ eq({0, 1, 1, 0}, call('getpos', '.'))
-- Works when selecting a register
feed('qillqqwhhq')
- eq(eval('@i'), 'hh')
- eq(eval('@w'), 'll')
+ eq('hh', eval('@i'))
+ eq('ll', eval('@w'))
feed('a<C-r>i<esc>')
expect('illii www')
feed('"ip')
@@ -107,7 +107,7 @@ describe("'langmap'", function()
expect('wwi www')
feed('u@a')
expect('wwi www')
- eq(eval('@a'), ':s/i/w/gc\ryyn')
+ eq(':s/i/w/gc\ryyn', eval('@a'))
end)
it('insert-mode CTRL-G', function()
command('set langmap=jk,kj')
@@ -127,7 +127,7 @@ describe("'langmap'", function()
helhellolo
helxlo
hello]])
- eq(eval('@a'), 'gg3|ahellojx')
+ eq('gg3|ahellojx', eval('@a'))
end)
it('command-line CTRL-\\', function()
command('set langmap=en,ne')
@@ -145,8 +145,8 @@ describe("'langmap'", function()
set langmap=ij,ji
]])
feed(':let <C-R>i=1<CR>')
- eq(eval('i_value'), 1)
- eq(eval('j_value'), 0)
+ eq(1, eval('i_value'))
+ eq(0, eval('j_value'))
end)
-- it('-- More -- prompt', function()
-- -- The 'b' 'j' 'd' 'f' commands at the -- More -- prompt
@@ -186,17 +186,17 @@ describe("'langmap'", function()
nnoremap x :call Map()<CR>
]])
feed('x1<CR>')
- eq(eval('gotten_one'), 1)
+ eq(1, eval('gotten_one'))
command('let g:gotten_one = 0')
feed_command('call Map()')
feed('1<CR>')
- eq(eval('gotten_one'), 1)
+ eq(1, eval('gotten_one'))
end)
end)
it('conversions are not applied during setreg()',
function()
call('setreg', 'i', 'ww')
- eq(eval('@i'), 'ww')
+ eq('ww', eval('@i'))
end)
it('conversions not applied in insert mode', function()
feed('aiiiwww')
@@ -213,11 +213,11 @@ describe("'langmap'", function()
iii]])
end)
- local function testrecording(command_string, expect_string, setup_function)
+ local function testrecording(command_string, expect_string, setup_function, expect_macro)
if setup_function then setup_function() end
feed('qa' .. command_string .. 'q')
expect(expect_string)
- eq(helpers.funcs.nvim_replace_termcodes(command_string, true, true, true),
+ eq(expect_macro or helpers.funcs.nvim_replace_termcodes(command_string, true, true, true),
eval('@a'))
if setup_function then setup_function() end
-- n.b. may need nvim_replace_termcodes() here.
@@ -273,8 +273,8 @@ describe("'langmap'", function()
it('treats control modified keys as characters', function()
command('nnoremap <C-w> iw<esc>')
command('nnoremap <C-i> ii<esc>')
- testrecording('<C-w>', 'whello', local_setup)
- testrecording('<C-i>', 'ihello', local_setup)
+ testrecording('<C-w>', 'whello', local_setup, eval([["\<*C-w>"]]))
+ testrecording('<C-i>', 'ihello', local_setup, eval([["\<*C-i>"]]))
end)
end)
diff --git a/test/functional/editor/macro_spec.lua b/test/functional/editor/macro_spec.lua
index c0c9256af2..53be7dcc62 100644
--- a/test/functional/editor/macro_spec.lua
+++ b/test/functional/editor/macro_spec.lua
@@ -6,28 +6,31 @@ local feed = helpers.feed
local clear = helpers.clear
local expect = helpers.expect
local command = helpers.command
+local funcs = helpers.funcs
+local meths = helpers.meths
local insert = helpers.insert
local curbufmeths = helpers.curbufmeths
+before_each(clear)
+
describe('macros', function()
- before_each(clear)
it('can be recorded and replayed', function()
feed('qiahello<esc>q')
expect('hello')
- eq(eval('@i'), 'ahello')
+ eq('ahello', eval('@i'))
feed('@i')
expect('hellohello')
- eq(eval('@i'), 'ahello')
+ eq('ahello', eval('@i'))
end)
it('applies maps', function()
command('imap x l')
command('nmap l a')
feed('qilxxx<esc>q')
expect('lll')
- eq(eval('@i'), 'lxxx')
+ eq('lxxx', eval('@i'))
feed('@i')
expect('llllll')
- eq(eval('@i'), 'lxxx')
+ eq('lxxx', eval('@i'))
end)
it('can be replayed with Q', function()
@@ -47,9 +50,47 @@ hello]]
end)
end)
-describe('reg_recorded()', function()
- before_each(clear)
+describe('immediately after a macro has finished executing,', function()
+ before_each(function()
+ command([[let @a = 'gg0']])
+ end)
+
+ describe('reg_executing() from RPC returns an empty string', function()
+ it('if the macro does not end with a <Nop> mapping', function()
+ feed('@a')
+ eq('', funcs.reg_executing())
+ end)
+
+ it('if the macro ends with a <Nop> mapping', function()
+ command('nnoremap 0 <Nop>')
+ feed('@a')
+ eq('', funcs.reg_executing())
+ end)
+ end)
+ describe('characters from a mapping are not treated as a part of the macro #18015', function()
+ before_each(function()
+ command('nnoremap s qa')
+ end)
+
+ it('if the macro does not end with a <Nop> mapping', function()
+ feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op
+ eq({mode = 'n', blocking = false}, meths.get_mode())
+ expect('')
+ eq('', eval('@a'))
+ end)
+
+ it('if the macro ends with a <Nop> mapping', function()
+ command('nnoremap 0 <Nop>')
+ feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op
+ eq({mode = 'n', blocking = false}, meths.get_mode())
+ expect('')
+ eq('', eval('@a'))
+ end)
+ end)
+end)
+
+describe('reg_recorded()', function()
it('returns the correct value', function()
feed [[qqyyq]]
eq('q', eval('reg_recorded()'))
diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua
new file mode 100644
index 0000000000..1eb76aa628
--- /dev/null
+++ b/test/functional/editor/mark_spec.lua
@@ -0,0 +1,401 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local meths = helpers.meths
+local curbufmeths = helpers.curbufmeths
+local clear = helpers.clear
+local command = helpers.command
+local funcs = helpers.funcs
+local eq = helpers.eq
+local feed = helpers.feed
+local write_file = helpers.write_file
+local pcall_err = helpers.pcall_err
+local cursor = function() return helpers.meths.win_get_cursor(0) end
+
+describe('named marks', function()
+ local file1 = 'Xtestfile-functional-editor-marks'
+ local file2 = 'Xtestfile-functional-editor-marks-2'
+ before_each(function()
+ clear()
+ write_file(file1, '1test1\n1test2\n1test3\n1test4', false, false)
+ write_file(file2, '2test1\n2test2\n2test3\n2test4', false, false)
+ end)
+ after_each(function()
+ os.remove(file1)
+ os.remove(file2)
+ end)
+
+
+ it("can be set", function()
+ command("edit " .. file1)
+ command("mark a")
+ eq({1, 0}, curbufmeths.get_mark("a"))
+ feed("jmb")
+ eq({2, 0}, curbufmeths.get_mark("b"))
+ feed("jmB")
+ eq({3, 0}, curbufmeths.get_mark("B"))
+ command("4kc")
+ eq({4, 0}, curbufmeths.get_mark("c"))
+ end)
+
+ it("errors when set out of range with :mark", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "1000mark x")
+ eq("Vim(mark):E16: Invalid range: 1000mark x", err)
+ end)
+
+ it("errors when set out of range with :k", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "1000kx")
+ eq("Vim(k):E16: Invalid range: 1000kx", err)
+ end)
+
+ it("errors on unknown mark name with :mark", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "mark #")
+ eq("Vim(mark):E191: Argument must be a letter or forward/backward quote", err)
+ end)
+
+ it("errors on unknown mark name with '", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "normal! '#")
+ eq("Vim(normal):E78: Unknown mark", err)
+ end)
+
+ it("errors on unknown mark name with `", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "normal! `#")
+ eq("Vim(normal):E78: Unknown mark", err)
+ end)
+
+ it("errors when moving to a mark that is not set with '", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "normal! 'z")
+ eq("Vim(normal):E20: Mark not set", err)
+ err = pcall_err(helpers.exec_capture, "normal! '.")
+ eq("Vim(normal):E20: Mark not set", err)
+ end)
+
+ it("errors when moving to a mark that is not set with `", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "normal! `z")
+ eq("Vim(normal):E20: Mark not set", err)
+ err = pcall_err(helpers.exec_capture, "normal! `>")
+ eq("Vim(normal):E20: Mark not set", err)
+ end)
+
+ it("errors when moving to a global mark that is not set with '", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "normal! 'Z")
+ eq("Vim(normal):E20: Mark not set", err)
+ end)
+
+ it("errors when moving to a global mark that is not set with `", function()
+ command("edit " .. file1)
+ local err = pcall_err(helpers.exec_capture, "normal! `Z")
+ eq("Vim(normal):E20: Mark not set", err)
+ end)
+
+ it("can move to them using '", function()
+ command("args " .. file1 .. " " .. file2)
+ feed("j")
+ feed("ma")
+ feed("G'a")
+ eq({2, 0}, cursor())
+ feed("mA")
+ command("next")
+ feed("'A")
+ eq(1, meths.get_current_buf().id)
+ eq({2, 0}, cursor())
+ end)
+
+ it("can move to them using `", function()
+ command("args " .. file1 .. " " .. file2)
+ feed("jll")
+ feed("ma")
+ feed("G`a")
+ eq({2, 2}, cursor())
+ feed("mA")
+ command("next")
+ feed("`A")
+ eq(1, meths.get_current_buf().id)
+ eq({2, 2}, cursor())
+ end)
+
+ it("can move to them using g'", function()
+ command("args " .. file1 .. " " .. file2)
+ feed("jll")
+ feed("ma")
+ feed("Gg'a")
+ eq({2, 0}, cursor())
+ feed("mA")
+ command("next")
+ feed("g'A")
+ eq(1, meths.get_current_buf().id)
+ eq({2, 0}, cursor())
+ end)
+
+ it("can move to them using g`", function()
+ command("args " .. file1 .. " " .. file2)
+ feed("jll")
+ feed("ma")
+ feed("Gg`a")
+ eq({2, 2}, cursor())
+ feed("mA")
+ command("next")
+ feed("g`A")
+ eq(1, meths.get_current_buf().id)
+ eq({2, 2}, cursor())
+ end)
+
+ it("errors when it can't find the buffer", function()
+ command("args " .. file1 .. " " .. file2)
+ feed("mA")
+ command("next")
+ command("bw! " .. file1 )
+ local err = pcall_err(helpers.exec_capture, "normal! 'A")
+ eq("Vim(normal):E92: Buffer 1 not found", err)
+ os.remove(file1)
+ end)
+
+ it("leave a context mark when moving with '", function()
+ command("edit " .. file1)
+ feed("llmamA")
+ feed("10j0") -- first col, last line
+ local pos = cursor()
+ feed("'a")
+ feed("<C-o>")
+ eq(pos, cursor())
+ feed("'A")
+ feed("<C-o>")
+ eq(pos, cursor())
+ end)
+
+ it("leave a context mark when moving with `", function()
+ command("edit " .. file1)
+ feed("llmamA")
+ feed("10j0") -- first col, last line
+ local pos = cursor()
+ feed("`a")
+ feed("<C-o>")
+ eq(pos, cursor())
+ feed("`A")
+ feed("<C-o>")
+ eq(pos, cursor())
+ end)
+
+ it("leave a context mark when the mark changes buffer with g'", function()
+ command("args " .. file1 .. " " .. file2)
+ local pos
+ feed("GmA")
+ command("next")
+ pos = cursor()
+ command("clearjumps")
+ feed("g'A") -- since the mark is in another buffer, it leaves a context mark
+ feed("<C-o>")
+ eq(pos, cursor())
+ end)
+
+ it("leave a context mark when the mark changes buffer with g`", function()
+ command("args " .. file1 .. " " .. file2)
+ local pos
+ feed("GmA")
+ command("next")
+ pos = cursor()
+ command("clearjumps")
+ feed("g`A") -- since the mark is in another buffer, it leaves a context mark
+ feed("<C-o>")
+ eq(pos, cursor())
+ end)
+
+ it("do not leave a context mark when moving with g'", function()
+ command("edit " .. file1)
+ local pos
+ feed("ma")
+ pos = cursor() -- Mark pos
+ feed("10j0") -- first col, last line
+ feed("g'a")
+ feed("<C-o>") -- should do nothing
+ eq(pos, cursor())
+ feed("mA")
+ pos = cursor() -- Mark pos
+ feed("10j0") -- first col, last line
+ feed("g'a")
+ feed("<C-o>") -- should do nothing
+ eq(pos, cursor())
+ end)
+
+ it("do not leave a context mark when moving with g`", function()
+ command("edit " .. file1)
+ local pos
+ feed("ma")
+ pos = cursor() -- Mark pos
+ feed("10j0") -- first col, last line
+ feed("g`a")
+ feed("<C-o>") -- should do nothing
+ eq(pos, cursor())
+ feed("mA")
+ pos = cursor() -- Mark pos
+ feed("10j0") -- first col, last line
+ feed("g'a")
+ feed("<C-o>") -- should do nothing
+ eq(pos, cursor())
+ end)
+
+ it("open folds when moving to them", function()
+ command("edit " .. file1)
+ feed("jzfG") -- Fold from the second line to the end
+ command("3mark a")
+ feed("G") -- On top of the fold
+ assert(funcs.foldclosed('.') ~= -1) -- folded
+ feed("'a")
+ eq(-1, funcs.foldclosed('.'))
+
+ feed("zc")
+ assert(funcs.foldclosed('.') ~= -1) -- folded
+ -- TODO: remove this workaround after fixing #15873
+ feed("k`a")
+ eq(-1, funcs.foldclosed('.'))
+
+ feed("zc")
+ assert(funcs.foldclosed('.') ~= -1) -- folded
+ feed("kg'a")
+ eq(-1, funcs.foldclosed('.'))
+
+ feed("zc")
+ assert(funcs.foldclosed('.') ~= -1) -- folded
+ feed("kg`a")
+ eq(-1, funcs.foldclosed('.'))
+ end)
+
+ it("do not open folds when moving to them doesn't move the cursor", function()
+ command("edit " .. file1)
+ feed("jzfG") -- Fold from the second line to the end
+ assert(funcs.foldclosed('.') == 2) -- folded
+ feed("ma")
+ feed("'a")
+ feed("`a")
+ feed("g'a")
+ feed("g`a")
+ -- should still be folded
+ eq(2, funcs.foldclosed('.'))
+ end)
+
+ it("getting '{ '} '( ') does not move cursor", function()
+ meths.buf_set_lines(0, 0, 0, true, {'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee'})
+ meths.win_set_cursor(0, {2, 0})
+ funcs.getpos("'{")
+ eq({2, 0}, meths.win_get_cursor(0))
+ funcs.getpos("'}")
+ eq({2, 0}, meths.win_get_cursor(0))
+ funcs.getpos("'(")
+ eq({2, 0}, meths.win_get_cursor(0))
+ funcs.getpos("')")
+ eq({2, 0}, meths.win_get_cursor(0))
+ end)
+
+ it('in command range does not move cursor #19248', function()
+ meths.create_user_command('Test', ':', {range = true})
+ meths.buf_set_lines(0, 0, 0, true, {'aaaaa', 'bbbbb', 'ccccc', 'ddddd', 'eeeee'})
+ meths.win_set_cursor(0, {2, 0})
+ command([['{,'}Test]])
+ eq({2, 0}, meths.win_get_cursor(0))
+ end)
+end)
+
+describe('named marks view', function()
+ local file1 = 'Xtestfile-functional-editor-marks'
+ local file2 = 'Xtestfile-functional-editor-marks-2'
+ local function content()
+ local c = {}
+ for i=1,30 do
+ c[i] = i .. " line"
+ end
+ return table.concat(c, "\n")
+ end
+ before_each(function()
+ clear()
+ write_file(file1, content(), false, false)
+ write_file(file2, content(), false, false)
+ command("set jumpoptions+=view")
+ end)
+ after_each(function()
+ os.remove(file1)
+ os.remove(file2)
+ end)
+
+ it('is restored', function()
+ local screen = Screen.new(5, 8)
+ screen:attach()
+ command("edit " .. file1)
+ feed("<C-e>jWma")
+ feed("G'a")
+ local expected = [[
+ 2 line |
+ ^3 line |
+ 4 line |
+ 5 line |
+ 6 line |
+ 7 line |
+ 8 line |
+ |
+ ]]
+ screen:expect({grid=expected})
+ feed("G`a")
+ screen:expect([[
+ 2 line |
+ 3 ^line |
+ 4 line |
+ 5 line |
+ 6 line |
+ 7 line |
+ 8 line |
+ |
+ ]])
+ end)
+
+ it('is restored across files', function()
+ local screen = Screen.new(5, 5)
+ screen:attach()
+ command("args " .. file1 .. " " .. file2)
+ feed("<C-e>mA")
+ local mark_view = [[
+ ^2 line |
+ 3 line |
+ 4 line |
+ 5 line |
+ |
+ ]]
+ screen:expect(mark_view)
+ command("next")
+ screen:expect([[
+ ^1 line |
+ 2 line |
+ 3 line |
+ 4 line |
+ |
+ ]])
+ feed("'A")
+ screen:expect(mark_view)
+ end)
+
+ it('fallback to standard behavior when view can\'t be recovered', function()
+ local screen = Screen.new(10, 10)
+ screen:attach()
+ command("edit " .. file1)
+ feed("7GzbmaG") -- Seven lines from the top
+ command("new") -- Screen size for window is now half the height can't be restored
+ feed("<C-w>p'a")
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] |
+ 6 line |
+ ^7 line |
+ 8 line |
+ {MATCH:.*} |
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua
index 2280f5bb24..23964ca10f 100644
--- a/test/functional/editor/meta_key_spec.lua
+++ b/test/functional/editor/meta_key_spec.lua
@@ -27,6 +27,14 @@ describe('meta-keys #8226 #13042', function()
command('nnoremap <A-j> Aalt-j<Esc>')
feed('<A-j><M-l>')
expect('llo<ESC>;<ESC>;alt-jmeta-l')
+ -- Unmapped ALT-chord with characters containing K_SPECIAL bytes
+ command('nnoremap … A…<Esc>')
+ feed('<A-…><M-…>')
+ expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…')
+ command("execute 'nnoremap' nr2char(0x40000000) 'AMAX<Esc>'")
+ command("call nvim_input('<A-'.nr2char(0x40000000).'>')")
+ command("call nvim_input('<M-'.nr2char(0x40000000).'>')")
+ expect('llo<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX')
end)
it('ALT/META, visual-mode', function()
@@ -36,13 +44,20 @@ describe('meta-keys #8226 #13042', function()
expect('peach')
-- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869
command('vnoremap <ESC> A<lt>ESC>')
- feed('viw<A-;><ESC>viw<M-;><ESC>')
+ feed('viw<A-;><Esc>viw<M-;><Esc>')
expect('peach<ESC>;<ESC>;')
-- Mapped ALT-chord behaves as mapped.
command('vnoremap <M-l> Ameta-l<Esc>')
command('vnoremap <A-j> Aalt-j<Esc>')
feed('viw<A-j>viw<M-l>')
expect('peach<ESC>;<ESC>;alt-jmeta-l')
+ -- Unmapped ALT-chord with characters containing K_SPECIAL bytes
+ feed('viw<A-…><Esc>viw<M-…><Esc>')
+ expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…')
+ command("execute 'inoremap' nr2char(0x40000000) 'MAX'")
+ command("call nvim_input('viw<A-'.nr2char(0x40000000).'><Esc>')")
+ command("call nvim_input('viw<M-'.nr2char(0x40000000).'><Esc>')")
+ expect('peach<ESC>;<ESC>;alt-jmeta-l<ESC>…<ESC>…<ESC>MAX<ESC>MAX')
end)
it('ALT/META insert-mode', function()
@@ -89,4 +104,41 @@ describe('meta-keys #8226 #13042', function()
eq({ 0, 2, 1, 0, }, funcs.getpos('.'))
eq('nt', eval('mode(1)'))
end)
+
+ it('ALT/META when recording a macro #13235', function()
+ command('inoremap <M-Esc> <lt>M-ESC>')
+ feed('ifoo<CR>bar<CR>baz<Esc>gg0')
+ -- <M-"> is reinterpreted as <Esc>"
+ feed('qrviw"ayC// This is some text: <M-">apq')
+ expect([[
+ // This is some text: foo
+ bar
+ baz]])
+ -- Should not insert an extra double quote or trigger <M-Esc> when replaying
+ feed('j0@rj0@@')
+ expect([[
+ // This is some text: foo
+ // This is some text: bar
+ // This is some text: baz]])
+ command('%delete')
+ end)
+
+ it('ALT/META with special key when recording a macro', function()
+ command('inoremap <M-Esc> <lt>M-ESC>')
+ command('noremap <S-Tab> "')
+ command('noremap! <S-Tab> "')
+ feed('ifoo<CR>bar<CR>baz<Esc>gg0')
+ -- <M-S-Tab> is reinterpreted as <Esc><S-Tab>
+ feed('qrviw<S-Tab>ayC// This is some text: <M-S-Tab>apq')
+ expect([[
+ // This is some text: foo
+ bar
+ baz]])
+ -- Should not insert an extra double quote or trigger <M-Esc> when replaying
+ feed('j0@rj0@@')
+ expect([[
+ // This is some text: foo
+ // This is some text: bar
+ // This is some text: baz]])
+ end)
end)
diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua
index 0f7d821bb5..50cc5e17ee 100644
--- a/test/functional/editor/mode_cmdline_spec.lua
+++ b/test/functional/editor/mode_cmdline_spec.lua
@@ -3,67 +3,74 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, insert, funcs, eq, feed =
helpers.clear, helpers.insert, helpers.funcs, helpers.eq, helpers.feed
+local eval = helpers.eval
local meths = helpers.meths
-describe('cmdline CTRL-R', function()
+describe('cmdline', function()
before_each(clear)
- it('pasting non-special register inserts <CR> *between* lines', function()
- insert([[
- line1abc
- line2somemoretext
- ]])
- -- Yank 2 lines linewise, then paste to cmdline.
- feed([[<C-\><C-N>gg0yj:<C-R>0]])
- -- <CR> inserted between lines, NOT after the final line.
- eq('line1abc\rline2somemoretext', funcs.getcmdline())
+ describe('Ctrl-R', function()
+ it('pasting non-special register inserts <CR> *between* lines', function()
+ insert([[
+ line1abc
+ line2somemoretext
+ ]])
+ -- Yank 2 lines linewise, then paste to cmdline.
+ feed([[<C-\><C-N>gg0yj:<C-R>0]])
+ -- <CR> inserted between lines, NOT after the final line.
+ eq('line1abc\rline2somemoretext', funcs.getcmdline())
- -- Yank 2 lines charwise, then paste to cmdline.
- feed([[<C-\><C-N>gg05lyvj:<C-R>0]])
- -- <CR> inserted between lines, NOT after the final line.
- eq('abc\rline2', funcs.getcmdline())
+ -- Yank 2 lines charwise, then paste to cmdline.
+ feed([[<C-\><C-N>gg05lyvj:<C-R>0]])
+ -- <CR> inserted between lines, NOT after the final line.
+ eq('abc\rline2', funcs.getcmdline())
- -- Yank 1 line linewise, then paste to cmdline.
- feed([[<C-\><C-N>ggyy:<C-R>0]])
- -- No <CR> inserted.
- eq('line1abc', funcs.getcmdline())
- end)
+ -- Yank 1 line linewise, then paste to cmdline.
+ feed([[<C-\><C-N>ggyy:<C-R>0]])
+ -- No <CR> inserted.
+ eq('line1abc', funcs.getcmdline())
+ end)
- it('pasting special register inserts <CR>, <NL>', function()
- feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
- eq('foo\nbar\rbaz', funcs.getcmdline())
+ it('pasting special register inserts <CR>, <NL>', function()
+ feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
+ eq('foo\nbar\rbaz', funcs.getcmdline())
+ end)
end)
-end)
-describe('cmdline history', function()
- before_each(clear)
+ it('Ctrl-Shift-V supports entering unsimplified key notations', function()
+ feed(':"<C-S-V><C-J><C-S-V><C-@><C-S-V><C-[><C-S-V><C-S-M><C-S-V><M-C-I><C-S-V><C-D-J><CR>')
- it('correctly clears start of the history', function()
- -- Regression test: check absence of the memory leak when clearing start of
- -- the history using ex_getln.c/clr_history().
- eq(1, funcs.histadd(':', 'foo'))
- eq(1, funcs.histdel(':'))
- eq('', funcs.histget(':', -1))
+ eq('"<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>', eval('@:'))
end)
- it('correctly clears end of the history', function()
- -- Regression test: check absence of the memory leak when clearing end of
- -- the history using ex_getln.c/clr_history().
- meths.set_option('history', 1)
- eq(1, funcs.histadd(':', 'foo'))
- eq(1, funcs.histdel(':'))
- eq('', funcs.histget(':', -1))
- end)
+ describe('history', function()
+ it('correctly clears start of the history', function()
+ -- Regression test: check absence of the memory leak when clearing start of
+ -- the history using ex_getln.c/clr_history().
+ eq(1, funcs.histadd(':', 'foo'))
+ eq(1, funcs.histdel(':'))
+ eq('', funcs.histget(':', -1))
+ end)
+
+ it('correctly clears end of the history', function()
+ -- Regression test: check absence of the memory leak when clearing end of
+ -- the history using ex_getln.c/clr_history().
+ meths.set_option('history', 1)
+ eq(1, funcs.histadd(':', 'foo'))
+ eq(1, funcs.histdel(':'))
+ eq('', funcs.histget(':', -1))
+ end)
- it('correctly removes item from history', function()
- -- Regression test: check that ex_getln.c/del_history_idx() correctly clears
- -- history index after removing history entry. If it does not then deleting
- -- history will result in a double free.
- eq(1, funcs.histadd(':', 'foo'))
- eq(1, funcs.histadd(':', 'bar'))
- eq(1, funcs.histadd(':', 'baz'))
- eq(1, funcs.histdel(':', -2))
- eq(1, funcs.histdel(':'))
- eq('', funcs.histget(':', -1))
+ it('correctly removes item from history', function()
+ -- Regression test: check that ex_getln.c/del_history_idx() correctly clears
+ -- history index after removing history entry. If it does not then deleting
+ -- history will result in a double free.
+ eq(1, funcs.histadd(':', 'foo'))
+ eq(1, funcs.histadd(':', 'bar'))
+ eq(1, funcs.histadd(':', 'baz'))
+ eq(1, funcs.histdel(':', -2))
+ eq(1, funcs.histdel(':'))
+ eq('', funcs.histget(':', -1))
+ end)
end)
end)
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index f03508035d..e3d3cdbd85 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -75,4 +75,62 @@ describe('insert-mode', function()
expect('hello oooworld')
end)
end)
+
+ describe('Ctrl-V', function()
+ it('supports entering the decimal value of a character', function()
+ feed('i<C-V>076<C-V>167')
+ expect('L§')
+ end)
+
+ it('supports entering the octal value of a character with "o"', function()
+ feed('i<C-V>o114<C-V>o247<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the octal value of a character with "O"', function()
+ feed('i<C-V>O114<C-V>O247<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "x"', function()
+ feed('i<C-V>x4c<C-V>xA7<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "X"', function()
+ feed('i<C-V>X4c<C-V>XA7<Esc>')
+ expect('L§')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "u"', function()
+ feed('i<C-V>u25ba<C-V>u25C7<Esc>')
+ expect('►◇')
+ end)
+
+ it('supports entering the hexadecimal value of a character with "U"', function()
+ feed('i<C-V>U0001f600<C-V>U0001F601<Esc>')
+ expect('😀😁')
+ end)
+
+ it('entering character by value is interrupted by invalid character', function()
+ feed('i<C-V>76c<C-V>76<C-F2><C-V>u3c0j<C-V>u3c0<M-F3><C-V>U1f600j<C-V>U1f600<D-F4><Esc>')
+ expect('LcL<C-F2>πjπ<M-F3>😀j😀<D-F4>')
+ end)
+
+ it('shows o, O, u, U, x, X, and digits with modifiers', function()
+ feed('i<C-V><M-o><C-V><D-o><C-V><M-O><C-V><D-O><Esc>')
+ expect('<M-o><D-o><M-O><D-O>')
+ feed('cc<C-V><M-u><C-V><D-u><C-V><M-U><C-V><D-U><Esc>')
+ expect('<M-u><D-u><M-U><D-U>')
+ feed('cc<C-V><M-x><C-V><D-x><C-V><M-X><C-V><D-X><Esc>')
+ expect('<M-x><D-x><M-X><D-X>')
+ feed('cc<C-V><M-1><C-V><D-2><C-V><M-7><C-V><D-8><Esc>')
+ expect('<M-1><D-2><M-7><D-8>')
+ end)
+ end)
+
+ it('Ctrl-Shift-V supports entering unsimplified key notations', function()
+ feed('i<C-S-V><C-J><C-S-V><C-@><C-S-V><C-[><C-S-V><C-S-M><C-S-V><M-C-I><C-S-V><C-D-J><Esc>')
+ expect('<C-J><C-@><C-[><C-S-M><M-C-I><C-D-J>')
+ end)
end)
diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua
index 26967ecbba..cc9fce8f67 100644
--- a/test/functional/editor/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
@@ -64,7 +64,7 @@ describe('put command', function()
-- one place to the right (unless we were at the end of the
-- line when we pasted).
if not (exception_table.undo_position and after_undo) then
- eq(funcs.getcurpos(), init_cursorpos)
+ eq(init_cursorpos, funcs.getcurpos())
end
end
@@ -86,7 +86,7 @@ describe('put command', function()
-- If we paste the ". register with a count we can't avoid
-- changing this register, hence avoid this check.
if not test.exception_table.dot_reg_changed then
- eq(funcs.getreg('.'), orig_dotstr)
+ eq(orig_dotstr, funcs.getreg('.'))
end
-- Doing something, undoing it, and then redoing it should
@@ -138,9 +138,9 @@ describe('put command', function()
end -- create_test_defs() }}}
local function find_cursor_position(expect_string) -- {{{
- -- There must only be one occurance of the character 'x' in
+ -- There must only be one occurrence of the character 'x' in
-- expect_string.
- -- This function removes that occurance, and returns the position that
+ -- This function removes that occurrence, and returns the position that
-- it was in.
-- This returns the cursor position that would leave the 'x' in that
-- place if we feed 'ix<esc>' and the string existed before it.
@@ -507,9 +507,11 @@ describe('put command', function()
return function(exception_table, after_redo)
test_expect(exception_table, after_redo)
if selection_string then
- eq(getreg('"'), selection_string)
+ if not conversion_table.put_backwards then
+ eq(selection_string, getreg('"'))
+ end
else
- eq(getreg('"'), 'test_string"')
+ eq('test_string"', getreg('"'))
end
end
end
@@ -714,7 +716,9 @@ describe('put command', function()
expect_base, conversion_table)
return function(exception_table, after_redo)
test_expect(exception_table, after_redo)
- eq(getreg('"'), 'Line of words 1\n')
+ if not conversion_table.put_backwards then
+ eq('Line of words 1\n', getreg('"'))
+ end
end
end
local base_expect_string = [[
@@ -748,7 +752,9 @@ describe('put command', function()
end, expect_base, conversion_table)
return function(e,c)
test_expect(e,c)
- eq(getreg('"'), 'Lin\nLin')
+ if not conversion_table.put_backwards then
+ eq('Lin\nLin', getreg('"'))
+ end
end
end
@@ -800,9 +806,9 @@ describe('put command', function()
feed('u')
-- Have to use feed('u') here to set curswant, because
-- ex_undo() doesn't do that.
- eq(funcs.getcurpos(), {0, 1, 1, 0, 1})
+ eq({0, 1, 1, 0, 1}, funcs.getcurpos())
feed('<C-r>')
- eq(funcs.getcurpos(), {0, 1, 1, 0, 1})
+ eq({0, 1, 1, 0, 1}, funcs.getcurpos())
end
end
diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index d1d6854b07..3b2c1db350 100644
--- a/test/functional/editor/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
@@ -3,8 +3,11 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local neq = helpers.neq
local feed = helpers.feed
local eval = helpers.eval
+local exec = helpers.exec
+local funcs = helpers.funcs
describe('tabpage', function()
before_each(clear)
@@ -34,5 +37,28 @@ describe('tabpage', function()
eq(3, eval('tabpagenr()'))
end)
-end)
+ it('does not crash or loop 999 times if BufWipeout autocommand switches window #17868', function()
+ exec([[
+ tabedit
+ let s:window_id = win_getid()
+ botright new
+ setlocal bufhidden=wipe
+ let g:win_closed = 0
+ autocmd WinClosed * let g:win_closed += 1
+ autocmd BufWipeout <buffer> call win_gotoid(s:window_id)
+ tabprevious
+ +tabclose
+ ]])
+ neq(999, eval('g:win_closed'))
+ end)
+
+ it(":tabmove handles modifiers and addr", function()
+ command('tabnew | tabnew | tabnew')
+ eq(4, funcs.nvim_tabpage_get_number(0))
+ command(' silent :keepalt :: ::: silent! - tabmove')
+ eq(3, funcs.nvim_tabpage_get_number(0))
+ command(' silent :keepalt :: ::: silent! -2 tabmove')
+ eq(1, funcs.nvim_tabpage_get_number(0))
+ end)
+end)
diff --git a/test/functional/editor/undo_spec.lua b/test/functional/editor/undo_spec.lua
index a023ca3d90..a041428cdc 100644
--- a/test/functional/editor/undo_spec.lua
+++ b/test/functional/editor/undo_spec.lua
@@ -2,9 +2,18 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local command = helpers.command
+local eval = helpers.eval
local expect = helpers.expect
+local eq = helpers.eq
local feed = helpers.feed
+local feed_command = helpers.feed_command
local insert = helpers.insert
+local funcs = helpers.funcs
+
+local function lastmessage()
+ local messages = funcs.split(funcs.execute('messages'), '\n')
+ return messages[#messages]
+end
describe('u CTRL-R g- g+', function()
before_each(clear)
@@ -59,3 +68,61 @@ describe('u CTRL-R g- g+', function()
undo_and_redo(4, 'g-', 'g+', '1')
end)
end)
+
+describe(':undo! command', function()
+ before_each(function()
+ clear()
+ feed('i1 little bug in the code<Esc>')
+ feed('o1 little bug in the code<Esc>')
+ feed('oTake 1 down, patch it around<Esc>')
+ feed('o99 little bugs in the code<Esc>')
+ end)
+ it('works', function()
+ feed_command('undo!')
+ expect([[
+ 1 little bug in the code
+ 1 little bug in the code
+ Take 1 down, patch it around]])
+ feed('<C-r>')
+ eq('Already at newest change', lastmessage())
+ end)
+ it('works with arguments', function()
+ feed_command('undo! 2')
+ expect([[
+ 1 little bug in the code
+ 1 little bug in the code]])
+ feed('<C-r>')
+ eq('Already at newest change', lastmessage())
+ end)
+ it('correctly sets alternative redo', function()
+ feed('uo101 little bugs in the code<Esc>')
+ feed_command('undo!')
+ feed('<C-r>')
+ expect([[
+ 1 little bug in the code
+ 1 little bug in the code
+ Take 1 down, patch it around
+ 99 little bugs in the code]])
+
+ feed('uuoTake 2 down, patch them around<Esc>')
+ feed('o101 little bugs in the code<Esc>')
+ feed_command('undo! 2')
+ feed('<C-r><C-r>')
+ expect([[
+ 1 little bug in the code
+ 1 little bug in the code
+ Take 1 down, patch it around
+ 99 little bugs in the code]])
+ end)
+ it('fails when attempting to redo or move to different undo branch', function()
+ feed_command('undo! 4')
+ eq('E5767: Cannot use :undo! to redo or move to a different undo branch', eval('v:errmsg'))
+ feed('u')
+ feed_command('undo! 4')
+ eq('E5767: Cannot use :undo! to redo or move to a different undo branch', eval('v:errmsg'))
+ feed('o101 little bugs in the code<Esc>')
+ feed('o101 little bugs in the code<Esc>')
+ feed_command('undo! 4')
+ eq('E5767: Cannot use :undo! to redo or move to a different undo branch', eval('v:errmsg'))
+ end)
+end)
diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua
index f9cce0deb6..42a811f5da 100644
--- a/test/functional/ex_cmds/cd_spec.lua
+++ b/test/functional/ex_cmds/cd_spec.lua
@@ -173,7 +173,7 @@ for _, cmd in ipairs {'cd', 'chdir'} do
-- Change tab-local working directory and verify it is different
command('silent t' .. cmd .. ' ' .. directories.tab)
eq(globalDir .. pathsep .. directories.tab, cwd())
- eq(cwd(), tcwd()) -- working directory maches tab directory
+ eq(cwd(), tcwd()) -- working directory matches tab directory
eq(1, tlwd())
eq(cwd(), wcwd()) -- still no window-directory
eq(0, wlwd())
diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 0b2190bbcf..919d167712 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -1,21 +1,23 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
-local feed_command = helpers.feed_command
local feed = helpers.feed
local eq = helpers.eq
local expect = helpers.expect
local eval = helpers.eval
local funcs = helpers.funcs
local insert = helpers.insert
+local write_file = helpers.write_file
local exc_exec = helpers.exc_exec
-local source = helpers.source
+local command = helpers.command
local Screen = require('test.functional.ui.screen')
describe('mappings with <Cmd>', function()
local screen
+ local tmpfile = 'X_ex_cmds_cmd_map'
+
local function cmdmap(lhs, rhs)
- feed_command('noremap '..lhs..' <Cmd>'..rhs..'<cr>')
- feed_command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>')
+ command('noremap '..lhs..' <Cmd>'..rhs..'<cr>')
+ command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>')
end
before_each(function()
@@ -39,7 +41,7 @@ describe('mappings with <Cmd>', function()
cmdmap('<F4>', 'normal! ww')
cmdmap('<F5>', 'normal! "ay')
cmdmap('<F6>', 'throw "very error"')
- feed_command([[
+ command([[
function! TextObj()
if mode() !=# "v"
normal! v
@@ -55,11 +57,15 @@ describe('mappings with <Cmd>', function()
feed('gg')
cmdmap('<F8>', 'startinsert')
cmdmap('<F9>', 'stopinsert')
- feed_command("abbr foo <Cmd>let g:y = 17<cr>bar")
+ command("abbr foo <Cmd>let g:y = 17<cr>bar")
+ end)
+
+ after_each(function()
+ os.remove(tmpfile)
end)
it('can be displayed', function()
- feed_command('map <F3>')
+ command('map <F3>')
screen:expect([[
^some short lines |
of test text |
@@ -73,8 +79,8 @@ describe('mappings with <Cmd>', function()
end)
it('handles invalid mappings', function()
- feed_command('let x = 0')
- feed_command('noremap <F3> <Cmd><Cmd>let x = 1<cr>')
+ command('let x = 0')
+ command('noremap <F3> <Cmd><Cmd>let x = 1<cr>')
feed('<F3>')
screen:expect([[
^some short lines |
@@ -87,7 +93,7 @@ describe('mappings with <Cmd>', function()
{2:E5521: <Cmd> mapping must end with <CR> before second <Cmd>} |
]])
- feed_command('noremap <F3> <Cmd><F3>let x = 2<cr>')
+ command('noremap <F3> <Cmd>let x = 3')
feed('<F3>')
screen:expect([[
^some short lines |
@@ -97,22 +103,50 @@ describe('mappings with <Cmd>', function()
{1:~ }|
{1:~ }|
{1:~ }|
- {2:E5522: <Cmd> mapping must not include <F3> key} |
+ {2:E5520: <Cmd> mapping must end with <CR>} |
]])
+ eq(0, eval('x'))
+ end)
- feed_command('noremap <F3> <Cmd>let x = 3')
+ it('allows special keys and modifiers', function()
+ command('noremap <F3> <Cmd>normal! <Down><CR>')
feed('<F3>')
screen:expect([[
- ^some short lines |
- of test text |
+ some short lines |
+ ^of test text |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- {2:E5520: <Cmd> mapping must end with <CR>} |
+ |
]])
- eq(0, eval('x'))
+
+ command('noremap <F3> <Cmd>normal! <C-Right><CR>')
+ feed('<F3>')
+ screen:expect([[
+ some short lines |
+ of ^test text |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('handles string containing K_SPECIAL (0x80) bytes correctly', function()
+ command([[noremap <F3> <Cmd>let g:str = 'foo…bar'<CR>]])
+ feed('<F3>')
+ eq('foo…bar', eval('g:str'))
+ local str = eval([["foo\<D-…>bar"]])
+ command([[noremap <F3> <Cmd>let g:str = ']]..str..[['<CR>]])
+ feed('<F3>')
+ eq(str, eval('g:str'))
+ command([[noremap <F3> <Cmd>let g:str = 'foo<D-…>bar'<CR>]])
+ feed('<F3>')
+ eq(str, eval('g:str'))
end)
it('works in various modes and sees correct `mode()` value', function()
@@ -137,7 +171,7 @@ describe('mappings with <Cmd>', function()
eq('n', eval('mode(1)'))
-- select mode mapping
- feed_command('snoremap <F3> <Cmd>let m = mode(1)<cr>')
+ command('snoremap <F3> <Cmd>let m = mode(1)<cr>')
feed('gh<F3>')
eq('s', eval('m'))
-- didn't leave select mode
@@ -184,8 +218,8 @@ describe('mappings with <Cmd>', function()
eq('n', eval('mode(1)'))
-- terminal mode
- feed_command('tnoremap <F3> <Cmd>let m = mode(1)<cr>')
- feed_command('split | terminal')
+ command('tnoremap <F3> <Cmd>let m = mode(1)<cr>')
+ command('split | terminal')
feed('i')
eq('t', eval('mode(1)'))
feed('<F3>')
@@ -264,11 +298,11 @@ describe('mappings with <Cmd>', function()
end)
it('works in :normal command', function()
- feed_command('noremap ,x <Cmd>call append(1, "xx")\\| call append(1, "aa")<cr>')
- feed_command('noremap ,f <Cmd>nosuchcommand<cr>')
- feed_command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>')
- feed_command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>')
- feed_command('noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>')
+ command('noremap ,x <Cmd>call append(1, "xx")\\| call append(1, "aa")<cr>')
+ command('noremap ,f <Cmd>nosuchcommand<cr>')
+ command('noremap ,e <Cmd>throw "very error"\\| call append(1, "yy")<cr>')
+ command('noremap ,m <Cmd>echoerr "The message."\\| call append(1, "zz")<cr>')
+ command('noremap ,w <Cmd>for i in range(5)\\|if i==1\\|echoerr "Err"\\|endif\\|call append(1, i)\\|endfor<cr>')
feed(":normal ,x<cr>")
screen:expect([[
@@ -297,7 +331,7 @@ describe('mappings with <Cmd>', function()
:normal ,x |
]])
- feed_command(':%d')
+ command(':%d')
eq('Vim(echoerr):Err', exc_exec("normal ,w"))
screen:expect([[
^ |
@@ -310,8 +344,8 @@ describe('mappings with <Cmd>', function()
--No lines in buffer-- |
]])
- feed_command(':%d')
- feed_command(':normal ,w')
+ command(':%d')
+ feed(':normal ,w<cr>')
screen:expect([[
^ |
4 |
@@ -401,8 +435,8 @@ describe('mappings with <Cmd>', function()
end)
it('works in select mode', function()
- feed_command('snoremap <F1> <cmd>throw "very error"<cr>')
- feed_command('snoremap <F2> <cmd>normal! <c-g>"by<cr>')
+ command('snoremap <F1> <cmd>throw "very error"<cr>')
+ command('snoremap <F2> <cmd>normal! <c-g>"by<cr>')
-- can extend select mode
feed('gh<F4>')
screen:expect([[
@@ -830,12 +864,14 @@ describe('mappings with <Cmd>', function()
end)
it("works with <SID> mappings", function()
- source([[
+ command('new!')
+ write_file(tmpfile, [[
map <f2> <Cmd>call <SID>do_it()<Cr>
function! s:do_it()
let g:x = 10
endfunction
]])
+ command('source '..tmpfile)
feed('<f2>')
eq('', eval('v:errmsg'))
eq(10, eval('g:x'))
diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua
index 9d84a2d4f6..2537ab9cdc 100644
--- a/test/functional/ex_cmds/drop_spec.lua
+++ b/test/functional/ex_cmds/drop_spec.lua
@@ -41,14 +41,14 @@ describe(":drop", function()
feed_command("edit tmp2")
feed_command("drop tmp1")
screen:expect([[
- {2:│}^ |
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
+ │^ |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
{2:tmp2 }{1:tmp1 }|
:drop tmp1 |
]])
@@ -62,14 +62,14 @@ describe(":drop", function()
feed("iABC<esc>")
feed_command("drop tmp3")
screen:expect([[
- ^ {2:│} |
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {1:tmp3 }{2:│}{0:~ }|
- ABC {2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }|
+ ^ │ |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {1:tmp3 }│{0:~ }|
+ ABC │{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
{2:tmp2 [+] tmp1 }|
"tmp3" [New] |
]])
diff --git a/test/functional/ex_cmds/echo_spec.lua b/test/functional/ex_cmds/echo_spec.lua
index d320425de1..a6be04138b 100644
--- a/test/functional/ex_cmds/echo_spec.lua
+++ b/test/functional/ex_cmds/echo_spec.lua
@@ -181,9 +181,9 @@ describe(':echo :echon :echomsg :echoerr', function()
end)
it('dumps references to script functions', function()
- eq('<SNR>2_Test2', eval('String(Test2_f)'))
- eq("function('<SNR>2_Test2')", eval('StringMsg(Test2_f)'))
- eq("function('<SNR>2_Test2')", eval('StringErr(Test2_f)'))
+ eq('<SNR>1_Test2', eval('String(Test2_f)'))
+ eq("function('<SNR>1_Test2')", eval('StringMsg(Test2_f)'))
+ eq("function('<SNR>1_Test2')", eval('StringErr(Test2_f)'))
end)
it('dump references to lambdas', function()
@@ -205,11 +205,11 @@ describe(':echo :echon :echomsg :echoerr', function()
it('dumps automatically created partials', function()
assert_same_echo_dump(
- "function('<SNR>2_Test2', {'f': function('<SNR>2_Test2')})",
+ "function('<SNR>1_Test2', {'f': function('<SNR>1_Test2')})",
'{"f": Test2_f}.f',
true)
assert_same_echo_dump(
- "function('<SNR>2_Test2', [1], {'f': function('<SNR>2_Test2', [1])})",
+ "function('<SNR>1_Test2', [1], {'f': function('<SNR>1_Test2', [1])})",
'{"f": function(Test2_f, [1])}.f',
true)
end)
@@ -227,7 +227,7 @@ describe(':echo :echon :echomsg :echoerr', function()
function()
meths.set_var('d', {v=true})
eq(dedent([[
- {'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]]),
+ {'p': function('<SNR>1_Test2', {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]]),
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
end)
@@ -264,7 +264,7 @@ describe(':echo :echon :echomsg :echoerr', function()
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
eq(dedent([=[
- {'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]=]),
+ {'p': function('<SNR>1_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]=]),
exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
end)
end)
diff --git a/test/functional/ex_cmds/ls_spec.lua b/test/functional/ex_cmds/ls_spec.lua
index 9853084c47..2583d80269 100644
--- a/test/functional/ex_cmds/ls_spec.lua
+++ b/test/functional/ex_cmds/ls_spec.lua
@@ -5,7 +5,7 @@ local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local nvim = helpers.nvim
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local retry = helpers.retry
describe(':ls', function()
@@ -14,7 +14,7 @@ describe(':ls', function()
end)
it('R, F for :terminal buffers', function()
- nvim('set_option', 'shell', string.format('"%s" INTERACT', nvim_dir..'/shell-test'))
+ nvim('set_option', 'shell', string.format('"%s" INTERACT', testprg('shell-test')))
command('edit foo')
command('set hidden')
diff --git a/test/functional/ex_cmds/make_spec.lua b/test/functional/ex_cmds/make_spec.lua
index 3b4d22ab38..bf585ee44c 100644
--- a/test/functional/ex_cmds/make_spec.lua
+++ b/test/functional/ex_cmds/make_spec.lua
@@ -4,7 +4,7 @@ local eval = helpers.eval
local has_powershell = helpers.has_powershell
local matches = helpers.matches
local nvim = helpers.nvim
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
describe(':make', function()
clear()
@@ -22,7 +22,7 @@ describe(':make', function()
end)
it('captures stderr & non zero exit code #14349', function ()
- nvim('set_option', 'makeprg', nvim_dir..'/shell-test foo')
+ nvim('set_option', 'makeprg', testprg('shell-test')..' foo')
local out = eval('execute("make")')
-- Make program exit code correctly captured
matches('\nshell returned 3', out)
@@ -31,7 +31,7 @@ describe(':make', function()
end)
it('captures stderr & zero exit code #14349', function ()
- nvim('set_option', 'makeprg', nvim_dir..'/shell-test')
+ nvim('set_option', 'makeprg', testprg('shell-test'))
local out = eval('execute("make")')
-- Ensure there are no "shell returned X" messages between
-- command and last line (indicating zero exit)
diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua
index 84d5bc2335..c6bdd017bd 100644
--- a/test/functional/ex_cmds/map_spec.lua
+++ b/test/functional/ex_cmds/map_spec.lua
@@ -1,11 +1,15 @@
local helpers = require("test.functional.helpers")(after_each)
+local Screen = require('test.functional.ui.screen')
local eq = helpers.eq
+local exec = helpers.exec
local feed = helpers.feed
local meths = helpers.meths
local clear = helpers.clear
local command = helpers.command
local expect = helpers.expect
+local insert = helpers.insert
+local eval = helpers.eval
describe(':*map', function()
before_each(clear)
@@ -25,4 +29,233 @@ describe(':*map', function()
feed('i-<M-">-')
expect('-foo-')
end)
+
+ it('shows <nop> as mapping rhs', function()
+ command('nmap asdf <Nop>')
+ eq([[
+
+n asdf <Nop>]],
+ helpers.exec_capture('nmap asdf'))
+ end)
+
+ it('mappings with description can be filtered', function()
+ meths.set_keymap('n', 'asdf1', 'qwert', {desc='do the one thing'})
+ meths.set_keymap('n', 'asdf2', 'qwert', {desc='doesnot really do anything'})
+ meths.set_keymap('n', 'asdf3', 'qwert', {desc='do the other thing'})
+ eq([[
+
+n asdf3 qwert
+ do the other thing
+n asdf1 qwert
+ do the one thing]],
+ helpers.exec_capture('filter the nmap'))
+ end)
+
+ it('<Plug> mappings ignore nore', function()
+ command('let x = 0')
+ eq(0, meths.eval('x'))
+ command [[
+ nnoremap <Plug>(Increase_x) <cmd>let x+=1<cr>
+ nmap increase_x_remap <Plug>(Increase_x)
+ nnoremap increase_x_noremap <Plug>(Increase_x)
+ ]]
+ feed('increase_x_remap')
+ eq(1, meths.eval('x'))
+ feed('increase_x_noremap')
+ eq(2, meths.eval('x'))
+ end)
+
+ it("Doesn't auto ignore nore for keys before or after <Plug> mapping", function()
+ command('let x = 0')
+ eq(0, meths.eval('x'))
+ command [[
+ nnoremap x <nop>
+ nnoremap <Plug>(Increase_x) <cmd>let x+=1<cr>
+ nmap increase_x_remap x<Plug>(Increase_x)x
+ nnoremap increase_x_noremap x<Plug>(Increase_x)x
+ ]]
+ insert("Some text")
+ eq('Some text', eval("getline('.')"))
+
+ feed('increase_x_remap')
+ eq(1, meths.eval('x'))
+ eq('Some text', eval("getline('.')"))
+ feed('increase_x_noremap')
+ eq(2, meths.eval('x'))
+ eq('Some te', eval("getline('.')"))
+ end)
+end)
+
+describe('Screen', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(20, 5)
+ screen:attach()
+ end)
+
+ it('cursor is restored after :map <expr> which calls input()', function()
+ command('map <expr> x input("> ")')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed('x')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ > ^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ > |
+ ]])
+ end)
+
+ it('cursor is restored after :imap <expr> which calls input()', function()
+ command('imap <expr> x input("> ")')
+ feed('i')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ feed('x')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ > ^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ > |
+ ]])
+ end)
+
+ it('cursor position does not move after empty-string :cmap <expr> #19046', function()
+ command([[cnoremap <expr> <F2> '']])
+ feed(':<F2>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ :^ |
+ ]])
+ end)
+
+ it('cursor is restored after :map <expr> which redraws statusline vim-patch:8.1.2336', function()
+ exec([[
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ set ls=2
+ hi! link StatusLine ErrorMsg
+ noremap <expr> <C-B> Func()
+ func Func()
+ let g:on = !get(g:, 'on', 0)
+ redraws
+ return ''
+ endfunc
+ func Status()
+ return get(g:, 'on', 0) ? '[on]' : ''
+ endfunc
+ set stl=%{Status()}
+ ]])
+ feed('<C-B>')
+ screen:expect([[
+ one |
+ ^two |
+ three |
+ [on] |
+ |
+ ]])
+ end)
+
+ it('error in :nmap <expr> does not mess up display vim-patch:4.2.4338', function()
+ screen:try_resize(40, 5)
+ command('nmap <expr> <F2> execute("throw 42")')
+ feed('<F2>')
+ screen:expect([[
+ |
+ |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ Press ENTER or type command to continue^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ end)
+
+ it('error in :cmap <expr> handled correctly vim-patch:4.2.4338', function()
+ screen:try_resize(40, 5)
+ command('cmap <expr> <F2> execute("throw 42")')
+ feed(':echo "foo')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ :echo "foo^ |
+ ]])
+ feed('<F2>')
+ screen:expect([[
+ |
+ :echo "foo |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ :echo "foo^ |
+ ]])
+ feed('"')
+ screen:expect([[
+ |
+ :echo "foo |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ :echo "foo"^ |
+ ]])
+ feed('\n')
+ screen:expect([[
+ :echo "foo |
+ Error detected while processing : |
+ E605: Exception not caught: 42 |
+ foo |
+ Press ENTER or type command to continue^ |
+ ]])
+ end)
+
+ it('listing mappings clears command line vim-patch:8.2.4401', function()
+ screen:try_resize(40, 5)
+ command('nmap a b')
+ feed(': nmap a<CR>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ n a b |
+ ]])
+ end)
end)
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
index 0cd32df27c..b9ed32c328 100644
--- a/test/functional/ex_cmds/menu_spec.lua
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -64,6 +64,8 @@ describe('menu_get', function()
before_each(function()
clear()
command([=[
+ aunmenu *
+
nnoremenu &Test.Test inormal<ESC>
inoremenu Test.Test insert
vnoremenu Test.Test x
@@ -396,6 +398,7 @@ describe('menu_get', function()
before_each(function()
clear()
+ command('aunmenu *')
end)
it('returns <keycode> representation of special keys', function()
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index 09eaa36686..1553de4432 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -1,14 +1,20 @@
local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local get_pathsep = helpers.get_pathsep
+local iswin = helpers.iswin
local eq = helpers.eq
+local neq = helpers.neq
local funcs = helpers.funcs
local matches = helpers.matches
local pesc = helpers.pesc
local rmdir = helpers.rmdir
+local sleep = helpers.sleep
+local meths = helpers.meths
+local expect_exit = helpers.expect_exit
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
@@ -30,7 +36,8 @@ describe(':mksession', function()
-- If the same :terminal is displayed in multiple windows, :mksession
-- should restore it as such.
- -- Create two windows showing the same :terminal buffer.
+ -- Create three windows: first two from top show same terminal, third -
+ -- another one (created earlier).
command('terminal')
command('split')
command('terminal')
@@ -38,13 +45,13 @@ describe(':mksession', function()
command('mksession '..session_file)
-- Create a new test instance of Nvim.
- command('qall!')
+ expect_exit(command, 'qall!')
clear()
-- Restore session.
command('source '..session_file)
- eq({2,2,4},
- {funcs.winbufnr(1), funcs.winbufnr(2), funcs.winbufnr(3)})
+ eq(funcs.winbufnr(1), funcs.winbufnr(2))
+ neq(funcs.winbufnr(1), funcs.winbufnr(3))
end)
it('restores tab-local working directories', function()
@@ -91,12 +98,7 @@ describe(':mksession', function()
command('tabnext 1')
eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '1', funcs.expand('%:p'))
command('tabnext 2')
- -- :mksession stores paths using unix slashes, but Nvim doesn't adjust these
- -- for absolute paths in all cases yet. Absolute paths are used in the
- -- session file after :tcd, so we need to expect unix slashes here for now
- -- eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p'))
- eq(cwd_dir:gsub([[\]], '/') .. '/' .. tmpfile_base .. '2',
- funcs.expand('%:p'))
+ eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p'))
end)
it('restores CWD for :terminal buffers #11288', function()
@@ -105,10 +107,14 @@ describe(':mksession', function()
local session_path = cwd_dir..'/'..session_file
command('cd '..tab_dir)
- command('terminal echo $PWD')
+ command('terminal')
command('cd '..cwd_dir)
command('mksession '..session_path)
- command('qall!')
+ command('bdelete!')
+ if iswin() then
+ sleep(100) -- Make sure all child processes have exited.
+ end
+ expect_exit(command, 'qall!')
-- Create a new test instance of Nvim.
clear()
@@ -116,6 +122,83 @@ describe(':mksession', function()
local expected_cwd = cwd_dir..'/'..tab_dir
matches('^term://'..pesc(expected_cwd)..'//%d+:', funcs.expand('%'))
- command('qall!')
+ command('bdelete!')
+ if iswin() then
+ sleep(100) -- Make sure all child processes have exited.
+ end
+ end)
+
+ it('restores CWD for :terminal buffer at root directory #16988', function()
+ if iswin() then
+ pending('N/A for Windows')
+ return
+ end
+
+ local screen
+ local cwd_dir = funcs.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
+ local session_path = cwd_dir..'/'..session_file
+
+ screen = Screen.new(50, 6)
+ screen:attach({rgb=false})
+ local expected_screen = [[
+ ^/ |
+ |
+ [Process exited 0] |
+ |
+ |
+ |
+ ]]
+
+ command('cd /')
+ command('terminal echo $PWD')
+
+ -- Verify that the terminal's working directory is "/".
+ screen:expect(expected_screen)
+
+ command('cd '..cwd_dir)
+ command('mksession '..session_path)
+ expect_exit(command, 'qall!')
+
+ -- Create a new test instance of Nvim.
+ clear()
+ screen = Screen.new(50, 6)
+ screen:attach({rgb=false})
+ command('silent source '..session_path)
+
+ -- Verify that the terminal's working directory is "/".
+ screen:expect(expected_screen)
+ end)
+
+ it('restores a session when there is a float #18432', function()
+ local tmpfile = file_prefix .. '-tmpfile-float'
+
+ command('edit ' .. tmpfile)
+ local buf = meths.create_buf(false, true)
+ local config = {
+ relative = 'editor',
+ focusable = false,
+ width = 10,
+ height = 3,
+ row = 0,
+ col = 1,
+ style = 'minimal'
+ }
+ meths.open_win(buf, false, config)
+ local cmdheight = meths.get_option('cmdheight')
+ command('mksession ' .. session_file)
+
+ -- Create a new test instance of Nvim.
+ clear()
+
+ command('source ' .. session_file)
+
+ eq(tmpfile, funcs.expand('%'))
+ -- Check that there is only a single window, which indicates the floating
+ -- window was not restored.
+ eq(1, funcs.winnr('$'))
+ -- The command-line height should remain the same as it was.
+ eq(cmdheight, meths.get_option('cmdheight'))
+
+ os.remove(tmpfile)
end)
end)
diff --git a/test/functional/ex_cmds/normal_spec.lua b/test/functional/ex_cmds/normal_spec.lua
new file mode 100644
index 0000000000..f6e7dd2b3a
--- /dev/null
+++ b/test/functional/ex_cmds/normal_spec.lua
@@ -0,0 +1,27 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local feed = helpers.feed
+local expect = helpers.expect
+local eq = helpers.eq
+local eval = helpers.eval
+
+before_each(clear)
+
+describe(':normal', function()
+ it('can get out of Insert mode if called from Ex mode #17924', function()
+ feed('gQnormal! Ifoo<CR>')
+ expect('foo')
+ end)
+
+ it('normal! does not execute command in Ex mode when running out of characters', function()
+ command('let g:var = 0')
+ command('normal! gQlet g:var = 1')
+ eq(0, eval('g:var'))
+ end)
+
+ it('normal! gQinsert does not hang #17980', function()
+ command('normal! gQinsert')
+ expect('')
+ end)
+end)
diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua
index c956a2df2d..94b7fa1a84 100644
--- a/test/functional/ex_cmds/quickfix_commands_spec.lua
+++ b/test/functional/ex_cmds/quickfix_commands_spec.lua
@@ -109,4 +109,17 @@ describe('quickfix', function()
]])
eq({0, 6, 1, 0, 1}, funcs.getcurpos())
end)
+
+ it('BufAdd does not cause E16 when reusing quickfix buffer #18135', function()
+ local file = file_base .. '_reuse_qfbuf_BufAdd'
+ write_file(file, ('\n'):rep(100) .. 'foo')
+ source([[
+ set grepprg=internal
+ autocmd BufAdd * call and(0, 0)
+ autocmd QuickFixCmdPost grep ++nested cclose | cwindow
+ ]])
+ command('grep foo ' .. file)
+ command('grep foo ' .. file)
+ os.remove(file)
+ end)
end)
diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua
index 0a772c559b..bf69ada820 100644
--- a/test/functional/ex_cmds/script_spec.lua
+++ b/test/functional/ex_cmds/script_spec.lua
@@ -2,18 +2,30 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local neq = helpers.neq
+local command = helpers.command
+local write_file = helpers.write_file
local meths = helpers.meths
local clear = helpers.clear
local dedent = helpers.dedent
-local source = helpers.source
local exc_exec = helpers.exc_exec
local missing_provider = helpers.missing_provider
+local tmpfile = 'X_ex_cmds_script'
+
before_each(clear)
+local function source(code)
+ write_file(tmpfile, code)
+ command('source '..tmpfile)
+end
+
describe('script_get-based command', function()
local garbage = ')}{+*({}]*[;(+}{&[]}{*])('
+ after_each(function()
+ os.remove(tmpfile)
+ end)
+
local function test_garbage_exec(cmd, check_neq)
describe(cmd, function()
it('works correctly when skipping oneline variant', function()
@@ -62,10 +74,10 @@ describe('script_get-based command', function()
-- Provider-based scripts
test_garbage_exec('ruby', not missing_provider('ruby'))
- test_garbage_exec('python', not missing_provider('python'))
test_garbage_exec('python3', not missing_provider('python3'))
-- Missing scripts
+ test_garbage_exec('python', false)
test_garbage_exec('tcl', false)
test_garbage_exec('mzscheme', false)
test_garbage_exec('perl', false)
diff --git a/test/functional/ex_cmds/sign_spec.lua b/test/functional/ex_cmds/sign_spec.lua
index 891cfe1670..f280a45174 100644
--- a/test/functional/ex_cmds/sign_spec.lua
+++ b/test/functional/ex_cmds/sign_spec.lua
@@ -1,5 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
-local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq
+local clear, nvim, eq, assert_alive = helpers.clear, helpers.nvim, helpers.eq, helpers.assert_alive
describe('sign', function()
before_each(clear)
@@ -21,4 +21,11 @@ describe('sign', function()
end)
end)
end)
+
+ describe('define {id}', function()
+ it ('does not leak memory when specifying multiple times the same argument', function()
+ nvim('command', 'sign define Foo culhl=Normal culhl=Normal')
+ assert_alive()
+ end)
+ end)
end)
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index fa650d611b..13a40fcc53 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -19,6 +19,26 @@ describe(':source', function()
clear()
end)
+ it('sourcing a file that is deleted and recreated is consistent vim-patch:8.1.0151', function()
+ local test_file = 'Xfile.vim'
+ local other_file = 'Xfoobar'
+ local script = [[
+ func Func()
+ endfunc
+ ]]
+ write_file(test_file, script)
+ command('source ' .. test_file)
+ os.remove(test_file)
+ write_file(test_file, script)
+ command('source ' .. test_file)
+ os.remove(test_file)
+ write_file(other_file, '')
+ write_file(test_file, script)
+ command('source ' .. test_file)
+ os.remove(other_file)
+ os.remove(test_file)
+ end)
+
it('current buffer', function()
insert([[
let a = 2
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index d91feb4bc1..4d984af41e 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -10,6 +10,7 @@ local feed = helpers.feed
local nvim_prog = helpers.nvim_prog
local ok = helpers.ok
local rmdir = helpers.rmdir
+local os_kill = helpers.os_kill
local set_session = helpers.set_session
local spawn = helpers.spawn
local nvim_async = helpers.nvim_async
@@ -62,6 +63,7 @@ describe(':preserve', function()
local swappath1 = eval('g:swapname')
+ os_kill(eval('getpid()'))
-- Start another Nvim instance.
local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
true)
@@ -122,6 +124,7 @@ describe('swapfile detection', function()
feed('isometext<esc>')
command('preserve')
+ os_kill(eval('getpid()'))
-- Start another Nvim instance.
local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'},
true)
diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua
new file mode 100644
index 0000000000..e6f67ef18e
--- /dev/null
+++ b/test/functional/ex_cmds/verbose_spec.lua
@@ -0,0 +1,168 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec = helpers.exec
+local exec_capture = helpers.exec_capture
+local write_file = helpers.write_file
+local call_viml_function = helpers.meths.call_function
+
+describe('lua :verbose', function()
+ local script_location, script_file
+ -- All test cases below use the same nvim instance.
+ setup(function()
+ clear{args={'-V1'}}
+ script_file = 'test_verbose.lua'
+ local current_dir = call_viml_function('getcwd', {})
+ current_dir = call_viml_function('fnamemodify', {current_dir, ':~'})
+ script_location = table.concat{current_dir, helpers.get_pathsep(), script_file}
+
+ write_file(script_file, [[
+vim.api.nvim_set_option('hlsearch', false)
+vim.bo.expandtab = true
+vim.opt.number = true
+vim.api.nvim_set_keymap('n', '<leader>key1', ':echo "test"<cr>', {noremap = true})
+vim.keymap.set('n', '<leader>key2', ':echo "test"<cr>')
+
+vim.api.nvim_exec("augroup test_group\
+ autocmd!\
+ autocmd FileType c setl cindent\
+ augroup END\
+ ", false)
+
+vim.api.nvim_command("command Bdelete :bd")
+vim.api.nvim_create_user_command("TestCommand", ":echo 'Hello'", {})
+
+vim.api.nvim_exec ("\
+function Close_Window() abort\
+ wincmd -\
+endfunction\
+", false)
+
+local ret = vim.api.nvim_exec ("\
+function! s:return80()\
+ return 80\
+endfunction\
+let &tw = s:return80()\
+", true)
+]])
+ exec(':source '..script_file)
+ end)
+
+ teardown(function()
+ os.remove(script_file)
+ end)
+
+ it('"Last set" for option set by Lua', function()
+ local result = exec_capture(':verbose set hlsearch?')
+ eq(string.format([[
+nohlsearch
+ Last set from %s line 1]],
+ script_location), result)
+ end)
+
+ it('"Last set" for option set by vim.o', function()
+ local result = exec_capture(':verbose set expandtab?')
+ eq(string.format([[
+ expandtab
+ Last set from %s line 2]],
+ script_location), result)
+ end)
+
+ it('"Last set" for option set by vim.opt', function()
+ local result = exec_capture(':verbose set number?')
+ eq(string.format([[
+ number
+ Last set from %s line 3]],
+ script_location), result)
+ end)
+
+ it('"Last set" for keymap set by Lua', function()
+ local result = exec_capture(':verbose map <leader>key1')
+ eq(string.format([[
+
+n \key1 * :echo "test"<CR>
+ Last set from %s line 4]],
+ script_location), result)
+ end)
+
+ it('"Last set" for keymap set by vim.keymap', function()
+ local result = exec_capture(':verbose map <leader>key2')
+ eq(string.format([[
+
+n \key2 * :echo "test"<CR>
+ Last set from %s line 5]],
+ script_location), result)
+ end)
+
+ it('"Last set" for autocmd by vim.api.nvim_exec', function()
+ local result = exec_capture(':verbose autocmd test_group Filetype c')
+ eq(string.format([[
+--- Autocommands ---
+test_group FileType
+ c setl cindent
+ Last set from %s line 7]],
+ script_location), result)
+ end)
+
+ it('"Last set" for command defined by nvim_command', function()
+ local result = exec_capture(':verbose command Bdelete')
+ eq(string.format([[
+ Name Args Address Complete Definition
+ Bdelete 0 :bd
+ Last set from %s line 13]],
+ script_location), result)
+ end)
+
+ it('"Last set" for command defined by nvim_create_user_command', function()
+ local result = exec_capture(':verbose command TestCommand')
+ eq(string.format([[
+ Name Args Address Complete Definition
+ TestCommand 0 :echo 'Hello'
+ Last set from %s line 14]],
+ script_location), result)
+ end)
+
+ it('"Last set for function', function()
+ local result = exec_capture(':verbose function Close_Window')
+ eq(string.format([[
+ function Close_Window() abort
+ Last set from %s line 16
+1 wincmd -
+ endfunction]],
+ script_location), result)
+ end)
+
+ it('"Last set" works with anonymous sid', function()
+ local result = exec_capture(':verbose set tw?')
+ eq(string.format([[
+ textwidth=80
+ Last set from %s line 22]],
+ script_location), result)
+ end)
+end)
+
+describe('lua verbose:', function()
+ local script_file
+
+ setup(function()
+ clear()
+ script_file = 'test_luafile.lua'
+ write_file(script_file, [[
+ vim.api.nvim_set_option('hlsearch', false)
+ ]])
+ exec(':source '..script_file)
+ end)
+
+ teardown(function()
+ os.remove(script_file)
+ end)
+
+ it('is disabled when verbose = 0', function()
+ local result = exec_capture(':verbose set hlsearch?')
+ eq([[
+nohlsearch
+ Last set from Lua]], result)
+ end)
+end)
+
diff --git a/test/functional/fixtures/CMakeLists.txt b/test/functional/fixtures/CMakeLists.txt
index 270540de2e..a5410c2f8c 100644
--- a/test/functional/fixtures/CMakeLists.txt
+++ b/test/functional/fixtures/CMakeLists.txt
@@ -2,9 +2,11 @@ add_executable(tty-test EXCLUDE_FROM_ALL tty-test.c)
target_link_libraries(tty-test ${LIBUV_LIBRARIES})
add_executable(shell-test EXCLUDE_FROM_ALL shell-test.c)
+# Fake pwsh (powershell) for testing make_filter_cmd(). #16271
+add_executable(pwsh-test EXCLUDE_FROM_ALL shell-test.c)
add_executable(printargs-test EXCLUDE_FROM_ALL printargs-test.c)
add_executable(printenv-test EXCLUDE_FROM_ALL printenv-test.c)
-if(WIN32)
+if(MINGW)
set_target_properties(printenv-test PROPERTIES LINK_FLAGS -municode)
endif()
diff --git a/test/functional/fixtures/api_level_9.mpack b/test/functional/fixtures/api_level_9.mpack
new file mode 100644
index 0000000000..650d7a6a4d
--- /dev/null
+++ b/test/functional/fixtures/api_level_9.mpack
Binary files differ
diff --git a/test/functional/fixtures/autoload/provider/python.vim b/test/functional/fixtures/autoload/provider/python3.vim
index d68360ac30..8ed4330a35 100644
--- a/test/functional/fixtures/autoload/provider/python.vim
+++ b/test/functional/fixtures/autoload/provider/python3.vim
@@ -1,6 +1,6 @@
" Dummy test provider, missing this required variable:
" let g:loaded_brokenenabled_provider = 0
-function! provider#python#Call(method, args)
+function! provider#python3#Call(method, args)
return 42
endfunction
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 5c0de50731..0dc0c8c2db 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -28,7 +28,10 @@ local function assert_eq(a, b, ...)
if not vim.deep_equal(a, b) then
error(message_parts(": ",
..., "assert_eq failed",
- string.format("left == %q, right == %q", vim.inspect(a), vim.inspect(b))
+ string.format("left == %q, right == %q",
+ table.concat(vim.split(vim.inspect(a), "\n"), ""),
+ table.concat(vim.split(vim.inspect(b), "\n"), "")
+ )
))
end
end
@@ -100,8 +103,12 @@ local tests = {}
function tests.basic_init()
skeleton {
- on_init = function(_params)
- return { capabilities = {} }
+ on_init = function(_)
+ return {
+ capabilities = {
+ textDocumentSync = protocol.TextDocumentSyncKind.None;
+ }
+ }
end;
body = function()
notify('test')
@@ -109,6 +116,19 @@ function tests.basic_init()
}
end
+function tests.basic_init_did_change_configuration()
+ skeleton({
+ on_init = function(_)
+ return {
+ capabilities = {},
+ }
+ end,
+ body = function()
+ expect_notification('workspace/didChangeConfiguration', { settings = { dummy = 1 } })
+ end,
+ })
+end
+
function tests.check_workspace_configuration()
skeleton {
on_init = function(_params)
@@ -119,8 +139,10 @@ function tests.check_workspace_configuration()
notify('workspace/configuration', { items = {
{ section = "testSetting1" };
{ section = "testSetting2" };
+ { section = "test.Setting3" };
+ { section = "test.Setting4" };
} })
- expect_notification('workspace/configuration', { true; vim.NIL})
+ expect_notification('workspace/configuration', { true; false; 'nested'; vim.NIL})
notify('shutdown')
end;
}
@@ -130,8 +152,11 @@ function tests.prepare_rename_nil()
skeleton {
on_init = function()
return { capabilities = {
- renameProvider = true,
- } }
+ renameProvider = {
+ prepareProvider = true
+ }
+ }
+ }
end;
body = function()
notify('start')
@@ -147,8 +172,11 @@ function tests.prepare_rename_placeholder()
skeleton {
on_init = function()
return { capabilities = {
- renameProvider = true,
- } }
+ renameProvider = {
+ prepareProvider = true
+ }
+ }
+ }
end;
body = function()
notify('start')
@@ -168,8 +196,11 @@ function tests.prepare_rename_range()
skeleton {
on_init = function()
return { capabilities = {
- renameProvider = true,
- } }
+ renameProvider = {
+ prepareProvider = true
+ }
+ }
+ }
end;
body = function()
notify('start')
@@ -191,19 +222,19 @@ end
function tests.prepare_rename_error()
skeleton {
on_init = function()
- return { capabilities = {
- renameProvider = true,
- } }
+ return {
+ capabilities = {
+ renameProvider = {
+ prepareProvider = true
+ },
+ }
+ }
end;
body = function()
notify('start')
expect_request('textDocument/prepareRename', function()
return {}, nil
end)
- expect_request('textDocument/rename', function(params)
- assert_eq(params.newName, 'renameto')
- return nil, nil
- end)
notify('shutdown')
end;
}
@@ -217,6 +248,7 @@ function tests.basic_check_capabilities()
return {
capabilities = {
textDocumentSync = protocol.TextDocumentSyncKind.Full;
+ codeLensProvider = false
}
}
end;
@@ -225,6 +257,51 @@ function tests.basic_check_capabilities()
}
end
+function tests.text_document_sync_save_bool()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ textDocumentSync = {
+ save = true
+ }
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ expect_notification('textDocument/didSave', {textDocument = { uri = "file://" }})
+ notify('shutdown')
+ end;
+ }
+end
+
+function tests.text_document_sync_save_includeText()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ textDocumentSync = {
+ save = {
+ includeText = true
+ }
+ }
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ expect_notification('textDocument/didSave', {
+ textDocument = {
+ uri = "file://"
+ },
+ text = "help me\n"
+ })
+ notify('shutdown')
+ end;
+ }
+end
+
function tests.capabilities_for_client_supports_method()
skeleton {
on_init = function(params)
@@ -235,6 +312,7 @@ function tests.capabilities_for_client_supports_method()
textDocumentSync = protocol.TextDocumentSyncKind.Full;
completionProvider = true;
hoverProvider = true;
+ renameProvider = false;
definitionProvider = false;
referencesProvider = false;
codeLensProvider = { resolveProvider = true; };
@@ -542,7 +620,15 @@ function tests.basic_check_buffer_open_and_change_incremental()
assert_eq(params.capabilities, expected_capabilities)
return {
capabilities = {
- textDocumentSync = protocol.TextDocumentSyncKind.Incremental;
+ textDocumentSync = {
+ openClose = true,
+ change = protocol.TextDocumentSyncKind.Incremental,
+ willSave = true,
+ willSaveWaitUntil = true,
+ save = {
+ includeText = true,
+ }
+ }
}
}
end;
@@ -671,6 +757,78 @@ function tests.code_action_with_resolve()
}
end
+function tests.code_action_server_side_command()
+ skeleton({
+ on_init = function()
+ return {
+ capabilities = {
+ codeActionProvider = {
+ resolveProvider = false,
+ },
+ },
+ }
+ end,
+ body = function()
+ notify('start')
+ local cmd = {
+ title = 'Command 1',
+ command = 'dummy1',
+ }
+ expect_request('textDocument/codeAction', function()
+ return nil, { cmd }
+ end)
+ expect_request('workspace/executeCommand', function()
+ return nil, cmd
+ end)
+ notify('shutdown')
+ end,
+ })
+end
+
+
+function tests.code_action_filter()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ codeActionProvider = {
+ resolveProvider = false
+ }
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ local action = {
+ title = 'Action 1',
+ command = 'command'
+ }
+ local preferred_action = {
+ title = 'Action 2',
+ isPreferred = true,
+ command = 'preferred_command',
+ }
+ local quickfix_action = {
+ title = 'Action 3',
+ kind = 'quickfix',
+ command = 'quickfix_command',
+ }
+ local quickfix_foo_action = {
+ title = 'Action 4',
+ kind = 'quickfix.foo',
+ command = 'quickfix_foo_command',
+ }
+ expect_request('textDocument/codeAction', function()
+ return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, }
+ end)
+ expect_request('textDocument/codeAction', function()
+ return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, }
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
function tests.clientside_commands()
skeleton {
on_init = function()
@@ -685,6 +843,68 @@ function tests.clientside_commands()
}
end
+function tests.codelens_refresh_lock()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ codeLensProvider = { resolveProvider = true; };
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ expect_request("textDocument/codeLens", function ()
+ return {code = -32002, message = "ServerNotInitialized"}, nil
+ end)
+ expect_request("textDocument/codeLens", function ()
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 3 }
+ },
+ command = { title = 'Lens1', command = 'Dummy' }
+ },
+ }
+ return nil, lenses
+ end)
+ expect_request("textDocument/codeLens", function ()
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 3 }
+ },
+ command = { title = 'Lens2', command = 'Dummy' }
+ },
+ }
+ return nil, lenses
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
+function tests.basic_formatting()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ documentFormattingProvider = true,
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ expect_request('textDocument/formatting', function()
+ return nil, {}
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
-- Tests will be indexed by TEST_NAME
local kill_timer = vim.loop.new_timer()
diff --git a/test/functional/fixtures/lua/test_plug/health/init.lua b/test/functional/fixtures/lua/test_plug/health/init.lua
index d07632cff4..58162d4515 100644
--- a/test/functional/fixtures/lua/test_plug/health/init.lua
+++ b/test/functional/fixtures/lua/test_plug/health/init.lua
@@ -1,11 +1,10 @@
local M = {}
-local health = require("health")
M.check = function()
- health.report_start("report 1")
- health.report_ok("everything is fine")
- health.report_start("report 2")
- health.report_ok("nothing to see here")
+ vim.health.report_start("report 1")
+ vim.health.report_ok("everything is fine")
+ vim.health.report_start("report 2")
+ vim.health.report_ok("nothing to see here")
end
return M
diff --git a/test/functional/fixtures/lua/test_plug/submodule/health.lua b/test/functional/fixtures/lua/test_plug/submodule/health.lua
index d07632cff4..58162d4515 100644
--- a/test/functional/fixtures/lua/test_plug/submodule/health.lua
+++ b/test/functional/fixtures/lua/test_plug/submodule/health.lua
@@ -1,11 +1,10 @@
local M = {}
-local health = require("health")
M.check = function()
- health.report_start("report 1")
- health.report_ok("everything is fine")
- health.report_start("report 2")
- health.report_ok("nothing to see here")
+ vim.health.report_start("report 1")
+ vim.health.report_ok("everything is fine")
+ vim.health.report_start("report 2")
+ vim.health.report_ok("nothing to see here")
end
return M
diff --git a/test/functional/fixtures/lua/test_plug/submodule_empty/health.lua b/test/functional/fixtures/lua/test_plug/submodule_empty/health.lua
new file mode 100644
index 0000000000..d2cf86e4f0
--- /dev/null
+++ b/test/functional/fixtures/lua/test_plug/submodule_empty/health.lua
@@ -0,0 +1,7 @@
+local M = {}
+
+M.check = function()
+ return {}
+end
+
+return M
diff --git a/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua b/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua
index 3a8af6ebb2..ee5f4e404b 100644
--- a/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua
+++ b/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua
@@ -1,10 +1,9 @@
local M = {}
-local health = require("health")
M.check = function()
- health.report_start("report 1")
- health.report_ok("everything is fine")
- health.report_warn("About to add a number to nil")
+ vim.health.report_start("report 1")
+ vim.health.report_ok("everything is fine")
+ vim.health.report_warn("About to add a number to nil")
local a = nil + 2
return a
end
diff --git a/test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua b/test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua
new file mode 100644
index 0000000000..c1c33d787e
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/start/bar/lua/baz-quux.lua
@@ -0,0 +1 @@
+return {doit=function() return 9004 end}
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 1845786c4b..0c616e73fb 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -21,7 +21,6 @@ local map = global_helpers.tbl_map
local ok = global_helpers.ok
local sleep = global_helpers.sleep
local tbl_contains = global_helpers.tbl_contains
-local write_file = global_helpers.write_file
local fail = global_helpers.fail
local module = {
@@ -42,10 +41,8 @@ module.nvim_set = (
module.nvim_argv = {
module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
'--cmd', module.nvim_set,
- '--cmd', 'unmap Y',
- '--cmd', 'unmap <C-L>',
- '--cmd', 'iunmap <C-U>',
- '--cmd', 'iunmap <C-W>',
+ '--cmd', 'mapclear',
+ '--cmd', 'mapclear!',
'--embed'}
-- Directory containing nvim.
@@ -54,7 +51,6 @@ if module.nvim_dir == module.nvim_prog then
module.nvim_dir = "."
end
-local tmpname = global_helpers.tmpname
local iswin = global_helpers.iswin
local prepend_argv
@@ -274,6 +270,13 @@ function module.command(cmd)
module.request('nvim_command', cmd)
end
+
+-- use for commands which expect nvim to quit
+function module.expect_exit(...)
+ eq("EOF was received from Nvim. Likely the Nvim process crashed.",
+ module.pcall_err(...))
+end
+
-- Evaluates a VimL expression.
-- Fails on VimL error, but does not update v:errmsg.
function module.eval(expr)
@@ -363,14 +366,15 @@ local function remove_args(args, args_rm)
return new_args
end
-function module.spawn(argv, merge, env, keep)
+--- @param io_extra used for stdin_fd, see :help ui-option
+function module.spawn(argv, merge, env, keep, io_extra)
if session and not keep then
session:close()
end
local child_stream = ChildProcessStream.spawn(
merge and module.merge_args(prepend_argv, argv) or argv,
- env)
+ env, io_extra)
return Session.new(child_stream)
end
@@ -417,8 +421,8 @@ end
-- clear('-e')
-- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}}
function module.clear(...)
- local argv, env = module.new_argv(...)
- module.set_session(module.spawn(argv, nil, env))
+ local argv, env, io_extra = module.new_argv(...)
+ module.set_session(module.spawn(argv, nil, env, nil, io_extra))
end
-- Builds an argument list for use in clear().
@@ -427,17 +431,25 @@ end
function module.new_argv(...)
local args = {unpack(module.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)
+ end
local new_args
+ local io_extra
local env = nil
local opts = select(1, ...)
- if type(opts) == 'table' then
+ if type(opts) ~= 'table' then
+ new_args = {...}
+ else
args = remove_args(args, opts.args_rm)
if opts.env then
- local env_tbl = {}
+ local env_opt = {}
for k, v in pairs(opts.env) do
assert(type(k) == 'string')
assert(type(v) == 'string')
- env_tbl[k] = v
+ env_opt[k] = v
end
for _, k in ipairs({
'HOME',
@@ -453,23 +465,23 @@ function module.new_argv(...)
'TMPDIR',
'VIMRUNTIME',
}) do
- if not env_tbl[k] then
- env_tbl[k] = os.getenv(k)
+ -- Set these from the environment unless the caller defined them.
+ if not env_opt[k] then
+ env_opt[k] = os.getenv(k)
end
end
env = {}
- for k, v in pairs(env_tbl) do
+ for k, v in pairs(env_opt) do
env[#env + 1] = k .. '=' .. v
end
end
new_args = opts.args or {}
- else
- new_args = {...}
+ io_extra = opts.io_extra
end
for _, arg in ipairs(new_args) do
table.insert(args, arg)
end
- return args, env
+ return args, env, io_extra
end
function module.insert(...)
@@ -494,44 +506,38 @@ function module.feed_command(...)
end
end
-local sourced_fnames = {}
+-- @deprecated use nvim_exec()
function module.source(code)
- local fname = tmpname()
- write_file(fname, code)
- module.command('source '..fname)
- -- DO NOT REMOVE FILE HERE.
- -- do_source() has a habit of checking whether files are “same” by using inode
- -- and device IDs. If you run two source() calls in quick succession there is
- -- a good chance that underlying filesystem will reuse the inode, making files
- -- appear as “symlinks” to do_source when it checks FileIDs. With current
- -- setup linux machines (both QB, travis and mine(ZyX-I) with XFS) do reuse
- -- inodes, Mac OS machines (again, both QB and travis) do not.
- --
- -- Files appearing as “symlinks” mean that both the first and the second
- -- source() calls will use same SID, which may fail some tests which check for
- -- exact numbers after `<SNR>` in e.g. function names.
- sourced_fnames[#sourced_fnames + 1] = fname
- return fname
+ module.exec(dedent(code))
end
function module.has_powershell()
return module.eval('executable("'..(iswin() and 'powershell' or 'pwsh')..'")') == 1
end
-function module.set_shell_powershell()
- local shell = iswin() and 'powershell' or 'pwsh'
- assert(module.has_powershell())
+--- Sets Nvim shell to powershell.
+---
+--- @param fake (boolean) If true, a fake will be used if powershell is not
+--- found on the system.
+--- @returns true if powershell was found on the system, else false.
+function module.set_shell_powershell(fake)
+ local found = module.has_powershell()
+ if not fake then
+ assert(found)
+ end
+ local shell = found and (iswin() and 'powershell' or 'pwsh') or module.testprg('pwsh-test')
local set_encoding = '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;'
local cmd = set_encoding..'Remove-Item -Force '..table.concat(iswin()
and {'alias:cat', 'alias:echo', 'alias:sleep'}
or {'alias:echo'}, ',')..';'
- module.source([[
+ module.exec([[
let &shell = ']]..shell..[['
set shellquote= shellxquote=
- let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
- let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ]]..cmd..[['
+ let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode'
+ let &shellredir = '-RedirectStandardOutput %s -NoNewWindow -Wait'
]])
+ return found
end
function module.nvim(method, ...)
@@ -736,14 +742,10 @@ function module.pending_win32(pending_fn)
end
function module.pending_c_parser(pending_fn)
- local status, msg = unpack(module.exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]]))
+ local status, _ = unpack(module.exec_lua([[ return {pcall(vim.treesitter.require_language, 'c')} ]]))
if not status then
- if module.isCI() then
- error("treesitter C parser not found, required on CI: " .. msg)
- else
- pending_fn 'no C parser, skipping'
- return true
- end
+ pending_fn 'no C parser, skipping'
+ return true
end
return false
end
@@ -791,12 +793,22 @@ function module.get_pathsep()
return iswin() and '\\' or '/'
end
+--- Gets the filesystem root dir, namely "/" or "C:/".
function module.pathroot()
local pathsep = package.config:sub(1,1)
return iswin() and (module.nvim_dir:sub(1,2)..pathsep) or '/'
end
--- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
+--- Gets the full `…/build/bin/{name}` path of a test program produced by
+--- `test/functional/fixtures/CMakeLists.txt`.
+---
+--- @param name (string) Name of the test program.
+function module.testprg(name)
+ local ext = module.iswin() and '.exe' or ''
+ return ('%s/%s%s'):format(module.nvim_dir, name, ext)
+end
+
+-- Returns a valid, platform-independent Nvim listen address.
-- Useful for communicating with child instances.
function module.new_pipename()
-- HACK: Start a server temporarily, get the name, then stop it.
@@ -887,9 +899,6 @@ module = global_helpers.tbl_extend('error', module, global_helpers)
return function(after_each)
if after_each then
after_each(function()
- for _, fname in ipairs(sourced_fnames) do
- os.remove(fname)
- end
check_logs()
check_cores('build/bin/nvim')
if session then
diff --git a/test/functional/legacy/003_cindent_spec.lua b/test/functional/legacy/003_cindent_spec.lua
deleted file mode 100644
index 061904c42f..0000000000
--- a/test/functional/legacy/003_cindent_spec.lua
+++ /dev/null
@@ -1,4774 +0,0 @@
--- Test for 'cindent'.
--- For new tests, consider putting them in test_cindent.vim.
---
--- There are 50+ test command blocks (the stuff between STARTTEST and ENDTEST)
--- in the original test. These have been converted to "it" test cases here.
-
-local helpers = require('test.functional.helpers')(after_each)
-local feed, insert = helpers.feed, helpers.insert
-local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
-
--- Inserts text as usual, and additionally positions the cursor on line 1 and
--- sets 'cindent' and tab settings. (In the original "test3.in" the modeline at
--- the top of the file takes care of this.)
-local function insert_(content)
- insert(content)
- feed_command('1', 'set cin ts=4 sw=4')
-end
-
--- luacheck: ignore 621 (Indentation)
--- luacheck: ignore 613 (Trailing whitespace in a string)
-describe('cindent', function()
- before_each(clear)
-
- it('1 is working', function()
- insert_([=[
-
- /* start of AUTO matically checked vim: set ts=4 : */
- {
- if (test)
- cmd1;
- cmd2;
- }
-
- {
- if (test)
- cmd1;
- else
- cmd2;
- }
-
- {
- if (test)
- {
- cmd1;
- cmd2;
- }
- }
-
- {
- if (test)
- {
- cmd1;
- else
- }
- }
-
- {
- while (this)
- if (test)
- cmd1;
- cmd2;
- }
-
- {
- while (this)
- if (test)
- cmd1;
- else
- cmd2;
- }
-
- {
- if (test)
- {
- cmd;
- }
-
- if (test)
- cmd;
- }
-
- {
- if (test) {
- cmd;
- }
-
- if (test) cmd;
- }
-
- {
- cmd1;
- for (blah)
- while (this)
- if (test)
- cmd2;
- cmd3;
- }
-
- {
- cmd1;
- for (blah)
- while (this)
- if (test)
- cmd2;
- cmd3;
-
- if (test)
- {
- cmd1;
- cmd2;
- cmd3;
- }
- }
-
-
- /* Test for 'cindent' do/while mixed with if/else: */
-
- {
- do
- if (asdf)
- asdfasd;
- while (cond);
-
- do
- if (asdf)
- while (asdf)
- asdf;
- while (asdf);
- }
-
- /* Test for 'cindent' with two ) on a continuation line */
- {
- if (asdfasdf;asldkfj asdlkfj as;ldkfj sal;d
- aal;sdkjf ( ;asldfkja;sldfk
- al;sdjfka ;slkdf ) sa;ldkjfsa dlk;)
- line up here;
- }
-
-
- /* C++ tests: */
-
- // foo() these three lines should remain in column 0
- // {
- // }
-
- /* Test for continuation and unterminated lines: */
- {
- i = 99 + 14325 +
- 21345 +
- 21345 +
- 21345 + ( 21345 +
- 21345) +
- 2345 +
- 1234;
- c = 1;
- }
-
- /*
- testje for indent with empty line
-
- here */
-
- {
- if (testing &&
- not a joke ||
- line up here)
- hay;
- if (testing &&
- (not a joke || testing
- )line up here)
- hay;
- if (testing &&
- (not a joke || testing
- line up here))
- hay;
- }
-
-
- {
- switch (c)
- {
- case xx:
- do
- if (asdf)
- do
- asdfasdf;
- while (asdf);
- else
- asdfasdf;
- while (cond);
- case yy:
- case xx:
- case zz:
- testing;
- }
- }
-
- {
- if (cond) {
- foo;
- }
- else
- {
- bar;
- }
- }
-
- {
- if (alskdfj ;alsdkfjal;skdjf (;sadlkfsa ;dlkf j;alksdfj ;alskdjf
- alsdkfj (asldk;fj
- awith cino=(0 ;lf this one goes to below the paren with ==
- ;laksjfd ;lsakdjf ;alskdf asd)
- asdfasdf;)))
- asdfasdf;
- }
-
- int
- func(a, b)
- int a;
- int c;
- {
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3)
- )
- }
-
- {
- while (asd)
- {
- if (asdf)
- if (test)
- if (that)
- {
- if (asdf)
- do
- cdasd;
- while (as
- df);
- }
- else
- if (asdf)
- asdf;
- else
- asdf;
- asdf;
- }
- }
-
- {
- s = "/*"; b = ';'
- s = "/*"; b = ';';
- a = b;
- }
-
- {
- switch (a)
- {
- case a:
- switch (t)
- {
- case 1:
- cmd;
- break;
- case 2:
- cmd;
- break;
- }
- cmd;
- break;
- case b:
- {
- int i;
- cmd;
- }
- break;
- case c: {
- int i;
- cmd;
- }
- case d: if (cond &&
- test) { /* this line doesn't work right */
- int i;
- cmd;
- }
- break;
- }
- }
-
- {
- if (!(vim_strchr(p_cpo, CPO_BUFOPTGLOB) != NULL && entering) &&
- (bp_to->b_p_initialized ||
- (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
- return;
- label :
- asdf = asdf ?
- asdf : asdf;
- asdf = asdf ?
- asdf: asdf;
- }
-
- /* Special Comments : This function has the added complexity (compared */
- /* : to addtolist) of having to check for a detail */
- /* : texture and add that to the list first. */
-
- char *(array[100]) = {
- "testje",
- "foo",
- "bar",
- }
-
- enum soppie
- {
- yes = 0,
- no,
- maybe
- };
-
- typedef enum soppie
- {
- yes = 0,
- no,
- maybe
- };
-
- static enum
- {
- yes = 0,
- no,
- maybe
- } soppie;
-
- public static enum
- {
- yes = 0,
- no,
- maybe
- } soppie;
-
- static private enum
- {
- yes = 0,
- no,
- maybe
- } soppie;
-
- {
- int a,
- b;
- }
-
- {
- struct Type
- {
- int i;
- char *str;
- } var[] =
- {
- 0, "zero",
- 1, "one",
- 2, "two",
- 3, "three"
- };
-
- float matrix[3][3] =
- {
- {
- 0,
- 1,
- 2
- },
- {
- 3,
- 4,
- 5
- },
- {
- 6,
- 7,
- 8
- }
- };
- }
-
- {
- /* blah ( blah */
- /* where does this go? */
-
- /* blah ( blah */
- cmd;
-
- func(arg1,
- /* comment */
- arg2);
- a;
- {
- b;
- {
- c; /* Hey, NOW it indents?! */
- }
- }
-
- {
- func(arg1,
- arg2,
- arg3);
- /* Hey, what am I doing here? Is this coz of the ","? */
- }
- }
-
- main ()
- {
- if (cond)
- {
- a = b;
- }
- if (cond) {
- a = c;
- }
- if (cond)
- a = d;
- return;
- }
-
- {
- case 2: if (asdf &&
- asdfasdf)
- aasdf;
- a = 9;
- case 3: if (asdf)
- aasdf;
- a = 9;
- case 4: x = 1;
- y = 2;
-
- label: if (asdf)
- here;
-
- label: if (asdf &&
- asdfasdf)
- {
- }
-
- label: if (asdf &&
- asdfasdf) {
- there;
- }
-
- label: if (asdf &&
- asdfasdf)
- there;
- }
-
- {
- /*
- hello with ":set comments= cino=c5"
- */
-
- /*
- hello with ":set comments= cino="
- */
- }
-
-
- {
- if (a < b) {
- a = a + 1;
- } else
- a = a + 2;
-
- if (a)
- do {
- testing;
- } while (asdfasdf);
- a = b + 1;
- asdfasdf
- }
-
- {
- for ( int i = 0;
- i < 10; i++ )
- {
- }
- i = 0;
- }
-
- class bob
- {
- int foo() {return 1;}
- int bar;
- }
-
- main()
- {
- while(1)
- if (foo)
- {
- bar;
- }
- else {
- asdf;
- }
- misplacedline;
- }
-
- {
- if (clipboard.state == SELECT_DONE
- && ((row == clipboard.start.lnum
- && col >= clipboard.start.col)
- || row > clipboard.start.lnum))
- }
-
- {
- if (1) {i += 4;}
- where_am_i;
- return 0;
- }
-
- {
- {
- } // sdf(asdf
- if (asdf)
- asd;
- }
-
- {
- label1:
- label2:
- }
-
- {
- int fooRet = foo(pBar1, false /*fKB*/,
- true /*fPTB*/, 3 /*nT*/, false /*fDF*/);
- f() {
- for ( i = 0;
- i < m;
- /* c */ i++ ) {
- a = b;
- }
- }
- }
-
- {
- f1(/*comment*/);
- f2();
- }
-
- {
- do {
- if (foo) {
- } else
- ;
- } while (foo);
- foo(); // was wrong
- }
-
- int x; // no extra indent because of the ;
- void func()
- {
- }
-
- char *tab[] = {"aaa",
- "};", /* }; */ NULL}
- int indented;
- {}
-
- char *a[] = {"aaa", "bbb",
- "ccc", NULL};
- // here
-
- char *tab[] = {"aaa",
- "xx", /* xx */}; /* asdf */
- int not_indented;
-
- {
- do {
- switch (bla)
- {
- case 1: if (foo)
- bar;
- }
- } while (boo);
- wrong;
- }
-
- int foo,
- bar;
- int foo;
-
- #if defined(foo) \
- && defined(bar)
- char * xx = "asdf\
- foo\
- bor";
- int x;
-
- char *foo = "asdf\
- asdf\
- asdf",
- *bar;
-
- void f()
- {
- #if defined(foo) \
- && defined(bar)
- char *foo = "asdf\
- asdf\
- asdf",
- *bar;
- {
- int i;
- char *foo = "asdf\
- asdf\
- asdf",
- *bar;
- }
- #endif
- }
- #endif
-
- int y; // comment
- // comment
-
- // comment
-
- {
- Constructor(int a,
- int b ) : BaseClass(a)
- {
- }
- }
-
- void foo()
- {
- char one,
- two;
- struct bla piet,
- jan;
- enum foo kees,
- jannie;
- static unsigned sdf,
- krap;
- unsigned int piet,
- jan;
- int
- kees,
- jan;
- }
-
- {
- t(int f,
- int d); // )
- d();
- }
-
- Constructor::Constructor(int a,
- int b
- ) :
- BaseClass(a,
- b,
- c),
- mMember(b),
- {
- }
-
- Constructor::Constructor(int a,
- int b ) :
- BaseClass(a)
- {
- }
-
- Constructor::Constructor(int a,
- int b ) /*x*/ : /*x*/ BaseClass(a),
- member(b)
- {
- }
-
- A::A(int a, int b)
- : aa(a),
- bb(b),
- cc(c)
- {
- }
-
- class CAbc :
- public BaseClass1,
- protected BaseClass2
- {
- int Test() { return FALSE; }
- int Test1() { return TRUE; }
-
- CAbc(int a, int b ) :
- BaseClass(a)
- {
- switch(xxx)
- {
- case abc:
- asdf();
- break;
-
- case 999:
- baer();
- break;
- }
- }
-
- public: // <-- this was incoreectly indented before!!
- void testfall();
- protected:
- void testfall();
- };
-
- class CAbc : public BaseClass1,
- protected BaseClass2
- {
- };
-
- static struct
- {
- int a;
- int b;
- } variable[COUNT] =
- {
- {
- 123,
- 456
- },
- {
- 123,
- 456
- }
- };
-
- static struct
- {
- int a;
- int b;
- } variable[COUNT] =
- {
- { 123, 456 },
- { 123, 456 }
- };
-
- void asdf() /* ind_maxparen may cause trouble here */
- {
- if ((0
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1)) break;
- }
-
- foo()
- {
- a = cond ? foo() : asdf
- + asdf;
-
- a = cond ?
- foo() : asdf
- + asdf;
- }
-
- int main(void)
- {
- if (a)
- if (b)
- 2;
- else 3;
- next_line_of_code();
- }
-
- barry()
- {
- Foo::Foo (int one,
- int two)
- : something(4)
- {}
- }
-
- barry()
- {
- Foo::Foo (int one, int two)
- : something(4)
- {}
- }
-
- Constructor::Constructor(int a,
- int b
- ) :
- BaseClass(a,
- b,
- c),
- mMember(b)
- {
- }
- int main ()
- {
- if (lala)
- do
- ++(*lolo);
- while (lili
- && lele);
- lulu;
- }
-
- int main ()
- {
- switch (c)
- {
- case 'c': if (cond)
- {
- }
- }
- }
-
- main()
- {
- (void) MyFancyFuasdfadsfnction(
- argument);
- }
-
- main()
- {
- char foo[] = "/*";
- /* as
- df */
- hello
- }
-
- /* valid namespaces with normal indent */
- namespace
- {
- {
- 111111111111;
- }
- }
- namespace /* test */
- {
- 11111111111111111;
- }
- namespace // test
- {
- 111111111111111111;
- }
- namespace
- {
- 111111111111111111;
- }
- namespace test
- {
- 111111111111111111;
- }
- namespace{
- 111111111111111111;
- }
- namespace test{
- 111111111111111111;
- }
- namespace {
- 111111111111111111;
- }
- namespace test {
- 111111111111111111;
- namespace test2 {
- 22222222222222222;
- }
- }
-
- /* invalid namespaces use block indent */
- namespace test test2 {
- 111111111111111111111;
- }
- namespace11111111111 {
- 111111111111;
- }
- namespace() {
- 1111111111111;
- }
- namespace()
- {
- 111111111111111111;
- }
- namespace test test2
- {
- 1111111111111111111;
- }
- namespace111111111
- {
- 111111111111111111;
- }
- void getstring() {
- /* Raw strings */
- const char* s = R"(
- test {
- # comment
- field: 123
- }
- )";
- }
- void getstring() {
- const char* s = R"foo(
- test {
- # comment
- field: 123
- }
- )foo";
- }
-
- {
- int a[4] = {
- [0] = 0,
- [1] = 1,
- [2] = 2,
- [3] = 3,
- };
- }
-
- {
- a = b[2]
- + 3;
- }
-
- {
- if (1)
- /* aaaaa
- * bbbbb
- */
- a = 1;
- }
-
- void func()
- {
- switch (foo)
- {
- case (bar):
- if (baz())
- quux();
- break;
- case (shmoo):
- if (!bar)
- {
- }
- case (foo1):
- switch (bar)
- {
- case baz:
- baz_f();
- break;
- }
- break;
- default:
- baz();
- baz();
- break;
- }
- }
-
- /* end of AUTO */
- ]=])
-
- feed_command('/start of AUTO')
- feed('=/end of AUTO<cr>')
-
- expect([=[
-
- /* start of AUTO matically checked vim: set ts=4 : */
- {
- if (test)
- cmd1;
- cmd2;
- }
-
- {
- if (test)
- cmd1;
- else
- cmd2;
- }
-
- {
- if (test)
- {
- cmd1;
- cmd2;
- }
- }
-
- {
- if (test)
- {
- cmd1;
- else
- }
- }
-
- {
- while (this)
- if (test)
- cmd1;
- cmd2;
- }
-
- {
- while (this)
- if (test)
- cmd1;
- else
- cmd2;
- }
-
- {
- if (test)
- {
- cmd;
- }
-
- if (test)
- cmd;
- }
-
- {
- if (test) {
- cmd;
- }
-
- if (test) cmd;
- }
-
- {
- cmd1;
- for (blah)
- while (this)
- if (test)
- cmd2;
- cmd3;
- }
-
- {
- cmd1;
- for (blah)
- while (this)
- if (test)
- cmd2;
- cmd3;
-
- if (test)
- {
- cmd1;
- cmd2;
- cmd3;
- }
- }
-
-
- /* Test for 'cindent' do/while mixed with if/else: */
-
- {
- do
- if (asdf)
- asdfasd;
- while (cond);
-
- do
- if (asdf)
- while (asdf)
- asdf;
- while (asdf);
- }
-
- /* Test for 'cindent' with two ) on a continuation line */
- {
- if (asdfasdf;asldkfj asdlkfj as;ldkfj sal;d
- aal;sdkjf ( ;asldfkja;sldfk
- al;sdjfka ;slkdf ) sa;ldkjfsa dlk;)
- line up here;
- }
-
-
- /* C++ tests: */
-
- // foo() these three lines should remain in column 0
- // {
- // }
-
- /* Test for continuation and unterminated lines: */
- {
- i = 99 + 14325 +
- 21345 +
- 21345 +
- 21345 + ( 21345 +
- 21345) +
- 2345 +
- 1234;
- c = 1;
- }
-
- /*
- testje for indent with empty line
-
- here */
-
- {
- if (testing &&
- not a joke ||
- line up here)
- hay;
- if (testing &&
- (not a joke || testing
- )line up here)
- hay;
- if (testing &&
- (not a joke || testing
- line up here))
- hay;
- }
-
-
- {
- switch (c)
- {
- case xx:
- do
- if (asdf)
- do
- asdfasdf;
- while (asdf);
- else
- asdfasdf;
- while (cond);
- case yy:
- case xx:
- case zz:
- testing;
- }
- }
-
- {
- if (cond) {
- foo;
- }
- else
- {
- bar;
- }
- }
-
- {
- if (alskdfj ;alsdkfjal;skdjf (;sadlkfsa ;dlkf j;alksdfj ;alskdjf
- alsdkfj (asldk;fj
- awith cino=(0 ;lf this one goes to below the paren with ==
- ;laksjfd ;lsakdjf ;alskdf asd)
- asdfasdf;)))
- asdfasdf;
- }
-
- int
- func(a, b)
- int a;
- int c;
- {
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3)
- )
- }
-
- {
- while (asd)
- {
- if (asdf)
- if (test)
- if (that)
- {
- if (asdf)
- do
- cdasd;
- while (as
- df);
- }
- else
- if (asdf)
- asdf;
- else
- asdf;
- asdf;
- }
- }
-
- {
- s = "/*"; b = ';'
- s = "/*"; b = ';';
- a = b;
- }
-
- {
- switch (a)
- {
- case a:
- switch (t)
- {
- case 1:
- cmd;
- break;
- case 2:
- cmd;
- break;
- }
- cmd;
- break;
- case b:
- {
- int i;
- cmd;
- }
- break;
- case c: {
- int i;
- cmd;
- }
- case d: if (cond &&
- test) { /* this line doesn't work right */
- int i;
- cmd;
- }
- break;
- }
- }
-
- {
- if (!(vim_strchr(p_cpo, CPO_BUFOPTGLOB) != NULL && entering) &&
- (bp_to->b_p_initialized ||
- (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
- return;
- label :
- asdf = asdf ?
- asdf : asdf;
- asdf = asdf ?
- asdf: asdf;
- }
-
- /* Special Comments : This function has the added complexity (compared */
- /* : to addtolist) of having to check for a detail */
- /* : texture and add that to the list first. */
-
- char *(array[100]) = {
- "testje",
- "foo",
- "bar",
- }
-
- enum soppie
- {
- yes = 0,
- no,
- maybe
- };
-
- typedef enum soppie
- {
- yes = 0,
- no,
- maybe
- };
-
- static enum
- {
- yes = 0,
- no,
- maybe
- } soppie;
-
- public static enum
- {
- yes = 0,
- no,
- maybe
- } soppie;
-
- static private enum
- {
- yes = 0,
- no,
- maybe
- } soppie;
-
- {
- int a,
- b;
- }
-
- {
- struct Type
- {
- int i;
- char *str;
- } var[] =
- {
- 0, "zero",
- 1, "one",
- 2, "two",
- 3, "three"
- };
-
- float matrix[3][3] =
- {
- {
- 0,
- 1,
- 2
- },
- {
- 3,
- 4,
- 5
- },
- {
- 6,
- 7,
- 8
- }
- };
- }
-
- {
- /* blah ( blah */
- /* where does this go? */
-
- /* blah ( blah */
- cmd;
-
- func(arg1,
- /* comment */
- arg2);
- a;
- {
- b;
- {
- c; /* Hey, NOW it indents?! */
- }
- }
-
- {
- func(arg1,
- arg2,
- arg3);
- /* Hey, what am I doing here? Is this coz of the ","? */
- }
- }
-
- main ()
- {
- if (cond)
- {
- a = b;
- }
- if (cond) {
- a = c;
- }
- if (cond)
- a = d;
- return;
- }
-
- {
- case 2: if (asdf &&
- asdfasdf)
- aasdf;
- a = 9;
- case 3: if (asdf)
- aasdf;
- a = 9;
- case 4: x = 1;
- y = 2;
-
- label: if (asdf)
- here;
-
- label: if (asdf &&
- asdfasdf)
- {
- }
-
- label: if (asdf &&
- asdfasdf) {
- there;
- }
-
- label: if (asdf &&
- asdfasdf)
- there;
- }
-
- {
- /*
- hello with ":set comments= cino=c5"
- */
-
- /*
- hello with ":set comments= cino="
- */
- }
-
-
- {
- if (a < b) {
- a = a + 1;
- } else
- a = a + 2;
-
- if (a)
- do {
- testing;
- } while (asdfasdf);
- a = b + 1;
- asdfasdf
- }
-
- {
- for ( int i = 0;
- i < 10; i++ )
- {
- }
- i = 0;
- }
-
- class bob
- {
- int foo() {return 1;}
- int bar;
- }
-
- main()
- {
- while(1)
- if (foo)
- {
- bar;
- }
- else {
- asdf;
- }
- misplacedline;
- }
-
- {
- if (clipboard.state == SELECT_DONE
- && ((row == clipboard.start.lnum
- && col >= clipboard.start.col)
- || row > clipboard.start.lnum))
- }
-
- {
- if (1) {i += 4;}
- where_am_i;
- return 0;
- }
-
- {
- {
- } // sdf(asdf
- if (asdf)
- asd;
- }
-
- {
- label1:
- label2:
- }
-
- {
- int fooRet = foo(pBar1, false /*fKB*/,
- true /*fPTB*/, 3 /*nT*/, false /*fDF*/);
- f() {
- for ( i = 0;
- i < m;
- /* c */ i++ ) {
- a = b;
- }
- }
- }
-
- {
- f1(/*comment*/);
- f2();
- }
-
- {
- do {
- if (foo) {
- } else
- ;
- } while (foo);
- foo(); // was wrong
- }
-
- int x; // no extra indent because of the ;
- void func()
- {
- }
-
- char *tab[] = {"aaa",
- "};", /* }; */ NULL}
- int indented;
- {}
-
- char *a[] = {"aaa", "bbb",
- "ccc", NULL};
- // here
-
- char *tab[] = {"aaa",
- "xx", /* xx */}; /* asdf */
- int not_indented;
-
- {
- do {
- switch (bla)
- {
- case 1: if (foo)
- bar;
- }
- } while (boo);
- wrong;
- }
-
- int foo,
- bar;
- int foo;
-
- #if defined(foo) \
- && defined(bar)
- char * xx = "asdf\
- foo\
- bor";
- int x;
-
- char *foo = "asdf\
- asdf\
- asdf",
- *bar;
-
- void f()
- {
- #if defined(foo) \
- && defined(bar)
- char *foo = "asdf\
- asdf\
- asdf",
- *bar;
- {
- int i;
- char *foo = "asdf\
- asdf\
- asdf",
- *bar;
- }
- #endif
- }
- #endif
-
- int y; // comment
- // comment
-
- // comment
-
- {
- Constructor(int a,
- int b ) : BaseClass(a)
- {
- }
- }
-
- void foo()
- {
- char one,
- two;
- struct bla piet,
- jan;
- enum foo kees,
- jannie;
- static unsigned sdf,
- krap;
- unsigned int piet,
- jan;
- int
- kees,
- jan;
- }
-
- {
- t(int f,
- int d); // )
- d();
- }
-
- Constructor::Constructor(int a,
- int b
- ) :
- BaseClass(a,
- b,
- c),
- mMember(b),
- {
- }
-
- Constructor::Constructor(int a,
- int b ) :
- BaseClass(a)
- {
- }
-
- Constructor::Constructor(int a,
- int b ) /*x*/ : /*x*/ BaseClass(a),
- member(b)
- {
- }
-
- A::A(int a, int b)
- : aa(a),
- bb(b),
- cc(c)
- {
- }
-
- class CAbc :
- public BaseClass1,
- protected BaseClass2
- {
- int Test() { return FALSE; }
- int Test1() { return TRUE; }
-
- CAbc(int a, int b ) :
- BaseClass(a)
- {
- switch(xxx)
- {
- case abc:
- asdf();
- break;
-
- case 999:
- baer();
- break;
- }
- }
-
- public: // <-- this was incoreectly indented before!!
- void testfall();
- protected:
- void testfall();
- };
-
- class CAbc : public BaseClass1,
- protected BaseClass2
- {
- };
-
- static struct
- {
- int a;
- int b;
- } variable[COUNT] =
- {
- {
- 123,
- 456
- },
- {
- 123,
- 456
- }
- };
-
- static struct
- {
- int a;
- int b;
- } variable[COUNT] =
- {
- { 123, 456 },
- { 123, 456 }
- };
-
- void asdf() /* ind_maxparen may cause trouble here */
- {
- if ((0
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1
- && 1)) break;
- }
-
- foo()
- {
- a = cond ? foo() : asdf
- + asdf;
-
- a = cond ?
- foo() : asdf
- + asdf;
- }
-
- int main(void)
- {
- if (a)
- if (b)
- 2;
- else 3;
- next_line_of_code();
- }
-
- barry()
- {
- Foo::Foo (int one,
- int two)
- : something(4)
- {}
- }
-
- barry()
- {
- Foo::Foo (int one, int two)
- : something(4)
- {}
- }
-
- Constructor::Constructor(int a,
- int b
- ) :
- BaseClass(a,
- b,
- c),
- mMember(b)
- {
- }
- int main ()
- {
- if (lala)
- do
- ++(*lolo);
- while (lili
- && lele);
- lulu;
- }
-
- int main ()
- {
- switch (c)
- {
- case 'c': if (cond)
- {
- }
- }
- }
-
- main()
- {
- (void) MyFancyFuasdfadsfnction(
- argument);
- }
-
- main()
- {
- char foo[] = "/*";
- /* as
- df */
- hello
- }
-
- /* valid namespaces with normal indent */
- namespace
- {
- {
- 111111111111;
- }
- }
- namespace /* test */
- {
- 11111111111111111;
- }
- namespace // test
- {
- 111111111111111111;
- }
- namespace
- {
- 111111111111111111;
- }
- namespace test
- {
- 111111111111111111;
- }
- namespace{
- 111111111111111111;
- }
- namespace test{
- 111111111111111111;
- }
- namespace {
- 111111111111111111;
- }
- namespace test {
- 111111111111111111;
- namespace test2 {
- 22222222222222222;
- }
- }
-
- /* invalid namespaces use block indent */
- namespace test test2 {
- 111111111111111111111;
- }
- namespace11111111111 {
- 111111111111;
- }
- namespace() {
- 1111111111111;
- }
- namespace()
- {
- 111111111111111111;
- }
- namespace test test2
- {
- 1111111111111111111;
- }
- namespace111111111
- {
- 111111111111111111;
- }
- void getstring() {
- /* Raw strings */
- const char* s = R"(
- test {
- # comment
- field: 123
- }
- )";
- }
- void getstring() {
- const char* s = R"foo(
- test {
- # comment
- field: 123
- }
- )foo";
- }
-
- {
- int a[4] = {
- [0] = 0,
- [1] = 1,
- [2] = 2,
- [3] = 3,
- };
- }
-
- {
- a = b[2]
- + 3;
- }
-
- {
- if (1)
- /* aaaaa
- * bbbbb
- */
- a = 1;
- }
-
- void func()
- {
- switch (foo)
- {
- case (bar):
- if (baz())
- quux();
- break;
- case (shmoo):
- if (!bar)
- {
- }
- case (foo1):
- switch (bar)
- {
- case baz:
- baz_f();
- break;
- }
- break;
- default:
- baz();
- baz();
- break;
- }
- }
-
- /* end of AUTO */
- ]=])
- end)
-
- it('2 is working', function()
- insert_([=[
-
- {
-
- /* this is
- * a real serious important big
- * comment
- */
- /* insert " about life, the universe, and the rest" after "serious" */
- }
- ]=])
-
- feed_command('set tw=0 noai fo=croq')
- feed_command('let &wm = &columns - 20')
- feed_command('/serious/e')
- feed('a about life, the universe, and the rest<esc>')
-
- expect([=[
-
- {
-
- /* this is
- * a real serious
- * about life, the
- * universe, and the
- * rest important big
- * comment
- */
- /* insert " about life, the universe, and the rest" after "serious" */
- }
- ]=])
- end)
-
- it('3 is working', function()
- insert_([=[
-
- {
- /*
- * Testing for comments, without 'cin' set
- */
-
- /*
- * what happens here?
- */
-
- /*
- the end of the comment, try inserting a line below */
-
- /* how about
- this one */
- }
- ]=])
-
- feed_command('set nocin')
- feed_command('/comments')
- feed('joabout life<esc>/happens<cr>')
- feed('jothere<esc>/below<cr>')
- feed('oline<esc>/this<cr>')
- feed('Ohello<esc>')
-
- expect([=[
-
- {
- /*
- * Testing for comments, without 'cin' set
- */
- about life
-
- /*
- * what happens here?
- */
- there
-
- /*
- the end of the comment, try inserting a line below */
- line
-
- /* how about
- hello
- this one */
- }
- ]=])
- end)
-
- it('4 is working', function()
- insert_([=[
-
- {
- var = this + that + vec[0] * vec[0]
- + vec[1] * vec[1]
- + vec2[2] * vec[2];
- }
- ]=])
- feed_command('set cin')
- feed_command('/vec2')
- feed('==<cr>')
-
- expect([=[
-
- {
- var = this + that + vec[0] * vec[0]
- + vec[1] * vec[1]
- + vec2[2] * vec[2];
- }
- ]=])
- end)
-
- it('5 is working', function()
- insert_([=[
-
- {
- asdf asdflkajds f;
- if (tes & ting) {
- asdf asdf asdf ;
- asdfa sdf asdf;
- }
- testing1;
- if (tes & ting)
- {
- asdf asdf asdf ;
- asdfa sdf asdf;
- }
- testing2;
- }
- ]=])
-
- feed_command('set cin')
- feed_command('set cino=}4')
- feed_command('/testing1')
- feed('k2==/testing2<cr>')
- feed('k2==<cr>')
-
- expect([=[
-
- {
- asdf asdflkajds f;
- if (tes & ting) {
- asdf asdf asdf ;
- asdfa sdf asdf;
- }
- testing1;
- if (tes & ting)
- {
- asdf asdf asdf ;
- asdfa sdf asdf;
- }
- testing2;
- }
- ]=])
- end)
-
- it('6 is working', function()
- insert_([=[
-
- main ( int first_par, /*
- * Comment for
- * first par
- */
- int second_par /*
- * Comment for
- * second par
- */
- )
- {
- func( first_par, /*
- * Comment for
- * first par
- */
- second_par /*
- * Comment for
- * second par
- */
- );
-
- }
- ]=])
-
- feed_command('set cin')
- feed_command('set cino=(0,)20')
- feed_command('/main')
- feed('=][<cr>')
-
- expect([=[
-
- main ( int first_par, /*
- * Comment for
- * first par
- */
- int second_par /*
- * Comment for
- * second par
- */
- )
- {
- func( first_par, /*
- * Comment for
- * first par
- */
- second_par /*
- * Comment for
- * second par
- */
- );
-
- }
- ]=])
- end)
-
- it('7 is working', function()
- insert_([=[
-
- main(void)
- {
- /* Make sure that cino=X0s is not parsed like cino=Xs. */
- if (cond)
- foo();
- else
- {
- bar();
- }
- }
- ]=])
-
- feed_command('set cin')
- feed_command('set cino=es,n0s')
- feed_command('/main')
- feed('=][<cr>')
-
- expect([=[
-
- main(void)
- {
- /* Make sure that cino=X0s is not parsed like cino=Xs. */
- if (cond)
- foo();
- else
- {
- bar();
- }
- }
- ]=])
- end)
-
- it('8 is working', function()
- insert_([=[
-
- {
- do
- {
- if ()
- {
- if ()
- asdf;
- else
- asdf;
- }
- } while ();
- cmd; /* this should go under the } */
- }
- ]=])
-
- feed_command('set cin')
- feed_command('set cino=')
- feed(']]=][<cr>')
-
- expect([=[
-
- {
- do
- {
- if ()
- {
- if ()
- asdf;
- else
- asdf;
- }
- } while ();
- cmd; /* this should go under the } */
- }
- ]=])
- end)
-
- it('9 is working', function()
- insert_([=[
-
- void f()
- {
- if ( k() ) {
- l();
-
- } else { /* Start (two words) end */
- m();
- }
-
- n();
- }
- ]=])
-
- feed(']]=][<cr>')
-
- expect([=[
-
- void f()
- {
- if ( k() ) {
- l();
-
- } else { /* Start (two words) end */
- m();
- }
-
- n();
- }
- ]=])
- end)
-
- it('10 is working', function()
- -- This is nasty. This is the only test case where the buffer content
- -- differs from the original. Why? Proper behaviour of this test depends on
- -- the fact that the setup code contains an (unbalanced) opening curly
- -- bracket in "set cino={s,e-s". This bracket actually affects the outcome
- -- of the test: without it the curly bracket under "void f()" would not be
- -- indented properly. And that's why we've had to add one explicitly.
- insert_([=[
- { <= THIS IS THE CURLY BRACKET EXPLAINED IN THE COMMENT.
-
- void f()
- {
- if ( k() )
- {
- l();
- } else { /* Start (two words) end */
- m();
- }
- n(); /* should be under the if () */
- }
- ]=])
-
- feed_command('set cino={s,e-s')
- feed(']]=][<cr>')
-
- expect([=[
- { <= THIS IS THE CURLY BRACKET EXPLAINED IN THE COMMENT.
-
- void f()
- {
- if ( k() )
- {
- l();
- } else { /* Start (two words) end */
- m();
- }
- n(); /* should be under the if () */
- }
- ]=])
- end)
-
- it('11 is working', function()
- insert_([=[
-
- void bar(void)
- {
- static array[2][2] =
- {
- { 1, 2 },
- { 3, 4 },
- }
-
- while (a)
- {
- foo(&a);
- }
-
- {
- int a;
- {
- a = a + 1;
- }
- }
- b = a;
- }
-
- void func(void)
- {
- a = 1;
- {
- b = 2;
- }
- c = 3;
- d = 4;
- }
- /* foo */
- ]=])
-
- feed_command('set cino={s,fs')
- feed(']]=/ foo<cr>')
-
- expect([=[
-
- void bar(void)
- {
- static array[2][2] =
- {
- { 1, 2 },
- { 3, 4 },
- }
-
- while (a)
- {
- foo(&a);
- }
-
- {
- int a;
- {
- a = a + 1;
- }
- }
- b = a;
- }
-
- void func(void)
- {
- a = 1;
- {
- b = 2;
- }
- c = 3;
- d = 4;
- }
- /* foo */
- ]=])
- end)
-
- it('12 is working', function()
- insert_([=[
-
- a()
- {
- do {
- a = a +
- a;
- } while ( a ); /* add text under this line */
- if ( a )
- a;
- }
- ]=])
-
- feed_command('set cino=')
- feed_command('/while')
- feed('ohere<esc>')
-
- expect([=[
-
- a()
- {
- do {
- a = a +
- a;
- } while ( a ); /* add text under this line */
- here
- if ( a )
- a;
- }
- ]=])
- end)
-
- it('13 is working', function()
- insert_([=[
-
- a()
- {
- label1:
- /* hmm */
- // comment
- }
- ]=])
-
- feed_command('set cino= com=')
- feed_command('/comment')
- feed('olabel2: b();<cr>label3 /* post */:<cr>/* pre */ label4:<cr>f(/*com*/);<cr>if (/*com*/)<cr>cmd();<esc>')
-
- expect([=[
-
- a()
- {
- label1:
- /* hmm */
- // comment
- label2: b();
- label3 /* post */:
- /* pre */ label4:
- f(/*com*/);
- if (/*com*/)
- cmd();
- }
- ]=])
- end)
-
- it('14 is working', function()
- insert_([=[
-
- /*
- * A simple comment
- */
-
- /*
- ** A different comment
- */
- ]=])
-
- feed_command('set comments& comments^=s:/*,m:**,ex:*/')
- feed_command('/simple')
- feed('=5j<cr>')
-
- expect([=[
-
- /*
- * A simple comment
- */
-
- /*
- ** A different comment
- */
- ]=])
- end)
-
- it('15 is working', function()
- insert_([=[
-
-
- void f()
- {
-
- /*********
- A comment.
- *********/
- }
- ]=])
-
- feed_command('set cino=c0')
- feed_command('set comments& comments-=s1:/* comments^=s0:/*')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
-
- /*********
- A comment.
- *********/
- }
- ]=])
- end)
-
- it('16 is working', function()
- insert_([=[
-
-
- void f()
- {
-
- /*********
- A comment.
- *********/
- }
- ]=])
-
- feed_command('set cino=c0,C1')
- feed_command('set comments& comments-=s1:/* comments^=s0:/*')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
-
- /*********
- A comment.
- *********/
- }
- ]=])
- end)
-
- it('17 is working', function()
- insert_([=[
-
- void f()
- {
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
-
- feed_command('set cino=')
- feed(']]=][<cr>')
-
- expect([=[
-
- void f()
- {
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
- end)
-
- it('18 is working', function()
- insert_([=[
-
-
- void f()
- {
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
-
- feed_command('set cino=(s')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
- end)
-
- it('19 is working', function()
- insert_([=[
-
-
- void f()
- {
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
-
- feed_command('set cino=(s,U1 ')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
- end)
-
- it('20 is working', function()
- insert_([=[
-
-
- void f()
- {
- if ( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
-
- feed_command('set cino=(0')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- if ( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
- end)
-
- it('21 is working', function()
- insert_([=[
-
-
- void f()
- {
- if ( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
-
- feed_command('set cino=(0,w1 ')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- if ( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
- end)
-
- it('22 is working', function()
- insert_([=[
-
-
- void f()
- {
- c = c1 && (
- c2 ||
- c3
- ) && c4;
- if (
- c1 && c2
- )
- foo;
- }
- ]=])
-
- feed_command('set cino=(s')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- c = c1 && (
- c2 ||
- c3
- ) && c4;
- if (
- c1 && c2
- )
- foo;
- }
- ]=])
- end)
-
- it('23 is working', function()
- insert_([=[
-
-
- void f()
- {
- c = c1 && (
- c2 ||
- c3
- ) && c4;
- if (
- c1 && c2
- )
- foo;
- }
- ]=])
-
- feed_command('set cino=(s,m1 ')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- c = c1 && (
- c2 ||
- c3
- ) && c4;
- if (
- c1 && c2
- )
- foo;
- }
- ]=])
- end)
-
- it('24 is working', function()
- insert_([=[
-
-
- void f()
- {
- switch (x)
- {
- case 1:
- a = b;
- break;
- default:
- a = 0;
- break;
- }
- }
- ]=])
-
- feed_command('set cino=b1')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- switch (x)
- {
- case 1:
- a = b;
- break;
- default:
- a = 0;
- break;
- }
- }
- ]=])
- end)
-
- it('25 is working', function()
- insert_([=[
-
-
- void f()
- {
- invokeme(
- argu,
- ment);
- invokeme(
- argu,
- ment
- );
- invokeme(argu,
- ment
- );
- }
- ]=])
-
- feed_command('set cino=(0,W5')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- invokeme(
- argu,
- ment);
- invokeme(
- argu,
- ment
- );
- invokeme(argu,
- ment
- );
- }
- ]=])
- end)
-
- it('26 is working', function()
- insert_([=[
-
-
- void f()
- {
- statement;
- // comment 1
- // comment 2
- }
- ]=])
-
- feed_command('set cino=/6')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void f()
- {
- statement;
- // comment 1
- // comment 2
- }
- ]=])
- end)
-
- it('27 is working', function()
- insert_([=[
-
-
- void f()
- {
- statement;
- // comment 1
- // comment 2
- }
- ]=])
-
- feed_command('set cino=')
- feed('2kdd]]/comment 1/+1<cr>')
- feed('==<cr>')
-
- expect([=[
-
- void f()
- {
- statement;
- // comment 1
- // comment 2
- }
- ]=])
- end)
-
- it('28 is working', function()
- insert_([=[
-
-
- class CAbc
- {
- int Test() { return FALSE; }
-
- public: // comment
- void testfall();
- protected:
- void testfall();
- };
- ]=])
-
- feed_command('set cino=g0')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- class CAbc
- {
- int Test() { return FALSE; }
-
- public: // comment
- void testfall();
- protected:
- void testfall();
- };
- ]=])
- end)
-
- it('29 is working', function()
- insert_([=[
-
-
- class Foo : public Bar
- {
- public:
- virtual void method1(void) = 0;
- virtual void method2(int arg1,
- int arg2,
- int arg3) = 0;
- };
- ]=])
-
- feed_command('set cino=(0,gs,hs')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- class Foo : public Bar
- {
- public:
- virtual void method1(void) = 0;
- virtual void method2(int arg1,
- int arg2,
- int arg3) = 0;
- };
- ]=])
- end)
-
- it('30 is working', function()
- insert_([=[
-
-
- void
- foo()
- {
- if (a)
- {
- } else
- asdf;
- }
- ]=])
-
- feed_command('set cino=+20')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- void
- foo()
- {
- if (a)
- {
- } else
- asdf;
- }
- ]=])
- end)
-
- it('31 is working', function()
- insert_([=[
-
-
- {
- averylongfunctionnamelongfunctionnameaverylongfunctionname()->asd(
- asdasdf,
- func(asdf,
- asdfadsf),
- asdfasdf
- );
-
- /* those are ugly, but consequent */
-
- func()->asd(asdasdf,
- averylongfunctionname(
- abc,
- dec)->averylongfunctionname(
- asdfadsf,
- asdfasdf,
- asdfasdf,
- ),
- func(asdfadf,
- asdfasdf
- ),
- asdasdf
- );
-
- averylongfunctionnameaverylongfunctionnameavery()->asd(fasdf(
- abc,
- dec)->asdfasdfasdf(
- asdfadsf,
- asdfasdf,
- asdfasdf,
- ),
- func(asdfadf,
- asdfasdf),
- asdasdf
- );
- }
- ]=])
-
- feed_command('set cino=(0,W2s')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- {
- averylongfunctionnamelongfunctionnameaverylongfunctionname()->asd(
- asdasdf,
- func(asdf,
- asdfadsf),
- asdfasdf
- );
-
- /* those are ugly, but consequent */
-
- func()->asd(asdasdf,
- averylongfunctionname(
- abc,
- dec)->averylongfunctionname(
- asdfadsf,
- asdfasdf,
- asdfasdf,
- ),
- func(asdfadf,
- asdfasdf
- ),
- asdasdf
- );
-
- averylongfunctionnameaverylongfunctionnameavery()->asd(fasdf(
- abc,
- dec)->asdfasdfasdf(
- asdfadsf,
- asdfasdf,
- asdfasdf,
- ),
- func(asdfadf,
- asdfasdf),
- asdasdf
- );
- }
- ]=])
- end)
-
- it('32 is working', function()
- insert_([=[
-
-
- int main ()
- {
- if (cond1 &&
- cond2
- )
- foo;
- }
- ]=])
-
- feed_command('set cino=M1')
- feed('2kdd]]=][<cr>')
-
- expect([=[
-
- int main ()
- {
- if (cond1 &&
- cond2
- )
- foo;
- }
- ]=])
- end)
-
- it('33 is working', function()
- insert_([=[
-
-
- void func(int a
- #if defined(FOO)
- , int b
- , int c
- #endif
- )
- {
- }
- ]=])
-
- feed_command('set cino=(0,ts')
- feed('2kdd2j=][<cr>')
-
- expect([=[
-
- void func(int a
- #if defined(FOO)
- , int b
- , int c
- #endif
- )
- {
- }
- ]=])
- end)
-
- it('34 is working', function()
- insert_([=[
-
-
-
- void
- func(int a
- #if defined(FOO)
- , int b
- , int c
- #endif
- )
- {
- }
- ]=])
-
- feed_command('set cino=(0')
- feed('2kdd2j=][<cr>')
-
- expect([=[
-
-
- void
- func(int a
- #if defined(FOO)
- , int b
- , int c
- #endif
- )
- {
- }
- ]=])
- end)
-
- it('35 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if(x==y)
- if(y==z)
- foo=1;
- else { bar=1;
- baz=2;
- }
- printf("Foo!\n");
- }
-
- void func1(void)
- {
- char* tab[] = {"foo", "bar",
- "baz", "quux",
- "this line used", "to be indented incorrectly"};
- foo();
- }
-
- void func2(void)
- {
- int tab[] =
- {1, 2,
- 3, 4,
- 5, 6};
-
- printf("This line used to be indented incorrectly.\n");
- }
-
- int foo[]
- #ifdef BAR
-
- = { 1, 2, 3,
- 4, 5, 6 }
-
- #endif
- ;
- int baz;
-
- void func3(void)
- {
- int tab[] = {
- 1, 2,
- 3, 4,
- 5, 6};
-
- printf("Don't you dare indent this line incorrectly!\n");
- }
-
- void
- func4(a, b,
- c)
- int a;
- int b;
- int c;
- {
- }
-
- void
- func5(
- int a,
- int b)
- {
- }
-
- void
- func6(
- int a)
- {
- }
- ]=])
-
- feed_command('set cino&')
- feed('2kdd2j=7][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if(x==y)
- if(y==z)
- foo=1;
- else { bar=1;
- baz=2;
- }
- printf("Foo!\n");
- }
-
- void func1(void)
- {
- char* tab[] = {"foo", "bar",
- "baz", "quux",
- "this line used", "to be indented incorrectly"};
- foo();
- }
-
- void func2(void)
- {
- int tab[] =
- {1, 2,
- 3, 4,
- 5, 6};
-
- printf("This line used to be indented incorrectly.\n");
- }
-
- int foo[]
- #ifdef BAR
-
- = { 1, 2, 3,
- 4, 5, 6 }
-
- #endif
- ;
- int baz;
-
- void func3(void)
- {
- int tab[] = {
- 1, 2,
- 3, 4,
- 5, 6};
-
- printf("Don't you dare indent this line incorrectly!\n");
- }
-
- void
- func4(a, b,
- c)
- int a;
- int b;
- int c;
- {
- }
-
- void
- func5(
- int a,
- int b)
- {
- }
-
- void
- func6(
- int a)
- {
- }
- ]=])
- end)
-
- it('36 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- int tab[] =
- {
- 1, 2, 3,
- 4, 5, 6};
-
- printf("Indent this line correctly!\n");
-
- switch (foo)
- {
- case bar:
- printf("bar");
- break;
- case baz: {
- printf("baz");
- break;
- }
- case quux:
- printf("But don't break the indentation of this instruction\n");
- break;
- }
- }
- ]=])
-
- feed_command('set cino&')
- feed_command('set cino+=l1')
- feed('2kdd2j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- int tab[] =
- {
- 1, 2, 3,
- 4, 5, 6};
-
- printf("Indent this line correctly!\n");
-
- switch (foo)
- {
- case bar:
- printf("bar");
- break;
- case baz: {
- printf("baz");
- break;
- }
- case quux:
- printf("But don't break the indentation of this instruction\n");
- break;
- }
- }
- ]=])
- end)
-
- it('37 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- cout << "a"
- << "b"
- << ") :"
- << "c";
- }
- ]=])
-
- feed_command('set cino&')
- feed('2kdd2j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- cout << "a"
- << "b"
- << ") :"
- << "c";
- }
- ]=])
- end)
-
- it('38 is working', function()
- insert_([=[
-
- void func(void)
- {
- /*
- * This is a comment.
- */
- }
- ]=])
-
- feed_command('set com=s1:/*,m:*,ex:*/')
- feed(']]3jofoo();<esc>')
-
- expect([=[
-
- void func(void)
- {
- /*
- * This is a comment.
- */
- foo();
- }
- ]=])
- end)
-
- it('39 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- for (int i = 0; i < 10; ++i)
- if (i & 1) {
- foo(1);
- } else
- foo(0);
- baz();
- }
- ]=])
-
- feed_command('set cino&')
- feed('2kdd2j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- for (int i = 0; i < 10; ++i)
- if (i & 1) {
- foo(1);
- } else
- foo(0);
- baz();
- }
- ]=])
- end)
-
- it('40 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
-
- if ( c1
- && ( c2
- || c3))
- foo;
- func( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
-
- feed_command('set cino=k2s,(0')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
-
- if ( c1
- && ( c2
- || c3))
- foo;
- func( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
- end)
-
- it('41 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
-
- if ( c1
- && ( c2
- || c3))
- foo;
- func( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
-
- feed_command('set cino=k2s,(s')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
-
- if ( c1
- && ( c2
- || c3))
- foo;
- func( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
- end)
-
- it('42 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
-
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
-
- feed_command('set cino=k2s,(s,U1')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
-
- c = c1 &&
- (
- c2 ||
- c3
- ) && c4;
- }
- ]=])
- end)
-
- it('43 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
-
- if ( c1
- && ( c2
- || c3))
- foo;
-
- a_long_line(
- argument,
- argument);
- a_short_line(argument,
- argument);
- }
- ]=])
-
- feed_command('set cino=k2s,(0,W4')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
-
- if ( c1
- && ( c2
- || c3))
- foo;
-
- a_long_line(
- argument,
- argument);
- a_short_line(argument,
- argument);
- }
- ]=])
- end)
-
- it('44 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
- }
- ]=])
-
- feed_command('set cino=k2s,u2')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
- }
- ]=])
- end)
-
- it('45 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
-
- if ( c1
- && ( c2
- || c3))
- foo;
- func( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
-
- feed_command('set cino=k2s,(0,w1')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- if (c123456789
- && (c22345
- || c3))
- printf("foo\n");
-
- if ( c1
- && ( c2
- || c3))
- foo;
- func( c1
- && ( c2
- || c3))
- foo;
- }
- ]=])
- end)
-
- it('46 is working', function()
- insert_([=[
-
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- }
- ]=])
-
- feed_command('set cino=k2,(s')
- feed('2kdd3j=][<cr>')
-
- expect([=[
-
- void func(void)
- {
- if (condition1
- && condition2)
- action();
- function(argument1
- && argument2);
-
- if (c1 && (c2 ||
- c3))
- foo;
- if (c1 &&
- (c2 || c3))
- {
- }
- }
- ]=])
- end)
-
- it('47 is working', function()
- insert_([=[
-
- NAMESPACESTART
- /* valid namespaces with normal indent */
- namespace
- {
- {
- 111111111111;
- }
- }
- namespace /* test */
- {
- 11111111111111111;
- }
- namespace // test
- {
- 111111111111111111;
- }
- namespace
- {
- 111111111111111111;
- }
- namespace test
- {
- 111111111111111111;
- }
- namespace test::cpp17
- {
- 111111111111111111;
- }
- namespace ::incorrectcpp17
- {
- 111111111111111111;
- }
- namespace test::incorrectcpp17::
- {
- 111111111111111111;
- }
- namespace test:incorrectcpp17
- {
- 111111111111111111;
- }
- namespace test:::incorrectcpp17
- {
- 111111111111111111;
- }
- namespace{
- 111111111111111111;
- }
- namespace test{
- 111111111111111111;
- }
- namespace {
- 111111111111111111;
- }
- namespace test {
- 111111111111111111;
- namespace test2 {
- 22222222222222222;
- }
- }
-
- /* invalid namespaces use block indent */
- namespace test test2 {
- 111111111111111111111;
- }
- namespace11111111111 {
- 111111111111;
- }
- namespace() {
- 1111111111111;
- }
- namespace()
- {
- 111111111111111111;
- }
- namespace test test2
- {
- 1111111111111111111;
- }
- namespace111111111
- {
- 111111111111111111;
- }
- NAMESPACEEND
- ]=])
-
- feed_command('set cino=N-s')
- feed_command('/^NAMESPACESTART')
- feed('=/^NAMESPACEEND<cr>')
-
- expect([=[
-
- NAMESPACESTART
- /* valid namespaces with normal indent */
- namespace
- {
- {
- 111111111111;
- }
- }
- namespace /* test */
- {
- 11111111111111111;
- }
- namespace // test
- {
- 111111111111111111;
- }
- namespace
- {
- 111111111111111111;
- }
- namespace test
- {
- 111111111111111111;
- }
- namespace test::cpp17
- {
- 111111111111111111;
- }
- namespace ::incorrectcpp17
- {
- 111111111111111111;
- }
- namespace test::incorrectcpp17::
- {
- 111111111111111111;
- }
- namespace test:incorrectcpp17
- {
- 111111111111111111;
- }
- namespace test:::incorrectcpp17
- {
- 111111111111111111;
- }
- namespace{
- 111111111111111111;
- }
- namespace test{
- 111111111111111111;
- }
- namespace {
- 111111111111111111;
- }
- namespace test {
- 111111111111111111;
- namespace test2 {
- 22222222222222222;
- }
- }
-
- /* invalid namespaces use block indent */
- namespace test test2 {
- 111111111111111111111;
- }
- namespace11111111111 {
- 111111111111;
- }
- namespace() {
- 1111111111111;
- }
- namespace()
- {
- 111111111111111111;
- }
- namespace test test2
- {
- 1111111111111111111;
- }
- namespace111111111
- {
- 111111111111111111;
- }
- NAMESPACEEND
- ]=])
- end)
-
- it('48 is working', function()
- insert_([=[
-
- JSSTART
- var bar = {
- foo: {
- that: this,
- some: ok,
- },
- "bar":{
- a : 2,
- b: "123abc",
- x: 4,
- "y": 5
- }
- }
- JSEND
- ]=])
-
- feed_command('set cino=j1,J1')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- var bar = {
- foo: {
- that: this,
- some: ok,
- },
- "bar":{
- a : 2,
- b: "123abc",
- x: 4,
- "y": 5
- }
- }
- JSEND
- ]=])
- end)
-
- it('49 is working', function()
- insert_([=[
-
- JSSTART
- var foo = [
- 1,
- 2,
- 3
- ];
- JSEND
- ]=])
-
- feed_command('set cino=j1,J1')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- var foo = [
- 1,
- 2,
- 3
- ];
- JSEND
- ]=])
- end)
-
- it('50 is working', function()
- insert_([=[
-
- JSSTART
- function bar() {
- var foo = [
- 1,
- 2,
- 3
- ];
- }
- JSEND
- ]=])
-
- feed_command('set cino=j1,J1')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- function bar() {
- var foo = [
- 1,
- 2,
- 3
- ];
- }
- JSEND
- ]=])
- end)
-
- it('51 is working', function()
- insert_([=[
-
- JSSTART
- (function($){
-
- if (cond &&
- cond) {
- stmt;
- }
- window.something.left =
- (width - 50 + offset) + "px";
- var class_name='myclass';
-
- function private_method() {
- }
-
- var public_method={
- method: function(options,args){
- private_method();
- }
- }
-
- function init(options) {
-
- $(this).data(class_name+'_public',$.extend({},{
- foo: 'bar',
- bar: 2,
- foobar: [
- 1,
- 2,
- 3
- ],
- callback: function(){
- return true;
- }
- }, options||{}));
- }
-
- $.fn[class_name]=function() {
-
- var _arguments=arguments;
- return this.each(function(){
-
- var options=$(this).data(class_name+'_public');
- if (!options) {
- init.apply(this,_arguments);
-
- } else {
- var method=public_method[_arguments[0]];
-
- if (typeof(method)!='function') {
- console.log(class_name+' has no method "'+_arguments[0]+'"');
- return false;
- }
- _arguments[0]=options;
- method.apply(this,_arguments);
- }
- });
- }
-
- })(jQuery);
- JSEND
- ]=])
-
- feed_command('set cino=j1,J1')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- (function($){
-
- if (cond &&
- cond) {
- stmt;
- }
- window.something.left =
- (width - 50 + offset) + "px";
- var class_name='myclass';
-
- function private_method() {
- }
-
- var public_method={
- method: function(options,args){
- private_method();
- }
- }
-
- function init(options) {
-
- $(this).data(class_name+'_public',$.extend({},{
- foo: 'bar',
- bar: 2,
- foobar: [
- 1,
- 2,
- 3
- ],
- callback: function(){
- return true;
- }
- }, options||{}));
- }
-
- $.fn[class_name]=function() {
-
- var _arguments=arguments;
- return this.each(function(){
-
- var options=$(this).data(class_name+'_public');
- if (!options) {
- init.apply(this,_arguments);
-
- } else {
- var method=public_method[_arguments[0]];
-
- if (typeof(method)!='function') {
- console.log(class_name+' has no method "'+_arguments[0]+'"');
- return false;
- }
- _arguments[0]=options;
- method.apply(this,_arguments);
- }
- });
- }
-
- })(jQuery);
- JSEND
- ]=])
- end)
-
- it('52 is working', function()
- insert_([=[
-
- JSSTART
- function init(options) {
- $(this).data(class_name+'_public',$.extend({},{
- foo: 'bar',
- bar: 2,
- foobar: [
- 1,
- 2,
- 3
- ],
- callback: function(){
- return true;
- }
- }, options||{}));
- }
- JSEND
- ]=])
-
- feed_command('set cino=j1,J1')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- function init(options) {
- $(this).data(class_name+'_public',$.extend({},{
- foo: 'bar',
- bar: 2,
- foobar: [
- 1,
- 2,
- 3
- ],
- callback: function(){
- return true;
- }
- }, options||{}));
- }
- JSEND
- ]=])
- end)
-
- it('53 is working', function()
- insert_([=[
-
- JSSTART
- (function($){
- function init(options) {
- $(this).data(class_name+'_public',$.extend({},{
- foo: 'bar',
- bar: 2,
- foobar: [
- 1,
- 2,
- 3
- ],
- callback: function(){
- return true;
- }
- }, options||{}));
- }
- })(jQuery);
- JSEND
- ]=])
-
- feed_command('set cino=j1,J1')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- (function($){
- function init(options) {
- $(this).data(class_name+'_public',$.extend({},{
- foo: 'bar',
- bar: 2,
- foobar: [
- 1,
- 2,
- 3
- ],
- callback: function(){
- return true;
- }
- }, options||{}));
- }
- })(jQuery);
- JSEND
- ]=])
- end)
-
- it('javascript indent / vim-patch 7.4.670', function()
- insert_([=[
-
- JSSTART
- // Results of JavaScript indent
- // 1
- (function(){
- var a = [
- 'a',
- 'b',
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
- }())
-
- // 2
- (function(){
- var a = [
- 0 +
- 5 *
- 9 *
- 'a',
- 'b',
- 0 +
- 5 *
- 9 *
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
- }())
-
- // 3
- (function(){
- var a = [
- 0 +
- // comment 1
- 5 *
- /* comment 2 */
- 9 *
- 'a',
- 'b',
- 0 +
- 5 *
- 9 *
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
- }())
-
- // 4
- {
- var a = [
- 0,
- 1
- ];
- var b;
- var c;
- }
-
- // 5
- {
- var a = [
- [
- 0
- ],
- 2,
- 3
- ];
- }
-
- // 6
- {
- var a = [
- [
- 0,
- 1
- ],
- 2,
- 3
- ];
- }
-
- // 7
- {
- var a = [
- // [
- 0,
- // 1
- // ],
- 2,
- 3
- ];
- }
-
- // 8
- var x = [
- (function(){
- var a,
- b,
- c,
- d,
- e,
- f,
- g,
- h,
- i;
- })
- ];
-
- // 9
- var a = [
- 0 +
- 5 *
- 9 *
- 'a',
- 'b',
- 0 +
- 5 *
- 9 *
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
-
- // 10
- var a,
- b,
- c,
- d,
- e,
- f,
- g,
- h,
- i;
- JSEND
- ]=])
-
- -- :set cino=j1,J1,+2
- feed_command('set cino=j1,J1,+2')
- feed_command('/^JSSTART')
- feed('=/^JSEND<cr>')
-
- expect([=[
-
- JSSTART
- // Results of JavaScript indent
- // 1
- (function(){
- var a = [
- 'a',
- 'b',
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
- }())
-
- // 2
- (function(){
- var a = [
- 0 +
- 5 *
- 9 *
- 'a',
- 'b',
- 0 +
- 5 *
- 9 *
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
- }())
-
- // 3
- (function(){
- var a = [
- 0 +
- // comment 1
- 5 *
- /* comment 2 */
- 9 *
- 'a',
- 'b',
- 0 +
- 5 *
- 9 *
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
- }())
-
- // 4
- {
- var a = [
- 0,
- 1
- ];
- var b;
- var c;
- }
-
- // 5
- {
- var a = [
- [
- 0
- ],
- 2,
- 3
- ];
- }
-
- // 6
- {
- var a = [
- [
- 0,
- 1
- ],
- 2,
- 3
- ];
- }
-
- // 7
- {
- var a = [
- // [
- 0,
- // 1
- // ],
- 2,
- 3
- ];
- }
-
- // 8
- var x = [
- (function(){
- var a,
- b,
- c,
- d,
- e,
- f,
- g,
- h,
- i;
- })
- ];
-
- // 9
- var a = [
- 0 +
- 5 *
- 9 *
- 'a',
- 'b',
- 0 +
- 5 *
- 9 *
- 'c',
- 'd',
- 'e',
- 'f',
- 'g',
- 'h',
- 'i'
- ];
-
- // 10
- var a,
- b,
- c,
- d,
- e,
- f,
- g,
- h,
- i;
- JSEND
- ]=])
- end)
-
- it('line continuations in macros / vim-patch 8.0.0148', function()
- insert_([=[
- /* start of define */
- {
- }
- #define AAA \
- BBB\
- CCC
-
- #define CNT \
- 1 + \
- 2 + \
- 4
- /* end of define */]=])
-
- feed_command('set cino&')
- feed_command('/start of define')
- feed('=/end of define<cr>')
-
- expect([=[
- /* start of define */
- {
- }
- #define AAA \
- BBB\
- CCC
-
- #define CNT \
- 1 + \
- 2 + \
- 4
- /* end of define */]=])
- end)
-
- it('* immediately follows comment / vim-patch 8.0.1291', function()
- insert_([=[
- {
- a = second/*bug*/*line;
- }]=])
-
- feed_command('set cin cino&')
- feed_command('/a = second')
- feed('ox')
-
- expect([=[
- {
- a = second/*bug*/*line;
- x
- }]=])
- end)
-end)
diff --git a/test/functional/legacy/008_autocommands_spec.lua b/test/functional/legacy/008_autocommands_spec.lua
index 002f037d09..4088cd1644 100644
--- a/test/functional/legacy/008_autocommands_spec.lua
+++ b/test/functional/legacy/008_autocommands_spec.lua
@@ -6,6 +6,7 @@ local source = helpers.source
local clear, command, expect, eq, eval = helpers.clear, helpers.command, helpers.expect, helpers.eq, helpers.eval
local write_file, dedent = helpers.write_file, helpers.dedent
local read_file = helpers.read_file
+local expect_exit = helpers.expect_exit
describe('autocommands that delete and unload buffers:', function()
local test_file = 'Xtest-008_autocommands.out'
@@ -78,7 +79,7 @@ describe('autocommands that delete and unload buffers:', function()
command('silent! edit Xxx1')
command('silent! edit Makefile') -- an existing file
command('silent! split new2')
- command('silent! quit')
+ expect_exit(command, 'silent! quit')
eq('VimLeave done',
string.match(read_file(test_file), "^%s*(.-)%s*$"))
end)
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index f666e51469..dd207ca0b4 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -16,6 +16,7 @@ local insert = helpers.insert
local command = helpers.command
local write_file = helpers.write_file
local curbufmeths = helpers.curbufmeths
+local expect_exit = helpers.expect_exit
local function ls_dir_sorted(dirname)
local files = {}
@@ -43,7 +44,7 @@ describe("'directory' option", function()
clear()
end)
teardown(function()
- command('qall!')
+ expect_exit(command, 'qall!')
helpers.rmdir('Xtest.je')
helpers.rmdir('Xtest2')
os.remove('Xtest1')
diff --git a/test/functional/legacy/031_close_commands_spec.lua b/test/functional/legacy/031_close_commands_spec.lua
index 64c67c9882..d02b1a2049 100644
--- a/test/functional/legacy/031_close_commands_spec.lua
+++ b/test/functional/legacy/031_close_commands_spec.lua
@@ -17,6 +17,7 @@ local source = helpers.source
local insert = helpers.insert
local expect = helpers.expect
local feed_command = helpers.feed_command
+local expect_exit = helpers.expect_exit
describe('Commands that close windows and/or buffers', function()
local function cleanup()
@@ -118,7 +119,7 @@ describe('Commands that close windows and/or buffers', function()
feed_command('q!')
feed('<CR>')
expect('testtext 1')
- source([[
+ expect_exit(source, [[
q!
" Now nvim should have exited
throw "Oh, Not finished yet."]])
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index 6a2e86ccb4..8379e426e0 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -1,8 +1,11 @@
-- Test argument list commands
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear, command, eq = helpers.clear, helpers.command, helpers.eq
local eval, exc_exec, neq = helpers.eval, helpers.exc_exec, helpers.neq
+local feed = helpers.feed
+local pcall_err = helpers.pcall_err
describe('argument list commands', function()
before_each(clear)
@@ -17,7 +20,7 @@ describe('argument list commands', function()
end
local function assert_fails(cmd, err)
- neq(exc_exec(cmd):find(err), nil)
+ neq(nil, exc_exec(cmd):find(err))
end
it('test that argidx() works', function()
@@ -206,7 +209,6 @@ describe('argument list commands', function()
command('%argd')
end)
-
it('test for autocommand that redefines the argument list, when doing ":all"', function()
command('autocmd BufReadPost Xxx2 next Xxx2 Xxx1')
command("call writefile(['test file Xxx1'], 'Xxx1')")
@@ -234,4 +236,45 @@ describe('argument list commands', function()
command('argdelete Xxx*')
command('bwipe! Xxx1 Xxx2 Xxx3')
end)
+
+ it('quitting Vim with unedited files in the argument list throws E173', function()
+ command('set nomore')
+ command('args a b c')
+ eq('Vim(quit):E173: 2 more files to edit', pcall_err(command, 'quit'))
+ end)
+
+ it(':confirm quit with unedited files in arglist', function()
+ local screen = Screen.new(60, 6)
+ screen:attach()
+ command('set nomore')
+ command('args a b c')
+ feed(':confirm quit\n')
+ screen:expect([[
+ |
+ ~ |
+ |
+ :confirm quit |
+ 2 more files to edit. Quit anyway? |
+ [Y]es, (N)o: ^ |
+ ]])
+ feed('N')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ feed(':confirm quit\n')
+ screen:expect([[
+ |
+ ~ |
+ |
+ :confirm quit |
+ 2 more files to edit. Quit anyway? |
+ [Y]es, (N)o: ^ |
+ ]])
+ feed('Y')
+ end)
end)
diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua
index c2b22472bf..4829a0bbe1 100644
--- a/test/functional/legacy/assert_spec.lua
+++ b/test/functional/legacy/assert_spec.lua
@@ -19,36 +19,10 @@ describe('assert function:', function()
clear()
end)
- describe('assert_beeps', function()
- it('works', function()
- call('assert_beeps', 'normal h')
- expected_empty()
- call('assert_beeps', 'normal 0')
- expected_errors({'command did not beep: normal 0'})
- end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(0, 'normal h'->assert_beeps())
- call assert_equal(1, 'normal 0'->assert_beeps())
- ]]
- expected_errors({tmpname .. ' line 2: command did not beep: normal 0'})
- end)
- end)
-
-- assert_equal({expected}, {actual}, [, {msg}])
describe('assert_equal', function()
it('should not change v:errors when expected is equal to actual', function()
source([[
- let s = 'foo'
- call assert_equal('foo', s)
- let n = 4
- call assert_equal(4, n)
- let l = [1, 2, 3]
- call assert_equal([1, 2, 3], l)
- call assert_equal(v:_null_list, v:_null_list)
- call assert_equal(v:_null_list, [])
- call assert_equal([], v:_null_list)
fu Func()
endfu
let F1 = function('Func')
@@ -98,30 +72,6 @@ describe('assert function:', function()
eq('Vim(call):E724: unable to correctly dump variable with self-referencing container',
exc_exec('call CheckAssert()'))
end)
-
- it('can specify a message and get a message about what failed', function()
- call('assert_equal', 'foo', 'bar', 'testing')
- expected_errors({"testing: Expected 'foo' but got 'bar'"})
- end)
-
- it('should shorten a long message', function()
- call ('assert_equal', 'XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX')
- expected_errors({"Expected 'X\\[x occurs 21 times]X' but got 'X\\[y occurs 25 times]X'"})
- end)
- end)
-
- -- assert_notequal({expected}, {actual}[, {msg}])
- describe('assert_notequal', function()
- it('should not change v:errors when expected differs from actual', function()
- eq(0, call('assert_notequal', 'foo', 4))
- eq(0, call('assert_notequal', {1, 2, 3}, 'foo'))
- expected_empty()
- end)
-
- it('should change v:errors when expected is equal to actual', function()
- eq(1, call('assert_notequal', 'foo', 'foo'))
- expected_errors({"Expected not equal to 'foo'"})
- end)
end)
-- assert_false({actual}, [, {msg}])
@@ -141,14 +91,6 @@ describe('assert function:', function()
call('assert_false', {})
expected_errors({'Expected False but got []'})
end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(0, v:false->assert_false())
- call assert_equal(1, 123->assert_false())
- ]]
- expected_errors({tmpname .. ' line 2: Expected False but got 123'})
- end)
end)
-- assert_true({actual}, [, {msg}])
@@ -164,14 +106,6 @@ describe('assert function:', function()
eq(1, call('assert_true', 1.5))
expected_errors({'Expected True but got 1.5'})
end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(0, v:true->assert_true())
- call assert_equal(1, 0->assert_true())
- ]]
- expected_errors({tmpname .. ' line 2: Expected True but got 0'})
- end)
end)
describe('v:errors', function()
@@ -202,91 +136,25 @@ describe('assert function:', function()
end)
it('should have file names and passed messages', function()
- local tmpname_one = source([[
+ source([[
call assert_equal(1, 100, 'equal assertion failed')
call assert_false('true', 'true assertion failed')
call assert_true('false', 'false assertion failed')
]])
- local tmpname_two = source([[
- call assert_true('', 'file two')
- ]])
- expected_errors({
- tmpname_one .. " line 1: equal assertion failed: Expected 1 but got 100",
- tmpname_one .. " line 2: true assertion failed: Expected False but got 'true'",
- tmpname_one .. " line 3: false assertion failed: Expected True but got 'false'",
- tmpname_two .. " line 1: file two: Expected True but got ''",
- })
- end)
-
- it('is reset to a list by assert functions', function()
source([[
- let save_verrors = v:errors
- let v:['errors'] = {'foo': 3}
- call assert_equal('yes', 'no')
- let verrors = v:errors
- let v:errors = save_verrors
- call assert_equal(type([]), type(verrors))
+ call assert_true('', 'file two')
]])
- expected_empty()
- end)
- end)
-
- -- assert_match({pat}, {text}[, {msg}])
- describe('assert_match', function()
- it('should not change v:errors when pat matches text', function()
- call('assert_match', '^f.*b.*r$', 'foobar')
- expected_empty()
- end)
-
- it('should change v:errors when pat does not match text', function()
- call('assert_match', 'bar.*foo', 'foobar')
- expected_errors({"Pattern 'bar.*foo' does not match 'foobar'"})
- end)
-
- it('should set v:errors to msg when given and match fails', function()
- call('assert_match', 'bar.*foo', 'foobar', 'wrong')
- expected_errors({"wrong: Pattern 'bar.*foo' does not match 'foobar'"})
- end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(1, 'foobar'->assert_match('bar.*foo', 'wrong'))
- ]]
expected_errors({
- tmpname .. " line 1: wrong: Pattern 'bar.*foo' does not match 'foobar'"
+ "nvim_exec(): equal assertion failed: Expected 1 but got 100",
+ "nvim_exec(): true assertion failed: Expected False but got 'true'",
+ "nvim_exec(): false assertion failed: Expected True but got 'false'",
+ "nvim_exec(): file two: Expected True but got ''",
})
end)
end)
- -- assert_notmatch({pat}, {text}[, {msg}])
- describe('assert_notmatch', function()
- it('should not change v:errors when pat does not match text', function()
- call('assert_notmatch', 'foo', 'bar')
- call('assert_notmatch', '^foobar$', 'foobars')
- expected_empty()
- end)
-
- it('should change v:errors when pat matches text', function()
- call('assert_notmatch', 'foo', 'foobar')
- expected_errors({"Pattern 'foo' does match 'foobar'"})
- end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(1, 'foobar'->assert_notmatch('foo'))
- ]]
- expected_errors({tmpname .. " line 1: Pattern 'foo' does match 'foobar'"})
- end)
- end)
-
-- assert_fails({cmd}, [, {error}])
describe('assert_fails', function()
- it('should change v:errors when error does not match v:errmsg', function()
- eq(1, eval([[assert_fails('xxx', 'E12345')]]))
- command([[call assert_match("Expected 'E12345' but got 'E492:", v:errors[0])]])
- expected_errors({"Expected 'E12345' but got 'E492: Not an editor command: xxx': xxx"})
- end)
-
it('should not change v:errors when cmd errors', function()
eq(0, eval([[assert_fails('NonexistentCmd')]]))
expected_empty()
@@ -296,106 +164,5 @@ describe('assert function:', function()
eq(1, eval([[assert_fails('call empty("")', '')]]))
expected_errors({'command did not fail: call empty("")'})
end)
-
- it('can specify and get a message about what failed', function()
- eq(1, eval([[assert_fails('xxx', 'E9876', 'stupid')]]))
- command([[call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0])]])
- expected_errors({"stupid: Expected 'E9876' but got 'E492: Not an editor command: xxx': stupid"})
- end)
-
- it('can specify and get a message even when cmd succeeds', function()
- eq(1, eval([[assert_fails('echo', '', 'echo command')]]))
- expected_errors({'command did not fail: echo command'})
- end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(1, 'echo'->assert_fails('', 'echo command'))
- ]]
- expected_errors({
- tmpname .. ' line 1: command did not fail: echo command'
- })
- end)
- end)
-
- -- assert_inrange({lower}, {upper}, {actual}[, {msg}])
- describe('assert_inrange()', function()
- it('should not change v:errors when actual is in range', function()
- call('assert_inrange', 7, 7, 7)
- call('assert_inrange', 5, 7, 5)
- call('assert_inrange', 5, 7, 6)
- call('assert_inrange', 5, 7, 7)
- expected_empty()
- end)
-
- it('should change v:errors when actual is not in range', function()
- call('assert_inrange', 5, 7, 4)
- call('assert_inrange', 5, 7, 8)
- expected_errors({
- "Expected range 5 - 7, but got 4",
- "Expected range 5 - 7, but got 8",
- })
- end)
-
- it('assert_inrange(1, 1) returns E119', function()
- eq('Vim(call):E119: Not enough arguments for function: assert_inrange',
- exc_exec("call assert_inrange(1, 1)"))
- end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(0, 5->assert_inrange(5, 7))
- call assert_equal(0, 7->assert_inrange(5, 7))
- call assert_equal(1, 8->assert_inrange(5, 7))
- ]]
- expected_errors({tmpname .. ' line 3: Expected range 5 - 7, but got 8'})
- end)
- end)
-
- -- assert_report({msg})
- describe('assert_report()', function()
- it('should add a message to v:errors', function()
- eq(1, call('assert_report', 'something is wrong'))
- command("call assert_match('something is wrong', v:errors[0])")
- command('call remove(v:errors, 0)')
- expected_empty()
- end)
-
- it('can be used as a method', function()
- local tmpname = source [[
- call assert_equal(1, 'also wrong'->assert_report())
- ]]
- expected_errors({tmpname .. ' line 1: also wrong'})
- end)
- end)
-
- -- assert_exception({cmd}, [, {error}])
- describe('assert_exception()', function()
- it('should assert thrown exceptions properly', function()
- source([[
- try
- nocommand
- catch
- call assert_equal(0, assert_exception('E492'))
- endtry
- ]])
- expected_empty()
- end)
-
- it('should work properly when nested', function()
- source([[
- try
- nocommand
- catch
- try
- " illegal argument, get NULL for error
- call assert_equal(1, assert_exception([]))
- catch
- call assert_equal(0, assert_exception('E730'))
- endtry
- endtry
- ]])
- expected_empty()
- end)
end)
end)
diff --git a/test/functional/legacy/autochdir_spec.lua b/test/functional/legacy/autochdir_spec.lua
index 37a94476a0..13cb6cd287 100644
--- a/test/functional/legacy/autochdir_spec.lua
+++ b/test/functional/legacy/autochdir_spec.lua
@@ -1,8 +1,12 @@
local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local clear, eq, matches = helpers.clear, helpers.eq, helpers.matches
-local eval, command, call = helpers.eval, helpers.command, helpers.call
-local exec_capture = helpers.exec_capture
+local eval, command, call, meths = helpers.eval, helpers.command, helpers.call, helpers.meths
+local source, exec_capture = helpers.source, helpers.exec_capture
+
+local function expected_empty()
+ eq({}, meths.get_vvar('errors'))
+end
describe('autochdir behavior', function()
local dir = 'Xtest_functional_legacy_autochdir'
@@ -10,19 +14,66 @@ describe('autochdir behavior', function()
before_each(function()
lfs.mkdir(dir)
clear()
+ command('set shellslash')
end)
after_each(function()
helpers.rmdir(dir)
end)
- -- Tests vim/vim/777 without test_autochdir().
+ -- Tests vim/vim#777 without test_autochdir().
it('sets filename', function()
command('set acd')
command('new')
command('w '..dir..'/Xtest')
eq('Xtest', eval("expand('%')"))
- eq(dir, eval([[substitute(getcwd(), '.*[/\\]\(\k*\)', '\1', '')]]))
+ eq(dir, eval([[substitute(getcwd(), '.*/\(\k*\)', '\1', '')]]))
+ end)
+
+ it(':file in win_execute() does not cause wrong directory', function()
+ command('cd '..dir)
+ source([[
+ func Test_set_filename_other_window()
+ let cwd = getcwd()
+ call mkdir('Xa')
+ call mkdir('Xb')
+ call mkdir('Xc')
+ try
+ args Xa/aaa.txt Xb/bbb.txt
+ set acd
+ let winid = win_getid()
+ snext
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt')
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ finally
+ set noacd
+ call chdir(cwd)
+ call delete('Xa', 'rf')
+ call delete('Xb', 'rf')
+ call delete('Xc', 'rf')
+ bwipe! aaa.txt
+ bwipe! bbb.txt
+ bwipe! ccc.txt
+ endtry
+ endfunc
+ ]])
+ call('Test_set_filename_other_window')
+ expected_empty()
+ end)
+
+ it('win_execute() does not change directory', function()
+ local subdir = 'Xfile'
+ command('cd '..dir)
+ command('set acd')
+ call('mkdir', subdir)
+ local winid = eval('win_getid()')
+ command('new '..subdir..'/file')
+ matches(dir..'/'..subdir..'$', eval('getcwd()'))
+ command('cd ..')
+ matches(dir..'$', eval('getcwd()'))
+ call('win_execute', winid, 'echo')
+ matches(dir..'$', eval('getcwd()'))
end)
it(':verbose pwd shows whether autochdir is used', function()
@@ -30,29 +81,36 @@ describe('autochdir behavior', function()
command('cd '..dir)
local cwd = eval('getcwd()')
command('edit global.txt')
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
call('mkdir', subdir)
command('split '..subdir..'/local.txt')
command('lcd '..subdir)
- matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
- command('set autochdir')
+ matches('%[window%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('set acd')
command('wincmd w')
- matches('%[autochdir%].*'..dir, exec_capture('verbose pwd'))
- command('lcd '..cwd)
- matches('%[window%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'$', exec_capture('verbose pwd'))
command('tcd '..cwd)
- matches('%[tabpage%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[tabpage%].*'..dir..'$', exec_capture('verbose pwd'))
command('cd '..cwd)
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('lcd '..cwd)
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
command('edit')
- matches('%[autochdir%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('enew')
command('wincmd w')
- matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
- command('set noautochdir')
- matches('%[autochdir%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
command('wincmd w')
- matches('%[global%].*'..dir, exec_capture('verbose pwd'))
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('wincmd w')
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('set noacd')
+ matches('%[autochdir%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
+ command('wincmd w')
+ matches('%[window%].*'..dir..'$', exec_capture('verbose pwd'))
+ command('cd '..cwd)
+ matches('%[global%].*'..dir..'$', exec_capture('verbose pwd'))
command('wincmd w')
- matches('%[window%].*'..dir..'[/\\]'..subdir, exec_capture('verbose pwd'))
+ matches('%[window%].*'..dir..'/'..subdir..'$', exec_capture('verbose pwd'))
end)
end)
diff --git a/test/functional/legacy/cdo_spec.lua b/test/functional/legacy/cdo_spec.lua
deleted file mode 100644
index 8b3216cbfd..0000000000
--- a/test/functional/legacy/cdo_spec.lua
+++ /dev/null
@@ -1,228 +0,0 @@
--- Tests for the :cdo, :cfdo, :ldo and :lfdo commands
-
-local helpers = require('test.functional.helpers')(after_each)
-local nvim, clear = helpers.meths, helpers.clear
-local call, feed = helpers.call, helpers.feed
-local source, eq = helpers.source, helpers.eq
-
-local function expected_empty()
- eq({}, nvim.get_vvar('errors'))
-end
-
-describe('cdo', function()
- before_each(function()
- clear()
-
- call('writefile', {'Line1', 'Line2', 'Line3'}, 'Xtestfile1')
- call('writefile', {'Line1', 'Line2', 'Line3'}, 'Xtestfile2')
- call('writefile', {'Line1', 'Line2', 'Line3'}, 'Xtestfile3')
-
- source([=[
- " Returns the current line in '<filename> <linenum>L <column>C' format
- function GetRuler()
- return expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C'
- endfunction
-
- " Tests for the :cdo and :ldo commands
- function XdoTests(cchar)
- enew
-
- " Shortcuts for calling the cdo and ldo commands
- let Xdo = a:cchar . 'do'
- let Xgetexpr = a:cchar . 'getexpr'
- let Xprev = a:cchar. 'prev'
- let XdoCmd = Xdo . ' call add(l, GetRuler())'
-
- " Try with an empty list
- let l = []
- exe XdoCmd
- call assert_equal([], l)
-
- " Populate the list and then try
- exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']"
-
- let l = []
- exe XdoCmd
- call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
-
- " Run command only on selected error lines
- let l = []
- enew
- exe "2,3" . XdoCmd
- call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
-
- " Boundary condition tests
- let l = []
- enew
- exe "1,1" . XdoCmd
- call assert_equal(['Xtestfile1 1L 3C'], l)
-
- let l = []
- enew
- exe "3" . XdoCmd
- call assert_equal(['Xtestfile3 3L 1C'], l)
-
- " Range test commands
- let l = []
- enew
- exe "%" . XdoCmd
- call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
-
- let l = []
- enew
- exe "1,$" . XdoCmd
- call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
-
- let l = []
- enew
- exe Xprev
- exe "." . XdoCmd
- call assert_equal(['Xtestfile2 2L 2C'], l)
-
- let l = []
- enew
- exe "+" . XdoCmd
- call assert_equal(['Xtestfile3 3L 1C'], l)
-
- " Invalid error lines test
- let l = []
- enew
- exe "silent! 27" . XdoCmd
- exe "silent! 4,5" . XdoCmd
- call assert_equal([], l)
-
- " Run commands from an unsaved buffer when 'hidden' is unset
- set nohidden
- let v:errmsg=''
- let l = []
- enew
- setlocal modified
- exe "silent! 2,2" . XdoCmd
- if v:errmsg !~# 'No write since last change'
- call add(v:errors, 'Unsaved file change test failed')
- endif
-
- " If the executed command fails, then the operation should be aborted
- enew!
- let subst_count = 0
- exe "silent!" . Xdo . " s/Line/xLine/ | let subst_count += 1"
- if subst_count != 1 || getline('.') != 'xLine1'
- call add(v:errors, 'Abort command on error test failed')
- endif
- set hidden
-
- let l = []
- exe "2,2" . Xdo . "! call add(l, GetRuler())"
- call assert_equal(['Xtestfile2 2L 2C'], l)
-
- " List with no valid error entries
- let l = []
- edit! +2 Xtestfile1
- exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']"
- exe XdoCmd
- call assert_equal([], l)
- exe "silent! 2" . XdoCmd
- call assert_equal([], l)
- let v:errmsg=''
- exe "%" . XdoCmd
- exe "1,$" . XdoCmd
- exe "." . XdoCmd
- call assert_equal('', v:errmsg)
-
- " List with only one valid entry
- let l = []
- exe Xgetexpr . " ['Xtestfile3:3:1:Line3']"
- exe XdoCmd
- call assert_equal(['Xtestfile3 3L 1C'], l)
-
- endfunction
-
- " Tests for the :cfdo and :lfdo commands
- function XfdoTests(cchar)
- enew
-
- " Shortcuts for calling the cfdo and lfdo commands
- let Xfdo = a:cchar . 'fdo'
- let Xgetexpr = a:cchar . 'getexpr'
- let XfdoCmd = Xfdo . ' call add(l, GetRuler())'
- let Xpfile = a:cchar. 'pfile'
-
- " Clear the quickfix/location list
- exe Xgetexpr . " []"
-
- " Try with an empty list
- let l = []
- exe XfdoCmd
- call assert_equal([], l)
-
- " Populate the list and then try
- exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']"
-
- let l = []
- exe XfdoCmd
- call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
-
- " Run command only on selected error lines
- let l = []
- exe "2,3" . XfdoCmd
- call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
-
- " Boundary condition tests
- let l = []
- exe "3" . XfdoCmd
- call assert_equal(['Xtestfile3 2L 3C'], l)
-
- " Range test commands
- let l = []
- exe "%" . XfdoCmd
- call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
-
- let l = []
- exe "1,$" . XfdoCmd
- call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
-
- let l = []
- exe Xpfile
- exe "." . XfdoCmd
- call assert_equal(['Xtestfile2 2L 2C'], l)
-
- " List with only one valid entry
- let l = []
- exe Xgetexpr . " ['Xtestfile2:2:5:Line2']"
- exe XfdoCmd
- call assert_equal(['Xtestfile2 2L 5C'], l)
-
- endfunction
- ]=])
- end)
-
- after_each(function()
- os.remove('Xtestfile1')
- os.remove('Xtestfile2')
- os.remove('Xtestfile3')
- end)
-
- it('works for :cdo', function()
- -- call('XdoTests', 'c')
- feed(":call XdoTests('c')<CR><C-l>")
- expected_empty()
- end)
-
- it('works for :cfdo', function()
- -- call('XfdoTests', 'c')
- feed(":call XfdoTests('c')<CR><C-l>")
- expected_empty()
- end)
-
- it('works for :ldo', function()
- -- call('XdoTests', 'l')
- feed(":call XdoTests('l')<CR><C-l>")
- expected_empty()
- end)
-
- it('works for :lfdo', function()
- -- call('XfdoTests', 'l')
- feed(":call XfdoTests('l')<CR><C-l>")
- expected_empty()
- end)
-end)
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
index 9ebe9aeb91..d8d849271b 100644
--- a/test/functional/legacy/cmdline_spec.lua
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -11,6 +11,15 @@ describe('cmdline', function()
it('is cleared when switching tabs', function()
local screen = Screen.new(30, 10)
screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {underline = true, background = Screen.colors.LightGrey};
+ [2] = {bold = true};
+ [3] = {reverse = true};
+ [4] = {bold = true, foreground = Screen.colors.Blue1};
+ }
+ -- TODO(bfredl): redraw with tabs is severly broken. fix it
+ feed_command [[ set display-=msgsep ]]
+
feed_command([[call setline(1, range(30))]])
screen:expect([[
^0 |
@@ -24,18 +33,61 @@ describe('cmdline', function()
8 |
:call setline(1, range(30)) |
]])
- feed([[:tabnew<cr><C-w>-<C-w>-gtgt]])
- screen:expect([[
- + [No Name] [No Name] X|
+
+ feed [[:tabnew<cr>]]
+ screen:expect{grid=[[
+ {1: + [No Name] }{2: [No Name] }{3: }{1:X}|
+ ^ |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ :tabnew |
+ ]]}
+
+ feed [[<C-w>-<C-w>-]]
+ screen:expect{grid=[[
+ {1: + [No Name] }{2: [No Name] }{3: }{1:X}|
^ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ |
+ |
+ :tabnew |
+ ]]}
+
+ feed [[gt]]
+ screen:expect{grid=[[
+ {2: + [No Name] }{1: [No Name] }{3: }{1:X}|
+ ^0 |
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ 5 |
6 |
7 |
|
+ ]]}
+
+ feed [[gt]]
+ screen:expect([[
+ {1: + [No Name] }{2: [No Name] }{3: }{1:X}|
+ ^ |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ |
+ |
+ |
]])
end)
diff --git a/test/functional/legacy/cpoptions_spec.lua b/test/functional/legacy/cpoptions_spec.lua
new file mode 100644
index 0000000000..d2f382ec12
--- /dev/null
+++ b/test/functional/legacy/cpoptions_spec.lua
@@ -0,0 +1,34 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('cpoptions', function()
+ it('$', function()
+ local screen = Screen.new(30, 6)
+ screen:attach()
+ command('set cpo+=$')
+ command([[call setline(1, 'one two three')]])
+ feed('c2w')
+ screen:expect([[
+ ^one tw$ three |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ feed('vim<Esc>')
+ screen:expect([[
+ vi^m three |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua
index 141d9583e6..4ba4c8d356 100644
--- a/test/functional/legacy/delete_spec.lua
+++ b/test/functional/legacy/delete_spec.lua
@@ -25,25 +25,6 @@ describe('Test for delete()', function()
eq(0, eval("isdirectory('Xdir1')"))
eq(-1, eval("delete('Xdir1', 'd')"))
end)
- it('recursive delete', function()
- command("call mkdir('Xdir1')")
- command("call mkdir('Xdir1/subdir')")
- command("call mkdir('Xdir1/empty')")
- command('split Xdir1/Xfile')
- command("call setline(1, ['a', 'b'])")
- command('w')
- command('w Xdir1/subdir/Xfile')
- command('close')
-
- eq(1, eval("isdirectory('Xdir1')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir1/Xfile')"))
- eq(1, eval("isdirectory('Xdir1/subdir')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir1/subdir/Xfile')"))
- eq(1, eval("'Xdir1/empty'->isdirectory()"))
- eq(0, eval("delete('Xdir1', 'rf')"))
- eq(0, eval("isdirectory('Xdir1')"))
- eq(-1, eval("delete('Xdir1', 'd')"))
- end)
it('symlink delete', function()
source([[
@@ -80,45 +61,8 @@ describe('Test for delete()', function()
eq(0, eval("delete('Xdir1', 'd')"))
end)
- it('symlink recursive delete', function()
- source([[
- call mkdir('Xdir3')
- call mkdir('Xdir3/subdir')
- call mkdir('Xdir4')
- split Xdir3/Xfile
- call setline(1, ['a', 'b'])
- w
- w Xdir3/subdir/Xfile
- w Xdir4/Xfile
- close
- if has('win32')
- silent !mklink /j Xdir3\Xlink Xdir4
- else
- silent !ln -s ../Xdir4 Xdir3/Xlink
- endif
- ]])
-
- eq(1, eval("isdirectory('Xdir3')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir3/Xfile')"))
- eq(1, eval("isdirectory('Xdir3/subdir')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir3/subdir/Xfile')"))
- eq(1, eval("isdirectory('Xdir4')"))
- eq(1, eval("isdirectory('Xdir3/Xlink')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir4/Xfile')"))
-
- eq(0, eval("delete('Xdir3', 'rf')"))
- eq(0, eval("isdirectory('Xdir3')"))
- eq(-1, eval("delete('Xdir3', 'd')"))
- -- symlink is deleted, not the directory it points to
- eq(1, eval("isdirectory('Xdir4')"))
- eq(eval("['a', 'b']"), eval("readfile('Xdir4/Xfile')"))
- eq(0, eval("delete('Xdir4/Xfile')"))
- eq(0, eval("delete('Xdir4', 'd')"))
- end)
-
it('gives correct emsgs', function()
eq('Vim(call):E474: Invalid argument', exc_exec("call delete('')"))
- eq('Vim(call):E15: Invalid expression: 0',
- exc_exec("call delete('foo', 0)"))
+ eq('Vim(call):E15: Invalid expression: 0', exc_exec("call delete('foo', 0)"))
end)
end)
diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index 3fbbe96947..f0ffaf2c48 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -2,23 +2,21 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
-local poke_eventloop = helpers.poke_eventloop
+local exec = helpers.exec
local feed = helpers.feed
-local feed_command = helpers.feed_command
+local command = helpers.command
describe('display', function()
- local screen
+ before_each(clear)
- it('scroll when modified at topline', function()
- clear()
- screen = Screen.new(20, 4)
+ it('scroll when modified at topline vim-patch:8.2.1488', function()
+ local screen = Screen.new(20, 4)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true},
})
- feed_command([[call setline(1, repeat('a', 21))]])
- poke_eventloop()
+ command([[call setline(1, repeat('a', 21))]])
feed('O')
screen:expect([[
^ |
@@ -27,5 +25,79 @@ describe('display', function()
{1:-- INSERT --} |
]])
end)
-end)
+ it('scrolling when modified at topline in Visual mode vim-patch:8.2.4626', function()
+ local screen = Screen.new(60, 8)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true}, -- ModeMsg
+ [2] = {background = Screen.colors.LightGrey}, -- Visual
+ [3] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue}, -- SignColumn
+ })
+
+ exec([[
+ set scrolloff=0
+ call setline(1, repeat(['foo'], 10))
+ call sign_define('foo', { 'text': '>' })
+ call sign_place(1, 'bar', 'foo', bufnr(), { 'lnum': 2 })
+ call sign_place(2, 'bar', 'foo', bufnr(), { 'lnum': 1 })
+ autocmd CursorMoved * if getcurpos()[1] == 2 | call sign_unplace('bar', { 'id': 1 }) | endif
+ ]])
+ feed('VG7kk')
+ screen:expect([[
+ {3: }^f{2:oo} |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {3: }foo |
+ {1:-- VISUAL LINE --} |
+ ]])
+ end)
+
+ it('@@@ in the last line shows correctly in a narrow window vim-patch:8.2.4718', function()
+ local screen = Screen.new(60, 10)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {bold = true, reverse = true}, -- StatusLine
+ [3] = {reverse = true}, -- StatusLineNC
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['aaa', 'b'->repeat(100)])
+ set display=truncate
+ vsplit
+ 100wincmd <
+ ]])
+ screen:expect([[
+ ^a│aaa |
+ a│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+ a│bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb |
+ b│{1:~ }|
+ b│{1:~ }|
+ b│{1:~ }|
+ b│{1:~ }|
+ {1:@}│{1:~ }|
+ {2:< }{3:[No Name] [+] }|
+ |
+ ]])
+ command('set display=lastline')
+ screen:expect_unchanged()
+ command('100wincmd >')
+ screen:expect([[
+ ^aaa │a|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb│a|
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb │a|
+ {1:~ }│b|
+ {1:~ }│b|
+ {1:~ }│b|
+ {1:~ }│b|
+ {1:~ }│{1:@}|
+ {2:[No Name] [+] }{3:<}|
+ |
+ ]])
+ command('set display=truncate')
+ screen:expect_unchanged()
+ end)
+end)
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
index 91d602924c..7fc5f11a79 100644
--- a/test/functional/legacy/edit_spec.lua
+++ b/test/functional/legacy/edit_spec.lua
@@ -1,25 +1,26 @@
--- Test for edit functions
--- See also: src/nvim/testdir/test_edit.vim
-
local helpers = require('test.functional.helpers')(after_each)
-local source = helpers.source
-local eq, eval = helpers.eq, helpers.eval
-local funcs = helpers.funcs
local clear = helpers.clear
+local command = helpers.command
+local expect = helpers.expect
+local feed = helpers.feed
+local sleep = helpers.sleep
-describe('edit', function()
- before_each(clear)
-
- it('reset insertmode from i_ctrl-r_=', function()
- source([=[
- call setline(1, ['abc'])
- call cursor(1, 4)
- call feedkeys(":set im\<cr>ZZZ\<c-r>=setbufvar(1,'&im', 0)\<cr>",'tnix')
- ]=])
- eq({'abZZZc'}, funcs.getline(1,'$'))
- eq({0, 1, 1, 0}, funcs.getpos('.'))
- eq(0, eval('&im'))
- end)
+before_each(clear)
+-- oldtest: Test_autoindent_remove_indent()
+it('autoindent removes indent when Insert mode is stopped', function()
+ command('set autoindent')
+ -- leaving insert mode in a new line with indent added by autoindent, should
+ -- remove the indent.
+ feed('i<Tab>foo<CR><Esc>')
+ -- Need to delay for sometime, otherwise the code in getchar.c will not be
+ -- exercised.
+ sleep(50)
+ -- when a line is wrapped and the cursor is at the start of the second line,
+ -- leaving insert mode, should move the cursor back to the first line.
+ feed('o' .. ('x'):rep(20) .. '<Esc>')
+ -- Need to delay for sometime, otherwise the code in getchar.c will not be
+ -- exercised.
+ sleep(50)
+ expect('\tfoo\n\n' .. ('x'):rep(20))
end)
-
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index b5de5cd232..05d853622e 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -666,7 +666,7 @@ describe('eval', function()
source([[
" Vim script used in test_eval.in. Needed for script-local function.
- func! s:Testje()
+ func s:Testje()
return "foo"
endfunc
diff --git a/test/functional/legacy/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua
new file mode 100644
index 0000000000..98f113bbd0
--- /dev/null
+++ b/test/functional/legacy/ex_mode_spec.lua
@@ -0,0 +1,125 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local meths = helpers.meths
+
+before_each(clear)
+
+describe('Ex mode', function()
+ it('supports command line editing', function()
+ local function test_ex_edit(expected, cmd)
+ feed('gQ' .. cmd .. '<C-b>"<CR>')
+ local ret = eval('@:[1:]') -- Remove leading quote.
+ feed('visual<CR>')
+ eq(meths.replace_termcodes(expected, true, true, true), ret)
+ end
+ command('set sw=2')
+ test_ex_edit('bar', 'foo bar<C-u>bar')
+ test_ex_edit('1<C-u>2', '1<C-v><C-u>2')
+ test_ex_edit('213', '1<C-b>2<C-e>3')
+ test_ex_edit('2013', '01<Home>2<End>3')
+ test_ex_edit('0213', '01<Left>2<Right>3')
+ test_ex_edit('0342', '012<Left><Left><Insert>3<Insert>4')
+ test_ex_edit('foo ', 'foo bar<C-w>')
+ test_ex_edit('foo', 'fooba<Del><Del>')
+ test_ex_edit('foobar', 'foo<Tab>bar')
+ test_ex_edit('abbreviate', 'abbrev<Tab>')
+ test_ex_edit('1<C-t><C-t>', '1<C-t><C-t>')
+ test_ex_edit('1<C-t><C-t>', '1<C-t><C-t><C-d>')
+ test_ex_edit(' foo', ' foo<C-d>')
+ test_ex_edit(' foo0', ' foo0<C-d>')
+ test_ex_edit(' foo^', ' foo^<C-d>')
+ test_ex_edit('foo', '<BS><C-H><Del><kDel>foo')
+ -- default wildchar <Tab> interferes with this test
+ command('set wildchar=<c-e>')
+ test_ex_edit('a\tb', 'a\t\t<C-H>b')
+ test_ex_edit('\tm<C-T>n', '\tm<C-T>n')
+ command('set wildchar&')
+ end)
+
+ it('substitute confirmation prompt', function()
+ command('set noincsearch nohlsearch inccommand=')
+ local screen = Screen.new(60, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, reverse = true}, -- MsgSeparator
+ [1] = {foreground = Screen.colors.Brown}, -- LineNr
+ [2] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ })
+ screen:attach()
+ command([[call setline(1, ['foo foo', 'foo foo', 'foo foo'])]])
+ command([[set number]])
+ feed('gQ')
+ screen:expect([[
+ {1: 1 }foo foo |
+ {1: 2 }foo foo |
+ {1: 3 }foo foo |
+ {0: }|
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :^ |
+ ]])
+
+ feed('%s/foo/bar/gc<CR>')
+ screen:expect([[
+ {1: 1 }foo foo |
+ {0: }|
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :%s/foo/bar/gc |
+ {1: 1 }foo foo |
+ ^^^^ |
+ ]])
+ feed('N<CR>')
+ screen:expect([[
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :%s/foo/bar/gc |
+ {1: 1 }foo foo |
+ ^^^N |
+ {1: 1 }foo foo |
+ ^^^^ |
+ ]])
+ feed('n<CR>')
+ screen:expect([[
+ {1: 1 }foo foo |
+ ^^^N |
+ {1: 1 }foo foo |
+ ^^^n |
+ {1: 1 }foo foo |
+ ^^^^ |
+ ]])
+ feed('y<CR>')
+
+ feed('q<CR>')
+ screen:expect([[
+ {1: 1 }foo foo |
+ ^^^y |
+ {1: 2 }foo foo |
+ ^^^q |
+ {1: 2 }foo foo |
+ :^ |
+ ]])
+
+ -- Pressing enter in ex mode should print the current line
+ feed('<CR>')
+ screen:expect([[
+ ^^^y |
+ {1: 2 }foo foo |
+ ^^^q |
+ {1: 2 }foo foo |
+ {1: 3 }foo foo |
+ :^ |
+ ]])
+
+ feed(':vi<CR>')
+ screen:expect([[
+ {1: 1 }foo bar |
+ {1: 2 }foo foo |
+ {1: 3 }^foo foo |
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua
new file mode 100644
index 0000000000..6b3b265579
--- /dev/null
+++ b/test/functional/legacy/excmd_spec.lua
@@ -0,0 +1,188 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+local meths = helpers.meths
+local poke_eventloop = helpers.poke_eventloop
+local read_file = helpers.read_file
+local source = helpers.source
+local eq = helpers.eq
+local write_file = helpers.write_file
+
+local function sizeoflong()
+ if not exec_lua('return pcall(require, "ffi")') then
+ pending('missing LuaJIT FFI')
+ end
+ return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))')
+end
+
+describe('Ex command', function()
+ before_each(clear)
+ after_each(function() eq({}, meths.get_vvar('errors')) end)
+
+ it('checks for address line overflow', function()
+ if sizeoflong() < 8 then
+ pending('Skipped: only works with 64 bit long ints')
+ end
+
+ source [[
+ new
+ call setline(1, 'text')
+ call assert_fails('|.44444444444444444444444', 'E1247:')
+ call assert_fails('|.9223372036854775806', 'E1247:')
+ bwipe!
+ ]]
+ end)
+end)
+
+it(':confirm command dialog', function()
+ local screen
+
+ local function start_new()
+ clear()
+ screen = Screen.new(60, 20)
+ screen:attach()
+ end
+
+ write_file('foo', 'foo1\n')
+ write_file('bar', 'bar1\n')
+
+ -- Test for saving all the modified buffers
+ start_new()
+ command("set nomore")
+ command("new foo")
+ command("call setline(1, 'foo2')")
+ command("new bar")
+ command("call setline(1, 'bar2')")
+ command("wincmd b")
+ feed(':confirm qall\n')
+ screen:expect([[
+ bar2 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ bar [+] |
+ foo2 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ foo [+] |
+ |
+ ~ |
+ ~ |
+ |
+ :confirm qall |
+ Save changes to "bar"? |
+ [Y]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ^ |
+ ]])
+ feed('A')
+ poke_eventloop()
+
+ eq('foo2\n', read_file('foo'))
+ eq('bar2\n', read_file('bar'))
+
+ -- Test for discarding all the changes to modified buffers
+ start_new()
+ command("set nomore")
+ command("new foo")
+ command("call setline(1, 'foo3')")
+ command("new bar")
+ command("call setline(1, 'bar3')")
+ command("wincmd b")
+ feed(':confirm qall\n')
+ screen:expect([[
+ bar3 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ bar [+] |
+ foo3 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ foo [+] |
+ |
+ ~ |
+ ~ |
+ |
+ :confirm qall |
+ Save changes to "bar"? |
+ [Y]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ^ |
+ ]])
+ feed('D')
+ poke_eventloop()
+
+ eq('foo2\n', read_file('foo'))
+ eq('bar2\n', read_file('bar'))
+
+ -- Test for saving and discarding changes to some buffers
+ start_new()
+ command("set nomore")
+ command("new foo")
+ command("call setline(1, 'foo4')")
+ command("new bar")
+ command("call setline(1, 'bar4')")
+ command("wincmd b")
+ feed(':confirm qall\n')
+ screen:expect([[
+ bar4 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ bar [+] |
+ foo4 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ foo [+] |
+ |
+ ~ |
+ ~ |
+ |
+ :confirm qall |
+ Save changes to "bar"? |
+ [Y]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ^ |
+ ]])
+ feed('N')
+ screen:expect([[
+ bar4 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ bar [+] |
+ foo4 |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ foo [+] |
+ |
+ |
+ :confirm qall |
+ Save changes to "bar"? |
+ |
+ Save changes to "foo"? |
+ [Y]es, (N)o, (C)ancel: ^ |
+ ]])
+ feed('Y')
+ poke_eventloop()
+
+ eq('foo4\n', read_file('foo'))
+ eq('bar2\n', read_file('bar'))
+
+ os.remove('foo')
+ os.remove('bar')
+end)
diff --git a/test/functional/legacy/expand_spec.lua b/test/functional/legacy/expand_spec.lua
deleted file mode 100644
index cd3713eabe..0000000000
--- a/test/functional/legacy/expand_spec.lua
+++ /dev/null
@@ -1,129 +0,0 @@
--- Test for expanding file names
-
-local helpers = require('test.functional.helpers')(after_each)
-local eq = helpers.eq
-local call = helpers.call
-local nvim = helpers.meths
-local clear = helpers.clear
-local source = helpers.source
-
-local function expected_empty()
- eq({}, nvim.get_vvar('errors'))
-end
-
-describe('expand file name', function()
- after_each(function()
- helpers.rmdir('Xdir1')
- helpers.rmdir('Xdir2')
- helpers.rmdir('Xdir3')
- helpers.rmdir('Xdir4')
- end)
-
- before_each(function()
- clear()
-
- source([[
- func Test_with_directories()
- call mkdir('Xdir1')
- call mkdir('Xdir2')
- call mkdir('Xdir3')
- cd Xdir3
- call mkdir('Xdir4')
- cd ..
-
- split Xdir1/file
- call setline(1, ['a', 'b'])
- w
- w Xdir3/Xdir4/file
- close
-
- next Xdir?/*/file
- call assert_equal('Xdir3/Xdir4/file', expand('%'))
- if has('unix')
- next! Xdir?/*/nofile
- call assert_equal('Xdir?/*/nofile', expand('%'))
- endif
- " Edit another file, on MS-Windows the swap file would be in use and can't
- " be deleted
- edit foo
-
- call assert_equal(0, delete('Xdir1', 'rf'))
- call assert_equal(0, delete('Xdir2', 'rf'))
- call assert_equal(0, delete('Xdir3', 'rf'))
- endfunc
-
- func Test_with_tilde()
- let dir = getcwd()
- call mkdir('Xdir ~ dir')
- call assert_true(isdirectory('Xdir ~ dir'))
- cd Xdir\ ~\ dir
- call assert_true(getcwd() =~ 'Xdir \~ dir')
- exe 'cd ' . fnameescape(dir)
- call delete('Xdir ~ dir', 'd')
- call assert_false(isdirectory('Xdir ~ dir'))
- endfunc
-
- func Test_expand_tilde_filename()
- split ~
- call assert_equal('~', expand('%'))
- call assert_notequal(expand('%:p'), expand('~/'))
- call assert_match('\~', expand('%:p'))
- bwipe!
- endfunc
-
- func Test_expandcmd()
- let $FOO = 'Test'
- call assert_equal('e x/Test/y', expandcmd('e x/$FOO/y'))
- unlet $FOO
-
- new
- edit Xfile1
- call assert_equal('e Xfile1', expandcmd('e %'))
- edit Xfile2
- edit Xfile1
- call assert_equal('e Xfile2', 'e #'->expandcmd())
- edit Xfile2
- edit Xfile3
- edit Xfile4
- let bnum = bufnr('Xfile2')
- call assert_equal('e Xfile2', expandcmd('e #' . bnum))
- call setline('.', 'Vim!@#')
- call assert_equal('e Vim', expandcmd('e <cword>'))
- call assert_equal('e Vim!@#', expandcmd('e <cWORD>'))
- enew!
- edit Xfile.java
- call assert_equal('e Xfile.py', expandcmd('e %:r.py'))
- call assert_equal('make abc.java', expandcmd('make abc.%:e'))
- call assert_equal('make Xabc.java', expandcmd('make %:s?file?abc?'))
- edit a1a2a3.rb
- call assert_equal('make b1b2b3.rb a1a2a3 Xfile.o', expandcmd('make %:gs?a?b? %< #<.o'))
-
- call assert_fails('call expandcmd("make <afile>")', 'E495:')
- call assert_fails('call expandcmd("make <afile>")', 'E495:')
- enew
- call assert_fails('call expandcmd("make %")', 'E499:')
- close
- endfunc
- ]])
- end)
-
- it('works with directories', function()
- call('Test_with_directories')
- expected_empty()
- end)
-
- it('works with tilde', function()
- call('Test_with_tilde')
- expected_empty()
- end)
-
- it('does not expand tilde if it is a filename', function()
- call('Test_expand_tilde_filename')
- expected_empty()
- end)
-
- it('works with expandcmd()', function()
- call('Test_expandcmd')
- expected_empty()
- end)
-end)
diff --git a/test/functional/legacy/file_perm_spec.lua b/test/functional/legacy/file_perm_spec.lua
deleted file mode 100644
index ccdbfe0534..0000000000
--- a/test/functional/legacy/file_perm_spec.lua
+++ /dev/null
@@ -1,43 +0,0 @@
--- Test getting and setting file permissions.
-require('os')
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear, call, eq = helpers.clear, helpers.call, helpers.eq
-local neq, exc_exec, eval = helpers.neq, helpers.exc_exec, helpers.eval
-
-describe('Test getting and setting file permissions', function()
- local tempfile = helpers.tmpname()
-
- before_each(function()
- os.remove(tempfile)
- clear()
- end)
-
- it('file permissions', function()
- -- eval() is used to test VimL method syntax for setfperm() and getfperm()
- eq('', call('getfperm', tempfile))
- eq(0, eval("'" .. tempfile .. "'->setfperm('r--------')"))
-
- call('writefile', {'one'}, tempfile)
- eq(9, eval("len('" .. tempfile .. "'->getfperm())"))
-
- eq(1, call('setfperm', tempfile, 'rwx------'))
- if helpers.is_os('win') then
- eq('rw-rw-rw-', call('getfperm', tempfile))
- else
- eq('rwx------', call('getfperm', tempfile))
- end
-
- eq(1, call('setfperm', tempfile, 'r--r--r--'))
- eq('r--r--r--', call('getfperm', tempfile))
-
- local err = exc_exec(('call setfperm("%s", "---")'):format(tempfile))
- neq(err:find('E475:'), nil)
-
- eq(1, call('setfperm', tempfile, 'rwx------'))
- end)
-
- after_each(function()
- os.remove(tempfile)
- end)
-end)
diff --git a/test/functional/legacy/filechanged_spec.lua b/test/functional/legacy/filechanged_spec.lua
new file mode 100644
index 0000000000..ecb861098c
--- /dev/null
+++ b/test/functional/legacy/filechanged_spec.lua
@@ -0,0 +1,131 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, source = helpers.clear, helpers.source
+local call, eq, meths = helpers.call, helpers.eq, helpers.meths
+
+local function expected_empty()
+ eq({}, meths.get_vvar('errors'))
+end
+
+describe('file changed dialog', function()
+ before_each(function()
+ clear()
+ meths.ui_attach(80, 24, {})
+ meths.set_option('autoread', false)
+ meths.set_option('fsync', true)
+ end)
+
+ it('works', function()
+ if helpers.pending_win32(pending) then return end
+ source([[
+ func Test_file_changed_dialog()
+ au! FileChangedShell
+
+ new Xchanged_d
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_d
+ call nvim_input('L')
+ checktime
+ call assert_match('W11:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('reload this', getline(1))
+ call assert_equal('extra line', getline(2))
+
+ " delete buffer, only shows an error, no prompt
+ silent !rm Xchanged_d
+ checktime
+ call assert_match('E211:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+ let v:warningmsg = 'empty'
+
+ " change buffer, recreate the file and reload
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >Xchanged_d
+ call nvim_input('L')
+ checktime
+ call assert_match('W12:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed, reload
+ silent !chmod +x Xchanged_d
+ call nvim_input('L')
+ checktime
+ call assert_match('W16:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed, no prompt
+ sleep 2
+ silent !touch Xchanged_d
+ let v:warningmsg = ''
+ checktime Xchanged_d
+ call assert_equal('', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ bwipe!
+ call delete('Xchanged_d')
+ endfunc
+ ]])
+ call('Test_file_changed_dialog')
+ expected_empty()
+ end)
+
+ it('works with FileChangedShell', function()
+ source([[
+ func Test_FileChangedShell_edit_dialog()
+ new Xchanged_r
+ call setline(1, 'reload this')
+ set fileformat=unix
+ silent write " Use :silent to prevent a hit-enter prompt
+
+ " File format changed, reload (content only) via prompt
+ augroup testreload
+ au!
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
+ augroup END
+ call assert_equal(&fileformat, 'unix')
+ sleep 10m " make the test less flaky in Nvim
+ call writefile(["line1\r", "line2\r"], 'Xchanged_r')
+ let g:reason = ''
+ call nvim_input('L') " load file content only
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(&fileformat, 'unix')
+ call assert_equal("line1\r", getline(1))
+ call assert_equal("line2\r", getline(2))
+ %s/\r
+ silent write " Use :silent to prevent a hit-enter prompt
+
+ " File format changed, reload (file and options) via prompt
+ augroup testreload
+ au!
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
+ augroup END
+ call assert_equal(&fileformat, 'unix')
+ sleep 10m " make the test less flaky in Nvim
+ call writefile(["line1\r", "line2\r"], 'Xchanged_r')
+ let g:reason = ''
+ call nvim_input('a') " load file content and options
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(&fileformat, 'dos')
+ call assert_equal("line1", getline(1))
+ call assert_equal("line2", getline(2))
+ set fileformat=unix
+ silent write " Use :silent to prevent a hit-enter prompt
+
+ au! testreload
+ bwipe!
+ call delete(undofile('Xchanged_r'))
+ call delete('Xchanged_r')
+ endfunc
+ ]])
+ call('Test_FileChangedShell_edit_dialog')
+ expected_empty()
+ end)
+end)
diff --git a/test/functional/legacy/fixeol_spec.lua b/test/functional/legacy/fixeol_spec.lua
index d3ff86d349..3cc9d54e2b 100644
--- a/test/functional/legacy/fixeol_spec.lua
+++ b/test/functional/legacy/fixeol_spec.lua
@@ -6,12 +6,11 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe('fixeol', function()
local function rmtestfiles()
- feed_command('%bwipeout!')
- feed_command('call delete("test.out")')
- feed_command('call delete("XXEol")')
- feed_command('call delete("XXNoEol")')
- feed_command('call delete("XXTestEol")')
- feed_command('call delete("XXTestNoEol")')
+ os.remove("test.out")
+ os.remove("XXEol")
+ os.remove("XXNoEol")
+ os.remove("XXTestEol")
+ os.remove("XXTestNoEol")
end
setup(function()
clear()
diff --git a/test/functional/legacy/function_sort_spec.lua b/test/functional/legacy/function_sort_spec.lua
index 12875460e0..414953aacc 100644
--- a/test/functional/legacy/function_sort_spec.lua
+++ b/test/functional/legacy/function_sort_spec.lua
@@ -52,6 +52,6 @@ describe('sort', function()
eq({'2', 'A', 'AA', 'a', 1, 3.3}, eval([[sort([3.3, 1, "2", "A", "a", "AA"], '')]]))
eq({'2', 'A', 'AA', 'a', 1, 3.3}, eval('sort([3.3, 1, "2", "A", "a", "AA"], 0)'))
eq({'2', 'A', 'a', 'AA', 1, 3.3}, eval('sort([3.3, 1, "2", "A", "a", "AA"], 1)'))
- neq(exc_exec('call sort([3.3, 1, "2"], 3)'):find('E474:'), nil)
+ neq(nil, exc_exec('call sort([3.3, 1, "2"], 3)'):find('E474:'))
end)
end)
diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua
index dc6ccd3628..a9aa238d4e 100644
--- a/test/functional/legacy/listchars_spec.lua
+++ b/test/functional/legacy/listchars_spec.lua
@@ -1,7 +1,8 @@
-- Tests for 'listchars' display with 'list' and :list.
local helpers = require('test.functional.helpers')(after_each)
-local feed, insert, source = helpers.feed, helpers.insert, helpers.source
+local Screen = require('test.functional.ui.screen')
+local feed, insert, exec = helpers.feed, helpers.insert, helpers.exec
local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect
-- luacheck: ignore 621 (Indentation)
@@ -13,7 +14,7 @@ describe("'listchars'", function()
-- luacheck: ignore 613 (Trailing whitespace in a string)
it("works with 'list'", function()
- source([[
+ exec([[
function GetScreenCharsForLine(lnum)
return join(map(range(1, virtcol('$')), 'nr2char(screenchar(a:lnum, v:val))'), '')
endfunction
@@ -98,4 +99,126 @@ describe("'listchars'", function()
.....h>-$
iii<<<<><<$]])
end)
+
+ it('"exceeds" character does not appear in foldcolumn vim-patch:8.2.3121', function()
+ local screen = Screen.new(60, 10)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {bold = true, reverse = true}, -- StatusLine
+ [3] = {reverse = true}, -- StatusLineNC
+ [4] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue}, -- FoldColumn, SignColumn
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['aaa', '', 'a', 'aaaaaa'])
+ vsplit
+ vsplit
+ windo set signcolumn=yes foldcolumn=1 winminwidth=0 nowrap list listchars=extends:>,precedes:<
+ ]])
+ feed('13<C-W>>')
+ screen:expect([[
+ {4: }aaa │{4: }a{1:>}│{4: }^aaa |
+ {4: } │{4: } │{4: } |
+ {4: }a │{4: }a │{4: }a |
+ {4: }aaaaaa │{4: }a{1:>}│{4: }aaaaaa |
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {3:[No Name] [+] <[+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ {4: }aaa │{4: }{1:>}│{4: }^aaa |
+ {4: } │{4: } │{4: } |
+ {4: }a │{4: }a│{4: }a |
+ {4: }aaaaaa │{4: }{1:>}│{4: }aaaaaa |
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {3:[No Name] [+] <+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ {4: }aaa │{4: }│{4: }^aaa |
+ {4: } │{4: }│{4: } |
+ {4: }a │{4: }│{4: }a |
+ {4: }aaaaaa │{4: }│{4: }aaaaaa |
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {3:[No Name] [+] <] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ {4: }aaa │{4: }│{4: }^aaa |
+ {4: } │{4: }│{4: } |
+ {4: }a │{4: }│{4: }a |
+ {4: }aaaaaa │{4: }│{4: }aaaaaa |
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {3:[No Name] [+] < }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('<C-W>>')
+ screen:expect([[
+ {4: }aaa │{4: }│{4: }^aaa |
+ {4: } │{4: }│{4: } |
+ {4: }a │{4: }│{4: }a |
+ {4: }aaaaaa │{4: }│{4: }aaaaaa |
+ {1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~}│{1:~ }|
+ {3:[No Name] [+] < }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('<C-W>h')
+ feed_command('set nowrap foldcolumn=4')
+ screen:expect([[
+ {4: }aaa │{4: }^aaa │{4: }aaa |
+ {4: } │{4: } │{4: } |
+ {4: }a │{4: }a │{4: }a |
+ {4: }aaaaaa │{4: }aaaaaa │{4: }aaaaaa |
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }{3:[No Name] [+] }|
+ :set nowrap foldcolumn=4 |
+ ]])
+ feed('15<C-W><lt>')
+ screen:expect([[
+ {4: }aaa │{4: }│{4: }aaa |
+ {4: } │{4: }│{4: } |
+ {4: }a │{4: }│{4: }a |
+ {4: }aaaaaa │{4: ^ }│{4: }aaaaaa |
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {1:~ }│{1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:<[+] }{3:[No Name] [+] }|
+ :set nowrap foldcolumn=4 |
+ ]])
+ feed('4<C-W><lt>')
+ screen:expect([[
+ {4: }aaa │{4: }│{4: }aaa |
+ {4: } │{4: }│{4: } |
+ {4: }a │{4: }│{4: }a |
+ {4: }aaaaaa │{4:^ }│{4: }aaaaaa |
+ {1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~}│{1:~ }|
+ {3:[No Name] [+] }{2:< }{3:[No Name] [+] }|
+ :set nowrap foldcolumn=4 |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua
index 92a757ca85..456acc12b5 100644
--- a/test/functional/legacy/mapping_spec.lua
+++ b/test/functional/legacy/mapping_spec.lua
@@ -2,7 +2,9 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local feed_command, expect, poke_eventloop = helpers.feed_command, helpers.expect, helpers.poke_eventloop
+local expect, poke_eventloop = helpers.expect, helpers.poke_eventloop
+local command, eq, eval, meths = helpers.command, helpers.eq, helpers.eval, helpers.meths
+local sleep = helpers.sleep
describe('mapping', function()
before_each(clear)
@@ -13,7 +15,7 @@ describe('mapping', function()
]])
-- Abbreviations with р (0x80) should work.
- feed_command('inoreab чкпр vim')
+ command('inoreab чкпр vim')
feed('GAчкпр <esc>')
expect([[
@@ -23,17 +25,15 @@ describe('mapping', function()
it('Ctrl-c works in Insert mode', function()
-- Mapping of ctrl-c in insert mode
- feed_command('set cpo-=< cpo-=k')
- feed_command('inoremap <c-c> <ctrl-c>')
- feed_command('cnoremap <c-c> dummy')
- feed_command('cunmap <c-c>')
+ command('set cpo-=< cpo-=k')
+ command('inoremap <c-c> <ctrl-c>')
+ command('cnoremap <c-c> dummy')
+ command('cunmap <c-c>')
feed('GA<cr>')
- feed('TEST2: CTRL-C |')
+ -- XXX: editor must be in Insert mode before <C-C> is put into input buffer
poke_eventloop()
- feed('<c-c>A|<cr><esc>')
- poke_eventloop()
- feed_command('unmap <c-c>')
- feed_command('unmap! <c-c>')
+ feed('TEST2: CTRL-C |<c-c>A|<cr><esc>')
+ command('unmap! <c-c>')
expect([[
@@ -42,13 +42,12 @@ describe('mapping', function()
end)
it('Ctrl-c works in Visual mode', function()
- feed_command([[vnoremap <c-c> :<C-u>$put ='vmap works'<cr>]])
+ command([[vnoremap <c-c> :<C-u>$put ='vmap works'<cr>]])
feed('GV')
- -- XXX: For some reason the mapping is only triggered
- -- when <C-c> is in a separate feed command.
+ -- XXX: editor must be in Visual mode before <C-C> is put into input buffer
poke_eventloop()
- feed('<c-c>')
- feed_command('vunmap <c-c>')
+ feed('vV<c-c>')
+ command('vunmap <c-c>')
expect([[
@@ -57,23 +56,23 @@ describe('mapping', function()
it('langmap', function()
-- langmap should not get remapped in insert mode.
- feed_command('inoremap { FAIL_ilangmap')
- feed_command('set langmap=+{ langnoremap')
+ command('inoremap { FAIL_ilangmap')
+ command('set langmap=+{ langnoremap')
feed('o+<esc>')
-- Insert mode expr mapping with langmap.
- feed_command('inoremap <expr> { "FAIL_iexplangmap"')
+ command('inoremap <expr> { "FAIL_iexplangmap"')
feed('o+<esc>')
-- langmap should not get remapped in cmdline mode.
- feed_command('cnoremap { FAIL_clangmap')
+ command('cnoremap { FAIL_clangmap')
feed('o+<esc>')
- feed_command('cunmap {')
+ command('cunmap {')
-- cmdline mode expr mapping with langmap.
- feed_command('cnoremap <expr> { "FAIL_cexplangmap"')
+ command('cnoremap <expr> { "FAIL_cexplangmap"')
feed('o+<esc>')
- feed_command('cunmap {')
+ command('cunmap {')
-- Assert buffer contents.
expect([[
@@ -91,10 +90,10 @@ describe('mapping', function()
]])
-- Vim's issue #212 (feedkeys insert mapping at current position)
- feed_command('nnoremap . :call feedkeys(".", "in")<cr>')
+ command('nnoremap . :call feedkeys(".", "in")<cr>')
feed('/^a b<cr>')
feed('0qqdw.ifoo<esc>qj0@q<esc>')
- feed_command('unmap .')
+ command('unmap .')
expect([[
fooc d
fooc d
@@ -103,15 +102,15 @@ describe('mapping', function()
it('i_CTRL-G_U', function()
-- <c-g>U<cursor> works only within a single line
- feed_command('imapclear')
- feed_command('imap ( ()<c-g>U<left>')
+ command('imapclear')
+ command('imap ( ()<c-g>U<left>')
feed('G2o<esc>ki<cr>Test1: text with a (here some more text<esc>k.')
-- test undo
feed('G2o<esc>ki<cr>Test2: text wit a (here some more text [und undo]<c-g>u<esc>k.u')
- feed_command('imapclear')
- feed_command('set whichwrap=<,>,[,]')
+ command('imapclear')
+ command('set whichwrap=<,>,[,]')
feed('G3o<esc>2k')
- feed_command([[:exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."]])
+ command([[:exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."]])
expect([[
@@ -126,4 +125,58 @@ describe('mapping', function()
new line here
]])
end)
+
+ it('dragging starts Select mode even if coming from mapping vim-patch:8.2.4806', function()
+ command('set mouse=a')
+ command('set selectmode=mouse')
+
+ command('nnoremap <LeftDrag> <LeftDrag><Cmd><CR>')
+ sleep(10)
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ sleep(10)
+ meths.input_mouse('left', 'drag', '', 0, 0, 1)
+ sleep(10)
+ eq('s', eval('mode()'))
+ end)
+
+ it('<LeftDrag> mapping in Insert mode works correctly vim-patch:8.2.4692', function()
+ command('set mouse=a')
+
+ command('inoremap <LeftDrag> <LeftDrag><Cmd>let g:dragged = 1<CR>')
+ feed('i')
+ sleep(10)
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ sleep(10)
+ meths.input_mouse('left', 'drag', '', 0, 0, 1)
+ sleep(10)
+ eq(1, eval('g:dragged'))
+ eq('v', eval('mode()'))
+ feed([[<C-\><C-N>]])
+
+ command([[inoremap <LeftDrag> <LeftDrag><C-\><C-N>]])
+ feed('i')
+ sleep(10)
+ meths.input_mouse('left', 'press', '', 0, 0, 0)
+ sleep(10)
+ meths.input_mouse('left', 'drag', '', 0, 0, 1)
+ sleep(10)
+ eq('n', eval('mode()'))
+ end)
+
+ it('timeout works after an <Nop> mapping is triggered on timeout vim-patch:8.1.0052', function()
+ command('set timeout timeoutlen=400')
+ command('inoremap ab TEST')
+ command('inoremap a <Nop>')
+ -- Enter Insert mode
+ feed('i')
+ -- Wait for the "a" mapping to time out
+ feed('a')
+ sleep(500)
+ -- Send "a" and wait for a period shorter than 'timeoutlen'
+ feed('a')
+ sleep(100)
+ -- Send "b", should trigger the "ab" mapping
+ feed('b')
+ expect('TEST')
+ end)
end)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index 8d25b9d927..eec89aa919 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -10,6 +10,7 @@ local source = helpers.source
local poke_eventloop = helpers.poke_eventloop
local uname = helpers.uname
local load_adjust = helpers.load_adjust
+local write_file = helpers.write_file
local isCI = helpers.isCI
local function isasan()
@@ -84,6 +85,12 @@ setmetatable(monitor_memory_usage,
end})
describe('memory usage', function()
+ local tmpfile = 'X_memory_usage'
+
+ after_each(function()
+ os.remove(tmpfile)
+ end)
+
local function check_result(tbl, status, result)
if not status then
print('')
@@ -103,7 +110,7 @@ describe('memory usage', function()
it('function capture vargs', function()
local pid = eval('getpid()')
local before = monitor_memory_usage(pid)
- source([[
+ write_file(tmpfile, [[
func s:f(...)
let x = a:000
endfunc
@@ -111,6 +118,8 @@ describe('memory usage', function()
call s:f(0)
endfor
]])
+ -- TODO: check_result fails if command() is used here. Why? #16064
+ feed_command('source '..tmpfile)
poke_eventloop()
local after = monitor_memory_usage(pid)
-- Estimate the limit of max usage as 2x initial usage.
@@ -136,7 +145,7 @@ describe('memory usage', function()
it('function capture lvars', function()
local pid = eval('getpid()')
local before = monitor_memory_usage(pid)
- local fname = source([[
+ write_file(tmpfile, [[
if !exists('s:defined_func')
func s:f()
let x = l:
@@ -147,10 +156,12 @@ describe('memory usage', function()
call s:f()
endfor
]])
+ feed_command('source '..tmpfile)
poke_eventloop()
local after = monitor_memory_usage(pid)
for _ = 1, 3 do
- feed_command('so '..fname)
+ -- TODO: check_result fails if command() is used here. Why? #16064
+ feed_command('source '..tmpfile)
poke_eventloop()
end
local last = monitor_memory_usage(pid)
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
new file mode 100644
index 0000000000..b296ac909d
--- /dev/null
+++ b/test/functional/legacy/messages_spec.lua
@@ -0,0 +1,421 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('messages', function()
+ local screen
+
+ describe('more prompt', function()
+ before_each(function()
+ screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [2] = {foreground = Screen.colors.Brown}, -- LineNr
+ [3] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ })
+ screen:attach()
+ command('set more')
+ end)
+
+ -- oldtest: Test_message_more()
+ it('works', function()
+ command('call setline(1, range(1, 100))')
+
+ feed(':%p#\n')
+ screen:expect([[
+ {2: 1 }1 |
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {1:-- More --}^ |
+ ]])
+
+ feed('?')
+ screen:expect([[
+ {2: 1 }1 |
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {1:-- More -- SPACE/d/j: screen/page/line down, b/u/k: up, q: quit }^ |
+ ]])
+
+ -- Down a line with j, <CR>, <NL> or <Down>.
+ feed('j')
+ screen:expect([[
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {2: 6 }6 |
+ {1:-- More --}^ |
+ ]])
+ feed('<NL>')
+ screen:expect([[
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {2: 6 }6 |
+ {2: 7 }7 |
+ {1:-- More --}^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {2: 6 }6 |
+ {2: 7 }7 |
+ {2: 8 }8 |
+ {1:-- More --}^ |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ {2: 5 }5 |
+ {2: 6 }6 |
+ {2: 7 }7 |
+ {2: 8 }8 |
+ {2: 9 }9 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Down a screen with <Space>, f, or <PageDown>.
+ feed('f')
+ screen:expect([[
+ {2: 10 }10 |
+ {2: 11 }11 |
+ {2: 12 }12 |
+ {2: 13 }13 |
+ {2: 14 }14 |
+ {1:-- More --}^ |
+ ]])
+ feed('<Space>')
+ screen:expect([[
+ {2: 15 }15 |
+ {2: 16 }16 |
+ {2: 17 }17 |
+ {2: 18 }18 |
+ {2: 19 }19 |
+ {1:-- More --}^ |
+ ]])
+ feed('<PageDown>')
+ screen:expect([[
+ {2: 20 }20 |
+ {2: 21 }21 |
+ {2: 22 }22 |
+ {2: 23 }23 |
+ {2: 24 }24 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Down a page (half a screen) with d.
+ feed('d')
+ screen:expect([[
+ {2: 23 }23 |
+ {2: 24 }24 |
+ {2: 25 }25 |
+ {2: 26 }26 |
+ {2: 27 }27 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Down all the way with 'G'.
+ feed('G')
+ screen:expect([[
+ {2: 96 }96 |
+ {2: 97 }97 |
+ {2: 98 }98 |
+ {2: 99 }99 |
+ {2:100 }100 |
+ {1:Press ENTER or type command to continue}^ |
+ ]])
+
+ -- Up a line k, <BS> or <Up>.
+ feed('k')
+ screen:expect([[
+ {2: 95 }95 |
+ {2: 96 }96 |
+ {2: 97 }97 |
+ {2: 98 }98 |
+ {2: 99 }99 |
+ {1:-- More --}^ |
+ ]])
+ feed('<BS>')
+ screen:expect([[
+ {2: 94 }94 |
+ {2: 95 }95 |
+ {2: 96 }96 |
+ {2: 97 }97 |
+ {2: 98 }98 |
+ {1:-- More --}^ |
+ ]])
+ feed('<Up>')
+ screen:expect([[
+ {2: 93 }93 |
+ {2: 94 }94 |
+ {2: 95 }95 |
+ {2: 96 }96 |
+ {2: 97 }97 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Up a screen with b or <PageUp>.
+ feed('b')
+ screen:expect([[
+ {2: 88 }88 |
+ {2: 89 }89 |
+ {2: 90 }90 |
+ {2: 91 }91 |
+ {2: 92 }92 |
+ {1:-- More --}^ |
+ ]])
+ feed('<PageUp>')
+ screen:expect([[
+ {2: 83 }83 |
+ {2: 84 }84 |
+ {2: 85 }85 |
+ {2: 86 }86 |
+ {2: 87 }87 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Up a page (half a screen) with u.
+ feed('u')
+ screen:expect([[
+ {2: 80 }80 |
+ {2: 81 }81 |
+ {2: 82 }82 |
+ {2: 83 }83 |
+ {2: 84 }84 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Up all the way with 'g'.
+ feed('g')
+ screen:expect([[
+ {2: 1 }1 |
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {1:-- More --}^ |
+ ]])
+
+ -- All the way down. Pressing f should do nothing but pressing
+ -- space should end the more prompt.
+ feed('G')
+ screen:expect([[
+ {2: 96 }96 |
+ {2: 97 }97 |
+ {2: 98 }98 |
+ {2: 99 }99 |
+ {2:100 }100 |
+ {1:Press ENTER or type command to continue}^ |
+ ]])
+ feed('f')
+ screen:expect_unchanged()
+ feed('<Space>')
+ screen:expect([[
+ 96 |
+ 97 |
+ 98 |
+ 99 |
+ ^100 |
+ |
+ ]])
+
+ -- Pressing g< shows the previous command output.
+ feed('g<lt>')
+ screen:expect([[
+ {2: 96 }96 |
+ {2: 97 }97 |
+ {2: 98 }98 |
+ {2: 99 }99 |
+ {2:100 }100 |
+ {1:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed(':%p#\n')
+ screen:expect([[
+ {2: 1 }1 |
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {1:-- More --}^ |
+ ]])
+
+ -- Stop command output with q, <Esc> or CTRL-C.
+ feed('q')
+ screen:expect([[
+ 96 |
+ 97 |
+ 98 |
+ 99 |
+ ^100 |
+ |
+ ]])
+
+ -- Execute a : command from the more prompt
+ feed(':%p#\n')
+ screen:expect([[
+ {2: 1 }1 |
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ {1:-- More --}^ |
+ ]])
+ feed(':')
+ screen:expect([[
+ {2: 1 }1 |
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ :^ |
+ ]])
+ feed("echo 'Hello'\n")
+ screen:expect([[
+ {2: 2 }2 |
+ {2: 3 }3 |
+ {2: 4 }4 |
+ {2: 5 }5 |
+ Hello |
+ {1:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ -- oldtest: Test_quit_long_message()
+ it('with control characters can be quit vim-patch:8.2.1844', function()
+ screen:try_resize(40, 6)
+ feed([[:echom range(9999)->join("\x01")<CR>]])
+ screen:expect([[
+ 0{3:^A}1{3:^A}2{3:^A}3{3:^A}4{3:^A}5{3:^A}6{3:^A}7{3:^A}8{3:^A}9{3:^A}10{3:^A}11{3:^A}12|
+ {3:^A}13{3:^A}14{3:^A}15{3:^A}16{3:^A}17{3:^A}18{3:^A}19{3:^A}20{3:^A}21{3:^A}22|
+ {3:^A}23{3:^A}24{3:^A}25{3:^A}26{3:^A}27{3:^A}28{3:^A}29{3:^A}30{3:^A}31{3:^A}32|
+ {3:^A}33{3:^A}34{3:^A}35{3:^A}36{3:^A}37{3:^A}38{3:^A}39{3:^A}40{3:^A}41{3:^A}42|
+ {3:^A}43{3:^A}44{3:^A}45{3:^A}46{3:^A}47{3:^A}48{3:^A}49{3:^A}50{3:^A}51{3:^A}52|
+ {1:-- More --}^ |
+ ]])
+ feed('q')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+ end)
+
+ -- oldtest: Test_ask_yesno()
+ it('y/n prompt works', function()
+ screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ [2] = {bold = true, reverse = true}, -- MsgSeparator
+ })
+ screen:attach()
+ command('set noincsearch nohlsearch inccommand=')
+ command('call setline(1, range(1, 2))')
+
+ feed(':2,1s/^/n/\n')
+ screen:expect([[
+ 1 |
+ 2 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:Backwards range given, OK to swap (y/n)?}^ |
+ ]])
+ feed('n')
+ screen:expect([[
+ ^1 |
+ 2 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:Backwards range given, OK to swap (y/n)?}n |
+ ]])
+
+ feed(':2,1s/^/Esc/\n')
+ screen:expect([[
+ 1 |
+ 2 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:Backwards range given, OK to swap (y/n)?}^ |
+ ]])
+ feed('<Esc>')
+ screen:expect([[
+ ^1 |
+ 2 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:Backwards range given, OK to swap (y/n)?}n |
+ ]])
+
+ feed(':2,1s/^/y/\n')
+ screen:expect([[
+ 1 |
+ 2 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:Backwards range given, OK to swap (y/n)?}^ |
+ ]])
+ feed('y')
+ screen:expect([[
+ y1 |
+ ^y2 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {1:Backwards range given, OK to swap (y/n)?}y |
+ ]])
+ end)
+
+ -- oldtest: Test_fileinfo_after_echo()
+ it('fileinfo does not overwrite echo message vim-patch:8.2.4156', function()
+ screen = Screen.new(40, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ set shortmess-=F
+
+ file a.txt
+
+ hide edit b.txt
+ call setline(1, "hi")
+ setlocal modified
+
+ hide buffer a.txt
+
+ autocmd CursorHold * buf b.txt | w | echo "'b' written"
+ ]])
+ command('set updatetime=50')
+ feed('0$')
+ screen:expect([[
+ ^hi |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ 'b' written |
+ ]])
+ os.remove('b.txt')
+ end)
+end)
diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua
deleted file mode 100644
index 4f9f5a0237..0000000000
--- a/test/functional/legacy/packadd_spec.lua
+++ /dev/null
@@ -1,507 +0,0 @@
--- Tests for 'packpath' and :packadd
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear, source, command = helpers.clear, helpers.source, helpers.command
-local call, eq, nvim = helpers.call, helpers.eq, helpers.meths
-local feed = helpers.feed
-
-local function expected_empty()
- eq({}, nvim.get_vvar('errors'))
-end
-
-describe('packadd', function()
- before_each(function()
- clear()
-
- source([=[
- func Escape(s)
- return escape(a:s, '\~')
- endfunc
-
- func SetUp()
- let s:topdir = expand(getcwd() . '/Xdir')
- if isdirectory(s:topdir)
- call delete(s:topdir, 'rf')
- endif
- exe 'set packpath=' . s:topdir
- let s:plugdir = expand(s:topdir . '/pack/mine/opt/mytest')
- endfunc
-
- func TearDown()
- call delete(s:topdir, 'rf')
- endfunc
-
- func Test_packadd()
- if !exists('s:plugdir')
- echomsg 'when running this test manually, call SetUp() first'
- return
- endif
-
- call mkdir(s:plugdir . '/plugin/also', 'p')
- call mkdir(s:plugdir . '/ftdetect', 'p')
- call mkdir(s:plugdir . '/after', 'p')
- set rtp&
- let rtp = &rtp
- filetype on
-
- let rtp_entries = split(rtp, ',')
- for entry in rtp_entries
- if entry =~? '\<after\>'
- let first_after_entry = entry
- break
- endif
- endfor
-
- exe 'split ' . s:plugdir . '/plugin/test.vim'
- call setline(1, 'let g:plugin_works = 42')
- wq
-
- exe 'split ' . s:plugdir . '/plugin/also/loaded.vim'
- call setline(1, 'let g:plugin_also_works = 77')
- wq
-
- exe 'split ' . s:plugdir . '/ftdetect/test.vim'
- call setline(1, 'let g:ftdetect_works = 17')
- wq
-
- packadd mytest
-
- call assert_true(42, g:plugin_works)
- call assert_equal(77, g:plugin_also_works)
- call assert_true(17, g:ftdetect_works)
- call assert_true(len(&rtp) > len(rtp))
- call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp)
-
- let new_after = match(&rtp, Escape(expand(s:plugdir . '/after') . ','))
- let forwarded = substitute(first_after_entry, '\\', '[/\\\\]', 'g')
- let old_after = match(&rtp, ',' . escape(forwarded, '~') . '\>')
- call assert_true(new_after > 0, 'rtp is ' . &rtp)
- call assert_true(old_after > 0, 'match ' . forwarded . ' in ' . &rtp)
- call assert_true(new_after < old_after, 'rtp is ' . &rtp)
-
- " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest'
- call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p')
- let rtp = &rtp
- packadd myte
-
- " Check the path of 'myte' is added
- call assert_true(len(&rtp) > len(rtp))
- call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp)
-
- " Check exception
- call assert_fails("packadd directorynotfound", 'E919:')
- call assert_fails("packadd", 'E471:')
- endfunc
-
- func Test_packadd_start()
- let plugdir = expand(s:topdir . '/pack/mine/start/other')
- call mkdir(plugdir . '/plugin', 'p')
- set rtp&
- let rtp = &rtp
- filetype on
-
- exe 'split ' . plugdir . '/plugin/test.vim'
- call setline(1, 'let g:plugin_works = 24')
- wq
-
- exe 'split ' . plugdir . '/plugin/test.lua'
- call setline(1, 'vim.g.plugin_lua_works = 24')
- wq
-
- packadd other
-
- call assert_equal(24, g:plugin_works)
- call assert_equal(24, g:plugin_lua_works)
- call assert_true(len(&rtp) > len(rtp))
- call assert_match(Escape(plugdir) . '\($\|,\)', &rtp)
- endfunc
-
- func Test_packadd_noload()
- call mkdir(s:plugdir . '/plugin', 'p')
- call mkdir(s:plugdir . '/syntax', 'p')
- set rtp&
- let rtp = &rtp
-
- exe 'split ' . s:plugdir . '/plugin/test.vim'
- call setline(1, 'let g:plugin_works = 42')
- wq
- exe 'split ' . s:plugdir . '/plugin/test.lua'
- call setline(1, 'let g:plugin_lua_works = 42')
- wq
- let g:plugin_works = 0
- let g:plugin_lua_works = 0
-
- packadd! mytest
-
- call assert_true(len(&rtp) > len(rtp))
- call assert_match(Escape(s:plugdir) . '\($\|,\)', &rtp)
- call assert_equal(0, g:plugin_works)
- call assert_equal(0, g:plugin_lua_works)
-
- " check the path is not added twice
- let new_rtp = &rtp
- packadd! mytest
- call assert_equal(new_rtp, &rtp)
- endfunc
-
- func Test_packadd_symlink_dir()
- let top2_dir = expand(s:topdir . '/Xdir2')
- let real_dir = expand(s:topdir . '/Xsym')
- call mkdir(real_dir, 'p')
- if has('win32')
- exec "silent! !mklink /d" top2_dir "Xsym"
- else
- exec "silent! !ln -s Xsym" top2_dir
- endif
- let &rtp = top2_dir . ',' . expand(top2_dir . '/after')
- let &packpath = &rtp
-
- let s:plugdir = expand(top2_dir . '/pack/mine/opt/mytest')
- call mkdir(s:plugdir . '/plugin', 'p')
-
- exe 'split ' . s:plugdir . '/plugin/test.vim'
- call setline(1, 'let g:plugin_works = 44')
- wq
- let g:plugin_works = 0
-
- packadd mytest
-
- " Must have been inserted in the middle, not at the end
- call assert_match(Escape(expand('/pack/mine/opt/mytest').','), &rtp)
- call assert_equal(44, g:plugin_works)
-
- " No change when doing it again.
- let rtp_before = &rtp
- packadd mytest
- call assert_equal(rtp_before, &rtp)
-
- set rtp&
- let rtp = &rtp
- exec "silent !" (has('win32') ? "rd /q/s" : "rm") top2_dir
- endfunc
-
- func Test_packadd_symlink_dir2()
- let top2_dir = expand(s:topdir . '/Xdir2')
- let real_dir = expand(s:topdir . '/Xsym/pack')
- call mkdir(top2_dir, 'p')
- call mkdir(real_dir, 'p')
- let &rtp = top2_dir . ',' . top2_dir . '/after'
- let &packpath = &rtp
-
- if has('win32')
- exec "silent! !mklink /d" top2_dir "Xsym"
- else
- exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack'
- endif
- let s:plugdir = expand(top2_dir . '/pack/mine/opt/mytest')
- call mkdir(s:plugdir . '/plugin', 'p')
-
- exe 'split ' . s:plugdir . '/plugin/test.vim'
- call setline(1, 'let g:plugin_works = 48')
- wq
- let g:plugin_works = 0
-
- packadd mytest
-
- " Must have been inserted in the middle, not at the end
- call assert_match(Escape(expand('/Xdir2/pack/mine/opt/mytest').','), &rtp)
- call assert_equal(48, g:plugin_works)
-
- " No change when doing it again.
- let rtp_before = &rtp
- packadd mytest
- call assert_equal(rtp_before, &rtp)
-
- set rtp&
- let rtp = &rtp
- if has('win32')
- exec "silent !rd /q/s" top2_dir
- else
- exec "silent !rm" top2_dir . '/pack'
- exec "silent !rmdir" top2_dir
- endif
- endfunc
-
- func Test_packloadall()
- " plugin foo with an autoload directory
- let fooplugindir = &packpath . '/pack/mine/start/foo/plugin'
- call mkdir(fooplugindir, 'p')
- call writefile(['let g:plugin_foo_number = 1234',
- \ 'let g:plugin_foo_auto = bbb#value',
- \ 'let g:plugin_extra_auto = extra#value'], fooplugindir . '/bar.vim')
- let fooautodir = &packpath . '/pack/mine/start/foo/autoload'
- call mkdir(fooautodir, 'p')
- call writefile(['let bar#value = 77'], fooautodir . '/bar.vim')
-
- " plugin aaa with an autoload directory
- let aaaplugindir = &packpath . '/pack/mine/start/aaa/plugin'
- call mkdir(aaaplugindir, 'p')
- call writefile(['let g:plugin_aaa_number = 333',
- \ 'let g:plugin_aaa_auto = bar#value'], aaaplugindir . '/bbb.vim')
- let aaaautodir = &packpath . '/pack/mine/start/aaa/autoload'
- call mkdir(aaaautodir, 'p')
- call writefile(['let bbb#value = 55'], aaaautodir . '/bbb.vim')
-
- " plugin extra with only an autoload directory
- let extraautodir = &packpath . '/pack/mine/start/extra/autoload'
- call mkdir(extraautodir, 'p')
- call writefile(['let extra#value = 99'], extraautodir . '/extra.vim')
-
- packloadall
- call assert_equal(1234, g:plugin_foo_number)
- call assert_equal(55, g:plugin_foo_auto)
- call assert_equal(99, g:plugin_extra_auto)
- call assert_equal(333, g:plugin_aaa_number)
- call assert_equal(77, g:plugin_aaa_auto)
-
- " only works once
- call writefile(['let g:plugin_bar_number = 4321'],
- \ fooplugindir . '/bar2.vim')
- packloadall
- call assert_false(exists('g:plugin_bar_number'))
-
- " works when ! used
- packloadall!
- call assert_equal(4321, g:plugin_bar_number)
- endfunc
-
- func Test_helptags()
- let docdir1 = &packpath . '/pack/mine/start/foo/doc'
- let docdir2 = &packpath . '/pack/mine/start/bar/doc'
- call mkdir(docdir1, 'p')
- call mkdir(docdir2, 'p')
- call writefile(['look here: *look-here*'], docdir1 . '/bar.txt')
- call writefile(['look away: *look-away*'], docdir2 . '/foo.txt')
- exe 'set rtp=' . &packpath . '/pack/mine/start/foo,' . &packpath . '/pack/mine/start/bar'
-
- helptags ALL
-
- let tags1 = readfile(docdir1 . '/tags')
- call assert_match('look-here', tags1[0])
- let tags2 = readfile(docdir2 . '/tags')
- call assert_match('look-away', tags2[0])
-
- call assert_fails('helptags abcxyz', 'E150:')
- endfunc
-
- func Test_colorscheme()
- let colordirrun = &packpath . '/runtime/colors'
- let colordirstart = &packpath . '/pack/mine/start/foo/colors'
- let colordiropt = &packpath . '/pack/mine/opt/bar/colors'
- call mkdir(colordirrun, 'p')
- call mkdir(colordirstart, 'p')
- call mkdir(colordiropt, 'p')
- call writefile(['let g:found_one = 1'], colordirrun . '/one.vim')
- call writefile(['let g:found_two = 1'], colordirstart . '/two.vim')
- call writefile(['let g:found_three = 1'], colordiropt . '/three.vim')
- exe 'set rtp=' . &packpath . '/runtime'
-
- colorscheme one
- call assert_equal(1, g:found_one)
- colorscheme two
- call assert_equal(1, g:found_two)
- colorscheme three
- call assert_equal(1, g:found_three)
- endfunc
-
- func Test_runtime()
- let rundir = &packpath . '/runtime/extra'
- let startdir = &packpath . '/pack/mine/start/foo/extra'
- let optdir = &packpath . '/pack/mine/opt/bar/extra'
- call mkdir(rundir, 'p')
- call mkdir(startdir, 'p')
- call mkdir(optdir, 'p')
- call writefile(['let g:sequence .= "run"'], rundir . '/bar.vim')
- call writefile(['let g:sequence .= "start"'], startdir . '/bar.vim')
- call writefile(['let g:sequence .= "foostart"'], startdir . '/foo.vim')
- call writefile(['let g:sequence .= "opt"'], optdir . '/bar.vim')
- call writefile(['let g:sequence .= "xxxopt"'], optdir . '/xxx.vim')
- exe 'set rtp=' . &packpath . '/runtime'
-
- let g:sequence = ''
- runtime extra/bar.vim
- call assert_equal('run', g:sequence)
- let g:sequence = ''
- runtime START extra/bar.vim
- call assert_equal('start', g:sequence)
- let g:sequence = ''
- runtime OPT extra/bar.vim
- call assert_equal('opt', g:sequence)
- let g:sequence = ''
- runtime PACK extra/bar.vim
- call assert_equal('start', g:sequence)
- let g:sequence = ''
- runtime! PACK extra/bar.vim
- call assert_equal('startopt', g:sequence)
- let g:sequence = ''
- runtime PACK extra/xxx.vim
- call assert_equal('xxxopt', g:sequence)
-
- let g:sequence = ''
- runtime ALL extra/bar.vim
- call assert_equal('run', g:sequence)
- let g:sequence = ''
- runtime ALL extra/foo.vim
- call assert_equal('foostart', g:sequence)
- let g:sequence = ''
- runtime! ALL extra/xxx.vim
- call assert_equal('xxxopt', g:sequence)
- let g:sequence = ''
- runtime! ALL extra/bar.vim
- call assert_equal('runstartopt', g:sequence)
- endfunc
- ]=])
- call('SetUp')
- end)
-
- after_each(function()
- call('TearDown')
- end)
-
- it('is working', function()
- call('Test_packadd')
- expected_empty()
- end)
-
- it('works with packadd!', function()
- call('Test_packadd_noload')
- expected_empty()
- end)
-
- it('works with symlinks', function()
- call('Test_packadd_symlink_dir')
- expected_empty()
- end)
-
- it('works with :packloadall', function()
- call('Test_packloadall')
- expected_empty()
- end)
-
- it('works with helptags', function()
- call('Test_helptags')
- expected_empty()
- end)
-
- it('works with colorschemes', function()
- call('Test_colorscheme')
- expected_empty()
- end)
-
- it('works with :runtime [what]', function()
- call('Test_runtime')
- expected_empty()
- end)
-
- it('loads packages from "start" directory', function()
- call('Test_packadd_start')
- expected_empty()
- end)
-
- describe('command line completion', function()
- local Screen = require('test.functional.ui.screen')
- local screen
-
- before_each(function()
- screen = Screen.new(30, 5)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- [1] = {
- foreground = Screen.colors.Black,
- background = Screen.colors.Yellow,
- },
- [2] = {bold = true, reverse = true}
- })
-
- command([[let optdir1 = &packpath . '/pack/mine/opt']])
- command([[let optdir2 = &packpath . '/pack/candidate/opt']])
- command([[call mkdir(optdir1 . '/pluginA', 'p')]])
- command([[call mkdir(optdir1 . '/pluginC', 'p')]])
- command([[call mkdir(optdir2 . '/pluginB', 'p')]])
- command([[call mkdir(optdir2 . '/pluginC', 'p')]])
- end)
-
- it('works', function()
- feed(':packadd <Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {1:pluginA}{2: pluginB pluginC }|
- :packadd pluginA^ |
- ]=])
- feed('<Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {2:pluginA }{1:pluginB}{2: pluginC }|
- :packadd pluginB^ |
- ]=])
- feed('<Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {2:pluginA pluginB }{1:pluginC}{2: }|
- :packadd pluginC^ |
- ]=])
- feed('<Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {2:pluginA pluginB pluginC }|
- :packadd ^ |
- ]=])
- end)
-
- it('works for colorschemes', function()
- source([[
- let colordirrun = &packpath . '/runtime/colors'
- let colordirstart = &packpath . '/pack/mine/start/foo/colors'
- let colordiropt = &packpath . '/pack/mine/opt/bar/colors'
- call mkdir(colordirrun, 'p')
- call mkdir(colordirstart, 'p')
- call mkdir(colordiropt, 'p')
- call writefile(['let g:found_one = 1'], colordirrun . '/one.vim')
- call writefile(['let g:found_two = 1'], colordirstart . '/two.vim')
- call writefile(['let g:found_three = 1'], colordiropt . '/three.vim')
- exe 'set rtp=' . &packpath . '/runtime']])
-
- feed(':colorscheme <Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {1:one}{2: three two }|
- :colorscheme one^ |
- ]=])
- feed('<Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {2:one }{1:three}{2: two }|
- :colorscheme three^ |
- ]=])
- feed('<Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {2:one three }{1:two}{2: }|
- :colorscheme two^ |
- ]=])
- feed('<Tab>')
- screen:expect([=[
- |
- {0:~ }|
- {0:~ }|
- {2:one three two }|
- :colorscheme ^ |
- ]=])
- end)
- end)
-end)
diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua
index 47eca19de3..63338b8dba 100644
--- a/test/functional/legacy/prompt_buffer_spec.lua
+++ b/test/functional/legacy/prompt_buffer_spec.lua
@@ -23,7 +23,7 @@ describe('prompt buffer', function()
close
else
call append(line("$") - 1, 'Command: "' . a:text . '"')
- set nomodfied
+ set nomodified
call timer_start(20, {id -> TimerFunc(a:text)})
endif
endfunc
@@ -33,7 +33,7 @@ describe('prompt buffer', function()
endfunc
func SwitchWindows()
- call timer_start(0, {-> execute("wincmd p|wincmd p", "")})
+ call timer_start(0, {-> execute("wincmd p", "")})
endfunc
]])
feed_command("set noshowmode | set laststatus=0")
@@ -187,7 +187,19 @@ describe('prompt buffer', function()
-- INSERT -- |
]])
feed("<C-O>:call SwitchWindows()<CR>")
- poke_eventloop()
+ screen:expect{grid=[[
+ cmd: |
+ ~ |
+ ~ |
+ ~ |
+ [Prompt] [+] |
+ ^other buffer |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]]}
+ feed("<C-O>:call SwitchWindows()<CR>")
screen:expect([[
cmd: ^ |
~ |
@@ -201,7 +213,6 @@ describe('prompt buffer', function()
-- INSERT -- |
]])
feed("<Esc>")
- poke_eventloop()
screen:expect([[
cmd:^ |
~ |
diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua
new file mode 100644
index 0000000000..3ddf65490e
--- /dev/null
+++ b/test/functional/legacy/put_spec.lua
@@ -0,0 +1,45 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local meths = helpers.meths
+local source = helpers.source
+local eq = helpers.eq
+
+local function sizeoflong()
+ if not exec_lua('return pcall(require, "ffi")') then
+ pending('missing LuaJIT FFI')
+ end
+ return exec_lua('return require("ffi").sizeof(require("ffi").typeof("long"))')
+end
+
+describe('put', function()
+ before_each(clear)
+ after_each(function() eq({}, meths.get_vvar('errors')) end)
+
+ it('very large count 64-bit', function()
+ if sizeoflong() < 8 then
+ pending('Skipped: only works with 64 bit long ints')
+ end
+
+ source [[
+ new
+ let @" = repeat('x', 100)
+ call assert_fails('norm 999999999p', 'E1240:')
+ bwipe!
+ ]]
+ end)
+
+ it('very large count (visual block) 64-bit', function()
+ if sizeoflong() < 8 then
+ pending('Skipped: only works with 64 bit long ints')
+ end
+
+ source [[
+ new
+ call setline(1, repeat('x', 100))
+ exe "norm \<C-V>$y"
+ call assert_fails('norm 999999999p', 'E1240:')
+ bwipe!
+ ]]
+ end)
+end)
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index 4ed08881de..67991f5d48 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -7,6 +7,7 @@ local eval = helpers.eval
local feed = helpers.feed
local funcs = helpers.funcs
local poke_eventloop = helpers.poke_eventloop
+local exec = helpers.exec
describe('search cmdline', function()
local screen
@@ -640,3 +641,34 @@ describe('search cmdline', function()
feed('<esc>')
end)
end)
+
+describe('Search highlight', function()
+ before_each(clear)
+ it('Search highlight is combined with Visual highlight vim-patch:8.2.2797', function()
+ local screen = Screen.new(40, 6)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {bold = true}, -- ModeMsg, Search
+ [3] = {background = Screen.colors.LightGrey}, -- Visual
+ [4] = {background = Screen.colors.Yellow, bold = true}, -- Search
+ [5] = {background = Screen.colors.LightGrey, bold = true}, -- Visual + Search
+ })
+ screen:attach()
+ exec([[
+ set hlsearch noincsearch
+ call setline(1, repeat(["xxx yyy zzz"], 3))
+ hi Search gui=bold
+ /yyy
+ call cursor(1, 6)
+ ]])
+ feed('vjj')
+ screen:expect([[
+ xxx {4:y}{5:yy}{3: zzz} |
+ {3:xxx }{5:yyy}{3: zzz} |
+ {3:xxx }{5:y}{4:^yy} zzz |
+ {1:~ }|
+ {1:~ }|
+ {2:-- VISUAL --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/search_stat_spec.lua b/test/functional/legacy/search_stat_spec.lua
new file mode 100644
index 0000000000..c2ca393a56
--- /dev/null
+++ b/test/functional/legacy/search_stat_spec.lua
@@ -0,0 +1,184 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, feed, exec, command = helpers.clear, helpers.feed, helpers.exec, helpers.command
+local poke_eventloop = helpers.poke_eventloop
+
+describe('search stat', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(30, 10)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {background = Screen.colors.Yellow}, -- Search
+ [3] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded
+ [4] = {reverse = true}, -- IncSearch, TabLineFill
+ })
+ screen:attach()
+ end)
+
+ it('right spacing with silent mapping vim-patch:8.1.1970', function()
+ exec([[
+ set shortmess-=S
+ " Append 50 lines with text to search for, "foobar" appears 20 times
+ call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 20))
+ call setline(2, 'find this')
+ call setline(70, 'find this')
+ nnoremap n n
+ let @/ = 'find this'
+ call cursor(1,1)
+ norm n
+ ]])
+ screen:expect([[
+ foobar |
+ {2:^find this} |
+ fooooobar |
+ foba |
+ foobar |
+ foobar |
+ foo |
+ fooooobar |
+ foba |
+ /find this [1/2] |
+ ]])
+ command('nnoremap <silent> n n')
+ feed('gg0n')
+ screen:expect([[
+ foobar |
+ {2:^find this} |
+ fooooobar |
+ foba |
+ foobar |
+ foobar |
+ foo |
+ fooooobar |
+ foba |
+ [1/2] |
+ ]])
+ end)
+
+ it('when only match is in fold vim-patch:8.2.0840', function()
+ exec([[
+ set shortmess-=S
+ setl foldenable foldmethod=indent foldopen-=search
+ call append(0, ['if', "\tfoo", "\tfoo", 'endif'])
+ let @/ = 'foo'
+ call cursor(1,1)
+ norm n
+ ]])
+ screen:expect([[
+ if |
+ {3:^+-- 2 lines: foo·············}|
+ endif |
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /foo [1/2] |
+ ]])
+ feed('n')
+ poke_eventloop()
+ screen:expect_unchanged()
+ feed('n')
+ poke_eventloop()
+ screen:expect_unchanged()
+ end)
+
+ it('is cleared by gd and gD vim-patch:8.2.3583', function()
+ exec([[
+ call setline(1, ['int cat;', 'int dog;', 'cat = dog;'])
+ set shortmess-=S
+ set hlsearch
+ ]])
+ feed('/dog<CR>')
+ screen:expect([[
+ int cat; |
+ int {2:^dog}; |
+ cat = {2:dog}; |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /dog [1/2] |
+ ]])
+ feed('G0gD')
+ screen:expect([[
+ int {2:^cat}; |
+ int dog; |
+ {2:cat} = dog; |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('is not broken by calling searchcount() in tabline vim-patch:8.2.4378', function()
+ exec([[
+ call setline(1, ['abc--c', '--------abc', '--abc'])
+ set hlsearch
+ set incsearch
+ set showtabline=2
+
+ function MyTabLine()
+ try
+ let a=searchcount(#{recompute: 1, maxcount: -1})
+ return a.current .. '/' .. a.total
+ catch
+ return ''
+ endtry
+ endfunction
+
+ set tabline=%!MyTabLine()
+ ]])
+
+ feed('/abc')
+ screen:expect([[
+ {4: }|
+ {2:abc}--c |
+ --------{4:abc} |
+ --{2:abc} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /abc^ |
+ ]])
+
+ feed('<C-G>')
+ screen:expect([[
+ {4:3/3 }|
+ {2:abc}--c |
+ --------{2:abc} |
+ --{4:abc} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /abc^ |
+ ]])
+
+ feed('<C-G>')
+ screen:expect([[
+ {4:1/3 }|
+ {4:abc}--c |
+ --------{2:abc} |
+ --{2:abc} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ /abc^ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/searchpos_spec.lua b/test/functional/legacy/searchpos_spec.lua
deleted file mode 100644
index fc18341c38..0000000000
--- a/test/functional/legacy/searchpos_spec.lua
+++ /dev/null
@@ -1,35 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local call = helpers.call
-local clear = helpers.clear
-local command = helpers.command
-local eq = helpers.eq
-local eval = helpers.eval
-local insert = helpers.insert
-
-describe('searchpos', function()
- before_each(clear)
-
- it('is working', function()
- insert([[
- 1a3
- 123xyz]])
-
- call('cursor', 1, 1)
- eq({1, 1, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
- call('cursor', 1, 2)
- eq({2, 1, 1}, eval([['\%(\([a-z]\)\|\_.\)\{-}xyz'->searchpos('pcW')]]))
-
- command('set cpo-=c')
- call('cursor', 1, 2)
- eq({1, 2, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
- call('cursor', 1, 3)
- eq({1, 3, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW')]]))
-
- -- Now with \zs, first match is in column 0, "a" is matched.
- call('cursor', 1, 3)
- eq({2, 4, 2}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcW')]]))
- -- With z flag start at cursor column, don't see the "a".
- call('cursor', 1, 3)
- eq({2, 4, 1}, eval([[searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcWz')]]))
- end)
-end)
diff --git a/test/functional/legacy/set_spec.lua b/test/functional/legacy/set_spec.lua
deleted file mode 100644
index deb268b1e8..0000000000
--- a/test/functional/legacy/set_spec.lua
+++ /dev/null
@@ -1,30 +0,0 @@
--- Tests for :set
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear, command, eval, eq =
- helpers.clear, helpers.command, helpers.eval, helpers.eq
-
-describe(':set', function()
- before_each(clear)
-
- it('handles backslash properly', function()
- command('set iskeyword=a,b,c')
- command('set iskeyword+=d')
- eq('a,b,c,d', eval('&iskeyword'))
-
- command([[set iskeyword+=\\,e]])
- eq([[a,b,c,d,\,e]], eval('&iskeyword'))
-
- command('set iskeyword-=e')
- eq([[a,b,c,d,\]], eval('&iskeyword'))
-
- command([[set iskeyword-=\]])
- eq('a,b,c,d', eval('&iskeyword'))
- end)
-
- it('recognizes a trailing comma with +=', function()
- command('set wildignore=*.png,')
- command('set wildignore+=*.jpg')
- eq('*.png,*.jpg', eval('&wildignore'))
- end)
-end)
diff --git a/test/functional/legacy/statusline_spec.lua b/test/functional/legacy/statusline_spec.lua
new file mode 100644
index 0000000000..e2b30a7c82
--- /dev/null
+++ b/test/functional/legacy/statusline_spec.lua
@@ -0,0 +1,71 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('statusline', function()
+ local screen
+
+ before_each(function()
+ screen = Screen.new(50, 7)
+ screen:attach()
+ end)
+
+ it('is updated in cmdline mode when using window-local statusline vim-patch:8.2.2737', function()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {bold = true, reverse = true}, -- StatusLine
+ [3] = {reverse = true}, -- StatusLineNC
+ })
+ exec([[
+ setlocal statusline=-%{mode()}-
+ split
+ setlocal statusline=+%{mode()}+
+ ]])
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {2:+n+ }|
+ |
+ {1:~ }|
+ {3:-n- }|
+ |
+ ]])
+ feed(':')
+ screen:expect([[
+ |
+ {1:~ }|
+ {2:+c+ }|
+ |
+ {1:~ }|
+ {3:-c- }|
+ :^ |
+ ]])
+ end)
+
+ it('truncated item does not cause off-by-one highlight vim-patch:8.2.4929', function()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {foreground = Screen.colors.Blue}, -- User1
+ [3] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- User2
+ })
+ exec([[
+ set laststatus=2
+ hi! link User1 Directory
+ hi! link User2 ErrorMsg
+ set statusline=%.5(%1*ABC%2*DEF%1*GHI%)
+ ]])
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:<F}{2:GHI }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/utf8_spec.lua b/test/functional/legacy/utf8_spec.lua
index 8b5fc02d11..67a4bec4c5 100644
--- a/test/functional/legacy/utf8_spec.lua
+++ b/test/functional/legacy/utf8_spec.lua
@@ -28,7 +28,7 @@ describe('utf8', function()
expect([[
start:
axaa
- xあああ
+ xあああ
bxbb]])
end)
diff --git a/test/functional/legacy/visual_mode_spec.lua b/test/functional/legacy/visual_mode_spec.lua
index c8e83ed649..8b5dd0c2dc 100644
--- a/test/functional/legacy/visual_mode_spec.lua
+++ b/test/functional/legacy/visual_mode_spec.lua
@@ -1,5 +1,3 @@
--- Test visual line mode selection redraw after scrolling
-
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
@@ -10,6 +8,7 @@ local feed_command = helpers.feed_command
local funcs = helpers.funcs
local meths = helpers.meths
local eq = helpers.eq
+local exec = helpers.exec
describe('visual line mode', function()
local screen
@@ -40,3 +39,44 @@ describe('visual line mode', function()
]])
end)
end)
+
+describe('visual block mode', function()
+ it('shows selection correctly with virtualedit=block', function()
+ clear()
+ local screen = Screen.new(30, 7)
+ screen:set_default_attr_ids({
+ [1] = {bold = true}, -- ModeMsg
+ [2] = {background = Screen.colors.LightGrey}, -- Visual
+ [3] = {foreground = Screen.colors.Blue, bold = true} -- NonText
+ })
+ screen:attach()
+
+ exec([[
+ call setline(1, ['aaaaaa', 'bbbb', 'cc'])
+ set virtualedit=block
+ normal G
+ ]])
+
+ feed('<C-V>gg$')
+ screen:expect([[
+ {2:aaaaaa}^ |
+ {2:bbbb } |
+ {2:cc } |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL BLOCK --} |
+ ]])
+
+ feed('<Esc>gg<C-V>G$')
+ screen:expect([[
+ {2:aaaaaa } |
+ {2:bbbb } |
+ {2:cc}^ {2: } |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL BLOCK --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/wordcount_spec.lua b/test/functional/legacy/wordcount_spec.lua
index 826743b0ca..21f96628c0 100644
--- a/test/functional/legacy/wordcount_spec.lua
+++ b/test/functional/legacy/wordcount_spec.lua
@@ -50,44 +50,44 @@ describe('wordcount', function()
]=])
-- Test 1: empty window
- eq(eval('DoRecordWin()'),
- eval([=[
+ eq(eval([=[
[[''], {'chars': 0, 'cursor_chars': 0, 'words': 0, 'cursor_words': 0, 'bytes': 0, 'cursor_bytes': 0}]
- ]=])
+ ]=]),
+ eval('DoRecordWin()')
)
-- Test 2: some words, cursor at start
command([[call PutInWindow('one two three')]])
- eq(eval('DoRecordWin([1, 1, 0])'),
- eval([=[
+ eq(eval([=[
[['', 'one two three'], {'chars': 15, 'cursor_chars': 1, 'words': 3, 'cursor_words': 0, 'bytes': 15, 'cursor_bytes': 1}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([1, 1, 0])')
)
-- Test 3: some words, cursor at end
command([[call PutInWindow('one two three')]])
- eq(eval('DoRecordWin([2, 99, 0])'),
- eval([=[
+ eq(eval([=[
[['', 'one two three'], {'chars': 15, 'cursor_chars': 14, 'words': 3, 'cursor_words': 3, 'bytes': 15, 'cursor_bytes': 14}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([2, 99, 0])')
)
-- Test 4: some words, cursor at end, ve=all
command('set ve=all')
command([[call PutInWindow('one two three')]])
- eq(eval('DoRecordWin([2,99,0])'),
- eval([=[
+ eq(eval([=[
[['', 'one two three'], {'chars': 15, 'cursor_chars': 15, 'words': 3, 'cursor_words': 3, 'bytes': 15, 'cursor_bytes': 15}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([2,99,0])')
)
command('set ve=')
-- Test 5: several lines with words
command([=[call PutInWindow(['one two three', 'one two three', 'one two three'])]=])
- eq(eval('DoRecordWin([4,99,0])'),
- eval([=[
+ eq(eval([=[
[['', 'one two three', 'one two three', 'one two three'], {'chars': 43, 'cursor_chars': 42, 'words': 9, 'cursor_words': 9, 'bytes': 43, 'cursor_bytes': 42}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([4,99,0])')
)
-- Test 6: one line with BOM set
@@ -95,10 +95,10 @@ describe('wordcount', function()
command('wincmd k')
command('set bomb')
command('wincmd j')
- eq(eval('DoRecordWin([2,99,0])'),
- eval([=[
+ eq(eval([=[
[['', 'one two three'], {'chars': 15, 'cursor_chars': 14, 'words': 3, 'cursor_words': 3, 'bytes': 18, 'cursor_bytes': 14}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([2,99,0])')
)
command('wincmd k')
command('set nobomb')
@@ -106,18 +106,18 @@ describe('wordcount', function()
-- Test 7: one line with multibyte words
command([=[call PutInWindow(['Äne M¤ne Müh'])]=])
- eq(eval('DoRecordWin([2,99,0])'),
- eval([=[
+ eq(eval([=[
[['', 'Äne M¤ne Müh'], {'chars': 14, 'cursor_chars': 13, 'words': 3, 'cursor_words': 3, 'bytes': 17, 'cursor_bytes': 16}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([2,99,0])')
)
-- Test 8: several lines with multibyte words
command([=[call PutInWindow(['Äne M¤ne Müh', 'und raus bist dü!'])]=])
- eq(eval('DoRecordWin([3,99,0])'),
- eval([=[
+ eq(eval([=[
[['', 'Äne M¤ne Müh', 'und raus bist dü!'], {'chars': 32, 'cursor_chars': 31, 'words': 7, 'cursor_words': 7, 'bytes': 36, 'cursor_bytes': 35}]
- ]=])
+ ]=]),
+ eval('DoRecordWin([3,99,0])')
)
-- Test 9: visual mode, complete buffer
@@ -131,10 +131,10 @@ describe('wordcount', function()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
- eq(eval('log'),
- eval([=[
+ eq(eval([=[
[['', 'Äne M¤ne Müh', 'und raus bist dü!'], {'chars': 32, 'words': 7, 'bytes': 36, 'visual_chars': 32, 'visual_words': 7, 'visual_bytes': 36}]
- ]=])
+ ]=]),
+ eval('log')
)
-- Test 10: visual mode (empty)
@@ -148,10 +148,10 @@ describe('wordcount', function()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
- eq(eval('log'),
- eval([=[
+ eq(eval([=[
[['', 'Äne M¤ne Müh', 'und raus bist dü!'], {'chars': 32, 'words': 7, 'bytes': 36, 'visual_chars': 1, 'visual_words': 0, 'visual_bytes': 1}]
- ]=])
+ ]=]),
+ eval('log')
)
-- Test 11: visual mode, single line
@@ -165,10 +165,10 @@ describe('wordcount', function()
command('set stl= ls=1')
command('let log=DoRecordWin([3,99,0])')
command('let log[1]=g:visual_stat')
- eq(eval('log'),
- eval([=[
+ eq(eval([=[
[['', 'Äne M¤ne Müh', 'und raus bist dü!'], {'chars': 32, 'words': 7, 'bytes': 36, 'visual_chars': 13, 'visual_words': 3, 'visual_bytes': 16}]
- ]=])
+ ]=]),
+ eval('log')
)
end)
end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index cb37fb9a1c..f173a15d32 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -102,6 +102,13 @@ describe('luaeval(vim.api.…)', function()
eq(false, funcs.luaeval('vim.api.nvim__id(false)'))
eq(NIL, funcs.luaeval('vim.api.nvim__id(nil)'))
+ -- API strings from Blobs can work as NUL-terminated C strings
+ eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ',
+ exc_exec('call nvim_eval(v:_null_blob)'))
+ eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ',
+ exc_exec('call nvim_eval(0z)'))
+ eq(1, eval('nvim_eval(0z31)'))
+
eq(0, eval([[type(luaeval('vim.api.nvim__id(1)'))]]))
eq(1, eval([[type(luaeval('vim.api.nvim__id("1")'))]]))
eq(3, eval([[type(luaeval('vim.api.nvim__id({1})'))]]))
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index c83a50b78b..10de45274c 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -252,9 +252,8 @@ describe('lua buffer event callbacks: on_lines', function()
eq(2, meths.win_get_cursor(0)[1])
end)
- it('does not SEGFAULT when calling win_findbuf in on_detach', function()
-
- exec_lua[[
+ it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function()
+ local code = [[
local buf = vim.api.nvim_create_buf(false, false)
vim.cmd"split"
@@ -262,13 +261,19 @@ describe('lua buffer event callbacks: on_lines', function()
vim.api.nvim_buf_attach(buf, false, {
on_detach = function(_, buf)
+ vim.fn.tabpagebuflist()
vim.fn.win_findbuf(buf)
end
})
]]
+ exec_lua(code)
command("q!")
helpers.assert_alive()
+
+ exec_lua(code)
+ command("bd!")
+ helpers.assert_alive()
end)
it('#12718 lnume', function()
@@ -612,7 +617,15 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
feed("<esc>")
- -- replacing with escaped characters
+ -- replacing with expression register
+ feed([[:%s/b/\=5+5]])
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 };
+ }
+
+ feed("<esc>")
+ -- replacing with backslash
feed([[:%s/b/\\]])
check_events {
{ "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
@@ -620,8 +633,24 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
feed("<esc>")
- -- replacing with expression register
- feed([[:%s/b/\=5+5]])
+ -- replacing with backslash from expression register
+ feed([[:%s/b/\='\']])
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 };
+ }
+
+ feed("<esc>")
+ -- replacing with backslash followed by another character
+ feed([[:%s/b/\\!]])
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 };
+ { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 };
+ }
+
+ feed("<esc>")
+ -- replacing with backslash followed by another character from expression register
+ feed([[:%s/b/\='\!']])
check_events {
{ "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 };
{ "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 };
@@ -1104,6 +1133,15 @@ describe('lua: nvim_buf_attach on_bytes', function()
check_events { }
end)
+ it("works with accepting spell suggestions", function()
+ local check_events = setup_eventcheck(verify, {"hallo"})
+
+ feed("gg0z=4<cr><cr>") -- accepts 'Hello'
+ check_events {
+ { "test1", "bytes", 1, 3, 0, 0, 0, 0, 2, 2, 0, 2, 2 };
+ }
+ end)
+
local function test_lockmarks(mode)
local description = (mode ~= "") and mode or "(baseline)"
it("test_lockmarks " .. description .. " %delete _", function()
diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua
index 3ba7e1589f..3a5966755e 100644
--- a/test/functional/lua/command_line_completion_spec.lua
+++ b/test/functional/lua/command_line_completion_spec.lua
@@ -106,6 +106,14 @@ describe('nlua_expand_pat', function()
)
end)
+ it('should work with lazy submodules of "vim" global', function()
+ eq({{ 'inspect' }, 4 },
+ get_completions('vim.inspec'))
+
+ eq({{ 'set' }, 11 },
+ get_completions('vim.keymap.se'))
+ end)
+
it('should be able to interpolate globals', function()
eq(
{{
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index 7d260f2e29..f9647f5b6a 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -208,10 +208,10 @@ describe('vim.diagnostic', function()
eq(all_highlights, exec_lua [[
local ns_1_diags = {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 3),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ make_warning("Warning 1", 2, 1, 2, 3),
}
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
@@ -255,10 +255,10 @@ describe('vim.diagnostic', function()
eq({0, 2}, exec_lua [[
local ns_1_diags = {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 3),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ make_warning("Warning 1", 2, 1, 2, 3),
}
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
@@ -599,10 +599,10 @@ describe('vim.diagnostic', function()
eq(all_highlights, exec_lua [[
local ns_1_diags = {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 2, 1, 2, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 3),
}
local ns_2_diags = {
- make_warning("Warning 1", 2, 1, 2, 5),
+ make_warning("Warning 1", 2, 1, 2, 3),
}
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
@@ -729,6 +729,19 @@ describe('vim.diagnostic', function()
return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
]])
end)
+
+ it('works with diagnostics before the start of the line', function()
+ eq({4, 0}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 3, 9001, 3, 9001),
+ make_error('Diagnostic #2', 4, -1, 4, -1),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {1, 1})
+ vim.diagnostic.goto_next { float = false }
+ return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
+ ]])
+end)
end)
describe('get_prev_pos()', function()
@@ -787,7 +800,7 @@ describe('vim.diagnostic', function()
eq(2, exec_lua [[
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 3),
})
return #vim.diagnostic.get(diagnostic_bufnr)
@@ -798,9 +811,9 @@ describe('vim.diagnostic', function()
eq({2, 3, 2}, exec_lua [[
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 5),
- make_info("Ignored information", 1, 1, 2, 5),
- make_hint("Here's a hint", 1, 1, 2, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 3),
+ make_info("Ignored information", 1, 1, 2, 3),
+ make_hint("Here's a hint", 1, 1, 2, 3),
})
return {
@@ -820,8 +833,8 @@ describe('vim.diagnostic', function()
eq(1, exec_lua [[
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error("Error 1", 1, 1, 1, 5),
- make_warning("Warning on Server 1", 1, 1, 2, 5),
- make_info("Ignored information", 1, 1, 2, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 3),
+ make_info("Ignored information", 1, 1, 2, 3),
make_error("Error On Other Line", 2, 1, 1, 5),
})
@@ -1939,24 +1952,31 @@ describe('vim.diagnostic', function()
end)
it('triggers the autocommand when diagnostics are set', function()
- eq(1, exec_lua [[
+ eq(true, exec_lua [[
+ -- Set a different buffer as current to test that <abuf> is being set properly in
+ -- DiagnosticChanged callbacks
+ local tmp = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(tmp)
+
vim.g.diagnostic_autocmd_triggered = 0
- vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = 1')
+ vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")')
vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test")
vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
make_error('Diagnostic', 0, 0, 0, 0)
})
- return vim.g.diagnostic_autocmd_triggered
+ return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr
]])
end)
it('triggers the autocommand when diagnostics are cleared', function()
- eq(1, exec_lua [[
+ eq(true, exec_lua [[
+ local tmp = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_set_current_buf(tmp)
vim.g.diagnostic_autocmd_triggered = 0
- vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = 1')
+ vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")')
vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test")
vim.diagnostic.reset(diagnostic_ns, diagnostic_bufnr)
- return vim.g.diagnostic_autocmd_triggered
+ return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr
]])
end)
end)
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
index 1b2cb61cc2..be57b2db31 100644
--- a/test/functional/lua/filetype_spec.lua
+++ b/test/functional/lua/filetype_spec.lua
@@ -3,6 +3,7 @@ local exec_lua = helpers.exec_lua
local eq = helpers.eq
local clear = helpers.clear
local pathroot = helpers.pathroot
+local command = helpers.command
local root = pathroot()
@@ -23,8 +24,7 @@ describe('vim.filetype', function()
rs = 'radicalscript',
},
})
- vim.filetype.match('main.rs')
- return vim.bo.filetype
+ return vim.filetype.match({ filename = 'main.rs' })
]])
end)
@@ -38,8 +38,7 @@ describe('vim.filetype', function()
['main.rs'] = 'somethingelse',
},
})
- vim.filetype.match('main.rs')
- return vim.bo.filetype
+ return vim.filetype.match({ filename = 'main.rs' })
]])
end)
@@ -50,8 +49,7 @@ describe('vim.filetype', function()
['s_O_m_e_F_i_l_e'] = 'nim',
},
})
- vim.filetype.match('s_O_m_e_F_i_l_e')
- return vim.bo.filetype
+ return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' })
]])
eq('dosini', exec_lua([[
@@ -62,25 +60,26 @@ describe('vim.filetype', function()
[root .. '/.config/fun/config'] = 'dosini',
},
})
- vim.filetype.match(root .. '/.config/fun/config')
- return vim.bo.filetype
+ return vim.filetype.match({ filename = root .. '/.config/fun/config' })
]], root))
end)
it('works with patterns', function()
eq('markdown', exec_lua([[
local root = ...
+ vim.env.HOME = '/a-funky+home%dir'
vim.filetype.add({
pattern = {
- [root .. '/blog/.*%.txt'] = 'markdown',
+ ['~/blog/.*%.txt'] = 'markdown',
}
})
- vim.filetype.match(root .. '/blog/why_neovim_is_awesome.txt')
- return vim.bo.filetype
+ return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' })
]], root))
end)
it('works with functions', function()
+ command('new')
+ command('file relevant_to_me')
eq('foss', exec_lua [[
vim.filetype.add({
pattern = {
@@ -91,8 +90,7 @@ describe('vim.filetype', function()
end,
}
})
- vim.filetype.match('relevant_to_me')
- return vim.bo.filetype
+ return vim.filetype.match({ buf = 0 })
]])
end)
end)
diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua
new file mode 100644
index 0000000000..2bcc84db0f
--- /dev/null
+++ b/test/functional/lua/fs_spec.lua
@@ -0,0 +1,101 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local mkdir_p = helpers.mkdir_p
+local rmdir = helpers.rmdir
+local nvim_dir = helpers.nvim_dir
+local test_build_dir = helpers.test_build_dir
+local iswin = helpers.iswin
+local nvim_prog = helpers.nvim_prog
+
+local nvim_prog_basename = iswin() and 'nvim.exe' or 'nvim'
+
+before_each(clear)
+
+describe('vim.fs', function()
+ describe('parents()', function()
+ it('works', function()
+ local test_dir = nvim_dir .. '/test'
+ mkdir_p(test_dir)
+ local dirs = exec_lua([[
+ local test_dir, test_build_dir = ...
+ local dirs = {}
+ for dir in vim.fs.parents(test_dir .. "/foo.txt") do
+ dirs[#dirs + 1] = dir
+ if dir == test_build_dir then
+ break
+ end
+ end
+ return dirs
+ ]], test_dir, test_build_dir)
+ eq({test_dir, nvim_dir, test_build_dir}, dirs)
+ rmdir(test_dir)
+ end)
+ end)
+
+ describe('dirname()', function()
+ it('works', function()
+ eq(test_build_dir, exec_lua([[
+ local nvim_dir = ...
+ return vim.fs.dirname(nvim_dir)
+ ]], nvim_dir))
+ end)
+ end)
+
+ describe('basename()', function()
+ it('works', function()
+ eq(nvim_prog_basename, exec_lua([[
+ local nvim_prog = ...
+ return vim.fs.basename(nvim_prog)
+ ]], nvim_prog))
+ end)
+ end)
+
+ describe('dir()', function()
+ it('works', function()
+ eq(true, exec_lua([[
+ local dir, nvim = ...
+ for name, type in vim.fs.dir(dir) do
+ if name == nvim and type == 'file' then
+ return true
+ end
+ end
+ return false
+ ]], nvim_dir, nvim_prog_basename))
+ end)
+ end)
+
+ describe('find()', function()
+ it('works', function()
+ eq({test_build_dir}, exec_lua([[
+ local dir = ...
+ return vim.fs.find('build', { path = dir, upward = true, type = 'directory' })
+ ]], nvim_dir))
+ eq({nvim_prog}, exec_lua([[
+ local dir, nvim = ...
+ return vim.fs.find(nvim, { path = dir, type = 'file' })
+ ]], test_build_dir, nvim_prog_basename))
+ end)
+ end)
+
+ describe('normalize()', function()
+ it('works with backward slashes', function()
+ eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]])
+ end)
+ it('works with ~', function()
+ if iswin() then
+ pending([[$HOME does not exist on Windows ¯\_(ツ)_/¯]])
+ end
+ eq(os.getenv('HOME') .. '/src/foo', exec_lua [[ return vim.fs.normalize('~/src/foo') ]])
+ end)
+ it('works with environment variables', function()
+ local xdg_config_home = test_build_dir .. '/.config'
+ eq(xdg_config_home .. '/nvim', exec_lua([[
+ vim.env.XDG_CONFIG_HOME = ...
+ return vim.fs.normalize('$XDG_CONFIG_HOME/nvim')
+ ]], xdg_config_home))
+ end)
+ end)
+end)
diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua
index 50eecb5d09..60d0ed5017 100644
--- a/test/functional/lua/highlight_spec.lua
+++ b/test/functional/lua/highlight_spec.lua
@@ -6,20 +6,29 @@ local command = helpers.command
local clear = helpers.clear
describe('vim.highlight.on_yank', function()
-
before_each(function()
clear()
end)
it('does not show errors even if buffer is wiped before timeout', function()
command('new')
- exec_lua[[
+ exec_lua([[
vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}})
vim.cmd('bwipeout!')
- ]]
+ ]])
helpers.sleep(10)
helpers.feed('<cr>') -- avoid hang if error message exists
eq('', eval('v:errmsg'))
end)
+ it('does not close timer twice', function()
+ exec_lua([[
+ vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}})
+ vim.loop.sleep(10)
+ vim.schedule(function()
+ vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}})
+ end)
+ ]])
+ eq('', eval('v:errmsg'))
+ end)
end)
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index c543dd1995..1322155595 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -532,6 +532,7 @@ describe('v:lua', function()
command('set pp+=test/functional/fixtures')
eq('\tbadval', eval("v:lua.require'leftpad'('badval')"))
eq(9003, eval("v:lua.require'bar'.doit()"))
+ eq(9004, eval("v:lua.require'baz-quux'.doit()"))
end)
it('throw errors for invalid use', function()
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index b0712ff366..9b51af1eec 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -61,6 +61,44 @@ describe('print', function()
eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
pcall_err(command, 'lua print("foo", v_tblout, "bar")'))
end)
+ it('coerces error values into strings', function()
+ write_file(fname, [[
+ function string_error() error("my mistake") end
+ function number_error() error(1234) end
+ function nil_error() error(nil) end
+ function table_error() error({message = "my mistake"}) end
+ function custom_error()
+ local err = {message = "my mistake", code = 11234}
+ setmetatable(err, {
+ __tostring = function(t)
+ return "Internal Error [" .. t.code .. "] " .. t.message
+ end
+ })
+ error(err)
+ end
+ function bad_custom_error()
+ local err = {message = "my mistake", code = 11234}
+ setmetatable(err, {
+ -- intentionally not a function, downstream programmer has made an mistake
+ __tostring = "Internal Error [" .. err.code .. "] " .. err.message
+ })
+ error(err)
+ end
+ ]])
+ eq('', exec_capture('luafile ' .. fname))
+ eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:0: my mistake',
+ pcall_err(command, 'lua string_error()'))
+ eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:0: 1234',
+ pcall_err(command, 'lua number_error()'))
+ eq('Vim(lua):E5108: Error executing lua [NULL]',
+ pcall_err(command, 'lua nil_error()'))
+ eq('Vim(lua):E5108: Error executing lua [NULL]',
+ pcall_err(command, 'lua table_error()'))
+ eq('Vim(lua):E5108: Error executing lua Internal Error [11234] my mistake',
+ pcall_err(command, 'lua custom_error()'))
+ eq('Vim(lua):E5108: Error executing lua [NULL]',
+ pcall_err(command, 'lua bad_custom_error()'))
+ end)
it('prints strings with NULs and NLs correctly', function()
meths.set_option('more', true)
eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n',
diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua
new file mode 100644
index 0000000000..e183ce3a57
--- /dev/null
+++ b/test/functional/lua/thread_spec.lua
@@ -0,0 +1,408 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
+local clear = helpers.clear
+local feed = helpers.feed
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local next_msg = helpers.next_msg
+local NIL = helpers.NIL
+local pcall_err = helpers.pcall_err
+
+describe('thread', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {bold = true},
+ })
+ end)
+
+ it('entry func is executed in protected mode', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ error('Error in thread entry func')
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error in luv thread:} |
+ {3:[string "<nvim>"]:2: Error in thread entry func} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+ assert_alive()
+ end)
+
+ it('callback is executed in protected mode', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ local timer = vim.loop.new_timer()
+ local function ontimeout()
+ timer:stop()
+ timer:close()
+ error('Error in thread callback')
+ end
+ timer:start(10, 0, ontimeout)
+ vim.loop.run()
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error in luv callback, thread:} |
+ {3:[string "<nvim>"]:6: Error in thread callback} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+ assert_alive()
+ end)
+
+ describe('print', function()
+ it('works', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ print('print in thread')
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ print in thread |
+ ]])
+ end)
+
+ it('vim.inspect', function()
+ exec_lua [[
+ local thread = vim.loop.new_thread(function()
+ print(vim.inspect({1,2}))
+ end)
+ vim.loop.thread_join(thread)
+ ]]
+
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ { 1, 2 } |
+ ]])
+ end)
+ end)
+
+ describe('vim.*', function()
+ before_each(function()
+ clear()
+ exec_lua [[
+ Thread_Test = {}
+
+ Thread_Test.entry_func = function(async, entry_str, args)
+ local decoded_args = vim.mpack.decode(args)
+ assert(loadstring(entry_str))(async, decoded_args)
+ end
+
+ function Thread_Test:do_test()
+ local async
+ local on_async = self.on_async
+ async = vim.loop.new_async(function(ret)
+ on_async(ret)
+ async:close()
+ end)
+ local thread =
+ vim.loop.new_thread(self.entry_func, async, self.entry_str, self.args)
+ vim.loop.thread_join(thread)
+ end
+
+ Thread_Test.new = function(entry, on_async, ...)
+ self = {}
+ setmetatable(self, {__index = Thread_Test})
+ self.args = vim.mpack.encode({...})
+ self.entry_str = string.dump(entry)
+ self.on_async = on_async
+ return self
+ end
+ ]]
+ end)
+
+ it('is_thread', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.is_thread())
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {true}}, next_msg())
+ end)
+
+ it('loop', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.loop.version())
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, ret)
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ local msg = next_msg()
+ eq(msg[1], 'notification')
+ assert(tonumber(msg[2]) >= 72961)
+ end)
+
+ it('mpack', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.mpack.encode({33, vim.NIL, 'text'}))
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', vim.mpack.decode(ret))
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('json', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.json.encode({33, vim.NIL, 'text'}))
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', vim.json.decode(ret))
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('diff', function()
+ exec_lua [[
+ local entry = function(async)
+ async:send(vim.diff('Hello\n', 'Helli\n'))
+ end
+ local on_async = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local thread_test = Thread_Test.new(entry, on_async)
+ thread_test:do_test()
+ ]]
+
+ eq({'notification', 'result',
+ {table.concat({
+ '@@ -1 +1 @@',
+ '-Hello',
+ '+Helli',
+ ''
+ }, '\n')}},
+ next_msg())
+ end)
+ end)
+end)
+
+describe('threadpool', function()
+ before_each(clear)
+
+ it('is_thread', function()
+ eq(false, exec_lua [[return vim.is_thread()]])
+
+ exec_lua [[
+ local work_fn = function()
+ return vim.is_thread()
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local work = vim.loop.new_work(work_fn, after_work_fn)
+ work:queue()
+ ]]
+
+ eq({'notification', 'result', {true}}, next_msg())
+ end)
+
+ it('with invalid argument', function()
+ local status = pcall_err(exec_lua, [[
+ local work = vim.loop.new_thread(function() end, function() end)
+ work:queue({})
+ ]])
+
+ eq([[Error executing lua: [string "<nvim>"]:0: Error: thread arg not support type 'function' at 1]],
+ status)
+ end)
+
+ it('with invalid return value', function()
+ local screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {bold = true},
+ })
+
+ exec_lua [[
+ local work = vim.loop.new_work(function() return {} end, function() end)
+ work:queue()
+ ]]
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error in luv thread:} |
+ {3:Error: thread arg not support type 'table' at 1} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ describe('vim.*', function()
+ before_each(function()
+ clear()
+ exec_lua [[
+ Threadpool_Test = {}
+
+ Threadpool_Test.work_fn = function(work_fn_str, args)
+ local decoded_args = vim.mpack.decode(args)
+ return assert(loadstring(work_fn_str))(decoded_args)
+ end
+
+ function Threadpool_Test:do_test()
+ local work =
+ vim.loop.new_work(self.work_fn, self.after_work)
+ work:queue(self.work_fn_str, self.args)
+ end
+
+ Threadpool_Test.new = function(work_fn, after_work, ...)
+ self = {}
+ setmetatable(self, {__index = Threadpool_Test})
+ self.args = vim.mpack.encode({...})
+ self.work_fn_str = string.dump(work_fn)
+ self.after_work = after_work
+ return self
+ end
+ ]]
+ end)
+
+ it('loop', function()
+ exec_lua [[
+ local work_fn = function()
+ return vim.loop.version()
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, ret)
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ local msg = next_msg()
+ eq(msg[1], 'notification')
+ assert(tonumber(msg[2]) >= 72961)
+ end)
+
+ it('mpack', function()
+ exec_lua [[
+ local work_fn = function()
+ local var = vim.mpack.encode({33, vim.NIL, 'text'})
+ return var
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', vim.mpack.decode(ret))
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('json', function()
+ exec_lua [[
+ local work_fn = function()
+ local var = vim.json.encode({33, vim.NIL, 'text'})
+ return var
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', vim.json.decode(ret))
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg())
+ end)
+
+ it('work', function()
+ exec_lua [[
+ local work_fn = function()
+ return vim.diff('Hello\n', 'Helli\n')
+ end
+ local after_work_fn = function(ret)
+ vim.rpcnotify(1, 'result', ret)
+ end
+ local threadpool_test = Threadpool_Test.new(work_fn, after_work_fn)
+ threadpool_test:do_test()
+ ]]
+
+ eq({'notification', 'result',
+ {table.concat({
+ '@@ -1 +1 @@',
+ '-Hello',
+ '+Helli',
+ ''
+ }, '\n')}},
+ next_msg())
+ end)
+ end)
+end)
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
index 2371939204..3fcb2dec8d 100644
--- a/test/functional/lua/ui_spec.lua
+++ b/test/functional/lua/ui_spec.lua
@@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local exec_lua = helpers.exec_lua
local clear = helpers.clear
+local feed = helpers.feed
+local eval = helpers.eval
describe('vim.ui', function()
before_each(function()
@@ -67,5 +69,19 @@ describe('vim.ui', function()
eq('Inputted text', result[1])
eq('Input: ', result[2])
end)
+
+ it('can input text on nil opt', function()
+ feed(':lua vim.ui.input(nil, function(input) result = input end)<cr>')
+ eq('', eval('v:errmsg'))
+ feed('Inputted text<cr>')
+ eq('Inputted text', exec_lua('return result'))
+ end)
+
+ it('can input text on {} opt', function()
+ feed(':lua vim.ui.input({}, function(input) result = input end)<cr>')
+ eq('', eval('v:errmsg'))
+ feed('abcdefg<cr>')
+ eq('abcdefg', exec_lua('return result'))
+ end)
end)
end)
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index fa11fdf794..4635f17557 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -101,7 +101,7 @@ describe('URI methods', function()
eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
end)
- it('file path includes only ascii charactors with encoded colon character', function()
+ it('file path includes only ascii characters with encoded colon character', function()
local test_case = [[
local uri = 'file:///C%3A/Foo/Bar/Baz.txt'
return vim.uri_to_fname(uri)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 642dc59bbc..883e0e373b 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -14,15 +14,19 @@ local feed = helpers.feed
local pcall_err = helpers.pcall_err
local exec_lua = helpers.exec_lua
local matches = helpers.matches
-local source = helpers.source
+local exec = helpers.exec
local NIL = helpers.NIL
local retry = helpers.retry
local next_msg = helpers.next_msg
local remove_trace = helpers.remove_trace
-
-before_each(clear)
+local mkdir_p = helpers.mkdir_p
+local rmdir = helpers.rmdir
+local write_file = helpers.write_file
+local expect_exit = helpers.expect_exit
+local poke_eventloop = helpers.poke_eventloop
describe('lua stdlib', function()
+ before_each(clear)
-- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has
-- length 2 (in bytes).
-- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has
@@ -487,6 +491,16 @@ describe('lua stdlib', function()
eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})"))
end)
+ it('vim.tbl_get', function()
+ eq(true, exec_lua("return vim.tbl_get({ test = { nested_test = true }}, 'test', 'nested_test')"))
+ eq(NIL, exec_lua("return vim.tbl_get({ unindexable = true }, 'unindexable', 'missing_key')"))
+ eq(NIL, exec_lua("return vim.tbl_get({ unindexable = 1 }, 'unindexable', 'missing_key')"))
+ eq(NIL, exec_lua("return vim.tbl_get({ unindexable = coroutine.create(function () end) }, 'unindexable', 'missing_key')"))
+ eq(NIL, exec_lua("return vim.tbl_get({ unindexable = function () end }, 'unindexable', 'missing_key')"))
+ eq(NIL, exec_lua("return vim.tbl_get({}, 'missing_key')"))
+ eq(NIL, exec_lua("return vim.tbl_get({})"))
+ end)
+
it('vim.tbl_extend', function()
ok(exec_lua([[
local a = {x = 1}
@@ -636,17 +650,17 @@ describe('lua stdlib', function()
return vim.tbl_islist(c) and count == 0
]]))
- eq(exec_lua([[
+ eq({a = {b = 1}}, exec_lua([[
local a = { a = { b = 1 } }
local b = { a = {} }
return vim.tbl_deep_extend("force", a, b)
- ]]), {a = {b = 1}})
+ ]]))
- eq(exec_lua([[
+ eq({a = {b = 1}}, exec_lua([[
local a = { a = 123 }
local b = { a = { b = 1} }
return vim.tbl_deep_extend("force", a, b)
- ]]), {a = {b = 1}})
+ ]]))
ok(exec_lua([[
local a = { a = {[2] = 3} }
@@ -655,11 +669,11 @@ describe('lua stdlib', function()
return vim.deep_equal(c, {a = {[3] = 3}})
]]))
- eq(exec_lua([[
+ eq({a = 123}, exec_lua([[
local a = { a = { b = 1} }
local b = { a = 123 }
return vim.tbl_deep_extend("force", a, b)
- ]]), {a = 123 })
+ ]]))
matches('invalid "behavior": nil',
pcall_err(exec_lua, [[
@@ -740,7 +754,7 @@ describe('lua stdlib', function()
-- compat: nvim_call_function uses "special" value for vimL float
eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]]))
- source([[
+ exec([[
func! FooFunc(test)
let g:test = a:test
return {}
@@ -768,6 +782,12 @@ describe('lua stdlib', function()
-- error handling
eq({false, 'Vim:E897: List or Blob required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
+
+ -- conversion between LuaRef and Vim Funcref
+ eq(true, exec_lua([[
+ local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end)
+ return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar'
+ ]]))
end)
it('vim.fn should error when calling API function', function()
@@ -775,6 +795,20 @@ describe('lua stdlib', function()
pcall_err(exec_lua, "vim.fn.nvim_get_current_line()"))
end)
+ it('vim.fn is allowed in "fast" context by some functions #18306', function()
+ exec_lua([[
+ local timer = vim.loop.new_timer()
+ timer:start(0, 0, function()
+ timer:close()
+ assert(vim.in_fast_event())
+ vim.g.fnres = vim.fn.iconv('hello', 'utf-8', 'utf-8')
+ end)
+ ]])
+
+ helpers.poke_eventloop()
+ eq('hello', exec_lua[[return vim.g.fnres]])
+ end)
+
it('vim.rpcrequest and vim.rpcnotify', function()
exec_lua([[
chan = vim.fn.jobstart({'cat'}, {rpc=true})
@@ -987,6 +1021,77 @@ describe('lua stdlib', function()
matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.g[0].testing'))
+
+ exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.g.AddCounter = add_counter
+ vim.g.GetCounter = get_counter
+ vim.g.funcs = {add = add_counter, get = get_counter}
+ ]]
+
+ eq(0, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(1, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(2, eval('g:GetCounter()'))
+ exec_lua([[vim.g.AddCounter()]])
+ eq(3, exec_lua([[return vim.g.GetCounter()]]))
+ exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
+ exec_lua([[vim.g.funcs.add()]])
+ eq(5, exec_lua([[return vim.g.funcs.get()]]))
+ exec_lua([[vim.api.nvim_get_var('funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
+
+ exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_set_var('AddCounter', add_counter)
+ vim.api.nvim_set_var('GetCounter', get_counter)
+ vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter})
+ ]]
+
+ eq(0, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(1, eval('g:GetCounter()'))
+ eval('g:AddCounter()')
+ eq(2, eval('g:GetCounter()'))
+ exec_lua([[vim.g.AddCounter()]])
+ eq(3, exec_lua([[return vim.g.GetCounter()]]))
+ exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
+ exec_lua([[vim.g.funcs.add()]])
+ eq(5, exec_lua([[return vim.g.funcs.get()]]))
+ exec_lua([[vim.api.nvim_get_var('funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
+
+ exec([[
+ function Test()
+ endfunction
+ function s:Test()
+ endfunction
+ let g:Unknown_func = function('Test')
+ let g:Unknown_script_func = function('s:Test')
+ ]])
+ eq(NIL, exec_lua([[return vim.g.Unknown_func]]))
+ eq(NIL, exec_lua([[return vim.g.Unknown_script_func]]))
+
+ -- Check if autoload works properly
+ local pathsep = helpers.get_pathsep()
+ local xconfig = 'Xhome' .. pathsep .. 'Xconfig'
+ local xdata = 'Xhome' .. pathsep .. 'Xdata'
+ local autoload_folder = table.concat({xconfig, 'nvim', 'autoload'}, pathsep)
+ local autoload_file = table.concat({autoload_folder , 'testload.vim'}, pathsep)
+ mkdir_p(autoload_folder)
+ write_file(autoload_file , [[let testload#value = 2]])
+
+ clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_DATA_HOME=xdata } }
+
+ eq(2, exec_lua("return vim.g['testload#value']"))
+ rmdir('Xhome')
end)
it('vim.b', function()
@@ -1022,6 +1127,63 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.b.to_delete")
exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.b.AddCounter = add_counter
+ vim.b.GetCounter = get_counter
+ vim.b.funcs = {add = add_counter, get = get_counter}
+ ]]
+
+ eq(0, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(1, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(2, eval('b:GetCounter()'))
+ exec_lua([[vim.b.AddCounter()]])
+ eq(3, exec_lua([[return vim.b.GetCounter()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.b.funcs.add()]])
+ eq(5, exec_lua([[return vim.b.funcs.get()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
+
+ exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter})
+ ]]
+
+ eq(0, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(1, eval('b:GetCounter()'))
+ eval('b:AddCounter()')
+ eq(2, eval('b:GetCounter()'))
+ exec_lua([[vim.b.AddCounter()]])
+ eq(3, exec_lua([[return vim.b.GetCounter()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.b.funcs.add()]])
+ eq(5, exec_lua([[return vim.b.funcs.get()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
+
+ exec([[
+ function Test()
+ endfunction
+ function s:Test()
+ endfunction
+ let b:Unknown_func = function('Test')
+ let b:Unknown_script_func = function('s:Test')
+ ]])
+ eq(NIL, exec_lua([[return vim.b.Unknown_func]]))
+ eq(NIL, exec_lua([[return vim.b.Unknown_script_func]]))
+
+ exec_lua [[
vim.cmd "vnew"
]]
@@ -1059,6 +1221,63 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.w.to_delete")
exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.w.AddCounter = add_counter
+ vim.w.GetCounter = get_counter
+ vim.w.funcs = {add = add_counter, get = get_counter}
+ ]]
+
+ eq(0, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(1, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(2, eval('w:GetCounter()'))
+ exec_lua([[vim.w.AddCounter()]])
+ eq(3, exec_lua([[return vim.w.GetCounter()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.w.funcs.add()]])
+ eq(5, exec_lua([[return vim.w.funcs.get()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
+
+ exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_win_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_win_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter})
+ ]]
+
+ eq(0, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(1, eval('w:GetCounter()'))
+ eval('w:AddCounter()')
+ eq(2, eval('w:GetCounter()'))
+ exec_lua([[vim.w.AddCounter()]])
+ eq(3, exec_lua([[return vim.w.GetCounter()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.w.funcs.add()]])
+ eq(5, exec_lua([[return vim.w.funcs.get()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
+
+ exec([[
+ function Test()
+ endfunction
+ function s:Test()
+ endfunction
+ let w:Unknown_func = function('Test')
+ let w:Unknown_script_func = function('s:Test')
+ ]])
+ eq(NIL, exec_lua([[return vim.w.Unknown_func]]))
+ eq(NIL, exec_lua([[return vim.w.Unknown_script_func]]))
+
+ exec_lua [[
vim.cmd "vnew"
]]
@@ -1091,6 +1310,52 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.t.to_delete")
exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.t.AddCounter = add_counter
+ vim.t.GetCounter = get_counter
+ vim.t.funcs = {add = add_counter, get = get_counter}
+ ]]
+
+ eq(0, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(1, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(2, eval('t:GetCounter()'))
+ exec_lua([[vim.t.AddCounter()]])
+ eq(3, exec_lua([[return vim.t.GetCounter()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.t.funcs.add()]])
+ eq(5, exec_lua([[return vim.t.funcs.get()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
+
+ exec_lua [[
+ local counter = 0
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter})
+ ]]
+
+ eq(0, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(1, eval('t:GetCounter()'))
+ eval('t:AddCounter()')
+ eq(2, eval('t:GetCounter()'))
+ exec_lua([[vim.t.AddCounter()]])
+ eq(3, exec_lua([[return vim.t.GetCounter()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
+ eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.t.funcs.add()]])
+ eq(5, exec_lua([[return vim.t.funcs.get()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
+
+ exec_lua [[
vim.cmd "tabnew"
]]
@@ -1131,10 +1396,12 @@ describe('lua stdlib', function()
]]
eq('', funcs.luaeval "vim.bo.filetype")
eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
- matches("Invalid option name: 'nosuchopt'$",
+ matches("unknown option 'nosuchopt'$",
pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
+ matches("Invalid buffer id: %-1$",
+ pcall_err(exec_lua, 'return vim.bo[-1].filetype'))
end)
it('vim.wo', function()
@@ -1150,15 +1417,24 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo.cole")
eq(0, funcs.luaeval "vim.wo[0].cole")
eq(0, funcs.luaeval "vim.wo[1001].cole")
- matches("Invalid option name: 'notanopt'$",
+ matches("unknown option 'notanopt'$",
pcall_err(exec_lua, 'return vim.wo.notanopt'))
matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.wo[0][0].list'))
+ matches("Invalid window id: %-1$",
+ pcall_err(exec_lua, 'return vim.wo[-1].list'))
eq(2, funcs.luaeval "vim.wo[1000].cole")
exec_lua [[
vim.wo[1000].cole = 0
]]
eq(0, funcs.luaeval "vim.wo[1000].cole")
+
+ -- Can handle global-local values
+ exec_lua [[vim.o.scrolloff = 100]]
+ exec_lua [[vim.wo.scrolloff = 200]]
+ eq(200, funcs.luaeval "vim.wo.scrolloff")
+ exec_lua [[vim.wo.scrolloff = -1]]
+ eq(100, funcs.luaeval "vim.wo.scrolloff")
end)
describe('vim.opt', function()
@@ -2004,6 +2280,22 @@ describe('lua stdlib', function()
eq('iworld<ESC>', exec_lua[[return table.concat(keys, '')]])
end)
+
+ it('can call vim.fn functions on Ctrl-C #17273', function()
+ exec_lua([[
+ _G.ctrl_c_cmdtype = ''
+
+ vim.on_key(function(c)
+ if c == '\3' then
+ _G.ctrl_c_cmdtype = vim.fn.getcmdtype()
+ end
+ end)
+ ]])
+ feed('/')
+ poke_eventloop() -- This is needed because Ctrl-C flushes input
+ feed('<C-C>')
+ eq('/', exec_lua([[return _G.ctrl_c_cmdtype]]))
+ end)
end)
describe('vim.wait', function()
@@ -2278,6 +2570,17 @@ describe('lua stdlib', function()
eq(buf1, meths.get_current_buf())
eq(buf2, val)
end)
+
+ it('does not cause ml_get errors with invalid visual selection', function()
+ -- Should be fixed by vim-patch:8.2.4028.
+ exec_lua [[
+ local a = vim.api
+ local t = function(s) return a.nvim_replace_termcodes(s, true, true, true) end
+ a.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"})
+ a.nvim_feedkeys(t "G<C-V>", "txn", false)
+ a.nvim_buf_call(a.nvim_create_buf(false, true), function() vim.cmd "redraw" end)
+ ]]
+ end)
end)
describe('vim.api.nvim_win_call', function()
@@ -2306,12 +2609,109 @@ describe('lua stdlib', function()
eq(win1, meths.get_current_win())
eq(win2, val)
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 [[
+ _G.a = vim.api
+ _G.t = function(s) return a.nvim_replace_termcodes(s, true, true, true) end
+ _G.win_lines = a.nvim_get_current_win()
+ vim.cmd "new"
+ _G.win_empty = a.nvim_get_current_win()
+ a.nvim_set_current_win(win_lines)
+ a.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"})
+ ]]
+
+ -- Start Visual in current window, redraw in other window with fewer lines.
+ -- Should be fixed by vim-patch:8.2.4018.
+ exec_lua [[
+ a.nvim_feedkeys(t "G<C-V>", "txn", false)
+ a.nvim_win_call(win_empty, function() vim.cmd "redraw" end)
+ ]]
+
+ -- Start Visual in current window, extend it in other window with more lines.
+ -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected.
+ exec_lua [[
+ a.nvim_feedkeys(t "<Esc>gg", "txn", false)
+ a.nvim_set_current_win(win_empty)
+ a.nvim_feedkeys(t "gg<C-V>", "txn", false)
+ a.nvim_win_call(win_lines, function() a.nvim_feedkeys(t "G<C-V>", "txn", false) end)
+ vim.cmd "redraw"
+ ]]
+ end)
+
+ it('updates ruler if cursor moved', function()
+ -- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too!
+ local screen = Screen.new(30, 5)
+ screen:set_default_attr_ids {
+ [1] = {reverse = true},
+ [2] = {bold = true, reverse = true},
+ }
+ screen:attach()
+ exec_lua [[
+ _G.a = vim.api
+ vim.opt.ruler = true
+ local lines = {}
+ for i = 0, 499 do lines[#lines + 1] = tostring(i) end
+ a.nvim_buf_set_lines(0, 0, -1, true, lines)
+ a.nvim_win_set_cursor(0, {20, 0})
+ vim.cmd "split"
+ _G.win = a.nvim_get_current_win()
+ vim.cmd "wincmd w | redraw"
+ ]]
+ screen:expect [[
+ 19 |
+ {1:[No Name] [+] 20,1 3%}|
+ ^19 |
+ {2:[No Name] [+] 20,1 3%}|
+ |
+ ]]
+ exec_lua [[
+ a.nvim_win_call(win, function() a.nvim_win_set_cursor(0, {100, 0}) end)
+ vim.cmd "redraw"
+ ]]
+ screen:expect [[
+ 99 |
+ {1:[No Name] [+] 100,1 19%}|
+ ^19 |
+ {2:[No Name] [+] 20,1 3%}|
+ |
+ ]]
+ end)
+ end)
+end)
+
+describe('lua: builtin modules', function()
+ local function do_tests()
+ eq(2, exec_lua[[return vim.tbl_count {x=1,y=2}]])
+ eq('{ 10, "spam" }', exec_lua[[return vim.inspect {10, 'spam'}]])
+ end
+
+ it('works', function()
+ clear()
+ do_tests()
+ end)
+
+ it('works when disabled', function()
+ clear('--luamod-dev')
+ do_tests()
+ end)
+
+ it('works without runtime', function()
+ clear{env={VIMRUNTIME='fixtures/a'}}
+ do_tests()
+ end)
+
+
+ it('does not work when disabled without runtime', function()
+ clear{args={'--luamod-dev'}, env={VIMRUNTIME='fixtures/a'}}
+ expect_exit(exec_lua, [[return vim.tbl_count {x=1,y=2}]])
end)
end)
describe('lua: require("mod") from packages', function()
before_each(function()
- command('set rtp+=test/functional/fixtures pp+=test/functional/fixtures')
+ clear('--cmd', 'set rtp+=test/functional/fixtures pp+=test/functional/fixtures')
end)
it('propagates syntax error', function()
@@ -2334,6 +2734,8 @@ describe('lua: require("mod") from packages', function()
end)
describe('vim.keymap', function()
+ before_each(clear)
+
it('can make a mapping', function()
eq(0, exec_lua [[
GlobalCount = 0
@@ -2397,6 +2799,39 @@ describe('vim.keymap', function()
eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
end)
+ it('works with buffer-local mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end, {buffer=true})
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.keymap.del('n', 'asdf', {buffer=true})
+ ]]
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
+ end)
+
+ it('does not mutate the opts parameter', function()
+ eq(true, exec_lua [[
+ opts = {buffer=true}
+ vim.keymap.set('n', 'asdf', function() end, opts)
+ return opts.buffer
+ ]])
+ eq(true, exec_lua [[
+ vim.keymap.del('n', 'asdf', opts)
+ return opts.buffer
+ ]])
+ end)
+
it('can do <Plug> mappings', function()
eq(0, exec_lua [[
GlobalCount = 0
diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua
index 4f28f84c01..d55268fc78 100644
--- a/test/functional/lua/xdiff_spec.lua
+++ b/test/functional/lua/xdiff_spec.lua
@@ -90,6 +90,48 @@ describe('xdiff bindings', function()
exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]]))
end)
+ it('can run different algorithms', function()
+ local a = table.concat({
+ '.foo1 {',
+ ' margin: 0;',
+ '}',
+ '',
+ '.bar {',
+ ' margin: 0;',
+ '}',
+ ''}, '\n')
+
+ local b = table.concat({
+ '.bar {',
+ ' margin: 0;',
+ '}',
+ '',
+ '.foo1 {',
+ ' margin: 0;',
+ ' color: green;',
+ '}',
+ ''}, '\n')
+
+ eq(
+ table.concat({'@@ -1,4 +0,0 @@',
+ '-.foo1 {',
+ '- margin: 0;',
+ '-}',
+ '-',
+ '@@ -7,0 +4,5 @@',
+ '+',
+ '+.foo1 {',
+ '+ margin: 0;',
+ '+ color: green;',
+ '+}',
+ ''}, '\n'),
+ exec_lua([[
+ local args = {...}
+ return vim.diff(args[1], args[2], {
+ algorithm = 'patience'
+ })
+ ]], a, b))
+ end)
end)
it('can handle bad args', function()
diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua
index 2fce0a5ed9..74959a8e76 100644
--- a/test/functional/options/autochdir_spec.lua
+++ b/test/functional/options/autochdir_spec.lua
@@ -1,7 +1,9 @@
+local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
-local getcwd = helpers.funcs.getcwd
+local funcs = helpers.funcs
+local command = helpers.command
describe("'autochdir'", function()
it('given on the shell gets processed properly', function()
@@ -9,11 +11,34 @@ describe("'autochdir'", function()
-- By default 'autochdir' is off, thus getcwd() returns the repo root.
clear(targetdir..'/tty-test.c')
- local rootdir = getcwd()
+ local rootdir = funcs.getcwd()
local expected = rootdir .. '/' .. targetdir
-- With 'autochdir' on, we should get the directory of tty-test.c.
clear('--cmd', 'set autochdir', targetdir..'/tty-test.c')
- eq(helpers.iswin() and expected:gsub('/', '\\') or expected, getcwd())
+ eq(helpers.iswin() and expected:gsub('/', '\\') or expected, funcs.getcwd())
+ end)
+
+ it('is not overwritten by getwinvar() call #17609',function()
+ local curdir = string.gsub(lfs.currentdir(), '\\', '/')
+ local dir_a = curdir..'/Xtest-functional-options-autochdir.dir_a'
+ local dir_b = curdir..'/Xtest-functional-options-autochdir.dir_b'
+ lfs.mkdir(dir_a)
+ lfs.mkdir(dir_b)
+ clear()
+ command('set shellslash')
+ command('set autochdir')
+ command('edit '..dir_a..'/file1')
+ eq(dir_a, funcs.getcwd())
+ command('lcd '..dir_b)
+ eq(dir_b, funcs.getcwd())
+ command('botright vnew ../file2')
+ eq(curdir, funcs.getcwd())
+ command('wincmd w')
+ eq(dir_a, funcs.getcwd())
+ funcs.getwinvar(2, 'foo')
+ eq(dir_a, funcs.getcwd())
+ helpers.rmdir(dir_a)
+ helpers.rmdir(dir_b)
end)
end)
diff --git a/test/functional/options/cursorbind_spec.lua b/test/functional/options/cursorbind_spec.lua
new file mode 100644
index 0000000000..1a03ed099a
--- /dev/null
+++ b/test/functional/options/cursorbind_spec.lua
@@ -0,0 +1,91 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe("'cursorbind'", function()
+ it("behaves consistently whether 'cursorline' is set or not vim-patch:8.2.4795", function()
+ local screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {bold = true, reverse = true}, -- StatusLine
+ [3] = {reverse = true}, -- StatusLineNC
+ [4] = {background = Screen.colors.Grey90}, -- CursorLine, CursorColumn
+ })
+ screen:attach()
+ exec([[
+ call setline(1, 'aa bb cc dd ee ff gg hh ii jj kk ll mm' ..
+ \ ' nn oo pp qq rr ss tt uu vv ww xx yy zz')
+ set nowrap
+ " The following makes the cursor apparent on the screen dump
+ set sidescroll=1 cursorcolumn
+ " add empty lines, required for cursorcolumn
+ call append(1, ['','','',''])
+ 20vsp
+ windo :set cursorbind
+ ]])
+ feed('20l')
+ screen:expect([[
+ a bb cc dd ee ff gg │aa bb cc dd ee ff gg^ hh ii jj kk ll mm |
+ {4: }│ {4: } |
+ {4: }│ {4: } |
+ {4: }│ {4: } |
+ {4: }│ {4: } |
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('10l')
+ screen:expect([[
+ hh ii jj kk ll mm n│aa bb cc dd ee ff gg hh ii jj ^kk ll mm |
+ {4: } │ {4: } |
+ {4: } │ {4: } |
+ {4: } │ {4: } |
+ {4: } │ {4: } |
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ command('windo :set cursorline')
+ feed('0')
+ feed('20l')
+ screen:expect([[
+ {4:a bb cc dd ee ff gg }│{4:aa bb cc dd ee ff gg^ hh ii jj kk ll mm }|
+ {4: }│ {4: } |
+ {4: }│ {4: } |
+ {4: }│ {4: } |
+ {4: }│ {4: } |
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ feed('10l')
+ screen:expect([[
+ {4: hh ii jj kk ll mm n}│{4:aa bb cc dd ee ff gg hh ii jj ^kk ll mm }|
+ {4: } │ {4: } |
+ {4: } │ {4: } |
+ {4: } │ {4: } |
+ {4: } │ {4: } |
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ command('windo :set nocursorline nocursorcolumn')
+ feed('0')
+ feed('40l')
+ screen:expect([[
+ kk ll mm nn oo pp qq│ bb cc dd ee ff gg hh ii jj kk ll mm n^n|
+ │ |
+ │ |
+ │ |
+ │ |
+ {1:~ }│{1:~ }|
+ {3:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 6620c9acef..9244ca0974 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -9,6 +9,7 @@ local clear = helpers.clear
local exc_exec = helpers.exc_exec
local eval = helpers.eval
local eq = helpers.eq
+local ok = helpers.ok
local funcs = helpers.funcs
local insert = helpers.insert
local iswin = helpers.iswin
@@ -17,6 +18,7 @@ local mkdir = helpers.mkdir
local rmdir = helpers.rmdir
local alter_slashes = helpers.alter_slashes
local tbl_contains = helpers.tbl_contains
+local expect_exit = helpers.expect_exit
describe('startup defaults', function()
describe(':filetype', function()
@@ -163,7 +165,7 @@ describe('startup defaults', function()
end)
it("'shadafile' ('viminfofile')", function()
- local env = {XDG_DATA_HOME='Xtest-userdata', XDG_CONFIG_HOME='Xtest-userconfig'}
+ local env = {XDG_DATA_HOME='Xtest-userdata', XDG_STATE_HOME='Xtest-userstate', XDG_CONFIG_HOME='Xtest-userconfig'}
clear{args={}, args_rm={'-i'}, env=env}
-- Default 'shadafile' is empty.
-- This means use the default location. :help shada-file-name
@@ -174,11 +176,11 @@ describe('startup defaults', function()
command('write')
local f = eval('fnamemodify(@%,":p")')
assert(string.len(f) > 3)
- command('qall')
+ expect_exit(command, 'qall')
clear{args={}, args_rm={'-i'}, env=env}
eq({ f }, eval('v:oldfiles'))
os.remove('Xtest-foo')
- rmdir('Xtest-userdata')
+ rmdir('Xtest-userstate')
-- Handles viminfo/viminfofile as alias for shada/shadafile.
eq('\n shadafile=', eval('execute("set shadafile?")'))
@@ -206,7 +208,7 @@ describe('startup defaults', function()
describe('$NVIM_LOG_FILE', function()
local xdgdir = 'Xtest-startup-xdg-logpath'
- local xdgcachedir = xdgdir..'/nvim'
+ local xdgstatedir = iswin() and xdgdir..'/nvim-data' or xdgdir..'/nvim'
after_each(function()
os.remove('Xtest-logpath')
rmdir(xdgdir)
@@ -218,26 +220,26 @@ describe('startup defaults', function()
}})
eq('Xtest-logpath', eval('$NVIM_LOG_FILE'))
end)
- it('defaults to stdpath("cache")/log if empty', function()
- eq(true, mkdir(xdgdir) and mkdir(xdgcachedir))
+ it('defaults to stdpath("log")/log if empty', function()
+ eq(true, mkdir(xdgdir) and mkdir(xdgstatedir))
clear({env={
- XDG_CACHE_HOME=xdgdir,
+ XDG_STATE_HOME=xdgdir,
NVIM_LOG_FILE='', -- Empty is invalid.
}})
- eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
+ eq(xdgstatedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
end)
- it('defaults to stdpath("cache")/log if invalid', function()
- eq(true, mkdir(xdgdir) and mkdir(xdgcachedir))
+ it('defaults to stdpath("log")/log if invalid', function()
+ eq(true, mkdir(xdgdir) and mkdir(xdgstatedir))
clear({env={
- XDG_CACHE_HOME=xdgdir,
+ XDG_STATE_HOME=xdgdir,
NVIM_LOG_FILE='.', -- Any directory is invalid.
}})
- eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
+ eq(xdgstatedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/'))
end)
end)
end)
-describe('XDG-based defaults', function()
+describe('XDG defaults', function()
-- Need separate describe() blocks to not run clear() twice.
-- Do not put before_each() here for the same reasons.
@@ -264,6 +266,7 @@ describe('XDG-based defaults', function()
XDG_CONFIG_HOME=nil,
XDG_DATA_HOME=nil,
XDG_CACHE_HOME=nil,
+ XDG_STATE_HOME=nil,
XDG_RUNTIME_DIR=nil,
XDG_CONFIG_DIRS=nil,
XDG_DATA_DIRS=nil,
@@ -280,6 +283,7 @@ describe('XDG-based defaults', function()
eq('.', meths.get_option('viewdir'))
eq('.', meths.get_option('directory'))
eq('.', meths.get_option('undodir'))
+ ok((funcs.tempname()):len() > 4)
end)
end)
@@ -293,6 +297,7 @@ describe('XDG-based defaults', function()
local env_sep = iswin() and ';' or ':'
local data_dir = iswin() and 'nvim-data' or 'nvim'
+ local state_dir = iswin() and 'nvim-data' or 'nvim'
local root_path = iswin() and 'C:' or ''
describe('with too long XDG variables', function()
@@ -303,6 +308,8 @@ describe('XDG-based defaults', function()
.. env_sep.. root_path .. ('/b'):rep(2048)
.. (env_sep .. root_path .. '/c'):rep(512)),
XDG_DATA_HOME=(root_path .. ('/X'):rep(4096)),
+ XDG_RUNTIME_DIR=(root_path .. ('/X'):rep(4096)),
+ XDG_STATE_HOME=(root_path .. ('/X'):rep(4096)),
XDG_DATA_DIRS=(root_path .. ('/A'):rep(2048)
.. env_sep .. root_path .. ('/B'):rep(2048)
.. (env_sep .. root_path .. '/C'):rep(512)),
@@ -355,13 +362,13 @@ describe('XDG-based defaults', function()
.. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
.. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
- eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup//',
+ eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. state_dir .. '/backup//',
(meths.get_option('backupdir'):gsub('\\', '/')))
- eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/swap//',
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//',
(meths.get_option('directory')):gsub('\\', '/'))
- eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo//',
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//',
(meths.get_option('undodir')):gsub('\\', '/'))
- eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view//',
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//',
(meths.get_option('viewdir')):gsub('\\', '/'))
end)
end)
@@ -372,6 +379,8 @@ describe('XDG-based defaults', function()
XDG_CONFIG_HOME='$XDG_DATA_HOME',
XDG_CONFIG_DIRS='$XDG_DATA_DIRS',
XDG_DATA_HOME='$XDG_CONFIG_HOME',
+ XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR',
+ XDG_STATE_HOME='$XDG_CONFIG_HOME',
XDG_DATA_DIRS='$XDG_CONFIG_DIRS',
}})
end)
@@ -405,13 +414,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
- eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
+ eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
+ eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
+ eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
+ eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
meths.command('set all&')
eq(('$XDG_DATA_HOME/nvim'
@@ -425,14 +434,15 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/'))
- eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
+ eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
+ eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
+ eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
+ eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
+ eq(nil, (funcs.tempname()):match('XDG_RUNTIME_DIR'))
end)
end)
@@ -442,6 +452,7 @@ describe('XDG-based defaults', function()
XDG_CONFIG_HOME=', , ,',
XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-',
XDG_DATA_HOME=',=,=,',
+ XDG_STATE_HOME=',=,=,',
XDG_DATA_DIRS=',≡,≡,' .. env_sep .. '≡,≡,≡',
}})
end)
@@ -484,13 +495,13 @@ describe('XDG-based defaults', function()
.. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after'
.. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after'
), meths.get_option('runtimepath'))
- eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
+ eq('.,\\,=\\,=\\,' .. path_sep .. state_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
meths.get_option('backupdir'))
- eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
meths.get_option('directory'))
- eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
meths.get_option('undodir'))
- eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
meths.get_option('viewdir'))
end)
end)
@@ -499,8 +510,9 @@ end)
describe('stdpath()', function()
-- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions
- -- due to XDG_CONFIG_HOME and XDG_DATA_HOME being the same.
+ -- due to XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_STATE_HOME being the same.
local datadir = iswin() and 'nvim-data' or 'nvim'
+ local statedir = iswin() and 'nvim-data' or 'nvim'
local env_sep = iswin() and ';' or ':'
it('acceptance', function()
@@ -509,8 +521,10 @@ describe('stdpath()', function()
eq('nvim', funcs.fnamemodify(funcs.stdpath('cache'), ':t'))
eq('nvim', funcs.fnamemodify(funcs.stdpath('config'), ':t'))
eq(datadir, funcs.fnamemodify(funcs.stdpath('data'), ':t'))
+ eq(statedir, funcs.fnamemodify(funcs.stdpath('state'), ':t'))
eq('table', type(funcs.stdpath('config_dirs')))
eq('table', type(funcs.stdpath('data_dirs')))
+ eq('string', type(funcs.stdpath('run')))
assert_alive() -- Check for crash. #8393
end)
@@ -582,6 +596,39 @@ describe('stdpath()', function()
end)
end)
+ describe('with "state"' , function ()
+ it('knows XDG_STATE_HOME', function()
+ clear({env={
+ XDG_STATE_HOME=alter_slashes('/home/docwhat/.local'),
+ }})
+ eq(alter_slashes('/home/docwhat/.local/'..statedir), funcs.stdpath('state'))
+ end)
+
+ it('handles changes during runtime', function()
+ clear({env={
+ XDG_STATE_HOME=alter_slashes('/home/original'),
+ }})
+ eq(alter_slashes('/home/original/'..statedir), funcs.stdpath('state'))
+ command("let $XDG_STATE_HOME='"..alter_slashes('/home/new').."'")
+ eq(alter_slashes('/home/new/'..statedir), funcs.stdpath('state'))
+ end)
+
+ it("doesn't expand $VARIABLES", function()
+ clear({env={
+ XDG_STATE_HOME='$VARIABLES',
+ VARIABLES='this-should-not-happen',
+ }})
+ eq(alter_slashes('$VARIABLES/'..statedir), funcs.stdpath('state'))
+ end)
+
+ it("doesn't expand ~/", function()
+ clear({env={
+ XDG_STATE_HOME=alter_slashes('~/frobnitz'),
+ }})
+ eq(alter_slashes('~/frobnitz/'..statedir), funcs.stdpath('state'))
+ end)
+ end)
+
describe('with "cache"' , function ()
it('knows XDG_CACHE_HOME', function()
clear({env={
diff --git a/test/functional/options/keymap_spec.lua b/test/functional/options/keymap_spec.lua
index 52a714f7a8..a814c35a39 100644
--- a/test/functional/options/keymap_spec.lua
+++ b/test/functional/options/keymap_spec.lua
@@ -120,9 +120,9 @@ describe("'keymap' / :lmap", function()
it("Can be toggled with <C-^> in insert mode", function()
feed('i<C-^>l<C-^>l<esc>')
expect('lalllaaa')
- eq(eval('&iminsert'), 1)
+ eq(1, eval('&iminsert'))
feed('i<C-^><esc>')
- eq(eval('&iminsert'), 0)
+ eq(0, eval('&iminsert'))
end)
end)
describe("'imsearch' option", function()
@@ -136,36 +136,36 @@ describe("'keymap' / :lmap", function()
expect('aaa')
end)
it("Can be toggled with C-^", function()
- eq(eval('&imsearch'), 1)
+ eq(1, eval('&imsearch'))
feed('/<C-^>lll<cr>3x')
expect('aaa')
- eq(eval('&imsearch'), 0)
+ eq(0, eval('&imsearch'))
feed('u0/<C-^>lll<cr>3x')
expect('lll')
- eq(eval('&imsearch'), 1)
+ eq(1, eval('&imsearch'))
end)
it("can follow 'iminsert'", function()
command('set imsearch=-1')
feed('/lll<cr>3x')
expect('lll')
- eq(eval('&imsearch'), -1)
- eq(eval('&iminsert'), 1)
+ eq(-1, eval('&imsearch'))
+ eq(1, eval('&iminsert'))
feed('u/<C-^>lll<cr>3x')
expect('aaa')
- eq(eval('&imsearch'), -1)
- eq(eval('&iminsert'), 0)
+ eq(-1, eval('&imsearch'))
+ eq(0, eval('&iminsert'))
end)
end)
it(":lmap not applied to macros", function()
command("call setreg('a', 'il')")
feed('@a')
expect('llllaaa')
- eq(call('getreg', 'a'), 'il')
+ eq('il', call('getreg', 'a'))
end)
it(":lmap applied to macro recording", function()
feed('qail<esc>q@a')
expect('aalllaaa')
- eq(call('getreg', 'a'), 'ia')
+ eq('ia', call('getreg', 'a'))
end)
it(":lmap not applied to mappings", function()
command('imap t l')
diff --git a/test/functional/options/mousescroll_spec.lua b/test/functional/options/mousescroll_spec.lua
new file mode 100644
index 0000000000..2c9b2d175e
--- /dev/null
+++ b/test/functional/options/mousescroll_spec.lua
@@ -0,0 +1,151 @@
+local helpers = require('test.functional.helpers')(after_each)
+local command = helpers.command
+local clear = helpers.clear
+local eval = helpers.eval
+local eq = helpers.eq
+local exc_exec = helpers.exc_exec
+local feed = helpers.feed
+
+local scroll = function(direction)
+ return helpers.request('nvim_input_mouse', 'wheel', direction, '', 0, 2, 2)
+end
+
+local screenrow = function()
+ return helpers.call('screenrow')
+end
+
+local screencol = function()
+ return helpers.call('screencol')
+end
+
+describe("'mousescroll'", function()
+ local invalid_arg = 'Vim(set):E474: Invalid argument: mousescroll='
+ local digit_expected = 'Vim(set):E548: digit expected: mousescroll='
+
+ local function should_fail(val, errorstr)
+ eq(errorstr..val, exc_exec('set mousescroll='..val))
+ end
+
+ local function should_succeed(val)
+ eq(0, exc_exec('set mousescroll='..val))
+ end
+
+ before_each(function()
+ clear()
+ command('set nowrap lines=20 columns=20 virtualedit=all')
+ feed('100o<Esc>50G10|')
+ end)
+
+ it('handles invalid values', function()
+ should_fail('', invalid_arg) -- empty string
+ should_fail('foo:123', invalid_arg) -- unknown direction
+ should_fail('hor:1,hor:2', invalid_arg) -- duplicate direction
+ should_fail('ver:99999999999999999999', invalid_arg) -- integer overflow
+ should_fail('ver:bar', digit_expected) -- expected digit
+ should_fail('ver:-1', digit_expected) -- negative count
+ end)
+
+ it('handles valid values', function()
+ should_succeed('hor:1,ver:1') -- both directions set
+ should_succeed('hor:1') -- only horizontal
+ should_succeed('ver:1') -- only vertical
+ should_succeed('hor:0,ver:0') -- zero
+ should_succeed('hor:2147483647') -- large count
+ end)
+
+ it('default set correctly', function()
+ eq('ver:3,hor:6', eval('&mousescroll'))
+
+ eq(10, screenrow())
+ scroll('up')
+ eq(13, screenrow())
+ scroll('down')
+ eq(10, screenrow())
+
+ eq(10, screencol())
+ scroll('right')
+ eq(4, screencol())
+ scroll('left')
+ eq(10, screencol())
+ end)
+
+ it('vertical scrolling falls back to default value', function()
+ command('set mousescroll=hor:1')
+ eq(10, screenrow())
+ scroll('up')
+ eq(13, screenrow())
+ end)
+
+ it('horizontal scrolling falls back to default value', function()
+ command('set mousescroll=ver:1')
+ eq(10, screencol())
+ scroll('right')
+ eq(4, screencol())
+ end)
+
+ it('count of zero disables mouse scrolling', function()
+ command('set mousescroll=hor:0,ver:0')
+
+ eq(10, screenrow())
+ scroll('up')
+ eq(10, screenrow())
+ scroll('down')
+ eq(10, screenrow())
+
+ eq(10, screencol())
+ scroll('right')
+ eq(10, screencol())
+ scroll('left')
+ eq(10, screencol())
+ end)
+
+ local test_vertical_scrolling = function()
+ eq(10, screenrow())
+
+ command('set mousescroll=ver:1')
+ scroll('up')
+ eq(11, screenrow())
+
+ command('set mousescroll=ver:2')
+ scroll('down')
+ eq(9, screenrow())
+
+ command('set mousescroll=ver:5')
+ scroll('up')
+ eq(14, screenrow())
+ end
+
+ it('controls vertical scrolling in normal mode', function()
+ test_vertical_scrolling()
+ end)
+
+ it('controls vertical scrolling in insert mode', function()
+ feed('i')
+ test_vertical_scrolling()
+ end)
+
+ local test_horizontal_scrolling = function()
+ eq(10, screencol())
+
+ command('set mousescroll=hor:1')
+ scroll('right')
+ eq(9, screencol())
+
+ command('set mousescroll=hor:3')
+ scroll('right')
+ eq(6, screencol())
+
+ command('set mousescroll=hor:2')
+ scroll('left')
+ eq(8, screencol())
+ end
+
+ it('controls horizontal scrolling in normal mode', function()
+ test_horizontal_scrolling()
+ end)
+
+ it('controls horizontal scrolling in insert mode', function()
+ feed('i')
+ test_horizontal_scrolling()
+ end)
+end)
diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua
index 4754c14f5b..f343e2da75 100644
--- a/test/functional/options/num_options_spec.lua
+++ b/test/functional/options/num_options_spec.lua
@@ -54,7 +54,7 @@ describe(':set validation', function()
should_fail('iminsert', 3, 'E474')
should_fail('imsearch', 3, 'E474')
should_fail('titlelen', -1, 'E487')
- should_fail('cmdheight', 0, 'E487')
+ should_fail('cmdheight', -1, 'E487')
should_fail('updatecount', -1, 'E487')
should_fail('textwidth', -1, 'E487')
should_fail('tabstop', 0, 'E487')
diff --git a/test/functional/options/pastetoggle_spec.lua b/test/functional/options/pastetoggle_spec.lua
index a1f86f73ff..40c14fa187 100644
--- a/test/functional/options/pastetoggle_spec.lua
+++ b/test/functional/options/pastetoggle_spec.lua
@@ -4,16 +4,14 @@ local clear = helpers.clear
local feed = helpers.feed
local command = helpers.command
local eq = helpers.eq
+local expect = helpers.expect
local eval = helpers.eval
+local insert = helpers.insert
+local meths = helpers.meths
local sleep = helpers.sleep
-local expect = helpers.expect
describe("'pastetoggle' option", function()
- before_each(function()
- clear()
- command('set nopaste')
- end)
-
+ before_each(clear)
it("toggles 'paste'", function()
command('set pastetoggle=a')
eq(0, eval('&paste'))
@@ -22,19 +20,71 @@ describe("'pastetoggle' option", function()
feed('j')
eq(1, eval('&paste'))
end)
+ describe("multiple key 'pastetoggle'", function()
+ before_each(function()
+ eq(0, eval('&paste'))
+ command('set timeoutlen=1 ttimeoutlen=10000')
+ end)
+ it('is waited for when chars are typed', function()
+ local pastetoggle = 'lllll'
+ command('set pastetoggle=' .. pastetoggle)
+ feed(pastetoggle:sub(0, 2))
+ -- sleep() for long enough that vgetorpeek() is gotten into, but short
+ -- enough that ttimeoutlen is not reached.
+ sleep(200)
+ feed(pastetoggle:sub(3, -1))
+ -- Need another key so that the vgetorpeek() function returns.
+ feed('j')
+ eq(1, eval('&paste'))
+ end)
+ it('is not waited for when there are no typed chars after mapped chars', function()
+ command('set pastetoggle=abc')
+ command('imap d a')
+ meths.feedkeys('id', 't', true)
+ -- sleep() for long enough that vgetorpeek() is gotten into, but short
+ -- enough that ttimeoutlen is not reached.
+ sleep(200)
+ feed('bc')
+ -- Need another key so that the vgetorpeek() function returns.
+ feed('j')
+ -- 'ttimeoutlen' should NOT apply
+ eq(0, eval('&paste'))
+ end)
- it('does not wait for timeout', function()
- command('set pastetoggle=abc')
- command('set ttimeoutlen=9999999')
- eq(0, eval('&paste'))
- -- n.b. need <esc> to return from vgetorpeek()
- feed('abc<esc>')
- eq(1, eval('&paste'))
- feed('ab')
- sleep(10)
- feed('c<esc>')
- expect('bc')
- eq(1, eval('&paste'))
+ it('is waited for when there are typed chars after mapped chars', function()
+ command('set pastetoggle=abc')
+ command('imap d a')
+ meths.feedkeys('idb', 't', true)
+ -- sleep() for long enough that vgetorpeek() is gotten into, but short
+ -- enough that ttimeoutlen is not reached.
+ sleep(200)
+ feed('c')
+ -- Need another key so that the vgetorpeek() function returns.
+ feed('j')
+ -- 'ttimeoutlen' should apply
+ eq(1, eval('&paste'))
+ end)
+
+ it('is waited for when there are typed chars after noremapped chars', function()
+ command('set pastetoggle=abc')
+ command('inoremap d a')
+ meths.feedkeys('idb', 't', true)
+ -- sleep() for long enough that vgetorpeek() is gotten into, but short
+ -- enough that ttimeoutlen is not reached.
+ sleep(200)
+ feed('c')
+ -- Need another key so that the vgetorpeek() function returns.
+ feed('j')
+ -- 'ttimeoutlen' should apply
+ eq(1, eval('&paste'))
+ end)
+ end)
+ it('does not interfere with character-find', function()
+ insert('foo,bar')
+ feed('0')
+ command('set pastetoggle=,sp')
+ feed('dt,')
+ expect(',bar')
end)
end)
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 37de5d0ce6..ba66117fb1 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -5,7 +5,7 @@ local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local curbuf_contents = helpers.curbuf_contents
local command = helpers.command
-local eq = helpers.eq
+local eq, neq = helpers.eq, helpers.neq
local getcompletion = helpers.funcs.getcompletion
describe(':checkhealth', function()
@@ -37,6 +37,7 @@ describe(':checkhealth', function()
eq('nvim', getcompletion('nvim', 'checkhealth')[1])
eq('provider', getcompletion('prov', 'checkhealth')[1])
eq('vim.lsp', getcompletion('vim.ls', 'checkhealth')[1])
+ neq('vim', getcompletion('^vim', 'checkhealth')[1]) -- should not complete vim.health
end)
end)
@@ -153,6 +154,10 @@ describe('health.vim', function()
## report 2
- OK: nothing to see here
+ test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
+ ========================================================================
+ - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
========================================================================
- ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
@@ -172,6 +177,16 @@ describe('health.vim', function()
]])
end)
+ it("... including empty reports", function()
+ command("checkhealth test_plug.submodule_empty")
+ helpers.expect([[
+
+ test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
+ ========================================================================
+ - ERROR: The healthcheck report for "test_plug.submodule_empty" plugin is empty.
+ ]])
+ end)
+
it("gracefully handles broken lua healthcheck", function()
command("checkhealth test_plug.submodule_failed")
local buf_lines = helpers.curbuf('get_lines', 0, -1, true)
@@ -228,5 +243,23 @@ describe('health.vim', function()
- ERROR: No healthcheck found for "non_existent_healthcheck" plugin.
]])
end)
+
+ it("does not use vim.health as a healtcheck", function()
+ -- vim.health is not a healthcheck
+ command("checkhealth vim")
+ helpers.expect([[
+ ERROR: No healthchecks found.]])
+ end)
+ end)
+end)
+
+describe(':checkhealth provider', function()
+ it("works correctly with a wrongly configured 'shell'", function()
+ clear()
+ command([[set shell=echo\ WRONG!!!]])
+ command('let g:loaded_perl_provider = 0')
+ command('let g:loaded_python3_provider = 0')
+ command('checkhealth provider')
+ eq(nil, string.match(curbuf_contents(), 'WRONG!!!'))
end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 1269a2350c..f73ffc29b0 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local exec_lua = helpers.exec_lua
local eq = helpers.eq
+local neq = require('test.helpers').neq
describe('vim.lsp.diagnostic', function()
local fake_uri
@@ -110,6 +111,7 @@ describe('vim.lsp.diagnostic', function()
}
]]
eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp)
+ eq(42, result[1].code)
eq(42, result[2].code)
eq({"foo", "bar"}, result[2].tags)
eq("Hello world", result[2].data)
@@ -219,12 +221,50 @@ describe('vim.lsp.diagnostic', function()
local diags = vim.diagnostic.get(diagnostic_bufnr)
vim.lsp.stop_client(client_id)
- vim.lsp._vim_exit_handler()
+ vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })
return diags
]], line)
eq(1, #result)
eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col)
eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col)
end)
+
+ it('does not create buffer on empty diagnostics', function()
+ local bufnr
+
+ -- No buffer is created without diagnostics
+ bufnr = exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = "file:///fake/uri2",
+ diagnostics = {},
+ }, {client_id=client_id})
+ return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
+ ]]
+ eq(bufnr, -1)
+
+ -- Create buffer on diagnostics
+ bufnr = exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = "file:///fake/uri2",
+ diagnostics = {
+ make_error('Diagnostic', 0, 0, 0, 0),
+ },
+ }, {client_id=client_id})
+ return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
+ ]]
+ neq(bufnr, -1)
+ eq(exec_lua([[return #vim.diagnostic.get(...)]], bufnr), 1)
+
+ -- Clear diagnostics after buffer was created
+ bufnr = exec_lua [[
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = "file:///fake/uri2",
+ diagnostics = {},
+ }, {client_id=client_id})
+ return vim.fn.bufnr(vim.uri_to_fname("file:///fake/uri2"))
+ ]]
+ neq(bufnr, -1)
+ eq(exec_lua([[return #vim.diagnostic.get(...)]], bufnr), 0)
+ end)
end)
end)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 4e3eddb960..4985da9cd7 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -207,16 +207,16 @@ describe('incremental synchronization', function()
{
range = {
['start'] = {
- character = 0,
- line = 1
+ character = 11,
+ line = 0,
},
['end'] = {
character = 0,
line = 1
}
},
- rangeLength = 0,
- text = 'hello world\n'
+ rangeLength = 1,
+ text = '\nhello world\n'
}
}
test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n')
@@ -226,19 +226,57 @@ describe('incremental synchronization', function()
{
range = {
['start'] = {
+ character = 11,
+ line = 0
+ },
+ ['end'] = {
character = 0,
line = 1
+ }
+ },
+ rangeLength = 1,
+ text = '\n\n'
+ }
+ }
+ test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('adding a line to an empty buffer', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
},
['end'] = {
character = 0,
line = 1
}
},
+ rangeLength = 1,
+ text = '\n\n'
+ }
+ }
+ test_edit({""}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('insert a line above the current line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
+ },
+ ['end'] = {
+ character = 0,
+ line = 0
+ }
+ },
rangeLength = 0,
text = '\n'
}
}
- test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ test_edit({""}, {"O"}, expected_text_changes, 'utf-16', '\n')
end)
end)
describe('multi line edit', function()
diff --git a/test/functional/plugin/lsp/snippet_spec.lua b/test/functional/plugin/lsp/snippet_spec.lua
index 4e127743eb..7903885420 100644
--- a/test/functional/plugin/lsp/snippet_spec.lua
+++ b/test/functional/plugin/lsp/snippet_spec.lua
@@ -19,9 +19,9 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
- esc = 'TE$}XT'
- }
- }
+ esc = 'TE$}XT',
+ },
+ },
}, parse('TE\\$\\}XT'))
end)
@@ -36,8 +36,8 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TABSTOP,
tabstop = 2,
- }
- }
+ },
+ },
}, parse('$1${2}'))
end)
@@ -56,7 +56,7 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
- esc = 'TE$}XT'
+ esc = 'TE$}XT',
},
{
type = snippet.NodeType.TABSTOP,
@@ -73,21 +73,21 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.FORMAT,
capture_index = 1,
- modifier = 'upcase'
- }
- }
+ modifier = 'upcase',
+ },
+ },
},
},
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
- esc = 'TE$}XT'
+ esc = 'TE$}XT',
},
- }
- }
- }
+ },
+ },
+ },
},
- }
+ },
}, parse('${1:${2:TE\\$\\}XT$3${1/regex/${1:/upcase}/i}TE\\$\\}XT}}'))
end)
@@ -110,8 +110,8 @@ describe('vim.lsp._snippet', function()
{
type = snippet.NodeType.TABSTOP,
tabstop = 1,
- }
- }
+ },
+ },
},
{
type = snippet.NodeType.VARIABLE,
@@ -124,11 +124,11 @@ describe('vim.lsp._snippet', function()
type = snippet.NodeType.FORMAT,
capture_index = 1,
modifier = 'upcase',
- }
- }
- }
+ },
+ },
+ },
},
- }
+ },
}, parse('$VAR${VAR}${VAR:$1}${VAR/regex/${1:/upcase}/}'))
end)
@@ -141,12 +141,96 @@ describe('vim.lsp._snippet', function()
tabstop = 1,
items = {
',',
- '|'
- }
- }
- }
+ '|',
+ },
+ },
+ },
}, parse('${1|\\,,\\||}'))
end)
-end)
+ it('should parse format', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.VARIABLE,
+ name = 'VAR',
+ transform = {
+ type = snippet.NodeType.TRANSFORM,
+ pattern = 'regex',
+ format = {
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ modifier = 'upcase',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ if_text = 'if_text',
+ else_text = '',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ if_text = '',
+ else_text = 'else_text',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ else_text = 'else_text',
+ if_text = 'if_text',
+ },
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ if_text = '',
+ else_text = 'else_text',
+ },
+ },
+ },
+ },
+ },
+ }, parse('${VAR/regex/${1:/upcase}${1:+if_text}${1:-else_text}${1:?if_text:else_text}${1:else_text}/}'))
+ end)
+ it('should parse empty strings', function()
+ eq({
+ children = {
+ {
+ children = { {
+ esc = '',
+ raw = '',
+ type = 7,
+ } },
+ tabstop = 1,
+ type = 2,
+ },
+ {
+ esc = ' ',
+ raw = ' ',
+ type = 7,
+ },
+ {
+ name = 'VAR',
+ transform = {
+ format = {
+ {
+ capture_index = 1,
+ else_text = '',
+ if_text = '',
+ type = 6,
+ },
+ },
+ option = 'g',
+ pattern = 'erg',
+ type = 5,
+ },
+ type = 3,
+ },
+ },
+ type = 0,
+ }, parse('${1:} ${VAR/erg/${1:?:}/g}'))
+ end)
+end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 7ad1a52fe3..c166982052 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -18,6 +18,7 @@ local NIL = helpers.NIL
local read_file = require('test.helpers').read_file
local write_file = require('test.helpers').write_file
local isCI = helpers.isCI
+local meths = helpers.meths
-- Use these to get access to a coroutine so that I can run async tests and use
-- yield.
@@ -44,10 +45,10 @@ local function clear_notrace()
end
-local function fake_lsp_server_setup(test_name, timeout_ms, options)
+local function fake_lsp_server_setup(test_name, timeout_ms, options, settings)
exec_lua([=[
lsp = require('vim.lsp')
- local test_name, fixture_filename, logfile, timeout, options = ...
+ local test_name, fixture_filename, logfile, timeout, options, settings = ...
TEST_RPC_CLIENT_ID = lsp.start_client {
cmd_env = {
NVIM_LOG_FILE = logfile;
@@ -78,17 +79,18 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options)
allow_incremental_sync = options.allow_incremental_sync or false;
debounce_text_changes = options.debounce_text_changes or 0;
};
+ settings = settings;
on_exit = function(...)
vim.rpcnotify(1, "exit", ...)
end;
}
- ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {})
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile, timeout_ms or 1e3, options or {}, settings or {})
end
local function test_rpc_server(config)
if config.test_name then
clear_notrace()
- fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options)
+ fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options, config.settings)
end
local client = setmetatable({}, {
__index = function(_, name)
@@ -135,7 +137,7 @@ local function test_rpc_server(config)
end
stop()
if config.test_name then
- exec_lua("lsp._vim_exit_handler()")
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
end
end
@@ -170,7 +172,7 @@ describe('LSP', function()
end)
after_each(function()
- exec_lua("lsp._vim_exit_handler()")
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
-- exec_lua("lsp.stop_all_clients(true)")
end)
@@ -221,11 +223,33 @@ describe('LSP', function()
end)
end)
+ describe('lsp._cmd_parts test', function()
+ local function _cmd_parts(input)
+ return exec_lua([[
+ lsp = require('vim.lsp')
+ return lsp._cmd_parts(...)
+ ]], input)
+ end
+ it('should valid cmd argument', function()
+ eq(true, pcall(_cmd_parts, {"nvim"}))
+ eq(true, pcall(_cmd_parts, {"nvim", "--head"}))
+ end)
+
+ it('should invalid cmd argument', function()
+ eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
+ pcall_err(_cmd_parts, 'nvim'))
+ eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
+ pcall_err(_cmd_parts, {'nvim', 1}))
+ end)
+ end)
+end)
+
+describe('LSP', function()
describe('basic_init test', function()
after_each(function()
stop()
- exec_lua("lsp.stop_client(lsp.get_active_clients())")
- exec_lua("lsp._vim_exit_handler()")
+ exec_lua("lsp.stop_client(lsp.get_active_clients(), true)")
+ exec_lua("vim.api.nvim_exec_autocmds('VimLeavePre', { modeline = false })")
end)
it('should run correctly', function()
@@ -242,8 +266,8 @@ describe('LSP', function()
end;
-- If the program timed out, then code will be nil.
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
-- Note that NIL must be used here.
-- on_handler(err, method, result, client_id)
@@ -264,8 +288,8 @@ describe('LSP', function()
client.stop()
end;
on_exit = function(code, signal)
- eq(101, code, "exit code", fake_lsp_logfile) -- See fake-lsp-server.lua
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(101, code, "exit code") -- See fake-lsp-server.lua
+ eq(0, signal, "exit signal")
assert_log(pesc([[assert_eq failed: left == "\"shutdown\"", right == "\"test\""]]),
fake_lsp_logfile)
end;
@@ -275,6 +299,22 @@ describe('LSP', function()
}
end)
+ it('should send didChangeConfiguration after initialize if there are settings', function()
+ test_rpc_server({
+ test_name = 'basic_init_did_change_configuration',
+ on_init = function(client, _)
+ client.stop()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, 'exit code', fake_lsp_logfile)
+ eq(0, signal, 'exit signal', fake_lsp_logfile)
+ end,
+ settings = {
+ dummy = 1,
+ },
+ })
+ end)
+
it('should succeed with manual shutdown', function()
if isCI() then
pending('hangs the build on CI #14028, re-enable with freeze timeout #14204')
@@ -289,14 +329,14 @@ describe('LSP', function()
test_rpc_server {
test_name = "basic_init";
on_init = function(client)
- eq(0, client.resolved_capabilities().text_document_did_change)
+ eq(0, client.server_capabilities().textDocumentSync.change)
client.request('shutdown')
client.notify('exit')
client.stop()
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -327,8 +367,8 @@ describe('LSP', function()
client.notify('finish')
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -341,12 +381,51 @@ describe('LSP', function()
}
end)
+ it('should fire autocommands on attach and detach', function()
+ local client
+ test_rpc_server {
+ test_name = "basic_init";
+ on_setup = function()
+ exec_lua [[
+ BUFFER = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_create_autocmd('LspAttach', {
+ callback = function(args)
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ vim.g.lsp_attached = client.name
+ end,
+ })
+ vim.api.nvim_create_autocmd('LspDetach', {
+ callback = function(args)
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+ vim.g.lsp_detached = client.name
+ end,
+ })
+ ]]
+ end;
+ on_init = function(_client)
+ client = _client
+ eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)"))
+ client.notify('finish')
+ end;
+ on_handler = function(_, _, ctx)
+ if ctx.method == 'finish' then
+ eq('basic_init', meths.get_var('lsp_attached'))
+ exec_lua("return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)")
+ eq('basic_init', meths.get_var('lsp_detached'))
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('client should return settings via workspace/configuration handler', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
{NIL, { items = {
{ section = "testSetting1" };
{ section = "testSetting2" };
+ { section = "test.Setting3" };
+ { section = "test.Setting4" };
}}, { method="workspace/configuration", client_id=1}};
{NIL, {}, {method="start", client_id=1}};
}
@@ -357,8 +436,8 @@ describe('LSP', function()
client = _client
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -368,6 +447,7 @@ describe('LSP', function()
client.config.settings = {
testSetting1 = true;
testSetting2 = false;
+ test = {Setting3 = 'nested' };
}]=])
end
if ctx.method == 'workspace/configuration' then
@@ -383,16 +463,23 @@ describe('LSP', function()
}
end)
it('workspace/configuration returns NIL per section if client was started without config.settings', function()
- fake_lsp_server_setup('workspace/configuration no settings')
- eq({ NIL, NIL, }, exec_lua [[
- local result = {
- items = {
- {section = 'foo'},
- {section = 'bar'},
- }
- }
- return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
- ]])
+ local result = nil
+ test_rpc_server {
+ test_name = 'basic_init';
+ on_init = function(c) c.stop() end,
+ on_setup = function()
+ result = exec_lua [[
+ local result = {
+ items = {
+ {section = 'foo'},
+ {section = 'bar'},
+ }
+ }
+ return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
+ ]]
+ end
+ }
+ eq({ NIL, NIL }, result)
end)
it('should verify capabilities sent', function()
@@ -404,14 +491,13 @@ describe('LSP', function()
on_init = function(client)
client.stop()
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_save)
- eq(false, client.resolved_capabilities().code_lens)
- eq(false, client.resolved_capabilities().code_lens_resolve)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq({includeText = false}, client.server_capabilities().textDocumentSync.save)
+ eq(false, client.server_capabilities().codeLensProvider)
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -419,6 +505,67 @@ describe('LSP', function()
}
end)
+ it('BufWritePost sends didSave with bool textDocumentSync.save', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "text_document_sync_save_bool";
+ on_init = function(c)
+ client = c
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end;
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == "start" then
+ exec_lua([=[
+ BUFFER = vim.api.nvim_get_current_buf()
+ lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
+ ]=])
+ else
+ client.stop()
+ end
+ end;
+ }
+ end)
+
+ it('BufWritePost sends didSave including text if server capability is set', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "text_document_sync_save_includeText";
+ on_init = function(c)
+ client = c
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end;
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == "start" then
+ exec_lua([=[
+ BUFFER = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(BUFFER, 0, -1, true, {"help me"})
+ lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
+ vim.api.nvim_exec_autocmds('BufWritePost', { buffer = BUFFER, modeline = false })
+ ]=])
+ else
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('client.supports_methods() should validate capabilities', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
@@ -427,14 +574,19 @@ describe('LSP', function()
test_name = "capabilities_for_client_supports_method";
on_init = function(client)
client.stop()
- local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().completion)
- eq(true, client.resolved_capabilities().hover)
- eq(false, client.resolved_capabilities().goto_definition)
- eq(false, client.resolved_capabilities().rename)
- eq(true, client.resolved_capabilities().code_lens)
- eq(true, client.resolved_capabilities().code_lens_resolve)
+ local expected_sync_capabilities = {
+ change = 1,
+ openClose = true,
+ save = { includeText = false },
+ willSave = false,
+ willSaveWaitUntil = false,
+ }
+ eq(expected_sync_capabilities, client.server_capabilities().textDocumentSync)
+ eq(true, client.server_capabilities().completionProvider)
+ eq(true, client.server_capabilities().hoverProvider)
+ eq(false, client.server_capabilities().definitionProvider)
+ eq(false, client.server_capabilities().renameProvider)
+ eq(true, client.server_capabilities().codeLensProvider.resolveProvider)
-- known methods for resolved capabilities
eq(true, client.supports_method("textDocument/hover"))
@@ -444,8 +596,8 @@ describe('LSP', function()
eq(true, client.supports_method("unknown-method"))
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -474,8 +626,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -499,8 +651,8 @@ describe('LSP', function()
exec_lua("vim.lsp.buf.type_definition()")
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(...)
eq(table.remove(expected_handlers), {...}, "expected handler")
@@ -520,8 +672,8 @@ describe('LSP', function()
client = _client
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ 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)
@@ -544,8 +696,8 @@ describe('LSP', function()
client = _client
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ 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)
@@ -574,8 +726,8 @@ describe('LSP', function()
client.notify("release")
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ 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)
@@ -607,8 +759,8 @@ describe('LSP', function()
client.notify("release")
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ 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)
@@ -641,8 +793,8 @@ describe('LSP', function()
client.notify("release")
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ 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)
@@ -676,8 +828,8 @@ describe('LSP', function()
client.notify("release")
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
eq(0, #expected_handlers, "did not call expected handler")
eq(3, eval('g:requests'))
end;
@@ -717,13 +869,13 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
client.notify('finish')
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -758,15 +910,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(not lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID), "Shouldn't attach twice")
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -801,15 +953,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -844,15 +996,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -893,15 +1045,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local full_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(full_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(full_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -944,15 +1096,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(sync_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -995,15 +1147,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(sync_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -1044,15 +1196,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Incremental")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(sync_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -1088,15 +1240,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(sync_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
if ctx.method == 'start' then
@@ -1139,15 +1291,15 @@ describe('LSP', function()
on_init = function(_client)
client = _client
local sync_kind = exec_lua("return require'vim.lsp.protocol'.TextDocumentSyncKind.Full")
- eq(sync_kind, client.resolved_capabilities().text_document_did_change)
- eq(true, client.resolved_capabilities().text_document_open_close)
+ eq(sync_kind, client.server_capabilities().textDocumentSync.change)
+ eq(true, client.server_capabilities().textDocumentSync.openClose)
exec_lua [[
assert(lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID))
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result,ctx)
if ctx.method == 'start' then
@@ -1188,8 +1340,8 @@ describe('LSP', function()
client.stop(true)
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -1227,8 +1379,8 @@ describe('LSP', function()
]]
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
@@ -1239,25 +1391,6 @@ describe('LSP', function()
}
end)
end)
- describe('lsp._cmd_parts test', function()
- local function _cmd_parts(input)
- return exec_lua([[
- lsp = require('vim.lsp')
- return lsp._cmd_parts(...)
- ]], input)
- end
- it('should valid cmd argument', function()
- eq(true, pcall(_cmd_parts, {"nvim"}))
- eq(true, pcall(_cmd_parts, {"nvim", "--head"}))
- end)
-
- it('should invalid cmd argument', function()
- eq('Error executing lua: .../lsp.lua:0: cmd: expected list, got nvim',
- pcall_err(_cmd_parts, 'nvim'))
- eq('Error executing lua: .../lsp.lua:0: cmd argument: expected string, got number',
- pcall_err(_cmd_parts, {'nvim', 1}))
- end)
- end)
end)
describe('LSP', function()
@@ -1291,7 +1424,7 @@ describe('LSP', function()
make_edit(2, 0, 2, 2, {"3"});
make_edit(3, 2, 3, 4, {""});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'123First line of text';
'2econd line of text';
@@ -1311,7 +1444,7 @@ describe('LSP', function()
make_edit(3, #'', 3, #"Fourth", {"another line of text", "before this"});
make_edit(3, #'Fourth', 3, #"Fourth line of text", {"!"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'';
'123';
@@ -1335,7 +1468,7 @@ describe('LSP', function()
make_edit(3, #"Fourth", 3, #'', {"another line of text", "before this"});
make_edit(3, #"Fourth line of text", 3, #'Fourth', {"!"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'';
'123';
@@ -1352,7 +1485,7 @@ describe('LSP', function()
local edits = {
make_edit(4, 3, 4, 4, {"ä"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1365,7 +1498,7 @@ describe('LSP', function()
local edits = {
make_edit(5, 0, 5, 0, "foobar");
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1375,6 +1508,20 @@ describe('LSP', function()
'foobar';
}, buf_lines(1))
end)
+ it('applies multiple text edits at the end of the document', function()
+ local edits = {
+ make_edit(4, 0, 5, 0, "");
+ make_edit(5, 0, 5, 0, "foobar");
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
+ eq({
+ 'First line of text';
+ 'Second line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'foobar';
+ }, buf_lines(1))
+ end)
describe('cursor position', function()
it('don\'t fix the cursor if the range contains the cursor', function()
@@ -1382,7 +1529,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 0, 1, 19, 'Second line of text')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second line of text';
@@ -1399,7 +1546,7 @@ describe('LSP', function()
make_edit(1, 0, 1, 6, ''),
make_edit(1, 6, 1, 19, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'';
@@ -1416,7 +1563,7 @@ describe('LSP', function()
make_edit(1, 0, 1, 6, ''),
make_edit(0, 18, 5, 0, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
}, buf_lines(1))
@@ -1428,7 +1575,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 0, 2, 0, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Third line of text';
@@ -1443,7 +1590,7 @@ describe('LSP', function()
local edits = {
make_edit(1, 7, 1, 11, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Second of text';
@@ -1459,7 +1606,7 @@ describe('LSP', function()
local edits = {
make_edit(0, 11, 1, 12, '')
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({
'First line of text';
'Third line of text';
@@ -1475,21 +1622,21 @@ describe('LSP', function()
local edits = {
make_edit(0, 0, 5, 0, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
it('applies edits when the end line is 2 larger than vim\'s', function()
local edits = {
make_edit(0, 0, 6, 0, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
it('applies edits with a column offset', function()
local edits = {
make_edit(0, 0, 5, 2, {"All replaced"});
}
- exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-16")
eq({'All replaced'}, buf_lines(1))
end)
end)
@@ -1517,7 +1664,7 @@ describe('LSP', function()
]]
end)
it('correctly goes ahead with the edit if all is normal', function()
- exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(5))
+ exec_lua("vim.lsp.util.apply_text_document_edit(..., nil, 'utf-16')", text_document_edit(5))
eq({
'First ↥ 🤦 🦄 line of text';
'2nd line of 语text';
@@ -1529,7 +1676,7 @@ describe('LSP', function()
local bufnr = select(1, ...)
local text_edit = select(2, ...)
vim.lsp.util.buf_versions[bufnr] = 10
- vim.lsp.util.apply_text_document_edit(text_edit)
+ vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16')
]], target_bufnr, text_document_edit(0))
eq({
'First ↥ 🤦 🦄 line of text';
@@ -1542,7 +1689,7 @@ describe('LSP', function()
local args = {...}
local versionedBuf = args[2]
vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion
- vim.lsp.util.apply_text_document_edit(args[1])
+ vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16')
]], edit, versionedBuf)
end
@@ -1568,17 +1715,36 @@ describe('LSP', function()
describe('workspace_apply_edit', function()
it('workspace/applyEdit returns ApplyWorkspaceEditResponse', function()
- local expected = {
- applied = true;
- failureReason = nil;
+ local expected_handlers = {
+ {NIL, {}, {method="test", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = "basic_init";
+ on_init = function(client, _)
+ client.stop()
+ end;
+ -- If the program timed out, then code will be nil.
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end;
+ -- Note that NIL must be used here.
+ -- on_handler(err, method, result, client_id)
+ on_handler = function(...)
+ local expected = {
+ applied = true;
+ failureReason = nil;
+ }
+ eq(expected, exec_lua [[
+ local apply_edit = {
+ label = nil;
+ edit = {};
+ }
+ return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit, {client_id = TEST_RPC_CLIENT_ID})
+ ]])
+ eq(table.remove(expected_handlers), {...})
+ end;
}
- eq(expected, exec_lua [[
- local apply_edit = {
- label = nil;
- edit = {};
- }
- return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit)
- ]])
end)
end)
@@ -1652,7 +1818,7 @@ describe('LSP', function()
local workspace_edits = args[1]
local target_bufnr = args[2]
- vim.lsp.util.apply_workspace_edit(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
]], make_workspace_edit(edits), target_bufnr))
@@ -1674,7 +1840,7 @@ describe('LSP', function()
local workspace_edits = args[1]
local target_bufnr = args[2]
- vim.lsp.util.apply_workspace_edit(workspace_edits)
+ vim.lsp.util.apply_workspace_edit(workspace_edits, 'utf-16')
return vim.api.nvim_buf_get_lines(target_bufnr, 0, -1, false)
]], make_workspace_edit(edits), target_bufnr))
@@ -1691,7 +1857,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
end)
it('createFile does not touch file if it exists and ignoreIfExists is set', function()
@@ -1709,7 +1875,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq('Dummy content', read_file(tmpfile))
end)
@@ -1729,7 +1895,7 @@ describe('LSP', function()
},
}
}
- exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit)
+ exec_lua('vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')
eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq('', read_file(tmpfile))
end)
@@ -1750,7 +1916,7 @@ describe('LSP', function()
}
}
}
- eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit))
+ eq(true, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16'))
eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', tmpfile))
eq(false, exec_lua('return vim.api.nvim_buf_is_loaded(vim.fn.bufadd(...))', tmpfile))
end)
@@ -1911,7 +2077,7 @@ describe('LSP', function()
}
},
}
- return vim.lsp.util.locations_to_items(locations)
+ return vim.lsp.util.locations_to_items(locations, 'utf-16')
]]
eq(expected, actual)
end)
@@ -1941,7 +2107,7 @@ describe('LSP', function()
}
},
}
- return vim.lsp.util.locations_to_items(locations)
+ return vim.lsp.util.locations_to_items(locations, 'utf-16')
]]
eq(expected, actual)
end)
@@ -2245,7 +2411,7 @@ describe('LSP', function()
end
local jump = function(msg)
- eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg))
+ eq(true, exec_lua('return vim.lsp.util.jump_to_location(...)', msg, "utf-16"))
eq(target_bufnr, exec_lua[[return vim.fn.bufnr('%')]])
return {
line = exec_lua[[return vim.fn.line('.')]],
@@ -2319,19 +2485,38 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.convert_signature_help_to_markdown_lines', function()
+ it('can handle negative activeSignature', function()
+ local result = exec_lua[[
+ local signature_help = {
+ activeParameter = 0,
+ activeSignature = -1,
+ signatures = {
+ {
+ documentation = "",
+ label = "TestEntity.TestEntity()",
+ parameters = {}
+ },
+ }
+ }
+ return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'cs', {','})
+ ]]
+ local expected = {'```cs', 'TestEntity.TestEntity()', '```', ''}
+ eq(expected, result)
+ end)
+ end)
+
describe('lsp.util.get_effective_tabstop', function()
- local function test_tabstop(tabsize, softtabstop)
+ local function test_tabstop(tabsize, shiftwidth)
exec_lua(string.format([[
- vim.api.nvim_buf_set_option(0, 'softtabstop', %d)
+ vim.api.nvim_buf_set_option(0, 'shiftwidth', %d)
vim.api.nvim_buf_set_option(0, 'tabstop', 2)
- vim.api.nvim_buf_set_option(0, 'shiftwidth', 3)
- ]], softtabstop))
+ ]], shiftwidth))
eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()'))
end
- it('with softtabstop = 1', function() test_tabstop(1, 1) end)
- it('with softtabstop = 0', function() test_tabstop(2, 0) end)
- it('with softtabstop = -1', function() test_tabstop(3, -1) end)
+ it('with shiftwidth = 1', function() test_tabstop(1, 1) end)
+ it('with shiftwidth = 0', function() test_tabstop(2, 0) end)
end)
describe('vim.lsp.buf.outgoing_calls', function()
@@ -2516,10 +2701,8 @@ describe('LSP', function()
name = "prepare_rename_error",
expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
- {NIL, NIL, {method="textDocument/rename", client_id=1, bufnr=1}};
{NIL, {}, {method="start", client_id=1}};
},
- expected_text = "two", -- see test case
},
}) do
it(test.it, function()
@@ -2528,7 +2711,7 @@ describe('LSP', function()
test_name = test.name;
on_init = function(_client)
client = _client
- eq(true, client.resolved_capabilities().rename)
+ eq(true, client.server_capabilities().renameProvider.prepareProvider)
end;
on_setup = function()
exec_lua([=[
@@ -2545,8 +2728,8 @@ describe('LSP', function()
]=])
end;
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end;
on_handler = function(err, result, ctx)
-- Don't compare & assert params, they're not relevant for the testcase
@@ -2585,8 +2768,8 @@ describe('LSP', function()
on_setup = function()
end,
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end,
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx})
@@ -2610,6 +2793,102 @@ describe('LSP', function()
end
}
end)
+ it('Calls workspace/executeCommand if no client side command', function()
+ local client
+ local expected_handlers = {
+ { NIL, {}, { method = 'shutdown', client_id = 1 } },
+ {
+ NIL,
+ { command = 'dummy1', title = 'Command 1' },
+ { bufnr = 1, method = 'workspace/executeCommand', client_id = 1 },
+ },
+ { NIL, {}, { method = 'start', client_id = 1 } },
+ }
+ test_rpc_server({
+ test_name = 'code_action_server_side_command',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function() end,
+ on_exit = function(code, signal)
+ eq(0, code, 'exit code', fake_lsp_logfile)
+ eq(0, signal, 'exit signal', fake_lsp_logfile)
+ end,
+ on_handler = function(err, result, ctx)
+ ctx.params = nil -- don't compare in assert
+ eq(table.remove(expected_handlers), { err, result, ctx })
+ if ctx.method == 'start' then
+ exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.fn.inputlist = function()
+ return 1
+ end
+ vim.lsp.buf.code_action()
+ ]])
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end,
+ })
+ end)
+ it('Filters and automatically applies action if requested', function()
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'code_action_filter',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end,
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx})
+ if ctx.method == 'start' then
+ exec_lua([[
+ vim.lsp.commands['preferred_command'] = function(cmd)
+ vim.lsp.commands['executed_preferred'] = function()
+ end
+ end
+ vim.lsp.commands['quickfix_command'] = function(cmd)
+ vim.lsp.commands['executed_quickfix'] = function()
+ end
+ end
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, })
+ vim.lsp.buf.code_action({
+ -- expect to be returned actions 'quickfix' and 'quickfix.foo'
+ context = { only = {'quickfix'}, },
+ apply = true,
+ filter = function(a)
+ if a.kind == 'quickfix.foo' then
+ vim.lsp.commands['filtered_quickfix_foo'] = function() end
+ return false
+ elseif a.kind == 'quickfix' then
+ return true
+ else
+ assert(nil, 'unreachable')
+ end
+ end,
+ })
+ ]])
+ elseif ctx.method == 'shutdown' then
+ eq('function', exec_lua[[return type(vim.lsp.commands['executed_preferred'])]])
+ eq('function', exec_lua[[return type(vim.lsp.commands['filtered_quickfix_foo'])]])
+ eq('function', exec_lua[[return type(vim.lsp.commands['executed_quickfix'])]])
+ client.stop()
+ end
+ end
+ }
+ end)
end)
describe('vim.lsp.commands', function()
it('Accepts only string keys', function()
@@ -2640,8 +2919,8 @@ describe('LSP', function()
on_setup = function()
end,
on_exit = function(code, signal)
- eq(0, code, "exit code", fake_lsp_logfile)
- eq(0, signal, "exit signal", fake_lsp_logfile)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
end,
on_handler = function(err, result, ctx)
eq(table.remove(expected_handlers), {err, result, ctx})
@@ -2677,5 +2956,189 @@ describe('LSP', function()
end
}
end)
+
+ it('releases buffer refresh lock', function()
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'codelens_refresh_lock',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function()
+ exec_lua([=[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+
+ CALLED = false
+ RESPONSE = nil
+ local on_codelens = vim.lsp.codelens.on_codelens
+ vim.lsp.codelens.on_codelens = function (err, result, ...)
+ CALLED = true
+ RESPONSE = { err = err, result = result }
+ return on_codelens(err, result, ...)
+ end
+ ]=])
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code")
+ eq(0, signal, "exit signal")
+ end,
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx})
+ if ctx.method == 'start' then
+ -- 1. first codelens request errors
+ local response = exec_lua([=[
+ CALLED = false
+ vim.lsp.codelens.refresh()
+ vim.wait(100, function () return CALLED end)
+ return RESPONSE
+ ]=])
+ eq( { err = { code = -32002, message = "ServerNotInitialized" } }, response)
+
+ -- 2. second codelens request runs
+ response = exec_lua([=[
+ CALLED = false
+ local cmd_called = nil
+ vim.lsp.commands["Dummy"] = function (command)
+ cmd_called = command
+ end
+ vim.lsp.codelens.refresh()
+ vim.wait(100, function () return CALLED end)
+ vim.lsp.codelens.run()
+ vim.wait(100, function () return cmd_called end)
+ return cmd_called
+ ]=])
+ eq( { command = "Dummy", title = "Lens1" }, response)
+
+ -- 3. third codelens request runs
+ response = exec_lua([=[
+ CALLED = false
+ local cmd_called = nil
+ vim.lsp.commands["Dummy"] = function (command)
+ cmd_called = command
+ end
+ vim.lsp.codelens.refresh()
+ vim.wait(100, function () return CALLED end)
+ vim.lsp.codelens.run()
+ vim.wait(100, function () return cmd_called end)
+ return cmd_called
+ ]=])
+ eq( { command = "Dummy", title = "Lens2" }, response)
+ elseif ctx.method == 'shutdown' then
+ client.stop()
+ end
+ end
+ }
+ end)
+ end)
+
+ describe("vim.lsp.buf.format", function()
+ it("Aborts with notify if no client matches filter", function()
+ local client
+ test_rpc_server {
+ test_name = "basic_init",
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function()
+ local notify_msg = exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ local notify_msg
+ local notify = vim.notify
+ vim.notify = function(msg, log_level)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({ name = 'does-not-exist' })
+ vim.notify = notify
+ return notify_msg
+ ]])
+ eq("[LSP] Format request failed, no matching language servers.", notify_msg)
+ client.stop()
+ end,
+ }
+ end)
+ it("Sends textDocument/formatting request to format buffer", function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "basic_formatting",
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == "start" then
+ local notify_msg = exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ local notify_msg
+ local notify = vim.notify
+ vim.notify = function(msg, log_level)
+ notify_msg = msg
+ end
+ vim.lsp.buf.format({ bufnr = bufnr })
+ vim.notify = notify
+ return notify_msg
+ ]])
+ eq(NIL, notify_msg)
+ elseif ctx.method == "shutdown" then
+ client.stop()
+ end
+ end,
+ }
+ end)
+ it('Can format async', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "basic_formatting",
+ on_init = function(c)
+ client = c
+ end,
+ on_handler = function(_, _, ctx)
+ table.remove(expected_handlers)
+ if ctx.method == "start" then
+ local result = exec_lua([[
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+
+ local notify_msg
+ local notify = vim.notify
+ vim.notify = function(msg, log_level)
+ notify_msg = msg
+ end
+
+ local handler = vim.lsp.handlers['textDocument/formatting']
+ local handler_called = false
+ vim.lsp.handlers['textDocument/formatting'] = function(...)
+ handler_called = true
+ end
+
+ vim.lsp.buf.format({ bufnr = bufnr, async = true })
+ vim.wait(1000, function() return handler_called end)
+
+ vim.notify = notify
+ vim.lsp.handlers['textDocument/formatting'] = handler
+ return {notify = notify_msg, handler_called = handler_called}
+ ]])
+ eq({handler_called=true}, result)
+ elseif ctx.method == "shutdown" then
+ client.stop()
+ end
+ end,
+ }
+ end)
end)
end)
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index e5b2e7dc1f..c8da5a711f 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -2,13 +2,19 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local command, eval, rawfeed = helpers.command, helpers.eval, helpers.rawfeed
local clear = helpers.clear
+local funcs = helpers.funcs
+local nvim_prog = helpers.nvim_prog
+local matches = helpers.matches
describe(':Man', function()
+ before_each(function()
+ clear()
+ end)
+
describe('man.lua: highlight_line()', function()
local screen
before_each(function()
- clear()
command('syntax on')
command('set filetype=man')
command('syntax off') -- Ignore syntax groups
@@ -137,4 +143,10 @@ describe(':Man', function()
]])
end)
end)
+
+ it('q quits in "$MANPAGER mode" (:Man!) #18281', function()
+ -- This will hang if #18281 regresses.
+ local args = {nvim_prog, '--headless', '+autocmd VimLeave * echo "quit works!!"', '+Man!', '+call nvim_input("q")'}
+ matches('quit works!!', funcs.system(args, {'manpage contents'}))
+ end)
end)
diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua
index 13e1283e2c..2670734c1a 100644
--- a/test/functional/plugin/matchparen_spec.lua
+++ b/test/functional/plugin/matchparen_spec.lua
@@ -27,7 +27,7 @@ describe('matchparen', function()
feed('{<cr>')
feed('}')
- -- critical part: up + cr should result in an empty line inbetween the
+ -- critical part: up + cr should result in an empty line in between the
-- brackets... if the bug is there, the empty line will be before the '{'
feed('<up>')
feed('<cr>')
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index a4d78682ad..6f22f865e6 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
-local eq, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
- helpers.eq, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
+local eq, meths, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
+ helpers.eq, helpers.meths, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
helpers.funcs, helpers.feed, helpers.curbuf
local neq = helpers.neq
local read_file = helpers.read_file
@@ -2162,6 +2162,10 @@ describe('plugin/shada.vim', function()
wshada('\004\000\009\147\000\196\002ab\196\001a')
wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
+
+ local bufread_commands = meths.get_autocmds({ group = "ShaDaCommands", event = "BufReadCmd" })
+ eq(2, #bufread_commands--[[, vim.inspect(bufread_commands) ]])
+
-- Need to set nohidden so that the buffer containing 'fname' is not unloaded
-- after loading 'fname_tmp', otherwise the '++opt not supported' test below
-- won't work since the BufReadCmd autocmd won't be triggered.
diff --git a/test/functional/preload.lua b/test/functional/preload.lua
index 24a3977e6b..74f03eaecf 100644
--- a/test/functional/preload.lua
+++ b/test/functional/preload.lua
@@ -1,8 +1,9 @@
--- Modules loaded here will not be cleared and reloaded by Busted.
+-- Modules loaded here will NOT be cleared and reloaded by Busted.
-- Busted started doing this to help provide more isolation. See issue #62
-- for more information about this.
local helpers = require('test.functional.helpers')(nil)
local iswin = helpers.iswin
+local busted = require("busted")
if iswin() then
local ffi = require('ffi')
@@ -12,3 +13,28 @@ if iswin() then
]]
ffi.C._set_fmode(0x8000)
end
+
+local testid = (function()
+ local id = 0
+ return (function()
+ id = id + 1
+ return id
+ end)
+end)()
+
+-- Global before_each. https://github.com/Olivine-Labs/busted/issues/613
+local function before_each(_element, _parent)
+ local id = ('T%d'):format(testid())
+ _G._nvim_test_id = id
+ return nil, true
+end
+busted.subscribe({ 'test', 'start' },
+ before_each,
+ {
+ -- Ensure our --helper is handled before --output (see busted/runner.lua).
+ priority = 1,
+ -- Don't generate a test-id for skipped tests. /shrug
+ predicate = function (element, _, status)
+ return not ((element.descriptor == 'pending' or status == 'pending'))
+ end
+ })
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 986db96a18..5bdfec574e 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -50,29 +50,33 @@ local function basic_register_test(noblock)
text, stuff and some more
some some text, stuff and some more]])
- -- deleting a word to named ("a) updates "1 (and not "-)
+ -- deleting a word to named ("a) doesn't update "1 or "-
feed('gg"adwj"1P^"-P')
expect([[
, stuff and some more
- some textsome some text, stuff and some more]])
+ some some random text
+ some some text, stuff and some more]])
-- deleting a line does update ""
feed('ggdd""P')
expect([[
, stuff and some more
- some textsome some text, stuff and some more]])
+ some some random text
+ some some text, stuff and some more]])
feed('ggw<c-v>jwyggP')
if noblock then
expect([[
stuf
- me t
+ me s
, stuff and some more
- some textsome some text, stuff and some more]])
+ some some random text
+ some some text, stuff and some more]])
else
expect([[
stuf, stuff and some more
- me tsome textsome some text, stuff and some more]])
+ me ssome some random text
+ some some text, stuff and some more]])
end
-- pasting in visual does unnamed delete of visual selection
diff --git a/test/functional/provider/nodejs_spec.lua b/test/functional/provider/nodejs_spec.lua
index 661a6f4f94..187f1c0412 100644
--- a/test/functional/provider/nodejs_spec.lua
+++ b/test/functional/provider/nodejs_spec.lua
@@ -29,7 +29,7 @@ describe('nodejs host', function()
local fname = 'Xtest-nodejs-hello.js'
write_file(fname, [[
const neovim = require('neovim');
- const nvim = neovim.attach({socket: process.env.NVIM_LISTEN_ADDRESS});
+ const nvim = neovim.attach({socket: process.env.NVIM});
nvim.command('let g:job_out = "hello"');
]])
command('let g:job_id = jobstart(["node", "'..fname..'"])')
@@ -39,7 +39,7 @@ describe('nodejs host', function()
local fname = 'Xtest-nodejs-hello-plugin.js'
write_file(fname, [[
const neovim = require('neovim');
- const nvim = neovim.attach({socket: process.env.NVIM_LISTEN_ADDRESS});
+ const nvim = neovim.attach({socket: process.env.NVIM});
class TestPlugin {
hello() {
diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua
index 125674660b..aff5e36e24 100644
--- a/test/functional/provider/perl_spec.lua
+++ b/test/functional/provider/perl_spec.lua
@@ -83,7 +83,7 @@ describe('perl provider', function()
use Neovim::Ext;
use Neovim::Ext::MsgPack::RPC;
- my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM_LISTEN_ADDRESS});
+ my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM});
my $nvim = Neovim::Ext::from_session($session);
$nvim->command('let g:job_out = "hello"');
1;
@@ -116,7 +116,7 @@ describe('perl provider', function()
use Neovim::Ext;
use Neovim::Ext::MsgPack::RPC;
- my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM_LISTEN_ADDRESS});
+ my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM});
my $nvim = Neovim::Ext::from_session($session);
my $plugin = TestPlugin->new($nvim);
$plugin->test_command();
diff --git a/test/functional/provider/provider_spec.lua b/test/functional/provider/provider_spec.lua
index 78bc4a4edb..3895b8613f 100644
--- a/test/functional/provider/provider_spec.lua
+++ b/test/functional/provider/provider_spec.lua
@@ -14,8 +14,8 @@ describe('providers', function()
command('set loadplugins')
-- Using test-fixture with broken impl:
-- test/functional/fixtures/autoload/provider/python.vim
- eq('Vim:provider: python: missing required variable g:loaded_python_provider',
- pcall_err(eval, "has('python')"))
+ eq('Vim:provider: python3: missing required variable g:loaded_python3_provider',
+ pcall_err(eval, "has('python3')"))
end)
it('with g:loaded_xx_provider, missing #Call()', function()
diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index d100db8de2..d9c44c3315 100644
--- a/test/functional/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -8,6 +8,8 @@ local source = helpers.source
local missing_provider = helpers.missing_provider
local matches = helpers.matches
local pcall_err = helpers.pcall_err
+local funcs = helpers.funcs
+local dedent = helpers.dedent
do
clear()
@@ -48,7 +50,12 @@ describe('python3 provider', function()
local very_long_symbol = string.rep('a', 1200)
feed_command(':silent! py3 print('..very_long_symbol..' b)')
-- Error message will contain this (last) line.
- eq('Error invoking \'python_execute\' on channel 3 (python3-script-host):\n File "<string>", line 1\n print('..very_long_symbol..' b)\n '..string.rep(' ',1200)..' ^\nSyntaxError: invalid syntax', eval('v:errmsg'))
+ matches(string.format(dedent([[
+ ^Error invoking 'python_execute' on channel 3 %%(python3%%-script%%-host%%):
+ File "<string>", line 1
+ print%%(%s b%%)
+ %%C*
+ SyntaxError: invalid syntax%%C*$]]), very_long_symbol), eval('v:errmsg'))
end)
it('python3_execute with nested commands', function()
@@ -93,16 +100,40 @@ describe('python3 provider', function()
ghi]])
end)
- it('py3eval', function()
- eq({1, 2, {['key'] = 'val'}}, eval([[py3eval('[1, 2, {"key": "val"}]')]]))
+ describe('py3eval()', function()
+ it('works', function()
+ eq({1, 2, {['key'] = 'val'}}, funcs.py3eval('[1, 2, {"key": "val"}]'))
+ end)
+
+ it('errors out when given non-string', function()
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(10)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:_null_dict)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:_null_list)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(0.0)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(function("tr"))'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:true)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:false)'))
+ eq('Vim:E474: Invalid argument', pcall_err(eval, 'py3eval(v:null)'))
+ end)
+
+ it('accepts NULL string', function()
+ matches('.*SyntaxError.*', pcall_err(eval, 'py3eval($XXX_NONEXISTENT_VAR_XXX)'))
+ end)
end)
it('pyxeval #10758', function()
- eq(0, eval([[&pyxversion]]))
+ eq(3, eval([[&pyxversion]]))
eq(3, eval([[pyxeval('sys.version_info[:3][0]')]]))
eq(3, eval([[&pyxversion]]))
end)
+ it("setting 'pyxversion'", function()
+ command 'set pyxversion=3' -- no error
+ eq('Vim(set):E474: Invalid argument: pyxversion=2', pcall_err(command, 'set pyxversion=2'))
+ command 'set pyxversion=0' -- allowed, but equivalent to pyxversion=3
+ eq(3, eval'&pyxversion')
+ end)
+
it('RPC call to expand("<afile>") during BufDelete #5245 #5617', function()
helpers.add_builddir_to_rtp()
source([=[
@@ -120,3 +151,15 @@ describe('python3 provider', function()
assert_alive()
end)
end)
+
+describe('python2 feature test', function()
+ -- python2 is not supported, so correct behaviour is to return 0
+ it('works', function()
+ eq(0, funcs.has('python2'))
+ eq(0, funcs.has('python'))
+ eq(0, funcs.has('python_compiled'))
+ eq(0, funcs.has('python_dynamic'))
+ eq(0, funcs.has('python_dynamic_'))
+ eq(0, funcs.has('python_'))
+ end)
+end)
diff --git a/test/functional/provider/python_spec.lua b/test/functional/provider/python_spec.lua
deleted file mode 100644
index d60d8d1001..0000000000
--- a/test/functional/provider/python_spec.lua
+++ /dev/null
@@ -1,123 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local eq = helpers.eq
-local neq = helpers.neq
-local feed = helpers.feed
-local clear = helpers.clear
-local funcs = helpers.funcs
-local meths = helpers.meths
-local insert = helpers.insert
-local expect = helpers.expect
-local command = helpers.command
-local exc_exec = helpers.exc_exec
-local write_file = helpers.write_file
-local curbufmeths = helpers.curbufmeths
-local missing_provider = helpers.missing_provider
-local matches = helpers.matches
-local pcall_err = helpers.pcall_err
-
-do
- clear()
- local reason = missing_provider('python')
- if reason then
- it(':python reports E319 if provider is missing', function()
- local expected = [[Vim%(py.*%):E319: No "python" provider found.*]]
- matches(expected, pcall_err(command, 'py print("foo")'))
- matches(expected, pcall_err(command, 'pyfile foo'))
- end)
- pending(string.format('Python 2 (or the pynvim module) is broken/missing (%s)', reason), function() end)
- return
- end
-end
-
-before_each(function()
- clear()
- command('python import vim')
-end)
-
-describe('python feature test', function()
- it('works', function()
- eq(1, funcs.has('python'))
- eq(1, funcs.has('python_compiled'))
- eq(1, funcs.has('python_dynamic'))
- eq(0, funcs.has('python_dynamic_'))
- eq(0, funcs.has('python_'))
- end)
-end)
-
-describe(':python command', function()
- it('works with a line', function()
- command('python vim.vars["set_by_python"] = [100, 0]')
- eq({100, 0}, meths.get_var('set_by_python'))
- end)
-
- -- TODO(ZyX-I): works with << EOF
- -- TODO(ZyX-I): works with execute 'python' line1."\n".line2."\n"…
-
- it('supports nesting', function()
- command([[python vim.command('python vim.command("python vim.command(\'let set_by_nested_python = 555\')")')]])
- eq(555, meths.get_var('set_by_nested_python'))
- end)
-
- it('supports range', function()
- insert([[
- line1
- line2
- line3
- line4]])
- feed('ggjvj:python vim.vars["range"] = vim.current.range[:]<CR>')
- eq({'line2', 'line3'}, meths.get_var('range'))
- end)
-end)
-
-describe(':pyfile command', function()
- it('works', function()
- local fname = 'pyfile.py'
- write_file(fname, 'vim.command("let set_by_pyfile = 123")')
- command('pyfile pyfile.py')
- eq(123, meths.get_var('set_by_pyfile'))
- os.remove(fname)
- end)
-end)
-
-describe(':pydo command', function()
- it('works', function()
- -- :pydo 42 returns None for all lines,
- -- the buffer should not be changed
- command('normal :pydo 42')
- eq(false, curbufmeths.get_option('modified'))
- -- insert some text
- insert('abc\ndef\nghi')
- expect([[
- abc
- def
- ghi]])
- -- go to top and select and replace the first two lines
- feed('ggvj:pydo return str(linenr)<CR>')
- expect([[
- 1
- 2
- ghi]])
- end)
-end)
-
-describe('pyeval()', function()
- it('works', function()
- eq({1, 2, {['key'] = 'val'}}, funcs.pyeval('[1, 2, {"key": "val"}]'))
- end)
-
- it('errors out when given non-string', function()
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(10)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:_null_dict)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:_null_list)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(0.0)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(function("tr"))'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:true)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:false)'))
- eq('Vim(call):E474: Invalid argument', exc_exec('call pyeval(v:null)'))
- end)
-
- it('accepts NULL string', function()
- neq(0, exc_exec('call pyeval($XXX_NONEXISTENT_VAR_XXX)'))
- end)
-end)
diff --git a/test/functional/shada/buffers_spec.lua b/test/functional/shada/buffers_spec.lua
index 04c9c01d7c..26a4569fce 100644
--- a/test/functional/shada/buffers_spec.lua
+++ b/test/functional/shada/buffers_spec.lua
@@ -2,6 +2,7 @@
local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, eq, curbufmeths =
helpers.command, helpers.funcs, helpers.eq, helpers.curbufmeths
+local expect_exit = helpers.expect_exit
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -15,7 +16,7 @@ describe('shada support code', function()
reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada+=%')
eq(3, funcs.bufnr('$'))
eq('', funcs.bufname(1))
@@ -27,7 +28,7 @@ describe('shada support code', function()
reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
@@ -37,7 +38,7 @@ describe('shada support code', function()
reset()
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada+=%')
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
@@ -48,7 +49,7 @@ describe('shada support code', function()
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
curbufmeths.set_option('buflisted', false)
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada+=%')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
@@ -60,7 +61,7 @@ describe('shada support code', function()
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
curbufmeths.set_option('buftype', 'quickfix')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada+=%')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
@@ -73,7 +74,7 @@ describe('shada support code', function()
nvim_command('enew')
curbufmeths.set_lines(0, 1, true, {'bar'})
eq(2, funcs.bufnr('$'))
- nvim_command('qall!')
+ expect_exit(nvim_command, 'qall!')
reset('set shada+=% hidden')
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
@@ -83,7 +84,7 @@ describe('shada support code', function()
reset('set shada+=%1')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada+=%1')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua
index 84cc34c7cc..d1daf6c7cc 100644
--- a/test/functional/shada/history_spec.lua
+++ b/test/functional/shada/history_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, meths, nvim_feed, eq =
helpers.command, helpers.funcs, helpers.meths, helpers.feed, helpers.eq
local assert_alive = helpers.assert_alive
+local expect_exit = helpers.expect_exit
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -25,13 +26,13 @@ describe('ShaDa support code', function()
nvim_command('set shada=\'0 history=2')
nvim_feed(':" Test\n')
nvim_feed(':" Test 2\n')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
nvim_command('set shada=\'0 history=2')
nvim_command('rshada')
eq('" Test 2', funcs.histget(':', -1))
eq('" Test', funcs.histget(':', -2))
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
end)
it('respects &history when dumping',
@@ -138,7 +139,7 @@ describe('ShaDa support code', function()
nvim_command('set hlsearch shada-=h')
nvim_feed('/test\n')
eq(1, meths.get_vvar('hlsearch'))
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq(1, meths.get_vvar('hlsearch'))
end)
@@ -147,7 +148,7 @@ describe('ShaDa support code', function()
nvim_command('set hlsearch shada-=h')
nvim_feed('/test\n')
nvim_command('nohlsearch')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq(0, meths.get_vvar('hlsearch'))
end)
@@ -156,7 +157,7 @@ describe('ShaDa support code', function()
nvim_command('set hlsearch')
nvim_feed('/test\n')
eq(1, meths.get_vvar('hlsearch'))
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq(0, meths.get_vvar('hlsearch'))
end)
@@ -175,7 +176,7 @@ describe('ShaDa support code', function()
it('dumps and loads history with UTF-8 characters', function()
reset()
nvim_feed(':echo "«"\n')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq('echo "«"', funcs.histget(':', -1))
end)
@@ -183,7 +184,7 @@ describe('ShaDa support code', function()
it('dumps and loads replacement with UTF-8 characters',
function()
nvim_command('substitute/./«/ge')
- nvim_command('qall!')
+ expect_exit(nvim_command, 'qall!')
reset()
funcs.setline('.', {'.'})
nvim_command('&')
@@ -193,7 +194,7 @@ describe('ShaDa support code', function()
it('dumps and loads substitute pattern with UTF-8 characters',
function()
nvim_command('substitute/«/./ge')
- nvim_command('qall!')
+ expect_exit(nvim_command, 'qall!')
reset()
funcs.setline('.', {'«\171'})
nvim_command('&')
@@ -204,7 +205,7 @@ describe('ShaDa support code', function()
function()
nvim_command('silent! /«/')
nvim_command('set shada+=/0')
- nvim_command('qall!')
+ expect_exit(nvim_command, 'qall!')
reset()
funcs.setline('.', {'\171«'})
nvim_command('~&')
@@ -217,7 +218,7 @@ describe('ShaDa support code', function()
-- \171 is U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK in latin1
nvim_command('silent! /\171/')
nvim_command('set shada+=/0')
- nvim_command('qall!')
+ expect_exit(nvim_command, 'qall!')
reset()
funcs.setline('.', {'\171«'})
nvim_command('~&')
diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua
index 153a1c346f..a91be18841 100644
--- a/test/functional/shada/marks_spec.lua
+++ b/test/functional/shada/marks_spec.lua
@@ -4,6 +4,7 @@ local meths, curwinmeths, curbufmeths, nvim_command, funcs, eq =
helpers.meths, helpers.curwinmeths, helpers.curbufmeths, helpers.command,
helpers.funcs, helpers.eq
local exc_exec, exec_capture = helpers.exc_exec, helpers.exec_capture
+local expect_exit = helpers.expect_exit
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -79,7 +80,7 @@ describe('ShaDa support code', function()
nvim_command('mark a')
nvim_command('2')
nvim_command('kb')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
nvim_command('edit ' .. testfilename)
nvim_command('normal! `a')
@@ -92,7 +93,7 @@ describe('ShaDa support code', function()
it('is able to dump and read back mark "', function()
nvim_command('edit ' .. testfilename)
nvim_command('2')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
nvim_command('edit ' .. testfilename)
nvim_command('normal! `"')
@@ -104,7 +105,7 @@ describe('ShaDa support code', function()
nvim_command('tabedit ' .. testfilename_2)
nvim_command('2')
nvim_command('q!')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
nvim_command('edit ' .. testfilename_2)
nvim_command('normal! `"')
@@ -116,7 +117,7 @@ describe('ShaDa support code', function()
local tf_full = curbufmeths.get_name()
nvim_command('edit ' .. testfilename_2)
local tf_full_2 = curbufmeths.get_name()
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
local oldfiles = meths.get_vvar('oldfiles')
table.sort(oldfiles)
@@ -145,7 +146,7 @@ describe('ShaDa support code', function()
nvim_command('enew')
nvim_command('normal! gg')
local saved = exec_capture('jumps')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq(saved, exec_capture('jumps'))
end)
@@ -176,7 +177,7 @@ describe('ShaDa support code', function()
nvim_command('normal! G')
nvim_command('sleep 2')
nvim_command('normal! gg')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
nvim_command('redraw')
nvim_command('edit ' .. testfilename)
@@ -200,7 +201,7 @@ describe('ShaDa support code', function()
nvim_command('edit ' .. testfilename)
nvim_command('normal! Gra')
nvim_command('normal! ggrb')
- nvim_command('qall!')
+ expect_exit(nvim_command, 'qall!')
reset()
nvim_command('edit ' .. testfilename)
nvim_command('normal! Gg;')
diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua
index 1f06cbe350..6aaa54cce8 100644
--- a/test/functional/shada/registers_spec.lua
+++ b/test/functional/shada/registers_spec.lua
@@ -4,6 +4,7 @@ local nvim_command, funcs, eq = helpers.command, helpers.funcs, helpers.eq
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
+local expect_exit = helpers.expect_exit
local setreg = function(name, contents, typ)
if type(contents) == 'string' then
@@ -27,7 +28,7 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
@@ -39,7 +40,7 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{}, ''}, getreg('c'))
eq({{}, ''}, getreg('l'))
@@ -50,7 +51,7 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada=\'0,<0')
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
@@ -62,7 +63,7 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{}, ''}, getreg('c'))
eq({{}, ''}, getreg('l'))
@@ -73,7 +74,7 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada=\'0,\\"0')
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
@@ -85,7 +86,7 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
@@ -96,7 +97,7 @@ describe('ShaDa support code', function()
nvim_command('set shada=\'0,<2')
setreg('o', {'d'}, 'c')
setreg('t', {'a', 'b', 'cde'}, 'l')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'d'}, 'v'}, getreg('o'))
eq({{}, ''}, getreg('t'))
@@ -106,7 +107,7 @@ describe('ShaDa support code', function()
nvim_command('set shada=\'0,\\"2')
setreg('o', {'d'}, 'c')
setreg('t', {'a', 'b', 'cde'}, 'l')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'d'}, 'v'}, getreg('o'))
eq({{}, ''}, getreg('t'))
@@ -117,7 +118,7 @@ describe('ShaDa support code', function()
setreg('o', {'d'}, 'c')
setreg('t', {'a', 'b', 'cde'}, 'l')
setreg('h', {'abc', 'acb', 'bac', 'bca', 'cab', 'cba'}, 'b3')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'d'}, 'v'}, getreg('o'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('t'))
@@ -128,7 +129,7 @@ describe('ShaDa support code', function()
function()
reset()
setreg('e', {'«'}, 'c')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'«'}, 'v'}, getreg('e'))
end)
@@ -138,7 +139,7 @@ describe('ShaDa support code', function()
reset()
-- \171 is U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK in latin1
setreg('e', {'\171«'}, 'c')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'\171«'}, 'v'}, getreg('e'))
end)
@@ -148,7 +149,7 @@ describe('ShaDa support code', function()
setreg('1', {'one'}, 'c')
setreg('2', {'two'}, 'c')
setreg('a', {'a'}, 'c')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{}, ''}, getreg('0'))
eq({{'one'}, 'v'}, getreg('1'))
@@ -161,7 +162,7 @@ describe('ShaDa support code', function()
setreg('0', {'zero'}, 'c')
setreg('1', {'one'}, 'c')
setreg('2', {'two'}, 'c')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'zero'}, 'v'}, getreg('0'))
eq({{'one'}, 'v'}, getreg('1'))
@@ -173,7 +174,7 @@ describe('ShaDa support code', function()
setreg('0', {'zero'}, 'c')
setreg('1', {'one'}, 'cu')
setreg('2', {'two'}, 'c')
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq({{'zero'}, 'v'}, getreg('0'))
eq({{'one'}, 'v'}, getreg('1'))
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index ff63aed235..d10a2facbb 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -7,7 +7,7 @@ local write_file, spawn, set_session, nvim_prog, exc_exec =
helpers.exc_exec
local lfs = require('lfs')
-local paths = require('test.config.paths')
+local paths = require('test.cmakeconfig.paths')
local mpack = require('mpack')
diff --git a/test/functional/shada/variables_spec.lua b/test/functional/shada/variables_spec.lua
index 854add1363..a91b7eb193 100644
--- a/test/functional/shada/variables_spec.lua
+++ b/test/functional/shada/variables_spec.lua
@@ -2,6 +2,7 @@
local helpers = require('test.functional.helpers')(after_each)
local meths, funcs, nvim_command, eq, eval =
helpers.meths, helpers.funcs, helpers.command, helpers.eq, helpers.eval
+local expect_exit = helpers.expect_exit
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -33,7 +34,7 @@ describe('ShaDa support code', function()
local vartype = eval('type(g:' .. varname .. ')')
-- Exit during `reset` is not a regular exit: it does not write shada
-- automatically
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset('set shada+=!')
eq(vartype, eval('type(g:' .. varname .. ')'))
eq(varval, meths.get_var(varname))
@@ -98,7 +99,7 @@ describe('ShaDa support code', function()
meths.set_var('LSTVAR', {'«'})
meths.set_var('DCTVAR', {['«']='«'})
meths.set_var('NESTEDVAR', {['«']={{'«'}, {['«']='«'}, {a='Test'}}})
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq('«', meths.get_var('STRVAR'))
eq({'«'}, meths.get_var('LSTVAR'))
@@ -116,7 +117,7 @@ describe('ShaDa support code', function()
meths.set_var('DCTVAR', {['«\171']='«\171'})
meths.set_var('NESTEDVAR', {['\171']={{'\171«'}, {['\171']='\171'},
{a='Test'}}})
- nvim_command('qall')
+ expect_exit(nvim_command, 'qall')
reset()
eq('\171', meths.get_var('STRVAR'))
eq({'\171'}, meths.get_var('LSTVAR'))
diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index e28cc03597..5305b8af9c 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -6,7 +6,7 @@ if helpers.pending_win32(pending) then return end
describe('api', function()
local screen
- local socket_name = "Xtest_functional_api.sock"
+ local socket_name = "./Xtest_functional_api.sock"
before_each(function()
helpers.clear()
@@ -29,7 +29,7 @@ describe('api', function()
{4:~ }|
{4:~ }|
{4:~ }|
- ]]..socket_name..[[ |
+ ]]..socket_name..[[ |
{3:-- TERMINAL --} |
]])
@@ -48,8 +48,8 @@ describe('api', function()
{3:-- TERMINAL --} |
]])
- ok(socket_session1:request("nvim_ui_attach", 42, 6, {rgb=true}))
- ok(socket_session2:request("nvim_ui_attach", 25, 30, {rgb=true}))
+ ok((socket_session1:request("nvim_ui_attach", 42, 6, {rgb=true})))
+ ok((socket_session2:request("nvim_ui_attach", 25, 30, {rgb=true})))
socket_session1:notify("nvim_input", "\n[socket 1] this is more than 25 columns")
socket_session2:notify("nvim_input", "\n[socket 2] input")
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index beb43e0271..1cef771f0d 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -258,6 +258,7 @@ describe(':terminal buffer', function()
end)
it('it works with set rightleft #11438', function()
+ if helpers.pending_win32(pending) then return end
local columns = eval('&columns')
feed(string.rep('a', columns))
command('set rightleft')
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 7223f5ba61..b5f3c2bd31 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -1,45 +1,94 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local eq = helpers.eq
+local eval = helpers.eval
local command = helpers.command
local pcall_err = helpers.pcall_err
local feed = helpers.feed
-local sleep = helpers.sleep
local poke_eventloop = helpers.poke_eventloop
-describe('associated channel is closed and later freed for terminal', function()
- before_each(clear)
+describe('terminal channel is closed and later released if', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new()
+ screen:attach()
+ end)
it('opened by nvim_open_term() and deleted by :bdelete!', function()
command([[let id = nvim_open_term(0, {})]])
- -- channel hasn't been freed yet
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[bdelete! | call chansend(id, 'test')]]))
- -- channel has been freed after one main loop iteration
- eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
+ local chans = eval('len(nvim_list_chans())')
+ -- channel hasn't been released yet
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[bdelete! | call chansend(id, 'test')]]))
+ -- channel has been released after one main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+
+ it('opened by nvim_open_term(), closed by chanclose(), and deleted by pressing a key', function()
+ command('let id = nvim_open_term(0, {})')
+ local chans = eval('len(nvim_list_chans())')
+ -- channel has been closed but not released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
+ screen:expect({any='%[Terminal closed%]'})
+ eq(chans, eval('len(nvim_list_chans())'))
+ -- delete terminal
+ feed('i<CR>')
+ -- need to first process input
+ poke_eventloop()
+ -- channel has been released after another main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+
+ it('opened by nvim_open_term(), closed by chanclose(), and deleted by :bdelete', function()
+ command('let id = nvim_open_term(0, {})')
+ local chans = eval('len(nvim_list_chans())')
+ -- channel has been closed but not released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
+ screen:expect({any='%[Terminal closed%]'})
+ eq(chans, eval('len(nvim_list_chans())'))
+ -- channel still hasn't been released yet
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
+ -- channel has been released after one main loop iteration
+ 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')]])
- sleep(500)
- -- process has exited
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[call chansend(id, 'test')]]))
+ local chans = eval('len(nvim_list_chans())')
+ -- wait for process to exit
+ screen:expect({any='%[Process exited 0%]'})
+ -- process has exited but channel has't been released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chansend(id, 'test')]]))
+ eq(chans, eval('len(nvim_list_chans())'))
-- delete terminal
feed('i<CR>')
-- need to first process input
poke_eventloop()
- -- channel has been freed after another main loop iteration
- eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
+ -- channel has been released after another main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
end)
-- This indirectly covers #16264
it('opened by termopen(), exited, and deleted by :bdelete', function()
command([[let id = termopen('echo')]])
- sleep(500)
- -- process has exited
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[call chansend(id, 'test')]]))
- -- channel hasn't been freed yet
- eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
- -- channel has been freed after one main loop iteration
- eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
+ local chans = eval('len(nvim_list_chans())')
+ -- wait for process to exit
+ screen:expect({any='%[Process exited 0%]'})
+ -- process has exited but channel hasn't been released
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chansend(id, 'test')]]))
+ eq(chans, eval('len(nvim_list_chans())'))
+ -- channel still hasn't been released yet
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
+ -- channel has been released after one main loop iteration
+ eq(chans - 1, eval('len(nvim_list_chans())'))
end)
end)
diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua
index e9495f45a2..2d1c790d2f 100644
--- a/test/functional/terminal/cursor_spec.lua
+++ b/test/functional/terminal/cursor_spec.lua
@@ -2,9 +2,10 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local thelpers = require('test.functional.terminal.helpers')
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
-local nvim_dir, command = helpers.nvim_dir, helpers.command
+local testprg, command = helpers.testprg, helpers.command
local nvim_prog = helpers.nvim_prog
local eq, eval = helpers.eq, helpers.eval
+local matches = helpers.matches
local feed_command = helpers.feed_command
local hide_cursor = thelpers.hide_cursor
local show_cursor = thelpers.show_cursor
@@ -87,6 +88,7 @@ describe(':terminal cursor', function()
describe('when invisible', function()
it('is not highlighted and is detached from screen cursor', function()
+ if helpers.pending_win32(pending) then return end
hide_cursor()
screen:expect([[
tty ready |
@@ -148,7 +150,7 @@ describe('cursor with customized highlighting', function()
[3] = {bold = true},
})
screen:attach({rgb=false})
- command('call termopen(["'..nvim_dir..'/tty-test"])')
+ command('call termopen(["'..testprg('tty-test')..'"])')
feed_command('startinsert')
end)
@@ -523,6 +525,33 @@ describe('buffer cursor position is correct in terminal without number column',
eq({6, 1}, eval('nvim_win_get_cursor(0)'))
end)
end)
+
+ it('at the end of a line with trailing spaces #16234', function()
+ setup_ex_register('aaaaaaaa ')
+ feed('<C-R>r')
+ screen:expect([[
+ |
+ |
+ |
+ |
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :aaaaaaaa {1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
+ eq({6, 13}, eval('nvim_win_get_cursor(0)'))
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ |
+ |
+ |
+ |
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ :aaaaaaaa ^ {2: } |
+ |
+ ]])
+ eq({6, 12}, eval('nvim_win_get_cursor(0)'))
+ end)
end)
describe('buffer cursor position is correct in terminal with number column', function()
@@ -876,4 +905,31 @@ describe('buffer cursor position is correct in terminal with number column', fun
eq({6, 1}, eval('nvim_win_get_cursor(0)'))
end)
end)
+
+ it('at the end of a line with trailing spaces #16234', function()
+ setup_ex_register('aaaaaaaa ')
+ feed('<C-R>r')
+ screen:expect([[
+ {7: 1 } |
+ {7: 2 } |
+ {7: 3 } |
+ {7: 4 } |
+ {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
+ {7: 6 }:aaaaaaaa {1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ matches('^:aaaaaaaa [ ]*$', eval('nvim_get_current_line()'))
+ eq({6, 13}, eval('nvim_win_get_cursor(0)'))
+ feed([[<C-\><C-N>]])
+ screen:expect([[
+ {7: 1 } |
+ {7: 2 } |
+ {7: 3 } |
+ {7: 4 } |
+ {7: 5 }Entering Ex mode. Type "visual" to go to Normal mode. |
+ {7: 6 }:aaaaaaaa ^ {2: } |
+ |
+ ]])
+ eq({6, 12}, eval('nvim_win_get_cursor(0)'))
+ end)
end)
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index fabc5524ed..aeb4b7cc2e 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -3,7 +3,7 @@ local screen = require('test.functional.ui.screen')
local curbufmeths = helpers.curbufmeths
local curwinmeths = helpers.curwinmeths
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local command = helpers.command
local funcs = helpers.funcs
local meths = helpers.meths
@@ -21,7 +21,7 @@ describe(':edit term://*', function()
before_each(function()
clear()
- meths.set_option('shell', nvim_dir .. '/shell-test')
+ meths.set_option('shell', testprg('shell-test'))
meths.set_option('shellcmdflag', 'EXE')
end)
@@ -36,6 +36,7 @@ describe(':edit term://*', function()
end)
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
+ if helpers.pending_win32(pending) then return end
local columns, lines = 20, 4
local scr = get_screen(columns, lines)
local rep = 97
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 065dd72485..23b69319f0 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local assert_alive = helpers.assert_alive
local clear, poke_eventloop, nvim = helpers.clear, helpers.poke_eventloop, helpers.nvim
-local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
+local testprg, source, eq = helpers.testprg, helpers.source, helpers.eq
local feed = helpers.feed
local feed_command, eval = helpers.feed_command, helpers.eval
local funcs = helpers.funcs
@@ -28,7 +28,7 @@ describe(':terminal', function()
echomsg "msg3"
]])
-- Invoke a command that emits frequent terminal activity.
- feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 9999 !terminal_output!<cr>]])
+ feed([[:terminal "]]..testprg('shell-test')..[[" REP 9999 !terminal_output!<cr>]])
feed([[<C-\><C-N>]])
poke_eventloop()
-- Wait for some terminal activity.
@@ -131,7 +131,7 @@ describe(':terminal (with fake shell)', function()
screen = Screen.new(50, 4)
screen:attach({rgb=false})
-- shell-test.c is a fake shell that prints its arguments and exits.
- nvim('set_option', 'shell', nvim_dir..'/shell-test')
+ nvim('set_option', 'shell', testprg('shell-test'))
nvim('set_option', 'shellcmdflag', 'EXE')
end)
@@ -142,6 +142,7 @@ describe(':terminal (with fake shell)', function()
end
it('with no argument, acts like termopen()', function()
+ if helpers.pending_win32(pending) then return end
terminal_with_fake_shell()
retry(nil, 4 * screen.timeout, function()
screen:expect([[
@@ -165,7 +166,8 @@ describe(':terminal (with fake shell)', function()
end)
it("with no argument, but 'shell' has arguments, acts like termopen()", function()
- nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
+ if helpers.pending_win32(pending) then return end
+ nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
terminal_with_fake_shell()
screen:expect([[
^jeff $ |
@@ -176,6 +178,7 @@ describe(':terminal (with fake shell)', function()
end)
it('executes a given command through the shell', function()
+ if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
screen:expect([[
@@ -187,7 +190,8 @@ describe(':terminal (with fake shell)', function()
end)
it("executes a given command through the shell, when 'shell' has arguments", function()
- nvim('set_option', 'shell', nvim_dir..'/shell-test -t jeff')
+ if helpers.pending_win32(pending) then return end
+ nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell('echo hi')
screen:expect([[
@@ -199,6 +203,7 @@ describe(':terminal (with fake shell)', function()
end)
it('allows quotes and slashes', function()
+ if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo 'hello' \ "world"]])
screen:expect([[
@@ -235,6 +240,7 @@ describe(':terminal (with fake shell)', function()
end)
it('works with :find', function()
+ if helpers.pending_win32(pending) then return end
terminal_with_fake_shell()
screen:expect([[
^ready $ |
@@ -253,6 +259,7 @@ describe(':terminal (with fake shell)', function()
end)
it('works with gf', function()
+ if helpers.pending_win32(pending) then return end
command('set shellxquote=') -- win: avoid extra quotes
terminal_with_fake_shell([[echo "scripts/shadacat.py"]])
retry(nil, 4 * screen.timeout, function()
diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua
index d909888613..bcfd3559e6 100644
--- a/test/functional/terminal/helpers.lua
+++ b/test/functional/terminal/helpers.lua
@@ -3,11 +3,13 @@
-- operate on the _host_ session, _not_ the child session.
local helpers = require('test.functional.helpers')(nil)
local Screen = require('test.functional.ui.screen')
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local feed_command, nvim = helpers.feed_command, helpers.nvim
local function feed_data(data)
- nvim('set_var', 'term_data', data)
+ -- A string containing NUL bytes is not converted to a Blob when
+ -- calling nvim_set_var() API, so convert it using Lua instead.
+ nvim('exec_lua', 'vim.g.term_data = ...', {data})
nvim('command', 'call jobsend(b:terminal_job_id, term_data)')
end
@@ -35,7 +37,7 @@ local function clear_attrs() feed_termcode('[0;10m') end
local function enable_mouse() feed_termcode('[?1002h') end
local function disable_mouse() feed_termcode('[?1002l') end
-local default_command = '["'..nvim_dir..'/tty-test'..'"]'
+local default_command = '["'..testprg('tty-test')..'"]'
local function screen_setup(extra_rows, command, cols, opts)
extra_rows = extra_rows and extra_rows or 0
@@ -94,7 +96,7 @@ local function screen_setup(extra_rows, command, cols, opts)
table.insert(expected, '{3:-- TERMINAL --}' .. ((' '):rep(cols - 14)))
screen:expect(table.concat(expected, '|\n')..'|')
else
- -- This eval also acts as a wait().
+ -- This eval also acts as a poke_eventloop().
if 0 == nvim('eval', "exists('b:terminal_job_id')") then
error("terminal job failed to start")
end
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 8d3f0218af..28ca07d815 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local thelpers = require('test.functional.terminal.helpers')
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
-local nvim_dir, command = helpers.nvim_dir, helpers.command
+local testprg, command = helpers.testprg, helpers.command
local nvim_prog_abs = helpers.nvim_prog_abs
local eq, eval = helpers.eq, helpers.eval
local funcs = helpers.funcs
@@ -28,7 +28,7 @@ describe(':terminal highlight', function()
[11] = {background = 11},
})
screen:attach({rgb=false})
- command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
+ command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
@@ -173,7 +173,7 @@ describe(':terminal highlight forwarding', function()
[4] = {{foreground = tonumber('0xff8000')}, {}},
})
screen:attach()
- command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
+ command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
@@ -214,7 +214,7 @@ describe(':terminal highlight with custom palette', function()
clear()
screen = Screen.new(50, 7)
screen:set_default_attr_ids({
- [1] = {foreground = tonumber('0x123456')}, -- no fg_indexed when overriden
+ [1] = {foreground = tonumber('0x123456')}, -- no fg_indexed when overridden
[2] = {foreground = 12},
[3] = {bold = true, reverse = true},
[5] = {background = 11},
@@ -225,7 +225,7 @@ describe(':terminal highlight with custom palette', function()
})
screen:attach({rgb=true})
nvim('set_var', 'terminal_color_3', '#123456')
- command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
+ command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
feed('i')
screen:expect([[
tty ready |
@@ -304,10 +304,17 @@ describe('synIDattr()', function()
eq('79', eval('synIDattr(hlID("Keyword"), "fg")'))
end)
- it('returns "1" if group has "strikethrough" attribute', function()
- eq('', eval('synIDattr(hlID("Normal"), "strikethrough")'))
- eq('1', eval('synIDattr(hlID("Keyword"), "strikethrough")'))
- eq('1', eval('synIDattr(hlID("Keyword"), "strikethrough", "gui")'))
+ it('returns "1" if group has given highlight attribute', function()
+ local hl_attrs = {
+ 'underline', 'undercurl', 'underdouble', 'underdotted', 'underdashed', 'strikethrough'
+ }
+ for _,hl_attr in ipairs(hl_attrs) do
+ local context = 'using ' .. hl_attr .. ' attr'
+ command('highlight Keyword cterm=' .. hl_attr .. ' gui=' .. hl_attr)
+ eq('', eval('synIDattr(hlID("Normal"), "'.. hl_attr .. '")'), context)
+ eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '")'), context)
+ eq('1', eval('synIDattr(hlID("Keyword"), "' .. hl_attr .. '", "gui")'), context)
+ end
end)
end)
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index 780a0b9b5a..6e2c851df7 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local clear, eq, eval = helpers.clear, helpers.eq, helpers.eval
-local feed, nvim = helpers.feed, helpers.nvim
+local feed, nvim, command = helpers.feed, helpers.nvim, helpers.command
local feed_data = thelpers.feed_data
describe(':terminal mouse', function()
@@ -10,9 +10,9 @@ describe(':terminal mouse', function()
before_each(function()
clear()
nvim('set_option', 'statusline', '==========')
- nvim('command', 'highlight StatusLine cterm=NONE')
- nvim('command', 'highlight StatusLineNC cterm=NONE')
- nvim('command', 'highlight VertSplit cterm=NONE')
+ command('highlight StatusLine cterm=NONE')
+ command('highlight StatusLineNC cterm=NONE')
+ command('highlight VertSplit cterm=NONE')
screen = thelpers.screen_setup()
local lines = {}
for i = 1, 30 do
@@ -38,6 +38,26 @@ describe(':terminal mouse', function()
eq('nt', eval('mode(1)'))
end)
+ it('will exit focus and trigger Normal mode mapping on mouse click', function()
+ command('let g:got_leftmouse = 0')
+ command('nnoremap <LeftMouse> <Cmd>let g:got_leftmouse = 1<CR>')
+ eq('t', eval('mode(1)'))
+ eq(0, eval('g:got_leftmouse'))
+ feed('<LeftMouse>')
+ eq('nt', eval('mode(1)'))
+ eq(1, eval('g:got_leftmouse'))
+ end)
+
+ it('will exit focus and trigger Normal mode mapping on mouse click with modifier', function()
+ command('let g:got_ctrl_leftmouse = 0')
+ command('nnoremap <C-LeftMouse> <Cmd>let g:got_ctrl_leftmouse = 1<CR>')
+ eq('t', eval('mode(1)'))
+ eq(0, eval('g:got_ctrl_leftmouse'))
+ feed('<C-LeftMouse>')
+ eq('nt', eval('mode(1)'))
+ eq(1, eval('g:got_ctrl_leftmouse'))
+ end)
+
it('will exit focus on <C-\\> + mouse-scroll', function()
eq('t', eval('mode(1)'))
feed('<C-\\>')
@@ -180,7 +200,7 @@ describe(':terminal mouse', function()
it('will forward mouse clicks to the program with the correct even if set nu', function()
if helpers.pending_win32(pending) then return end
- nvim('command', 'set number')
+ command('set number')
-- When the display area such as a number is clicked, it returns to the
-- normal mode.
feed('<LeftMouse><3,0>')
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 11bdc73a47..b491cb2735 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -2,10 +2,11 @@ local Screen = require('test.functional.ui.screen')
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
local clear, eq, curbuf = helpers.clear, helpers.eq, helpers.curbuf
-local feed, nvim_dir, feed_command = helpers.feed, helpers.nvim_dir, helpers.feed_command
+local feed, testprg, feed_command = helpers.feed, helpers.testprg, helpers.feed_command
local iswin = helpers.iswin
local eval = helpers.eval
local command = helpers.command
+local matches = helpers.matches
local poke_eventloop = helpers.poke_eventloop
local retry = helpers.retry
local curbufmeths = helpers.curbufmeths
@@ -345,10 +346,11 @@ end)
describe(':terminal prints more lines than the screen height and exits', function()
it('will push extra lines to scrollback', function()
+ if helpers.pending_win32(pending) then return end
clear()
local screen = Screen.new(30, 7)
screen:attach({rgb=false})
- feed_command('call termopen(["'..nvim_dir..'/tty-test", "10"]) | startinsert')
+ feed_command(("call termopen(['%s', '10']) | startinsert"):format(testprg('tty-test')))
poke_eventloop()
screen:expect([[
line6 |
@@ -380,7 +382,7 @@ describe("'scrollback' option", function()
local function set_fake_shell()
-- shell-test.c is a fake shell that prints its arguments and exits.
- nvim('set_option', 'shell', nvim_dir..'/shell-test')
+ nvim('set_option', 'shell', testprg('shell-test'))
nvim('set_option', 'shellcmdflag', 'EXE')
end
@@ -401,7 +403,7 @@ describe("'scrollback' option", function()
end
curbufmeths.set_option('scrollback', 0)
- feed_data(nvim_dir..'/shell-test REP 31 line'..(iswin() and '\r' or '\n'))
+ feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), iswin() and '\r' or '\n'))
screen:expect{any='30: line '}
retry(nil, nil, function() expect_lines(7) end)
end)
@@ -421,7 +423,7 @@ describe("'scrollback' option", function()
-- Wait for prompt.
screen:expect{any='%$'}
- feed_data(nvim_dir.."/shell-test REP 31 line"..(iswin() and '\r' or '\n'))
+ feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), iswin() and '\r' or '\n'))
screen:expect{any='30: line '}
retry(nil, nil, function() expect_lines(33, 2) end)
@@ -434,7 +436,7 @@ describe("'scrollback' option", function()
-- 'scrollback' option is synchronized with the internal sb_buffer.
command('sleep 100m')
- feed_data(nvim_dir.."/shell-test REP 41 line"..(iswin() and '\r' or '\n'))
+ feed_data(('%s REP 41 line%s'):format(testprg('shell-test'), iswin() and '\r' or '\n'))
if iswin() then
screen:expect{grid=[[
37: line |
@@ -459,8 +461,36 @@ describe("'scrollback' option", function()
expect_lines(58)
-- Verify off-screen state
- eq((iswin() and '36: line' or '35: line'), eval("getline(line('w0') - 1)"))
- eq((iswin() and '27: line' or '26: line'), eval("getline(line('w0') - 10)"))
+ matches((iswin() and '^36: line[ ]*$' or '^35: line[ ]*$'), eval("getline(line('w0') - 1)"))
+ matches((iswin() and '^27: line[ ]*$' or '^26: line[ ]*$'), eval("getline(line('w0') - 10)"))
+ end)
+
+ it('deletes extra lines immediately', function()
+ -- Scrollback is 10 on screen_setup
+ local screen = thelpers.screen_setup(nil, nil, 30)
+ local lines = {}
+ for i = 1, 30 do
+ table.insert(lines, 'line'..tostring(i))
+ end
+ table.insert(lines, '')
+ feed_data(lines)
+ screen:expect([[
+ line26 |
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ {1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ local term_height = 6 -- Actual terminal screen height, not the scrollback
+ -- Initial
+ local scrollback = curbufmeths.get_option('scrollback')
+ eq(scrollback + term_height, eval('line("$")'))
+ -- Reduction
+ scrollback = scrollback - 2
+ curbufmeths.set_option('scrollback', scrollback)
+ eq(scrollback + term_height, eval('line("$")'))
end)
it('defaults to 10000 in :terminal buffers', function()
@@ -576,6 +606,7 @@ describe("pending scrollback line handling", function()
end)
it("does not crash after nvim_buf_call #14891", function()
+ if helpers.pending_win32(pending) then return end
exec_lua [[
local a = vim.api
local bufnr = a.nvim_create_buf(false, true)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index faf44fa01d..dd88379344 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -14,12 +14,13 @@ local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
local clear = helpers.clear
local command = helpers.command
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local retry = helpers.retry
local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
+local funcs = helpers.funcs
if helpers.pending_win32(pending) then return end
@@ -85,6 +86,24 @@ describe('TUI', function()
assert_alive()
end)
+ it('resize at startup', function()
+ -- Issues: #17285 #15044 #11330
+ screen:try_resize(50, 10)
+ feed_command([[call termopen([v:progpath, '--clean', '--cmd', 'let start = reltime() | while v:true | if reltimefloat(reltime(start)) > 2 | break | endif | endwhile']) | sleep 500m | vs new]])
+ screen:expect([[
+ {1: } │ |
+ {4:~ }│{4:~ }|
+ {4:~ }│{4:~ }|
+ {4:~ }│{4:~ }|
+ {4:~ }│{4:~ }|
+ {4:~ }│{5:[No Name] 0,0-1 All}|
+ {4:~ }│ |
+ {5:new }{MATCH:<.*[/\]nvim }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('accepts resize while pager is active', function()
child_session:request("nvim_command", [[
set more
@@ -214,7 +233,7 @@ describe('TUI', function()
]])
end)
- it('interprets ESC+key as ALT chord', function()
+ it('interprets ESC+key as ALT chord in i_CTRL-V', function()
-- Vim represents ALT/META by setting the "high bit" of the modified key:
-- ALT+j inserts "ê". Nvim does not (#3982).
feed_data('i\022\027j')
@@ -229,6 +248,38 @@ describe('TUI', function()
]])
end)
+ it('interprets <Esc>[27u as <Esc>', function()
+ feed_command('nnoremap <M-;> <Nop>')
+ feed_command('nnoremap <Esc> AESC<Esc>')
+ feed_command('nnoremap ; Asemicolon<Esc>')
+ feed_data('\027[27u;')
+ screen:expect([[
+ ESCsemicolo{1:n} |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ -- <Esc>; should be recognized as <M-;> when <M-;> is mapped
+ feed_data('\027;')
+ screen:expect_unchanged()
+ end)
+
+ it('interprets <Esc><Nul> as <M-C-Space> #17198', function()
+ feed_data('i\022\027\000')
+ screen:expect([[
+ <M-C-Space>{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('accepts ASCII control sequences', function()
feed_data('i')
feed_data('\022\007') -- ctrl+g
@@ -247,6 +298,179 @@ describe('TUI', function()
]], attrs)
end)
+ it('accepts keypad keys from kitty keyboard protocol #19180', function()
+ feed_data('i')
+ feed_data(funcs.nr2char(57399)) -- KP_0
+ feed_data(funcs.nr2char(57400)) -- KP_1
+ feed_data(funcs.nr2char(57401)) -- KP_2
+ feed_data(funcs.nr2char(57402)) -- KP_3
+ feed_data(funcs.nr2char(57403)) -- KP_4
+ feed_data(funcs.nr2char(57404)) -- KP_5
+ feed_data(funcs.nr2char(57405)) -- KP_6
+ feed_data(funcs.nr2char(57406)) -- KP_7
+ feed_data(funcs.nr2char(57407)) -- KP_8
+ feed_data(funcs.nr2char(57408)) -- KP_9
+ feed_data(funcs.nr2char(57409)) -- KP_DECIMAL
+ feed_data(funcs.nr2char(57410)) -- KP_DIVIDE
+ feed_data(funcs.nr2char(57411)) -- KP_MULTIPLY
+ feed_data(funcs.nr2char(57412)) -- KP_SUBTRACT
+ feed_data(funcs.nr2char(57413)) -- KP_ADD
+ feed_data(funcs.nr2char(57414)) -- KP_ENTER
+ feed_data(funcs.nr2char(57415)) -- KP_EQUAL
+ screen:expect([[
+ 0123456789./*-+ |
+ ={1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57417)) -- KP_LEFT
+ screen:expect([[
+ 0123456789./*-+ |
+ {1:=} |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57418)) -- KP_RIGHT
+ screen:expect([[
+ 0123456789./*-+ |
+ ={1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57419)) -- KP_UP
+ screen:expect([[
+ 0{1:1}23456789./*-+ |
+ = |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57420)) -- KP_DOWN
+ screen:expect([[
+ 0123456789./*-+ |
+ ={1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57425)) -- KP_INSERT
+ screen:expect([[
+ 0123456789./*-+ |
+ ={1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- REPLACE --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data('\027[27u') -- ESC
+ screen:expect([[
+ 0123456789./*-+ |
+ {1:=} |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data('\027[57417;5u') -- CTRL + KP_LEFT
+ screen:expect([[
+ {1:0}123456789./*-+ |
+ = |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data('\027[57418;2u') -- SHIFT + KP_RIGHT
+ screen:expect([[
+ 0123456789{1:.}/*-+ |
+ = |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57426)) -- KP_DELETE
+ screen:expect([[
+ 0123456789{1:/}*-+ |
+ = |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57423)) -- KP_HOME
+ screen:expect([[
+ {1:0}123456789/*-+ |
+ = |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(funcs.nr2char(57424)) -- KP_END
+ screen:expect([[
+ 0123456789/*-{1:+} |
+ = |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(':tab split\r:tabnew\r')
+ feed_data(':highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline\r')
+ local attrs = screen:get_default_attr_ids()
+ attrs[11] = {underline = true}
+ screen:expect([[
+ {11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11:X}|
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]], attrs)
+ feed_data('\027[57421;5u') -- CTRL + KP_PAGE_UP
+ screen:expect([[
+ {11: + [No Name] }{3: + [No Name] }{11: [No Name] }{1: }{11:X}|
+ 0123456789/*-{1:+} |
+ = |
+ {4:~ }|
+ {5:[No Name] [+] }|
+ |
+ {3:-- TERMINAL --} |
+ ]], attrs)
+ feed_data('\027[57422;5u') -- CTRL + KP_PAGE_DOWN
+ screen:expect([[
+ {11: + [No Name] + [No Name] }{3: [No Name] }{1: }{11:X}|
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ |
+ {3:-- TERMINAL --} |
+ ]], attrs)
+ end)
+
it('paste: Insert mode', function()
-- "bracketed paste"
feed_data('i""\027i\027[200~')
@@ -271,7 +495,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]])
feed_data('\027[201~') -- End paste.
- feed_data('\027\000') -- ESC: go to Normal mode.
+ feed_data('\027[27u') -- ESC: go to Normal mode.
wait_for_mode('n')
screen:expect([[
"pasted from termina{1:l}" |
@@ -323,7 +547,7 @@ describe('TUI', function()
feed_data('just paste it™')
feed_data('\027[201~')
screen:expect{grid=[[
- thisjust paste it™{1:3} is here |
+ thisjust paste it{1:™}3 is here |
|
{4:~ }|
{4:~ }|
@@ -353,7 +577,7 @@ describe('TUI', function()
return
end
feed_data(':set statusline=^^^^^^^\n')
- feed_data(':terminal '..nvim_dir..'/tty-test\n')
+ feed_data(':terminal '..testprg('tty-test')..'\n')
feed_data('i')
screen:expect{grid=[[
tty ready |
@@ -379,7 +603,7 @@ describe('TUI', function()
end)
it('paste: normal-mode (+CRLF #10872)', function()
- feed_data(':set ruler')
+ feed_data(':set ruler | echo')
wait_for_mode('c')
feed_data('\n')
wait_for_mode('n')
@@ -423,13 +647,13 @@ describe('TUI', function()
expect_child_buf_lines(expected_crlf)
feed_data('u')
expect_child_buf_lines({''})
+ feed_data(':echo')
+ wait_for_mode('c')
+ feed_data('\n')
+ wait_for_mode('n')
-- CRLF input
feed_data('\027[200~'..table.concat(expected_lf,'\r\n')..'\027[201~')
- screen:expect{
- grid=expected_grid1:gsub(
- ':set ruler *',
- '3 fewer lines; before #1 0 seconds ago '),
- attr_ids=expected_attr}
+ screen:expect{grid=expected_grid1, attr_ids=expected_attr}
expect_child_buf_lines(expected_crlf)
end)
@@ -453,7 +677,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]]}
-- Dot-repeat/redo.
- feed_data('\027\000')
+ feed_data('\027[27u')
wait_for_mode('n')
feed_data('.')
screen:expect{grid=[[
@@ -499,7 +723,7 @@ describe('TUI', function()
vim.paste = function(lines, phase) error("fake fail") end
]], {})
-- Prepare something for dot-repeat/redo.
- feed_data('ifoo\n\027\000')
+ feed_data('ifoo\n\027[27u')
wait_for_mode('n')
screen:expect{grid=[[
foo |
@@ -541,7 +765,7 @@ describe('TUI', function()
{3:-- TERMINAL --} |
]]}
-- Editor should still work after failed/drained paste.
- feed_data('ityped input...\027\000')
+ feed_data('ityped input...\027[27u')
screen:expect{grid=[[
foo |
foo |
@@ -575,7 +799,7 @@ describe('TUI', function()
vim.paste = function(lines, phase) return false end
]], {})
feed_data('\027[200~line A\nline B\n\027[201~')
- feed_data('ifoo\n\027\000')
+ feed_data('ifoo\n\027[27u')
expect_child_buf_lines({'foo',''})
end)
@@ -669,7 +893,7 @@ describe('TUI', function()
{3:-- INSERT --} |
{3:-- TERMINAL --} |
]])
- feed_data('\027\000') -- ESC: go to Normal mode.
+ feed_data('\027[27u') -- ESC: go to Normal mode.
wait_for_mode('n')
-- Dot-repeat/redo.
feed_data('.')
@@ -871,7 +1095,7 @@ describe('TUI', function()
feed_data(':set statusline=^^^^^^^\n')
feed_data(':set termguicolors\n')
- feed_data(':terminal '..nvim_dir..'/tty-test\n')
+ feed_data(':terminal '..testprg('tty-test')..'\n')
-- Depending on platform the above might or might not fit in the cmdline
-- so clear it for consistent behavior.
feed_data(':\027')
@@ -1098,7 +1322,7 @@ describe('TUI FocusGained/FocusLost', function()
end)
it('in terminal-mode', function()
- feed_data(':set shell='..nvim_dir..'/shell-test\n')
+ feed_data(':set shell='..testprg('shell-test')..'\n')
feed_data(':set noshowmode laststatus=0\n')
feed_data(':terminal\n')
diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index 9f278fd157..0d3295cf32 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -18,6 +18,7 @@ describe(':terminal window', function()
end)
it('sets topline correctly #8556', function()
+ if helpers.pending_win32(pending) then return end
-- Test has hardcoded assumptions of dimensions.
eq(7, eval('&lines'))
feed_data('\n\n\n') -- Add blank lines.
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 175525b3f2..5ec0a8a060 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -23,7 +23,7 @@ local hl_query = [[
"enum" @type
"extern" @type
- (string_literal) @string
+ (string_literal) @string.nonexistent-specializer-for-string.should-fallback-to-string
(number_literal) @number
(char_literal) @string
@@ -613,4 +613,131 @@ describe('treesitter highlighting', function()
[12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Grey100};
}}
end)
+
+ it("allows to use captures with dots (don't use fallback when specialization of foo exists)", function()
+ if pending_c_parser(pending) then return end
+
+ insert([[
+ char* x = "Will somebody ever read this?";
+ ]])
+
+ screen:expect{grid=[[
+ char* x = "Will somebody ever read this?"; |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ exec_lua [[
+ local parser = vim.treesitter.get_parser(0, "c", {})
+ local highlighter = vim.treesitter.highlighter
+ highlighter.hl_map['foo.bar'] = 'Type'
+ highlighter.hl_map['foo'] = 'String'
+ test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}})
+ ]]
+
+ screen:expect{grid=[[
+ {3:char}* x = {5:"Will somebody ever read this?"}; |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it("supports conceal attribute", function()
+ if pending_c_parser(pending) then return end
+ insert(hl_text)
+
+ -- conceal can be empty or a single cchar.
+ exec_lua [=[
+ vim.opt.cole = 2
+ local parser = vim.treesitter.get_parser(0, "c")
+ test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = [[
+ ("static" @keyword
+ (set! conceal "R"))
+
+ ((identifier) @Identifier
+ (set! conceal "")
+ (eq? @Identifier "lstate"))
+ ]]}})
+ ]=]
+
+ 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); |
+ |
+ multiqueue_put(main_loop.events, nlua_schedule_event, |
+ 1, (void *)(ptrdiff_t)cb); |
+ return 0; |
+ ^} |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it("hl_map has the correct fallback behavior", function()
+ exec_lua [[
+ local hl_map = vim.treesitter.highlighter.hl_map
+ hl_map["foo"] = 1
+ hl_map["foo.bar"] = 2
+ hl_map["foo.bar.baz"] = 3
+
+ assert(hl_map["foo"] == 1)
+ assert(hl_map["foo.a.b.c.d"] == 1)
+ assert(hl_map["foo.bar"] == 2)
+ assert(hl_map["foo.bar.a.b.c.d"] == 2)
+ assert(hl_map["foo.bar.baz"] == 3)
+ assert(hl_map["foo.bar.baz.d"] == 3)
+
+ hl_map["FOO"] = 1
+ hl_map["FOO.BAR"] = 2
+ assert(hl_map["FOO.BAR.BAZ"] == 2)
+
+ hl_map["foo.missing.exists"] = 3
+ assert(hl_map["foo.missing"] == 1)
+ assert(hl_map["foo.missing.exists"] == 3)
+ assert(hl_map["foo.missing.exists.bar"] == 3)
+ assert(hl_map["total.nonsense.but.a.lot.of.dots"] == nil)
+ -- It will not perform a second look up of this variable but return a sentinel value
+ assert(hl_map["total.nonsense.but.a.lot.of.dots"] == "__notfound")
+ ]]
+
+ end)
end)
diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua
index afb17dd2cf..30585be328 100644
--- a/test/functional/treesitter/language_spec.lua
+++ b/test/functional/treesitter/language_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
+local command = helpers.command
local exec_lua = helpers.exec_lua
local pcall_err = helpers.pcall_err
local matches = helpers.matches
@@ -67,5 +68,16 @@ describe('treesitter API', function()
end
eq({true,true}, {has_named,has_anonymous})
end)
+
+ it('checks if vim.treesitter.get_parser tries to create a new parser on filetype change', function ()
+ if pending_c_parser(pending) then return end
+ command("set filetype=c")
+ -- Should not throw an error when filetype is c
+ eq('c', exec_lua("return vim.treesitter.get_parser(0):lang()"))
+ command("set filetype=borklang")
+ -- Should throw an error when filetype changes to borklang
+ eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
+ pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0)"))
+ end)
end)
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 911fa017ab..7f3b0e770a 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -167,6 +167,27 @@ void ui_refresh(void)
eq('variable', ret)
end)
+ it("supports caching queries", function()
+ local long_query = query:rep(100)
+ local function q(n)
+ return exec_lua ([[
+ local query, n = ...
+ local before = vim.loop.hrtime()
+ for i=1,n,1 do
+ cquery = vim.treesitter.parse_query("c", ...)
+ end
+ local after = vim.loop.hrtime()
+ return after - before
+ ]], long_query, n)
+ end
+
+ local firstrun = q(1)
+ local manyruns = q(100)
+
+ -- First run should be at least 4x slower.
+ assert(400 * manyruns < firstrun, ('firstrun: %d ms, manyruns: %d ms'):format(firstrun / 1000, manyruns / 1000))
+ end)
+
it('support query and iter by capture', function()
insert(test_text)
@@ -264,6 +285,25 @@ end]]
eq(true, result)
end)
+ it('support getting empty text if node range is zero width', function()
+ local text = [[
+```lua
+{}
+```]]
+ insert(text)
+ local result = exec_lua([[
+ local fake_node = {}
+ function fake_node:start()
+ return 1, 0, 7
+ end
+ function fake_node:end_()
+ return 1, 0, 7
+ end
+ return vim.treesitter.get_node_text(fake_node, 0) == ''
+ ]])
+ eq(true, result)
+ end)
+
it('can match special regex characters like \\ * + ( with `vim-match?`', function()
insert('char* astring = "\\n"; (1 + 1) * 2 != 2;')
@@ -645,6 +685,21 @@ int x = INT_MAX;
-- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
}, get_ranges())
end)
+
+ it("should not inject bad languages", function()
+ if helpers.pending_win32(pending) then return end
+ exec_lua([=[
+ vim.treesitter.add_directive("inject-bad!", function(match, _, _, pred, metadata)
+ metadata.language = "{"
+ metadata.combined = true
+ metadata.content = pred[2]
+ end)
+
+ parser = vim.treesitter.get_parser(0, "c", {
+ injections = {
+ c = "(preproc_function_def value: ((preproc_arg) @_a (#inject-bad! @_a)))"}})
+ ]=])
+ end)
end)
describe("when using the offset directive", function()
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 16ed3b9486..7c0831bd09 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -564,6 +564,16 @@ describe('Buffer highlighting', function()
]]
clear_namespace(id, 0, -1)
+ screen:expect{grid=[[
+ fooba^r |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
set_extmark(id, 0, 0, {
end_line = 0,
@@ -755,12 +765,26 @@ describe('Buffer highlighting', function()
-- TODO: only a virtual text from the same ns curretly overrides
-- an existing virtual text. We might add a prioritation system.
set_virtual_text(id1, 0, s1, {})
- eq({{1, 0, 0, { priority = 0, virt_text = s1}}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
+ eq({{1, 0, 0, {
+ priority = 0,
+ virt_text = s1,
+ -- other details
+ right_gravity = true,
+ virt_text_pos = 'eol',
+ virt_text_hide = false,
+ }}}, get_extmarks(id1, {0,0}, {0, -1}, {details=true}))
-- TODO: is this really valid? shouldn't the max be line_count()-1?
local lastline = line_count()
set_virtual_text(id1, line_count(), s2, {})
- eq({{3, lastline, 0, { priority = 0, virt_text = s2}}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
+ eq({{3, lastline, 0, {
+ priority = 0,
+ virt_text = s2,
+ -- other details
+ right_gravity = true,
+ virt_text_pos = 'eol',
+ virt_text_hide = false,
+ }}}, get_extmarks(id1, {lastline,0}, {lastline, -1}, {details=true}))
eq({}, get_extmarks(id1, {lastline+9000,0}, {lastline+9000, -1}, {}))
end)
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 9c746b99bd..384761ab17 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -33,7 +33,7 @@ before_each(function()
let g:NUM_LVLS = 4
function Redraw()
mode
- return ''
+ return "\<Ignore>"
endfunction
let g:id = ''
cnoremap <expr> {REDRAW} Redraw()
@@ -42,7 +42,7 @@ before_each(function()
let Cb = g:Nvim_color_input{g:id}
let out = input({'prompt': ':', 'highlight': Cb})
let g:out{id} = out
- return (a:do_return ? out : '')
+ return (a:do_return ? out : "\<Ignore>")
endfunction
nnoremap <expr> {PROMPT} DoPrompt(0)
cnoremap <expr> {PROMPT} DoPrompt(1)
@@ -410,7 +410,7 @@ describe('Command-line coloring', function()
end)
it('stops executing callback after a number of errors', function()
set_color_cb('SplittedMultibyteStart')
- start_prompt('let x = "«»«»«»«»«»"\n')
+ start_prompt('let x = "«»«»«»«»«»"')
screen:expect([[
{EOB:~ }|
{EOB:~ }|
@@ -419,7 +419,7 @@ describe('Command-line coloring', function()
:let x = " |
{ERR:E5405: Chunk 0 start 10 splits multibyte}|
{ERR: character} |
- ^:let x = "«»«»«»«»«»" |
+ :let x = "«»«»«»«»«»"^ |
]])
feed('\n')
screen:expect([[
@@ -432,6 +432,7 @@ describe('Command-line coloring', function()
{EOB:~ }|
|
]])
+ feed('\n')
eq('let x = "«»«»«»«»«»"', meths.get_var('out'))
local msg = '\nE5405: Chunk 0 start 10 splits multibyte character'
eq(msg:rep(1), funcs.execute('messages'))
@@ -474,14 +475,14 @@ describe('Command-line coloring', function()
]])
feed('\n')
screen:expect([[
- |
+ ^ |
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
- ^:echo 42 |
+ :echo 42 |
]])
feed('\n')
eq('echo 42', meths.get_var('out'))
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index ad23402ff9..eb0a14da31 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -4,6 +4,9 @@ local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local command = helpers.command
local assert_alive = helpers.assert_alive
+local uname = helpers.uname
+local eval = helpers.eval
+local eq = helpers.eq
local function new_screen(opt)
local screen = Screen.new(25, 5)
@@ -16,6 +19,8 @@ local function new_screen(opt)
[5] = {bold = true, foreground = Screen.colors.SeaGreen4},
[6] = {foreground = Screen.colors.Magenta},
[7] = {bold = true, foreground = Screen.colors.Brown},
+ [8] = {background = Screen.colors.LightGrey},
+ [9] = {bold = true},
})
return screen
end
@@ -824,7 +829,7 @@ describe('cmdline redraw', function()
end)
it('with <Cmd>', function()
- if 'openbsd' == helpers.uname() then
+ if string.find(uname(), 'bsd') then
pending('FIXME #10804')
end
command('cmap a <Cmd>call sin(0)<CR>') -- no-op
@@ -845,6 +850,37 @@ describe('cmdline redraw', function()
456789^ |
]], unchanged=true}
end)
+
+ it('after pressing Ctrl-C in cmdwin in Visual mode #18967', function()
+ screen:try_resize(40, 10)
+ command('set cmdwinheight=3')
+ feed('q:iabc<Esc>vhh')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ {1::}^a{8:bc} |
+ {1:~ }|
+ {1:~ }|
+ {3:[Command Line] }|
+ {9:-- VISUAL --} |
+ ]])
+ feed('<C-C>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ {1::}a{8:bc} |
+ {1:~ }|
+ {1:~ }|
+ {3:[Command Line] }|
+ :^abc |
+ ]])
+ end)
end)
describe("cmdline height", function()
@@ -857,3 +893,228 @@ describe("cmdline height", function()
assert_alive()
end)
end)
+
+describe('cmdheight=0', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach()
+ end)
+
+ it("with cmdheight=1 noruler laststatus=2", function()
+ command("set cmdheight=1 noruler laststatus=2")
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ [No Name] |
+ |
+ ]]}
+ end)
+
+ it("with cmdheight=0 noruler laststatus=2", function()
+ command("set cmdheight=0 noruler laststatus=2")
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] |
+ ]]}
+ end)
+
+ it("with cmdheight=0 ruler laststatus=0", function()
+ command("set cmdheight=0 ruler laststatus=0")
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]]}
+ end)
+
+ it("with cmdheight=0 ruler laststatus=0", function()
+ command("set cmdheight=0 noruler laststatus=0 showmode")
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]], showmode={}}
+ feed('<Esc>')
+ eq(0, eval('&cmdheight'))
+ end)
+
+ it("with cmdheight=0 ruler rulerformat laststatus=0", function()
+ command("set cmdheight=0 noruler laststatus=0 rulerformat=%l,%c%= showmode")
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]], showmode={}}
+ feed('<Esc>')
+ eq(0, eval('&cmdheight'))
+ end)
+
+ it("with showmode", function()
+ command("set cmdheight=1 noruler laststatus=0 showmode")
+ feed('i')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]]}
+ feed('<Esc>')
+ eq(1, eval('&cmdheight'))
+ end)
+
+ it("when using command line", function()
+ command("set cmdheight=0 noruler laststatus=0")
+ feed(':')
+ screen:expect{grid=[[
+ |
+ ~ |
+ ~ |
+ ~ |
+ :^ |
+ ]]}
+ eq(1, eval('&cmdheight'))
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]], showmode={}}
+ eq(0, eval('&cmdheight'))
+ end)
+
+ it("when using input()", function()
+ command("set cmdheight=0 noruler laststatus=0")
+ feed(':call input("foo >")<cr>')
+ screen:expect{grid=[[
+ |
+ ~ |
+ ~ |
+ ~ |
+ foo >^ |
+ ]]}
+ eq(1, eval('&cmdheight'))
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]], showmode={}}
+ eq(0, eval('&cmdheight'))
+ end)
+
+ it("with winbar and splits", function()
+ command("set cmdheight=0 noruler laststatus=3 winbar=foo")
+ feed(':split<CR>')
+ screen:expect{grid=[[
+ foo |
+ |
+ E36: Not enough room |
+ Press ENTER or type comma|
+ nd to continue^ |
+ ]]}
+ feed('<CR>')
+ screen:expect{grid=[[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ [No Name] |
+ ]]}
+ feed(':')
+ screen:expect{grid=[[
+ foo |
+ |
+ ~ |
+ [No Name] |
+ :^ |
+ ]]}
+ feed('<Esc>')
+ screen:expect{grid=[[
+ foo |
+ ^ |
+ ~ |
+ ~ |
+ [No Name] |
+ ]], showmode={}}
+ eq(0, eval('&cmdheight'))
+
+ assert_alive()
+ end)
+
+ it("when macro with lastline", function()
+ command("set cmdheight=0 display=lastline")
+ feed('qq')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]], showmode={}}
+ feed('q')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ]], showmode={}}
+ end)
+
+ it("when substitute text", function()
+ command("set cmdheight=0 noruler laststatus=3")
+ feed('ifoo<ESC>')
+ screen:expect{grid=[[
+ fo^o |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] [+] |
+ ]]}
+
+ feed(':%s/foo/bar/gc<CR>')
+ screen:expect{grid=[[
+ foo |
+ ~ |
+ ~ |
+ [No Name] [+] |
+ replace wi...q/l/^E/^Y)?^ |
+ ]]}
+
+ feed('y')
+ screen:expect{grid=[[
+ ^bar |
+ ~ |
+ ~ |
+ ~ |
+ [No Name] [+] |
+ ]]}
+
+ assert_alive()
+ end)
+
+ it("when window resize", function()
+ command("set cmdheight=0")
+ feed('<C-w>+')
+ eq(0, eval('&cmdheight'))
+ end)
+end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 03cd4bfd06..a1423c98a8 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -215,7 +215,7 @@ describe('ui/cursor', function()
m.hl_id = 60
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 61 end
+ if m.id_lm then m.id_lm = 65 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 1575cab591..9af5d386db 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -30,6 +30,7 @@ describe('decorations providers', function()
[11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')};
[12] = {foreground = tonumber('0x990000')};
[13] = {background = Screen.colors.LightBlue};
+ [14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
}
end)
@@ -404,6 +405,50 @@ describe('decorations providers', function()
|
]]}
end)
+
+ it('can create and remove signs when CursorMoved autocommand validates botline #18661', function()
+ exec_lua([[
+ local lines = {}
+ for i = 1, 200 do
+ lines[i] = 'hello' .. tostring(i)
+ end
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
+ ]])
+ setup_provider([[
+ local function on_do(kind, winid, bufnr, topline, botline_guess)
+ if kind == 'win' then
+ if topline < 100 and botline_guess > 100 then
+ vim.api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' })
+ else
+ vim.api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1)
+ end
+ end
+ end
+ ]])
+ command([[autocmd CursorMoved * call line('w$')]])
+ meths.win_set_cursor(0, {100, 0})
+ screen:expect([[
+ {14: }hello97 |
+ {14: }hello98 |
+ {14: }hello99 |
+ X ^hello100 |
+ {14: }hello101 |
+ {14: }hello102 |
+ {14: }hello103 |
+ |
+ ]])
+ meths.win_set_cursor(0, {1, 0})
+ screen:expect([[
+ ^hello1 |
+ hello2 |
+ hello3 |
+ hello4 |
+ hello5 |
+ hello6 |
+ hello7 |
+ |
+ ]])
+ end)
end)
describe('extmark decorations', function()
@@ -437,6 +482,8 @@ describe('extmark decorations', function()
[22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')};
[23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey};
[24] = {bold = true};
+ [25] = {background = Screen.colors.LightRed};
+ [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
}
ns = meths.create_namespace 'test'
@@ -456,6 +503,31 @@ for _,item in ipairs(items) do
end
end]]
+ it('empty virtual text at eol should not break colorcolumn #17860', function()
+ insert(example_text)
+ feed('gg')
+ command('set colorcolumn=40')
+ screen:expect([[
+ ^for _,item in ipairs(items) do {25: } |
+ local text, hl_id_cell, count = unp{25:a}ck(item) |
+ if hl_id_cell ~= nil then {25: } |
+ hl_id = hl_id_cell {25: } |
+ end {25: } |
+ for _ = 1, (count or 1) do {25: } |
+ local cell = line[colpos] {25: } |
+ cell.text = text {25: } |
+ cell.hl_id = hl_id {25: } |
+ colpos = colpos+1 {25: } |
+ end {25: } |
+ end {25: } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ meths.buf_set_extmark(0, ns, 4, 0, { virt_text={{''}}, virt_text_pos='eol'})
+ screen:expect_unchanged()
+ end)
+
it('can have virtual text of overlay position', function()
insert(example_text)
feed 'gg'
@@ -471,7 +543,9 @@ end]]
-- can "float" beyond end of line
meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
-- bound check: right edge of window
- meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork ' }, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+ meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork '}, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+ -- empty virt_text should not change anything
+ meths.buf_set_extmark(0, ns, 6, 16, { virt_text={{''}}, virt_text_pos='overlay'})
screen:expect{grid=[[
^for _,item in ipairs(items) do |
@@ -621,6 +695,8 @@ end]]
meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
+ -- empty virt_text should not change anything
+ meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'})
screen:expect{grid=[[
^for _,item in ipairs(items) do |
@@ -698,7 +774,7 @@ end]]
]]}
end)
- it('can have virtual text which combines foreground and backround groups', function()
+ it('can have virtual text which combines foreground and background groups', function()
screen:set_default_attr_ids {
[1] = {bold=true, foreground=Screen.colors.Blue};
[2] = {background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb')};
@@ -789,6 +865,20 @@ end]]
]]}
helpers.assert_alive()
end)
+
+ it('conceal #19007', function()
+ screen:try_resize(50, 5)
+ insert('foo\n')
+ command('let &conceallevel=2')
+ meths.buf_set_extmark(0, ns, 0, 0, {end_col=0, end_row=2, conceal='X'})
+ screen:expect([[
+ {26:X} |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
end)
describe('decorations: virtual lines', function()
@@ -1111,6 +1201,27 @@ if (h->n_buckets < new_n_buckets) { // expand
]]}
end)
+ it('does not cause syntax ml_get error at the end of a buffer #17816', function()
+ command([[syntax region foo keepend start='^foo' end='^$']])
+ command('syntax sync minlines=100')
+ insert('foo')
+ meths.buf_set_extmark(0, ns, 0, 0, {virt_lines = {{{'bar', 'Comment'}}}})
+ screen:expect([[
+ fo^o |
+ {6:bar} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
it('works with a block scrolling up', function()
screen:try_resize(30, 7)
insert("aa\nbb\ncc\ndd\nee\nff\ngg\nhh")
@@ -1362,3 +1473,372 @@ if (h->n_buckets < new_n_buckets) { // expand
end)
end)
+
+describe('decorations: signs', function()
+ local screen, ns
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {foreground = Screen.colors.Blue4, background = Screen.colors.Grey};
+ [2] = {foreground = Screen.colors.Blue1, bold = true};
+ [3] = {background = Screen.colors.Yellow1, foreground = Screen.colors.Blue1};
+ }
+
+ ns = meths.create_namespace 'test'
+ meths.win_set_option(0, 'signcolumn', 'auto:9')
+ end)
+
+ local example_text = [[
+l1
+l2
+l3
+l4
+l5
+]]
+
+ it('can add a single sign (no end row)', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S'})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add a single sign (with end row)', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row=1})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add multiple signs (single extmark)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row = 2})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S l2 |
+ S l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add multiple signs (multiple extmarks)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+ insert(example_text)
+ feed'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 3, -1, {sign_text='S2', end_row = 4})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S1l2 |
+ {1: }l3 |
+ S2l4 |
+ S2l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add multiple signs (multiple extmarks) 2', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S2S1l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ -- TODO(lewis6991): Support ranged signs
+ -- meths.buf_set_extmark(1, ns, 1, -1, {sign_text='S3', end_row = 2})
+
+ -- screen:expect{grid=[[
+ -- {1: }^l1 |
+ -- S3S2S1l2 |
+ -- S3{1: }l3 |
+ -- {1: }l4 |
+ -- {1: }l5 |
+ -- {1: } |
+ -- {2:~ }|
+ -- {2:~ }|
+ -- {2:~ }|
+ -- |
+ -- ]]}
+
+ end)
+
+ it('can add multiple signs (multiple extmarks) 3', function()
+ pending('TODO(lewis6991): Support ranged signs')
+
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1', end_row=2})
+ meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S2', end_row=3})
+
+ screen:expect{grid=[[
+ {1: }^l1 |
+ S1{1: }l2 |
+ S2S1l3 |
+ S2{1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('can add multiple signs (multiple extmarks) 4', function()
+ insert(example_text)
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=0})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row=1})
+
+ screen:expect{grid=[[
+ S1^l1 |
+ S2l2 |
+ {1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with old signs', function()
+ insert(example_text)
+ feed 'gg'
+
+ helpers.command('sign define Oldsign text=x')
+ helpers.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
+
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
+ meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
+
+ screen:expect{grid=[[
+ S4S1^l1 |
+ S2x l2 |
+ S5{1: }l3 |
+ {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with old signs (with range)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+ insert(example_text)
+ feed 'gg'
+
+ helpers.command('sign define Oldsign text=x')
+ helpers.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
+
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S3', end_row = 4})
+ meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
+ meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
+
+ screen:expect{grid=[[
+ S3S4S1^l1 |
+ S2S3x l2 |
+ S5S3{1: }l3 |
+ S3{1: }l4 |
+ S3{1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+ end)
+
+ it('can add a ranged sign (with start out of view)', function()
+ pending('TODO(lewis6991): Support ranged signs')
+
+ insert(example_text)
+ command 'set signcolumn=yes:2'
+ feed 'gg'
+ feed '2<C-e>'
+
+ meths.buf_set_extmark(0, ns, 1, -1, {sign_text='X', end_row=3})
+
+ screen:expect{grid=[[
+ X {1: }^l3 |
+ X {1: }l4 |
+ {1: }l5 |
+ {1: } |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]}
+
+ end)
+
+ it('can add lots of signs', function()
+ screen:try_resize(40, 10)
+ command 'normal 10oa b c d e f g h'
+
+ for i = 1, 10 do
+ meths.buf_set_extmark(0, ns, i, 0, { end_col = 1, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 2, { end_col = 3, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 4, { end_col = 5, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 6, { end_col = 7, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 8, { end_col = 9, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 10, { end_col = 11, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 12, { end_col = 13, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, 14, { end_col = 15, hl_group='Todo' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='W' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='X' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='Y' })
+ meths.buf_set_extmark(0, ns, i, -1, { sign_text='Z' })
+ end
+
+ screen:expect{grid=[[
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:h} |
+ X Y Z W {3:a} {3:b} {3:c} {3:d} {3:e} {3:f} {3:g} {3:^h} |
+ |
+ ]]}
+ end)
+
+end)
+
+describe('decorations: virt_text', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 10)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {foreground = Screen.colors.Brown};
+ [2] = {foreground = Screen.colors.Fuchsia};
+ [3] = {bold = true, foreground = Screen.colors.Blue1};
+ }
+ end)
+
+ it('avoids regression in #17638', function()
+ exec_lua[[
+ vim.wo.number = true
+ vim.wo.relativenumber = true
+ ]]
+
+ command 'normal 4ohello'
+ command 'normal aVIRTUAL'
+
+ local ns = meths.create_namespace('test')
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_text = {{"hello", "String"}},
+ virt_text_win_col = 20,
+ })
+
+ screen:expect{grid=[[
+ {1: 4 } |
+ {1: 3 }hello |
+ {1: 2 }hello {2:hello} |
+ {1: 1 }hello |
+ {1:5 }helloVIRTUA^L |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+
+ -- Trigger a screen update
+ feed('k')
+
+ screen:expect{grid=[[
+ {1: 3 } |
+ {1: 2 }hello |
+ {1: 1 }hello {2:hello} |
+ {1:4 }hell^o |
+ {1: 1 }helloVIRTUAL |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ end)
+
+end)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index bd2692d19a..5d056cd6c3 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -6,7 +6,7 @@ local clear = helpers.clear
local command = helpers.command
local insert = helpers.insert
local write_file = helpers.write_file
-local source = helpers.source
+local exec = helpers.exec
describe('Diff mode screen', function()
local fname = 'Xtest-functional-diff-screen-1'
@@ -57,40 +57,40 @@ describe('Diff mode screen', function()
feed(':set diffopt=filler<cr>')
screen:expect([[
- {1: }{2:------------------}{3:│}{1: }{4:0 }|
- {1: }^1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }{2:------------------}│{1: }{4:0 }|
+ {1: }^1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1:+ }{5:+-- 4 lines: 7···}│{1:+ }{5:+-- 4 lines: 7··}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(':set diffopt+=internal<cr>')
screen:expect([[
- {1: }{2:------------------}{3:│}{1: }{4:0 }|
- {1: }^1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }{2:------------------}│{1: }{4:0 }|
+ {1: }^1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1:+ }{5:+-- 4 lines: 7···}│{1:+ }{5:+-- 4 lines: 7··}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -103,40 +103,40 @@ describe('Diff mode screen', function()
feed(":set diffopt=filler<cr>")
screen:expect([[
- {1: }{4:^0 }{3:│}{1: }{2:-----------------}|
- {1: }1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }{4:^0 }│{1: }{2:-----------------}|
+ {1: }1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1:+ }{5:+-- 4 lines: 7···}│{1:+ }{5:+-- 4 lines: 7··}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(":set diffopt+=internal<cr>")
screen:expect([[
- {1: }{4:^0 }{3:│}{1: }{2:-----------------}|
- {1: }1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1:+ }{5:+-- 4 lines: 7···}{3:│}{1:+ }{5:+-- 4 lines: 7··}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }{4:^0 }│{1: }{2:-----------------}|
+ {1: }1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1:+ }{5:+-- 4 lines: 7···}│{1:+ }{5:+-- 4 lines: 7··}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -149,53 +149,53 @@ describe('Diff mode screen', function()
feed(":set diffopt=filler<cr>")
screen:expect([[
- {1:+ }{5:^+-- 4 lines: 1···}{3:│}{1:+ }{5:+-- 4 lines: 1··}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{2:------------------}{3:│}{1: }{4:11 }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:+ }{5:^+-- 4 lines: 1···}│{1:+ }{5:+-- 4 lines: 1··}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{2:------------------}│{1: }{4:11 }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(":set diffopt+=internal<cr>")
screen:expect([[
- {1:+ }{5:^+-- 4 lines: 1···}{3:│}{1:+ }{5:+-- 4 lines: 1··}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{2:------------------}{3:│}{1: }{4:11 }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:+ }{5:^+-- 4 lines: 1···}│{1:+ }{5:+-- 4 lines: 1··}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{2:------------------}│{1: }{4:11 }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
screen:try_resize(40, 9)
screen:expect([[
- {1:+ }{5:^+-- 4 lines: 1···}{3:│}{1:+ }{5:+-- 4 lines: 1··}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
+ {1:+ }{5:^+-- 4 lines: 1···}│{1:+ }{5:+-- 4 lines: 1··}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
@@ -208,53 +208,53 @@ describe('Diff mode screen', function()
feed(":set diffopt=filler<cr>")
screen:expect([[
- {1:+ }{5:^+-- 4 lines: 1···}{3:│}{1:+ }{5:+-- 4 lines: 1··}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{4:11 }{3:│}{1: }{2:-----------------}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:+ }{5:^+-- 4 lines: 1···}│{1:+ }{5:+-- 4 lines: 1··}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{4:11 }│{1: }{2:-----------------}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(":set diffopt+=internal<cr>")
screen:expect([[
- {1:+ }{5:^+-- 4 lines: 1···}{3:│}{1:+ }{5:+-- 4 lines: 1··}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{4:11 }{3:│}{1: }{2:-----------------}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:+ }{5:^+-- 4 lines: 1···}│{1:+ }{5:+-- 4 lines: 1··}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{4:11 }│{1: }{2:-----------------}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
screen:try_resize(40, 9)
screen:expect([[
- {1:+ }{5:^+-- 4 lines: 1···}{3:│}{1:+ }{5:+-- 4 lines: 1··}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
+ {1:+ }{5:^+-- 4 lines: 1···}│{1:+ }{5:+-- 4 lines: 1··}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
@@ -267,40 +267,40 @@ describe('Diff mode screen', function()
feed(':set diffopt=filler<cr>')
screen:expect([[
- {1: }^1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }{2:------------------}{3:│}{1: }{4:4 }|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{4:11 }{3:│}{1: }{2:-----------------}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }{2:------------------}│{1: }{4:4 }|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{4:11 }│{1: }{2:-----------------}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(':set diffopt+=internal<cr>')
screen:expect([[
- {1: }^1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }{2:------------------}{3:│}{1: }{4:4 }|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{4:11 }{3:│}{1: }{2:-----------------}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }{2:------------------}│{1: }{4:4 }|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{4:11 }│{1: }{2:-----------------}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -313,40 +313,40 @@ describe('Diff mode screen', function()
feed(':set diffopt=filler<cr>')
screen:expect([[
- {1: }^1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }{4:4 }{3:│}{1: }{2:-----------------}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{2:------------------}{3:│}{1: }{4:11 }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }{4:4 }│{1: }{2:-----------------}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{2:------------------}│{1: }{4:11 }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(':set diffopt+=internal<cr>')
screen:expect([[
- {1: }^1 {3:│}{1: }1 |
- {1: }2 {3:│}{1: }2 |
- {1: }3 {3:│}{1: }3 |
- {1: }4 {3:│}{1: }4 |
- {1: }{4:4 }{3:│}{1: }{2:-----------------}|
- {1: }5 {3:│}{1: }5 |
- {1: }6 {3:│}{1: }6 |
- {1: }7 {3:│}{1: }7 |
- {1: }8 {3:│}{1: }8 |
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }{2:------------------}{3:│}{1: }{4:11 }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^1 │{1: }1 |
+ {1: }2 │{1: }2 |
+ {1: }3 │{1: }3 |
+ {1: }4 │{1: }4 |
+ {1: }{4:4 }│{1: }{2:-----------------}|
+ {1: }5 │{1: }5 |
+ {1: }6 │{1: }6 |
+ {1: }7 │{1: }7 |
+ {1: }8 │{1: }8 |
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }{2:------------------}│{1: }{4:11 }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -413,40 +413,40 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=internal,filler<cr>')
screen:expect([[
- {1: }^#include <stdio.h>{3:│}{1: }#include <stdio.h|
- {1: } {3:│}{1: } |
- {1: }{8:// Frobs foo heart}{3:│}{1: }{8:int fib(int n)}{9: }|
- {1: }{4:int frobnitz(int f}{3:│}{1: }{2:-----------------}|
- {1: }{ {3:│}{1: }{ |
- {1: }{9: i}{8:nt i;}{9: }{3:│}{1: }{9: i}{8:f(n > 2)}{9: }|
- {1: }{4: for(i = 0; i <}{3:│}{1: }{2:-----------------}|
- {1: } { {3:│}{1: } { |
- {1: }{9: }{8:printf("Yo}{3:│}{1: }{9: }{8:return fi}|
- {1: }{4: printf("%d}{3:│}{1: }{2:-----------------}|
- {1: } } {3:│}{1: } } |
- {1: }{2:------------------}{3:│}{1: }{4: return 1; }|
- {1: }} {3:│}{1: }} |
- {1: } {3:│}{1: } |
+ {1: }^#include <stdio.h>│{1: }#include <stdio.h|
+ {1: } │{1: } |
+ {1: }{8:// Frobs foo heart}│{1: }{8:int fib(int n)}{9: }|
+ {1: }{4:int frobnitz(int f}│{1: }{2:-----------------}|
+ {1: }{ │{1: }{ |
+ {1: }{9: i}{8:nt i;}{9: }│{1: }{9: i}{8:f(n > 2)}{9: }|
+ {1: }{4: for(i = 0; i <}│{1: }{2:-----------------}|
+ {1: } { │{1: } { |
+ {1: }{9: }{8:printf("Yo}│{1: }{9: }{8:return fi}|
+ {1: }{4: printf("%d}│{1: }{2:-----------------}|
+ {1: } } │{1: } } |
+ {1: }{2:------------------}│{1: }{4: return 1; }|
+ {1: }} │{1: }} |
+ {1: } │{1: } |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=internal,filler |
]])
feed('G')
screen:expect([[
- {1: }{2:------------------}{3:│}{1: }{4:int frobnitz(int }|
- {1: }{ {3:│}{1: }{ |
- {1: }{9: i}{8:f(n > 1)}{9: }{3:│}{1: }{9: i}{8:nt i;}{9: }|
- {1: }{2:------------------}{3:│}{1: }{4: for(i = 0; i }|
- {1: } { {3:│}{1: } { |
- {1: }{9: }{8:return fac}{3:│}{1: }{9: }{8:printf("%}|
- {1: } } {3:│}{1: } } |
- {1: }{4: return 1; }{3:│}{1: }{2:-----------------}|
- {1: }} {3:│}{1: }} |
- {1: } {3:│}{1: } |
- {1: }int main(int argc,{3:│}{1: }int main(int argc|
- {1: }{ {3:│}{1: }{ |
- {1: }{9: frobnitz(f}{8:act}{9:(}{3:│}{1: }{9: frobnitz(f}{8:ib}{9:(}|
- {1: }^} {3:│}{1: }} |
+ {1: }{2:------------------}│{1: }{4:int frobnitz(int }|
+ {1: }{ │{1: }{ |
+ {1: }{9: i}{8:f(n > 1)}{9: }│{1: }{9: i}{8:nt i;}{9: }|
+ {1: }{2:------------------}│{1: }{4: for(i = 0; i }|
+ {1: } { │{1: } { |
+ {1: }{9: }{8:return fac}│{1: }{9: }{8:printf("%}|
+ {1: } } │{1: } } |
+ {1: }{4: return 1; }│{1: }{2:-----------------}|
+ {1: }} │{1: }} |
+ {1: } │{1: } |
+ {1: }int main(int argc,│{1: }int main(int argc|
+ {1: }{ │{1: }{ |
+ {1: }{9: frobnitz(f}{8:act}{9:(}│{1: }{9: frobnitz(f}{8:ib}{9:(}|
+ {1: }^} │{1: }} |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=internal,filler |
]])
@@ -456,40 +456,40 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=internal,filler,algorithm:patience<cr>')
screen:expect([[
- {1: }^#include <stdio.h>{3:│}{1: }#include <stdio.h|
- {1: } {3:│}{1: } |
- {1: }{2:------------------}{3:│}{1: }{4:int fib(int n) }|
- {1: }{2:------------------}{3:│}{1: }{4:{ }|
- {1: }{2:------------------}{3:│}{1: }{4: if(n > 2) }|
- {1: }{2:------------------}{3:│}{1: }{4: { }|
- {1: }{2:------------------}{3:│}{1: }{4: return fi}|
- {1: }{2:------------------}{3:│}{1: }{4: } }|
- {1: }{2:------------------}{3:│}{1: }{4: return 1; }|
- {1: }{2:------------------}{3:│}{1: }{4:} }|
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: }// Frobs foo heart{3:│}{1: }// Frobs foo hear|
- {1: }int frobnitz(int f{3:│}{1: }int frobnitz(int |
- {1: }{ {3:│}{1: }{ |
+ {1: }^#include <stdio.h>│{1: }#include <stdio.h|
+ {1: } │{1: } |
+ {1: }{2:------------------}│{1: }{4:int fib(int n) }|
+ {1: }{2:------------------}│{1: }{4:{ }|
+ {1: }{2:------------------}│{1: }{4: if(n > 2) }|
+ {1: }{2:------------------}│{1: }{4: { }|
+ {1: }{2:------------------}│{1: }{4: return fi}|
+ {1: }{2:------------------}│{1: }{4: } }|
+ {1: }{2:------------------}│{1: }{4: return 1; }|
+ {1: }{2:------------------}│{1: }{4:} }|
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: }// Frobs foo heart│{1: }// Frobs foo hear|
+ {1: }int frobnitz(int f│{1: }int frobnitz(int |
+ {1: }{ │{1: }{ |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
feed('G')
screen:expect([[
- {1: } {3:│}{1: } |
- {1: }{4:int fact(int n) }{3:│}{1: }{2:-----------------}|
- {1: }{4:{ }{3:│}{1: }{2:-----------------}|
- {1: }{4: if(n > 1) }{3:│}{1: }{2:-----------------}|
- {1: }{4: { }{3:│}{1: }{2:-----------------}|
- {1: }{4: return fac}{3:│}{1: }{2:-----------------}|
- {1: }{4: } }{3:│}{1: }{2:-----------------}|
- {1: }{4: return 1; }{3:│}{1: }{2:-----------------}|
- {1: }{4:} }{3:│}{1: }{2:-----------------}|
- {1: }{4: }{3:│}{1: }{2:-----------------}|
- {1: }int main(int argc,{3:│}{1: }int main(int argc|
- {1: }{ {3:│}{1: }{ |
- {1: }{9: frobnitz(f}{8:act}{9:(}{3:│}{1: }{9: frobnitz(f}{8:ib}{9:(}|
- {1: }^} {3:│}{1: }} |
+ {1: } │{1: } |
+ {1: }{4:int fact(int n) }│{1: }{2:-----------------}|
+ {1: }{4:{ }│{1: }{2:-----------------}|
+ {1: }{4: if(n > 1) }│{1: }{2:-----------------}|
+ {1: }{4: { }│{1: }{2:-----------------}|
+ {1: }{4: return fac}│{1: }{2:-----------------}|
+ {1: }{4: } }│{1: }{2:-----------------}|
+ {1: }{4: return 1; }│{1: }{2:-----------------}|
+ {1: }{4:} }│{1: }{2:-----------------}|
+ {1: }{4: }│{1: }{2:-----------------}|
+ {1: }int main(int argc,│{1: }int main(int argc|
+ {1: }{ │{1: }{ |
+ {1: }{9: frobnitz(f}{8:act}{9:(}│{1: }{9: frobnitz(f}{8:ib}{9:(}|
+ {1: }^} │{1: }} |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
@@ -499,40 +499,40 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=internal,filler,algorithm:histogram<cr>')
screen:expect([[
- {1: }^#include <stdio.h>{3:│}{1: }#include <stdio.h|
- {1: } {3:│}{1: } |
- {1: }{2:------------------}{3:│}{1: }{4:int fib(int n) }|
- {1: }{2:------------------}{3:│}{1: }{4:{ }|
- {1: }{2:------------------}{3:│}{1: }{4: if(n > 2) }|
- {1: }{2:------------------}{3:│}{1: }{4: { }|
- {1: }{2:------------------}{3:│}{1: }{4: return fi}|
- {1: }{2:------------------}{3:│}{1: }{4: } }|
- {1: }{2:------------------}{3:│}{1: }{4: return 1; }|
- {1: }{2:------------------}{3:│}{1: }{4:} }|
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: }// Frobs foo heart{3:│}{1: }// Frobs foo hear|
- {1: }int frobnitz(int f{3:│}{1: }int frobnitz(int |
- {1: }{ {3:│}{1: }{ |
+ {1: }^#include <stdio.h>│{1: }#include <stdio.h|
+ {1: } │{1: } |
+ {1: }{2:------------------}│{1: }{4:int fib(int n) }|
+ {1: }{2:------------------}│{1: }{4:{ }|
+ {1: }{2:------------------}│{1: }{4: if(n > 2) }|
+ {1: }{2:------------------}│{1: }{4: { }|
+ {1: }{2:------------------}│{1: }{4: return fi}|
+ {1: }{2:------------------}│{1: }{4: } }|
+ {1: }{2:------------------}│{1: }{4: return 1; }|
+ {1: }{2:------------------}│{1: }{4:} }|
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: }// Frobs foo heart│{1: }// Frobs foo hear|
+ {1: }int frobnitz(int f│{1: }int frobnitz(int |
+ {1: }{ │{1: }{ |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
feed('G')
screen:expect([[
- {1: } {3:│}{1: } |
- {1: }{4:int fact(int n) }{3:│}{1: }{2:-----------------}|
- {1: }{4:{ }{3:│}{1: }{2:-----------------}|
- {1: }{4: if(n > 1) }{3:│}{1: }{2:-----------------}|
- {1: }{4: { }{3:│}{1: }{2:-----------------}|
- {1: }{4: return fac}{3:│}{1: }{2:-----------------}|
- {1: }{4: } }{3:│}{1: }{2:-----------------}|
- {1: }{4: return 1; }{3:│}{1: }{2:-----------------}|
- {1: }{4:} }{3:│}{1: }{2:-----------------}|
- {1: }{4: }{3:│}{1: }{2:-----------------}|
- {1: }int main(int argc,{3:│}{1: }int main(int argc|
- {1: }{ {3:│}{1: }{ |
- {1: }{9: frobnitz(f}{8:act}{9:(}{3:│}{1: }{9: frobnitz(f}{8:ib}{9:(}|
- {1: }^} {3:│}{1: }} |
+ {1: } │{1: } |
+ {1: }{4:int fact(int n) }│{1: }{2:-----------------}|
+ {1: }{4:{ }│{1: }{2:-----------------}|
+ {1: }{4: if(n > 1) }│{1: }{2:-----------------}|
+ {1: }{4: { }│{1: }{2:-----------------}|
+ {1: }{4: return fac}│{1: }{2:-----------------}|
+ {1: }{4: } }│{1: }{2:-----------------}|
+ {1: }{4: return 1; }│{1: }{2:-----------------}|
+ {1: }{4:} }│{1: }{2:-----------------}|
+ {1: }{4: }│{1: }{2:-----------------}|
+ {1: }int main(int argc,│{1: }int main(int argc|
+ {1: }{ │{1: }{ |
+ {1: }{9: frobnitz(f}{8:act}{9:(}│{1: }{9: frobnitz(f}{8:ib}{9:(}|
+ {1: }^} │{1: }} |
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
@@ -566,20 +566,20 @@ int main(int argc, char **argv)
reread()
feed(":set diffopt=internal,filler<cr>")
screen:expect([[
- {1: }^def finalize(value{3:│}{1: }def finalize(valu|
- {1: } {3:│}{1: } |
- {1: } values.each do |{3:│}{1: } values.each do |
- {1: }{2:------------------}{3:│}{1: }{4: v.prepare }|
- {1: }{2:------------------}{3:│}{1: }{4: end }|
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: }{2:------------------}{3:│}{1: }{4: values.each do }|
- {1: } v.finalize {3:│}{1: } v.finalize |
- {1: } end {3:│}{1: } end |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^def finalize(value│{1: }def finalize(valu|
+ {1: } │{1: } |
+ {1: } values.each do |│{1: } values.each do |
+ {1: }{2:------------------}│{1: }{4: v.prepare }|
+ {1: }{2:------------------}│{1: }{4: end }|
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: }{2:------------------}│{1: }{4: values.each do }|
+ {1: } v.finalize │{1: } v.finalize |
+ {1: } end │{1: } end |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=internal,filler |
]])
@@ -589,20 +589,20 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=internal,filler,indent-heuristic<cr>')
screen:expect([[
- {1: }^def finalize(value{3:│}{1: }def finalize(valu|
- {1: } {3:│}{1: } |
- {1: }{2:------------------}{3:│}{1: }{4: values.each do }|
- {1: }{2:------------------}{3:│}{1: }{4: v.prepare }|
- {1: }{2:------------------}{3:│}{1: }{4: end }|
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: } values.each do |{3:│}{1: } values.each do |
- {1: } v.finalize {3:│}{1: } v.finalize |
- {1: } end {3:│}{1: } end |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^def finalize(value│{1: }def finalize(valu|
+ {1: } │{1: } |
+ {1: }{2:------------------}│{1: }{4: values.each do }|
+ {1: }{2:------------------}│{1: }{4: v.prepare }|
+ {1: }{2:------------------}│{1: }{4: end }|
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: } values.each do |│{1: } values.each do |
+ {1: } v.finalize │{1: } v.finalize |
+ {1: } end │{1: } end |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
|
]])
@@ -613,20 +613,20 @@ int main(int argc, char **argv)
feed(':set diffopt=internal,filler,indent-heuristic,algorithm:patience<cr>')
feed(':<cr>')
screen:expect([[
- {1: }^def finalize(value{3:│}{1: }def finalize(valu|
- {1: } {3:│}{1: } |
- {1: }{2:------------------}{3:│}{1: }{4: values.each do }|
- {1: }{2:------------------}{3:│}{1: }{4: v.prepare }|
- {1: }{2:------------------}{3:│}{1: }{4: end }|
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: } values.each do |{3:│}{1: } values.each do |
- {1: } v.finalize {3:│}{1: } v.finalize |
- {1: } end {3:│}{1: } end |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^def finalize(value│{1: }def finalize(valu|
+ {1: } │{1: } |
+ {1: }{2:------------------}│{1: }{4: values.each do }|
+ {1: }{2:------------------}│{1: }{4: v.prepare }|
+ {1: }{2:------------------}│{1: }{4: end }|
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: } values.each do |│{1: } values.each do |
+ {1: } v.finalize │{1: } v.finalize |
+ {1: } end │{1: } end |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
: |
]])
@@ -640,40 +640,40 @@ int main(int argc, char **argv)
feed(':set diffopt=filler<cr>')
screen:expect([[
- {1:+ }{5:^+-- 10 lines: 1···}{3:│}{1:+ }{5:+-- 10 lines: 1··}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:+ }{5:^+-- 10 lines: 1···}│{1:+ }{5:+-- 10 lines: 1··}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(':set diffopt+=internal<cr>')
screen:expect([[
- {1:+ }{5:^+-- 10 lines: 1···}{3:│}{1:+ }{5:+-- 10 lines: 1··}|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:+ }{5:^+-- 10 lines: 1···}│{1:+ }{5:+-- 10 lines: 1··}|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -686,40 +686,40 @@ int main(int argc, char **argv)
feed(':set diffopt=filler<cr>')
screen:expect([[
- {1:- }^ {3:│}{1:- } |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:- }^ │{1:- } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler |
]])
feed(':set diffopt+=internal<cr>')
screen:expect([[
- {1:- }^ {3:│}{1:- } |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1:- }^ │{1:- } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -732,40 +732,40 @@ int main(int argc, char **argv)
feed(':set diffopt=filler,icase<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }A |
- {1: }b {3:│}{1: }b |
- {1: }{9:cd }{3:│}{1: }{9:cD}{8:e}{9: }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }A |
+ {1: }b │{1: }b |
+ {1: }{9:cd }│{1: }{9:cD}{8:e}{9: }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler,icase |
]])
feed(':set diffopt+=internal<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }A |
- {1: }b {3:│}{1: }b |
- {1: }{9:cd }{3:│}{1: }{9:cD}{8:e}{9: }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }A |
+ {1: }b │{1: }b |
+ {1: }{9:cd }│{1: }{9:cD}{8:e}{9: }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt+=internal |
]])
@@ -784,20 +784,20 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=filler,iwhite<cr>')
screen:expect([[
- {1: }^int main() {3:│}{1: }int main() |
- {1: }{ {3:│}{1: }{ |
- {1: }{2:------------------}{3:│}{1: }{4: if (0) }|
- {1: }{2:------------------}{3:│}{1: }{4: { }|
- {1: } printf("Hello, {3:│}{1: } printf("Hel|
- {1: } return 0; {3:│}{1: } return 0; |
- {1: }{2:------------------}{3:│}{1: }{4: } }|
- {1: }} {3:│}{1: }} |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^int main() │{1: }int main() |
+ {1: }{ │{1: }{ |
+ {1: }{2:------------------}│{1: }{4: if (0) }|
+ {1: }{2:------------------}│{1: }{4: { }|
+ {1: } printf("Hello, │{1: } printf("Hel|
+ {1: } return 0; │{1: } return 0; |
+ {1: }{2:------------------}│{1: }{4: } }|
+ {1: }} │{1: }} |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler,iwhite |
]])
@@ -807,20 +807,20 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=filler,iwhite,internal<cr>')
screen:expect([[
- {1: }^int main() {3:│}{1: }int main() |
- {1: }{ {3:│}{1: }{ |
- {1: }{2:------------------}{3:│}{1: }{4: if (0) }|
- {1: }{2:------------------}{3:│}{1: }{4: { }|
- {1: } printf("Hello, {3:│}{1: } printf("Hel|
- {1: } return 0; {3:│}{1: } return 0; |
- {1: }{2:------------------}{3:│}{1: }{4: } }|
- {1: }} {3:│}{1: }} |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^int main() │{1: }int main() |
+ {1: }{ │{1: }{ |
+ {1: }{2:------------------}│{1: }{4: if (0) }|
+ {1: }{2:------------------}│{1: }{4: { }|
+ {1: } printf("Hello, │{1: } printf("Hel|
+ {1: } return 0; │{1: } return 0; |
+ {1: }{2:------------------}│{1: }{4: } }|
+ {1: }} │{1: }} |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=filler,iwhite,internal |
]])
@@ -838,20 +838,20 @@ int main(int argc, char **argv)
reread()
feed(':set diffopt=internal,filler,iblank<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }a |
- {1: }{4: }{3:│}{1: }{2:-----------------}|
- {1: }{4: }{3:│}{1: }{2:-----------------}|
- {1: }cd {3:│}{1: }cd |
- {1: }ef {3:│}{1: } |
- {1: }{8:xxx}{9: }{3:│}{1: }ef |
- {6:~ }{3:│}{1: }{8:yyy}{9: }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }a |
+ {1: }{4: }│{1: }{2:-----------------}|
+ {1: }{4: }│{1: }{2:-----------------}|
+ {1: }cd │{1: }cd |
+ {1: }ef │{1: } |
+ {1: }{8:xxx}{9: }│{1: }ef |
+ {6:~ }│{1: }{8:yyy}{9: }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
:set diffopt=internal,filler,iblank |
]])
@@ -862,20 +862,20 @@ int main(int argc, char **argv)
feed(':set diffopt=internal,filler,iblank,iwhite<cr>')
feed(':<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }a |
- {1: } {3:│}{1: }cd |
- {1: } {3:│}{1: } |
- {1: }cd {3:│}{1: }ef |
- {1: }ef {3:│}{1: }{8:yyy}{9: }|
- {1: }{8:xxx}{9: }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }a |
+ {1: } │{1: }cd |
+ {1: } │{1: } |
+ {1: }cd │{1: }ef |
+ {1: }ef │{1: }{8:yyy}{9: }|
+ {1: }{8:xxx}{9: }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
: |
]])
@@ -886,20 +886,20 @@ int main(int argc, char **argv)
feed(':set diffopt=internal,filler,iblank,iwhiteall<cr>')
feed(':<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }a |
- {1: } {3:│}{1: }cd |
- {1: } {3:│}{1: } |
- {1: }cd {3:│}{1: }ef |
- {1: }ef {3:│}{1: }{8:yyy}{9: }|
- {1: }{8:xxx}{9: }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }a |
+ {1: } │{1: }cd |
+ {1: } │{1: } |
+ {1: }cd │{1: }ef |
+ {1: }ef │{1: }{8:yyy}{9: }|
+ {1: }{8:xxx}{9: }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
: |
]])
@@ -910,20 +910,20 @@ int main(int argc, char **argv)
feed(':set diffopt=internal,filler,iblank,iwhiteeol<cr>')
feed(':<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }a |
- {1: } {3:│}{1: }cd |
- {1: } {3:│}{1: } |
- {1: }cd {3:│}{1: }ef |
- {1: }ef {3:│}{1: }{8:yyy}{9: }|
- {1: }{8:xxx}{9: }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }a |
+ {1: } │{1: }cd |
+ {1: } │{1: } |
+ {1: }cd │{1: }ef |
+ {1: }ef │{1: }{8:yyy}{9: }|
+ {1: }{8:xxx}{9: }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
: |
]])
@@ -942,20 +942,20 @@ int main(int argc, char **argv)
feed(':set diffopt=internal,filler,iwhiteeol<cr>')
feed(':<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }a |
- {1: }x {3:│}{1: }x |
- {1: }{9:cd }{3:│}{1: }{9:c}{8: }{9:d }|
- {1: }{9:ef }{3:│}{1: }{8: }{9:ef }|
- {1: }{9:xx }{8: }{9:xx }{3:│}{1: }{9:xx xx }|
- {1: }foo {3:│}{1: }foo |
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: }bar {3:│}{1: }bar |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }a |
+ {1: }x │{1: }x |
+ {1: }{9:cd }│{1: }{9:c}{8: }{9:d }|
+ {1: }{9:ef }│{1: }{8: }{9:ef }|
+ {1: }{9:xx }{8: }{9:xx }│{1: }{9:xx xx }|
+ {1: }foo │{1: }foo |
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: }bar │{1: }bar |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
: |
]])
@@ -966,20 +966,20 @@ int main(int argc, char **argv)
feed(':set diffopt=internal,filler,iwhiteall<cr>')
feed(':<cr>')
screen:expect([[
- {1: }^a {3:│}{1: }a |
- {1: }x {3:│}{1: }x |
- {1: }cd {3:│}{1: }c d |
- {1: }ef {3:│}{1: } ef |
- {1: }xx xx {3:│}{1: }xx xx |
- {1: }foo {3:│}{1: }foo |
- {1: }{2:------------------}{3:│}{1: }{4: }|
- {1: }bar {3:│}{1: }bar |
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
- {6:~ }{3:│}{6:~ }|
+ {1: }^a │{1: }a |
+ {1: }x │{1: }x |
+ {1: }cd │{1: }c d |
+ {1: }ef │{1: } ef |
+ {1: }xx xx │{1: }xx xx |
+ {1: }foo │{1: }foo |
+ {1: }{2:------------------}│{1: }{4: }|
+ {1: }bar │{1: }bar |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
{7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
: |
]])
@@ -1029,14 +1029,14 @@ it('win_update redraws lines properly', function()
command("windo diffthis")
command("windo 1")
screen:expect{grid=[[
- {13: }{16:-----------------------}{14:│}{13: }{15:^1 }|
- {13: }{16:-----------------------}{14:│}{13: }{15: }|
- {13: }{16:-----------------------}{14:│}{13: }{15: }|
- {13: }2 {14:│}{13: }2 |
- {13: }{17:2}{18:a }{14:│}{13: }{17:1}{18:a }|
- {13: }{15:2b }{14:│}{13: }{16:----------------------}|
- {13: } {14:│}{13: } |
- {1:~ }{14:│}{1:~ }|
+ {13: }{16:-----------------------}│{13: }{15:^1 }|
+ {13: }{16:-----------------------}│{13: }{15: }|
+ {13: }{16:-----------------------}│{13: }{15: }|
+ {13: }2 │{13: }2 |
+ {13: }{17:2}{18:a }│{13: }{17:1}{18:a }|
+ {13: }{15:2b }│{13: }{16:----------------------}|
+ {13: } │{13: } |
+ {1:~ }│{1:~ }|
{14:left [+] }{12:[No Name] [+] }|
|
]]}
@@ -1046,14 +1046,14 @@ it('win_update redraws lines properly', function()
feed('<C-y>')
feed('<C-y>')
screen:expect{grid=[[
- {13: }{16:-----------------------}{14:│}{13: }{15:1 }|
- {13: }{16:-----------------------}{14:│}{13: }{15: }|
- {13: }{16:-----------------------}{14:│}{13: }{15:^ }|
- {13: }2 {14:│}{13: }2 |
- {13: }{17:2}{18:a }{14:│}{13: }{17:1}{18:a }|
- {13: }{15:2b }{14:│}{13: }{16:----------------------}|
- {13: } {14:│}{13: } |
- {1:~ }{14:│}{1:~ }|
+ {13: }{16:-----------------------}│{13: }{15:1 }|
+ {13: }{16:-----------------------}│{13: }{15: }|
+ {13: }{16:-----------------------}│{13: }{15:^ }|
+ {13: }2 │{13: }2 |
+ {13: }{17:2}{18:a }│{13: }{17:1}{18:a }|
+ {13: }{15:2b }│{13: }{16:----------------------}|
+ {13: } │{13: } |
+ {1:~ }│{1:~ }|
{14:left [+] }{12:[No Name] [+] }|
|
]]}
@@ -1075,10 +1075,8 @@ it('diff updates line numbers below filler lines', function()
[9] = {background = Screen.colors.LightMagenta},
[10] = {bold = true, foreground = Screen.colors.Brown},
[11] = {foreground = Screen.colors.Brown},
- [12] = {foreground = Screen.colors.Brown, bold = true, background = Screen.colors.Red};
- [13] = {background = Screen.colors.Gray90};
})
- source([[
+ exec([[
call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b'])
vnew
call setline(1, ['a', 'a', 'a', 'x', 'x', 'x', 'b', 'b', 'b', 'b', 'b'])
@@ -1086,73 +1084,55 @@ it('diff updates line numbers below filler lines', function()
setlocal number rnu cursorline cursorlineopt=number foldcolumn=0
]])
screen:expect([[
- {1: }a {3:│}{10:1 }^a |
- {1: }a {3:│}{11: 1 }a |
- {1: }a {3:│}{11: 2 }a |
- {1: }{8:x}{9: }{3:│}{11: 3 }{8:y}{9: }|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }b {3:│}{11: 4 }b |
- {1: }b {3:│}{11: 5 }b |
- {1: }b {3:│}{11: 6 }b |
- {1: }b {3:│}{11: 7 }b |
- {1: }b {3:│}{11: 8 }b |
- {6:~ }{3:│}{6:~ }|
+ {1: }a │{10:1 }^a |
+ {1: }a │{11: 1 }a |
+ {1: }a │{11: 2 }a |
+ {1: }{8:x}{9: }│{11: 3 }{8:y}{9: }|
+ {1: }{4:x }│{11: }{2:----------------}|
+ {1: }{4:x }│{11: }{2:----------------}|
+ {1: }b │{11: 4 }b |
+ {1: }b │{11: 5 }b |
+ {1: }b │{11: 6 }b |
+ {1: }b │{11: 7 }b |
+ {1: }b │{11: 8 }b |
+ {6:~ }│{6:~ }|
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
feed('j')
screen:expect([[
- {1: }a {3:│}{11: 1 }a |
- {1: }a {3:│}{10:2 }^a |
- {1: }a {3:│}{11: 1 }a |
- {1: }{8:x}{9: }{3:│}{11: 2 }{8:y}{9: }|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }b {3:│}{11: 3 }b |
- {1: }b {3:│}{11: 4 }b |
- {1: }b {3:│}{11: 5 }b |
- {1: }b {3:│}{11: 6 }b |
- {1: }b {3:│}{11: 7 }b |
- {6:~ }{3:│}{6:~ }|
+ {1: }a │{11: 1 }a |
+ {1: }a │{10:2 }^a |
+ {1: }a │{11: 1 }a |
+ {1: }{8:x}{9: }│{11: 2 }{8:y}{9: }|
+ {1: }{4:x }│{11: }{2:----------------}|
+ {1: }{4:x }│{11: }{2:----------------}|
+ {1: }b │{11: 3 }b |
+ {1: }b │{11: 4 }b |
+ {1: }b │{11: 5 }b |
+ {1: }b │{11: 6 }b |
+ {1: }b │{11: 7 }b |
+ {6:~ }│{6:~ }|
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
feed('j')
screen:expect([[
- {1: }a {3:│}{11: 2 }a |
- {1: }a {3:│}{11: 1 }a |
- {1: }a {3:│}{10:3 }^a |
- {1: }{8:x}{9: }{3:│}{11: 1 }{8:y}{9: }|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }b {3:│}{11: 2 }b |
- {1: }b {3:│}{11: 3 }b |
- {1: }b {3:│}{11: 4 }b |
- {1: }b {3:│}{11: 5 }b |
- {1: }b {3:│}{11: 6 }b |
- {6:~ }{3:│}{6:~ }|
+ {1: }a │{11: 2 }a |
+ {1: }a │{11: 1 }a |
+ {1: }a │{10:3 }^a |
+ {1: }{8:x}{9: }│{11: 1 }{8:y}{9: }|
+ {1: }{4:x }│{11: }{2:----------------}|
+ {1: }{4:x }│{11: }{2:----------------}|
+ {1: }b │{11: 2 }b |
+ {1: }b │{11: 3 }b |
+ {1: }b │{11: 4 }b |
+ {1: }b │{11: 5 }b |
+ {1: }b │{11: 6 }b |
+ {6:~ }│{6:~ }|
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
- command("set signcolumn number tgc cursorline cursorlineopt=number,line")
- command("hi CursorLineNr guibg=red")
- screen:expect{grid=[[
- {1: }a {3:│}{11: 2 }a |
- {1: }a {3:│}{11: 1 }a |
- {1: }a {3:│}{12:3 }{13:^a }|
- {1: }{8:x}{9: }{3:│}{11: 1 }{8:y}{9: }|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }{4:x }{3:│}{11: }{2:----------------}|
- {1: }b {3:│}{11: 2 }b |
- {1: }b {3:│}{11: 3 }b |
- {1: }b {3:│}{11: 4 }b |
- {1: }b {3:│}{11: 5 }b |
- {1: }b {3:│}{11: 6 }b |
- {6:~ }{3:│}{6:~ }|
- {3:[No Name] [+] }{7:[No Name] [+] }|
- signcolumn=auto |
- ]]}
end)
it('Align the filler lines when changing text in diff mode', function()
@@ -1169,7 +1149,7 @@ it('Align the filler lines when changing text in diff mode', function()
[7] = {foreground = Screen.colors.Blue1, bold = true};
[8] = {reverse = true, bold = true};
})
- source([[
+ exec([[
call setline(1, range(1, 15))
vnew
call setline(1, range(9, 15))
@@ -1178,71 +1158,198 @@ it('Align the filler lines when changing text in diff mode', function()
exe "normal Gl5\<C-E>"
]])
screen:expect{grid=[[
- {1: }{2:------------------}{3:│}{1: }{4:6 }|
- {1: }{2:------------------}{3:│}{1: }{4:7 }|
- {1: }{2:------------------}{3:│}{1: }{4:8 }|
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }11 {3:│}{1: }11 |
- {1: }12 {3:│}{1: }12 |
- {1: }13 {3:│}{1: }13 |
- {1: }14 {3:│}{1: }14 |
- {1:- }1^5 {3:│}{1:- }15 |
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
+ {1: }{2:------------------}│{1: }{4:6 }|
+ {1: }{2:------------------}│{1: }{4:7 }|
+ {1: }{2:------------------}│{1: }{4:8 }|
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }11 │{1: }11 |
+ {1: }12 │{1: }12 |
+ {1: }13 │{1: }13 |
+ {1: }14 │{1: }14 |
+ {1:- }1^5 │{1:- }15 |
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
{8:[No Name] [+] }{3:[No Name] [+] }|
|
]]}
feed('ax<Esc>')
screen:expect{grid=[[
- {1: }{2:------------------}{3:│}{1: }{4:6 }|
- {1: }{2:------------------}{3:│}{1: }{4:7 }|
- {1: }{2:------------------}{3:│}{1: }{4:8 }|
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }11 {3:│}{1: }11 |
- {1: }12 {3:│}{1: }12 |
- {1: }13 {3:│}{1: }13 |
- {1: }14 {3:│}{1: }14 |
- {1: }{5:15}{6:^x}{5: }{3:│}{1: }{5:15 }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
+ {1: }{2:------------------}│{1: }{4:6 }|
+ {1: }{2:------------------}│{1: }{4:7 }|
+ {1: }{2:------------------}│{1: }{4:8 }|
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }11 │{1: }11 |
+ {1: }12 │{1: }12 |
+ {1: }13 │{1: }13 |
+ {1: }14 │{1: }14 |
+ {1: }{5:15}{6:^x}{5: }│{1: }{5:15 }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
{8:[No Name] [+] }{3:[No Name] [+] }|
|
]]}
feed('<C-W>lay<Esc>')
screen:expect{grid=[[
- {1: }{2:-----------------}{3:│}{1: }{4:6 }|
- {1: }{2:-----------------}{3:│}{1: }{4:7 }|
- {1: }{2:-----------------}{3:│}{1: }{4:8 }|
- {1: }9 {3:│}{1: }9 |
- {1: }10 {3:│}{1: }10 |
- {1: }11 {3:│}{1: }11 |
- {1: }12 {3:│}{1: }12 |
- {1: }13 {3:│}{1: }13 |
- {1: }14 {3:│}{1: }14 |
- {1: }{5:15}{6:x}{5: }{3:│}{1: }{5:15}{6:^y}{5: }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
- {7:~ }{3:│}{7:~ }|
+ {1: }{2:-----------------}│{1: }{4:6 }|
+ {1: }{2:-----------------}│{1: }{4:7 }|
+ {1: }{2:-----------------}│{1: }{4:8 }|
+ {1: }9 │{1: }9 |
+ {1: }10 │{1: }10 |
+ {1: }11 │{1: }11 |
+ {1: }12 │{1: }12 |
+ {1: }13 │{1: }13 |
+ {1: }14 │{1: }14 |
+ {1: }{5:15}{6:x}{5: }│{1: }{5:15}{6:^y}{5: }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
{3:[No Name] [+] }{8:[No Name] [+] }|
|
]]}
end)
+
+it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function()
+ clear()
+ local screen = Screen.new(40, 20)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {reverse = true};
+ [3] = {background = Screen.colors.LightBlue};
+ [4] = {background = Screen.colors.LightMagenta};
+ [5] = {background = Screen.colors.Red, bold = true};
+ [6] = {foreground = Screen.colors.Blue, bold = true};
+ [7] = {background = Screen.colors.Red, foreground = Screen.colors.Blue, bold = true};
+ [8] = {reverse = true, bold = true};
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g'])
+ vnew
+ call setline(1, ['A', 'b', 'c', 'd', 'E', 'f', 'g'])
+ windo diffthis
+ wincmd p
+ norm! gg0
+ redraw!
+ ]])
+
+ -- Test using internal diff
+ screen:expect([[
+ {1: }{5:^A}{4: }│{1: }{5:a}{4: }|
+ {1: }b │{1: }b |
+ {1: }{4:c }│{1: }{4:c}{7:^@}{4: }|
+ {1: }d │{1: }d |
+ {1: }{5:E}{4: }│{1: }{5:e}{4: }|
+ {1: }f │{1: }f |
+ {1: }g │{1: }g |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+
+ -- Test using internal diff and case folding
+ command('set diffopt+=icase')
+ feed('<C-L>')
+ screen:expect([[
+ {1: }^A │{1: }a |
+ {1: }b │{1: }b |
+ {1: }{4:c }│{1: }{4:c}{7:^@}{4: }|
+ {1: }d │{1: }d |
+ {1: }E │{1: }e |
+ {1: }f │{1: }f |
+ {1: }g │{1: }g |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+
+ -- Test using external diff
+ command('set diffopt=filler')
+ feed('<C-L>')
+ screen:expect([[
+ {1: }{5:^A}{4: }│{1: }{5:a}{4: }|
+ {1: }b │{1: }b |
+ {1: }{4:c }│{1: }{4:c}{7:^@}{4: }|
+ {1: }d │{1: }d |
+ {1: }{5:E}{4: }│{1: }{5:e}{4: }|
+ {1: }f │{1: }f |
+ {1: }g │{1: }g |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+
+ -- Test using external diff and case folding
+ command('set diffopt+=filler,icase')
+ feed('<C-L>')
+ screen:expect([[
+ {1: }^A │{1: }a |
+ {1: }b │{1: }b |
+ {1: }{4:c }│{1: }{4:c}{7:^@}{4: }|
+ {1: }d │{1: }d |
+ {1: }E │{1: }e |
+ {1: }f │{1: }f |
+ {1: }g │{1: }g |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {8:[No Name] [+] }{2:[No Name] [+] }|
+ |
+ ]])
+end)
diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua
index 8218c8e12d..92f5beebf5 100644
--- a/test/functional/ui/embed_spec.lua
+++ b/test/functional/ui/embed_spec.lua
@@ -1,3 +1,5 @@
+local uv = require'luv'
+
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
@@ -98,3 +100,49 @@ end
describe('--embed UI on startup (ext_linegrid=true)', function() test_embed(true) end)
describe('--embed UI on startup (ext_linegrid=false)', function() test_embed(false) end)
+
+describe('--embed UI', function()
+ it('can pass stdin', function()
+ local pipe = assert(uv.pipe())
+
+ local writer = assert(uv.new_pipe(false))
+ writer:open(pipe.write)
+
+ clear {args_rm={'--headless'}, io_extra=pipe.read}
+
+ -- attach immediately after startup, for early UI
+ local screen = Screen.new(40, 8)
+ screen:attach {stdin_fd=3}
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {bold = true};
+ }
+
+ writer:write "hello nvim\nfrom external input\n"
+ writer:shutdown(function() writer:close() end)
+
+ screen:expect{grid=[[
+ ^hello nvim |
+ from external input |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ -- stdin (rpc input) still works
+ feed 'o'
+ screen:expect{grid=[[
+ hello nvim |
+ ^ |
+ from external input |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]]}
+ end)
+end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 5f29261b17..50247ed214 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -8,6 +8,7 @@ local command, feed_command = helpers.command, helpers.feed_command
local eval = helpers.eval
local eq = helpers.eq
local neq = helpers.neq
+local expect = helpers.expect
local exec_lua = helpers.exec_lua
local insert = helpers.insert
local meths = helpers.meths
@@ -16,10 +17,12 @@ local funcs = helpers.funcs
local run = helpers.run
local pcall_err = helpers.pcall_err
local tbl_contains = global_helpers.tbl_contains
+local curbuf, curwin, curtab = helpers.curbuf, helpers.curwin, helpers.curtab
describe('float window', function()
before_each(function()
clear()
+ command('hi VertSplit gui=reverse')
end)
local attrs = {
[0] = {bold=true, foreground=Screen.colors.Blue},
@@ -83,8 +86,8 @@ describe('float window', function()
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'})
local win = meths.open_win(buf, true, {relative='win', width=16, height=1, row=0, col=10})
- eq(pcall_err(funcs.win_execute, win, 'close'), 'Vim(close):E37: No write since last change (add ! to override)')
- eq(pcall_err(funcs.win_execute, win, 'bdelete'), 'Vim(bdelete):E89: No write since last change for buffer 2 (add ! to override)')
+ eq('Vim(close):E37: No write since last change (add ! to override)', pcall_err(funcs.win_execute, win, 'close'))
+ eq('Vim(bdelete):E89: No write since last change for buffer 2 (add ! to override)', pcall_err(funcs.win_execute, win, 'bdelete'))
funcs.win_execute(win, 'bwipe!')
end)
@@ -365,7 +368,7 @@ describe('float window', function()
return vim.api.nvim_open_win(bufnr, false, opts)
]])
command('windo echo')
- neq(eval('win_getid()'), winid)
+ neq(winid, eval('win_getid()'))
end)
it('is active after windo when focusable', function()
@@ -382,7 +385,7 @@ describe('float window', function()
return vim.api.nvim_open_win(bufnr, false, opts)
]])
command('windo echo')
- eq(eval('win_getid()'), winid)
+ eq(winid, eval('win_getid()'))
end)
it('supports windo with focusable and non-focusable floats', function()
@@ -417,6 +420,287 @@ describe('float window', function()
eq(winids, eval('winids'))
end)
+ describe('with only one tabpage,', function()
+ local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
+ local old_buf, old_win
+ before_each(function()
+ insert('foo')
+ old_buf = curbuf().id
+ old_win = curwin().id
+ end)
+ describe('closing the last non-floating window gives E444', function()
+ before_each(function()
+ meths.open_win(old_buf, true, float_opts)
+ end)
+ it('if called from non-floating window', function()
+ meths.set_current_win(old_win)
+ eq('Vim:E444: Cannot close last window',
+ pcall_err(meths.win_close, old_win, false))
+ end)
+ it('if called from floating window', function()
+ eq('Vim:E444: Cannot close last window',
+ pcall_err(meths.win_close, old_win, false))
+ end)
+ end)
+ describe("deleting the last non-floating window's buffer", function()
+ describe('leaves one window with an empty buffer when there is only one buffer', function()
+ local same_buf_float
+ before_each(function()
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ end)
+ after_each(function()
+ eq(old_win, curwin().id)
+ expect('')
+ eq(1, #meths.list_wins())
+ end)
+ it('if called from non-floating window', function()
+ meths.buf_delete(old_buf, {force = true})
+ end)
+ it('if called from floating window', function()
+ meths.set_current_win(same_buf_float)
+ command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()')
+ command('autocmd WinEnter * let g:win_enter = nvim_get_current_win()')
+ meths.buf_delete(old_buf, {force = true})
+ eq(same_buf_float, eval('g:win_leave'))
+ eq(old_win, eval('g:win_enter'))
+ end)
+ end)
+ describe('closes other windows with that buffer when there are other buffers', function()
+ local same_buf_float, other_buf, other_buf_float
+ before_each(function()
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ other_buf = meths.create_buf(true, false).id
+ other_buf_float = meths.open_win(other_buf, true, float_opts).id
+ insert('bar')
+ meths.set_current_win(old_win)
+ end)
+ after_each(function()
+ eq(other_buf, curbuf().id)
+ expect('bar')
+ eq(2, #meths.list_wins())
+ end)
+ it('if called from non-floating window', function()
+ meths.buf_delete(old_buf, {force = true})
+ eq(old_win, curwin().id)
+ end)
+ it('if called from floating window with the same buffer', function()
+ meths.set_current_win(same_buf_float)
+ command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()')
+ command('autocmd WinEnter * let g:win_enter = nvim_get_current_win()')
+ meths.buf_delete(old_buf, {force = true})
+ eq(same_buf_float, eval('g:win_leave'))
+ eq(old_win, eval('g:win_enter'))
+ eq(old_win, curwin().id)
+ end)
+ -- TODO: this case is too hard to deal with
+ pending('if called from floating window with another buffer', function()
+ meths.set_current_win(other_buf_float)
+ meths.buf_delete(old_buf, {force = true})
+ end)
+ end)
+ describe('creates an empty buffer when there is only one listed buffer', function()
+ local same_buf_float, unlisted_buf_float
+ before_each(function()
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ local unlisted_buf = meths.create_buf(true, false).id
+ unlisted_buf_float = meths.open_win(unlisted_buf, true, float_opts).id
+ insert('unlisted')
+ command('set nobuflisted')
+ meths.set_current_win(old_win)
+ end)
+ after_each(function()
+ expect('')
+ eq(2, #meths.list_wins())
+ end)
+ it('if called from non-floating window', function()
+ meths.buf_delete(old_buf, {force = true})
+ eq(old_win, curwin().id)
+ end)
+ it('if called from floating window with the same buffer', function()
+ meths.set_current_win(same_buf_float)
+ command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()')
+ command('autocmd WinEnter * let g:win_enter = nvim_get_current_win()')
+ meths.buf_delete(old_buf, {force = true})
+ eq(same_buf_float, eval('g:win_leave'))
+ eq(old_win, eval('g:win_enter'))
+ eq(old_win, curwin().id)
+ end)
+ -- TODO: this case is too hard to deal with
+ pending('if called from floating window with an unlisted buffer', function()
+ meths.set_current_win(unlisted_buf_float)
+ meths.buf_delete(old_buf, {force = true})
+ end)
+ end)
+ end)
+ describe('with splits, deleting the last listed buffer creates an empty buffer', function()
+ describe('when a non-floating window has an unlisted buffer', function()
+ local same_buf_float
+ before_each(function()
+ command('botright vnew')
+ insert('unlisted')
+ command('set nobuflisted')
+ meths.set_current_win(old_win)
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ end)
+ after_each(function()
+ expect('')
+ eq(2, #meths.list_wins())
+ end)
+ it('if called from non-floating window with the deleted buffer', function()
+ meths.buf_delete(old_buf, {force = true})
+ eq(old_win, curwin().id)
+ end)
+ it('if called from floating window with the deleted buffer', function()
+ meths.set_current_win(same_buf_float)
+ meths.buf_delete(old_buf, {force = true})
+ eq(same_buf_float, curwin().id)
+ end)
+ end)
+ end)
+ end)
+
+ describe('with mulitple tabpages but only one listed buffer,', function()
+ local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
+ local unlisted_buf, old_buf, old_win
+ before_each(function()
+ insert('unlisted')
+ command('set nobuflisted')
+ unlisted_buf = curbuf().id
+ command('tabnew')
+ insert('foo')
+ old_buf = curbuf().id
+ old_win = curwin().id
+ end)
+ describe('without splits, deleting the last listed buffer creates an empty buffer', function()
+ local same_buf_float
+ before_each(function()
+ meths.set_current_win(old_win)
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ end)
+ after_each(function()
+ expect('')
+ eq(2, #meths.list_wins())
+ eq(2, #meths.list_tabpages())
+ end)
+ it('if called from non-floating window', function()
+ meths.buf_delete(old_buf, {force = true})
+ eq(old_win, curwin().id)
+ end)
+ it('if called from floating window with the same buffer', function()
+ meths.set_current_win(same_buf_float)
+ command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()')
+ command('autocmd WinEnter * let g:win_enter = nvim_get_current_win()')
+ meths.buf_delete(old_buf, {force = true})
+ eq(same_buf_float, eval('g:win_leave'))
+ eq(old_win, eval('g:win_enter'))
+ eq(old_win, curwin().id)
+ end)
+ end)
+ describe('with splits, deleting the last listed buffer creates an empty buffer', function()
+ local same_buf_float
+ before_each(function()
+ command('botright vsplit')
+ meths.set_current_buf(unlisted_buf)
+ meths.set_current_win(old_win)
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ end)
+ after_each(function()
+ expect('')
+ eq(3, #meths.list_wins())
+ eq(2, #meths.list_tabpages())
+ end)
+ it('if called from non-floating window with the deleted buffer', function()
+ meths.buf_delete(old_buf, {force = true})
+ eq(old_win, curwin().id)
+ end)
+ it('if called from floating window with the deleted buffer', function()
+ meths.set_current_win(same_buf_float)
+ meths.buf_delete(old_buf, {force = true})
+ eq(same_buf_float, curwin().id)
+ end)
+ end)
+ end)
+
+ describe('with multiple tabpages and multiple listed buffers,', function()
+ local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
+ local old_tabpage, old_buf, old_win
+ before_each(function()
+ old_tabpage = curtab().id
+ insert('oldtab')
+ command('tabnew')
+ old_buf = curbuf().id
+ old_win = curwin().id
+ end)
+ describe('closing the last non-floating window', function()
+ describe('closes the tabpage when all floating windows are closeable', function()
+ local same_buf_float
+ before_each(function()
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ end)
+ after_each(function()
+ eq(old_tabpage, curtab().id)
+ expect('oldtab')
+ eq(1, #meths.list_tabpages())
+ end)
+ it('if called from non-floating window', function()
+ meths.win_close(old_win, false)
+ end)
+ it('if called from floating window', function()
+ meths.set_current_win(same_buf_float)
+ meths.win_close(old_win, false)
+ end)
+ end)
+ describe('gives E5601 when there are non-closeable floating windows', function()
+ local other_buf_float
+ before_each(function()
+ command('set nohidden')
+ local other_buf = meths.create_buf(true, false).id
+ other_buf_float = meths.open_win(other_buf, true, float_opts).id
+ insert('foo')
+ meths.set_current_win(old_win)
+ end)
+ it('if called from non-floating window', function()
+ eq('Vim:E5601: Cannot close window, only floating window would remain',
+ pcall_err(meths.win_close, old_win, false))
+ end)
+ it('if called from floating window', function()
+ meths.set_current_win(other_buf_float)
+ eq('Vim:E5601: Cannot close window, only floating window would remain',
+ pcall_err(meths.win_close, old_win, false))
+ end)
+ end)
+ end)
+ describe("deleting the last non-floating window's buffer", function()
+ describe('closes the tabpage when all floating windows are closeable', function()
+ local same_buf_float, other_buf, other_buf_float
+ before_each(function()
+ same_buf_float = meths.open_win(old_buf, false, float_opts).id
+ other_buf = meths.create_buf(true, false).id
+ other_buf_float = meths.open_win(other_buf, true, float_opts).id
+ meths.set_current_win(old_win)
+ end)
+ after_each(function()
+ eq(old_tabpage, curtab().id)
+ expect('oldtab')
+ eq(1, #meths.list_tabpages())
+ end)
+ it('if called from non-floating window', function()
+ meths.buf_delete(old_buf, {force = false})
+ end)
+ it('if called from floating window with the same buffer', function()
+ meths.set_current_win(same_buf_float)
+ meths.buf_delete(old_buf, {force = false})
+ end)
+ -- TODO: this case is too hard to deal with
+ pending('if called from floating window with another buffer', function()
+ meths.set_current_win(other_buf_float)
+ meths.buf_delete(old_buf, {force = false})
+ end)
+ end)
+ -- TODO: what to do when there are non-closeable floating windows?
+ end)
+ end)
+
local function with_ext_multigrid(multigrid)
local screen
before_each(function()
@@ -3376,10 +3660,10 @@ describe('float window', function()
screen:expect{grid=[[
## grid 1
[2:----------------------------------------]|
- {5:[No Name] }|
- [5:----------------------------------------]|
- [5:----------------------------------------]|
- [5:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
{5:[Preview] }|
[3:----------------------------------------]|
## grid 2
@@ -3390,10 +3674,6 @@ describe('float window', function()
{17:f}{1:oo }|
{17:b}{1:ar }|
{1: }|
- ## grid 5
- |1| {17:f}oo |
- |2| {17:b}ar |
- {0:~ }|
]], float_pos=expected_pos}
else
screen:expect([[
@@ -4169,7 +4449,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4207,7 +4487,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -4243,7 +4523,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4283,7 +4563,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4319,7 +4599,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4357,7 +4637,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -4393,7 +4673,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4431,7 +4711,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
meths.input_mouse('left', 'press', '', 0, 2, 5)
screen:expect([[
@@ -4468,7 +4748,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
meths.input_mouse('left', 'press', '', 0, 0, 0)
screen:expect([[
@@ -4510,7 +4790,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
meths.input_mouse('left', 'press', '', 0, 2, 5)
screen:expect([[
@@ -4547,7 +4827,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos, unchanged=true}
+ ]], float_pos=expected_pos, unchanged=true}
else
meths.input_mouse('left', 'press', '', 0, 0, 0)
screen:expect([[
@@ -4562,7 +4842,6 @@ describe('float window', function()
end
end)
-
it("j", function()
feed("<c-w>ji") -- INSERT to trigger screen change
if multigrid then
@@ -4587,7 +4866,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4623,7 +4902,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -4659,7 +4938,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -4698,7 +4977,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -4886,7 +5165,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5067,7 +5346,7 @@ describe('float window', function()
## grid 5
^x |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -5102,7 +5381,7 @@ describe('float window', function()
## grid 5
x |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5137,7 +5416,7 @@ describe('float window', function()
## grid 5
x |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5173,7 +5452,7 @@ describe('float window', function()
## grid 5
^x |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x |
@@ -5210,7 +5489,7 @@ describe('float window', function()
## grid 5
^y |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^y |
@@ -5245,7 +5524,7 @@ describe('float window', function()
## grid 5
y |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
y |
@@ -5280,7 +5559,7 @@ describe('float window', function()
## grid 5
y |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
y |
@@ -5317,7 +5596,7 @@ describe('float window', function()
## grid 5
^ |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^ |
@@ -5354,7 +5633,7 @@ describe('float window', function()
## grid 5
^ |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^ |
@@ -5397,7 +5676,7 @@ describe('float window', function()
{0:~ }|
{0:~ }|
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^x {5:│}x |
@@ -5440,17 +5719,17 @@ describe('float window', function()
{0:~ }|
{0:~ }|
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
- screen:expect([[
- ^ {5:│}x |
- {0:~ }{5:│}{0:~ }|
- {0:~ }{1:y }{0: }|
- {0:~ }{2:~ }{0: }|
- {0:~ }{5:│}{0:~ }|
- {4:[No Name] }{5:[No Name] [+] }|
- :vnew |
- ]])
+ screen:expect([[
+ ^ {5:│}x |
+ {0:~ }{5:│}{0:~ }|
+ {0:~ }{1:y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{5:│}{0:~ }|
+ {4:[No Name] }{5:[No Name] [+] }|
+ :vnew |
+ ]])
end
end)
@@ -5483,7 +5762,7 @@ describe('float window', function()
{0:~ }|
{0:~ }|
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
^ {5:│}x |
@@ -5553,7 +5832,7 @@ describe('float window', function()
[4] = {{id = 1001}, "NW", 1, 2, 5, true},
[5] = {{id = 1002}, "NW", 1, 4, 8, true}
}}
- else
+ else
screen:expect([[
x |
{0:~ }|
@@ -5574,7 +5853,7 @@ describe('float window', function()
[2:----------------------------------------]|
[2:----------------------------------------]|
[2:----------------------------------------]|
- {5:[No Name] [+] }|
+ [2:----------------------------------------]|
[3:----------------------------------------]|
## grid 2
x |
@@ -5582,6 +5861,7 @@ describe('float window', function()
{0:~ }|
{0:~ }|
{0:~ }|
+ {0:~ }|
## grid 3
:quit |
## grid 4
@@ -5590,14 +5870,14 @@ describe('float window', function()
]], float_pos={
[4] = {{id = 1001}, "NW", 1, 2, 5, true},
}}
- else
+ else
screen:expect([[
x |
{0:~ }|
{0:~ }{1:^y }{0: }|
{0:~ }{2:~ }{0: }|
{0:~ }|
- {5:[No Name] [+] }|
+ {0:~ }|
:quit |
]])
end
@@ -5659,7 +5939,7 @@ describe('float window', function()
{0:~ }|
## grid 3
|
- ]]}
+ ]]}
else
screen:expect([[
^x |
@@ -5699,7 +5979,7 @@ describe('float window', function()
## grid 4
{1:y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5736,7 +6016,7 @@ describe('float window', function()
## grid 4
{1:^y }|
{2:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5806,7 +6086,7 @@ describe('float window', function()
{0:~ }|
{0:~ }|
{0:~ }|
- ]]}
+ ]]}
else
screen:expect([[
^x |
@@ -5843,7 +6123,7 @@ describe('float window', function()
## grid 5
x |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5880,7 +6160,7 @@ describe('float window', function()
## grid 5
x |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
screen:expect([[
x |
@@ -5914,7 +6194,7 @@ describe('float window', function()
## grid 4
^y |
{0:~ }|
- ]]}
+ ]]}
else
screen:expect([[
x |
@@ -5950,7 +6230,7 @@ describe('float window', function()
## grid 4
^y |
{0:~ }|
- ]], float_pos=expected_pos}
+ ]], float_pos=expected_pos}
else
eq("UI doesn't support external windows",
pcall_err(meths.win_set_config, 0, {external=true, width=30, height=2}))
@@ -5980,6 +6260,78 @@ describe('float window', function()
end
end)
+ it('J (float with border)', function()
+ meths.win_set_config(win, {relative='editor', width=20, height=2, row=2, col=5, border='single'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {5:┌────────────────────┐}|
+ {5:│}{1:y }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ ^x |
+ {0:~ }|
+ {0:~ }{5:┌────────────────────┐}{0: }|
+ {0:~ }{5:│}{1:y }{5:│}{0: }|
+ {0:~ }{5:│}{2:~ }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ |
+ ]])
+ end
+
+ feed("<c-w>w<c-w>J")
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ x |
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ ^y |
+ {0:~ }|
+ ]]}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {5:[No Name] [+] }|
+ ^y |
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+ end)
+
it('movements with nested split layout', function()
command("set hidden")
feed("<c-w>s<c-w>v<c-w>b<c-w>v")
@@ -6342,7 +6694,7 @@ describe('float window', function()
it("left drag changes visual selection in float window", function()
local buf = meths.create_buf(false,false)
- meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar'})
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
meths.open_win(buf, false, {relative='editor', width=20, height=3, row=2, col=5})
if multigrid then
screen:expect{grid=[[
@@ -6366,13 +6718,14 @@ describe('float window', function()
## grid 5
{1:foo }|
{1:bar }|
- {2:~ }|
+ {1:baz }|
]], float_pos={
[5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
}}
+
meths.input_mouse('left', 'press', '', 5, 0, 0)
screen:expect{grid=[[
## grid 1
@@ -6395,13 +6748,14 @@ describe('float window', function()
## grid 5
{1:^foo }|
{1:bar }|
- {2:~ }|
+ {1:baz }|
]], float_pos={
[5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
}}
+
meths.input_mouse('left', 'drag', '', 5, 1, 2)
screen:expect{grid=[[
## grid 1
@@ -6424,12 +6778,12 @@ describe('float window', function()
## grid 5
{27:foo}{1: }|
{27:ba}{1:^r }|
- {2:~ }|
+ {1:baz }|
]], float_pos={
[5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
}, win_viewport={
[2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 2};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3};
}}
else
screen:expect{grid=[[
@@ -6437,7 +6791,7 @@ describe('float window', function()
{0:~ }|
{0:~ }{1:foo }{0: }|
{0:~ }{1:bar }{0: }|
- {0:~ }{2:~ }{0: }|
+ {0:~ }{1:baz }{0: }|
{0:~ }|
|
]]}
@@ -6448,7 +6802,7 @@ describe('float window', function()
{0:~ }|
{0:~ }{1:^foo }{0: }|
{0:~ }{1:bar }{0: }|
- {0:~ }{2:~ }{0: }|
+ {0:~ }{1:baz }{0: }|
{0:~ }|
|
]]}
@@ -6459,13 +6813,396 @@ describe('float window', function()
{0:~ }|
{0:~ }{27:foo}{1: }{0: }|
{0:~ }{27:ba}{1:^r }{0: }|
- {0:~ }{2:~ }{0: }|
+ {0:~ }{1:baz }{0: }|
{0:~ }|
{3:-- VISUAL --} |
]]}
end
end)
+ it("left drag changes visual selection in float window with border", function()
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
+ meths.open_win(buf, false, {relative='editor', width=20, height=3, row=0, col=5, border='single'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌────────────────────┐}|
+ {5:│}{1:foo }{5:│}|
+ {5:│}{1:bar }{5:│}|
+ {5:│}{1:baz }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+
+ meths.input_mouse('left', 'press', '', 5, 1, 1)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {5:┌────────────────────┐}|
+ {5:│}{1:^foo }{5:│}|
+ {5:│}{1:bar }{5:│}|
+ {5:│}{1:baz }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+
+ meths.input_mouse('left', 'drag', '', 5, 2, 3)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- VISUAL --} |
+ ## grid 5
+ {5:┌────────────────────┐}|
+ {5:│}{27:foo}{1: }{5:│}|
+ {5:│}{27:ba}{1:^r }{5:│}|
+ {5:│}{1:baz }{5:│}|
+ {5:└────────────────────┘}|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{1:foo }{5:│}{0: }|
+ {0:~ }{5:│}{1:bar }{5:│}{0: }|
+ {0:~ }{5:│}{1:baz }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'press', '', 0, 1, 6)
+ screen:expect{grid=[[
+ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{1:^foo }{5:│}{0: }|
+ {0:~ }{5:│}{1:bar }{5:│}{0: }|
+ {0:~ }{5:│}{1:baz }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'drag', '', 0, 2, 8)
+ screen:expect{grid=[[
+ {5:┌────────────────────┐} |
+ {0:~ }{5:│}{27:foo}{1: }{5:│}{0: }|
+ {0:~ }{5:│}{27:ba}{1:^r }{5:│}{0: }|
+ {0:~ }{5:│}{1:baz }{5:│}{0: }|
+ {0:~ }{5:└────────────────────┘}{0: }|
+ {0:~ }|
+ {3:-- VISUAL --} |
+ ]]}
+ end
+ end)
+
+ it("left drag changes visual selection in float window with winbar", function()
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
+ local float_win = meths.open_win(buf, false, {relative='editor', width=20, height=4, row=1, col=5})
+ meths.win_set_option(float_win, 'winbar', 'floaty bar')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {3:floaty bar }|
+ {1:foo }|
+ {1:bar }|
+ {1:baz }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+
+ meths.input_mouse('left', 'press', '', 5, 1, 0)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ {3:floaty bar }|
+ {1:^foo }|
+ {1:bar }|
+ {1:baz }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3};
+ }}
+
+ meths.input_mouse('left', 'drag', '', 5, 2, 2)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- VISUAL --} |
+ ## grid 5
+ {3:floaty bar }|
+ {27:foo}{1: }|
+ {27:ba}{1:^r }|
+ {1:baz }|
+ ]], float_pos={
+ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{1:foo }{0: }|
+ {0:~ }{1:bar }{0: }|
+ {0:~ }{1:baz }{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'press', '', 0, 2, 5)
+ screen:expect{grid=[[
+ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{1:^foo }{0: }|
+ {0:~ }{1:bar }{0: }|
+ {0:~ }{1:baz }{0: }|
+ {0:~ }|
+ |
+ ]]}
+
+ meths.input_mouse('left', 'drag', '', 0, 3, 7)
+ screen:expect{grid=[[
+ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{27:foo}{1: }{0: }|
+ {0:~ }{27:ba}{1:^r }{0: }|
+ {0:~ }{1:baz }{0: }|
+ {0:~ }|
+ {3:-- VISUAL --} |
+ ]]}
+ end
+ end)
+
+ it('left drag changes visual selection if float window is turned into a split', function()
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
+ meths.open_win(buf, true, {relative='editor', width=20, height=3, row=2, col=5})
+ command('wincmd L')
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ {5:[No Name] }{4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ ^foo |
+ bar |
+ baz |
+ {0:~ }|
+ {0:~ }|
+ ]])
+
+ meths.input_mouse('left', 'press', '', 5, 2, 2)
+ screen:expect([[
+ ## grid 1
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ {5:[No Name] }{4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 5
+ foo |
+ bar |
+ ba^z |
+ {0:~ }|
+ {0:~ }|
+ ]])
+
+ meths.input_mouse('left', 'drag', '', 5, 1, 1)
+ screen:expect([[
+ ## grid 1
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ [2:-------------------]{5:│}[5:--------------------]|
+ {5:[No Name] }{4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {3:-- VISUAL --} |
+ ## grid 5
+ foo |
+ b^a{27:r} |
+ {27:baz} |
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ {5:│}^foo |
+ {0:~ }{5:│}bar |
+ {0:~ }{5:│}baz |
+ {0:~ }{5:│}{0:~ }|
+ {0:~ }{5:│}{0:~ }|
+ {5:[No Name] }{4:[No Name] [+] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'press', '', 0, 2, 22)
+ screen:expect([[
+ {5:│}foo |
+ {0:~ }{5:│}bar |
+ {0:~ }{5:│}ba^z |
+ {0:~ }{5:│}{0:~ }|
+ {0:~ }{5:│}{0:~ }|
+ {5:[No Name] }{4:[No Name] [+] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'drag', '', 0, 1, 21)
+ screen:expect([[
+ {5:│}foo |
+ {0:~ }{5:│}b^a{27:r} |
+ {0:~ }{5:│}{27:baz} |
+ {0:~ }{5:│}{0:~ }|
+ {0:~ }{5:│}{0:~ }|
+ {5:[No Name] }{4:[No Name] [+] }|
+ {3:-- VISUAL --} |
+ ]])
+ end
+ end)
+
it("'winblend' option", function()
screen:try_resize(50,9)
screen:set_default_attr_ids({
@@ -7306,6 +8043,100 @@ describe('float window', function()
]]}
end
end)
+
+ it('can use winbar', function()
+ local buf = meths.create_buf(false,false)
+ local win1 = meths.open_win(buf, false, {relative='editor', width=15, height=3, row=1, col=5})
+ meths.win_set_option(win1, 'winbar', 'floaty bar')
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {3:floaty bar }|
+ {1: }|
+ {2:~ }|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }{3:floaty bar }{0: }|
+ {0:~ }{1: }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end
+
+ -- resize and add a border
+ meths.win_set_config(win1, {relative='editor', width=15, height=4, row=0, col=4, border = 'single'})
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {5:┌───────────────┐}|
+ {5:│}{3:floaty bar }{5:│}|
+ {5:│}{1: }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:│}{2:~ }{5:│}|
+ {5:└───────────────┘}|
+ ]], float_pos={
+ [4] = {{id = 1001}, "NW", 1, 0, 4, true, 50};
+ }, win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ else
+ screen:expect{grid=[[
+ ^ {5:┌───────────────┐} |
+ {0:~ }{5:│}{3:floaty bar }{5:│}{0: }|
+ {0:~ }{5:│}{1: }{5:│}{0: }|
+ {0:~ }{5:│}{2:~ }{5:│}{0: }|
+ {0:~ }{5:│}{2:~ }{5:│}{0: }|
+ {0:~ }{5:└───────────────┘}{0: }|
+ |
+ ]]}
+ end
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 3e0e15c2b7..394f2f5f49 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -21,12 +21,14 @@ local content1 = [[
describe("folded lines", function()
before_each(function()
clear()
+ command('hi VertSplit gui=reverse')
end)
local function with_ext_multigrid(multigrid)
local screen
before_each(function()
clear()
+ command('hi VertSplit gui=reverse')
screen = Screen.new(45, 8)
screen:attach({rgb=true, ext_multigrid=multigrid})
screen:set_default_attr_ids({
@@ -1672,7 +1674,7 @@ describe("folded lines", function()
end
-- relax the maximum fdc thus fdc should expand to
- -- accomodate the current number of folds
+ -- accommodate the current number of folds
command("set foldcolumn=auto:4")
if multigrid then
screen:expect([[
@@ -1755,6 +1757,67 @@ describe("folded lines", function()
end
assert_alive()
end)
+
+ it('work correctly with :move #18668', function()
+ screen:try_resize(45, 12)
+ source([[
+ set foldmethod=expr foldexpr=indent(v:lnum)
+ let content = ['', '', 'Line1', ' Line2', ' Line3',
+ \ 'Line4', ' Line5', ' Line6',
+ \ 'Line7', ' Line8', ' Line9']
+ call append(0, content)
+ normal! zM
+ call cursor(4, 1)
+ move 2
+ move 1
+ ]])
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [2:---------------------------------------------]|
+ [3:---------------------------------------------]|
+ ## grid 2
+ |
+ {5:^+-- 2 lines: Line2··························}|
+ |
+ Line1 |
+ Line4 |
+ {5:+-- 2 lines: Line5··························}|
+ Line7 |
+ {5:+-- 2 lines: Line8··························}|
+ |
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]])
+ else
+ screen:expect([[
+ |
+ {5:^+-- 2 lines: Line2··························}|
+ |
+ Line1 |
+ Line4 |
+ {5:+-- 2 lines: Line5··························}|
+ Line7 |
+ {5:+-- 2 lines: Line8··························}|
+ |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end
+ end)
end
describe("with ext_multigrid", function()
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 255180bba8..946129b082 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local os = require('os')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local command = helpers.command
+local command, exec = helpers.command, helpers.exec
local eval, exc_exec = helpers.eval, helpers.exc_exec
local feed_command, eq = helpers.feed_command, helpers.eq
local curbufmeths = helpers.curbufmeths
@@ -104,12 +104,12 @@ describe('highlight defaults', function()
})
feed_command('sp', 'vsp', 'vsp')
screen:expect([[
- ^ {2:│} {2:│} |
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
+ ^ │ │ |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{1:[No Name] }{2:[No Name] [No Name] }|
|
{0:~ }|
@@ -122,12 +122,12 @@ describe('highlight defaults', function()
-- navigate to verify that the attributes are properly moved
feed('<c-w>j')
screen:expect([[
- {2:│} {2:│} |
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
+ │ │ |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{2:[No Name] [No Name] [No Name] }|
^ |
{0:~ }|
@@ -142,12 +142,12 @@ describe('highlight defaults', function()
-- (upstream vim has the same behavior)
feed('<c-w>k<c-w>l')
screen:expect([[
- {2:│}^ {2:│} |
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
+ │^ │ |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{2:[No Name] }{1:[No Name] }{2:[No Name] }|
|
{0:~ }|
@@ -159,12 +159,12 @@ describe('highlight defaults', function()
]])
feed('<c-w>l')
screen:expect([[
- {2:│} {2:│}^ |
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
+ │ │^ |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{2:[No Name] [No Name] }{1:[No Name] }|
|
{0:~ }|
@@ -176,12 +176,12 @@ describe('highlight defaults', function()
]])
feed('<c-w>h<c-w>h')
screen:expect([[
- ^ {2:│} {2:│} |
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
- {0:~ }{2:│}{0:~ }{2:│}{0:~ }|
+ ^ │ │ |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{1:[No Name] }{2:[No Name] [No Name] }|
|
{0:~ }|
@@ -840,7 +840,7 @@ describe("'listchars' highlight", function()
end)
end)
-describe('CursorLine highlight', function()
+describe('CursorLine and CursorLineNr highlights', function()
before_each(clear)
it('overridden by Error, ColorColumn if fg not set', function()
@@ -938,17 +938,18 @@ describe('CursorLine highlight', function()
[2] = {foreground = Screen.colors.Yellow};
[3] = {foreground = Screen.colors.Red, background = Screen.colors.Green};
[4] = {foreground = Screen.colors.Green, background = Screen.colors.Red};
+ [5] = {bold = true}, -- ModeMsg
})
screen:attach()
- feed_command('set wrap cursorline cursorlineopt=screenline')
- feed_command('set showbreak=>>>')
- feed_command('highlight clear NonText')
- feed_command('highlight clear CursorLine')
- feed_command('highlight NonText guifg=Yellow gui=NONE')
- feed_command('highlight LineNr guifg=Red guibg=Green gui=NONE')
- feed_command('highlight CursorLine guifg=Black guibg=White gui=NONE')
- feed_command('highlight CursorLineNr guifg=Green guibg=Red gui=NONE')
+ command('set wrap cursorline cursorlineopt=screenline')
+ command('set showbreak=>>>')
+ command('highlight clear NonText')
+ command('highlight clear CursorLine')
+ command('highlight NonText guifg=Yellow gui=NONE')
+ command('highlight LineNr guifg=Red guibg=Green gui=NONE')
+ command('highlight CursorLine guifg=Black guibg=White gui=NONE')
+ command('highlight CursorLineNr guifg=Green guibg=Red gui=NONE')
feed('30iø<esc>o<esc>30ia<esc>')
@@ -978,7 +979,7 @@ describe('CursorLine highlight', function()
]])
-- CursorLineNr should not apply to line number when 'cursorlineopt' does not contain "number"
- feed_command('set relativenumber numberwidth=2')
+ command('set relativenumber numberwidth=2')
screen:expect([[
{3:0 }{1:øøøøøøøøøøøø^øøøøøø}|
{3: }{2:>>>}øøøøøøøøøøøø |
@@ -988,7 +989,7 @@ describe('CursorLine highlight', function()
]])
-- CursorLineNr should apply to line number when 'cursorlineopt' contains "number"
- feed_command('set cursorlineopt+=number')
+ command('set cursorlineopt+=number')
screen:expect([[
{4:0 }{1:øøøøøøøøøøøø^øøøøøø}|
{3: }{2:>>>}øøøøøøøøøøøø |
@@ -1020,6 +1021,44 @@ describe('CursorLine highlight', function()
{3: }{2:>>>}{1:aaaaaaaaa^aaa }|
|
]])
+
+ -- updated in Insert mode
+ feed('I')
+ screen:expect([[
+ {3:1 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {4:0 }{1:^aaaaaaaaaaaaaaaaaa}|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ {5:-- INSERT --} |
+ ]])
+
+ feed('<Esc>gg')
+ screen:expect([[
+ {4:0 }{1:^øøøøøøøøøøøøøøøøøø}|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ |
+ ]])
+
+ command('inoremap <F2> <Cmd>call cursor(1, 1)<CR>')
+ feed('A')
+ screen:expect([[
+ {4:0 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}{1:øøøøøøøøøøøø^ }|
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ {5:-- INSERT --} |
+ ]])
+
+ feed('<F2>')
+ screen:expect([[
+ {4:0 }{1:^øøøøøøøøøøøøøøøøøø}|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ {5:-- INSERT --} |
+ ]])
end)
it('always updated. vim-patch:8.1.0849', function()
@@ -1082,7 +1121,47 @@ describe('CursorLine highlight', function()
]])
end)
- it('with split-windows in diff-mode', function()
+ it('is updated if cursor is moved up from timer vim-patch:8.2.4591', function()
+ local screen = Screen.new(50, 8)
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.Gray90}, -- CursorLine
+ [2] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set cursorline
+ call cursor(4, 1)
+
+ func Func(timer)
+ call cursor(2, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ ]])
+ screen:expect({grid = [[
+ aaaaa |
+ bbbbb |
+ ccccc |
+ {1:^ddddd }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], timeout = 100})
+ screen:expect({grid = [[
+ aaaaa |
+ {1:^bbbbb }|
+ ccccc |
+ ddddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]})
+ end)
+
+ it('with split windows in diff mode', function()
local screen = Screen.new(50,12)
screen:set_default_attr_ids({
[1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
@@ -1094,7 +1173,6 @@ describe('CursorLine highlight', function()
[7] = {background = Screen.colors.Red, foreground = Screen.colors.White},
[8] = {bold = true, foreground = Screen.colors.Blue1},
[9] = {bold = true, reverse = true},
- [10] = {bold = true},
})
screen:attach()
@@ -1108,31 +1186,31 @@ describe('CursorLine highlight', function()
feed('<esc>gg')
command('windo diffthis')
screen:expect([[
- {1: }{7:line 1 some text }{4:│}{1: }{7:^line 1 some text }|
- {1: }{3:line 2 mo}{2:Re text!}{3: }{4:│}{1: }{3:line 2 mo}{2:re text}{3: }|
- {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
- {1: }extra line! {4:│}{1: }extra line! |
- {1: }extra line! {4:│}{1: }extra line! |
- {1: }last line ... {4:│}{1: }last line ... |
- {1: } {4:│}{1: } |
- {8:~ }{4:│}{8:~ }|
- {8:~ }{4:│}{8:~ }|
- {8:~ }{4:│}{8:~ }|
+ {1: }{7:line 1 some text }│{1: }{7:^line 1 some text }|
+ {1: }{3:line 2 mo}{2:Re text!}{3: }│{1: }{3:line 2 mo}{2:re text}{3: }|
+ {1: }{5:extra line! }│{1: }{6:----------------------}|
+ {1: }extra line! │{1: }extra line! |
+ {1: }extra line! │{1: }extra line! |
+ {1: }last line ... │{1: }last line ... |
+ {1: } │{1: } |
+ {8:~ }│{8:~ }|
+ {8:~ }│{8:~ }|
+ {8:~ }│{8:~ }|
{4:[No Name] [+] }{9:[No Name] [+] }|
|
]])
feed('jjjjj')
screen:expect([[
- {1: }line 1 some text {4:│}{1: }line 1 some text |
- {1: }{3:line 2 mo}{2:Re text!}{3: }{4:│}{1: }{3:line 2 mo}{2:re text}{3: }|
- {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
- {1: }extra line! {4:│}{1: }extra line! |
- {1: }extra line! {4:│}{1: }extra line! |
- {1: }last line ... {4:│}{1: }last line ... |
- {1: }{7: }{4:│}{1: }{7:^ }|
- {8:~ }{4:│}{8:~ }|
- {8:~ }{4:│}{8:~ }|
- {8:~ }{4:│}{8:~ }|
+ {1: }line 1 some text │{1: }line 1 some text |
+ {1: }{3:line 2 mo}{2:Re text!}{3: }│{1: }{3:line 2 mo}{2:re text}{3: }|
+ {1: }{5:extra line! }│{1: }{6:----------------------}|
+ {1: }extra line! │{1: }extra line! |
+ {1: }extra line! │{1: }extra line! |
+ {1: }last line ... │{1: }last line ... |
+ {1: }{7: }│{1: }{7:^ }|
+ {8:~ }│{8:~ }|
+ {8:~ }│{8:~ }|
+ {8:~ }│{8:~ }|
{4:[No Name] [+] }{9:[No Name] [+] }|
|
]])
@@ -1142,16 +1220,16 @@ describe('CursorLine highlight', function()
command('hi CursorLine ctermbg=red ctermfg=NONE guibg=red guifg=NONE')
feed('kkkk')
screen:expect([[
- {1: }line 1 some text {4:│}{1: }line 1 some text |
- {1: }{11:line 2 mo}{12:Re text!}{11: }{4:│}{1: }{11:^line 2 mo}{12:re text}{11: }|
- {1: }{5:extra line! }{4:│}{1: }{6:----------------------}|
- {1: }extra line! {4:│}{1: }extra line! |
- {1: }extra line! {4:│}{1: }extra line! |
- {1: }last line ... {4:│}{1: }last line ... |
- {1: } {4:│}{1: } |
- {8:~ }{4:│}{8:~ }|
- {8:~ }{4:│}{8:~ }|
- {8:~ }{4:│}{8:~ }|
+ {1: }line 1 some text │{1: }line 1 some text |
+ {1: }{11:line 2 mo}{12:Re text!}{11: }│{1: }{11:^line 2 mo}{12:re text}{11: }|
+ {1: }{5:extra line! }│{1: }{6:----------------------}|
+ {1: }extra line! │{1: }extra line! |
+ {1: }extra line! │{1: }extra line! |
+ {1: }last line ... │{1: }last line ... |
+ {1: } │{1: } |
+ {8:~ }│{8:~ }|
+ {8:~ }│{8:~ }|
+ {8:~ }│{8:~ }|
{4:[No Name] [+] }{9:[No Name] [+] }|
|
]], {
@@ -1171,8 +1249,261 @@ describe('CursorLine highlight', function()
background = Screen.colors.Red},
})
end)
+
+ it('CursorLineNr shows correctly just below filler lines', function()
+ local screen = Screen.new(50,12)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [2] = {background = Screen.colors.LightCyan1, bold = true, foreground = Screen.colors.Blue1},
+ [3] = {reverse = true},
+ [4] = {background = Screen.colors.LightBlue},
+ [5] = {background = Screen.colors.Red, foreground = Screen.colors.White},
+ [6] = {background = Screen.colors.White, bold = true, foreground = Screen.colors.Black},
+ [7] = {bold = true, foreground = Screen.colors.Blue1},
+ [8] = {bold = true, reverse = true},
+ [9] = {foreground = Screen.colors.Brown},
+ })
+ screen:attach()
+
+ command('hi CursorLine guibg=red guifg=white')
+ command('hi CursorLineNr guibg=white guifg=black gui=bold')
+ command('set cursorline number')
+ command('call setline(1, ["baz", "foo", "foo", "bar"])')
+ feed('2gg0')
+ command('vnew')
+ command('call setline(1, ["foo", "foo", "bar"])')
+ command('windo diffthis')
+ command('1wincmd w')
+ screen:expect([[
+ {1: }{9: }{2:-------------------}│{1: }{9: 1 }{4:baz }|
+ {1: }{6: 1 }{5:^foo }│{1: }{6: 2 }{5:foo }|
+ {1: }{9: 2 }foo │{1: }{9: 3 }foo |
+ {1: }{9: 3 }bar │{1: }{9: 4 }bar |
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ command('set cursorlineopt=number')
+ screen:expect([[
+ {1: }{9: }{2:-------------------}│{1: }{9: 1 }{4:baz }|
+ {1: }{6: 1 }^foo │{1: }{6: 2 }{5:foo }|
+ {1: }{9: 2 }foo │{1: }{9: 3 }foo |
+ {1: }{9: 3 }bar │{1: }{9: 4 }bar |
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {7:~ }│{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]])
+ end)
+end)
+
+describe('CursorColumn highlight', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 8)
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.Gray90}, -- CursorColumn
+ [2] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ [3] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ end)
+
+ it('is updated when pressing "i" on a TAB character', function()
+ exec([[
+ call setline(1, ['123456789', "a\tb"])
+ set cursorcolumn
+ call cursor(2, 2)
+ ]])
+ screen:expect([[
+ 1234567{1:8}9 |
+ a ^ b |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ feed('i')
+ screen:expect([[
+ 1{1:2}3456789 |
+ a^ b |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {3:-- INSERT --} |
+ ]])
+ feed('<C-O>')
+ screen:expect([[
+ 1234567{1:8}9 |
+ a ^ b |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {3:-- (insert) --} |
+ ]])
+ feed('i')
+ screen:expect([[
+ 1{1:2}3456789 |
+ a^ b |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {3:-- INSERT --} |
+ ]])
+ end)
+
+ it('is updated if cursor is moved from timer', function()
+ exec([[
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set cursorcolumn
+ call cursor(4, 5)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ ]])
+ screen:expect({grid = [[
+ aaaa{1:a} |
+ bbbb{1:b} |
+ cccc{1:c} |
+ dddd^d |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], timeout = 100})
+ screen:expect({grid = [[
+ ^aaaaa |
+ {1:b}bbbb |
+ {1:c}cccc |
+ {1:d}dddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]})
+ end)
end)
+describe('ColorColumn highlight', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 15)
+ Screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.LightRed}, -- ColorColumn
+ [2] = {background = Screen.colors.Grey90}, -- CursorLine
+ [3] = {foreground = Screen.colors.Brown}, -- LineNr
+ [4] = {foreground = Screen.colors.Brown, bold = true}, -- CursorLineNr
+ [5] = {foreground = Screen.colors.Blue, bold = true}, -- NonText
+ -- NonText and ColorColumn
+ [6] = {foreground = Screen.colors.Blue, background = Screen.colors.LightRed, bold = true},
+ [7] = {reverse = true, bold = true}, -- StatusLine
+ [8] = {reverse = true}, -- StatusLineNC
+ })
+ screen:attach()
+ end)
+
+ it('when entering a buffer vim-patch:8.1.2073', function()
+ exec([[
+ set nohidden
+ split
+ edit X
+ call setline(1, ["1111111111","22222222222","3333333333"])
+ set nomodified
+ set colorcolumn=3,9
+ set number cursorline cursorlineopt=number
+ wincmd w
+ buf X
+ ]])
+ screen:expect([[
+ {4: 1 }11{1:1}11111{1:1}1 |
+ {3: 2 }22{1:2}22222{1:2}22 |
+ {3: 3 }33{1:3}33333{1:3}3 |
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {8:X }|
+ {4: 1 }^11{1:1}11111{1:1}1 |
+ {3: 2 }22{1:2}22222{1:2}22 |
+ {3: 3 }33{1:3}33333{1:3}3 |
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {7:X }|
+ |
+ ]])
+ end)
+
+ it("in 'breakindent' vim-patch:8.2.1689", function()
+ exec([[
+ call setline(1, 'The quick brown fox jumped over the lazy dogs')
+ set co=40 linebreak bri briopt=shift:2 cc=40,41,43
+ ]])
+ screen:expect([[
+ ^The quick brown fox jumped over the {1: }|
+ {1: } {1:l}azy dogs |
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ |
+ ]])
+ end)
+
+ it("in 'showbreak' vim-patch:8.2.1689", function()
+ exec([[
+ call setline(1, 'The quick brown fox jumped over the lazy dogs')
+ set co=40 showbreak=+++>\\ cc=40,41,43
+ ]])
+ screen:expect([[
+ ^The quick brown fox jumped over the laz{1:y}|
+ {6:+}{5:+}{6:+}{5:>\} dogs |
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ {5:~ }|
+ |
+ ]])
+ end)
+end)
describe("MsgSeparator highlight and msgsep fillchar", function()
local screen
@@ -1378,6 +1709,46 @@ describe("'number' and 'relativenumber' highlight", function()
|
]])
end)
+
+ it('relative number highlight is updated if cursor is moved from timer', function()
+ local screen = Screen.new(50, 8)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Brown}, -- LineNr
+ [2] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ })
+ screen:attach()
+ exec([[
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set relativenumber
+ call cursor(4, 1)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ ]])
+ screen:expect({grid = [[
+ {1: 3 }aaaaa |
+ {1: 2 }bbbbb |
+ {1: 1 }ccccc |
+ {1: 0 }^ddddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]], timeout = 100})
+ screen:expect({grid = [[
+ {1: 0 }^aaaaa |
+ {1: 1 }bbbbb |
+ {1: 2 }ccccc |
+ {1: 3 }ddddd |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]]})
+ end)
end)
describe("'winhighlight' highlight", function()
@@ -1478,8 +1849,7 @@ describe("'winhighlight' highlight", function()
]], unchanged=true}
end)
-
- it('works local to the buffer', function()
+ it('works local to the window', function()
insert("aa")
command("split")
command("setlocal winhl=Normal:Background1")
@@ -1870,4 +2240,35 @@ describe("'winhighlight' highlight", function()
|
]]}
end)
+
+ it('can override StatusLine and StatusLineNC', function()
+ command('set winhighlight=StatusLine:Background1,StatusLineNC:Background2')
+ command('split')
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {1:[No Name] }|
+ |
+ {0:~ }|
+ {5:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('can override WinBar and WinBarNC #19345', function()
+ command('setlocal winbar=foobar')
+ command('set winhighlight=WinBar:Background1,WinBarNC:Background2')
+ command('split')
+ screen:expect([[
+ {1:foobar }|
+ ^ |
+ {0:~ }|
+ {3:[No Name] }|
+ {5:foobar }|
+ |
+ {4:[No Name] }|
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index 2a567b28ee..df7f34aa7f 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -5,7 +5,7 @@ local clear, insert = helpers.clear, helpers.insert
local command = helpers.command
local meths = helpers.meths
local iswin = helpers.iswin
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local thelpers = require('test.functional.terminal.helpers')
describe('ext_hlstate detailed highlights', function()
@@ -14,6 +14,7 @@ describe('ext_hlstate detailed highlights', function()
before_each(function()
clear()
command('syntax on')
+ command('hi VertSplit gui=reverse')
screen = Screen.new(40, 8)
screen:attach({ext_hlstate=true})
end)
@@ -59,7 +60,7 @@ describe('ext_hlstate detailed highlights', function()
it('work with cleared UI highlights', function()
screen:set_default_attr_ids({
- [1] = {{}, {{hi_name = "VertSplit", ui_name = "VertSplit", kind = "ui"}}},
+ [1] = {{}, {{hi_name = "Normal", ui_name = "WinSeparator", kind = "ui"}}},
[2] = {{bold = true, foreground = Screen.colors.Blue1},
{{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
[3] = {{bold = true, reverse = true},
@@ -179,6 +180,8 @@ describe('ext_hlstate detailed highlights', function()
end)
it("work with :terminal", function()
+ if helpers.pending_win32(pending) then return end
+
screen:set_default_attr_ids({
[1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}},
[2] = {{foreground = tonumber('0x00ccff'), fg_indexed=true}, {{kind = "term"}}},
@@ -188,7 +191,7 @@ 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(["'..nvim_dir..'/tty-test"])')
+ command(("enew | call termopen(['%s'])"):format(testprg('tty-test')))
screen:expect([[
^tty ready |
{1: } |
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index b6e2f2311f..d8dd546a8d 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -17,7 +17,7 @@ local source = helpers.source
local poke_eventloop = helpers.poke_eventloop
local nvim = helpers.nvim
local sleep = helpers.sleep
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local assert_alive = helpers.assert_alive
local default_text = [[
@@ -123,13 +123,11 @@ describe(":substitute, inccommand=split interactivity", function()
it("no preview if invoked by feedkeys()", function()
-- in a script...
source([[:call feedkeys(":%s/tw/MO/g\<CR>")]])
- poke_eventloop()
-- or interactively...
- feed([[:call feedkeys(":%s/tw/MO/g\<CR>")<CR>]])
- poke_eventloop()
+ feed([[:call feedkeys(":%s/bs/BUU/g\<lt>CR>")<CR>]])
eq(1, eval("bufnr('$')"))
-- sanity check: assert the buffer state
- expect(default_text:gsub("tw", "MO"))
+ expect(default_text:gsub("tw", "MO"):gsub("bs", "BUU"))
end)
end)
@@ -257,42 +255,70 @@ describe(":substitute, 'inccommand' preserves", function()
end)
end
- for _, case in pairs{"", "split", "nosplit"} do
- it("visual selection for non-previewable command (inccommand="..case..") #5888", function()
+ for _, case in ipairs({'', 'split', 'nosplit'}) do
+ it('previous substitute string ~ (inccommand='..case..') #12109', function()
local screen = Screen.new(30,10)
common_setup(screen, case, default_text)
- feed('1G2V')
- feed(':s')
- screen:expect([[
- {vis:Inc substitution on} |
- t{vis:wo lines} |
- |
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- :'<,'>s^ |
- ]])
+ feed(':%s/Inc/SUB<CR>')
+ expect([[
+ SUB substitution on
+ two lines
+ ]])
- feed('o')
- screen:expect([[
- {vis:Inc substitution on} |
- t{vis:wo lines} |
- |
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- {15:~ }|
- :'<,'>so^ |
- ]])
+ feed(':%s/line/')
+ poke_eventloop()
+ feed('~')
+ poke_eventloop()
+ feed('<CR>')
+ expect([[
+ SUB substitution on
+ two SUBs
+ ]])
+
+ feed(':%s/sti/')
+ poke_eventloop()
+ feed('~')
+ poke_eventloop()
+ feed('B')
+ poke_eventloop()
+ feed('<CR>')
+ expect([[
+ SUB subSUBBtution on
+ two SUBs
+ ]])
+
+ feed(':%s/ion/NEW<CR>')
+ expect([[
+ SUB subSUBBtutNEW on
+ two SUBs
+ ]])
+
+ feed(':%s/two/')
+ poke_eventloop()
+ feed('N')
+ poke_eventloop()
+ feed('~')
+ poke_eventloop()
+ feed('<CR>')
+ expect([[
+ SUB subSUBBtutNEW on
+ NNEW SUBs
+ ]])
+
+ feed(':%s/bS/')
+ poke_eventloop()
+ feed('~')
+ poke_eventloop()
+ feed('W')
+ poke_eventloop()
+ feed('<CR>')
+ expect([[
+ SUB suNNEWWUBBtutNEW on
+ NNEW SUBs
+ ]])
end)
end
-
end)
describe(":substitute, 'inccommand' preserves undo", function()
@@ -317,7 +343,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
}
local function test_sub(substring, split, redoable)
- clear()
+ command('bwipe!')
feed_command("set inccommand=" .. split)
insert("1")
@@ -343,7 +369,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
end
local function test_notsub(substring, split, redoable)
- clear()
+ command('bwipe!')
feed_command("set inccommand=" .. split)
insert("1")
@@ -377,7 +403,7 @@ describe(":substitute, 'inccommand' preserves undo", function()
local function test_threetree(substring, split)
- clear()
+ command('bwipe!')
feed_command("set inccommand=" .. split)
insert("1")
@@ -429,6 +455,8 @@ describe(":substitute, 'inccommand' preserves undo", function()
2]])
end
+ before_each(clear)
+
it("at a non-leaf of the undo tree", function()
for _, case in pairs(cases) do
for _, str in pairs(substrings) do
@@ -1279,6 +1307,108 @@ describe(":substitute, inccommand=split", function()
]])
end)
+ it([[preview changes correctly with c_CTRL-R_= and c_CTRL-\_e]], function()
+ feed('gg')
+ feed(":1,2s/t/X")
+ screen:expect([[
+ Inc subs{12:X}itution on |
+ {12:X}wo lines |
+ Inc substitution on |
+ two lines |
+ |
+ {11:[No Name] [+] }|
+ |1| Inc subs{12:X}itution on |
+ |2| {12:X}wo lines |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :1,2s/t/X^ |
+ ]])
+
+ feed([[<C-R>='Y']])
+ -- preview should be unchanged during c_CTRL-R_= editing
+ screen:expect([[
+ Inc subs{12:X}itution on |
+ {12:X}wo lines |
+ Inc substitution on |
+ two lines |
+ |
+ {11:[No Name] [+] }|
+ |1| Inc subs{12:X}itution on |
+ |2| {12:X}wo lines |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ ={1:'Y'}^ |
+ ]])
+
+ feed('<CR>')
+ -- preview should be changed by the result of the expression
+ screen:expect([[
+ Inc subs{12:XY}itution on |
+ {12:XY}wo lines |
+ Inc substitution on |
+ two lines |
+ |
+ {11:[No Name] [+] }|
+ |1| Inc subs{12:XY}itution on |
+ |2| {12:XY}wo lines |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ :1,2s/t/XY^ |
+ ]])
+
+ feed([[<C-\>e'echo']])
+ -- preview should be unchanged during c_CTRL-\_e editing
+ screen:expect([[
+ Inc subs{12:XY}itution on |
+ {12:XY}wo lines |
+ Inc substitution on |
+ two lines |
+ |
+ {11:[No Name] [+] }|
+ |1| Inc subs{12:XY}itution on |
+ |2| {12:XY}wo lines |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {10:[Preview] }|
+ ={1:'echo'}^ |
+ ]])
+
+ feed('<CR>')
+ -- preview should be cleared if command is changed to a non-previewable one
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :echo^ |
+ ]])
+ end)
+
end)
describe("inccommand=nosplit", function()
@@ -1582,10 +1712,12 @@ end)
describe("'inccommand' and :cnoremap", function()
local cases = { "", "split", "nosplit" }
+ local screen
- local function refresh(case)
+ local function refresh(case, visual)
clear()
- common_setup(nil, case, default_text)
+ screen = visual and Screen.new(50,10) or nil
+ common_setup(screen, case, default_text)
end
it('work with remapped characters', function()
@@ -1642,13 +1774,15 @@ describe("'inccommand' and :cnoremap", function()
it('still works with a broken mapping', function()
for _, case in pairs(cases) do
- refresh(case)
+ refresh(case, true)
feed_command("cnoremap <expr> x execute('bwipeout!')[-1].'x'")
feed(":%s/tw/tox<enter>")
+ screen:expect{any=[[{14:^E565:]]}
+ feed('<c-c>')
-- error thrown b/c of the mapping
- neq(nil, eval('v:errmsg'):find('^E523:'))
+ neq(nil, eval('v:errmsg'):find('^E565:'))
expect([[
Inc substitution on
toxo lines
@@ -1794,26 +1928,26 @@ describe("'inccommand' split windows", function()
feed_command("split")
feed(":%s/tw")
screen:expect([[
- Inc substitution on {10:│}Inc substitution on|
- {12:tw}o lines {10:│}{12:tw}o lines |
- {10:│} |
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {11:[No Name] [+] }{10:│}{15:~ }|
- Inc substitution on {10:│}{15:~ }|
- {12:tw}o lines {10:│}{15:~ }|
- {10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
+ Inc substitution on │Inc substitution on|
+ {12:tw}o lines │{12:tw}o lines |
+ │ |
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {11:[No Name] [+] }│{15:~ }|
+ Inc substitution on │{15:~ }|
+ {12:tw}o lines │{15:~ }|
+ │{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
{10:[No Name] [+] [No Name] [+] }|
|2| {12:tw}o lines |
{15:~ }|
@@ -1833,20 +1967,20 @@ describe("'inccommand' split windows", function()
feed(":%s/tw")
screen:expect([[
- Inc substitution on {10:│}Inc substitution on|
- {12:tw}o lines {10:│}{12:tw}o lines |
- {10:│} |
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
- {15:~ }{10:│}{15:~ }|
+ Inc substitution on │Inc substitution on|
+ {12:tw}o lines │{12:tw}o lines |
+ │ |
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
+ {15:~ }│{15:~ }|
{11:[No Name] [+] }{10:[No Name] [+] }|
Inc substitution on |
{12:tw}o lines |
@@ -1917,6 +2051,16 @@ describe("'inccommand' split windows", function()
end
end)
+ it("don't open if there's not enough room", function()
+ refresh()
+ screen:try_resize(40, 3)
+ feed("gg:%s/tw")
+ screen:expect([[
+ Inc substitution on |
+ {12:tw}o lines |
+ :%s/tw^ |
+ ]])
+ end)
end)
describe("'inccommand' with 'gdefault'", function()
@@ -2731,7 +2875,7 @@ it(':substitute with inccommand during :terminal activity', function()
clear()
command("set cmdwinheight=3")
- feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 5000 xxx<cr>]])
+ feed(([[:terminal "%s" REP 5000 xxx<cr>]]):format(testprg('shell-test')))
command('file term')
feed('G') -- Follow :terminal output.
command('new')
@@ -2773,6 +2917,62 @@ it(':substitute with inccommand, timer-induced :redraw #9777', function()
]])
end)
+it(':substitute with inccommand, allows :redraw before first separator is typed #18857', function()
+ local screen = Screen.new(30,6)
+ clear()
+ common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
+ command('hi! link NormalFloat CursorLine')
+ local float_buf = meths.create_buf(false, true)
+ meths.open_win(float_buf, false, {
+ relative = 'editor', height = 1, width = 5, row = 3, col = 0, focusable = false,
+ })
+ feed(':%s')
+ screen:expect([[
+ foo bar baz |
+ bar baz fox |
+ bar foo baz |
+ {16: }{15: }|
+ {15:~ }|
+ :%s^ |
+ ]])
+ meths.buf_set_lines(float_buf, 0, -1, true, {'foo'})
+ command('redraw')
+ screen:expect([[
+ foo bar baz |
+ bar baz fox |
+ bar foo baz |
+ {16:foo }{15: }|
+ {15:~ }|
+ :%s^ |
+ ]])
+end)
+
+it(':substitute with inccommand, does not crash if range contains invalid marks', function()
+ local screen = Screen.new(30, 6)
+ clear()
+ common_setup(screen, 'split', 'test')
+ feed([[:'a,'bs]])
+ screen:expect([[
+ test |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :'a,'bs^ |
+ ]])
+ -- v:errmsg shouldn't be set either before the first separator is typed
+ eq('', eval('v:errmsg'))
+ feed('/')
+ screen:expect([[
+ test |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :'a,'bs/^ |
+ ]])
+end)
+
it(":substitute doesn't crash with inccommand, if undo is empty #12932", function()
local screen = Screen.new(10,5)
clear()
@@ -2808,3 +3008,16 @@ it('long :%s/ with inccommand does not collapse cmdline', function()
AAAAAAA^ |
]])
end)
+
+it("with 'inccommand' typing :filter doesn't segfault or leak memory #19057", function()
+ clear()
+ common_setup(nil, 'nosplit')
+ feed(':filter s')
+ assert_alive()
+ feed(' ')
+ assert_alive()
+ feed('h')
+ assert_alive()
+ feed('i')
+ assert_alive()
+end)
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
new file mode 100644
index 0000000000..b5816f6fe6
--- /dev/null
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -0,0 +1,356 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local insert = helpers.insert
+local feed = helpers.feed
+local command = helpers.command
+local assert_alive = helpers.assert_alive
+
+-- Implements a :Replace command that works like :substitute.
+local setup_replace_cmd = [[
+ local function show_replace_preview(buf, use_preview_win, preview_ns, preview_buf, matches)
+ -- Find the width taken by the largest line number, used for padding the line numbers
+ local highest_lnum = math.max(matches[#matches][1], 1)
+ local highest_lnum_width = math.floor(math.log10(highest_lnum))
+ local preview_buf_line = 0
+
+ vim.g.prevns = preview_ns
+ vim.g.prevbuf = preview_buf
+
+ for _, match in ipairs(matches) do
+ local lnum = match[1]
+ local line_matches = match[2]
+ local prefix
+
+ if use_preview_win then
+ prefix = string.format(
+ '|%s%d| ',
+ string.rep(' ', highest_lnum_width - math.floor(math.log10(lnum))),
+ lnum
+ )
+
+ vim.api.nvim_buf_set_lines(
+ preview_buf,
+ preview_buf_line,
+ preview_buf_line,
+ 0,
+ { prefix .. vim.api.nvim_buf_get_lines(buf, lnum - 1, lnum, false)[1] }
+ )
+ end
+
+ for _, line_match in ipairs(line_matches) do
+ vim.api.nvim_buf_add_highlight(
+ buf,
+ preview_ns,
+ 'Substitute',
+ lnum - 1,
+ line_match[1],
+ line_match[2]
+ )
+
+ if use_preview_win then
+ vim.api.nvim_buf_add_highlight(
+ preview_buf,
+ preview_ns,
+ 'Substitute',
+ preview_buf_line,
+ #prefix + line_match[1],
+ #prefix + line_match[2]
+ )
+ end
+ end
+
+ preview_buf_line = preview_buf_line + 1
+ end
+
+ if use_preview_win then
+ return 2
+ else
+ return 1
+ end
+ end
+
+ local function do_replace(opts, preview, preview_ns, preview_buf)
+ local pat1 = opts.fargs[1] or ''
+ local pat2 = opts.fargs[2] or ''
+ local line1 = opts.line1
+ local line2 = opts.line2
+
+ local buf = vim.api.nvim_get_current_buf()
+ local lines = vim.api.nvim_buf_get_lines(buf, line1 - 1, line2, 0)
+ local matches = {}
+
+ for i, line in ipairs(lines) do
+ local startidx, endidx = 0, 0
+ local line_matches = {}
+ local num = 1
+
+ while startidx ~= -1 do
+ local match = vim.fn.matchstrpos(line, pat1, 0, num)
+ startidx, endidx = match[2], match[3]
+
+ if startidx ~= -1 then
+ line_matches[#line_matches+1] = { startidx, endidx }
+ end
+
+ num = num + 1
+ end
+
+ if #line_matches > 0 then
+ matches[#matches+1] = { line1 + i - 1, line_matches }
+ end
+ end
+
+ local new_lines = {}
+
+ for _, match in ipairs(matches) do
+ local lnum = match[1]
+ local line_matches = match[2]
+ local line = lines[lnum - line1 + 1]
+ local pat_width_differences = {}
+
+ -- If previewing, only replace the text in current buffer if pat2 isn't empty
+ -- Otherwise, always replace the text
+ if pat2 ~= '' or not preview then
+ if preview then
+ for _, line_match in ipairs(line_matches) do
+ local startidx, endidx = unpack(line_match)
+ local pat_match = line:sub(startidx + 1, endidx)
+
+ pat_width_differences[#pat_width_differences+1] =
+ #vim.fn.substitute(pat_match, pat1, pat2, 'g') - #pat_match
+ end
+ end
+
+ new_lines[lnum] = vim.fn.substitute(line, pat1, pat2, 'g')
+ end
+
+ -- Highlight the matches if previewing
+ if preview then
+ local idx_offset = 0
+ for i, line_match in ipairs(line_matches) do
+ local startidx, endidx = unpack(line_match)
+ -- Starting index of replacement text
+ local repl_startidx = startidx + idx_offset
+ -- Ending index of the replacement text (if pat2 isn't empty)
+ local repl_endidx
+
+ if pat2 ~= '' then
+ repl_endidx = endidx + idx_offset + pat_width_differences[i]
+ else
+ repl_endidx = endidx + idx_offset
+ end
+
+ if pat2 ~= '' then
+ idx_offset = idx_offset + pat_width_differences[i]
+ end
+
+ line_matches[i] = { repl_startidx, repl_endidx }
+ end
+ end
+ end
+
+ for lnum, line in pairs(new_lines) do
+ vim.api.nvim_buf_set_lines(buf, lnum - 1, lnum, false, { line })
+ end
+
+ if preview then
+ local lnum = vim.api.nvim_win_get_cursor(0)[1]
+ -- Use preview window only if preview buffer is provided and range isn't just the current line
+ local use_preview_win = (preview_buf ~= nil) and (line1 ~= lnum or line2 ~= lnum)
+ return show_replace_preview(buf, use_preview_win, preview_ns, preview_buf, matches)
+ end
+ end
+
+ local function replace(opts)
+ do_replace(opts, false)
+ end
+
+ local function replace_preview(opts, preview_ns, preview_buf)
+ return do_replace(opts, true, preview_ns, preview_buf)
+ end
+
+ -- ":<range>Replace <pat1> <pat2>"
+ -- Replaces all occurences of <pat1> in <range> with <pat2>
+ vim.api.nvim_create_user_command(
+ 'Replace',
+ replace,
+ { nargs = '*', range = '%', addr = 'lines',
+ preview = replace_preview }
+ )
+]]
+
+describe("'inccommand' for user commands", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 17)
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.Yellow1},
+ [2] = {foreground = Screen.colors.Blue1, bold = true},
+ [3] = {reverse = true},
+ [4] = {reverse = true, bold = true}
+ })
+ screen:attach()
+ exec_lua(setup_replace_cmd)
+ command('set cmdwinheight=5')
+ insert[[
+ 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
+ ]]
+ end)
+
+ it('works with inccommand=nosplit', function()
+ command('set inccommand=nosplit')
+ feed(':Replace text cats')
+ screen:expect([[
+ {1:cats} on line 1 |
+ more {1:cats} on line 2 |
+ oh no, even more {1:cats} |
+ will the {1:cats} ever stop |
+ oh well |
+ did the {1:cats} stop |
+ why won't it stop |
+ make the {1:cats} stop |
+ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ :Replace text cats^ |
+ ]])
+ end)
+
+ it('works with inccommand=split', function()
+ command('set inccommand=split')
+ feed(':Replace text cats')
+ screen:expect([[
+ {1:cats} on line 1 |
+ more {1:cats} on line 2 |
+ oh no, even more {1:cats} |
+ will the {1:cats} ever stop |
+ oh well |
+ did the {1:cats} stop |
+ why won't it stop |
+ make the {1:cats} stop |
+ |
+ {4:[No Name] [+] }|
+ |1| {1:cats} on line 1 |
+ |2| more {1:cats} on line 2 |
+ |3| oh no, even more {1:cats} |
+ |4| will the {1:cats} ever stop |
+ |6| did the {1:cats} stop |
+ {3:[Preview] }|
+ :Replace text cats^ |
+ ]])
+ end)
+
+ it('properly closes preview when inccommand=split', function()
+ command('set inccommand=split')
+ feed(':Replace text cats<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 |
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ |
+ ]])
+ end)
+
+ it('properly executes command when inccommand=split', function()
+ command('set inccommand=split')
+ feed(':Replace text cats<CR>')
+ screen:expect([[
+ cats on line 1 |
+ more cats on line 2 |
+ oh no, even more cats |
+ will the cats ever stop |
+ oh well |
+ did the cats stop |
+ why won't it stop |
+ make the cats stop |
+ ^ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ :Replace text cats |
+ ]])
+ end)
+
+ it('shows preview window only when range is not current line', function()
+ command('set inccommand=split')
+ feed('gg:.Replace text cats')
+ screen:expect([[
+ {1:cats} 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 |
+ |
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ :.Replace text cats^ |
+ ]])
+ end)
+
+ it('does not crash on ambiguous command #18825', function()
+ command('set inccommand=split')
+ command('command Reply echo 1')
+ feed(':R')
+ assert_alive()
+ feed('e')
+ assert_alive()
+ end)
+
+ it('no crash if preview callback changes inccommand option', function()
+ command('set inccommand=nosplit')
+ exec_lua([[
+ vim.api.nvim_create_user_command('Replace', function() end, {
+ nargs = '*',
+ preview = function()
+ vim.api.nvim_set_option('inccommand', 'split')
+ return 2
+ end,
+ })
+ ]])
+ feed(':R')
+ assert_alive()
+ feed('e')
+ assert_alive()
+ end)
+end)
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index ea8968a653..0f4e97088c 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -3,9 +3,12 @@ local clear, feed_command = helpers.clear, helpers.feed_command
local feed, next_msg, eq = helpers.feed, helpers.next_msg, helpers.eq
local command = helpers.command
local expect = helpers.expect
+local curbuf_contents = helpers.curbuf_contents
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local write_file = helpers.write_file
+local funcs = helpers.funcs
+local eval = helpers.eval
local Screen = require('test.functional.ui.screen')
before_each(clear)
@@ -50,6 +53,8 @@ describe('mappings', function()
add_mapping('<kenter>','<kenter>')
add_mapping('<kcomma>','<kcomma>')
add_mapping('<kequal>','<kequal>')
+ add_mapping('<f38>','<f38>')
+ add_mapping('<f63>','<f63>')
end)
it('ok', function()
@@ -106,6 +111,8 @@ describe('mappings', function()
check_mapping('<KPComma>','<kcomma>')
check_mapping('<kequal>','<kequal>')
check_mapping('<KPEquals>','<kequal>')
+ check_mapping('<f38>','<f38>')
+ check_mapping('<f63>','<f63>')
end)
it('support meta + multibyte char mapping', function()
@@ -114,11 +121,196 @@ describe('mappings', function()
end)
end)
-describe('input utf sequences that contain CSI/K_SPECIAL', function()
+describe('input utf sequences that contain K_SPECIAL (0x80)', function()
it('ok', function()
feed('i…<esc>')
expect('…')
end)
+
+ it('can be mapped', function()
+ command('inoremap … E280A6')
+ feed('i…<esc>')
+ expect('E280A6')
+ end)
+end)
+
+describe('input utf sequences that contain CSI (0x9B)', function()
+ it('ok', function()
+ feed('iě<esc>')
+ expect('ě')
+ end)
+
+ it('can be mapped', function()
+ command('inoremap ě C49B')
+ feed('iě<esc>')
+ expect('C49B')
+ end)
+end)
+
+describe('input split utf sequences', function()
+ it('ok', function()
+ local str = '►'
+ feed('i' .. str:sub(1, 1))
+ helpers.sleep(10)
+ feed(str:sub(2, 3))
+ expect('►')
+ end)
+
+ it('can be mapped', function()
+ command('inoremap ► E296BA')
+ local str = '►'
+ feed('i' .. str:sub(1, 1))
+ helpers.sleep(10)
+ feed(str:sub(2, 3))
+ expect('E296BA')
+ end)
+end)
+
+describe('input pairs', function()
+ describe('<tab> / <c-i>', function()
+ it('ok', function()
+ feed('i<tab><c-i><esc>')
+ eq('\t\t', curbuf_contents())
+ end)
+
+ describe('can be mapped separately', function()
+ it('if <tab> is mapped after <c-i>', function()
+ command('inoremap <c-i> CTRL-I!')
+ command('inoremap <tab> TAB!')
+ feed('i<tab><c-i><esc>')
+ eq('TAB!CTRL-I!', curbuf_contents())
+ end)
+
+ it('if <tab> is mapped before <c-i>', function()
+ command('inoremap <tab> TAB!')
+ command('inoremap <c-i> CTRL-I!')
+ feed('i<tab><c-i><esc>')
+ eq('TAB!CTRL-I!', curbuf_contents())
+ end)
+ end)
+ end)
+
+ describe('<cr> / <c-m>', function()
+ it('ok', function()
+ feed('iunos<c-m>dos<cr>tres<esc>')
+ eq('unos\ndos\ntres', curbuf_contents())
+ end)
+
+ describe('can be mapped separately', function()
+ it('if <cr> is mapped after <c-m>', function()
+ command('inoremap <c-m> SNIPPET!')
+ command('inoremap <cr> , and then<cr>')
+ feed('iunos<c-m>dos<cr>tres<esc>')
+ eq('unosSNIPPET!dos, and then\ntres', curbuf_contents())
+ end)
+
+ it('if <cr> is mapped before <c-m>', function()
+ command('inoremap <cr> , and then<cr>')
+ command('inoremap <c-m> SNIPPET!')
+ feed('iunos<c-m>dos<cr>tres<esc>')
+ eq('unosSNIPPET!dos, and then\ntres', curbuf_contents())
+ end)
+ end)
+ end)
+
+ describe('<esc> / <c-[>', function()
+ it('ok', function()
+ feed('2adouble<c-[>asingle<esc>')
+ eq('doubledoublesingle', curbuf_contents())
+ end)
+
+ describe('can be mapped separately', function()
+ it('if <esc> is mapped after <c-[>', function()
+ command('inoremap <c-[> HALLOJ!')
+ command('inoremap <esc> ,<esc>')
+ feed('2adubbel<c-[>upp<esc>')
+ eq('dubbelHALLOJ!upp,dubbelHALLOJ!upp,', curbuf_contents())
+ end)
+
+ it('if <esc> is mapped before <c-[>', function()
+ command('inoremap <esc> ,<esc>')
+ command('inoremap <c-[> HALLOJ!')
+ feed('2adubbel<c-[>upp<esc>')
+ eq('dubbelHALLOJ!upp,dubbelHALLOJ!upp,', curbuf_contents())
+ end)
+ end)
+ end)
+end)
+
+it('Ctrl-6 is Ctrl-^ vim-patch:8.1.2333', function()
+ command('split aaa')
+ command('edit bbb')
+ feed('<C-6>')
+ eq('aaa', funcs.bufname())
+end)
+
+it('c_CTRL-R_CTRL-R, i_CTRL-R_CTRL-R, i_CTRL-G_CTRL-K work properly vim-patch:8.1.2346', function()
+ command('set timeoutlen=10')
+
+ command([[let @a = 'aaa']])
+ feed([[:let x = '<C-R><C-R>a'<CR>]])
+ eq([[let x = 'aaa']], eval('@:'))
+
+ feed('a<C-R><C-R>a<Esc>')
+ expect('aaa')
+ command('bwipe!')
+
+ feed('axx<CR>yy<C-G><C-K>a<Esc>')
+ expect([[
+ axx
+ yy]])
+end)
+
+it('typing a simplifiable key at hit-enter prompt triggers mapping vim-patch:8.2.0839', function()
+ local screen = Screen.new(60,8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [2] = {bold = true, reverse = true}, -- MsgSeparator
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg
+ })
+ screen:attach()
+ command([[nnoremap <C-6> <Cmd>echo 'hit ctrl-6'<CR>]])
+ feed_command('ls')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ :ls |
+ 1 %a "[No Name]" line 1 |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<C-6>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ hit ctrl-6 |
+ ]])
+end)
+
+it('mixing simplified and unsimplified keys can trigger mapping vim-patch:8.2.0916', function()
+ command('set timeoutlen=10')
+ command([[imap ' <C-W>]])
+ command('imap <C-W><C-A> c-a')
+ feed([[a'<C-A>]])
+ expect('c-a')
+end)
+
+it('unsimplified mapping works when there was a partial match vim-patch:8.2.4504', function()
+ command('set timeoutlen=10')
+ command('nnoremap <C-J> a')
+ command('nnoremap <NL> x')
+ command('nnoremap <C-J>x <Nop>')
+ funcs.setline(1, 'x')
+ -- CTRL-J b should have trigger the <C-J> mapping and then insert "b"
+ feed('<C-J>b<Esc>')
+ expect('xb')
end)
describe('input non-printable chars', function()
@@ -146,7 +338,7 @@ describe('input non-printable chars', function()
{1:~ }|
{1:~ }|
{1:~ }|
- "Xtest-overwrite" [noeol] 1L, 6C |
+ "Xtest-overwrite" [noeol] 1L, 6B |
]])
-- The timestamp is in second resolution, wait two seconds to be sure.
@@ -237,3 +429,47 @@ describe("event processing and input", function()
eq({'notification', 'stop', {}}, next_msg())
end)
end)
+
+describe('display is updated', function()
+ local screen
+ before_each(function()
+ screen = Screen.new(60, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1}, -- NonText
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ end)
+
+ it('in Insert mode after <Nop> mapping #17911', function()
+ command('imap <Plug>test <Nop>')
+ command('imap <F2> abc<CR><Plug>test')
+ feed('i<F2>')
+ screen:expect([[
+ abc |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+
+ it('in Insert mode after empty string <expr> mapping #17911', function()
+ command('imap <expr> <Plug>test ""')
+ command('imap <F2> abc<CR><Plug>test')
+ feed('i<F2>')
+ screen:expect([[
+ abc |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index f038348253..00f126a1f2 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -12,6 +12,7 @@ local nvim_prog = helpers.nvim_prog
local iswin = helpers.iswin
local exc_exec = helpers.exc_exec
local exec_lua = helpers.exec_lua
+local poke_eventloop = helpers.poke_eventloop
describe('ui/ext_messages', function()
local screen
@@ -30,6 +31,7 @@ describe('ui/ext_messages', function()
[7] = {background = Screen.colors.Yellow},
[8] = {foreground = Screen.colors.Red},
[9] = {special = Screen.colors.Red, undercurl = true},
+ [10] = {foreground = Screen.colors.Brown};
})
end)
after_each(function()
@@ -303,13 +305,25 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], messages={
+ ]], msg_history={
{kind="echoerr", content={{"raa", 2}}},
{kind="echoerr", content={{"bork", 2}}},
{kind="echoerr", content={{"fail", 2}}},
{kind="echoerr", content={{"extrafail", 2}}},
{kind="echoerr", content={{"problem", 2}}}
- }}
+ }, messages={{
+ content = {{ "Press ENTER or type command to continue", 4 }},
+ kind = "return_prompt"
+ }}}
+
+ feed '<cr>'
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
end)
it('shortmess-=S', function()
@@ -454,11 +468,14 @@ describe('ui/ext_messages', function()
alphpabe^t |
{1:~ }|
{1:~ }|
- ]], messages={
- {kind="echomsg", content={{"stuff"}}},
- }, showmode={
- { "-- INSERT --", 3 }
- }}
+ ]], msg_history={{
+ content = {{ "stuff" }},
+ kind = "echomsg",
+ }}, showmode={{ "-- INSERT --", 3 }},
+ messages={{
+ content = {{ "Press ENTER or type command to continue", 4}},
+ kind = "return_prompt"
+ }}}
end)
it('&showmode with macro-recording message', function()
@@ -684,12 +701,15 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], messages={
+ ]], msg_history={
{kind="echomsg", content={{"howdy"}}},
{kind="", content={{"Type :qa and press <Enter> to exit Nvim"}}},
{kind="echoerr", content={{"bork", 2}}},
{kind="emsg", content={{"E117: Unknown function: nosuchfunction", 2}}}
- }}
+ }, messages={{
+ content = {{ "Press ENTER or type command to continue", 4}},
+ kind = "return_prompt"
+ }}}
end)
it('implies ext_cmdline and ignores cmdheight', function()
@@ -717,7 +737,6 @@ describe('ui/ext_messages', function()
]])
eq(0, eval('&cmdheight'))
- -- normally this would be an error
feed(':set cmdheight=0')
screen:expect{grid=[[
^ |
@@ -839,9 +858,53 @@ stack traceback:
{1:~ }|
{1:~ }|
]]}
-
end)
+ it('supports nvim_echo messages with multiple attrs', function()
+ async_meths.echo({{'wow, ',"Search"}, {"such\n\nvery ", "ErrorMsg"}, {"color", "LineNr"}}, true, {})
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "" }
+ }}
+
+ feed ':ls<cr>'
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = "echomsg" }
+ }}
+
+ feed ':messages<cr>'
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ { content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" }
+ }, msg_history={
+ { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "echomsg" }
+ }}
+
+ feed '<cr>'
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+ end)
end)
describe('ui/builtin messages', function()
@@ -850,17 +913,19 @@ describe('ui/builtin messages', function()
clear()
screen = Screen.new(60, 7)
screen:attach({rgb=true, ext_popupmenu=true})
- screen:set_default_attr_ids({
- [1] = {bold = true, foreground = Screen.colors.Blue1},
- [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
- [3] = {bold = true, reverse = true},
- [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
- [5] = {foreground = Screen.colors.Blue1},
- [6] = {bold = true, foreground = Screen.colors.Magenta},
- [7] = {background = Screen.colors.Grey20},
- [8] = {reverse = true},
- [9] = {background = Screen.colors.LightRed}
- })
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
+ [3] = {bold = true, reverse = true};
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4};
+ [5] = {foreground = Screen.colors.Blue1};
+ [6] = {bold = true, foreground = Screen.colors.Magenta};
+ [7] = {background = Screen.colors.Grey20};
+ [8] = {reverse = true};
+ [9] = {background = Screen.colors.LightRed};
+ [10] = {background = Screen.colors.Yellow};
+ [11] = {foreground = Screen.colors.Brown};
+ }
end)
it('supports multiline messages from rpc', function()
@@ -1013,7 +1078,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
end)
it('redraws NOT_VALID correctly after message', function()
- -- edge case: only one window was set NOT_VALID. Orginal report
+ -- edge case: only one window was set NOT_VALID. Original report
-- used :make, but fake it using one command to set the current
-- window NOT_VALID and another to show a long message.
command("set more")
@@ -1096,6 +1161,88 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
{4:Press ENTER or type command to continue}^ |
]]}
end)
+
+ it('supports nvim_echo messages with multiple attrs', function()
+ async_meths.echo({{'wow, ',"Search"}, {"such\n\nvery ", "ErrorMsg"}, {"color", "LineNr"}}, true, {})
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {3: }|
+ {10:wow, }{2:such} |
+ |
+ {2:very }{11:color} |
+ {4:Press ENTER or type command to continue}^ |
+ ]]}
+
+ feed '<cr>'
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed ':messages<cr>'
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {3: }|
+ {10:wow, }{2:such} |
+ |
+ {2:very }{11:color} |
+ {4:Press ENTER or type command to continue}^ |
+ ]]}
+ end)
+
+ it('prints lines in Ex mode correctly with a burst of carriage returns #19341', function()
+ command('set number')
+ meths.buf_set_lines(0, 0, 0, true, {'aaa', 'bbb', 'ccc'})
+ command('set display-=msgsep')
+ feed('gggQ<CR><CR>1<CR><CR>vi')
+ screen:expect([[
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ {11: 2 }bbb |
+ {11: 3 }ccc |
+ :1 |
+ {11: 1 }aaa |
+ {11: 2 }bbb |
+ :vi^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ {11: 1 }aaa |
+ {11: 2 }^bbb |
+ {11: 3 }ccc |
+ {11: 4 } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ command('set display+=msgsep')
+ feed('gggQ<CR><CR>1<CR><CR>vi')
+ screen:expect([[
+ Entering Ex mode. Type "visual" to go to Normal mode. |
+ {11: 2 }bbb |
+ {11: 3 }ccc |
+ :1 |
+ {11: 1 }aaa |
+ {11: 2 }bbb |
+ :vi^ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ {11: 1 }aaa |
+ {11: 2 }^bbb |
+ {11: 3 }ccc |
+ {11: 4 } |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
end)
describe('ui/ext_messages', function()
@@ -1111,6 +1258,8 @@ describe('ui/ext_messages', function()
[3] = {bold = true},
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
[5] = {foreground = Screen.colors.Blue1},
+ [6] = {reverse = true},
+ [7] = {bold = true, reverse = true},
})
end)
@@ -1202,6 +1351,107 @@ describe('ui/ext_messages', function()
{content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" }
}}
end)
+
+ it('supports global statusline', function()
+ feed(":set laststatus=3<cr>")
+ feed(":sp<cr>")
+ feed(":set cmdheight<cr>")
+ screen:expect({grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────────────────────────|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {7:[No Name] }|
+ ]], messages={
+ {content = { { " cmdheight=0" } }, kind = "" }
+ }})
+
+ feed("<c-w>+")
+ feed(":set laststatus<cr>")
+ screen:expect({grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────────────────────────|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {7:[No Name] }|
+ ]], messages={
+ {content = { { " laststatus=3" } }, kind = "" }
+ }})
+
+ feed(":set mouse=a<cr>")
+ meths.input_mouse('left', 'press', '', 0, 12, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 0, 12, 10)
+ meths.input_mouse('left', 'drag', '', 0, 11, 10)
+ feed("<c-l>")
+ feed(":set cmdheight<cr>")
+ screen:expect({grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ────────────────────────────────────────────────────────────────────────────────|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {7:[No Name] }|
+ ]], messages={
+ {content = { { " cmdheight=0" } }, kind = "" }
+ }})
+ end)
end)
describe('ui/msg_puts_printf', function()
@@ -1226,7 +1476,7 @@ describe('ui/msg_puts_printf', function()
pending('Locale ja_JP.UTF-8 not supported', function() end)
return
elseif helpers.isCI() then
- -- Fails non--Windows CI. Message catalog direcotry issue?
+ -- Fails non--Windows CI. Message catalog directory issue?
pending('fails on unix CI', function() end)
return
end
@@ -1281,7 +1531,7 @@ ullamco laboris nisi ut
aliquip ex ea commodo consequat.]])
end)
- it('can be quit', function()
+ it('can be quit with echon', function()
screen:try_resize(25,5)
feed(':echon join(map(range(0, &lines*10), "v:val"), "\\n")<cr>')
screen:expect{grid=[[
@@ -1301,6 +1551,45 @@ aliquip ex ea commodo consequat.]])
]]}
end)
+ it('can be quit with Lua #11224 #16537', function()
+ -- NOTE: adds "4" to message history, although not displayed initially
+ -- (triggered the more prompt).
+ screen:try_resize(40,5)
+ feed(':lua for i=0,10 do print(i) end<cr>')
+ screen:expect{grid=[[
+ 0 |
+ 1 |
+ 2 |
+ 3 |
+ {4:-- More --}^ |
+ ]]}
+ feed('q')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ feed(':mess<cr>')
+ screen:expect{grid=[[
+ 0 |
+ 1 |
+ 2 |
+ 3 |
+ {4:-- More --}^ |
+ ]]}
+ feed('j')
+ screen:expect{grid=[[
+ 1 |
+ 2 |
+ 3 |
+ 4 |
+ {4:Press ENTER or type command to continue}^ |
+ ]]}
+ feed('<cr>')
+ end)
+
it('handles wrapped lines with line scroll', function()
feed(':lua error(_G.x)<cr>')
screen:expect{grid=[[
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index baacef358f..69b0d1ecec 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -32,7 +32,7 @@ describe('ui/mouse/input', function()
[6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[7] = {bold = true, foreground = Screen.colors.SeaGreen4},
})
- command("set display-=msgsep")
+ command("set display-=msgsep mousemodel=extend")
feed('itesting<cr>mouse<cr>support and selection<esc>')
screen:expect([[
testing |
@@ -595,54 +595,54 @@ describe('ui/mouse/input', function()
feed('ifoo\nbar<esc>')
screen:expect{grid=[[
- testing {4:│}testing |
- mouse {4:│}mouse |
- support and selection {4:│}support and selection |
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│[No Name] [+] }|
- {0:~ }{4:│}foo{0:$} |
- {0:~ }{4:│}ba^r{0:$} |
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
+ testing │testing |
+ mouse │mouse |
+ support and selection │support and selection |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{4:[No Name] [+] }|
+ {0:~ }│foo{0:$} |
+ {0:~ }│ba^r{0:$} |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
{4:[No Name] [+] }{5:[No Name] [+] }|
|
]]}
meths.input_mouse('left', 'press', '', 0, 6, 27)
screen:expect{grid=[[
- testing {4:│}testing |
- mouse {4:│}mouse |
- support and selection {4:│}support and selection |
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│[No Name] [+] }|
- {0:~ }{4:│}^foo{0:$} |
- {0:~ }{4:│}bar{0:$} |
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
+ testing │testing |
+ mouse │mouse |
+ support and selection │support and selection |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{4:[No Name] [+] }|
+ {0:~ }│^foo{0:$} |
+ {0:~ }│bar{0:$} |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
{4:[No Name] [+] }{5:[No Name] [+] }|
|
]]}
meths.input_mouse('left', 'drag', '', 0, 7, 30)
screen:expect{grid=[[
- testing {4:│}testing |
- mouse {4:│}mouse |
- support and selection {4:│}support and selection |
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│[No Name] [+] }|
- {0:~ }{4:│}{1:foo}{3:$} |
- {0:~ }{4:│}{1:bar}{0:^$} |
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
- {0:~ }{4:│}{0:~ }|
+ testing │testing |
+ mouse │mouse |
+ support and selection │support and selection |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{4:[No Name] [+] }|
+ {0:~ }│{1:foo}{3:$} |
+ {0:~ }│{1:bar}{0:^$} |
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
+ {0:~ }│{0:~ }|
{4:[No Name] [+] }{5:[No Name] [+] }|
{2:-- VISUAL --} |
]]}
@@ -729,12 +729,12 @@ describe('ui/mouse/input', function()
feed('k')
feed_command('sp', 'vsp')
screen:expect([[
- lines {4:│}lines |
- to {4:│}to |
- test {4:│}test |
- ^mouse scrolling {4:│}mouse scrolling |
- {4:│} |
- {0:~ }{4:│}{0:~ }|
+ lines │lines |
+ to │to |
+ test │test |
+ ^mouse scrolling │mouse scrolling |
+ │ |
+ {0:~ }│{0:~ }|
{5:[No Name] [+] }{4:[No Name] [+] }|
to |
test |
@@ -750,12 +750,12 @@ describe('ui/mouse/input', function()
feed('<ScrollWheelDown><0,0>')
end
screen:expect([[
- ^mouse scrolling {4:│}lines |
- {4:│}to |
- {0:~ }{4:│}test |
- {0:~ }{4:│}mouse scrolling |
- {0:~ }{4:│} |
- {0:~ }{4:│}{0:~ }|
+ ^mouse scrolling │lines |
+ │to |
+ {0:~ }│test |
+ {0:~ }│mouse scrolling |
+ {0:~ }│ |
+ {0:~ }│{0:~ }|
{5:[No Name] [+] }{4:[No Name] [+] }|
to |
test |
@@ -771,12 +771,12 @@ describe('ui/mouse/input', function()
feed('<ScrollWheelUp><27,0>')
end
screen:expect([[
- ^mouse scrolling {4:│}text |
- {4:│}with |
- {0:~ }{4:│}many |
- {0:~ }{4:│}lines |
- {0:~ }{4:│}to |
- {0:~ }{4:│}test |
+ ^mouse scrolling │text |
+ │with |
+ {0:~ }│many |
+ {0:~ }│lines |
+ {0:~ }│to |
+ {0:~ }│test |
{5:[No Name] [+] }{4:[No Name] [+] }|
to |
test |
@@ -793,12 +793,12 @@ describe('ui/mouse/input', function()
feed('<ScrollWheelUp><27,7><ScrollWheelUp>')
end
screen:expect([[
- ^mouse scrolling {4:│}text |
- {4:│}with |
- {0:~ }{4:│}many |
- {0:~ }{4:│}lines |
- {0:~ }{4:│}to |
- {0:~ }{4:│}test |
+ ^mouse scrolling │text |
+ │with |
+ {0:~ }│many |
+ {0:~ }│lines |
+ {0:~ }│to |
+ {0:~ }│test |
{5:[No Name] [+] }{4:[No Name] [+] }|
Inserting |
text |
@@ -1571,4 +1571,23 @@ describe('ui/mouse/input', function()
meths.set_option('winwidth', winwidth)
meths.input_mouse('left', 'release', '', 0, 0, 0)
end)
+
+ it('scroll keys are not translated into multiclicks #6211 #6989', function()
+ meths.set_var('mouse_up', 0)
+ meths.set_var('mouse_up2', 0)
+ meths.set_var('mouse_up3', 0)
+ meths.set_var('mouse_up4', 0)
+ command('nnoremap <ScrollWheelUp> <Cmd>let g:mouse_up += 1<CR>')
+ command('nnoremap <2-ScrollWheelUp> <Cmd>let g:mouse_up2 += 1<CR>')
+ command('nnoremap <3-ScrollWheelUp> <Cmd>let g:mouse_up3 += 1<CR>')
+ command('nnoremap <4-ScrollWheelUp> <Cmd>let g:mouse_up4 += 1<CR>')
+ meths.input_mouse('wheel', 'up', '', 0, 0, 0)
+ meths.input_mouse('wheel', 'up', '', 0, 0, 0)
+ meths.input_mouse('wheel', 'up', '', 0, 0, 0)
+ meths.input_mouse('wheel', 'up', '', 0, 0, 0)
+ eq(4, meths.get_var('mouse_up'))
+ eq(0, meths.get_var('mouse_up2'))
+ eq(0, meths.get_var('mouse_up3'))
+ eq(0, meths.get_var('mouse_up4'))
+ end)
end)
diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua
index e6a79feadc..d4e237bcb4 100644
--- a/test/functional/ui/multibyte_spec.lua
+++ b/test/functional/ui/multibyte_spec.lua
@@ -6,6 +6,9 @@ local feed = helpers.feed
local feed_command = helpers.feed_command
local insert = helpers.insert
local funcs = helpers.funcs
+local meths = helpers.meths
+local split = helpers.split
+local dedent = helpers.dedent
describe("multibyte rendering", function()
local screen
@@ -26,7 +29,7 @@ describe("multibyte rendering", function()
̊
x]])
feed("gg")
- -- verify the modifier infact is alone
+ -- verify the modifier in fact is alone
feed_command("ascii")
screen:expect([[
^ ̊ |
@@ -115,6 +118,35 @@ describe("multibyte rendering", function()
{4:-- INSERT --} |
]])
end)
+
+ it('works with a lot of unicode (zalgo) text', function()
+ screen:try_resize(65, 10)
+ meths.buf_set_lines(0,0,-1,true, split(dedent [[
+ L̓̉̑̒̌̚ơ̗̌̒̄̀ŕ̈̈̎̐̕è̇̅̄̄̐m̖̟̟̅̄̚ ̛̓̑̆̇̍i̗̟̞̜̅̐p̗̞̜̉̆̕s̟̜̘̍̑̏ū̟̞̎̃̉ḿ̘̙́́̐ ̖̍̌̇̉̚d̞̄̃̒̉̎ò́̌̌̂̐l̞̀̄̆̌̚ȯ̖̞̋̀̐r̓̇̌̃̃̚ ̗̘̀̏̍́s̜̀̎̎̑̕i̟̗̐̄̄̚t̝̎̆̓̐̒ ̘̇̔̓̊̚ȃ̛̟̗̏̅m̜̟̙̞̈̓é̘̞̟̔̆t̝̂̂̈̑̔,̜̜̖̅̄̍ ̛̗̊̓̆̚c̟̍̆̍̈̔ȯ̖̖̝̑̀n̜̟̎̊̃̚s̟̏̇̎̒̚e̙̐̈̓̌̚c̙̍̈̏̅̕ť̇̄̇̆̓e̛̓̌̈̓̈t̟̍̀̉̆̅u̝̞̎̂̄̚r̘̀̅̈̅̐ ̝̞̓́̇̉ã̏̀̆̅̕d̛̆̐̉̆̋ȉ̞̟̍̃̚p̛̜̊̍̂̓ȋ̏̅̃̋̚ṥ̛̏̃̕č̛̞̝̀̂í̗̘̌́̎n̔̎́̒̂̕ǧ̗̜̋̇̂ ̛̜̔̄̎̃ê̛̔̆̇̕l̘̝̏̐̊̏ĩ̛̍̏̏̄t̟̐́̀̐̎,̙̘̍̆̉̐ ̋̂̏̄̌̅s̙̓̌̈́̇e̛̗̋̒̎̏d̜̗̊̍̊̚
+ ď̘̋̌̌̕ǒ̝̗̔̇̕ ̙̍́̄̄̉è̛̛̞̌̌i̜̖̐̈̆̚ȕ̇̈̓̃̓ŝ̛̞̙̉̋m̜̐̂̄̋̂ȯ̈̎̎̅̕d̜̙̓̔̋̑ ̞̗̄̂̂̚t̝̊́̃́̄e̛̘̜̞̓̑m̊̅̏̉̌̕p̛̈̂̇̀̐ỏ̙̘̈̉̔r̘̞̋̍̃̚ ̝̄̀̇̅̇ỉ̛̖̍̓̈n̛̛̝̎̕̕c̛̛̊̅́̐ĭ̗̓̀̍̐d̞̜̋̐̅̚i̟̙̇̄̊̄d̞̊̂̀̇̚ủ̝̉̑̃̕n̜̏̇̄̐̋ť̗̜̞̋̉ ̝̒̓̌̓̚ȕ̖̙̀̚̕t̖̘̎̉̂̌ ̛̝̄̍̌̂l̛̟̝̃̑̋á̛̝̝̔̅b̝̙̜̗̅̒ơ̖̌̒̄̆r̒̇̓̎̈̄e̛̛̖̅̏̇ ̖̗̜̝̃́e̛̛̘̅̔̌ẗ̛̙̗̐̕ ̖̟̇̋̌̈d̞̙̀̉̑̕ŏ̝̂́̐̑l̞̟̗̓̓̀ơ̘̎̃̄̂r̗̗̖̔̆̍ẻ̖̝̞̋̅ ̜̌̇̍̈̊m̈̉̇̄̒̀a̜̞̘̔̅̆g̗̖̈̃̈̉n̙̖̄̈̉̄â̛̝̜̄̃ ̛́̎̕̕̚ā̊́́̆̌l̟̙̞̃̒́i̖̇̎̃̀̋q̟̇̒̆́̊ủ́̌̇̑̚ã̛̘̉̐̚.̛́̏̐̍̊
+ U̝̙̎̈̐̆t̜̍̌̀̔̏ ̞̉̍̇̈̃e̟̟̊̄̕̕n̝̜̒̓̆̕i̖̒̌̅̇̚m̞̊̃̔̊̂ ̛̜̊̎̄̂a̘̜̋̒̚̚d̟̊̎̇̂̍ ̜̖̏̑̉̕m̜̒̎̅̄̚i̝̖̓̂̍̕n̙̉̒̑̀̔ỉ̖̝̌̒́m̛̖̘̅̆̎ ̖̉̎̒̌̕v̖̞̀̔́̎e̖̙̗̒̎̉n̛̗̝̎̀̂ȉ̞̗̒̕̚ȧ̟̜̝̅̚m̆̉̐̐̇̈,̏̐̎́̍́ ̜̞̙̘̏̆q̙̖̙̅̓̂ủ̇́̀̔̚í̙̟̟̏̐s̖̝̍̏̂̇ ̛̘̋̈̕̕ń̛̞̜̜̎o̗̜̔̔̈̆s̞̘̘̄̒̋t̛̅̋́̔̈ȓ̓̒́̇̅ủ̜̄̃̒̍d̙̝̘̊̏̚ ̛̟̞̄́̔e̛̗̝̍̃̀x̞̖̃̄̂̅e̖̅̇̐̔̃r̗̞̖̔̎̚c̘̜̖̆̊̏ï̙̝̙̂̕t̖̏́̓̋̂ă̖̄̆̑̒t̜̟̍̉̑̏i̛̞̞̘̒̑ǒ̜̆̅̃̉ṅ̖̜̒̎̚
+ u̗̞̓̔̈̏ĺ̟̝́̎̚l̛̜̅̌̎̆a̒̑̆̔̇̃m̜̗̈̊̎̚ċ̘̋̇̂̚ơ̟̖̊́̕ ̖̟̍̉̏̚l̙̔̓̀̅̏ä̞̗̘̙̅ḃ̟̎̄̃̕o̞̎̓̓̓̚r̗̜̊̓̈̒ï̗̜̃̃̅s̀̒̌̂̎̂ ̖̗̗̋̎̐n̝̟̝̘̄̚i̜̒̀̒̐̕s̘̘̄̊̃̀ī̘̜̏̌̕ ̗̖̞̐̈̒ư̙̞̄́̌t̟̘̖̙̊̚ ̌̅̋̆̚̚ä̇̊̇̕̕l̝̞̘̋̔̅i̍̋́̆̑̈q̛̆̐̈̐̚ư̏̆̊́̚î̜̝̑́̊p̗̓̅̑̆̏ ̆́̓̔̋̋e̟̊̋̏̓̚x̗̍̑̊̎̈ ̟̞̆̄̂̍ë̄̎̄̃̅a̛̜̅́̃̈ ̔̋̀̎̐̀c̖̖̍̀̒̂ơ̛̙̖̄̒m̘̔̍̏̆̕ḿ̖̙̝̏̂ȍ̓̋̈̀̕d̆̂̊̅̓̚o̖̔̌̑̚̕ ̙̆́̔̊̒c̖̘̖̀̄̍o̓̄̑̐̓̒ñ̞̒̎̈̚s̞̜̘̈̄̄e̙̊̀̇̌̋q̐̒̓́̔̃ư̗̟̔̔̚å̖̙̞̄̏t̛̙̟̒̇̏.̙̗̓̃̓̎
+ D̜̖̆̏̌̌ư̑̃̌̍̕i̝̊̊̊̊̄s̛̙̒́̌̇ ̛̃̔̄̆̌ă̘̔̅̅̀ú̟̟̟̃̃t̟̂̄̈̈̃e̘̅̌̒̂̆ ̖̟̐̉̉̌î̟̟̙̜̇r̛̙̞̗̄̌ú̗̗̃̌̎r̛̙̘̉̊̕e̒̐̔̃̓̋ ̊̊̍̋̑̉d̛̝̙̉̀̓o̘̜̐̐̓̐l̞̋̌̆̍́o̊̊̐̃̃̚ṙ̛̖̘̃̕ ̞̊̀̍̒̕ȉ́̑̐̇̅ǹ̜̗̜̞̏ ̛̜̐̄̄̚r̜̖̈̇̅̋ĕ̗̉̃̔̚p̟̝̀̓̔̆r̜̈̆̇̃̃e̘̔̔̏̎̓h̗̒̉̑̆̚ė̛̘̘̈̐n̘̂̀̒̕̕d̗̅̂̋̅́ê̗̜̜̜̕r̟̋̄̐̅̂i̛̔̌̒̂̕t̛̗̓̎̀̎ ̙̗̀̉̂̚ȉ̟̗̐̓̚n̙̂̍̏̓̉ ̙̘̊̋̍̕v̜̖̀̎̆̐ő̜̆̉̃̎l̑̋̒̉̔̆ư̙̓̓́̚p̝̘̖̎̏̒t̛̘̝̞̂̓ȁ̘̆̔́̊t̖̝̉̒̐̎e̞̟̋̀̅̄ ̆̌̃̀̑̔v̝̘̝̍̀̇ȅ̝̊̄̓̕l̞̝̑̔̂̋ĭ̝̄̅̆̍t̝̜̉̂̈̇
+ ē̟̊̇̕̚s̖̘̘̒̄̑s̛̘̀̊̆̇e̛̝̘̒̏̚ ̉̅̑̂̐̎c̛̟̙̎̋̓i̜̇̒̏̆̆l̟̄́̆̊̌l̍̊̋̃̆̌ủ̗̙̒̔̚m̛̘̘̖̅̍ ̖̙̈̎̂̕d̞̟̏̋̈̔ơ̟̝̌̃̄l̗̙̝̂̉̒õ̒̃̄̄̚ŕ̗̏̏̊̍ê̞̝̞̋̈ ̜̔̒̎̃̚e̞̟̞̒̃̄ư̖̏̄̑̃ ̛̗̜̄̓̎f̛̖̞̅̓̃ü̞̏̆̋̕g̜̝̞̑̑̆i̛̘̐̐̅̚à̜̖̌̆̎t̙̙̎̉̂̍ ̋̔̈̎̎̉n̞̓́̔̊̕ư̘̅̋̔̚l̗̍̒̄̀̚l̞̗̘̙̓̍â̘̔̒̎̚ ̖̓̋̉̃̆p̛̛̘̋̌̀ä̙̔́̒̕r̟̟̖̋̐̋ì̗̙̎̓̓ȃ̔̋̑̚̕t̄́̎̓̂̋ư̏̈̂̑̃r̖̓̋̊̚̚.̒̆̑̆̊̎ ̘̜̍̐̂̚E̞̅̐̇́̂x̄́̈̌̉̕ć̘̃̉̃̕è̘̂̑̏̑p̝̘̑̂̌̆t̔̐̅̍̌̂ȇ̞̈̐̚̕ű̝̞̜́̚ŕ̗̝̉̆́
+ š̟́̔̏̀ȉ̝̟̝̏̅n̑̆̇̒̆̚t̝̒́̅̋̏ ̗̑̌̋̇̚ơ̙̗̟̆̅c̙̞̙̎̊̎c̘̟̍̔̊̊a̛̒̓̉́̐e̜̘̙̒̅̇ć̝̝̂̇̕ả̓̍̎̂̚t̗̗̗̟̒̃ ̘̒̓̐̇́c̟̞̉̐̓̄ȕ̙̗̅́̏p̛̍̋̈́̅i̖̓̒̍̈̄d̞̃̈̌̆̐a̛̗̝̎̋̉t̞̙̀̊̆̇a̛̙̒̆̉̚t̜̟̘̉̓̚ ̝̘̗̐̇̕n̛̘̑̏̂́ō̑̋̉̏́ň̞̊̆̄̃ ̙̙̙̜̄̏p̒̆̋̋̓̏r̖̖̅̉́̚ơ̜̆̑̈̚i̟̒̀̃̂̌d̛̏̃̍̋̚ë̖̞̙̗̓n̛̘̓̒̅̎t̟̗̙̊̆̚,̘̙̔̊̚̕ ̟̗̘̜̑̔s̜̝̍̀̓̌û̞̙̅̇́n̘̗̝̒̃̎t̗̅̀̅̊̈ ̗̖̅̅̀̄i̛̖̍̅̋̂n̙̝̓̓̎̚ ̞̋̅̋̃̚c̗̒̀̆̌̎ū̞̂̑̌̓ĺ̛̐̍̑́p̝̆̌̎̈̚a̖̙̒̅̈̌ ̝̝̜̂̈̀q̝̖̔̍̒̚ư̔̐̂̎̊ǐ̛̟̖̘̕
+ o̖̜̔̋̅̚f̛̊̀̉́̕f̏̉̀̔̃̃i̘̍̎̐̔̎c̙̅̑̂̐̅ȋ̛̜̀̒̚a̋̍̇̏̀̋ ̖̘̒̅̃̒d̗̘̓̈̇̋é̝́̎̒̄š̙̒̊̉̋e̖̓̐̀̍̕r̗̞̂̅̇̄ù̘̇̐̉̀n̐̑̀̄̍̐t̟̀̂̊̄̚ ̟̝̂̍̏́m̜̗̈̂̏̚ő̞̊̑̇̒l̘̑̏́̔̄l̛̛̇̃̋̊i̓̋̒̃̉̌t̛̗̜̏̀̋ ̙̟̒̂̌̐a̙̝̔̆̏̅n̝̙̙̗̆̅i̍̔́̊̃̕m̖̝̟̒̍̚ ̛̃̃̑̌́ǐ̘̉̔̅̚d̝̗̀̌̏̒ ̖̝̓̑̊̚ȇ̞̟̖̌̕š̙̙̈̔̀t̂̉̒̍̄̄ ̝̗̊̋̌̄l̛̞̜̙̘̔å̝̍̂̍̅b̜̆̇̈̉̌ǒ̜̙̎̃̆r̝̀̄̍́̕ư̋̊́̊̕m̜̗̒̐̕̚.̟̘̀̒̌̚]],
+ '\n'))
+
+ -- tests that we can handle overflow of the buffer
+ -- for redraw events (4096 bytes) gracefully
+ screen:expect{grid=[[
+ ^L̓̉̑̒̌̚ơ̗̌̒̄̀ŕ̈̈̎̐̕è̇̅̄̄̐m̖̟̟̅̄̚ ̛̓̑̆̇̍i̗̟̞̜̅̐p̗̞̜̉̆̕s̟̜̘̍̑̏ū̟̞̎̃̉ḿ̘̙́́̐ ̖̍̌̇̉̚d̞̄̃̒̉̎ò́̌̌̂̐l̞̀̄̆̌̚ȯ̖̞̋̀̐r̓̇̌̃̃̚ ̗̘̀̏̍́s̜̀̎̎̑̕i̟̗̐̄̄̚t̝̎̆̓̐̒ ̘̇̔̓̊̚ȃ̛̟̗̏̅m̜̟̙̞̈̓é̘̞̟̔̆t̝̂̂̈̑̔,̜̜̖̅̄̍ ̛̗̊̓̆̚c̟̍̆̍̈̔ȯ̖̖̝̑̀n̜̟̎̊̃̚s̟̏̇̎̒̚e̙̐̈̓̌̚c̙̍̈̏̅̕ť̇̄̇̆̓e̛̓̌̈̓̈t̟̍̀̉̆̅u̝̞̎̂̄̚r̘̀̅̈̅̐ ̝̞̓́̇̉ã̏̀̆̅̕d̛̆̐̉̆̋ȉ̞̟̍̃̚p̛̜̊̍̂̓ȋ̏̅̃̋̚ṥ̛̏̃̕č̛̞̝̀̂í̗̘̌́̎n̔̎́̒̂̕ǧ̗̜̋̇̂ ̛̜̔̄̎̃ê̛̔̆̇̕l̘̝̏̐̊̏ĩ̛̍̏̏̄t̟̐́̀̐̎,̙̘̍̆̉̐ ̋̂̏̄̌̅s̙̓̌̈́̇e̛̗̋̒̎̏d̜̗̊̍̊̚ |
+ ď̘̋̌̌̕ǒ̝̗̔̇̕ ̙̍́̄̄̉è̛̛̞̌̌i̜̖̐̈̆̚ȕ̇̈̓̃̓ŝ̛̞̙̉̋m̜̐̂̄̋̂ȯ̈̎̎̅̕d̜̙̓̔̋̑ ̞̗̄̂̂̚t̝̊́̃́̄e̛̘̜̞̓̑m̊̅̏̉̌̕p̛̈̂̇̀̐ỏ̙̘̈̉̔r̘̞̋̍̃̚ ̝̄̀̇̅̇ỉ̛̖̍̓̈n̛̛̝̎̕̕c̛̛̊̅́̐ĭ̗̓̀̍̐d̞̜̋̐̅̚i̟̙̇̄̊̄d̞̊̂̀̇̚ủ̝̉̑̃̕n̜̏̇̄̐̋ť̗̜̞̋̉ ̝̒̓̌̓̚ȕ̖̙̀̚̕t̖̘̎̉̂̌ ̛̝̄̍̌̂l̛̟̝̃̑̋á̛̝̝̔̅b̝̙̜̗̅̒ơ̖̌̒̄̆r̒̇̓̎̈̄e̛̛̖̅̏̇ ̖̗̜̝̃́e̛̛̘̅̔̌ẗ̛̙̗̐̕ ̖̟̇̋̌̈d̞̙̀̉̑̕ŏ̝̂́̐̑l̞̟̗̓̓̀ơ̘̎̃̄̂r̗̗̖̔̆̍ẻ̖̝̞̋̅ ̜̌̇̍̈̊m̈̉̇̄̒̀a̜̞̘̔̅̆g̗̖̈̃̈̉n̙̖̄̈̉̄â̛̝̜̄̃ ̛́̎̕̕̚ā̊́́̆̌l̟̙̞̃̒́i̖̇̎̃̀̋q̟̇̒̆́̊ủ́̌̇̑̚ã̛̘̉̐̚.̛́̏̐̍̊ |
+ U̝̙̎̈̐̆t̜̍̌̀̔̏ ̞̉̍̇̈̃e̟̟̊̄̕̕n̝̜̒̓̆̕i̖̒̌̅̇̚m̞̊̃̔̊̂ ̛̜̊̎̄̂a̘̜̋̒̚̚d̟̊̎̇̂̍ ̜̖̏̑̉̕m̜̒̎̅̄̚i̝̖̓̂̍̕n̙̉̒̑̀̔ỉ̖̝̌̒́m̛̖̘̅̆̎ ̖̉̎̒̌̕v̖̞̀̔́̎e̖̙̗̒̎̉n̛̗̝̎̀̂ȉ̞̗̒̕̚ȧ̟̜̝̅̚m̆̉̐̐̇̈,̏̐̎́̍́ ̜̞̙̘̏̆q̙̖̙̅̓̂ủ̇́̀̔̚í̙̟̟̏̐s̖̝̍̏̂̇ ̛̘̋̈̕̕ń̛̞̜̜̎o̗̜̔̔̈̆s̞̘̘̄̒̋t̛̅̋́̔̈ȓ̓̒́̇̅ủ̜̄̃̒̍d̙̝̘̊̏̚ ̛̟̞̄́̔e̛̗̝̍̃̀x̞̖̃̄̂̅e̖̅̇̐̔̃r̗̞̖̔̎̚c̘̜̖̆̊̏ï̙̝̙̂̕t̖̏́̓̋̂ă̖̄̆̑̒t̜̟̍̉̑̏i̛̞̞̘̒̑ǒ̜̆̅̃̉ṅ̖̜̒̎̚ |
+ u̗̞̓̔̈̏ĺ̟̝́̎̚l̛̜̅̌̎̆a̒̑̆̔̇̃m̜̗̈̊̎̚ċ̘̋̇̂̚ơ̟̖̊́̕ ̖̟̍̉̏̚l̙̔̓̀̅̏ä̞̗̘̙̅ḃ̟̎̄̃̕o̞̎̓̓̓̚r̗̜̊̓̈̒ï̗̜̃̃̅s̀̒̌̂̎̂ ̖̗̗̋̎̐n̝̟̝̘̄̚i̜̒̀̒̐̕s̘̘̄̊̃̀ī̘̜̏̌̕ ̗̖̞̐̈̒ư̙̞̄́̌t̟̘̖̙̊̚ ̌̅̋̆̚̚ä̇̊̇̕̕l̝̞̘̋̔̅i̍̋́̆̑̈q̛̆̐̈̐̚ư̏̆̊́̚î̜̝̑́̊p̗̓̅̑̆̏ ̆́̓̔̋̋e̟̊̋̏̓̚x̗̍̑̊̎̈ ̟̞̆̄̂̍ë̄̎̄̃̅a̛̜̅́̃̈ ̔̋̀̎̐̀c̖̖̍̀̒̂ơ̛̙̖̄̒m̘̔̍̏̆̕ḿ̖̙̝̏̂ȍ̓̋̈̀̕d̆̂̊̅̓̚o̖̔̌̑̚̕ ̙̆́̔̊̒c̖̘̖̀̄̍o̓̄̑̐̓̒ñ̞̒̎̈̚s̞̜̘̈̄̄e̙̊̀̇̌̋q̐̒̓́̔̃ư̗̟̔̔̚å̖̙̞̄̏t̛̙̟̒̇̏.̙̗̓̃̓̎ |
+ D̜̖̆̏̌̌ư̑̃̌̍̕i̝̊̊̊̊̄s̛̙̒́̌̇ ̛̃̔̄̆̌ă̘̔̅̅̀ú̟̟̟̃̃t̟̂̄̈̈̃e̘̅̌̒̂̆ ̖̟̐̉̉̌î̟̟̙̜̇r̛̙̞̗̄̌ú̗̗̃̌̎r̛̙̘̉̊̕e̒̐̔̃̓̋ ̊̊̍̋̑̉d̛̝̙̉̀̓o̘̜̐̐̓̐l̞̋̌̆̍́o̊̊̐̃̃̚ṙ̛̖̘̃̕ ̞̊̀̍̒̕ȉ́̑̐̇̅ǹ̜̗̜̞̏ ̛̜̐̄̄̚r̜̖̈̇̅̋ĕ̗̉̃̔̚p̟̝̀̓̔̆r̜̈̆̇̃̃e̘̔̔̏̎̓h̗̒̉̑̆̚ė̛̘̘̈̐n̘̂̀̒̕̕d̗̅̂̋̅́ê̗̜̜̜̕r̟̋̄̐̅̂i̛̔̌̒̂̕t̛̗̓̎̀̎ ̙̗̀̉̂̚ȉ̟̗̐̓̚n̙̂̍̏̓̉ ̙̘̊̋̍̕v̜̖̀̎̆̐ő̜̆̉̃̎l̑̋̒̉̔̆ư̙̓̓́̚p̝̘̖̎̏̒t̛̘̝̞̂̓ȁ̘̆̔́̊t̖̝̉̒̐̎e̞̟̋̀̅̄ ̆̌̃̀̑̔v̝̘̝̍̀̇ȅ̝̊̄̓̕l̞̝̑̔̂̋ĭ̝̄̅̆̍t̝̜̉̂̈̇ |
+ ē̟̊̇̕̚s̖̘̘̒̄̑s̛̘̀̊̆̇e̛̝̘̒̏̚ ̉̅̑̂̐̎c̛̟̙̎̋̓i̜̇̒̏̆̆l̟̄́̆̊̌l̍̊̋̃̆̌ủ̗̙̒̔̚m̛̘̘̖̅̍ ̖̙̈̎̂̕d̞̟̏̋̈̔ơ̟̝̌̃̄l̗̙̝̂̉̒õ̒̃̄̄̚ŕ̗̏̏̊̍ê̞̝̞̋̈ ̜̔̒̎̃̚e̞̟̞̒̃̄ư̖̏̄̑̃ ̛̗̜̄̓̎f̛̖̞̅̓̃ü̞̏̆̋̕g̜̝̞̑̑̆i̛̘̐̐̅̚à̜̖̌̆̎t̙̙̎̉̂̍ ̋̔̈̎̎̉n̞̓́̔̊̕ư̘̅̋̔̚l̗̍̒̄̀̚l̞̗̘̙̓̍â̘̔̒̎̚ ̖̓̋̉̃̆p̛̛̘̋̌̀ä̙̔́̒̕r̟̟̖̋̐̋ì̗̙̎̓̓ȃ̔̋̑̚̕t̄́̎̓̂̋ư̏̈̂̑̃r̖̓̋̊̚̚.̒̆̑̆̊̎ ̘̜̍̐̂̚E̞̅̐̇́̂x̄́̈̌̉̕ć̘̃̉̃̕è̘̂̑̏̑p̝̘̑̂̌̆t̔̐̅̍̌̂ȇ̞̈̐̚̕ű̝̞̜́̚ŕ̗̝̉̆́ |
+ š̟́̔̏̀ȉ̝̟̝̏̅n̑̆̇̒̆̚t̝̒́̅̋̏ ̗̑̌̋̇̚ơ̙̗̟̆̅c̙̞̙̎̊̎c̘̟̍̔̊̊a̛̒̓̉́̐e̜̘̙̒̅̇ć̝̝̂̇̕ả̓̍̎̂̚t̗̗̗̟̒̃ ̘̒̓̐̇́c̟̞̉̐̓̄ȕ̙̗̅́̏p̛̍̋̈́̅i̖̓̒̍̈̄d̞̃̈̌̆̐a̛̗̝̎̋̉t̞̙̀̊̆̇a̛̙̒̆̉̚t̜̟̘̉̓̚ ̝̘̗̐̇̕n̛̘̑̏̂́ō̑̋̉̏́ň̞̊̆̄̃ ̙̙̙̜̄̏p̒̆̋̋̓̏r̖̖̅̉́̚ơ̜̆̑̈̚i̟̒̀̃̂̌d̛̏̃̍̋̚ë̖̞̙̗̓n̛̘̓̒̅̎t̟̗̙̊̆̚,̘̙̔̊̚̕ ̟̗̘̜̑̔s̜̝̍̀̓̌û̞̙̅̇́n̘̗̝̒̃̎t̗̅̀̅̊̈ ̗̖̅̅̀̄i̛̖̍̅̋̂n̙̝̓̓̎̚ ̞̋̅̋̃̚c̗̒̀̆̌̎ū̞̂̑̌̓ĺ̛̐̍̑́p̝̆̌̎̈̚a̖̙̒̅̈̌ ̝̝̜̂̈̀q̝̖̔̍̒̚ư̔̐̂̎̊ǐ̛̟̖̘̕ |
+ o̖̜̔̋̅̚f̛̊̀̉́̕f̏̉̀̔̃̃i̘̍̎̐̔̎c̙̅̑̂̐̅ȋ̛̜̀̒̚a̋̍̇̏̀̋ ̖̘̒̅̃̒d̗̘̓̈̇̋é̝́̎̒̄š̙̒̊̉̋e̖̓̐̀̍̕r̗̞̂̅̇̄ù̘̇̐̉̀n̐̑̀̄̍̐t̟̀̂̊̄̚ ̟̝̂̍̏́m̜̗̈̂̏̚ő̞̊̑̇̒l̘̑̏́̔̄l̛̛̇̃̋̊i̓̋̒̃̉̌t̛̗̜̏̀̋ ̙̟̒̂̌̐a̙̝̔̆̏̅n̝̙̙̗̆̅i̍̔́̊̃̕m̖̝̟̒̍̚ ̛̃̃̑̌́ǐ̘̉̔̅̚d̝̗̀̌̏̒ ̖̝̓̑̊̚ȇ̞̟̖̌̕š̙̙̈̔̀t̂̉̒̍̄̄ ̝̗̊̋̌̄l̛̞̜̙̘̔å̝̍̂̍̅b̜̆̇̈̉̌ǒ̜̙̎̃̆r̝̀̄̍́̕ư̋̊́̊̕m̜̗̒̐̕̚.̟̘̀̒̌̚ |
+ {1:~ }|
+ |
+ ]]}
+ end)
end)
describe('multibyte rendering: statusline', function()
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 4e5e9c3a71..b30aa67fd3 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -77,18 +77,18 @@ describe('ext_multigrid', function()
command('vsplit')
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -129,18 +129,18 @@ describe('ext_multigrid', function()
command('split')
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}{11:[No Name] }|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│{11:[No Name] }|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{12:[No Name] [No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -300,12 +300,12 @@ describe('ext_multigrid', function()
command('vsp')
screen:expect{grid=[[
## grid 1
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
{11:[No Name] }{12:[No Name] [No Name] }|
[2:-----------------------------------------------------]|
[2:-----------------------------------------------------]|
@@ -347,12 +347,12 @@ describe('ext_multigrid', function()
insert('hello')
screen:expect{grid=[[
## grid 1
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
- [6:--------------------]{12:│}[5:----------------]{12:│}[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
+ [6:--------------------]│[5:----------------]│[4:---------------]|
{11:[No Name] [+] }{12:[No Name] [+] [No Name] [+] }|
[2:-----------------------------------------------------]|
[2:-----------------------------------------------------]|
@@ -467,18 +467,18 @@ describe('ext_multigrid', function()
command('vsp')
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -516,18 +516,18 @@ describe('ext_multigrid', function()
command('vertical resize 10')
screen:expect{grid=[[
## grid 1
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
- [4:----------]{12:│}[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
+ [4:----------]│[2:------------------------------------------]|
{11:<No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -565,18 +565,18 @@ describe('ext_multigrid', function()
command('sp')
screen:expect{grid=[[
## grid 1
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- {11:[No Name] }{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ {11:[No Name] }│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{12:[No Name] [No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -611,18 +611,18 @@ describe('ext_multigrid', function()
insert('hello')
screen:expect{grid=[[
## grid 1
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- {11:[No Name] [+] }{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ {11:[No Name] [+] }│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{12:[No Name] [+] [No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -659,18 +659,18 @@ describe('ext_multigrid', function()
command('vsp')
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -1056,12 +1056,12 @@ describe('ext_multigrid', function()
command('vsp')
screen:expect{grid=[[
## grid 1
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[2:-----------------------------------------------------]|
[2:-----------------------------------------------------]|
@@ -1097,12 +1097,12 @@ describe('ext_multigrid', function()
feed(":echoerr 'very' | echoerr 'much' | echoerr 'fail'<cr>")
screen:expect{grid=[[
## grid 1
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[2:-----------------------------------------------------]|
[2:-----------------------------------------------------]|
@@ -1141,12 +1141,12 @@ describe('ext_multigrid', function()
feed('<cr>')
screen:expect{grid=[[
## grid 1
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[2:-----------------------------------------------------]|
[2:-----------------------------------------------------]|
@@ -1242,12 +1242,12 @@ describe('ext_multigrid', function()
feed("<c-c>")
screen:expect{grid=[[
## grid 1
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
- [5:--------------------------]{12:│}[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
+ [5:--------------------------]│[4:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[2:-----------------------------------------------------]|
[2:-----------------------------------------------------]|
@@ -1285,18 +1285,18 @@ describe('ext_multigrid', function()
command('vsp')
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -1453,17 +1453,17 @@ describe('ext_multigrid', function()
screen:expect{grid=[[
## grid 1
{7: }{18:2}{7: [No Name] }{16: }{17:2}{16: [No Name] }{12: }{16:X}|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -1637,18 +1637,18 @@ describe('ext_multigrid', function()
command('tabclose')
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{11:[No Name] }{12:[No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -1915,7 +1915,7 @@ describe('ext_multigrid', function()
{1:~ }|
]]}
- meths.input_mouse('left', 'press', '', 1,6, 20)
+ meths.input_mouse('left', 'press', '', 1, 6, 20)
-- TODO(bfredl): "batching" input_mouse is formally not supported yet.
-- Normally it should work fine in async context when nvim is not blocked,
-- but add a poke_eventloop be sure.
@@ -1960,13 +1960,13 @@ describe('ext_multigrid', function()
[4:-----------------------------------------------------]|
[4:-----------------------------------------------------]|
{12:[No Name] [+] }|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
- [5:--------------------------]{12:│}[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
+ [5:--------------------------]│[2:--------------------------]|
{11:[No Name] [+] }{12:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -2002,13 +2002,13 @@ describe('ext_multigrid', function()
[4:-----------------------------------------------------]|
[4:-----------------------------------------------------]|
{12:[No Name] [+] }|
- [5:------------------------------]{12:│}[2:----------------------]|
- [5:------------------------------]{12:│}[2:----------------------]|
- [5:------------------------------]{12:│}[2:----------------------]|
- [5:------------------------------]{12:│}[2:----------------------]|
- [5:------------------------------]{12:│}[2:----------------------]|
- [5:------------------------------]{12:│}[2:----------------------]|
- [5:------------------------------]{12:│}[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
+ [5:------------------------------]│[2:----------------------]|
{11:[No Name] [+] }{12:[No Name] [+] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -2049,18 +2049,18 @@ describe('ext_multigrid', function()
screen:expect{grid=[[
## grid 1
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}[5:--------------------------]|
- [4:--------------------------]{12:│}{11:[No Name] [+] }|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
- [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│[5:--------------------------]|
+ [4:--------------------------]│{11:[No Name] [+] }|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
+ [4:--------------------------]│[2:--------------------------]|
{12:[No Name] [No Name] }|
[3:-----------------------------------------------------]|
## grid 2
@@ -2092,7 +2092,6 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
]]}
-
end)
it('has viewport information', function()
@@ -2369,4 +2368,223 @@ describe('ext_multigrid', function()
[2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11},
}}
end)
+
+ it('with winbar', function()
+ command 'split'
+ command 'setlocal winbar=very\\ bar'
+ screen:expect{grid=[[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:very bar }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ }}
+ end)
+
+ it('with winbar dragging statusline with mouse works correctly', function()
+ meths.set_option('winbar', 'Set Up The Bars')
+ command('split')
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 6, 20)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 7, 20)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ meths.input_mouse('left', 'drag', '', 1, 4, 20)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 12, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 10, 10)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ [3:-----------------------------------------------------]|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ |
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]])
+ eq(3, meths.get_option('cmdheight'))
+
+ meths.input_mouse('left', 'drag', '', 1, 12, 10)
+ screen:expect([[
+ ## grid 1
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ [4:-----------------------------------------------------]|
+ {11:[No Name] }|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ [2:-----------------------------------------------------]|
+ {12:[No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ {7:Set Up The Bars }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {7:Set Up The Bars }|
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ ]])
+ eq(1, meths.get_option('cmdheight'))
+ end)
end)
diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua
index 2f113f6ac6..c2b0bcdb64 100644
--- a/test/functional/ui/options_spec.lua
+++ b/test/functional/ui/options_spec.lua
@@ -4,6 +4,7 @@ local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
local shallowcopy = helpers.shallowcopy
+local eval = helpers.eval
describe('UI receives option updates', function()
local screen
@@ -62,17 +63,18 @@ describe('UI receives option updates', function()
end
screen:attach()
screen:expect(function()
- eq({'mouse_off'}, evs)
+ eq({'mouse_on'}, evs)
end)
- command("set mouse=nvi")
+ command("set mouse=")
+ command("set mouse&")
screen:expect(function()
- eq({'mouse_off','mouse_on'}, evs)
+ eq({'mouse_on','mouse_off', 'mouse_on'}, evs)
end)
screen:detach()
- eq({'mouse_off','mouse_on'}, evs)
+ eq({'mouse_on','mouse_off', 'mouse_on'}, evs)
screen:attach()
screen:expect(function()
- eq({'mouse_off','mouse_on','mouse_on'}, evs)
+ eq({'mouse_on','mouse_off','mouse_on', 'mouse_on'}, evs)
end)
end)
@@ -86,6 +88,12 @@ describe('UI receives option updates', function()
eq(expected, screen.options)
end)
+ command("set pumblend=-1")
+ expected.pumblend = 0
+ screen:expect(function()
+ eq(expected, screen.options)
+ end)
+
command("set guifont=Comic\\ Sans")
expected.guifont = "Comic Sans"
screen:expect(function()
@@ -168,3 +176,42 @@ describe('UI receives option updates', function()
it('from startup options with --headless', function() startup_test(true) end)
it('from startup options with --embed', function() startup_test(false) end)
end)
+
+describe('UI can set terminal option', function()
+ local screen
+ before_each(function()
+ -- by default we implicity "--cmd 'set bg=light'" which ruins everything
+ clear{args_rm={'--cmd'}}
+ screen = Screen.new(20,5)
+ end)
+
+ it('term_background', function()
+ eq('dark', eval '&background')
+
+ screen:attach {term_background='light'}
+ eq('light', eval '&background')
+ end)
+
+ it("term_background but not if 'background' already set by user", function()
+ eq('dark', eval '&background')
+ command 'set background=dark'
+
+ screen:attach {term_background='light'}
+
+ eq('dark', eval '&background')
+ end)
+
+ it('term_name', function()
+ eq('nvim', eval '&term')
+
+ screen:attach {term_name='xterm'}
+ eq('xterm', eval '&term')
+ end)
+
+ it('term_colors', function()
+ eq('256', eval '&t_Co')
+
+ screen:attach {term_colors=8}
+ eq('8', eval '&t_Co')
+ end)
+end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 50e5dfac84..71c6410013 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -9,6 +9,7 @@ local feed_command = helpers.feed_command
local iswin = helpers.iswin
local clear = helpers.clear
local command = helpers.command
+local testprg = helpers.testprg
local nvim_dir = helpers.nvim_dir
local has_powershell = helpers.has_powershell
local set_shell_powershell = helpers.set_shell_powershell
@@ -54,7 +55,7 @@ describe("shell command :!", function()
if 'openbsd' == helpers.uname() then
pending('FIXME #10804')
end
- child_session.feed_data(":!"..nvim_dir.."/shell-test REP 30001 foo\n")
+ child_session.feed_data((":!%s REP 30001 foo\n"):format(testprg('shell-test')))
-- If we observe any line starting with a dot, then throttling occurred.
-- Avoid false failure on slow systems.
@@ -207,12 +208,7 @@ describe("shell command :!", function()
it('handles multibyte sequences split over buffer boundaries', function()
command('cd '..nvim_dir)
- local cmd
- if iswin() then
- cmd = '!shell-test UTF-8 '
- else
- cmd = '!./shell-test UTF-8'
- end
+ local cmd = iswin() and '!shell-test UTF-8 ' or '!./shell-test UTF-8'
feed_command(cmd)
-- Note: only the first example of split composed char works
screen:expect([[
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 4fc5c389e5..7b0005bcf1 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -10,6 +10,8 @@ local funcs = helpers.funcs
local get_pathsep = helpers.get_pathsep
local eq = helpers.eq
local pcall_err = helpers.pcall_err
+local exec_lua = helpers.exec_lua
+local exec = helpers.exec
describe('ui/ext_popupmenu', function()
local screen
@@ -25,6 +27,7 @@ describe('ui/ext_popupmenu', function()
[5] = {bold = true, foreground = Screen.colors.SeaGreen},
[6] = {background = Screen.colors.WebGray},
[7] = {background = Screen.colors.LightMagenta},
+ [8] = {foreground = Screen.colors.Red},
})
source([[
function! TestComplete() abort
@@ -369,6 +372,111 @@ describe('ui/ext_popupmenu', function()
{1:~ }|
{2:-- INSERT --} |
]])
+
+ command('iunmap <f1>')
+ command('iunmap <f2>')
+ command('iunmap <f3>')
+ exec_lua([[
+ vim.keymap.set('i', '<f1>', function() vim.api.nvim_select_popupmenu_item(2, true, false, {}) end)
+ vim.keymap.set('i', '<f2>', function() vim.api.nvim_select_popupmenu_item(-1, false, false, {}) end)
+ vim.keymap.set('i', '<f3>', function() vim.api.nvim_select_popupmenu_item(1, false, true, {}) end)
+ ]])
+ feed('<C-r>=TestComplete()<CR>')
+ screen:expect([[
+ |
+ foo^ |
+ {6:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {7:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f1>')
+ screen:expect([[
+ |
+ spam^ |
+ {7:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {6:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f2>')
+ screen:expect([[
+ |
+ spam^ |
+ {7:fo x the foo }{1: }|
+ {7:bar }{1: }|
+ {7:spam }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<f3>')
+ screen:expect([[
+ |
+ bar^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ feed('<esc>ddiaa bb cc<cr>')
+ feed('<c-x><c-n>')
+ screen:expect([[
+ aa bb cc |
+ aa^ |
+ {6:aa }{1: }|
+ {7:bb }{1: }|
+ {7:cc }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- Keyword Local completion (^N^P) }{5:match 1 of 3} |
+ ]])
+
+ feed('<f1>')
+ screen:expect([[
+ aa bb cc |
+ cc^ |
+ {7:aa }{1: }|
+ {7:bb }{1: }|
+ {6:cc }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- Keyword Local completion (^N^P) }{5:match 3 of 3} |
+ ]])
+
+ feed('<f2>')
+ screen:expect([[
+ aa bb cc |
+ cc^ |
+ {7:aa }{1: }|
+ {7:bb }{1: }|
+ {7:cc }{1: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- Keyword Local completion (^N^P) }{8:Back at original} |
+ ]])
+
+ feed('<f3>')
+ screen:expect([[
+ aa bb cc |
+ bb^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
end)
local function source_complete_month()
@@ -846,72 +954,72 @@ describe('builtin popupmenu', function()
insert('aaa aab aac\n')
feed(':vsplit<cr>')
screen:expect([[
- aaa aab aac {3:│}aaa aab aac|
- ^ {3:│} |
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
+ aaa aab aac │aaa aab aac|
+ ^ │ |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
{4:[No Name] [+] }{3:<Name] [+] }|
:vsplit |
]])
feed('ibbb a<c-x><c-n>')
screen:expect([[
- aaa aab aac {3:│}aaa aab aac|
- bbb aaa^ {3:│}bbb aaa |
- {1:~ }{s: aaa }{1: }{3:│}{1:~ }|
- {1:~ }{n: aab }{1: }{3:│}{1:~ }|
- {1:~ }{n: aac }{1: }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
+ aaa aab aac │aaa aab aac|
+ bbb aaa^ │bbb aaa |
+ {1:~ }{s: aaa }{1: }│{1:~ }|
+ {1:~ }{n: aab }{1: }│{1:~ }|
+ {1:~ }{n: aac }{1: }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
{4:[No Name] [+] }{3:<Name] [+] }|
{2:-- }{5:match 1 of 3} |
]])
feed('<esc><c-w><c-w>oc a<c-x><c-n>')
screen:expect([[
- aaa aab aac{3:│}aaa aab aac |
- bbb aaa {3:│}bbb aaa |
- c aaa {3:│}c aaa^ |
- {1:~ }{3:│}{1:~}{s: aaa }{1: }|
- {1:~ }{3:│}{1:~}{n: aab }{1: }|
- {1:~ }{3:│}{1:~}{n: aac }{1: }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
- {1:~ }{3:│}{1:~ }|
+ aaa aab aac│aaa aab aac |
+ bbb aaa │bbb aaa |
+ c aaa │c aaa^ |
+ {1:~ }│{1:~}{s: aaa }{1: }|
+ {1:~ }│{1:~}{n: aab }{1: }|
+ {1:~ }│{1:~}{n: aac }{1: }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
{3:<Name] [+] }{4:[No Name] [+] }|
{2:-- }{5:match 1 of 3} |
]])
@@ -1845,7 +1953,7 @@ describe('builtin popupmenu', function()
]])
end)
- it('wildoptions=pum with scrolled mesages ', function()
+ it('wildoptions=pum with scrolled messages ', function()
screen:try_resize(40,10)
command('set wildmenu')
command('set wildoptions=pum')
@@ -2084,7 +2192,7 @@ describe('builtin popupmenu', function()
{20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
]])
- -- can disable blending for indiviual attribute. For instance current
+ -- can disable blending for individual attribute. For instance current
-- selected item. (also tests that `hi Pmenu*` take immediate effect)
command('hi PMenuSel blend=0')
screen:expect([[
@@ -2252,6 +2360,103 @@ describe('builtin popupmenu', function()
{2:-- INSERT --} |
]])
end)
+
+ it('supports mousemodel=popup', function()
+ screen:try_resize(32, 6)
+ exec([[
+ call setline(1, 'popup menu test')
+ set mouse=a mousemodel=popup
+
+ aunmenu PopUp
+ menu PopUp.foo :let g:menustr = 'foo'<CR>
+ menu PopUp.bar :let g:menustr = 'bar'<CR>
+ menu PopUp.baz :let g:menustr = 'baz'<CR>
+ ]])
+ meths.input_mouse('right', 'press', '', 0, 0, 4)
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: baz }{1: }|
+ {1:~ }|
+ |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{s: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: baz }{1: }|
+ {1:~ }|
+ |
+ ]])
+ feed('<Down>')
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{s: bar }{1: }|
+ {1:~ }{n: baz }{1: }|
+ {1:~ }|
+ |
+ ]])
+ feed('<CR>')
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :let g:menustr = 'bar' |
+ ]])
+ eq('bar', meths.get_var('menustr'))
+ meths.input_mouse('right', 'press', '', 0, 1, 20)
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: baz }{1: }|
+ :let g:menustr = 'bar' |
+ ]])
+ meths.input_mouse('left', 'press', '', 0, 4, 22)
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :let g:menustr = 'baz' |
+ ]])
+ eq('baz', meths.get_var('menustr'))
+ meths.input_mouse('right', 'press', '', 0, 0, 4)
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{n: baz }{1: }|
+ {1:~ }|
+ :let g:menustr = 'baz' |
+ ]])
+ meths.input_mouse('right', 'drag', '', 0, 3, 6)
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }{n: foo }{1: }|
+ {1:~ }{n: bar }{1: }|
+ {1:~ }{s: baz }{1: }|
+ {1:~ }|
+ :let g:menustr = 'baz' |
+ ]])
+ meths.input_mouse('right', 'release', '', 0, 1, 6)
+ screen:expect([[
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :let g:menustr = 'foo' |
+ ]])
+ eq('foo', meths.get_var('menustr'))
+ end)
end)
describe('builtin popupmenu with ui/ext_multigrid', function()
@@ -2343,4 +2548,121 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
end)
+
+ it('supports mousemodel=popup', function()
+ screen:try_resize(32, 6)
+ exec([[
+ call setline(1, 'popup menu test')
+ set mouse=a mousemodel=popup
+
+ aunmenu PopUp
+ menu PopUp.foo :let g:menustr = 'foo'<CR>
+ menu PopUp.bar :let g:menustr = 'bar'<CR>
+ menu PopUp.baz :let g:menustr = 'baz'<CR>
+ ]])
+ meths.input_mouse('right', 'press', '', 2, 1, 20)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {n: foo }|
+ {n: bar }|
+ {n: baz }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 2, 19, false, 100}}})
+ meths.input_mouse('left', 'press', '', 4, 2, 2)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'baz' |
+ ]]})
+ eq('baz', meths.get_var('menustr'))
+ meths.input_mouse('right', 'press', '', 2, 0, 4)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'baz' |
+ ## grid 4
+ {n: foo }|
+ {n: bar }|
+ {n: baz }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+ meths.input_mouse('right', 'drag', '', 2, 3, 6)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'baz' |
+ ## grid 4
+ {n: foo }|
+ {n: bar }|
+ {s: baz }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+ meths.input_mouse('right', 'release', '', 2, 1, 6)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^popup menu test |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ :let g:menustr = 'foo' |
+ ]]})
+ eq('foo', meths.get_var('menustr'))
+ end)
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 61f19c3794..ea98705394 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -75,7 +75,7 @@ local busted = require('busted')
local deepcopy = helpers.deepcopy
local shallowcopy = helpers.shallowcopy
local concat_tables = helpers.concat_tables
-local request, run_session = helpers.request, helpers.run_session
+local run_session = helpers.run_session
local eq = helpers.eq
local dedent = helpers.dedent
local get_session = helpers.get_session
@@ -90,8 +90,6 @@ end
local Screen = {}
Screen.__index = Screen
-local debug_screen
-
local default_timeout_factor = 1
if os.getenv('VALGRIND') then
default_timeout_factor = default_timeout_factor * 3
@@ -123,18 +121,6 @@ do
Screen.colornames = colornames
end
-function Screen.debug(command)
- if not command then
- command = 'pynvim -n -c '
- end
- command = command .. request('vim_eval', '$NVIM_LISTEN_ADDRESS')
- if debug_screen then
- debug_screen:close()
- end
- debug_screen = io.popen(command, 'r')
- debug_screen:read()
-end
-
function Screen.new(width, height)
if not width then
width = 53
@@ -179,6 +165,7 @@ function Screen.new(width, height)
_width = width,
_height = height,
_grids = {},
+ _grid_win_extmarks = {},
_cursor = {
grid = 1, row = 1, col = 1
},
@@ -255,7 +242,7 @@ end
-- canonical order of ext keys, used to generate asserts
local ext_keys = {
'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos',
- 'messages', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport'
+ 'messages', 'msg_history', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport'
}
-- Asserts that the screen state eventually matches an expected state.
@@ -278,6 +265,8 @@ local ext_keys = {
-- attributes in the final state are an error.
-- Use screen:set_default_attr_ids() to define attributes for many
-- expect() calls.
+-- extmarks: Expected win_extmarks accumulated for the grids. For each grid,
+-- the win_extmark messages are accumulated into an array.
-- condition: Function asserting some arbitrary condition. Return value is
-- ignored, throw an error (use eq() or similar) to signal failure.
-- any: Lua pattern string expected to match a screen line. NB: the
@@ -320,7 +309,7 @@ function Screen:expect(expected, attr_ids, ...)
assert(not (attr_ids ~= nil))
local is_key = {grid=true, attr_ids=true, condition=true, mouse_enabled=true,
any=true, mode=true, unchanged=true, intermediate=true,
- reset=true, timeout=true, request_cb=true, hl_groups=true}
+ reset=true, timeout=true, request_cb=true, hl_groups=true, extmarks=true}
for _, v in ipairs(ext_keys) do
is_key[v] = true
end
@@ -394,7 +383,7 @@ function Screen:expect(expected, attr_ids, ...)
for i, row in ipairs(expected_rows) do
msg_expected_rows[i] = row
local m = (row ~= actual_rows[i] and row:match('{MATCH:(.*)}') or nil)
- if row ~= actual_rows[i] and (not m or not actual_rows[i]:match(m)) then
+ if row ~= actual_rows[i] and (not m or not (actual_rows[i] and actual_rows[i]:match(m))) then
msg_expected_rows[i] = '*' .. msg_expected_rows[i]
if i <= #actual_rows then
actual_rows[i] = '*' .. actual_rows[i]
@@ -459,6 +448,25 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
end
+
+ if expected.extmarks ~= nil then
+ for gridid, expected_marks in pairs(expected.extmarks) do
+ local stored_marks = self._grid_win_extmarks[gridid]
+ if stored_marks == nil then
+ return 'no win_extmark for grid '..tostring(gridid)
+ end
+ local status, res = pcall(eq, expected_marks, stored_marks, "extmarks for grid "..tostring(gridid))
+ if not status then
+ return tostring(res)
+ end
+ end
+ for gridid, _ in pairs(self._grid_win_extmarks) do
+ local expected_marks = expected.extmarks[gridid]
+ if expected_marks == nil then
+ return 'unexpected win_extmark for grid '..tostring(gridid)
+ end
+ end
+ end
end, expected)
end
@@ -544,7 +552,7 @@ function Screen:_wait(check, flags)
elseif not checked then
err = check()
if not err and flags.unchanged then
- -- expecting NO screen change: use a shorter timout
+ -- expecting NO screen change: use a shorter timeout
success_seen = true
end
end
@@ -576,16 +584,16 @@ to the test if they make sense.
print([[
warning: Screen changes were received after the expected state. This indicates
-indeterminism in the test. Try adding screen:expect(...) (or wait()) between
-asynchronous (feed(), nvim_input()) and synchronous API calls.
+indeterminism in the test. Try adding screen:expect(...) (or poke_eventloop())
+between asynchronous (feed(), nvim_input()) and synchronous API calls.
- Use screen:redraw_debug() to investigate; it may find relevant intermediate
states that should be added to the test to make it more robust.
- If the purpose of the test is to assert state after some user input sent
with feed(), adding screen:expect() before the feed() will help to ensure
the input is sent when Nvim is in a predictable state. This is preferable
- to wait(), for being closer to real user interaction.
- - wait() can trigger redraws and consequently generate more indeterminism.
- Try removing wait().
+ to poke_eventloop(), for being closer to real user interaction.
+ - poke_eventloop() can trigger redraws and thus generate more indeterminism.
+ Try removing poke_eventloop().
]])
did_warn = true
end
@@ -703,6 +711,7 @@ function Screen:_reset()
self.cmdline_block = {}
self.wildmenu_items = nil
self.wildmenu_pos = nil
+ self._grid_win_extmarks = {}
end
function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
@@ -803,6 +812,13 @@ function Screen:_handle_win_close(grid)
self.float_pos[grid] = nil
end
+function Screen:_handle_win_extmark(grid, ...)
+ if self._grid_win_extmarks[grid] == nil then
+ self._grid_win_extmarks[grid] = {}
+ end
+ table.insert(self._grid_win_extmarks[grid], {...})
+end
+
function Screen:_handle_busy_start()
self._busy = true
end
@@ -1067,6 +1083,10 @@ function Screen:_handle_msg_history_show(entries)
self.msg_history = entries
end
+function Screen:_handle_msg_history_clear()
+ self.msg_history = {}
+end
+
function Screen:_clear_block(grid, top, bot, left, right)
for i = top, bot do
self:_clear_row_section(grid, i, left, right)
@@ -1155,7 +1175,7 @@ function Screen:_extstate_repr(attr_state)
local msg_history = {}
for i, entry in ipairs(self.msg_history) do
- messages[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
+ msg_history[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
end
local win_viewport = (next(self.win_viewport) and self.win_viewport) or nil
@@ -1560,9 +1580,10 @@ end
function Screen:_equal_attrs(a, b)
return a.bold == b.bold and a.standout == b.standout and
a.underline == b.underline and a.undercurl == b.undercurl and
- a.italic == b.italic and a.reverse == b.reverse and
- a.foreground == b.foreground and a.background == b.background and
- a.special == b.special and a.blend == b.blend and
+ a.underdouble == b.underdouble and a.underdotted == b.underdotted and
+ a.underdashed == b.underdashed and a.italic == b.italic and
+ a.reverse == b.reverse and a.foreground == b.foreground and
+ a.background == b.background and a.special == b.special and a.blend == b.blend and
a.strikethrough == b.strikethrough and
a.fg_indexed == b.fg_indexed and a.bg_indexed == b.bg_indexed
end
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 958e137f65..6c872e52d3 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -6,6 +6,7 @@ local insert = helpers.insert
local eq = helpers.eq
local eval = helpers.eval
local iswin = helpers.iswin
+local funcs, meths, exec_lua = helpers.funcs, helpers.meths, helpers.exec_lua
describe('screen', function()
local screen
@@ -127,14 +128,67 @@ local function screen_tests(linegrid)
end)
it('has correct default title with named file', function()
- local expected = (iswin() and 'myfile (C:\\mydir) - NVIM'
- or 'myfile (/mydir) - NVIM')
+ local expected = (iswin() and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
command('set title')
command(iswin() and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
screen:expect(function()
eq(expected, screen.title)
end)
end)
+
+ describe('is not changed by', function()
+ local file1 = iswin() and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
+ local file2 = iswin() and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
+ local expected = (iswin() and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
+ local buf2
+
+ before_each(function()
+ command('edit '..file1)
+ buf2 = funcs.bufadd(file2)
+ command('set title')
+ end)
+
+ it('calling setbufvar() to set an option in a hidden buffer from i_CTRL-R', function()
+ command([[inoremap <F2> <C-R>=setbufvar(]]..buf2..[[, '&autoindent', 1) ? '' : ''<CR>]])
+ feed('i<F2><Esc>')
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+
+ it('an RPC call to nvim_buf_set_option in a hidden buffer', function()
+ meths.buf_set_option(buf2, 'autoindent', true)
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+
+ it('a Lua callback calling nvim_buf_set_option in a hidden buffer', function()
+ exec_lua(string.format([[
+ vim.schedule(function()
+ vim.api.nvim_buf_set_option(%d, 'autoindent', true)
+ end)
+ ]], buf2))
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+
+ it('a Lua callback calling nvim_buf_call in a hidden buffer', function()
+ exec_lua(string.format([[
+ vim.schedule(function()
+ vim.api.nvim_buf_call(%d, function() end)
+ end)
+ ]], buf2))
+ command('redraw!')
+ screen:expect(function()
+ eq(expected, screen.title)
+ end)
+ end)
+ end)
end)
describe(':set icon', function()
@@ -272,12 +326,12 @@ local function screen_tests(linegrid)
command('vsp')
command('vsp')
screen:expect([[
- ^ {3:│} {3:│} |
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
+ ^ │ │ |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{1:[No Name] }{3:[No Name] [No Name] }|
|
{0:~ }|
@@ -289,12 +343,12 @@ local function screen_tests(linegrid)
]])
insert('hello')
screen:expect([[
- hell^o {3:│}hello {3:│}hello |
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
+ hell^o │hello │hello |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
hello |
{0:~ }|
@@ -315,12 +369,12 @@ local function screen_tests(linegrid)
command('vsp')
insert('hello')
screen:expect([[
- hell^o {3:│}hello {3:│}hello |
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
+ hell^o │hello │hello |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
hello |
{0:~ }|
@@ -352,12 +406,12 @@ local function screen_tests(linegrid)
command('tabprevious')
screen:expect([[
{2: }{6:4}{2:+ [No Name] }{4: + [No Name] }{3: }{4:X}|
- hell^o {3:│}hello {3:│}hello |
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
- {0:~ }{3:│}{0:~ }{3:│}{0:~ }|
+ hell^o │hello │hello |
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
+ {0:~ }│{0:~ }│{0:~ }|
{1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
hello |
{0:~ }|
@@ -466,36 +520,36 @@ local function screen_tests(linegrid)
command('vsplit')
screen:expect([[
- ^foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
+ ^foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
{1:[No Name] [+] }{3:[No Name] [+] }|
|
]])
feed('<PageDown>')
screen:expect([[
- ^foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- foo {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
- bar {3:│}foo |
+ ^foo │foo |
+ foo │foo |
+ foo │foo |
+ foo │foo |
+ bar │foo |
+ bar │foo |
+ bar │foo |
+ bar │foo |
+ bar │foo |
+ bar │foo |
+ bar │foo |
+ bar │foo |
{1:[No Name] [+] }{3:[No Name] [+] }|
|
]])
@@ -694,12 +748,12 @@ local function screen_tests(linegrid)
command('vsp')
command('vsp')
screen:expect([[
- and {3:│}and {3:│}and |
- clearing {3:│}clearing {3:│}clearing |
- in {3:│}in {3:│}in |
- split {3:│}split {3:│}split |
- windows {3:│}windows {3:│}windows |
- ^ {3:│} {3:│} |
+ and │and │and |
+ clearing │clearing │clearing |
+ in │in │in |
+ split │split │split |
+ windows │windows │windows |
+ ^ │ │ |
{1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
clearing |
in |
@@ -714,12 +768,12 @@ local function screen_tests(linegrid)
it('only affects the current scroll region', function()
feed('6k')
screen:expect([[
- ^scrolling {3:│}and {3:│}and |
- and {3:│}clearing {3:│}clearing |
- clearing {3:│}in {3:│}in |
- in {3:│}split {3:│}split |
- split {3:│}windows {3:│}windows |
- windows {3:│} {3:│} |
+ ^scrolling │and │and |
+ and │clearing │clearing |
+ clearing │in │in |
+ in │split │split |
+ split │windows │windows |
+ windows │ │ |
{1:[No Name] [+] }{3:[No Name] [+] [No Name] [+] }|
clearing |
in |
@@ -731,12 +785,12 @@ local function screen_tests(linegrid)
]])
feed('<c-w>l')
screen:expect([[
- scrolling {3:│}and {3:│}and |
- and {3:│}clearing {3:│}clearing |
- clearing {3:│}in {3:│}in |
- in {3:│}split {3:│}split |
- split {3:│}windows {3:│}windows |
- windows {3:│}^ {3:│} |
+ scrolling │and │and |
+ and │clearing │clearing |
+ clearing │in │in |
+ in │split │split |
+ split │windows │windows |
+ windows │^ │ |
{3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
@@ -748,12 +802,12 @@ local function screen_tests(linegrid)
]])
feed('gg')
screen:expect([[
- scrolling {3:│}^Inserting {3:│}and |
- and {3:│}text {3:│}clearing |
- clearing {3:│}with {3:│}in |
- in {3:│}many {3:│}split |
- split {3:│}lines {3:│}windows |
- windows {3:│}to {3:│} |
+ scrolling │^Inserting │and |
+ and │text │clearing |
+ clearing │with │in |
+ in │many │split |
+ split │lines │windows |
+ windows │to │ |
{3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
@@ -765,12 +819,12 @@ local function screen_tests(linegrid)
]])
feed('7j')
screen:expect([[
- scrolling {3:│}with {3:│}and |
- and {3:│}many {3:│}clearing |
- clearing {3:│}lines {3:│}in |
- in {3:│}to {3:│}split |
- split {3:│}test {3:│}windows |
- windows {3:│}^scrolling {3:│} |
+ scrolling │with │and |
+ and │many │clearing |
+ clearing │lines │in |
+ in │to │split |
+ split │test │windows |
+ windows │^scrolling │ |
{3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
@@ -782,12 +836,12 @@ local function screen_tests(linegrid)
]])
feed('2j')
screen:expect([[
- scrolling {3:│}lines {3:│}and |
- and {3:│}to {3:│}clearing |
- clearing {3:│}test {3:│}in |
- in {3:│}scrolling {3:│}split |
- split {3:│}and {3:│}windows |
- windows {3:│}^clearing {3:│} |
+ scrolling │lines │and |
+ and │to │clearing |
+ clearing │test │in |
+ in │scrolling │split |
+ split │and │windows |
+ windows │^clearing │ |
{3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
@@ -799,12 +853,12 @@ local function screen_tests(linegrid)
]])
feed('5k')
screen:expect([[
- scrolling {3:│}^lines {3:│}and |
- and {3:│}to {3:│}clearing |
- clearing {3:│}test {3:│}in |
- in {3:│}scrolling {3:│}split |
- split {3:│}and {3:│}windows |
- windows {3:│}clearing {3:│} |
+ scrolling │^lines │and |
+ and │to │clearing |
+ clearing │test │in |
+ in │scrolling │split |
+ split │and │windows |
+ windows │clearing │ |
{3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
@@ -816,12 +870,12 @@ local function screen_tests(linegrid)
]])
feed('k')
screen:expect([[
- scrolling {3:│}^many {3:│}and |
- and {3:│}lines {3:│}clearing |
- clearing {3:│}to {3:│}in |
- in {3:│}test {3:│}split |
- split {3:│}scrolling {3:│}windows |
- windows {3:│}and {3:│} |
+ scrolling │^many │and |
+ and │lines │clearing |
+ clearing │to │in |
+ in │test │split |
+ split │scrolling │windows |
+ windows │and │ |
{3:[No Name] [+] }{1:[No Name] [+] }{3:<Name] [+] }|
clearing |
in |
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 5540b3c2dc..c5c88323a2 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -5,7 +5,8 @@ local command = helpers.command
local feed_command = helpers.feed_command
local eq = helpers.eq
local eval = helpers.eval
-local nvim_dir = helpers.nvim_dir
+local funcs = helpers.funcs
+local testprg = helpers.testprg
describe('search highlighting', function()
local screen
@@ -43,7 +44,7 @@ describe('search highlighting', function()
insert("some text\nmore text")
feed_command('1,2fold')
feed("gg/text")
- screen:expect([[
+ screen:expect{grid=[[
{6:+-- 2 lines: some text·················}|
{1:~ }|
{1:~ }|
@@ -51,7 +52,9 @@ describe('search highlighting', function()
{1:~ }|
{1:~ }|
/text^ |
- ]])
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 9, linecount = 2};
+ }}
end)
it('works', function()
@@ -109,6 +112,146 @@ describe('search highlighting', function()
]])
end)
+ describe('CurSearch highlight', function()
+ before_each(function()
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.Yellow}, -- Search
+ [2] = {foreground = Screen.colors.White, background = Screen.colors.Black}, -- CurSearch
+ [3] = {foreground = Screen.colors.Red}, -- WarningMsg
+ })
+ command('highlight CurSearch guibg=Black guifg=White')
+ end)
+
+ it('works for match under cursor', function()
+ insert([[
+ There is no way that a bee should be
+ able to fly. Its wings are too small
+ to get its fat little body off the
+ ground. The bee, of course, flies
+ anyway because bees don't care what
+ humans think is impossible.]])
+
+ feed('/bee<CR>')
+ screen:expect{grid=[[
+ There is no way that a {2:^bee} should be |
+ able to fly. Its wings are too small |
+ to get its fat little body off the |
+ ground. The {1:bee}, of course, flies |
+ anyway because {1:bee}s don't care what |
+ humans think is impossible. |
+ {3:search hit BOTTOM, continuing at TOP} |
+ ]]}
+
+ feed('nn')
+ screen:expect{grid=[[
+ There is no way that a {1:bee} should be |
+ able to fly. Its wings are too small |
+ to get its fat little body off the |
+ ground. The {1:bee}, of course, flies |
+ anyway because {2:^bee}s don't care what |
+ humans think is impossible. |
+ /bee |
+ ]]}
+
+ feed('N')
+ screen:expect{grid=[[
+ There is no way that a {1:bee} should be |
+ able to fly. Its wings are too small |
+ to get its fat little body off the |
+ ground. The {2:^bee}, of course, flies |
+ anyway because {1:bee}s don't care what |
+ humans think is impossible. |
+ ?bee |
+ ]]}
+ end)
+
+ it('works for multiline match', function()
+ command([[call setline(1, ['one', 'foo', 'bar', 'baz', 'foo the foo and foo', 'bar'])]])
+ feed('gg/foo<CR>')
+ screen:expect([[
+ one |
+ {2:^foo} |
+ bar |
+ baz |
+ {1:foo} the {1:foo} and {1:foo} |
+ bar |
+ /foo |
+ ]])
+ feed('n')
+ screen:expect([[
+ one |
+ {1:foo} |
+ bar |
+ baz |
+ {2:^foo} the {1:foo} and {1:foo} |
+ bar |
+ /foo |
+ ]])
+ feed('n')
+ screen:expect([[
+ one |
+ {1:foo} |
+ bar |
+ baz |
+ {1:foo} the {2:^foo} and {1:foo} |
+ bar |
+ /foo |
+ ]])
+ feed('n')
+ screen:expect([[
+ one |
+ {1:foo} |
+ bar |
+ baz |
+ {1:foo} the {1:foo} and {2:^foo} |
+ bar |
+ /foo |
+ ]])
+ command([[call setline(5, 'foo')]])
+ feed('0?<CR>')
+ screen:expect([[
+ one |
+ {2:^foo} |
+ bar |
+ baz |
+ {1:foo} |
+ bar |
+ ?foo |
+ ]])
+ feed('gg/foo\\nbar<CR>')
+ screen:expect([[
+ one |
+ {2:^foo} |
+ {2:bar} |
+ baz |
+ {1:foo} |
+ {1:bar} |
+ /foo\nbar |
+ ]])
+ command([[call setline(1, ['---', 'abcdefg', 'hijkl', '---', 'abcdefg', 'hijkl'])]])
+ feed('gg/efg\\nhij<CR>')
+ screen:expect([[
+ --- |
+ abcd{2:^efg} |
+ {2:hij}kl |
+ --- |
+ abcd{1:efg} |
+ {1:hij}kl |
+ /efg\nhij |
+ ]])
+ feed('n')
+ screen:expect([[
+ --- |
+ abcd{1:efg} |
+ {1:hij}kl |
+ --- |
+ abcd{2:^efg} |
+ {2:hij}kl |
+ /efg\nhij |
+ ]])
+ end)
+ end)
+
it('highlights after EOL', function()
insert("\n\n\n\n\n\n")
@@ -163,7 +306,7 @@ describe('search highlighting', function()
end)
it('is preserved during :terminal activity', function()
- feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 5000 foo<cr>]])
+ feed((':terminal "%s" REP 5000 foo<cr>'):format(testprg('shell-test')))
feed(':file term<CR>')
feed('G') -- Follow :terminal output.
@@ -179,100 +322,101 @@ describe('search highlighting', function()
end)
it('works with incsearch', function()
- feed_command('set hlsearch')
- feed_command('set incsearch')
+ command('set hlsearch')
+ command('set incsearch')
+ command('set laststatus=0')
insert([[
the first line
- in a little file
- ]])
+ in a little file]])
+ command('vsplit')
feed("gg/li")
screen:expect([[
- the first {3:li}ne |
- in a {2:li}ttle file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first {3:li}ne │the first {2:li}ne |
+ in a {2:li}ttle file │in a {2:li}ttle file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/li^ |
]])
-- check that consecutive matches are caught by C-g/C-t
feed("<C-g>")
screen:expect([[
- the first {2:li}ne |
- in a {3:li}ttle file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first {2:li}ne │the first {2:li}ne |
+ in a {3:li}ttle file │in a {2:li}ttle file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/li^ |
]])
feed("<C-t>")
screen:expect([[
- the first {3:li}ne |
- in a {2:li}ttle file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first {3:li}ne │the first {2:li}ne |
+ in a {2:li}ttle file │in a {2:li}ttle file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/li^ |
]])
feed("t")
screen:expect([[
- the first line |
- in a {3:lit}tle file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first line │the first line |
+ in a {3:lit}tle file │in a {2:lit}tle file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/lit^ |
]])
feed("<cr>")
screen:expect([[
- the first line |
- in a {2:^lit}tle file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first line │the first line |
+ in a {2:^lit}tle file │in a {2:lit}tle file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/lit |
]])
feed("/fir")
screen:expect([[
- the {3:fir}st line |
- in a little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the {3:fir}st line │the {2:fir}st line |
+ in a little file │in a little file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/fir^ |
]])
-- incsearch have priority over hlsearch
feed("<esc>/ttle")
screen:expect([[
- the first line |
- in a li{3:ttle} file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first line │the first line |
+ in a li{3:ttle} file │in a li{2:ttle} file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/ttle^ |
]])
-- cancelling search resets to the old search term
feed('<esc>')
screen:expect([[
- the first line |
- in a {2:^lit}tle file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first line │the first line |
+ in a {2:^lit}tle file │in a {2:lit}tle file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
|
]])
eq('lit', eval('@/'))
@@ -280,91 +424,78 @@ describe('search highlighting', function()
-- cancelling inc search restores the hl state
feed(':noh<cr>')
screen:expect([[
- the first line |
- in a ^little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first line │the first line |
+ in a ^little file │in a little file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
:noh |
]])
feed('/first')
screen:expect([[
- the {3:first} line |
- in a little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the {3:first} line │the {2:first} line |
+ in a little file │in a little file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
/first^ |
]])
feed('<esc>')
screen:expect([[
- the first line |
- in a ^little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the first line │the first line |
+ in a ^little file │in a little file |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
|
]])
-- test that pressing C-g in an empty command line does not move the cursor
- feed('/<C-g>')
- screen:expect([[
- the first line |
- in a little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- /^ |
- ]])
-
- -- same, for C-t
- feed('<ESC>')
- screen:expect([[
- the first line |
- in a ^little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- |
- ]])
- feed('/<C-t>')
- screen:expect([[
- the first line |
- in a little file |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
- /^ |
- ]])
+ feed('gg0')
+ command([[let @/ = 'i']])
+ -- moves to next match of previous search pattern, just like /<cr>
+ feed('/<c-g><cr>')
+ eq({0, 1, 6, 0}, funcs.getpos('.'))
+ -- moves to next match of previous search pattern, just like /<cr>
+ feed('/<cr>')
+ eq({0, 1, 12, 0}, funcs.getpos('.'))
+ -- moves to next match of previous search pattern, just like /<cr>
+ feed('/<c-t><cr>')
+ eq({0, 2, 1, 0}, funcs.getpos('.'))
-- 8.0.1304, test that C-g and C-t works with incsearch and empty pattern
feed('<esc>/fi<CR>')
+ screen:expect([[
+ the {2:fi}rst line │the {2:fi}rst line |
+ in a little {2:^fi}le │in a little {2:fi}le |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ /fi |
+ ]])
feed('//')
screen:expect([[
- the {3:fi}rst line |
- in a little {2:fi}le |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the {3:fi}rst line │the {2:fi}rst line |
+ in a little {2:fi}le │in a little {2:fi}le |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
//^ |
]])
-
feed('<C-g>')
screen:expect([[
- the {2:fi}rst line |
- in a little {3:fi}le |
- |
- {1:~ }|
- {1:~ }|
- {1:~ }|
+ the {2:fi}rst line │the {2:fi}rst line |
+ in a little {3:fi}le │in a little {2:fi}le |
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
//^ |
]])
end)
@@ -439,19 +570,20 @@ describe('search highlighting', function()
end)
it('works with matchadd and syntax', function()
- screen:set_default_attr_ids( {
- [1] = {bold=true, foreground=Screen.colors.Blue},
- [2] = {background = colors.Yellow},
- [3] = {reverse = true},
- [4] = {foreground = colors.Red},
- [5] = {bold = true, background = colors.Green},
- [6] = {italic = true, background = colors.Magenta},
- [7] = {bold = true, background = colors.Yellow},
- } )
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {background = colors.Yellow};
+ [3] = {reverse = true};
+ [4] = {foreground = colors.Red};
+ [5] = {bold = true, background = colors.Green};
+ [6] = {italic = true, background = colors.Magenta};
+ [7] = {bold = true, background = colors.Yellow};
+ [8] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGray};
+ }
feed_command('set hlsearch')
- insert([[
+ insert [[
very special text
- ]])
+ ]]
feed_command("syntax on")
feed_command("highlight MyGroup guibg=Green gui=bold")
feed_command("highlight MyGroup2 guibg=Magenta gui=italic")
@@ -461,7 +593,7 @@ describe('search highlighting', function()
-- searchhl and matchadd matches are exclusive, only the highest priority
-- is used (and matches with lower priorities are not combined)
feed_command("/ial te")
- screen:expect([[
+ screen:expect{grid=[[
very {5:spec^ial}{2: te}{6:xt} |
|
{1:~ }|
@@ -469,10 +601,21 @@ describe('search highlighting', function()
{1:~ }|
{1:~ }|
{4:search hit BOTTOM, continuing at TOP} |
- ]])
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 11, linecount = 2};
+ }}
- -- check hilights work also in folds
+ -- check highlights work also in folds
feed("zf4j")
+ screen:expect{grid=[[
+ {8:^+-- 2 lines: very special text·········}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {4:search hit BOTTOM, continuing at TOP} |
+ ]]}
command("%foldopen")
screen:expect([[
very {5:spec^ial}{2: te}{6:xt} |
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index dcd31cfdb7..dbc92ca222 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -446,7 +446,7 @@ describe('Signs', function()
{1:>>>>>>>>}{6: 1 }a |
{2: }{6: 2 }b |
{2: }{6: 3 }c |
- {2: }{6:^ 4 } |
+ {2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -468,7 +468,7 @@ describe('Signs', function()
{1:>>>>>>>>>>}{6: 1 }a |
{2: }{6: 2 }b |
{2: }{6: 3 }c |
- {2: ^ }{6: 4 } |
+ {2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -482,7 +482,7 @@ describe('Signs', function()
]])
end)
- it('ignores signs with no icon and text when calculting the signcolumn width', function()
+ it('ignores signs with no icon and text when calculating the signcolumn width', function()
feed('ia<cr>b<cr>c<cr><esc>')
command('set number')
command('set signcolumn=auto:2')
@@ -512,7 +512,33 @@ describe('Signs', function()
{1:>>}{6: 1 }a |
{2: }{6: 2 }b |
{2: }{6: 3 }c |
- {2: }{6: ^4 } |
+ {2: }{6: 4 }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
+ it('shows the line number when signcolumn=number but no marks on a line have text', function()
+ feed('ia<cr>b<cr>c<cr><esc>')
+ command('set number signcolumn=number')
+ command('sign define pietSearch text=>> texthl=Search numhl=Error')
+ command('sign define pietError text= texthl=Search numhl=Error')
+ command('sign place 1 line=1 name=pietSearch buffer=1')
+ command('sign place 2 line=2 name=pietError buffer=1')
+ -- no signcolumn, line number for "a" is Search, for "b" is Error, for "c" is LineNr
+ screen:expect([[
+ {1: >> }a |
+ {8: 2 }b |
+ {6: 3 }c |
+ {6: 4 }^ |
{0:~ }|
{0:~ }|
{0:~ }|
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
new file mode 100644
index 0000000000..1e1066d48a
--- /dev/null
+++ b/test/functional/ui/statusline_spec.lua
@@ -0,0 +1,342 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local feed = helpers.feed
+local eq = helpers.eq
+local funcs = helpers.funcs
+local meths = helpers.meths
+local exec = helpers.exec
+local exec_lua = helpers.exec_lua
+local eval = helpers.eval
+
+describe('statusline clicks', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(40, 8)
+ screen:attach()
+ command('set laststatus=2 mousemodel=extend')
+ exec([=[
+ function! MyClickFunc(minwid, clicks, button, mods)
+ let mods = trim(a:mods)
+ if mods ==# ''
+ let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
+ else
+ let g:testvar = printf("%d %d %s %s", a:minwid, a:clicks, a:button, mods)
+ endif
+ endfunction
+ ]=])
+ end)
+
+ it('works', function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('works for winbar', function()
+ meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 0, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 0, 17)
+ eq('0 1 r', eval("g:testvar"))
+ end)
+
+ it('works for winbar in floating window', function()
+ meths.open_win(0, true, { width=30, height=4, relative='editor', row=1, col=5,
+ border = "single" })
+ meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T',
+ { scope = 'local' })
+ meths.input_mouse('left', 'press', '', 0, 2, 23)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('works when there are multiple windows', function()
+ command('split')
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 0, 17)
+ eq('0 1 l', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 4, 17)
+ eq('0 1 r', eval("g:testvar"))
+ meths.input_mouse('middle', 'press', '', 0, 3, 17)
+ eq('0 1 m', eval("g:testvar"))
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('works with Lua function', function()
+ exec_lua([[
+ function clicky_func(minwid, clicks, button, mods)
+ vim.g.testvar = string.format("%d %d %s", minwid, clicks, button)
+ end
+ ]])
+ meths.set_option('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 17)
+ eq('0 1 l', eval("g:testvar"))
+ end)
+
+ it('ignores unsupported click items', function()
+ command('tabnew | tabprevious')
+ meths.set_option('statusline', '%2TNot clicky stuff%T')
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq(1, meths.get_current_tabpage().id)
+ meths.set_option('statusline', '%2XNot clicky stuff%X')
+ meths.input_mouse('left', 'press', '', 0, 6, 0)
+ eq(2, #meths.list_tabpages())
+ end)
+
+ it("right click works when statusline isn't focused #18994", function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 1 r', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 6, 17)
+ eq('0 2 r', eval("g:testvar"))
+ end)
+
+ it("click works with modifiers #18994", function()
+ meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+ meths.input_mouse('right', 'press', 's', 0, 6, 17)
+ eq('0 1 r s', eval("g:testvar"))
+ meths.input_mouse('left', 'press', 's', 0, 6, 17)
+ eq('0 1 l s', eval("g:testvar"))
+ end)
+end)
+
+describe('global statusline', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 16)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue};
+ [2] = {bold = true, reverse = true};
+ [3] = {bold = true};
+ [4] = {reverse = true};
+ })
+ command('set laststatus=3')
+ command('set ruler')
+ end)
+
+ it('works', function()
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ feed('i<CR><CR>')
+ screen:expect([[
+ |
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] 3,1 All}|
+ {3:-- INSERT --} |
+ ]])
+ end)
+
+ it('works with splits', function()
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
+
+ it('works when switching between values of laststatus', function()
+ command('set laststatus=1')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ 0,0-1 All |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ command('set laststatus=2')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│ |
+ {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {4:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+
+ command('set laststatus=0')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}|
+ {1:~ }│{1:~ }│{1:~}│ |
+ {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ 0,0-1 All |
+ ]])
+
+ command('set laststatus=3')
+ screen:expect([[
+ │ │ │^ |
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }├────────────────┤{1:~}│{1:~ }|
+ {1:~ }│ │{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}│{1:~ }|
+ {1:~ }│{1:~ }│{1:~}├────────────────────|
+ {1:~ }│{1:~ }│{1:~}│ |
+ ────────────────────┴────────────────┴─┤{1:~ }|
+ │{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {1:~ }│{1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]])
+ end)
+
+ it('win_move_statusline() can reduce cmdheight to 1', function()
+ eq(1, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, -1)
+ eq(3, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(2, meths.get_option('cmdheight'))
+ funcs.win_move_statusline(0, 1)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+
+ it('mouse dragging can reduce cmdheight to 1', function()
+ command('set mouse=a')
+ meths.input_mouse('left', 'press', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 12, 10)
+ eq(3, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 13, 10)
+ eq(2, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 15, 10)
+ eq(0, meths.get_option('cmdheight'))
+ meths.input_mouse('left', 'drag', '', 0, 14, 10)
+ eq(1, meths.get_option('cmdheight'))
+ end)
+end)
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index 4e1852162f..f790597140 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -3,6 +3,8 @@ local Screen = require('test.functional.ui.screen')
local clear, feed, command = helpers.clear, helpers.feed, helpers.command
local eq = helpers.eq
local insert = helpers.insert
+local poke_eventloop = helpers.poke_eventloop
+local expect_exit = helpers.expect_exit
describe('Screen', function()
local screen
@@ -255,6 +257,40 @@ 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()
+ insert([[foobarfoobarfoobar]])
+ -- move to end of line
+ feed("$")
+ command("set concealcursor=ni")
+ command("syn match Foo /foobar/ conceal cchar=&")
+ screen:expect([[
+ {1:&&&}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed("i")
+ -- cursor should stay in place, not jump to column 16
+ screen:expect([[
+ {1:&&&}^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:-- INSERT --} |
+ ]])
+ end)
end) -- match and conceal
describe("let the conceal level be", function()
@@ -911,14 +947,64 @@ describe('Screen', function()
{0:~ }|
|
]]}
- eq(grid_lines, {{2, 0, {{'c', 0, 3}}}})
+ eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ end)
+
+ it('K_EVENT should not cause extra redraws with concealcursor #13196', function()
+ command('set conceallevel=1')
+ command('set concealcursor=nv')
+ command('set redrawdebug+=nodelta')
+
+ insert([[
+ aaa
+ bbb
+ ccc
+ ]])
+ screen:expect{grid=[[
+ aaa |
+ bbb |
+ ccc |
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+
+ -- XXX: hack to get notifications, and check only a single line is
+ -- updated. Could use next_msg() also.
+ local orig_handle_grid_line = screen._handle_grid_line
+ local grid_lines = {}
+ function screen._handle_grid_line(self, grid, row, col, items)
+ table.insert(grid_lines, {row, col, items})
+ orig_handle_grid_line(self, grid, row, col, items)
+ end
+ feed('k')
+ screen:expect{grid=[[
+ aaa |
+ bbb |
+ ^ccc |
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
+ poke_eventloop() -- causes K_EVENT key
+ screen:expect_unchanged()
+ eq({{2, 0, {{'c', 0, 3}}}}, grid_lines)
end)
-- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in
-- test/functional/ui/syntax_conceal_spec.lua.
describe('concealed line after window scroll', function()
after_each(function()
- command(':qall!')
+ expect_exit(command, ':qall!')
os.remove('Xcolesearch')
end)
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 65c6fabfa8..98398bc7a1 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -7,7 +7,7 @@ local meths = helpers.meths
local eq = helpers.eq
local eval = helpers.eval
local retry = helpers.retry
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
describe("'wildmenu'", function()
local screen
@@ -114,7 +114,7 @@ describe("'wildmenu'", function()
it('is preserved during :terminal activity', function()
command('set wildmenu wildmode=full')
command('set scrollback=4')
- feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 5000 !terminal_output!<cr>]])
+ feed((':terminal "%s" REP 5000 !terminal_output!<cr>'):format(testprg('shell-test')))
feed('G') -- Follow :terminal output.
feed([[:sign <Tab>]]) -- Invoke wildmenu.
-- NB: in earlier versions terminal output was redrawn during cmdline mode.
diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
new file mode 100644
index 0000000000..92a6ab2e84
--- /dev/null
+++ b/test/functional/ui/winbar_spec.lua
@@ -0,0 +1,580 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local insert = helpers.insert
+local meths = helpers.meths
+local eq = helpers.eq
+local poke_eventloop = helpers.poke_eventloop
+local feed = helpers.feed
+local pcall_err = helpers.pcall_err
+
+describe('winbar', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 13)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true},
+ [2] = {reverse = true},
+ [3] = {bold = true, foreground = Screen.colors.Blue},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.Red},
+ [6] = {foreground = Screen.colors.Blue},
+ [7] = {background = Screen.colors.LightGrey},
+ [8] = {background = Screen.colors.LightMagenta},
+ [9] = {bold = true, foreground = Screen.colors.Blue, background = Screen.colors.LightMagenta},
+ [10] = {background = Screen.colors.LightGrey, underline = true},
+ [11] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta},
+ })
+ meths.set_option('winbar', 'Set Up The Bars')
+ end)
+
+ it('works', function()
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+
+ it('works with custom \'fillchars\' value', function()
+ command('set fillchars=wbr:+')
+ screen:expect([[
+ {1:Set Up The Bars+++++++++++++++++++++++++++++++++++++++++++++}|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+
+ it('works with custom highlight', function()
+ command('hi WinBar guifg=red')
+ screen:expect([[
+ {5:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end)
+
+ it('works with splits', function()
+ command('hi WinBar guifg=red')
+ command('hi WinBarNC guifg=blue')
+ command('belowright vsplit | split | split')
+ screen:expect([[
+ {6:Set Up The Bars }│{5:Set Up The Bars }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│{6:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│{6:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ end)
+
+ it('works when switching value of \'winbar\'', function()
+ command('belowright vsplit | split | split | set winbar=')
+ screen:expect([[
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ command('set winbar=All\\ Your\\ Bar\\ Are\\ Belong\\ To\\ Us')
+ screen:expect([[
+ {1:All Your Bar Are Belong To Us}│{1:All Your Bar Are Belong To Us }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│{1:All Your Bar Are Belong To Us }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│{1:All Your Bar Are Belong To Us }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ command('set winbar=Changed\\ winbar')
+ screen:expect([[
+ {1:Changed winbar }│{1:Changed winbar }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{4:[No Name] }|
+ {3:~ }│{1:Changed winbar }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{2:[No Name] }|
+ {3:~ }│{1:Changed winbar }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {2:[No Name] [No Name] }|
+ |
+ ]])
+ end)
+
+ it('can be ruler', function()
+ insert [[
+ just some
+ random text]]
+ meths.set_option('winbar', 'Hello, I am a ruler: %l,%c')
+ screen:expect{grid=[[
+ {1:Hello, I am a ruler: 2,11 }|
+ just some |
+ random tex^t |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ feed 'b'
+ screen:expect{grid=[[
+ {1:Hello, I am a ruler: 2,8 }|
+ just some |
+ random ^text |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ feed 'k'
+ screen:expect{grid=[[
+ {1:Hello, I am a ruler: 1,8 }|
+ just so^me |
+ random text |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with laststatus=3', function()
+ command('set laststatus=3')
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+ command('belowright vsplit | split | split')
+ screen:expect([[
+ {1:Set Up The Bars }│{1:Set Up The Bars }|
+ │^ |
+ {3:~ }│{3:~ }|
+ {3:~ }├──────────────────────────────|
+ {3:~ }│{1:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {3:~ }├──────────────────────────────|
+ {3:~ }│{1:Set Up The Bars }|
+ {3:~ }│ |
+ {3:~ }│{3:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+ -- Test for issue #18791
+ command('tabnew')
+ screen:expect([[
+ {10: }{11:4}{10: [No Name] }{1: [No Name] }{2: }{10:X}|
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('mouse click and drag work correctly in buffer', function()
+ insert([[
+ line 1
+ line 2
+ line 3
+ line 4
+ line -42
+ line i
+ line sin(theta)
+ line 8]])
+
+ meths.input_mouse('left', 'press', '', 0, 5, 1)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ line 1 |
+ line 2 |
+ line 3 |
+ line 4 |
+ l^ine -42 |
+ line i |
+ line sin(theta) |
+ line 8 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ eq({5, 1}, meths.win_get_cursor(0))
+
+ meths.input_mouse('left', 'drag', '', 0, 6, 2)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ line 1 |
+ line 2 |
+ line 3 |
+ line 4 |
+ l{7:ine -42} |
+ {7:li}^ne i |
+ line sin(theta) |
+ line 8 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL --} |
+ ]])
+ eq({6, 2}, meths.win_get_cursor(0))
+
+ meths.input_mouse('left', 'drag', '', 0, 1, 2)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ li^n{7:e 1} |
+ {7:line 2} |
+ {7:line 3} |
+ {7:line 4} |
+ {7:li}ne -42 |
+ line i |
+ line sin(theta) |
+ line 8 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {1:-- VISUAL --} |
+ ]])
+ eq({1, 2}, meths.win_get_cursor(0))
+
+ meths.input_mouse('left', 'drag', '', 0, 0, 2)
+ screen:expect_unchanged()
+ eq({1, 2}, meths.win_get_cursor(0))
+ end)
+
+ it('dragging statusline with mouse works correctly', function()
+ command('split')
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 5, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 6, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'drag', '', 1, 4, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+
+ meths.input_mouse('left', 'press', '', 1, 11, 10)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 9, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ |
+ |
+ ]])
+ eq(3, meths.get_option('cmdheight'))
+
+ meths.input_mouse('left', 'drag', '', 1, 11, 10)
+ screen:expect([[
+ {1:Set Up The Bars }|
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ {4:[No Name] }|
+ {1:Set Up The Bars }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+ eq(1, meths.get_option('cmdheight'))
+ end)
+
+ it('properly equalizes window height for window-local value', function()
+ command('set equalalways | set winbar= | setlocal winbar=a | split')
+ command('setlocal winbar= | split')
+ command('setlocal winbar=b | split')
+ screen:expect([[
+ {1:b }|
+ ^ |
+ {4:[No Name] }|
+ {1:b }|
+ |
+ {2:[No Name] }|
+ |
+ {3:~ }|
+ {2:[No Name] }|
+ {1:a }|
+ |
+ {2:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('requires window-local value for floating windows', function()
+ local win = meths.open_win(0, false, { relative = 'editor', row = 2, col = 10, height = 7,
+ width = 30 })
+ meths.set_option_value('winbar', 'bar', {})
+ screen:expect{grid=[[
+ {1:bar }|
+ ^ |
+ {3:~ }{8: }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ meths.set_option_value('winbar', 'floaty bar', { scope = 'local', win = win.id })
+ screen:expect{grid=[[
+ {1:bar }|
+ ^ |
+ {3:~ }{1:floaty bar }{3: }|
+ {3:~ }{8: }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }{9:~ }{3: }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]]}
+ end)
+
+ it('works correctly when moving a split', function()
+ screen:try_resize(45, 6)
+ command('set winbar=')
+ command('vsplit')
+ command('setlocal winbar=foo')
+ screen:expect([[
+ {1:foo }│ |
+ ^ │{3:~ }|
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {4:[No Name] }{2:[No Name] }|
+ |
+ ]])
+
+ command('wincmd L')
+ screen:expect([[
+ │{1:foo }|
+ {3:~ }│^ |
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {2:[No Name] }{4:[No Name] }|
+ |
+ ]])
+
+ command('wincmd w')
+ command('wincmd L')
+ screen:expect([[
+ {1:foo }│^ |
+ │{3:~ }|
+ {3:~ }│{3:~ }|
+ {3:~ }│{3:~ }|
+ {2:[No Name] }{4:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('properly resizes window when there is no space in it', function()
+ command('set winbar= | 1split')
+ screen:expect([[
+ ^ |
+ {4:[No Name] }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+ command('set winbar=a')
+ screen:expect([[
+ {1:a }|
+ ^ |
+ {4:[No Name] }|
+ {1:a }|
+ |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {2:[No Name] }|
+ |
+ ]])
+ end)
+
+ it('cannot be added unless there is room', function()
+ command('set winbar= | split | split | split | split | split')
+ screen:expect([[
+ ^ |
+ {4:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ {2:[No Name] }|
+ |
+ ]])
+ eq('Vim(set):E36: Not enough room', pcall_err(command, 'set winbar=test'))
+ end)
+end)
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index d07e74d40e..8ca245f61a 100644
--- a/test/functional/vimscript/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -49,7 +49,8 @@ describe('eval-API', function()
it('cannot change texts if textlocked', function()
command("autocmd TextYankPost <buffer> ++once call nvim_buf_set_lines(0, 0, -1, v:false, [])")
- eq('Vim(call):E5555: API call: E523: Not allowed here', pcall_err(command, "normal! yy"))
+ eq('Vim(call):E5555: API call: E565: Not allowed to change text or change window',
+ pcall_err(command, "normal! yy"))
end)
it("use buffer numbers and windows ids as handles", function()
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index e1459ab5b8..0c2ca8de78 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -5,7 +5,7 @@
-- null_spec.lua
-- operators_spec.lua
--
--- Tests for the Vimscript |functions| library should live in:
+-- Tests for the Vimscript |builtin-functions| library should live in:
-- test/functional/vimscript/<funcname>_spec.lua
-- test/functional/vimscript/functions_spec.lua
diff --git a/test/functional/vimscript/executable_spec.lua b/test/functional/vimscript/executable_spec.lua
index 048a65188d..b4162b2336 100644
--- a/test/functional/vimscript/executable_spec.lua
+++ b/test/functional/vimscript/executable_spec.lua
@@ -17,6 +17,21 @@ describe('executable()', function()
eq(1, call('executable', 'false'))
end)
+ if iswin() then
+ it('exepath respects shellslash', function()
+ command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
+ eq([[test\functional\fixtures\bin\null.CMD]], call('fnamemodify', call('exepath', 'null'), ':.'))
+ command('set shellslash')
+ eq('test/functional/fixtures/bin/null.CMD', call('fnamemodify', call('exepath', 'null'), ':.'))
+ end)
+
+ it('stdpath respects shellslash', function()
+ eq([[build\Xtest_xdg\share\nvim-data]], call('fnamemodify', call('stdpath', 'data'), ':.'))
+ command('set shellslash')
+ eq('build/Xtest_xdg/share/nvim-data', call('fnamemodify', call('stdpath', 'data'), ':.'))
+ end)
+ end
+
it('fails for invalid values', function()
for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
eq('Vim(call):E928: String required', exc_exec('call executable('..input..')'))
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index e21c71dc7f..a733b098f5 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -153,7 +153,7 @@ describe('execute()', function()
function! Test3()
echo 1234
let x = execute('echoerr "abcdef"', 'silent!')
- echon 'ABCD'
+ echon 'ABCDXZYZ'
endfunction
" test 4: silenced echoerr goes as usual
@@ -214,7 +214,7 @@ describe('execute()', function()
~ |
~ |
~ |
- 1234ABCD |
+ 1234ABCDXZYZ |
]])
feed([[:call Test4()<cr>]])
diff --git a/test/functional/vimscript/functions_spec.lua b/test/functional/vimscript/functions_spec.lua
index 0ad7fd8010..20c1400030 100644
--- a/test/functional/vimscript/functions_spec.lua
+++ b/test/functional/vimscript/functions_spec.lua
@@ -1,4 +1,4 @@
--- Tests for misc Vimscript |functions|.
+-- Tests for misc Vimscript |builtin-functions|.
--
-- If a function is non-trivial, consider moving its spec to:
-- test/functional/vimscript/<funcname>_spec.lua
diff --git a/test/functional/vimscript/has_spec.lua b/test/functional/vimscript/has_spec.lua
index c03fd13e0c..4d9b226434 100644
--- a/test/functional/vimscript/has_spec.lua
+++ b/test/functional/vimscript/has_spec.lua
@@ -68,4 +68,11 @@ describe('has()', function()
eq(0, funcs.has('wsl'))
end
end)
+
+ it('does not change v:shell_error', function()
+ local nvim_prog = helpers.nvim_prog
+ funcs.system({nvim_prog, '-es', '+73cquit'})
+ funcs.has('python3') -- use a call whose implementation shells out
+ eq(73, funcs.eval('v:shell_error'))
+ end)
end)
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index 14c02f9eb2..554d15e550 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -9,6 +9,7 @@ local source = helpers.source
local command = helpers.command
local exc_exec = helpers.exc_exec
local nvim_async = helpers.nvim_async
+local NIL = helpers.NIL
local screen
@@ -200,6 +201,15 @@ describe('input()', function()
feed(':let var = input({"cancelreturn": "BAR"})<CR>')
feed('<Esc>')
eq('BAR', meths.get_var('var'))
+ feed(':let var = input({"cancelreturn": []})<CR>')
+ feed('<Esc>')
+ eq({}, meths.get_var('var'))
+ feed(':let var = input({"cancelreturn": v:false})<CR>')
+ feed('<Esc>')
+ eq(false, meths.get_var('var'))
+ feed(':let var = input({"cancelreturn": v:null})<CR>')
+ feed('<Esc>')
+ eq(NIL, meths.get_var('var'))
end)
it('supports default string', function()
feed(':let var = input("", "DEF1")<CR>')
@@ -220,8 +230,6 @@ describe('input()', function()
eq('Vim(call):E730: using List as a String',
exc_exec('call input({"prompt": []})'))
eq('Vim(call):E730: using List as a String',
- exc_exec('call input({"cancelreturn": []})'))
- eq('Vim(call):E730: using List as a String',
exc_exec('call input({"default": []})'))
eq('Vim(call):E730: using List as a String',
exc_exec('call input({"completion": []})'))
@@ -418,8 +426,6 @@ describe('inputdialog()', function()
eq('Vim(call):E730: using List as a String',
exc_exec('call inputdialog({"prompt": []})'))
eq('Vim(call):E730: using List as a String',
- exc_exec('call inputdialog({"cancelreturn": []})'))
- eq('Vim(call):E730: using List as a String',
exc_exec('call inputdialog({"default": []})'))
eq('Vim(call):E730: using List as a String',
exc_exec('call inputdialog({"completion": []})'))
diff --git a/test/functional/vimscript/lang_spec.lua b/test/functional/vimscript/lang_spec.lua
index d5254986ab..90437f2ee1 100644
--- a/test/functional/vimscript/lang_spec.lua
+++ b/test/functional/vimscript/lang_spec.lua
@@ -11,6 +11,7 @@ describe('vimscript', function()
return
end
source([[
+ let s:foo = 1
func! <sid>_dummy_function()
echo 1
endfunc
diff --git a/test/functional/vimscript/let_spec.lua b/test/functional/vimscript/let_spec.lua
index 4ff4090a18..ca1b5e8907 100644
--- a/test/functional/vimscript/let_spec.lua
+++ b/test/functional/vimscript/let_spec.lua
@@ -5,9 +5,10 @@ local clear = helpers.clear
local command = helpers.command
local eval = helpers.eval
local meths = helpers.meths
+local exec = helpers.exec
local exec_capture = helpers.exec_capture
local source = helpers.source
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
before_each(clear)
@@ -47,33 +48,33 @@ describe(':let', function()
end)
it("multibyte env var #8398 #9267", function()
- command("let $NVIM_TEST = 'AìaB'")
- eq('AìaB', eval('$NVIM_TEST'))
- command("let $NVIM_TEST = 'AaあB'")
- eq('AaあB', eval('$NVIM_TEST'))
+ command("let $NVIM_TEST_LET = 'AìaB'")
+ eq('AìaB', eval('$NVIM_TEST_LET'))
+ command("let $NVIM_TEST_LET = 'AaあB'")
+ eq('AaあB', eval('$NVIM_TEST_LET'))
local mbyte = [[\p* .ม .ม .ม .ม่ .ม่ .ม่ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ ֹֻ
.ֹֻ .ֹֻ .ֹֻ ֹֻ ֹֻ ֹֻ .ֹֻ .ֹֻ .ֹֻ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ
.ֹֻ .ֹֻ .ֹֻ a a a ca ca ca à à à]]
- command("let $NVIM_TEST = '"..mbyte.."'")
- eq(mbyte, eval('$NVIM_TEST'))
+ command("let $NVIM_TEST_LET = '"..mbyte.."'")
+ eq(mbyte, eval('$NVIM_TEST_LET'))
end)
it("multibyte env var to child process #8398 #9267", function()
- local cmd_get_child_env = "let g:env_from_child = system(['"..nvim_dir.."/printenv-test', 'NVIM_TEST'])"
- command("let $NVIM_TEST = 'AìaB'")
+ local cmd_get_child_env = ("let g:env_from_child = system(['%s', 'NVIM_TEST_LET'])"):format(testprg('printenv-test'))
+ command("let $NVIM_TEST_LET = 'AìaB'")
command(cmd_get_child_env)
- eq(eval('$NVIM_TEST'), eval('g:env_from_child'))
+ eq(eval('$NVIM_TEST_LET'), eval('g:env_from_child'))
- command("let $NVIM_TEST = 'AaあB'")
+ command("let $NVIM_TEST_LET = 'AaあB'")
command(cmd_get_child_env)
- eq(eval('$NVIM_TEST'), eval('g:env_from_child'))
+ eq(eval('$NVIM_TEST_LET'), eval('g:env_from_child'))
local mbyte = [[\p* .ม .ม .ม .ม่ .ม่ .ม่ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ ֹֻ
.ֹֻ .ֹֻ .ֹֻ ֹֻ ֹֻ ֹֻ .ֹֻ .ֹֻ .ֹֻ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹ ֹ ֹ .ֹ .ֹ .ֹ ֹֻ ֹֻ
.ֹֻ .ֹֻ .ֹֻ a a a ca ca ca à à à]]
- command("let $NVIM_TEST = '"..mbyte.."'")
+ command("let $NVIM_TEST_LET = '"..mbyte.."'")
command(cmd_get_child_env)
- eq(eval('$NVIM_TEST'), eval('g:env_from_child'))
+ eq(eval('$NVIM_TEST_LET'), eval('g:env_from_child'))
end)
it("release of list assigned to l: variable does not trigger assertion #12387, #12430", function()
@@ -91,3 +92,19 @@ describe(':let', function()
eq(1, eval('1'))
end)
end)
+
+describe(':let and :const', function()
+ it('have the same output when called without arguments', function()
+ eq(exec_capture('let'), exec_capture('const'))
+ end)
+
+ it('can be used in sandbox', function()
+ exec([[
+ func Func()
+ let l:foo = 'foo'
+ const l:bar = 'bar'
+ endfunc
+ sandbox call Func()
+ ]])
+ end)
+end)
diff --git a/test/functional/vimscript/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua
index 837b629858..cab67d77e4 100644
--- a/test/functional/vimscript/msgpack_functions_spec.lua
+++ b/test/functional/vimscript/msgpack_functions_spec.lua
@@ -5,6 +5,7 @@ local eval, eq = helpers.eval, helpers.eq
local command = helpers.command
local nvim = helpers.nvim
local exc_exec = helpers.exc_exec
+local iswin = helpers.iswin
describe('msgpack*() functions', function()
before_each(clear)
@@ -466,6 +467,11 @@ describe('msgpackparse() function', function()
eval(cmd)
eval(cmd) -- do it again (try to force segfault)
local api_info = eval(cmd) -- do it again
+ if iswin() then
+ helpers.assert_alive()
+ pending('msgpackparse() has a bug on windows')
+ return
+ end
eq({'error_types', 'functions', 'types',
'ui_events', 'ui_options', 'version'}, api_info)
end)
diff --git a/test/functional/vimscript/reltime_spec.lua b/test/functional/vimscript/reltime_spec.lua
index d87943e485..6d661402a6 100644
--- a/test/functional/vimscript/reltime_spec.lua
+++ b/test/functional/vimscript/reltime_spec.lua
@@ -12,7 +12,7 @@ describe('reltimestr(), reltimefloat()', function()
local later = reltime()
local elapsed = reltime(now)
- neq(reltimestr(elapsed), '0.0')
+ neq('0.0', reltimestr(elapsed))
ok(reltimefloat(elapsed) > 0.0)
-- original vim test for < 0.1, but easily fails on travis
ok(nil ~= string.match(reltimestr(elapsed), "0%."))
@@ -26,7 +26,7 @@ describe('reltimestr(), reltimefloat()', function()
eq(0.0, reltimefloat(same))
local differs = reltime(now, later)
- neq(reltimestr(differs), '0.0')
+ neq('0.0', reltimestr(differs))
ok(reltimefloat(differs) > 0.0)
-- original vim test for < 0.1, but easily fails on travis
ok(nil ~= string.match(reltimestr(differs), "0%."))
diff --git a/test/functional/vimscript/screenchar_spec.lua b/test/functional/vimscript/screenchar_spec.lua
new file mode 100644
index 0000000000..767e3c57ef
--- /dev/null
+++ b/test/functional/vimscript/screenchar_spec.lua
@@ -0,0 +1,69 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq
+local command, meths, funcs = helpers.command, helpers.meths, helpers.funcs
+local tbl_deep_extend = helpers.tbl_deep_extend
+
+-- Set up two overlapping floating windows
+local setup_floating_windows = function()
+ local base_opts = {
+ relative = 'editor',
+ height = 1,
+ width = 2,
+ anchor = 'NW',
+ style = 'minimal',
+ border = 'none',
+ }
+
+ local bufnr_1 = meths.create_buf(false, true)
+ meths.buf_set_lines(bufnr_1, 0, -1, true, { 'aa' })
+ local opts_1 = tbl_deep_extend('force', { row = 0, col = 0, zindex = 11 }, base_opts)
+ meths.open_win(bufnr_1, false, opts_1)
+
+ local bufnr_2 = meths.create_buf(false, true)
+ meths.buf_set_lines(bufnr_2, 0, -1, true, { 'bb' })
+ local opts_2 = tbl_deep_extend('force', { row = 0, col = 1, zindex = 10 }, base_opts)
+ meths.open_win(bufnr_2, false, opts_2)
+
+ command('redraw')
+end
+
+describe('screenchar() and family respect floating windows', function()
+ before_each(function()
+ clear()
+ -- These commands result into visible text `aabc`.
+ -- `aab` - from floating windows, `c` - from text in regular window.
+ meths.buf_set_lines(0, 0, -1, true, { 'cccc' })
+ setup_floating_windows()
+ end)
+
+ it('screenattr()', function()
+ local attr_1 = funcs.screenattr(1, 1)
+ local attr_2 = funcs.screenattr(1, 2)
+ local attr_3 = funcs.screenattr(1, 3)
+ local attr_4 = funcs.screenattr(1, 4)
+ eq(attr_1, attr_2)
+ eq(attr_1, attr_3)
+ neq(attr_1, attr_4)
+ end)
+
+ it('screenchar()', function()
+ eq(97, funcs.screenchar(1, 1))
+ eq(97, funcs.screenchar(1, 2))
+ eq(98, funcs.screenchar(1, 3))
+ eq(99, funcs.screenchar(1, 4))
+ end)
+
+ it('screenchars()', function()
+ eq({ 97 }, funcs.screenchars(1, 1))
+ eq({ 97 }, funcs.screenchars(1, 2))
+ eq({ 98 }, funcs.screenchars(1, 3))
+ eq({ 99 }, funcs.screenchars(1, 4))
+ end)
+
+ it('screenstring()', function()
+ eq('a', funcs.screenstring(1, 1))
+ eq('a', funcs.screenstring(1, 2))
+ eq('b', funcs.screenstring(1, 3))
+ eq('c', funcs.screenstring(1, 4))
+ end)
+end)
diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua
index 238d1aeb0f..6e95459630 100644
--- a/test/functional/vimscript/server_spec.lua
+++ b/test/functional/vimscript/server_spec.lua
@@ -1,11 +1,11 @@
local helpers = require('test.functional.helpers')(after_each)
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
-local command = helpers.command
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
local iswin = helpers.iswin
local ok = helpers.ok
local matches = helpers.matches
local pcall_err = helpers.pcall_err
+local mkdir = helpers.mkdir
local function clear_serverlist()
for _, server in pairs(funcs.serverlist()) do
@@ -14,29 +14,38 @@ local function clear_serverlist()
end
describe('server', function()
- before_each(clear)
+ it('serverstart() stores sockets in $XDG_RUNTIME_DIR', function()
+ local dir = 'Xtest_xdg_run'
+ mkdir(dir)
+ clear({ env={ XDG_RUNTIME_DIR=dir } })
+ matches(dir, funcs.stdpath('run'))
+ if not iswin() then
+ matches(dir, funcs.serverstart())
+ end
+ end)
- it('serverstart() sets $NVIM_LISTEN_ADDRESS on first invocation', function()
- -- Unset $NVIM_LISTEN_ADDRESS
- command('let $NVIM_LISTEN_ADDRESS = ""')
+ it('serverstart(), serverstop() does not set $NVIM', function()
+ clear()
local s = eval('serverstart()')
assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
- eq(s, eval('$NVIM_LISTEN_ADDRESS'))
+ eq('', eval('$NVIM'))
+ eq('', eval('$NVIM_LISTEN_ADDRESS'))
eq(1, eval("serverstop('"..s.."')"))
eq('', eval('$NVIM_LISTEN_ADDRESS'))
end)
it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function()
clear({env={NVIM_LISTEN_ADDRESS='.'}})
- eq('.', eval('$NVIM_LISTEN_ADDRESS'))
+ -- Cleared on startup.
+ eq('', eval('$NVIM_LISTEN_ADDRESS'))
local servers = funcs.serverlist()
eq(1, #servers)
- ok(string.len(servers[1]) > 4) -- Like /tmp/nvim…/… or \\.\pipe\…
+ ok(string.len(servers[1]) > 4) -- "~/.local/state/nvim…/…" or "\\.\pipe\…"
end)
- it('sets v:servername at startup or if all servers were stopped',
- function()
+ it('sets v:servername at startup or if all servers were stopped', function()
+ clear()
local initial_server = meths.get_vvar('servername')
assert(initial_server ~= nil and initial_server:len() > 0,
'v:servername was not initialized')
@@ -55,19 +64,23 @@ describe('server', function()
eq(1, funcs.serverstop(funcs.serverlist()[1]))
eq('', meths.get_vvar('servername'))
- -- v:servername will take the next available server.
+ -- v:servername and $NVIM take the next available server.
local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]]
- or 'Xtest-functional-server-socket')
+ or './Xtest-functional-server-socket')
funcs.serverstart(servername)
eq(servername, meths.get_vvar('servername'))
+ -- Not set in the current process, only in children.
+ eq('', eval('$NVIM'))
end)
it('serverstop() returns false for invalid input', function()
+ clear()
eq(0, eval("serverstop('')"))
eq(0, eval("serverstop('bogus-socket-name')"))
end)
- it('parses endpoints correctly', function()
+ it('parses endpoints', function()
+ clear()
clear_serverlist()
eq({}, funcs.serverlist())
@@ -102,19 +115,24 @@ describe('server', function()
eq(expected, funcs.serverlist())
clear_serverlist()
+ -- Address without slashes is a "name" which is appended to a generated path. #8519
+ matches([[.*[/\\]xtest1%.2%.3%.4[^/\\]*]], funcs.serverstart('xtest1.2.3.4'))
+ clear_serverlist()
+
eq('Vim:Failed to start server: invalid argument',
pcall_err(funcs.serverstart, '127.0.0.1:65536')) -- invalid port
eq({}, funcs.serverlist())
end)
it('serverlist() returns the list of servers', function()
+ clear()
-- There should already be at least one server.
local n = eval('len(serverlist())')
-- Add some servers.
local servs = (iswin()
and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] }
- or { [[Xtest-pipe0934]], [[Xtest-pipe4324]] })
+ or { [[./Xtest-pipe0934]], [[./Xtest-pipe4324]] })
for _, s in ipairs(servs) do
eq(s, eval("serverstart('"..s.."')"))
end
@@ -136,7 +154,6 @@ end)
describe('startup --listen', function()
it('validates', function()
clear()
-
local cmd = { unpack(helpers.nvim_argv) }
table.insert(cmd, '--listen')
matches('nvim.*: Argument missing after: "%-%-listen"', funcs.system(cmd))
@@ -148,9 +165,13 @@ describe('startup --listen', function()
it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]]
- or 'Xtest-listen-pipe')
- clear({ env={ NVIM_LISTEN_ADDRESS='Xtest-env-pipe' },
+ or './Xtest-listen-pipe')
+ clear({ env={ NVIM_LISTEN_ADDRESS='./Xtest-env-pipe' },
args={ '--listen', addr } })
eq(addr, meths.get_vvar('servername'))
+
+ -- Address without slashes is a "name" which is appended to a generated path. #8519
+ clear({ args={ '--listen', 'test-name' } })
+ matches([[.*[/\\]test%-name[^/\\]*]], meths.get_vvar('servername'))
end)
end)
diff --git a/test/functional/vimscript/setpos_spec.lua b/test/functional/vimscript/setpos_spec.lua
index 935f387bcc..02e550dcc0 100644
--- a/test/functional/vimscript/setpos_spec.lua
+++ b/test/functional/vimscript/setpos_spec.lua
@@ -24,41 +24,41 @@ describe('setpos() function', function()
end)
it('can set the current cursor position', function()
setpos(".", {0, 2, 1, 0})
- eq(getpos("."), {0, 2, 1, 0})
+ eq({0, 2, 1, 0}, getpos("."))
setpos(".", {2, 1, 1, 0})
- eq(getpos("."), {0, 1, 1, 0})
+ eq({0, 1, 1, 0}, getpos("."))
local ret = exc_exec('call setpos(".", [1, 1, 1, 0])')
eq(0, ret)
end)
it('can set lowercase marks in the current buffer', function()
setpos("'d", {0, 2, 1, 0})
- eq(getpos("'d"), {0, 2, 1, 0})
+ eq({0, 2, 1, 0}, getpos("'d"))
command('undo')
command('call setpos("\'d", [2, 3, 1, 0])')
- eq(getpos("'d"), {0, 3, 1, 0})
+ eq({0, 3, 1, 0}, getpos("'d"))
end)
it('can set lowercase marks in other buffers', function()
local retval = setpos("'d", {1, 2, 1, 0})
eq(0, retval)
setpos("'d", {1, 2, 1, 0})
- eq(getpos("'d"), {0, 0, 0, 0})
+ eq({0, 0, 0, 0}, getpos("'d"))
command('wincmd w')
- eq(eval('bufnr("%")'), 1)
- eq(getpos("'d"), {0, 2, 1, 0})
+ eq(1, eval('bufnr("%")'))
+ eq({0, 2, 1, 0}, getpos("'d"))
end)
it("fails when setting a mark in a buffer that doesn't exist", function()
local retval = setpos("'d", {3, 2, 1, 0})
eq(-1, retval)
- eq(getpos("'d"), {0, 0, 0, 0})
+ eq({0, 0, 0, 0}, getpos("'d"))
retval = setpos("'D", {3, 2, 1, 0})
eq(-1, retval)
- eq(getpos("'D"), {0, 0, 0, 0})
+ eq({0, 0, 0, 0}, getpos("'D"))
end)
it('can set uppercase marks', function()
setpos("'D", {2, 2, 3, 0})
- eq(getpos("'D"), {2, 2, 3, 0})
+ eq({2, 2, 3, 0}, getpos("'D"))
-- Can set a mark in another buffer
setpos("'D", {1, 2, 2, 0})
- eq(getpos("'D"), {1, 2, 2, 0})
+ eq({1, 2, 2, 0}, getpos("'D"))
end)
end)
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index 24a1f05390..c915556c57 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -1,11 +1,13 @@
local helpers = require('test.functional.helpers')(after_each)
local assert_alive = helpers.assert_alive
-local nvim_dir = helpers.nvim_dir
+local testprg = helpers.testprg
local eq, call, clear, eval, feed_command, feed, nvim =
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
helpers.feed, helpers.nvim
local command = helpers.command
+local insert = helpers.insert
+local expect = helpers.expect
local exc_exec = helpers.exc_exec
local iswin = helpers.iswin
local os_kill = helpers.os_kill
@@ -30,10 +32,6 @@ describe('system()', function()
before_each(clear)
describe('command passed as a List', function()
- local function printargs_path()
- return nvim_dir..'/printargs-test' .. (iswin() and '.exe' or '')
- end
-
it('throws error if cmd[0] is not executable', function()
eq("Vim:E475: Invalid value for argument cmd: 'this-should-not-exist' is not executable",
pcall_err(call, 'system', { 'this-should-not-exist' }))
@@ -66,23 +64,23 @@ describe('system()', function()
it('quotes arguments correctly #5280', function()
local out = call('system',
- { printargs_path(), [[1]], [[2 "3]], [[4 ' 5]], [[6 ' 7']] })
+ { testprg('printargs-test'), [[1]], [[2 "3]], [[4 ' 5]], [[6 ' 7']] })
eq(0, eval('v:shell_error'))
eq([[arg1=1;arg2=2 "3;arg3=4 ' 5;arg4=6 ' 7';]], out)
- out = call('system', { printargs_path(), [['1]], [[2 "3]] })
+ out = call('system', { testprg('printargs-test'), [['1]], [[2 "3]] })
eq(0, eval('v:shell_error'))
eq([[arg1='1;arg2=2 "3;]], out)
- out = call('system', { printargs_path(), "A\nB" })
+ out = call('system', { testprg('printargs-test'), "A\nB" })
eq(0, eval('v:shell_error'))
eq("arg1=A\nB;", out)
end)
it('calls executable in $PATH', function()
- if 0 == eval("executable('python')") then pending("missing `python`") end
- eq("foo\n", eval([[system(['python', '-c', 'print("foo")'])]]))
+ if 0 == eval("executable('python3')") then pending("missing `python3`") end
+ eq("foo\n", eval([[system(['python3', '-c', 'print("foo")'])]]))
eq(0, eval('v:shell_error'))
end)
@@ -167,7 +165,7 @@ describe('system()', function()
end
end)
- it('works with powershell', function()
+ it('with powershell', function()
helpers.set_shell_powershell()
eq('a\nb\n', eval([[system('Write-Output a b')]]))
eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]]))
@@ -175,12 +173,11 @@ describe('system()', function()
end)
end
- it('works with powershell w/ UTF-8 text (#13713)', function()
+ it('powershell w/ UTF-8 text #13713', function()
if not helpers.has_powershell() then
- pending("not tested; powershell was not found", function() end)
+ pending("powershell not found", function() end)
return
end
- -- Should work with recommended config used in helper
helpers.set_shell_powershell()
eq('ああ\n', eval([[system('Write-Output "ああ"')]]))
-- Sanity test w/ default encoding
@@ -268,7 +265,7 @@ describe('system()', function()
:call system("for /L %I in (1,0,2) do @echo y") |]]
or [[
:call system("yes") |]]))
- feed('<c-c>')
+ feed('foo<c-c>')
screen:expect([[
^ |
~ |
@@ -286,6 +283,49 @@ describe('system()', function()
Type :qa and press <Enter> to exit Nvim |
]])
end)
+
+ it('`yes` interrupted with mapped CTRL-C', function()
+ command('nnoremap <C-C> i')
+ feed(':call system("' .. (iswin()
+ and 'for /L %I in (1,0,2) do @echo y'
+ or 'yes') .. '")<cr>')
+ screen:expect([[
+ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+]] .. (iswin()
+ and [[
+ :call system("for /L %I in (1,0,2) do @echo y") |]]
+ or [[
+ :call system("yes") |]]))
+ feed('foo<c-c>')
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ end)
end)
describe('passing no input', function()
@@ -387,7 +427,7 @@ describe('system()', function()
end)
it("with a program that doesn't close stdout will exit properly after passing input", function()
- local out = eval(string.format("system('%s', 'clip-data')", nvim_dir..'/streams-test'))
+ local out = eval(string.format("system('%s', 'clip-data')", testprg('streams-test')))
assert(out:sub(0, 5) == 'pid: ', out)
os_kill(out:match("%d+"))
end)
@@ -527,7 +567,7 @@ describe('systemlist()', function()
end)
-- Unlike `system()` which uses SOH to represent NULs, with `systemlist()`
- -- input and ouput are the same.
+ -- input and output are the same.
describe('with linefeed characters inside list items', function()
it('converts linefeed characters to NULs', function()
eq({'l1\np2', 'line2\na\nb', 'l3'},
@@ -566,17 +606,16 @@ describe('systemlist()', function()
end)
it("with a program that doesn't close stdout will exit properly after passing input", function()
- local out = eval(string.format("systemlist('%s', 'clip-data')", nvim_dir..'/streams-test'))
+ local out = eval(string.format("systemlist('%s', 'clip-data')", testprg('streams-test')))
assert(out[1]:sub(0, 5) == 'pid: ', out)
os_kill(out[1]:match("%d+"))
end)
- it('works with powershell w/ UTF-8 text (#13713)', function()
+ it('powershell w/ UTF-8 text #13713', function()
if not helpers.has_powershell() then
- pending("not tested; powershell was not found", function() end)
+ pending("powershell not found", function() end)
return
end
- -- Should work with recommended config used in helper
helpers.set_shell_powershell()
eq({iswin() and 'あ\r' or 'あ'}, eval([[systemlist('Write-Output あ')]]))
-- Sanity test w/ default encoding
@@ -587,3 +626,31 @@ describe('systemlist()', function()
end)
end)
+
+describe('shell :!', function()
+ before_each(clear)
+
+ it(':{range}! with powershell filter/redirect #16271', function()
+ local screen = Screen.new(500, 8)
+ screen:attach()
+ local found = helpers.set_shell_powershell(true)
+ insert([[
+ 3
+ 1
+ 4
+ 2]])
+ feed(':4verbose %!sort<cr>')
+ screen:expect{
+ any=[[Executing command: .?Start%-Process sort %-RedirectStandardInput .* %-RedirectStandardOutput .* %-NoNewWindow %-Wait]]
+ }
+ feed('<CR>')
+ if found then
+ -- Not using fake powershell, so we can test the result.
+ expect([[
+ 1
+ 2
+ 3
+ 4]])
+ end
+ end)
+end)
diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index e45b64422f..5463cfb234 100644
--- a/test/functional/vimscript/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
@@ -96,7 +96,7 @@ describe('timers', function()
nvim_async("command", "let g:val = 0 | let g:c = getchar()")
retry(nil, nil, function()
local val = eval("g:val")
- ok(val >= 2, "expected >= 2, got: "..tostring(val))
+ ok(val >= 2, '>= 2', tostring(val))
eq(0, eval("getchar(1)"))
end)
feed("c")
@@ -272,4 +272,12 @@ describe('timers', function()
]]
eq("Vim(call):E48: Not allowed in sandbox", exc_exec("sandbox call timer_start(0, 'Scary')"))
end)
+
+ it('can be triggered after an empty string <expr> mapping #17257', function()
+ local screen = Screen.new(40, 6)
+ screen:attach()
+ command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=])
+ feed('i<F2>')
+ screen:expect({any='E605: Exception not caught: x'})
+ end)
end)
diff --git a/test/helpers.lua b/test/helpers.lua
index 87431e4342..7ec9beea92 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -4,7 +4,7 @@ local assert = require('luassert')
local luv = require('luv')
local lfs = require('lfs')
local relpath = require('pl.path').relpath
-local Paths = require('test.config.paths')
+local Paths = require('test.cmakeconfig.paths')
assert:set_parameter('TableFormatLevel', 100)
@@ -40,10 +40,6 @@ function module.popen_r(...)
return io.popen(module.argss_to_cmd(...), 'r')
end
-function module.popen_w(...)
- return io.popen(module.argss_to_cmd(...), 'w')
-end
-
-- sleeps the test runner (_not_ the nvim instance)
function module.sleep(ms)
luv.sleep(ms)
@@ -55,42 +51,31 @@ local check_logs_useless_lines = {
['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3,
}
---- Invokes `fn` and includes the tail of `logfile` in the error message if it
---- fails.
----
----@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog'
----@param fn Function to invoke
----@param ... Function arguments
-local function dumplog(logfile, fn, ...)
- -- module.validate({
- -- logfile={logfile,'s',true},
- -- fn={fn,'f',false},
- -- })
- local status, rv = pcall(fn, ...)
- if status == false then
- logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
- local logtail = module.read_nvim_log(logfile)
- error(string.format('%s\n%s', tostring(rv), logtail))
- end
+function module.eq(expected, actual, context)
+ return assert.are.same(expected, actual, context)
end
-function module.eq(expected, actual, context, logfile)
- return dumplog(logfile, assert.are.same, expected, actual, context)
+function module.neq(expected, actual, context)
+ return assert.are_not.same(expected, actual, context)
end
-function module.neq(expected, actual, context, logfile)
- return dumplog(logfile, assert.are_not.same, expected, actual, context)
-end
-function module.ok(res, msg, logfile)
- return dumplog(logfile, assert.is_true, res, msg)
+
+--- Asserts that `cond` is true, or prints a message.
+---
+--- @param cond (boolean) expression to assert
+--- @param expected (any) description of expected result
+--- @param actual (any) description of actual result
+function module.ok(cond, expected, actual)
+ assert((not expected and not actual) or (expected and actual), 'if "expected" is given, "actual" is also required')
+ local msg = expected and ('expected %s, got: %s'):format(expected, tostring(actual)) or nil
+ return assert(cond, msg)
end
--- TODO(bfredl): this should "failure" not "error" (issue with dumplog() )
local function epicfail(state, arguments, _)
state.failure_message = arguments[1]
return false
end
assert:register("assertion", "epicfail", epicfail)
-function module.fail(msg, logfile)
- return dumplog(logfile, assert.epicfail, msg)
+function module.fail(msg)
+ return assert.epicfail(msg)
end
function module.matches(pat, actual)
@@ -100,20 +85,33 @@ function module.matches(pat, actual)
error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual))
end
---- Asserts that `pat` matches one or more lines in the tail of $NVIM_LOG_FILE.
+--- Asserts that `pat` matches (or *not* if inverse=true) any line in the tail of `logfile`.
---
----@param pat (string) Lua pattern to search for in the log file.
----@param logfile (string, default=$NVIM_LOG_FILE) full path to log file.
-function module.assert_log(pat, logfile)
+---@param pat (string) Lua pattern to match lines in the log file
+---@param logfile (string) Full path to log file (default=$NVIM_LOG_FILE)
+---@param nrlines (number) Search up to this many log lines
+---@param inverse (boolean) Assert that the pattern does NOT match.
+function module.assert_log(pat, logfile, nrlines, inverse)
logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
- local nrlines = 10
+ assert(logfile ~= nil, 'no logfile')
+ nrlines = nrlines or 10
+ inverse = inverse or false
local lines = module.read_file_list(logfile, -nrlines) or {}
+ local msg = string.format('Pattern %q %sfound in log (last %d lines): %s:\n%s',
+ pat, (inverse and '' or 'not '), nrlines, logfile, ' '..table.concat(lines, '\n '))
for _,line in ipairs(lines) do
- if line:match(pat) then return end
+ if line:match(pat) then
+ if inverse then error(msg) else return end
+ end
end
- local logtail = module.read_nvim_log(logfile)
- error(string.format('Pattern %q not found in log (last %d lines): %s:\n%s',
- pat, nrlines, logfile, logtail))
+ if not inverse then error(msg) end
+end
+
+--- Asserts that `pat` does NOT matche any line in the tail of `logfile`.
+---
+--- @see assert_log
+function module.assert_nolog(pat, logfile, nrlines)
+ return module.assert_log(pat, logfile, nrlines, true)
end
-- Invokes `fn` and returns the error string (with truncated paths), or raises
@@ -271,7 +269,7 @@ module.uname = (function()
return platform
end
- if os.getenv("SYSTEM_NAME") then -- From CMAKE_SYSTEM_NAME.
+ if os.getenv("SYSTEM_NAME") then -- From CMAKE_HOST_SYSTEM_NAME.
platform = string.lower(os.getenv("SYSTEM_NAME"))
return platform
end
@@ -307,6 +305,7 @@ local function tmpdir_is_local(dir)
return not not (dir and string.find(dir, 'Xtest'))
end
+--- Creates a new temporary file for use by tests.
module.tmpname = (function()
local seq = 0
local tmpdir = tmpdir_get()
@@ -314,7 +313,8 @@ module.tmpname = (function()
if tmpdir_is_local(tmpdir) then
-- Cannot control os.tmpname() dir, so hack our own tmpname() impl.
seq = seq + 1
- local fname = tmpdir..'/nvim-test-lua-'..seq
+ -- "…/Xtest_tmpdir/T42.7"
+ local fname = ('%s/%s.%d'):format(tmpdir, (_G._nvim_test_id or 'nvim-test'), seq)
io.open(fname, 'w'):close()
return fname
else
@@ -409,17 +409,6 @@ function module.check_cores(app, force)
end
end
-function module.which(exe)
- local pipe = module.popen_r('which', exe)
- local ret = pipe:read('*a')
- pipe:close()
- if ret == '' then
- return nil
- else
- return ret:sub(1, -2)
- end
-end
-
function module.repeated_read_cmd(...)
for _ = 1, 10 do
local stream = module.popen_r(...)
@@ -801,12 +790,10 @@ end
function module.isCI(name)
local any = (name == nil)
- assert(any or name == 'appveyor' or name == 'travis' or name == 'sourcehut' or name == 'github')
- local av = ((any or name == 'appveyor') and nil ~= os.getenv('APPVEYOR'))
- local tr = ((any or name == 'travis') and nil ~= os.getenv('TRAVIS'))
+ assert(any or name == 'sourcehut' or name == 'github')
local sh = ((any or name == 'sourcehut') and nil ~= os.getenv('SOURCEHUT'))
local gh = ((any or name == 'github') and nil ~= os.getenv('GITHUB_ACTIONS'))
- return tr or av or sh or gh
+ return sh or gh
end
@@ -815,7 +802,7 @@ end
function module.read_nvim_log(logfile, ci_rename)
logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
local is_ci = module.isCI()
- local keep = is_ci and 999 or 10
+ local keep = is_ci and 100 or 10
local lines = module.read_file_list(logfile, -keep) or {}
local log = (('-'):rep(78)..'\n'
..string.format('$NVIM_LOG_FILE: %s\n', logfile)
diff --git a/test/symbolic/klee/nvim/keymap.c b/test/symbolic/klee/nvim/keymap.c
index 8bc597d7fe..26cdd9db47 100644
--- a/test/symbolic/klee/nvim/keymap.c
+++ b/test/symbolic/klee/nvim/keymap.c
@@ -1,7 +1,7 @@
#include <stdbool.h>
#include "nvim/types.h"
-#include "nvim/keymap.h"
+#include "nvim/keycodes.h"
#include "nvim/ascii.h"
#include "nvim/eval/typval.h"
diff --git a/test/symbolic/klee/run.sh b/test/symbolic/klee/run.sh
index 0234a935b5..97ce42c31b 100755
--- a/test/symbolic/klee/run.sh
+++ b/test/symbolic/klee/run.sh
@@ -54,7 +54,7 @@ main() {
includes="$includes -I$PROJECT_SOURCE_DIR/src"
includes="$includes -I$PROJECT_BINARY_DIR/src/nvim/auto"
includes="$includes -I$PROJECT_BINARY_DIR/include"
- includes="$includes -I$PROJECT_BINARY_DIR/config"
+ includes="$includes -I$PROJECT_BINARY_DIR/cmake.config"
includes="$includes -I/host-includes"
local defines=
diff --git a/test/symbolic/klee/viml_expressions_lexer.c b/test/symbolic/klee/viml_expressions_lexer.c
index ee7dc312e9..03c9d66ca4 100644
--- a/test/symbolic/klee/viml_expressions_lexer.c
+++ b/test/symbolic/klee/viml_expressions_lexer.c
@@ -17,7 +17,7 @@
#include "nvim/charset.c"
#include "nvim/garray.c"
#include "nvim/gettext.c"
-#include "nvim/keymap.c"
+#include "nvim/keycodes.c"
#include "nvim/viml/parser/expressions.c"
#define INPUT_SIZE 7
diff --git a/test/symbolic/klee/viml_expressions_parser.c b/test/symbolic/klee/viml_expressions_parser.c
index 9a876ed3fa..b0e1d71127 100644
--- a/test/symbolic/klee/viml_expressions_parser.c
+++ b/test/symbolic/klee/viml_expressions_parser.c
@@ -17,7 +17,7 @@
#include "nvim/garray.c"
#include "nvim/gettext.c"
#include "nvim/viml/parser/expressions.c"
-#include "nvim/keymap.c"
+#include "nvim/keycodes.c"
#define INPUT_SIZE 50
diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua
index 3692e19379..204d713fb7 100644
--- a/test/unit/buffer_spec.lua
+++ b/test/unit/buffer_spec.lua
@@ -17,22 +17,22 @@ describe('buffer functions', function()
return buffer.buflist_new(c_file, c_file, 1, flags)
end
- local close_buffer = function(win, buf, action, abort_if_last)
- return buffer.close_buffer(win, buf, action, abort_if_last)
+ local close_buffer = function(win, buf, action, abort_if_last, ignore_abort)
+ return buffer.close_buffer(win, buf, action, abort_if_last, ignore_abort)
end
local path1 = 'test_file_path'
local path2 = 'file_path_test'
local path3 = 'path_test_file'
- before_each(function()
+ setup(function()
-- create the files
io.open(path1, 'w').close()
io.open(path2, 'w').close()
io.open(path3, 'w').close()
end)
- after_each(function()
+ teardown(function()
os.remove(path1)
os.remove(path2)
os.remove(path3)
@@ -53,7 +53,7 @@ describe('buffer functions', function()
itp('should view a closed and hidden buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
- close_buffer(NULL, buf, 0, 0)
+ close_buffer(NULL, buf, 0, 0, 0)
eq(true, buffer.buf_valid(buf))
end)
@@ -61,7 +61,7 @@ describe('buffer functions', function()
itp('should view a closed and unloaded buffer as valid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
- close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0)
+ close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0, 0)
eq(true, buffer.buf_valid(buf))
end)
@@ -69,7 +69,7 @@ describe('buffer functions', function()
itp('should view a closed and wiped buffer as invalid', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
- close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0, 0)
eq(false, buffer.buf_valid(buf))
end)
@@ -90,7 +90,7 @@ describe('buffer functions', function()
eq(buf.handle, buflist_findpat(path1, ONLY_LISTED))
- close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0, 0)
end)
itp('should prefer to match the start of a file path', function()
@@ -102,9 +102,9 @@ describe('buffer functions', function()
eq(buf2.handle, buflist_findpat("file", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("path", ONLY_LISTED))
- close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
- close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
- close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
+ close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
+ close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
end)
itp('should prefer to match the end of a file over the middle', function()
@@ -118,7 +118,7 @@ describe('buffer functions', function()
--}
--{ When: We close buf2
- close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
-- And: Open buf1, which has 'file' in the middle of its name
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
@@ -127,8 +127,8 @@ describe('buffer functions', function()
eq(buf3.handle, buflist_findpat("file", ONLY_LISTED))
--}
- close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
- close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
+ close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
end)
itp('should match a unique fragment of a file path', function()
@@ -138,9 +138,9 @@ describe('buffer functions', function()
eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED))
- close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
- close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
- close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
+ close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
+ close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
end)
itp('should include / ignore unlisted buffers based on the flag.', function()
@@ -152,7 +152,7 @@ describe('buffer functions', function()
--}
--{ When: We unlist the buffer
- close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0)
+ close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0, 0)
-- Then: It should not find the buffer when searching only listed buffers
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
@@ -162,7 +162,7 @@ describe('buffer functions', function()
--}
--{ When: We wipe the buffer
- close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0)
-- Then: It should not find the buffer at all
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
@@ -180,7 +180,7 @@ describe('buffer functions', function()
--}
--{ When: The first buffer is unlisted
- close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0)
+ close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0, 0)
-- Then: The second buffer is preferred because
-- unlisted buffers are not allowed
@@ -194,7 +194,7 @@ describe('buffer functions', function()
--}
--{ When: We unlist the second buffer
- close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0)
+ close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0, 0)
-- Then: The first buffer is preferred again
-- because buf1 matches better which takes precedence
@@ -205,8 +205,8 @@ describe('buffer functions', function()
eq(-1, buflist_findpat("test", ONLY_LISTED))
--}
- close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
- close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
+ close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0)
+ close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0)
end)
end)
@@ -249,7 +249,7 @@ describe('buffer functions', function()
--
-- @param arg Options can be placed in an optional dictionary as the last parameter
-- .expected_cell_count The expected number of cells build_stl_str_hl will return
- -- .expected_byte_length The expected byte length of the string
+ -- .expected_byte_length The expected byte length of the string (defaults to byte length of expected_stl)
-- .file_name The name of the file to be tested (useful in %f type tests)
-- .fillchar The character that will be used to fill any 'extra' space in the stl
local function statusline_test (description,
@@ -264,7 +264,7 @@ describe('buffer functions', function()
local fillchar = option.fillchar or (' '):byte()
local expected_cell_count = option.expected_cell_count or statusline_cell_count
- local expected_byte_length = option.expected_byte_length or expected_cell_count
+ local expected_byte_length = option.expected_byte_length or #expected_stl
itp(description, function()
if option.file_name then
@@ -312,12 +312,12 @@ describe('buffer functions', function()
statusline_test('should put fillchar `~` in between text', 10,
'abc%=def', 'abc~~~~def',
{fillchar=('~'):byte()})
+ statusline_test('should put fillchar `━` in between text', 10,
+ 'abc%=def', 'abc━━━━def',
+ {fillchar=0x2501})
statusline_test('should handle zero-fillchar as a space', 10,
'abcde%=', 'abcde ',
{fillchar=0})
- statusline_test('should handle multibyte-fillchar as a dash', 10,
- 'abcde%=', 'abcde-----',
- {fillchar=0x80})
statusline_test('should print the tail file name', 80,
'%t', 'buffer_spec.lua',
{file_name='test/unit/buffer_spec.lua', expected_cell_count=15})
@@ -366,70 +366,86 @@ describe('buffer functions', function()
statusline_test('should ignore trailing %', 3, 'abc%', 'abc')
- -- alignment testing
- statusline_test('should right align when using =', 20,
- 'neo%=vim', 'neo vim')
- statusline_test('should, when possible, center text when using %=text%=', 20,
- 'abc%=neovim%=def', 'abc neovim def')
- statusline_test('should handle uneven spacing in the buffer when using %=text%=', 20,
- 'abc%=neo_vim%=def', 'abc neo_vim def')
- statusline_test('should have equal spaces even with non-equal sides when using =', 20,
- 'foobar%=test%=baz', 'foobar test baz')
- statusline_test('should have equal spaces even with longer right side when using =', 20,
- 'a%=test%=longtext', 'a test longtext')
- statusline_test('should handle an empty left side when using ==', 20,
- '%=test%=baz', ' test baz')
- statusline_test('should handle an empty right side when using ==', 20,
- 'foobar%=test%=', 'foobar test ')
- statusline_test('should handle consecutive empty ==', 20,
- '%=%=test%=', ' test ')
- statusline_test('should handle an = alone', 20,
- '%=', ' ')
- statusline_test('should right align text when it is alone with =', 20,
- '%=foo', ' foo')
- statusline_test('should left align text when it is alone with =', 20,
- 'foo%=', 'foo ')
-
- statusline_test('should approximately center text when using %=text%=', 21,
- 'abc%=neovim%=def', 'abc neovim def')
- statusline_test('should completely fill the buffer when using %=text%=', 21,
- 'abc%=neo_vim%=def', 'abc neo_vim def')
- statusline_test('should have equal spaces even with non-equal sides when using =', 21,
- 'foobar%=test%=baz', 'foobar test baz')
- statusline_test('should have equal spaces even with longer right side when using =', 21,
- 'a%=test%=longtext', 'a test longtext')
- statusline_test('should handle an empty left side when using ==', 21,
- '%=test%=baz', ' test baz')
- statusline_test('should handle an empty right side when using ==', 21,
- 'foobar%=test%=', 'foobar test ')
-
- statusline_test('should quadrant the text when using 3 %=', 40,
- 'abcd%=n%=eovim%=ef', 'abcd n eovim ef')
- statusline_test('should work well with %t', 40,
- '%t%=right_aligned', 'buffer_spec.lua right_aligned',
+ -- alignment testing with fillchar
+ local function statusline_test_align (description,
+ statusline_cell_count,
+ input_stl,
+ expected_stl,
+ arg)
+ arg = arg or {}
+ statusline_test(description .. ' without fillchar',
+ statusline_cell_count, input_stl, expected_stl:gsub('%~', ' '), arg)
+ arg.fillchar = ('!'):byte()
+ statusline_test(description .. ' with fillchar `!`',
+ statusline_cell_count, input_stl, expected_stl:gsub('%~', '!'), arg)
+ arg.fillchar = 0x2501
+ statusline_test(description .. ' with fillchar `━`',
+ statusline_cell_count, input_stl, expected_stl:gsub('%~', '━'), arg)
+ end
+
+ statusline_test_align('should right align when using =', 20,
+ 'neo%=vim', 'neo~~~~~~~~~~~~~~vim')
+ statusline_test_align('should, when possible, center text when using %=text%=', 20,
+ 'abc%=neovim%=def', 'abc~~~~neovim~~~~def')
+ statusline_test_align('should handle uneven spacing in the buffer when using %=text%=', 20,
+ 'abc%=neo_vim%=def', 'abc~~~neo_vim~~~~def')
+ statusline_test_align('should have equal spaces even with non-equal sides when using =', 20,
+ 'foobar%=test%=baz', 'foobar~~~test~~~~baz')
+ statusline_test_align('should have equal spaces even with longer right side when using =', 20,
+ 'a%=test%=longtext', 'a~~~test~~~~longtext')
+ statusline_test_align('should handle an empty left side when using ==', 20,
+ '%=test%=baz', '~~~~~~test~~~~~~~baz')
+ statusline_test_align('should handle an empty right side when using ==', 20,
+ 'foobar%=test%=', 'foobar~~~~~test~~~~~')
+ statusline_test_align('should handle consecutive empty ==', 20,
+ '%=%=test%=', '~~~~~~~~~~test~~~~~~')
+ statusline_test_align('should handle an = alone', 20,
+ '%=', '~~~~~~~~~~~~~~~~~~~~')
+ statusline_test_align('should right align text when it is alone with =', 20,
+ '%=foo', '~~~~~~~~~~~~~~~~~foo')
+ statusline_test_align('should left align text when it is alone with =', 20,
+ 'foo%=', 'foo~~~~~~~~~~~~~~~~~')
+
+ statusline_test_align('should approximately center text when using %=text%=', 21,
+ 'abc%=neovim%=def', 'abc~~~~neovim~~~~~def')
+ statusline_test_align('should completely fill the buffer when using %=text%=', 21,
+ 'abc%=neo_vim%=def', 'abc~~~~neo_vim~~~~def')
+ statusline_test_align('should have equal spacing even with non-equal sides when using =', 21,
+ 'foobar%=test%=baz', 'foobar~~~~test~~~~baz')
+ statusline_test_align('should have equal spacing even with longer right side when using =', 21,
+ 'a%=test%=longtext', 'a~~~~test~~~~longtext')
+ statusline_test_align('should handle an empty left side when using ==', 21,
+ '%=test%=baz', '~~~~~~~test~~~~~~~baz')
+ statusline_test_align('should handle an empty right side when using ==', 21,
+ 'foobar%=test%=', 'foobar~~~~~test~~~~~~')
+
+ statusline_test_align('should quadrant the text when using 3 %=', 40,
+ 'abcd%=n%=eovim%=ef', 'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~ef')
+ statusline_test_align('should work well with %t', 40,
+ '%t%=right_aligned', 'buffer_spec.lua~~~~~~~~~~~~right_aligned',
{file_name='test/unit/buffer_spec.lua'})
- statusline_test('should work well with %t and regular text', 40,
- 'l%=m_l %t m_r%=r', 'l m_l buffer_spec.lua m_r r',
+ statusline_test_align('should work well with %t and regular text', 40,
+ 'l%=m_l %t m_r%=r', 'l~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
{file_name='test/unit/buffer_spec.lua'})
- statusline_test('should work well with %=, %t, %L, and %l', 40,
- '%t %= %L %= %l', 'buffer_spec.lua 1 0',
+ statusline_test_align('should work well with %=, %t, %L, and %l', 40,
+ '%t %= %L %= %l', 'buffer_spec.lua ~~~~~~~~~ 1 ~~~~~~~~~~ 0',
{file_name='test/unit/buffer_spec.lua'})
- statusline_test('should quadrant the text when using 3 %=', 41,
- 'abcd%=n%=eovim%=ef', 'abcd n eovim ef')
- statusline_test('should work well with %t', 41,
- '%t%=right_aligned', 'buffer_spec.lua right_aligned',
+ statusline_test_align('should quadrant the text when using 3 %=', 41,
+ 'abcd%=n%=eovim%=ef', 'abcd~~~~~~~~~n~~~~~~~~~eovim~~~~~~~~~~~ef')
+ statusline_test_align('should work well with %t', 41,
+ '%t%=right_aligned', 'buffer_spec.lua~~~~~~~~~~~~~right_aligned',
{file_name='test/unit/buffer_spec.lua'})
- statusline_test('should work well with %t and regular text', 41,
- 'l%=m_l %t m_r%=r', 'l m_l buffer_spec.lua m_r r',
+ statusline_test_align('should work well with %t and regular text', 41,
+ 'l%=m_l %t m_r%=r', 'l~~~~~~~~m_l buffer_spec.lua m_r~~~~~~~~r',
{file_name='test/unit/buffer_spec.lua'})
- statusline_test('should work well with %=, %t, %L, and %l', 41,
- '%t %= %L %= %l', 'buffer_spec.lua 1 0',
+ statusline_test_align('should work well with %=, %t, %L, and %l', 41,
+ '%t %= %L %= %l', 'buffer_spec.lua ~~~~~~~~~~ 1 ~~~~~~~~~~ 0',
{file_name='test/unit/buffer_spec.lua'})
- statusline_test('should work with 10 %=', 50,
+ statusline_test_align('should work with 10 %=', 50,
'aaaa%=b%=c%=d%=e%=fg%=hi%=jk%=lmnop%=qrstuv%=wxyz',
- 'aaaa b c d e fg hi jk lmnop qrstuv wxyz')
+ 'aaaa~~b~~c~~d~~e~~fg~~hi~~jk~~lmnop~~qrstuv~~~wxyz')
-- stl item testing
local tabline = ''
@@ -452,11 +468,10 @@ describe('buffer functions', function()
-- multi-byte testing
statusline_test('should handle multibyte characters', 10,
- 'Ĉ%=x', 'Ĉ x',
- {expected_byte_length=11})
+ 'Ĉ%=x', 'Ĉ x')
statusline_test('should handle multibyte characters and different fillchars', 10,
'Ą%=mid%=end', 'Ą@mid@@end',
- {fillchar=('@'):byte(), expected_byte_length=11})
+ {fillchar=('@'):byte()})
-- escaping % testing
statusline_test('should handle escape of %', 4, 'abc%%', 'abc%')
diff --git a/test/unit/fixtures/rbuffer.c b/test/unit/fixtures/rbuffer.c
index 3f4062fa18..efa7ab1986 100644
--- a/test/unit/fixtures/rbuffer.c
+++ b/test/unit/fixtures/rbuffer.c
@@ -15,7 +15,7 @@ void ut_rbuffer_each_read_chunk(RBuffer *buf, each_ptr_cb cb)
void ut_rbuffer_each_write_chunk(RBuffer *buf, each_ptr_cb cb)
{
- RBUFFER_UNTIL_FULL(buf, wptr, wcnt) {
+ RBUFFER_UNTIL_FULL(buf, wptr, wcnt) { // -V1044
cb(wptr, wcnt);
rbuffer_produced(buf, wcnt);
}
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index 465b553693..29ea0235be 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -2,7 +2,7 @@ local ffi = require('ffi')
local formatc = require('test.unit.formatc')
local Set = require('test.unit.set')
local Preprocess = require('test.unit.preprocess')
-local Paths = require('test.config.paths')
+local Paths = require('test.cmakeconfig.paths')
local global_helpers = require('test.helpers')
local assert = require('luassert')
local say = require('say')
@@ -96,6 +96,7 @@ local init = only_separate(function()
c.func(unpack(c.args))
end
libnvim.time_init()
+ libnvim.fs_init()
libnvim.event_init()
libnvim.early_init(nil)
if child_calls_mod then
@@ -778,7 +779,8 @@ local function cppimport(path)
return cimport(Paths.test_source_path .. '/test/includes/pre/' .. path)
end
-cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h')
+cimport('./src/nvim/types.h', './src/nvim/main.h', './src/nvim/os/time.h',
+ './src/nvim/os/fs.h')
local function conv_enum(etab, eval)
local n = tonumber(eval)
diff --git a/test/unit/keymap_spec.lua b/test/unit/keycodes_spec.lua
index 595a19eb17..5bf27c9232 100644
--- a/test/unit/keymap_spec.lua
+++ b/test/unit/keycodes_spec.lua
@@ -5,9 +5,10 @@ local ffi = helpers.ffi
local eq = helpers.eq
local neq = helpers.neq
-local keymap = helpers.cimport("./src/nvim/keymap.h")
+local keymap = helpers.cimport('./src/nvim/keycodes.h')
+local NULL = helpers.NULL
-describe('keymap.c', function()
+describe('keycodes.c', function()
describe('find_special_key()', function()
local srcp = ffi.new('const unsigned char *[1]')
@@ -15,12 +16,12 @@ describe('keymap.c', function()
itp('no keycode', function()
srcp[0] = 'abc'
- eq(0, keymap.find_special_key(srcp, 3, modp, false, false, false))
+ eq(0, keymap.find_special_key(srcp, 3, modp, 0, NULL))
end)
itp('keycode with multiple modifiers', function()
srcp[0] = '<C-M-S-A>'
- neq(0, keymap.find_special_key(srcp, 9, modp, false, false, false))
+ neq(0, keymap.find_special_key(srcp, 9, modp, 0, NULL))
neq(0, modp[0])
end)
@@ -28,22 +29,22 @@ describe('keymap.c', function()
-- Compare other capitalizations to this.
srcp[0] = '<C-A>'
local all_caps_key =
- keymap.find_special_key(srcp, 5, modp, false, false, false)
+ keymap.find_special_key(srcp, 5, modp, 0, NULL)
local all_caps_mod = modp[0]
srcp[0] = '<C-a>'
eq(all_caps_key,
- keymap.find_special_key(srcp, 5, modp, false, false, false))
+ keymap.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-A>'
eq(all_caps_key,
- keymap.find_special_key(srcp, 5, modp, false, false, false))
+ keymap.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
srcp[0] = '<c-a>'
eq(all_caps_key,
- keymap.find_special_key(srcp, 5, modp, false, false, false))
+ keymap.find_special_key(srcp, 5, modp, 0, NULL))
eq(all_caps_mod, modp[0])
end)
@@ -51,20 +52,20 @@ describe('keymap.c', function()
-- Unescaped with in_string=false
srcp[0] = '<C-">'
eq(string.byte('"'),
- keymap.find_special_key(srcp, 5, modp, false, false, false))
+ keymap.find_special_key(srcp, 5, modp, 0, NULL))
-- Unescaped with in_string=true
- eq(0, keymap.find_special_key(srcp, 5, modp, false, false, true))
+ eq(0, keymap.find_special_key(srcp, 5, modp, keymap.FSK_IN_STRING, NULL))
-- Escaped with in_string=false
srcp[0] = '<C-\\">'
-- Should fail because the key is invalid
-- (more than 1 non-modifier character).
- eq(0, keymap.find_special_key(srcp, 6, modp, false, false, false))
+ eq(0, keymap.find_special_key(srcp, 6, modp, 0, NULL))
-- Escaped with in_string=true
eq(string.byte('"'),
- keymap.find_special_key(srcp, 6, modp, false, false, true))
+ keymap.find_special_key(srcp, 6, modp, keymap.FSK_IN_STRING, NULL))
end)
end)
diff --git a/test/unit/marktree_spec.lua b/test/unit/marktree_spec.lua
index 10d02d2eb4..3c96bc5f58 100644
--- a/test/unit/marktree_spec.lua
+++ b/test/unit/marktree_spec.lua
@@ -32,11 +32,11 @@ local function shadoworder(tree, shadow, iter, giveorder)
local mark = lib.marktree_itr_current(iter)
local id = tonumber(mark.id)
local spos = shadow[id]
- if (mark.row ~= spos[1] or mark.col ~= spos[2]) then
- error("invalid pos for "..id..":("..mark.row..", "..mark.col..") instead of ("..spos[1]..", "..spos[2]..")")
+ if (mark.pos.row ~= spos[1] or mark.pos.col ~= spos[2]) then
+ error("invalid pos for "..id..":("..mark.pos.row..", "..mark.pos.col..") instead of ("..spos[1]..", "..spos[2]..")")
end
- if mark.right_gravity ~= spos[3] then
- error("invalid gravity for "..id..":("..mark.row..", "..mark.col..")")
+ if lib.mt_right_test(mark) ~= spos[3] then
+ error("invalid gravity for "..id..":("..mark.pos.row..", "..mark.pos.col..")")
end
if count > 0 then
if not pos_leq(last, spos) then
@@ -87,7 +87,21 @@ local function dosplice(tree, shadow, start, old_extent, new_extent)
shadowsplice(shadow, start, old_extent, new_extent)
end
+local last_id = nil
+
+local function put(tree, row, col, gravitate)
+ last_id = last_id + 1
+ local my_id = last_id
+
+ lib.marktree_put_test(tree, my_id, row, col, gravitate);
+ return my_id
+end
+
describe('marktree', function()
+ before_each(function()
+ last_id = 0
+ end)
+
itp('works', function()
local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
local shadow = {}
@@ -97,7 +111,7 @@ describe('marktree', function()
for i = 1,100 do
for j = 1,100 do
local gravitate = (i%2) > 0
- local id = tonumber(lib.marktree_put(tree, j, i, gravitate, 0))
+ local id = put(tree, j, i, gravitate)
ok(id > 0)
eq(nil, shadow[id])
shadow[id] = {j,i,gravitate}
@@ -115,12 +129,12 @@ describe('marktree', function()
eq({}, id2pos)
for i,ipos in pairs(shadow) do
- local pos = lib.marktree_lookup(tree, i, iter)
- eq(ipos[1], pos.row)
- eq(ipos[2], pos.col)
+ local p = lib.marktree_lookup_ns(tree, -1, i, false, iter)
+ eq(ipos[1], p.pos.row)
+ eq(ipos[2], p.pos.col)
local k = lib.marktree_itr_current(iter)
- eq(ipos[1], k.row)
- eq(ipos[2], k.col, ipos[1])
+ eq(ipos[1], k.pos.row)
+ eq(ipos[2], k.pos.col, ipos[1])
lib.marktree_itr_next(tree, iter)
-- TODO(bfredl): use id2pos to check neighbour?
-- local k2 = lib.marktree_itr_current(iter)
@@ -130,8 +144,8 @@ describe('marktree', function()
lib.marktree_itr_get(tree, ipos[1], ipos[2], iter)
local k = lib.marktree_itr_current(iter)
eq(i, tonumber(k.id))
- eq(ipos[1], k.row)
- eq(ipos[2], k.col)
+ eq(ipos[1], k.pos.row)
+ eq(ipos[2], k.pos.col)
end
ok(lib.marktree_itr_first(tree, iter))
@@ -146,8 +160,8 @@ describe('marktree', function()
lib.marktree_itr_get(tree, i, 50+ci, iter)
local k = lib.marktree_itr_current(iter)
local id = tonumber(k.id)
- eq(shadow[id][1], k.row)
- eq(shadow[id][2], k.col)
+ eq(shadow[id][1], k.pos.row)
+ eq(shadow[id][2], k.pos.col)
lib.marktree_del_itr(tree, iter, false)
shadow[id] = nil
end
@@ -191,7 +205,7 @@ describe('marktree', function()
-- https://github.com/neovim/neovim/pull/14719
lib.marktree_clear(tree)
for i = 1,20 do
- lib.marktree_put(tree, i, i, false, 0)
+ put(tree, i, i, false)
end
lib.marktree_itr_get(tree, 10, 10, iter)
diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua
index a0e02b6624..71177f4c65 100644
--- a/test/unit/os/env_spec.lua
+++ b/test/unit/os/env_spec.lua
@@ -154,7 +154,7 @@ describe('env.c', function()
local value = 'TESTVALUE'
os_setenv(name, value, 1)
eq(OK, os_unsetenv(name))
- neq(os_getenv(name), value)
+ neq(value, os_getenv(name))
-- Depending on the platform the var might be unset or set as ''
assert.True(os_getenv(name) == nil or os_getenv(name) == '')
if os_getenv(name) == nil then
@@ -266,7 +266,7 @@ describe('env.c', function()
itp('does not crash #3725', function()
local name_out = ffi.new('char[100]')
- cimp.os_get_user_name(name_out, 100)
+ cimp.os_get_username(name_out, 100)
local curuser = ffi.string(name_out)
local src = to_cstr("~"..curuser.."/Vcs/django-rest-framework/rest_framework/renderers.py")
diff --git a/test/unit/os/users_spec.lua b/test/unit/os/users_spec.lua
index f92413c7de..679e76fae1 100644
--- a/test/unit/os/users_spec.lua
+++ b/test/unit/os/users_spec.lua
@@ -48,10 +48,10 @@ describe('users function', function()
end)
end)
- describe('os_get_user_name', function()
+ describe('os_get_username', function()
itp('should write the username into the buffer and return OK', function()
local name_out = ffi.new('char[100]')
- eq(OK, users.os_get_user_name(name_out, 100))
+ eq(OK, users.os_get_username(name_out, 100))
eq(current_username, ffi.string(name_out))
end)
end)
@@ -73,18 +73,18 @@ describe('users function', function()
end)
end)
- describe('os_get_user_directory', function()
+ describe('os_get_userdir', function()
itp('should return NULL if called with NULL', function()
- eq(NULL, users.os_get_user_directory(NULL))
+ eq(NULL, users.os_get_userdir(NULL))
end)
itp('should return $HOME for the current user', function()
local home = os.getenv('HOME')
- eq(home, ffi.string((users.os_get_user_directory(current_username))))
+ eq(home, ffi.string((users.os_get_userdir(current_username))))
end)
itp('should return NULL if the user is not found', function()
- eq(NULL, users.os_get_user_directory('neovim_user_not_found_test'))
+ eq(NULL, users.os_get_userdir('neovim_user_not_found_test'))
end)
end)
end)
diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua
index 15ce59747e..fb476397e6 100644
--- a/test/unit/path_spec.lua
+++ b/test/unit/path_spec.lua
@@ -626,4 +626,20 @@ describe('path.c', function()
eq(false, path_with_extension('/some/path/file', 'lua'))
end)
end)
+
+ describe('path_with_url', function()
+ itp('scheme is alpha and inner hyphen only', function()
+ local function path_with_url(fname)
+ return cimp.path_with_url(to_cstr(fname))
+ end
+ eq(1, path_with_url([[test://xyz/foo/b0]]))
+ eq(2, path_with_url([[test:\\xyz\foo\b0]]))
+ eq(0, path_with_url([[test+abc://xyz/foo/b1]]))
+ eq(0, path_with_url([[test_abc://xyz/foo/b2]]))
+ eq(1, path_with_url([[test-abc://xyz/foo/b3]]))
+ eq(2, path_with_url([[test-abc:\\xyz\foo\b3]]))
+ eq(0, path_with_url([[-test://xyz/foo/b4]]))
+ eq(0, path_with_url([[test-://xyz/foo/b5]]))
+ end)
+ end)
end)
diff --git a/test/unit/search_spec.lua b/test/unit/search_spec.lua
index 3c2d485e0e..ce37ebfc3a 100644
--- a/test/unit/search_spec.lua
+++ b/test/unit/search_spec.lua
@@ -5,6 +5,8 @@ local to_cstr = helpers.to_cstr
local eq = helpers.eq
local search = helpers.cimport("./src/nvim/search.h")
+local globals = helpers.cimport('./src/nvim/globals.h')
+local ffi = helpers.ffi
itp('pat_has_uppercase', function()
-- works on empty string
@@ -31,3 +33,25 @@ itp('pat_has_uppercase', function()
eq(false, search.pat_has_uppercase(to_cstr("aa\\%Ab")))
eq(true, search.pat_has_uppercase(to_cstr("aab\\%AU")))
end)
+
+describe('search_regcomp', function()
+ local search_regcomp = function(pat, pat_save, pat_use, options )
+ local regmatch = ffi.new("regmmatch_T")
+ local fail = search.search_regcomp(to_cstr(pat), pat_save, pat_use, options, regmatch)
+ return fail, regmatch
+ end
+
+ local get_search_pat = function()
+ return helpers.internalize(search.get_search_pat())
+ end
+
+ itp("accepts regexp pattern with invalid utf", function()
+ --crafted to call reverse_text with invalid utf
+ globals.curwin.w_onebuf_opt.wo_rl = 1
+ globals.curwin.w_onebuf_opt.wo_rlc = to_cstr('s')
+ globals.cmdmod.cmod_flags = globals.CMOD_KEEPPATTERNS
+ local fail = search_regcomp("a\192", 0,0,0)
+ eq(1, fail)
+ eq("\192a", get_search_pat())
+ end)
+end)
diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua
index e54c82b26a..b2c839f25c 100644
--- a/test/unit/strings_spec.lua
+++ b/test/unit/strings_spec.lua
@@ -138,3 +138,50 @@ describe('vim_strchr()', function()
eq(nil, vim_strchr('«\237\175\191\237\188\128»', 0x10FF00))
end)
end)
+
+describe('strcase_save()' , function()
+ local strcase_save = function(input_string, upper)
+ local res = strings.strcase_save(to_cstr(input_string), upper)
+ return ffi.string(res)
+ end
+
+ itp('decodes overlong encoded characters.', function()
+ eq("A", strcase_save("\xc1\x81", true))
+ eq("a", strcase_save("\xc1\x81", false))
+ end)
+end)
+
+describe("reverse_text", function()
+ local reverse_text = function(str)
+ return helpers.internalize(strings.reverse_text(to_cstr(str)))
+ end
+
+ itp("handles empty string", function()
+ eq("", reverse_text(""))
+ end)
+
+ itp("handles simple cases", function()
+ eq("a", reverse_text("a"))
+ eq("ba", reverse_text("ab"))
+ end)
+
+ itp("handles multibyte characters", function()
+ eq("bα", reverse_text("αb"))
+ eq("Yötön yö", reverse_text("öy nötöY"))
+ end)
+
+ itp("handles combining chars", function()
+ local utf8_COMBINING_RING_ABOVE = "\204\138"
+ local utf8_COMBINING_RING_BELOW = "\204\165"
+ eq("bba" .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. "aa",
+ reverse_text("aaa" .. utf8_COMBINING_RING_ABOVE .. utf8_COMBINING_RING_BELOW .. "bb"))
+ end)
+
+ itp("treats invalid utf as separate characters", function()
+ eq("\192ba", reverse_text("ab\192"))
+ end)
+
+ itp("treats an incomplete utf continuation sequence as valid", function()
+ eq("\194ba", reverse_text("ab\194"))
+ end)
+end)
diff --git a/test/unit/tempfile_spec.lua b/test/unit/tempfile_spec.lua
index c05abfd640..44bd19c1d2 100644
--- a/test/unit/tempfile_spec.lua
+++ b/test/unit/tempfile_spec.lua
@@ -24,7 +24,7 @@ describe('tempfile related functions', function()
end
describe('vim_gettempdir', function()
- itp('returns path to Neovim own temp directory', function()
+ itp('returns path to Nvim own temp directory', function()
local dir = vim_gettempdir()
assert.True(dir ~= nil and dir:len() > 0)
-- os_file_is_writable returns 2 for a directory which we have rights
@@ -36,9 +36,7 @@ describe('tempfile related functions', function()
end)
itp('returns the same directory on each call', function()
- local dir1 = vim_gettempdir()
- local dir2 = vim_gettempdir()
- eq(dir1, dir2)
+ eq(vim_gettempdir(), vim_gettempdir())
end)
end)
@@ -54,12 +52,10 @@ describe('tempfile related functions', function()
end)
itp('generate different names on each call', function()
- local fst = vim_tempname()
- local snd = vim_tempname()
- neq(fst, snd)
+ neq(vim_tempname(), vim_tempname())
end)
- itp('generate file name in Neovim own temp directory', function()
+ itp('generate file name in Nvim own temp directory', function()
local dir = vim_gettempdir()
local file = vim_tempname()
eq(string.sub(file, 1, string.len(dir)), dir)
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index 8342044b5e..51a703b593 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -48,6 +48,7 @@ local predefined_hl_defs = {
TermCursor=true,
VertSplit=true,
WildMenu=true,
+ WinSeparator=true,
EndOfBuffer=true,
QuickFixLine=true,
Substitute=true,