aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake.deps/CMakeLists.txt18
-rw-r--r--cmake/GenerateVersion.cmake48
-rw-r--r--runtime/doc/change.txt3
-rw-r--r--runtime/doc/vim_diff.txt4
-rw-r--r--runtime/lua/vim/lsp.lua13
-rw-r--r--runtime/lua/vim/treesitter/query.lua15
-rw-r--r--runtime/syntax/lsp_markdown.vim27
-rwxr-xr-xscripts/update_version_stamp.lua54
-rwxr-xr-xsrc/nvim/CMakeLists.txt40
-rw-r--r--src/nvim/buffer.c36
-rw-r--r--src/nvim/eval.c32
-rw-r--r--src/nvim/eval/funcs.c11
-rw-r--r--src/nvim/ex_cmds.c13
-rw-r--r--src/nvim/ex_cmds2.c6
-rw-r--r--src/nvim/ex_docmd.c16
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/ex_session.c6
-rw-r--r--src/nvim/fileio.c30
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/mapping.c4
-rw-r--r--src/nvim/match.c8
-rw-r--r--src/nvim/message.c2
-rw-r--r--src/nvim/move.c6
-rw-r--r--src/nvim/normal.c3
-rw-r--r--src/nvim/popupmnu.c3
-rw-r--r--src/nvim/regexp.c7
-rw-r--r--src/nvim/screen.c8
-rw-r--r--src/nvim/search.c34
-rw-r--r--src/nvim/spellfile.c10
-rw-r--r--src/nvim/tag.c3
-rw-r--r--src/nvim/testdir/runtest.vim19
-rw-r--r--src/nvim/testdir/setup.vim61
-rw-r--r--src/nvim/testdir/test_arglist.vim42
-rw-r--r--src/nvim/testdir/test_assert.vim20
-rw-r--r--src/nvim/testdir/test_autocmd.vim29
-rw-r--r--src/nvim/testdir/test_buffer.vim5
-rw-r--r--src/nvim/testdir/test_changelist.vim2
-rw-r--r--src/nvim/testdir/test_charsearch.vim14
-rw-r--r--src/nvim/testdir/test_clientserver.vim8
-rw-r--r--src/nvim/testdir/test_cmdline.vim164
-rw-r--r--src/nvim/testdir/test_compiler.vim4
-rw-r--r--src/nvim/testdir/test_digraph.vim10
-rw-r--r--src/nvim/testdir/test_edit.vim70
-rw-r--r--src/nvim/testdir/test_ex_mode.vim85
-rw-r--r--src/nvim/testdir/test_excmd.vim189
-rw-r--r--src/nvim/testdir/test_expand.vim47
-rw-r--r--src/nvim/testdir/test_filechanged.vim2
-rw-r--r--src/nvim/testdir/test_filetype.vim24
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim8
-rw-r--r--src/nvim/testdir/test_findfile.vim6
-rw-r--r--src/nvim/testdir/test_global.vim12
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim5
-rw-r--r--src/nvim/testdir/test_history.vim51
-rw-r--r--src/nvim/testdir/test_increment.vim8
-rw-r--r--src/nvim/testdir/test_join.vim6
-rw-r--r--src/nvim/testdir/test_mapping.vim7
-rw-r--r--src/nvim/testdir/test_marks.vim27
-rw-r--r--src/nvim/testdir/test_move.vim1
-rw-r--r--src/nvim/testdir/test_normal.vim266
-rw-r--r--src/nvim/testdir/test_options.vim32
-rw-r--r--src/nvim/testdir/test_plus_arg_edit.vim2
-rw-r--r--src/nvim/testdir/test_put.vim10
-rw-r--r--src/nvim/testdir/test_quickfix.vim30
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim142
-rw-r--r--src/nvim/testdir/test_registers.vim14
-rw-r--r--src/nvim/testdir/test_search.vim211
-rw-r--r--src/nvim/testdir/test_smartindent.vim66
-rw-r--r--src/nvim/testdir/test_sort.vim16
-rw-r--r--src/nvim/testdir/test_source.vim31
-rw-r--r--src/nvim/testdir/test_spell.vim10
-rw-r--r--src/nvim/testdir/test_substitute.vim37
-rw-r--r--src/nvim/testdir/test_swap.vim41
-rw-r--r--src/nvim/testdir/test_tabpage.vim14
-rw-r--r--src/nvim/testdir/test_tagjump.vim243
-rw-r--r--src/nvim/testdir/test_textformat.vim75
-rw-r--r--src/nvim/testdir/test_timers.vim99
-rw-r--r--src/nvim/testdir/test_trycatch.vim41
-rw-r--r--src/nvim/testdir/test_undo.vim2
-rw-r--r--src/nvim/testdir/test_vimscript.vim119
-rw-r--r--src/nvim/testdir/test_visual.vim13
-rw-r--r--src/nvim/testdir/test_window_cmd.vim178
-rw-r--r--src/nvim/testdir/test_writefile.vim2
-rw-r--r--src/nvim/testing.c72
-rw-r--r--src/nvim/window.c1
-rw-r--r--test/functional/legacy/arglist_spec.lua45
-rw-r--r--test/functional/legacy/cpoptions_spec.lua34
-rw-r--r--test/functional/legacy/ex_mode_spec.lua83
-rw-r--r--test/functional/legacy/excmd_spec.lua156
-rw-r--r--test/functional/legacy/filechanged_spec.lua2
-rw-r--r--test/functional/ui/highlight_spec.lua34
-rw-r--r--test/functional/ui/messages_spec.lua47
-rw-r--r--test/functional/ui/searchhl_spec.lua219
-rw-r--r--test/functional/vimscript/input_spec.lua14
93 files changed, 3266 insertions, 525 deletions
diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt
index 27374a2a9a..5427382783 100644
--- a/cmake.deps/CMakeLists.txt
+++ b/cmake.deps/CMakeLists.txt
@@ -140,15 +140,15 @@ set(HOSTDEPS_CXX_COMPILER "${DEPS_CXX_COMPILER}")
include(ExternalProject)
-set(LIBUV_URL https://github.com/libuv/libuv/archive/730e07e2f77a4001bdf6894112271c926399f5a8.tar.gz)
-set(LIBUV_SHA256 271869759a7dbdaf1d1bf75f1ec388a7307592153b34ebb52d3934715cbaac8a)
+set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.44.2.tar.gz)
+set(LIBUV_SHA256 e6e2ba8b4c349a4182a33370bb9be5e23c51b32efb9b9e209d0e8556b73a48da)
set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/c-4.0.0/msgpack-c-4.0.0.tar.gz)
set(MSGPACK_SHA256 420fe35e7572f2a168d17e660ef981a589c9cbe77faa25eb34a520e1fcc032c8)
# https://github.com/LuaJIT/LuaJIT/tree/v2.1
-set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/4ef96cff887c268cc676f9b4b1dc9c54a693efd5.tar.gz)
-set(LUAJIT_SHA256 ae913e33be80dded08a2fc368787f168305c22808519c962553bf4c8668e9856)
+set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/50936d784474747b4569d988767f1b5bab8bb6d0.tar.gz)
+set(LUAJIT_SHA256 4d44e4709130b031c1c2c81cf5c102dfce877bf454409dabba03249e18870e66)
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)
@@ -165,9 +165,9 @@ set(LIBTERMKEY_SHA256 6945bd3c4aaa83da83d80a045c5563da4edd7d0374c62c0d35aec09eb3
set(LIBVTERM_URL https://www.leonerd.org.uk/code/libvterm/libvterm-0.1.4.tar.gz)
set(LIBVTERM_SHA256 bc70349e95559c667672fc8c55b9527d9db9ada0fb80a3beda533418d782d3dd)
-set(LUV_VERSION 1.43.0-0)
-set(LUV_URL https://github.com/luvit/luv/archive/9f80386338af7d164ff1f47d480ee1ae775cb0ef.tar.gz)
-set(LUV_SHA256 a6fe420f06944c0d84a173fccff2eb0d14dfd1293bc24666a580b98dd1a7254f)
+set(LUV_VERSION 1.44.2-0)
+set(LUV_URL https://github.com/luvit/luv/archive/1.44.2-0.tar.gz)
+set(LUV_SHA256 44ccda27035bfe683e6325a2a93f2c254be1eb76bde6efc2bd37c56a7af7b00a)
set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.9.tar.gz)
set(LUA_COMPAT53_SHA256 ad05540d2d96a48725bb79a1def35cf6652a4e2ec26376e2617c8ce2baa6f416)
@@ -193,8 +193,8 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891
set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.1.tar.gz)
set(TREESITTER_C_SHA256 ffcc2ef0eded59ad1acec9aec4f9b0c7dd209fc1a85d85f8b0e81298e3dddcc2)
-set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.6.tar.gz)
-set(TREESITTER_SHA256 4d37eaef8a402a385998ff9aca3e1043b4a3bba899bceeff27a7178e1165b9de)
+set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/1f1b1eb4501ed0a2d195d37f7de15f72aa10acd0.tar.gz)
+set(TREESITTER_SHA256 a324bdb7ff507cd5157a36b908224d60ba638f8e3363070dd51aa383c7cbd790)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)
diff --git a/cmake/GenerateVersion.cmake b/cmake/GenerateVersion.cmake
new file mode 100644
index 0000000000..b9313f2498
--- /dev/null
+++ b/cmake/GenerateVersion.cmake
@@ -0,0 +1,48 @@
+# Handle generating version from Git.
+set(use_git_version 0)
+if(NVIM_VERSION_MEDIUM)
+ message(STATUS "USING NVIM_VERSION_MEDIUM: ${NVIM_VERSION_MEDIUM}")
+ return()
+endif()
+
+find_program(GIT_EXECUTABLE git)
+if(NOT GIT_EXECUTABLE)
+ message(AUTHOR_WARNING "Skipping version-string generation (cannot find git)")
+ file(WRITE "${OUTPUT}" "")
+ return()
+endif()
+
+execute_process(
+ COMMAND git describe --first-parent --tags --always --dirty
+ OUTPUT_VARIABLE GIT_TAG
+ ERROR_VARIABLE ERR
+ RESULT_VARIABLE RES
+)
+
+if("${RES}" EQUAL 1)
+ if(EXISTS ${OUTPUT})
+ message(STATUS "Unable to extract version-string from git: keeping the last known version")
+ else()
+ # this will only be executed once since the file will get generated afterwards
+ message(AUTHOR_WARNING "Git tag extraction failed with: " "${ERR}")
+ file(WRITE "${OUTPUT}" "")
+ endif()
+ return()
+endif()
+
+string(STRIP "${GIT_TAG}" GIT_TAG)
+string(REGEX REPLACE "^v[0-9]+.[0-9]+.[0-9]+-" "" NVIM_VERSION_GIT "${GIT_TAG}")
+set(NVIM_VERSION_MEDIUM
+ "v${NVIM_VERSION_MAJOR}.${NVIM_VERSION_MINOR}.${NVIM_VERSION_PATCH}-dev-${NVIM_VERSION_GIT}"
+)
+set(NVIM_VERSION_STRING "#define NVIM_VERSION_MEDIUM \"${NVIM_VERSION_MEDIUM}\"\n")
+string(SHA1 CURRENT_VERSION_HASH "${NVIM_VERSION_STRING}")
+
+if(EXISTS ${OUTPUT})
+ file(SHA1 "${OUTPUT}" NVIM_VERSION_HASH)
+endif()
+
+if(NOT "${NVIM_VERSION_HASH}" STREQUAL "${CURRENT_VERSION_HASH}")
+ message(STATUS "Updating NVIM_VERSION_MEDIUM: ${NVIM_VERSION_MEDIUM}")
+ file(WRITE "${OUTPUT}" "${NVIM_VERSION_STRING}")
+endif()
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 571fbaec95..b905f53db7 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -633,6 +633,9 @@ Directory for temporary files is created in the first possible directory of:
actually work differently. You can use `:&&` to keep
the flags.
+ *&-default*
+ Mapped to ":&&<CR>" by default. |default-mappings|
+
*g&*
g& Synonym for `:%s//~/&` (repeat last substitute with
last search pattern on all lines with the same flags).
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 8e853aaf9e..bacf160206 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -89,6 +89,7 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y".
inoremap <C-W> <C-G>u<C-W>
xnoremap * y/\V<C-R>"<CR>
xnoremap # y?\V<C-R>"<CR>
+ nnoremap & :&&<CR>
<
Default Autocommands ~
*default-autocmds*
@@ -350,7 +351,8 @@ Commands:
Functions:
|input()| and |inputdialog()| support for each other’s features (return on
cancel and completion respectively) via dictionary argument (replaces all
- other arguments if used).
+ other arguments if used), and "cancelreturn" can have any type if passed in
+ a dictionary.
|input()| and |inputdialog()| support user-defined cmdline highlighting.
Highlight groups:
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 554b5f0bfa..0e72aae188 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -739,13 +739,18 @@ function lsp.start(config, opts)
end
config.name = config.name or (config.cmd[1] and vim.fs.basename(config.cmd[1])) or nil
local bufnr = api.nvim_get_current_buf()
- for _, client in pairs(lsp.get_active_clients()) do
- if reuse_client(client, config) then
- lsp.buf_attach_client(bufnr, client.id)
- return client.id
+ for _, clients in ipairs({ uninitialized_clients, lsp.get_active_clients() }) do
+ for _, client in pairs(clients) do
+ if reuse_client(client, config) then
+ lsp.buf_attach_client(bufnr, client.id)
+ return client.id
+ end
end
end
local client_id = lsp.start_client(config)
+ if client_id == nil then
+ return nil -- lsp.start_client will have printed an error
+ end
lsp.buf_attach_client(bufnr, client_id)
return client_id
end
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 0cc2b6d2a4..103e85abfd 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -221,6 +221,9 @@ end
local predicate_handlers = {
['eq?'] = function(match, _, source, predicate)
local node = match[predicate[2]]
+ if not node then
+ return true
+ end
local node_text = M.get_node_text(node, source)
local str
@@ -241,6 +244,9 @@ local predicate_handlers = {
['lua-match?'] = function(match, _, source, predicate)
local node = match[predicate[2]]
+ if not node then
+ return true
+ end
local regex = predicate[3]
return string.find(M.get_node_text(node, source), regex)
end,
@@ -265,6 +271,9 @@ local predicate_handlers = {
return function(match, _, source, pred)
local node = match[pred[2]]
+ if not node then
+ return true
+ end
local regex = compiled_vim_regexes[pred[3]]
return regex:match_str(M.get_node_text(node, source))
end
@@ -272,6 +281,9 @@ local predicate_handlers = {
['contains?'] = function(match, _, source, predicate)
local node = match[predicate[2]]
+ if not node then
+ return true
+ end
local node_text = M.get_node_text(node, source)
for i = 3, #predicate do
@@ -285,6 +297,9 @@ local predicate_handlers = {
['any-of?'] = function(match, _, source, predicate)
local node = match[predicate[2]]
+ if not node then
+ return true
+ end
local node_text = M.get_node_text(node, source)
-- Since 'predicate' will not be used by callers of this function, use it
diff --git a/runtime/syntax/lsp_markdown.vim b/runtime/syntax/lsp_markdown.vim
index 90d3185673..4be7595807 100644
--- a/runtime/syntax/lsp_markdown.vim
+++ b/runtime/syntax/lsp_markdown.vim
@@ -1,23 +1,34 @@
" Vim syntax file
-" Language: lsp_markdown
-" Maintainer: Michael Lingelbach <m.j.lbach@gmail.com
-" URL: http://neovim.io
-" Remark: Uses markdown syntax file
+" Language: Markdown-like LSP docstrings
+" Maintainer: https://github.com/neovim/neovim
+" URL: http://neovim.io
+" Remark: Uses markdown syntax file
-" always source the system included markdown instead of any other installed
-" markdown.vim syntax files
+" Source the default Nvim markdown syntax, not other random ones.
execute 'source' expand('<sfile>:p:h') .. '/markdown.vim'
syn cluster mkdNonListItem add=mkdEscape,mkdNbsp
+" Don't highlight invalid markdown syntax in LSP docstrings.
+syn clear markdownError
+
syn clear markdownEscape
syntax region markdownEscape matchgroup=markdownEscape start=/\\\ze[\\\x60*{}\[\]()#+\-,.!_>~|"$%&'\/:;<=?@^ ]/ end=/./ containedin=ALL keepend oneline concealends
-" conceal html entities
+" Conceal backticks (which delimit code fragments).
+" We ignore g:markdown_syntax_conceal here.
+syn region markdownCode matchgroup=markdownCodeDelimiter start="`" end="`" keepend contains=markdownLineStart concealends
+syn region markdownCode matchgroup=markdownCodeDelimiter start="`` \=" end=" \=``" keepend contains=markdownLineStart concealends
+syn region markdownCode matchgroup=markdownCodeDelimiter start="^\s*````*.*$" end="^\s*````*\ze\s*$" keepend concealends
+
+" Highlight code fragments.
+hi def link markdownCode Special
+
+" Conceal HTML entities.
syntax match mkdNbsp /&nbsp;/ conceal cchar=
syntax match mkdLt /&lt;/ conceal cchar=<
syntax match mkdGt /&gt;/ conceal cchar=>
syntax match mkdAmp /&amp;/ conceal cchar=&
syntax match mkdQuot /&quot;/ conceal cchar="
-hi def link mkdEscape special
+hi def link mkdEscape Special
diff --git a/scripts/update_version_stamp.lua b/scripts/update_version_stamp.lua
deleted file mode 100755
index 0342e08f31..0000000000
--- a/scripts/update_version_stamp.lua
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env lua
---
--- Script to update the Git version stamp during build.
--- This is called via the custom update_version_stamp target in
--- src/nvim/CMakeLists.txt.
---
--- arg[1]: file in which to update the version string
--- arg[2]: prefix to use always ("vX.Y.Z")
-
-local function die(msg)
- io.stderr:write(string.format('%s: %s\n', arg[0], msg))
- -- No error, fall back to using generated "-dev" version.
- os.exit(0)
-end
-
-local function iswin()
- return package.config:sub(1,1) == '\\'
-end
-
-if #arg ~= 2 then
- die(string.format("Expected two args, got %d", #arg))
-end
-
-local versiondeffile = arg[1]
-local prefix = arg[2]
-
-local dev_null = iswin() and 'NUL' or '/dev/null'
-local described = io.popen('git describe --first-parent --dirty 2>'..dev_null):read('*l')
-if not described then
- described = io.popen('git describe --first-parent --tags --always --dirty'):read('*l')
-end
-if not described then
- io.open(versiondeffile, 'w'):write('\n')
- die('git-describe failed, using empty include file.')
-end
-
--- `git describe` annotates the most recent tagged release; for pre-release
--- builds we append that to the dev version
-local with_prefix = prefix
-if prefix:match('-dev$') ~= nil then
- with_prefix = prefix .. '+' .. described:gsub('^v%d+%.%d+%.%d+-', '')
-end
-
--- Read existing include file.
-local current = io.open(versiondeffile, 'r')
-if current then
- current = current:read('*l')
-end
-
--- Write new include file, if different.
-local new = '#define NVIM_VERSION_MEDIUM "'..with_prefix..'"'
-if current ~= new then
- io.open(versiondeffile, 'w'):write(new .. '\n')
-end
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index de4af8e77b..360993de68 100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -222,31 +222,17 @@ function(get_preproc_output varname iname)
endif()
endfunction()
-# Handle generating version from Git.
-set(use_git_version 0)
-if(NVIM_VERSION_MEDIUM)
- message(STATUS "NVIM_VERSION_MEDIUM: ${NVIM_VERSION_MEDIUM}")
-elseif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
- find_program(GIT_EXECUTABLE git)
- if(GIT_EXECUTABLE)
- message(STATUS "Using NVIM_VERSION_MEDIUM from Git")
- set(use_git_version 1)
- else()
- message(STATUS "Skipping version-string generation (cannot find git)")
- endif()
-endif()
-if(use_git_version)
- # Create a update_version_stamp target to update the version during build.
- file(RELATIVE_PATH relbuild "${PROJECT_SOURCE_DIR}" "${CMAKE_BINARY_DIR}")
- add_custom_target(update_version_stamp ALL
- COMMAND ${LUA_PRG} scripts/update_version_stamp.lua
- ${relbuild}/cmake.config/auto/versiondef_git.h
- "v${NVIM_VERSION_MAJOR}.${NVIM_VERSION_MINOR}.${NVIM_VERSION_PATCH}${NVIM_VERSION_PRERELEASE}"
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
- BYPRODUCTS ${CMAKE_BINARY_DIR}/cmake.config/auto/versiondef_git.h)
-else()
- file(WRITE ${CMAKE_BINARY_DIR}/cmake.config/auto/versiondef_git.h "")
-endif()
+set(NVIM_VERSION_GIT_H ${PROJECT_BINARY_DIR}/cmake.config/auto/versiondef_git.h)
+add_custom_target(update_version_stamp
+ COMMAND ${CMAKE_COMMAND}
+ -DNVIM_VERSION_MAJOR=${NVIM_VERSION_MAJOR}
+ -DNVIM_VERSION_MINOR=${NVIM_VERSION_MINOR}
+ -DNVIM_VERSION_PATCH=${NVIM_VERSION_PATCH}
+ -DNVIM_VERSION_PRERELEASE=${NVIM_VERSION_PRERELEASE}
+ -DOUTPUT=${NVIM_VERSION_GIT_H}
+ -P ${PROJECT_SOURCE_DIR}/cmake/GenerateVersion.cmake
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ BYPRODUCTS ${NVIM_VERSION_GIT_H})
# NVIM_GENERATED_FOR_HEADERS: generated headers to be included in headers
# NVIM_GENERATED_FOR_SOURCES: generated headers to be included in sources
@@ -280,9 +266,9 @@ foreach(sfile ${NVIM_SOURCES}
get_preproc_output(PREPROC_OUTPUT ${gf_i})
set(depends "${HEADER_GENERATOR}" "${sfile}")
- if(use_git_version AND "${f}" STREQUAL "version.c")
+ if("${f}" STREQUAL "version.c")
# Ensure auto/versiondef_git.h exists after "make clean".
- list(APPEND depends update_version_stamp)
+ list(APPEND depends "${NVIM_VERSION_GIT_H}")
endif()
add_custom_command(
OUTPUT "${gf_c_h}" "${gf_h_h}"
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 7e1eae9632..f937450107 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -94,11 +94,19 @@ static char *e_buflocked = N_("E937: Attempt to delete a buffer that is in use")
// Number of times free_buffer() was called.
static int buf_free_count = 0;
+static int top_file_num = 1; ///< highest file number
+
typedef enum {
kBffClearWinInfo = 1,
kBffInitChangedtick = 2,
} BufFreeFlags;
+/// @return the highest possible buffer number
+int get_highest_fnum(void)
+{
+ return top_file_num - 1;
+}
+
/// Read data from buffer for retrying.
///
/// @param read_stdin read file from stdin, otherwise fifo
@@ -443,6 +451,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
return false;
}
+ // check no autocommands closed the window
if (win != NULL // Avoid bogus clang warning.
&& win_valid_any_tab(win)) {
// Set b_last_cursor when closing the last window for the buffer.
@@ -1643,8 +1652,6 @@ void no_write_message_nobang(const buf_T *const buf)
// functions for dealing with the buffer list
//
-static int top_file_num = 1; ///< highest file number
-
/// Initialize b:changedtick and changedtick_val attribute
///
/// @param[out] buf Buffer to initialize for.
@@ -3136,18 +3143,16 @@ void maketitle(void)
if (*p_titlestring != NUL) {
if (stl_syntax & STL_IN_TITLE) {
int use_sandbox = false;
- int save_called_emsg = called_emsg;
+ const int called_emsg_before = called_emsg;
use_sandbox = was_set_insecurely(curwin, "titlestring", 0);
- called_emsg = false;
build_stl_str_hl(curwin, buf, sizeof(buf),
(char *)p_titlestring, use_sandbox,
0, maxlen, NULL, NULL);
title_str = buf;
- if (called_emsg) {
+ if (called_emsg > called_emsg_before) {
set_string_option_direct("titlestring", -1, "", OPT_FREE, SID_ERROR);
}
- called_emsg |= save_called_emsg;
} else {
title_str = (char *)p_titlestring;
}
@@ -3252,17 +3257,15 @@ void maketitle(void)
if (*p_iconstring != NUL) {
if (stl_syntax & STL_IN_ICON) {
int use_sandbox = false;
- int save_called_emsg = called_emsg;
+ const int called_emsg_before = called_emsg;
use_sandbox = was_set_insecurely(curwin, "iconstring", 0);
- called_emsg = false;
build_stl_str_hl(curwin, icon_str, sizeof(buf),
(char *)p_iconstring, use_sandbox,
0, 0, NULL, NULL);
- if (called_emsg) {
+ if (called_emsg > called_emsg_before) {
set_string_option_direct("iconstring", -1, "", OPT_FREE, SID_ERROR);
}
- called_emsg |= save_called_emsg;
} else {
icon_str = (char *)p_iconstring;
}
@@ -5268,9 +5271,9 @@ bool bt_terminal(const buf_T *const buf)
return buf != NULL && buf->b_p_bt[0] == 't';
}
-/// @return true if "buf" is a "nofile", "acwrite", "terminal" or "prompt" /
+/// @return true if "buf" is a "nofile", "acwrite", "terminal" or "prompt"
/// buffer. This means the buffer name is not a file name.
-bool bt_nofile(const buf_T *const buf)
+bool bt_nofilename(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f')
@@ -5279,6 +5282,13 @@ bool bt_nofile(const buf_T *const buf)
|| buf->b_p_bt[0] == 'p');
}
+/// @return true if "buf" has 'buftype' set to "nofile".
+bool bt_nofile(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return buf != NULL && buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f';
+}
+
/// @return true if "buf" is a "nowrite", "nofile", "terminal" or "prompt"
/// buffer.
bool bt_dontwrite(const buf_T *const buf)
@@ -5330,7 +5340,7 @@ char *buf_spname(buf_T *buf)
}
// There is no _file_ when 'buftype' is "nofile", b_sfname
// contains the name as specified by the user.
- if (bt_nofile(buf)) {
+ if (bt_nofilename(buf)) {
if (buf->b_fname != NULL) {
return buf->b_fname;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index c7173c2078..096fcba981 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6554,7 +6554,8 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
const char *prompt = "";
const char *defstr = "";
- const char *cancelreturn = NULL;
+ typval_T *cancelreturn = NULL;
+ typval_T cancelreturn_strarg2 = TV_INITIAL_VALUE;
const char *xp_name = NULL;
Callback input_callback = { .type = kCallbackNone };
char prompt_buf[NUMBUFLEN];
@@ -6576,13 +6577,9 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
if (defstr == NULL) {
return;
}
- cancelreturn = tv_dict_get_string_buf_chk(dict, S_LEN("cancelreturn"),
- cancelreturn_buf, def);
- if (cancelreturn == NULL) { // error
- return;
- }
- if (*cancelreturn == NUL) {
- cancelreturn = NULL;
+ dictitem_T *cancelreturn_di = tv_dict_find(dict, S_LEN("cancelreturn"));
+ if (cancelreturn_di != NULL) {
+ cancelreturn = &cancelreturn_di->di_tv;
}
xp_name = tv_dict_get_string_buf_chk(dict, S_LEN("completion"),
xp_name_buf, def);
@@ -6606,15 +6603,16 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
return;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- const char *const arg2 = tv_get_string_buf_chk(&argvars[2],
- cancelreturn_buf);
- if (arg2 == NULL) {
+ const char *const strarg2 = tv_get_string_buf_chk(&argvars[2], cancelreturn_buf);
+ if (strarg2 == NULL) {
return;
}
if (inputdialog) {
- cancelreturn = arg2;
+ cancelreturn_strarg2.v_type = VAR_STRING;
+ cancelreturn_strarg2.vval.v_string = (char *)strarg2;
+ cancelreturn = &cancelreturn_strarg2;
} else {
- xp_name = arg2;
+ xp_name = strarg2;
}
}
}
@@ -6662,7 +6660,7 @@ void get_user_input(const typval_T *const argvars, typval_T *const rettv, const
callback_free(&input_callback);
if (rettv->vval.v_string == NULL && cancelreturn != NULL) {
- rettv->vval.v_string = xstrdup(cancelreturn);
+ tv_copy(cancelreturn, rettv);
}
xfree(xp_arg);
@@ -7296,7 +7294,7 @@ void timer_due_cb(TimeWatcher *tw, void *data)
{
timer_T *timer = (timer_T *)data;
int save_did_emsg = did_emsg;
- int save_called_emsg = called_emsg;
+ const int called_emsg_before = called_emsg;
const bool save_ex_pressedreturn = get_pressedreturn();
if (timer->stopped || timer->paused) {
@@ -7313,19 +7311,17 @@ void timer_due_cb(TimeWatcher *tw, void *data)
argv[0].v_type = VAR_NUMBER;
argv[0].vval.v_number = timer->timer_id;
typval_T rettv = TV_INITIAL_VALUE;
- called_emsg = false;
callback_call(&timer->callback, 1, argv, &rettv);
// Handle error message
- if (called_emsg && did_emsg) {
+ if (called_emsg > called_emsg_before && did_emsg) {
timer->emsg_count++;
if (current_exception != NULL) {
discard_current_exception();
}
}
did_emsg = save_did_emsg;
- called_emsg = save_called_emsg;
set_pressedreturn(save_ex_pressedreturn);
if (timer->emsg_count >= 3) {
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 6466e06010..f231146d7c 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -482,7 +482,7 @@ static buf_T *find_buffer(typval_T *avar)
* buffer, these don't use the full path. */
FOR_ALL_BUFFERS(bp) {
if (bp->b_fname != NULL
- && (path_with_url(bp->b_fname) || bt_nofile(bp))
+ && (path_with_url(bp->b_fname) || bt_nofilename(bp))
&& STRCMP(bp->b_fname, avar->vval.v_string) == 0) {
buf = bp;
break;
@@ -3902,15 +3902,14 @@ static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
typval_T argv = TV_INITIAL_VALUE;
typval_T exprval = TV_INITIAL_VALUE;
bool error = false;
- int save_called_emsg = called_emsg;
- called_emsg = false;
+ const int called_emsg_before = called_emsg;
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, timeout,
eval_expr_typval(&expr, &argv, 0, &exprval) != OK
|| tv_get_number_chk(&exprval, &error)
- || called_emsg || error || got_int);
+ || called_emsg > called_emsg_before || error || got_int);
- if (called_emsg || error) {
+ if (called_emsg > called_emsg_before || error) {
rettv->vval.v_number = -3;
} else if (got_int) {
got_int = false;
@@ -3920,8 +3919,6 @@ static void f_wait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = 0;
}
- called_emsg = save_called_emsg;
-
// Stop dummy timer
time_watcher_stop(tw);
time_watcher_close(tw, dummy_timer_close_cb);
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 1955a0b3d0..28e1893b31 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1980,17 +1980,14 @@ theend:
/// @return OK if it's OK, FAIL if it is not.
int check_overwrite(exarg_T *eap, buf_T *buf, char *fname, char *ffname, int other)
{
- /*
- * write to other file or b_flags set or not writing the whole file:
- * overwriting only allowed with '!'
- */
+ // Write to another file or b_flags set or not writing the whole file:
+ // overwriting only allowed with '!'
if ((other
|| (buf->b_flags & BF_NOTEDITED)
|| ((buf->b_flags & BF_NEW)
&& vim_strchr(p_cpo, CPO_OVERNEW) == NULL)
|| (buf->b_flags & BF_READERR))
&& !p_wa
- && !bt_nofile(buf)
&& os_path_exists((char_u *)ffname)) {
if (!eap->forceit && !eap->append) {
#ifdef UNIX
@@ -3874,6 +3871,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
curwin->w_cursor.col = 0;
}
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &ec);
+ curwin->w_cursor.col = regmatch.startpos[0].col;
if (subflags.do_number || curwin->w_p_nu) {
int numw = number_width(curwin) + 1;
sc += numw;
@@ -3883,7 +3881,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
prompt = xmallocz((size_t)ec + 1);
memset(prompt, ' ', (size_t)sc);
memset(prompt + sc, '^', (size_t)(ec - sc) + 1);
- resp = getcmdline_prompt((char)(-1), prompt, 0, EXPAND_NOTHING, NULL, CALLBACK_NONE);
+ resp = getcmdline_prompt(-1, prompt, 0, EXPAND_NOTHING, NULL, CALLBACK_NONE);
msg_putchar('\n');
xfree(prompt);
if (resp != NULL) {
@@ -4861,8 +4859,7 @@ void ex_help(exarg_T *eap)
* Re-use an existing help window or open a new one.
* Always open a new one for ":tab help".
*/
- if (!bt_help(curwin->w_buffer)
- || cmdmod.cmod_tab != 0) {
+ if (!bt_help(curwin->w_buffer) || cmdmod.cmod_tab != 0) {
if (cmdmod.cmod_tab != 0) {
wp = NULL;
} else {
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 897928abec..e57dc5d13f 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1018,8 +1018,7 @@ void check_arg_idx(win_T *win)
// We are editing the current entry in the argument list.
// Set "arg_had_last" if it's also the last one
win->w_arg_idx_invalid = false;
- if (win->w_arg_idx == WARGCOUNT(win) - 1
- && win->w_alist == &global_alist) {
+ if (win->w_arg_idx == WARGCOUNT(win) - 1 && win->w_alist == &global_alist) {
arg_had_last = true;
}
}
@@ -1150,8 +1149,7 @@ void do_argfile(exarg_T *eap, int argn)
}
curwin->w_arg_idx = argn;
- if (argn == ARGCOUNT - 1
- && curwin->w_alist == &global_alist) {
+ if (argn == ARGCOUNT - 1 && curwin->w_alist == &global_alist) {
arg_had_last = true;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 2899e17039..4e6846bf21 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -227,6 +227,8 @@ void do_exmode(void)
emsg(_(e_emptybuf));
} else {
if (ex_pressedreturn) {
+ // Make sure the message overwrites the right line and isn't throttled.
+ msg_scroll_flush();
// go up one line, to overwrite the ":<CR>" line, so the
// output doesn't contain empty lines.
msg_row = prev_msg_row;
@@ -908,6 +910,15 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
msg_list = saved_msg_list;
+ // Cleanup if "cs_emsg_silent_list" remains.
+ if (cstack.cs_emsg_silent_list != NULL) {
+ eslist_T *elem, *temp;
+ for (elem = cstack.cs_emsg_silent_list; elem != NULL; elem = temp) {
+ temp = elem->next;
+ xfree(elem);
+ }
+ }
+
/*
* If there was too much output to fit on the command line, ask the user to
* hit return before redrawing the screen. With the ":global" command we do
@@ -4605,8 +4616,9 @@ char *invalid_range(exarg_T *eap)
}
break;
case ADDR_BUFFERS:
- if (eap->line1 < firstbuf->b_fnum
- || eap->line2 > lastbuf->b_fnum) {
+ // Only a boundary check, not whether the buffers actually
+ // exist.
+ if (eap->line1 < 1 || eap->line2 > get_highest_fnum()) {
return _(e_invrange);
}
break;
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index a5783f4ced..92c9d83045 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2646,7 +2646,7 @@ char_u *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_
/// @param[in] highlight_callback Callback used for highlighting user input.
///
/// @return [allocated] Command line or NULL.
-char *getcmdline_prompt(const char firstc, const char *const prompt, const int attr,
+char *getcmdline_prompt(const int firstc, const char *const prompt, const int attr,
const int xp_context, const char *const xp_arg,
const Callback highlight_callback)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index a7f4080b22..6ca6da9cd0 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -187,7 +187,7 @@ static int ses_do_win(win_T *wp)
}
if (wp->w_buffer->b_fname == NULL
// When 'buftype' is "nofile" can't restore the window contents.
- || (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) {
+ || (!wp->w_buffer->terminal && bt_nofilename(wp->w_buffer))) {
return ssop_flags & SSOP_BLANK;
}
if (bt_help(wp->w_buffer)) {
@@ -363,7 +363,7 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr
return FAIL;
}
} else if (wp->w_buffer->b_ffname != NULL
- && (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal)) {
+ && (!bt_nofilename(wp->w_buffer) || wp->w_buffer->terminal)) {
// Load the file.
// Editing a file in this buffer: use ":edit file".
@@ -706,7 +706,7 @@ static int makeopens(FILE *fd, char_u *dirnow)
if (ses_do_win(wp)
&& wp->w_buffer->b_ffname != NULL
&& !bt_help(wp->w_buffer)
- && !bt_nofile(wp->w_buffer)) {
+ && !bt_nofilename(wp->w_buffer)) {
if (need_tabnext && put_line(fd, "tabnext") == FAIL) {
return FAIL;
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index febde53ce2..6782465ef1 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -2286,7 +2286,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
&& reset_changed
&& whole
&& buf == curbuf
- && !bt_nofile(buf)
+ && !bt_nofilename(buf)
&& !filtering
&& (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
&& vim_strchr(p_cpo, CPO_FNAMEW) != NULL) {
@@ -2360,22 +2360,22 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
if (append) {
if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
- sfname, sfname, FALSE, curbuf, eap))) {
- if (overwriting && bt_nofile(curbuf)) {
- nofile_err = TRUE;
+ sfname, sfname, false, curbuf, eap))) {
+ if (overwriting && bt_nofilename(curbuf)) {
+ nofile_err = true;
} else {
apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, false, curbuf, eap);
}
}
} else if (filtering) {
apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
- NULL, sfname, FALSE, curbuf, eap);
+ NULL, sfname, false, curbuf, eap);
} else if (reset_changed && whole) {
int was_changed = curbufIsChanged();
did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, false, curbuf, eap);
if (did_cmd) {
if (was_changed && !curbufIsChanged()) {
/* Written everything correctly and BufWriteCmd has reset
@@ -2385,21 +2385,21 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
u_update_save_nr(curbuf);
}
} else {
- if (overwriting && bt_nofile(curbuf)) {
- nofile_err = TRUE;
+ if (overwriting && bt_nofilename(curbuf)) {
+ nofile_err = true;
} else {
apply_autocmds_exarg(EVENT_BUFWRITEPRE,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, false, curbuf, eap);
}
}
} else {
if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
- sfname, sfname, FALSE, curbuf, eap))) {
- if (overwriting && bt_nofile(curbuf)) {
- nofile_err = TRUE;
+ sfname, sfname, false, curbuf, eap))) {
+ if (overwriting && bt_nofilename(curbuf)) {
+ nofile_err = true;
} else {
apply_autocmds_exarg(EVENT_FILEWRITEPRE,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, false, curbuf, eap);
}
}
}
@@ -4306,7 +4306,7 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
char *p;
if (buf->b_fname != NULL
- && !bt_nofile(buf)
+ && !bt_nofilename(buf)
&& !path_with_url(buf->b_fname)
&& (force
|| buf->b_sfname == NULL
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 01d4ab086e..8d896aef31 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -229,7 +229,7 @@ EXTERN bool did_emsg; // set by emsg() when the message
EXTERN bool called_vim_beep; // set if vim_beep() is called
EXTERN bool did_emsg_syntax; // did_emsg set because of a
// syntax error
-EXTERN int called_emsg; // always set by emsg()
+EXTERN int called_emsg; // always incremented by emsg()
EXTERN int ex_exitval INIT(= 0); // exit value for ex mode
EXTERN bool emsg_on_display INIT(= false); // there is an error message
EXTERN bool rc_did_emsg INIT(= false); // vim_regcomp() called emsg()
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 9a4db520a6..7f4df66b4d 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -2125,6 +2125,10 @@ void init_default_mappings(void)
add_map("<C-W>", "<C-G>u<C-W>", MODE_INSERT, false);
add_map("*", "y/\\\\V<C-R>\"<CR>", MODE_VISUAL, false);
add_map("#", "y?\\\\V<C-R>\"<CR>", MODE_VISUAL, false);
+
+ // Use : instead of <Cmd> so that ranges are supported (e.g. 3& repeats the substitution on the
+ // next 3 lines)
+ add_map("&", ":&&<CR>", MODE_NORMAL, false);
}
/// Add a mapping. Unlike @ref do_map this copies the string arguments, so
diff --git a/src/nvim/match.c b/src/nvim/match.c
index d5e3d8cddc..e17a95569c 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -398,7 +398,7 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_
linenr_T l;
colnr_T matchcol;
long nmatched = 0;
- int save_called_emsg = called_emsg;
+ const int called_emsg_before = called_emsg;
// for :{range}s/pat only highlight inside the range
if (lnum < search_first_line || lnum > search_last_line) {
@@ -421,7 +421,6 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_
// Repeat searching for a match until one is found that includes "mincol"
// or none is found in this line.
- called_emsg = false;
for (;;) {
// Stop searching after passing the time limit.
if (profile_passed_limit(shl->tm)) {
@@ -468,7 +467,7 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_
if (regprog_is_copy) {
cur->match.regprog = cur->hl.rm.regprog;
}
- if (called_emsg || got_int || timed_out) {
+ if (called_emsg > called_emsg_before || got_int || timed_out) {
// Error while handling regexp: stop using this regexp.
if (shl == search_hl) {
// don't free regprog in the match list, it's a copy
@@ -495,9 +494,6 @@ static void next_search_hl(win_T *win, match_T *search_hl, match_T *shl, linenr_
break; // useful match found
}
}
-
- // Restore called_emsg for assert_fails().
- called_emsg = save_called_emsg;
}
/// Advance to the match in window "wp" line "lnum" or past it.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 6ab0a5d3e6..2c96613bb3 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -637,7 +637,7 @@ static bool emsg_multiline(const char *s, bool multiline)
return true;
}
- called_emsg = true;
+ called_emsg++;
// If "emsg_severe" is true: When an error exception is to be thrown,
// prefer this message over previous messages for the same command.
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 99ca5060cd..bd68ad6f97 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -786,8 +786,7 @@ void curs_columns(win_T *wp, int may_scroll)
} else {
wp->w_wrow = wp->w_height_inner - 1 - wp->w_empty_rows;
}
- } else if (wp->w_p_wrap
- && wp->w_width_inner != 0) {
+ } else if (wp->w_p_wrap && wp->w_width_inner != 0) {
width = textwidth + win_col_off2(wp);
// long line wrapping, adjust wp->w_wrow
@@ -1083,8 +1082,7 @@ bool scrolldown(long line_count, int byfold)
* and move the cursor onto the displayed part of the window.
*/
int wrow = curwin->w_wrow;
- if (curwin->w_p_wrap
- && curwin->w_width_inner != 0) {
+ if (curwin->w_p_wrap && curwin->w_width_inner != 0) {
validate_virtcol();
validate_cheight();
wrow += curwin->w_cline_height - 1 -
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 0eb8a8f59b..b675abfb7d 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -6012,8 +6012,7 @@ static void nv_g_home_m_cmd(cmdarg_T *cap)
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
- if (curwin->w_p_wrap
- && curwin->w_width_inner != 0) {
+ if (curwin->w_p_wrap && curwin->w_width_inner != 0) {
int width1 = curwin->w_width_inner - curwin_col_off();
int width2 = width1 + curwin_col_off2();
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index ba151b5ce2..90c0b6f5c6 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -726,8 +726,7 @@ static int pum_set_selected(int n, int repeat)
if (!resized
&& (curbuf->b_nwindows == 1)
&& (curbuf->b_fname == NULL)
- && (curbuf->b_p_bt[0] == 'n')
- && (curbuf->b_p_bt[2] == 'f')
+ && bt_nofile(curbuf)
&& (curbuf->b_p_bh[0] == 'w')) {
// Already a "wipeout" buffer, make it empty.
while (!buf_is_empty(curbuf)) {
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index bb6cbc35bc..4c49d30819 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -2327,7 +2327,6 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags)
{
regprog_T *prog = NULL;
char_u *expr = (char_u *)expr_arg;
- int save_called_emsg;
regexp_engine = p_re;
@@ -2360,8 +2359,7 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags)
//
// First try the NFA engine, unless backtracking was requested.
//
- save_called_emsg = called_emsg;
- called_emsg = false;
+ const int called_emsg_before = called_emsg;
if (regexp_engine != BACKTRACKING_ENGINE) {
prog = nfa_regengine.regcomp(expr,
re_flags + (regexp_engine == AUTOMATIC_ENGINE ? RE_AUTO : 0));
@@ -2388,13 +2386,12 @@ regprog_T *vim_regcomp(char *expr_arg, int re_flags)
// also fails for patterns that it can't handle well but are still valid
// patterns, thus a retry should work.
// But don't try if an error message was given.
- if (regexp_engine == AUTOMATIC_ENGINE && !called_emsg) {
+ if (regexp_engine == AUTOMATIC_ENGINE && called_emsg == called_emsg_before) {
regexp_engine = BACKTRACKING_ENGINE;
report_re_switch(expr);
prog = bt_regengine.regcomp(expr, re_flags);
}
}
- called_emsg |= save_called_emsg;
if (prog != NULL) {
// Store the info needed to call regcomp() again when the engine turns out
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 3d69d317fd..de837720c1 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -5316,7 +5316,7 @@ static void win_redr_custom(win_T *wp, bool draw_winbar, bool draw_ruler)
}
fillchar = wp->w_p_fcs_chars.wbr;
- attr = (wp == curwin) ? HL_ATTR(HLF_WBR) : HL_ATTR(HLF_WBRNC);
+ attr = (wp == curwin) ? win_hl_attr(wp, HLF_WBR) : win_hl_attr(wp, HLF_WBRNC);
maxwidth = wp->w_width_inner;
use_sandbox = was_set_insecurely(wp, "winbar", 0);
@@ -6533,13 +6533,11 @@ static void win_redr_ruler(win_T *wp, bool always)
}
if (*p_ruf && p_ch > 0 && !ui_has(kUIMessages)) {
- int save_called_emsg = called_emsg;
- called_emsg = false;
+ const int called_emsg_before = called_emsg;
win_redr_custom(wp, false, true);
- if (called_emsg) {
+ if (called_emsg > called_emsg_before) {
set_string_option_direct("rulerformat", -1, "", OPT_FREE, SID_ERROR);
}
- called_emsg |= save_called_emsg;
return;
}
diff --git a/src/nvim/search.c b/src/nvim/search.c
index a915594e26..f3061b4dc4 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -556,7 +556,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
long nmatched;
int submatch = 0;
bool first_match = true;
- int save_called_emsg = called_emsg;
+ const int called_emsg_before = called_emsg;
bool break_loop = false;
linenr_T stop_lnum = 0; // stop after this line number when != 0
proftime_T *tm = NULL; // timeout limit or NULL
@@ -579,7 +579,6 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
/*
* find the string
*/
- called_emsg = FALSE;
do { // loop for count
// When not accepting a match at the start position set "extra_col" to a
// non-zero value. Don't do that when starting at MAXCOL, since MAXCOL + 1
@@ -651,7 +650,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
break;
}
// Abort searching on an error (e.g., out of stack).
- if (called_emsg || (timed_out != NULL && *timed_out)) {
+ if (called_emsg > called_emsg_before || (timed_out != NULL && *timed_out)) {
break;
}
if (nmatched > 0) {
@@ -908,7 +907,8 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
// Stop the search if wrapscan isn't set, "stop_lnum" is
// specified, after an interrupt, after a match and after looping
// twice.
- if (!p_ws || stop_lnum != 0 || got_int || called_emsg
+ if (!p_ws || stop_lnum != 0 || got_int
+ || called_emsg > called_emsg_before
|| (timed_out != NULL && *timed_out)
|| break_loop
|| found || loop) {
@@ -933,7 +933,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
extra_arg->sa_wrapped = true;
}
}
- if (got_int || called_emsg
+ if (got_int || called_emsg > called_emsg_before
|| (timed_out != NULL && *timed_out)
|| break_loop) {
break;
@@ -942,8 +942,6 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
vim_regfree(regmatch.regprog);
- called_emsg |= save_called_emsg;
-
if (!found) { // did not find it
if (got_int) {
emsg(_(e_interr));
@@ -4409,7 +4407,7 @@ static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direct
int nmatched = 0;
int result = -1;
pos_T pos;
- int save_called_emsg = called_emsg;
+ const int called_emsg_before = called_emsg;
int flag = 0;
if (pattern == NULL) {
@@ -4435,7 +4433,6 @@ static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direct
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) {
// Zero-width pattern should match somewhere, then we can check if
// start and end are in the same position.
- called_emsg = false;
do {
regmatch.startpos[0].col++;
nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
@@ -4449,14 +4446,13 @@ static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direct
? regmatch.startpos[0].col < pos.col
: regmatch.startpos[0].col > pos.col);
- if (!called_emsg) {
+ if (called_emsg == called_emsg_before) {
result = (nmatched != 0
&& regmatch.startpos[0].lnum == regmatch.endpos[0].lnum
&& regmatch.startpos[0].col == regmatch.endpos[0].col);
}
}
- called_emsg |= save_called_emsg;
vim_regfree(regmatch.regprog);
return result;
}
@@ -5303,6 +5299,16 @@ void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
do_fuzzymatch(argvars, rettv, true);
}
+/// Get line "lnum" and copy it into "buf[LSIZE]".
+/// The copy is made because the regexp may make the line invalid when using a
+/// mark.
+static char_u *get_line_and_copy(linenr_T lnum, char_u *buf)
+{
+ char_u *line = ml_get(lnum);
+ STRLCPY(buf, line, LSIZE);
+ return buf;
+}
+
/// Find identifiers or defines in included files.
/// If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase.
///
@@ -5399,7 +5405,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo
if (lnum > end_lnum) { // do at least one line
lnum = end_lnum;
}
- line = ml_get(lnum);
+ line = get_line_and_copy(lnum, file_line);
for (;;) {
if (incl_regmatch.regprog != NULL
@@ -5687,7 +5693,7 @@ search_line:
if (lnum >= end_lnum) {
goto exit_matched;
}
- line = ml_get(++lnum);
+ line = get_line_and_copy(++lnum, file_line);
} else if (vim_fgets(line = file_line,
LSIZE, files[depth].fp)) {
goto exit_matched;
@@ -5879,7 +5885,7 @@ exit_matched:
if (++lnum > end_lnum) {
break;
}
- line = ml_get(lnum);
+ line = get_line_and_copy(lnum, file_line);
}
already = NULL;
}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 04eb9dd2bc..9d2fd2637d 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -3905,12 +3905,12 @@ static wordnode_T *wordtree_alloc(spellinfo_T *spin)
/// Return true if "word" contains valid word characters.
/// Control characters and trailing '/' are invalid. Space is OK.
-static bool valid_spell_word(const char_u *word)
+static bool valid_spell_word(const char_u *word, const char_u *end)
{
- if (!utf_valid_string(word, NULL)) {
+ if (!utf_valid_string(word, end)) {
return false;
}
- for (const char_u *p = word; *p != NUL; p += utfc_ptr2len((const char *)p)) {
+ for (const char_u *p = word; *p != NUL && p < end; p += utfc_ptr2len((const char *)p)) {
if (*p < ' ' || (p[0] == '/' && p[1] == NUL)) {
return false;
}
@@ -3939,7 +3939,7 @@ static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, co
int res = OK;
// Avoid adding illegal bytes to the word tree.
- if (!valid_spell_word(word)) {
+ if (!valid_spell_word(word, word + len)) {
return FAIL;
}
@@ -5536,7 +5536,7 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo
int i;
char_u *spf;
- if (!valid_spell_word(word)) {
+ if (!valid_spell_word(word, word + len)) {
emsg(_(e_illegal_character_in_word));
return;
}
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 5b62d11bc9..28b3b6c1ef 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -1863,6 +1863,7 @@ parse_line:
// For "normal" tags: Do a quick check if the tag matches.
// This speeds up tag searching a lot!
if (orgpat.headlen) {
+ memset(&tagp, 0, sizeof(tagp));
tagp.tagname = lbuf;
tagp.tagname_end = (char_u *)vim_strchr((char *)lbuf, TAB);
if (tagp.tagname_end == NULL) {
@@ -2784,7 +2785,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
// A :ta from a help file will keep the b_help flag set. For ":ptag"
// we need to use the flag from the window where we came from.
if (l_g_do_tagpreview != 0) {
- keep_help_flag = curwin_save->w_buffer->b_help;
+ keep_help_flag = bt_help(curwin_save->w_buffer);
} else {
keep_help_flag = curbuf->b_help;
}
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index d0a666a049..6b16e888a9 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -153,6 +153,9 @@ func RunTheTest(test)
" directory after executing the test.
let save_cwd = getcwd()
+ " Align Nvim defaults to Vim.
+ source setup.vim
+
if exists("*SetUp")
try
call SetUp()
@@ -191,9 +194,6 @@ func RunTheTest(test)
endtry
endif
- " Align Nvim defaults to Vim.
- source setup.vim
-
" Clear any autocommands and put back the catch-all for SwapExists.
au!
au SwapExists * call HandleSwapExists()
@@ -364,24 +364,25 @@ let s:flaky_tests = [
\ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
\ 'Test_map_timeout_with_timer_interrupt()',
- \ 'Test_oneshot()',
\ 'Test_out_cb()',
- \ 'Test_paused()',
\ 'Test_popup_and_window_resize()',
\ 'Test_quoteplus()',
\ 'Test_quotestar()',
\ 'Test_reltime()',
- \ 'Test_repeat_many()',
- \ 'Test_repeat_three()',
\ 'Test_state()',
- \ 'Test_stop_all_in_callback()',
\ 'Test_term_mouse_double_click_to_create_tab()',
\ 'Test_term_mouse_multiple_clicks_to_visually_select()',
\ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()',
\ 'Test_terminal_tmap()',
+ \ 'Test_timer_oneshot()',
+ \ 'Test_timer_paused()',
+ \ 'Test_timer_repeat_many()',
+ \ 'Test_timer_repeat_three()',
+ \ 'Test_timer_stop_all_in_callback()',
+ \ 'Test_timer_stop_in_callback()',
+ \ 'Test_timer_with_partial_callback()',
\ 'Test_termwinscroll()',
- \ 'Test_with_partial_callback()',
\ ]
" Locate Test_ functions and execute them.
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index f8db2ea120..e6c0762729 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -1,33 +1,34 @@
-" Align Nvim defaults to Vim.
-set backspace=
-set complete=.,w,b,u,t,i
-set directory&
-set directory^=.
-set fillchars=vert:\|,fold:-
-set formatoptions=tcq
-set fsync
-set laststatus=1
-set listchars=eol:$
-set joinspaces
-set nohidden nosmarttab noautoindent noautoread noruler noshowcmd
-set nohlsearch noincsearch
-set nrformats=bin,octal,hex
-set shortmess=filnxtToOS
-set sidescroll=0
-set tags=./tags,tags
-set undodir&
-set undodir^=.
-set wildoptions=
-set startofline
-set sessionoptions&
-set sessionoptions+=options
-set viewoptions&
-set viewoptions+=options
-set switchbuf=
-
-" Make "Q" switch to Ex mode.
-" This does not work for all tests.
-nnoremap Q gQ
+if exists('s:did_load')
+ " Align Nvim defaults to Vim.
+ set backspace=
+ set complete=.,w,b,u,t,i
+ set directory&
+ set directory^=.
+ set fillchars=vert:\|,fold:-
+ set formatoptions=tcq
+ set fsync
+ set laststatus=1
+ set listchars=eol:$
+ set joinspaces
+ set nohidden nosmarttab noautoindent noautoread noruler noshowcmd
+ set nohlsearch noincsearch
+ set nrformats=bin,octal,hex
+ set shortmess=filnxtToOS
+ set sidescroll=0
+ set tags=./tags,tags
+ set undodir&
+ set undodir^=.
+ set wildoptions=
+ set startofline
+ set sessionoptions&
+ set sessionoptions+=options
+ set viewoptions&
+ set viewoptions+=options
+ set switchbuf=
+ " Make "Q" switch to Ex mode.
+ " This does not work for all tests.
+ nnoremap Q gQ
+endif
" Common preparations for running tests.
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 164149476f..ca7c8574cb 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -1,5 +1,8 @@
" Test argument list commands
+source shared.vim
+source term_util.vim
+
func Reset_arglist()
args a | %argd
endfunc
@@ -510,3 +513,42 @@ func Test_argdo()
call assert_equal(['Xa.c', 'Xb.c', 'Xc.c'], l)
bwipe Xa.c Xb.c Xc.c
endfunc
+
+" Test for quiting Vim with unedited files in the argument list
+func Test_quit_with_arglist()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot run vim in terminal'
+ endif
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":args a b c\n")
+ call term_sendkeys(buf, ":quit\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^E173:', term_getline(buf, 6))})
+ call StopVimInTerminal(buf)
+
+ " Try :confirm quit with unedited files in arglist
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":args a b c\n")
+ call term_sendkeys(buf, ":confirm quit\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^\[Y\]es, (N)o: *$',
+ \ term_getline(buf, 6))})
+ call term_sendkeys(buf, "N")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":confirm quit\n")
+ call WaitForAssert({-> assert_match('^\[Y\]es, (N)o: *$',
+ \ term_getline(buf, 6))})
+ call term_sendkeys(buf, "Y")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal("finished", term_getstatus(buf))})
+ only!
+ " When this test fails, swap files are left behind which breaks subsequent
+ " tests
+ call delete('.a.swp')
+ call delete('.b.swp')
+ call delete('.c.swp')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index 9d0d5b3e70..fdd8b0bef6 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -50,6 +50,26 @@ func Test_assert_equal()
call remove(v:errors, 0)
endfunc
+func Test_assert_equal_dict()
+ call assert_equal(0, assert_equal(#{one: 1, two: 2}, #{two: 2, one: 1}))
+
+ call assert_equal(1, assert_equal(#{one: 1, two: 2}, #{two: 2, one: 3}))
+ call assert_match("Expected {'one': 1} but got {'one': 3} - 1 equal item omitted", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_equal(#{one: 1, two: 2}, #{two: 22, one: 11}))
+ call assert_match("Expected {'one': 1, 'two': 2} but got {'one': 11, 'two': 22}", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_equal(#{}, #{two: 2, one: 1}))
+ call assert_match("Expected {} but got {'one': 1, 'two': 2}", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_equal(#{two: 2, one: 1}, #{}))
+ call assert_match("Expected {'one': 1, 'two': 2} but got {}", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
func Test_assert_equalfile()
call assert_equal(1, assert_equalfile('abcabc', 'xyzxyz'))
call assert_match("E485: Can't read file abcabc", v:errors[0])
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 1936832400..438851a0ad 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -2226,7 +2226,7 @@ func Test_autocmd_bufreadpre()
" (even though the position will be invalid, this should make Vim reset the
" cursor position in the other window.
wincmd p
- 1
+ 1 " set cpo+=g
" won't do anything, but try to set the cursor on an invalid lnum
autocmd BufReadPre <buffer> :norm! 70gg
" triggers BufReadPre, should not move the cursor in either window
@@ -2241,8 +2241,11 @@ func Test_autocmd_bufreadpre()
close
close
call delete('XAutocmdBufReadPre.txt')
+ " set cpo-=g
endfunc
+" FileChangedShell tested in test_filechanged.vim
+
" Tests for the following autocommands:
" - FileWritePre writing a compressed file
" - FileReadPost reading a compressed file
@@ -2560,7 +2563,29 @@ func Test_BufWrite_lockmarks()
call delete('Xtest2')
endfunc
-" FileChangedShell tested in test_filechanged.vim
+" Test closing a window or editing another buffer from a FileChangedRO handler
+" in a readonly buffer
+func Test_FileChangedRO_winclose()
+ augroup FileChangedROTest
+ au!
+ autocmd FileChangedRO * quit
+ augroup END
+ new
+ set readonly
+ call assert_fails('normal i', 'E788:')
+ close
+ augroup! FileChangedROTest
+
+ augroup FileChangedROTest
+ au!
+ autocmd FileChangedRO * edit Xfile
+ augroup END
+ new
+ set readonly
+ call assert_fails('normal i', 'E788:')
+ close
+ augroup! FileChangedROTest
+endfunc
func LogACmd()
call add(g:logged, line('$'))
diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim
index 02360b4e75..67be3e6747 100644
--- a/src/nvim/testdir/test_buffer.vim
+++ b/src/nvim/testdir/test_buffer.vim
@@ -105,9 +105,9 @@ func Test_buflist_browse()
call assert_equal(b2, bufnr())
call assert_equal(1, line('.'))
- brewind +/foo3
+ brewind +
call assert_equal(b1, bufnr())
- call assert_equal(3, line('.'))
+ call assert_equal(4, line('.'))
blast +/baz2
call assert_equal(b3, bufnr())
@@ -146,6 +146,7 @@ endfunc
func Test_bdelete_cmd()
%bwipe!
call assert_fails('bdelete 5', 'E516:')
+ call assert_fails('1,1bdelete 1 2', 'E488:')
" Deleting a unlisted and unloaded buffer
edit Xfile1
diff --git a/src/nvim/testdir/test_changelist.vim b/src/nvim/testdir/test_changelist.vim
index ce77c1f3c7..3741f32e69 100644
--- a/src/nvim/testdir/test_changelist.vim
+++ b/src/nvim/testdir/test_changelist.vim
@@ -46,3 +46,5 @@ func Test_getchangelist()
call delete('Xfile1.txt')
call delete('Xfile2.txt')
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim
index 6f09e85a42..683bcabe34 100644
--- a/src/nvim/testdir/test_charsearch.vim
+++ b/src/nvim/testdir/test_charsearch.vim
@@ -1,3 +1,4 @@
+" Test for character search commands - t, T, f, F, ; and ,
func Test_charsearch()
enew!
@@ -60,3 +61,16 @@ func Test_search_cmds()
call assert_equal('ddd yee y', getline(6))
enew!
endfunc
+
+" Test for character search in virtual edit mode with <Tab>
+func Test_csearch_virtualedit()
+ new
+ set virtualedit=all
+ call setline(1, "a\tb")
+ normal! tb
+ call assert_equal([0, 1, 2, 6], getpos('.'))
+ set virtualedit&
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index 922803438f..db62fe5fa6 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -39,6 +39,8 @@ func Test_client_server()
call remote_send(name, ":let testvar = 'yes'\<CR>")
call WaitFor('remote_expr("' . name . '", "exists(\"testvar\") ? testvar : \"\"", "", 1) == "yes"')
call assert_equal('yes', remote_expr(name, "testvar", "", 2))
+ call assert_fails("let x=remote_expr(name, '2+x')", 'E449:')
+ call assert_fails("let x=remote_expr('[], '2+2')", 'E116:')
if has('unix') && has('gui') && !has('gui_running')
" Running in a terminal and the GUI is available: Tell the server to open
@@ -75,6 +77,7 @@ func Test_client_server()
eval 'MYSELF'->remote_startserver()
" May get MYSELF1 when running the test again.
call assert_match('MYSELF', v:servername)
+ call assert_fails("call remote_startserver('MYSELF')", 'E941:')
endif
let g:testvar = 'myself'
call assert_equal('myself', remote_expr(v:servername, 'testvar'))
@@ -107,7 +110,12 @@ func Test_client_server()
call job_stop(job, 'kill')
endif
endtry
+
+ call assert_fails("let x=remote_peek([])", 'E730:')
+ call assert_fails("let x=remote_read('vim10')", 'E277:')
endfunc
" Uncomment this line to get a debugging log
" call ch_logfile('channellog', 'w')
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 9885d356fd..276bb7fb71 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -603,12 +603,22 @@ func Test_cmdline_paste()
call feedkeys(":\"one\<C-R>\<C-X>two\<CR>", 'xt')
call assert_equal('"onetwo', @:)
+ " Test for pasting register containing CTRL-H using CTRL-R and CTRL-R CTRL-R
let @a = "xy\<C-H>z"
call feedkeys(":\"\<C-R>a\<CR>", 'xt')
call assert_equal('"xz', @:)
+ call feedkeys(":\"\<C-R>\<C-R>a\<CR>", 'xt')
+ call assert_equal("\"xy\<C-H>z", @:)
call feedkeys(":\"\<C-R>\<C-O>a\<CR>", 'xt')
call assert_equal("\"xy\<C-H>z", @:)
+ " Test for pasting register containing CTRL-V using CTRL-R and CTRL-R CTRL-R
+ let @a = "xy\<C-V>z"
+ call feedkeys(":\"\<C-R>=@a\<CR>\<cr>", 'xt')
+ call assert_equal('"xyz', @:)
+ call feedkeys(":\"\<C-R>\<C-R>=@a\<CR>\<cr>", 'xt')
+ call assert_equal("\"xy\<C-V>z", @:)
+
call assert_beeps('call feedkeys(":\<C-R>=\<C-R>=\<Esc>", "xt")')
bwipe!
@@ -1268,6 +1278,10 @@ endfunc
func Test_cmdwin_feedkeys()
" This should not generate E488
call feedkeys("q:\<CR>", 'x')
+ " Using feedkeys with q: only should automatically close the cmd window
+ call feedkeys('q:', 'xt')
+ call assert_equal(1, winnr('$'))
+ call assert_equal('', getcmdwintype())
endfunc
" Tests for the issues fixed in 7.4.441.
@@ -1312,22 +1326,6 @@ func Test_cmdwin_autocmd()
augroup! CmdWin
endfunc
-func Test_cmdwin_jump_to_win()
- call assert_fails('call feedkeys("q:\<C-W>\<C-W>\<CR>", "xt")', 'E11:')
- new
- set modified
- call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', 'E162:')
- close!
- call feedkeys("q/:close\<CR>", "xt")
- call assert_equal(1, winnr('$'))
- call feedkeys("q/:exit\<CR>", "xt")
- call assert_equal(1, winnr('$'))
-
- " opening command window twice should fail
- call assert_beeps('call feedkeys("q:q:\<CR>\<CR>", "xt")')
- call assert_equal(1, winnr('$'))
-endfunc
-
func Test_cmdlineclear_tabenter()
" See test/functional/legacy/cmdline_spec.lua
CheckScreendump
@@ -1365,6 +1363,22 @@ func Test_cmdline_expand_special()
call delete('Xfile.java')
endfunc
+func Test_cmdwin_jump_to_win()
+ call assert_fails('call feedkeys("q:\<C-W>\<C-W>\<CR>", "xt")', 'E11:')
+ new
+ set modified
+ call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', 'E162:')
+ close!
+ call feedkeys("q/:close\<CR>", "xt")
+ call assert_equal(1, winnr('$'))
+ call feedkeys("q/:exit\<CR>", "xt")
+ call assert_equal(1, winnr('$'))
+
+ " opening command window twice should fail
+ call assert_beeps('call feedkeys("q:q:\<CR>\<CR>", "xt")')
+ call assert_equal(1, winnr('$'))
+endfunc
+
" Test for backtick expression in the command line
func Test_cmd_backtick()
%argd
@@ -1385,6 +1399,35 @@ func Test_cmdwin_tabpage()
tabclose!
endfunc
+" Test for the :! command
+func Test_cmd_bang()
+ if !has('unix')
+ return
+ endif
+
+ let lines =<< trim [SCRIPT]
+ " Test for no previous command
+ call assert_fails('!!', 'E34:')
+ set nomore
+ " Test for cmdline expansion with :!
+ call setline(1, 'foo!')
+ silent !echo <cWORD> > Xfile.out
+ call assert_equal(['foo!'], readfile('Xfile.out'))
+ " Test for using previous command
+ silent !echo \! !
+ call assert_equal(['! echo foo!'], readfile('Xfile.out'))
+ call writefile(v:errors, 'Xresult')
+ call delete('Xfile.out')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
" Test error: "E135: *Filter* Autocommands must not change current buffer"
func Test_cmd_bang_E135()
new
@@ -1529,6 +1572,7 @@ endfunc
func Test_cmdline_edit()
let str = ":one two\<C-U>"
let str ..= "one two\<C-W>\<C-W>"
+ let str ..= "four\<BS>\<C-H>\<Del>\<kDel>"
let str ..= "\<Left>five\<Right>"
let str ..= "\<Home>two "
let str ..= "\<C-Left>one "
@@ -1547,6 +1591,7 @@ func Test_cmdline_edit_rightleft()
set rightleftcmd=search
let str = "/one two\<C-U>"
let str ..= "one two\<C-W>\<C-W>"
+ let str ..= "four\<BS>\<C-H>\<Del>\<kDel>"
let str ..= "\<Right>five\<Left>"
let str ..= "\<Home>two "
let str ..= "\<C-Right>one "
@@ -1574,6 +1619,63 @@ func Test_cmdline_expr()
call assert_equal("\"e \<C-\>\<C-Y>", @:)
endfunc
+" Test for 'imcmdline' and 'imsearch'
+" This test doesn't actually test the input method functionality.
+func Test_cmdline_inputmethod()
+ new
+ call setline(1, ['', 'abc', ''])
+ set imcmdline
+
+ call feedkeys(":\"abc\<CR>", 'xt')
+ call assert_equal("\"abc", @:)
+ call feedkeys(":\"\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal("\"abc", @:)
+ call feedkeys("/abc\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ " set imsearch=2
+ call cursor(1, 1)
+ call feedkeys("/abc\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ call cursor(1, 1)
+ call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ set imdisable
+ call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ set imdisable&
+ set imsearch&
+
+ set imcmdline&
+ %bwipe!
+endfunc
+
+" Test for recursively getting multiple command line inputs
+func Test_cmdwin_multi_input()
+ call feedkeys(":\<C-R>=input('P: ')\<CR>\"cyan\<CR>\<CR>", 'xt')
+ call assert_equal('"cyan', @:)
+endfunc
+
+" Test for using CTRL-_ in the command line with 'allowrevins'
+func Test_cmdline_revins()
+ CheckNotMSWindows
+ CheckFeature rightleft
+ call feedkeys(":\"abc\<c-_>\<cr>", 'xt')
+ call assert_equal("\"abc\<c-_>", @:)
+ set allowrevins
+ call feedkeys(":\"abc\<c-_>xyz\<c-_>\<CR>", 'xt')
+ call assert_equal('"abcñèæ', @:)
+ set allowrevins&
+endfunc
+
+" Test for typing UTF-8 composing characters in the command line
+func Test_cmdline_composing_chars()
+ call feedkeys(":\"\<C-V>u3046\<C-V>u3099\<CR>", 'xt')
+ call assert_equal('"ゔ', @:)
+endfunc
+
" Test for normal mode commands not supported in the cmd window
func Test_cmdwin_blocked_commands()
call assert_fails('call feedkeys("q:\<C-T>\<CR>", "xt")', 'E11:')
@@ -1582,6 +1684,36 @@ func Test_cmdwin_blocked_commands()
call assert_fails('call feedkeys("q:Q\<CR>", "xt")', 'E11:')
call assert_fails('call feedkeys("q:Z\<CR>", "xt")', 'E11:')
call assert_fails('call feedkeys("q:\<F1>\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>s\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>v\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>^\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>n\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>z\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>o\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>w\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>j\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>k\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>h\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>l\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>T\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>x\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>r\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>R\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>K\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>}\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>]\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>f\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>d\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>g\<CR>", "xt")', 'E11:')
+endfunc
+
+" Close the Cmd-line window in insert mode using CTRL-C
+func Test_cmdwin_insert_mode_close()
+ %bw!
+ let s = ''
+ exe "normal q:a\<C-C>let s='Hello'\<CR>"
+ call assert_equal('Hello', s)
+ call assert_equal(1, winnr('$'))
endfunc
" test that ";" works to find a match at the start of the first line
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index c0c572ce65..3dc8710d63 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -68,5 +68,9 @@ func Test_compiler_completion()
endfunc
func Test_compiler_error()
+ let g:current_compiler = 'abc'
call assert_fails('compiler doesnotexist', 'E666:')
+ call assert_equal('abc', g:current_compiler)
+ call assert_fails('compiler! doesnotexist', 'E666:')
+ unlet! g:current_compiler
endfunc
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
index 7b6bc940d3..acc34e5e7c 100644
--- a/src/nvim/testdir/test_digraph.vim
+++ b/src/nvim/testdir/test_digraph.vim
@@ -466,10 +466,12 @@ endfunc
func Test_digraph_cmndline()
" Create digraph on commandline
- " This is a hack, to let Vim create the digraph in commandline mode
- let s = ''
- exe "sil! norm! :let s.='\<c-k>Eu'\<cr>"
- call assert_equal("€", s)
+ call feedkeys(":\"\<c-k>Eu\<cr>", 'xt')
+ call assert_equal('"€', @:)
+
+ " Canceling a CTRL-K on the cmdline
+ call feedkeys(":\"a\<c-k>\<esc>b\<cr>", 'xt')
+ call assert_equal('"ab', @:)
endfunc
func Test_show_digraph()
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 19b088959b..65194f49dd 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -286,7 +286,7 @@ func Test_edit_11()
call cursor(2, 1)
call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
call cursor(3, 1)
- call feedkeys("i/* comment */", 'tnix')
+ call feedkeys("\<Insert>/* comment */", 'tnix')
call assert_equal(['{', "\<tab>int c;", "/* comment */"], getline(1, '$'))
" added changed cindentkeys slightly
set cindent cinkeys+=*/
@@ -1617,6 +1617,22 @@ func Test_edit_startinsert()
bwipe!
endfunc
+" Test for :startreplace and :startgreplace
+func Test_edit_startreplace()
+ new
+ call setline(1, 'abc')
+ call feedkeys("l:startreplace\<CR>xyz\e", 'xt')
+ call assert_equal('axyz', getline(1))
+ call feedkeys("0:startreplace!\<CR>abc\e", 'xt')
+ call assert_equal('axyzabc', getline(1))
+ call setline(1, "a\tb")
+ call feedkeys("0l:startgreplace\<CR>xyz\e", 'xt')
+ call assert_equal("axyz\tb", getline(1))
+ call feedkeys("0i\<C-R>=execute('startreplace')\<CR>12\e", 'xt')
+ call assert_equal("12axyz\tb", getline(1))
+ close!
+endfunc
+
func Test_edit_noesckeys()
CheckNotGui
new
@@ -1637,6 +1653,58 @@ func Test_edit_noesckeys()
" set esckeys
endfunc
+" Test for running an invalid ex command in insert mode using CTRL-O
+" Note that vim has a hard-coded sleep of 3 seconds. So this test will take
+" more than 3 seconds to complete.
+func Test_edit_ctrl_o_invalid_cmd()
+ new
+ set showmode showcmd
+ let caught_e492 = 0
+ try
+ call feedkeys("i\<C-O>:invalid\<CR>abc\<Esc>", "xt")
+ catch /E492:/
+ let caught_e492 = 1
+ endtry
+ call assert_equal(1, caught_e492)
+ call assert_equal('abc', getline(1))
+ set showmode& showcmd&
+ close!
+endfunc
+
+" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
+func Test_edit_cpo_H()
+ throw 'Skipped: Nvim does not support cpoptions flag "H"'
+ new
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a', getline(1))
+ set cpo+=H
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a ', getline(1))
+ set cpo-=H
+ close!
+endfunc
+
+" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
+func Test_edit_cpo_L()
+ new
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ set cpo+=L
+ set list
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
+ set nolist
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ set cpo-=L
+ %bw!
+endfunc
+
" Test for editing a directory
func Test_edit_is_a_directory()
CheckEnglish
diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index cff78620d1..b478332c79 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -64,6 +64,66 @@ func Test_ex_mode()
let &encoding = encoding_save
endfunc
+" Test substitute confirmation prompt :%s/pat/str/c in Ex mode
+func Test_Ex_substitute()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('', {'rows': 6})
+
+ call term_sendkeys(buf, ":call setline(1, ['foo foo', 'foo foo', 'foo foo'])\<CR>")
+ call term_sendkeys(buf, ":set number\<CR>")
+ call term_sendkeys(buf, "gQ")
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
+
+ call term_sendkeys(buf, "%s/foo/bar/gc\<CR>")
+ call WaitForAssert({-> assert_match(' 1 foo foo', term_getline(buf, 5))},
+ \ 1000)
+ call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, "N\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, "n\<CR>")
+ call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))},
+ \ 1000)
+ call term_sendkeys(buf, "y\<CR>")
+
+ call term_sendkeys(buf, "q\<CR>")
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
+
+ " Pressing enter in ex mode should print the current line
+ call term_sendkeys(buf, "\<CR>")
+ call WaitForAssert({-> assert_match(' 3 foo foo',
+ \ term_getline(buf, 5))}, 1000)
+
+ call term_sendkeys(buf, ":vi\<CR>")
+ call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
+
+ call term_sendkeys(buf, ":q!\n")
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test for displaying lines from an empty buffer in Ex mode
+func Test_Ex_emptybuf()
+ new
+ call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E749:')
+ call setline(1, "abc")
+ call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E501:')
+ call assert_fails('call feedkeys("Q%d\<CR>", "xt")', 'E749:')
+ close!
+endfunc
+
+" Test for the :open command
+func Test_open_command()
+ throw 'Skipped: Nvim does not have :open'
+ new
+ call setline(1, ['foo foo', 'foo bar', 'foo baz'])
+ call feedkeys("Qopen\<CR>j", 'xt')
+ call assert_equal('foo bar', getline('.'))
+ call feedkeys("Qopen /bar/\<CR>", 'xt')
+ call assert_equal(5, col('.'))
+ call assert_fails('call feedkeys("Qopen /baz/\<CR>", "xt")', 'E479:')
+ close!
+endfunc
+
" Test for :g/pat/visual to run vi commands in Ex mode
" This used to hang Vim before 8.2.0274.
func Test_Ex_global()
@@ -81,6 +141,31 @@ func Test_Ex_escape_enter()
call assert_equal("a\rb", l)
endfunc
+" Test for :append! command in Ex mode
+func Test_Ex_append()
+ throw 'Skipped: Nvim only supports Vim Ex mode'
+ new
+ call setline(1, "\t abc")
+ call feedkeys("Qappend!\npqr\nxyz\n.\nvisual\n", 'xt')
+ call assert_equal(["\t abc", "\t pqr", "\t xyz"], getline(1, '$'))
+ close!
+endfunc
+
+" In Ex-mode, backslashes at the end of a command should be halved.
+func Test_Ex_echo_backslash()
+ throw 'Skipped: Nvim only supports Vim Ex mode'
+ " This test works only when the language is English
+ if v:lang != "C" && v:lang !~ '^[Ee]n'
+ return
+ endif
+ let bsl = '\\\\'
+ let bsl2 = '\\\'
+ call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")',
+ \ "E15: Invalid expression: \\\\")
+ call assert_fails('call feedkeys("Qecho " .. bsl2 .. "\nm\nvisual\n", "xt")',
+ \ "E15: Invalid expression: \\\nm")
+endfunc
+
func Test_ex_mode_errors()
" Not allowed to enter ex mode when text is locked
au InsertCharPre <buffer> normal! gQ<CR>
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index df2cf97633..6858efeaa9 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -22,6 +22,7 @@ func Test_range_error()
call assert_fails(':\/echo 1', 'E481:')
normal vv
call assert_fails(":'<,'>echo 1", 'E481:')
+ call assert_fails(":\\xcenter", 'E10:')
endfunc
func Test_buffers_lastused()
@@ -65,6 +66,10 @@ func Test_copy()
1,3copy 2
call assert_equal(['L1', 'L2', 'L1', 'L2', 'L3', 'L3', 'L4'], getline(1, 7))
+ " Specifying a count before using : to run an ex-command
+ exe "normal! gg4:yank\<CR>"
+ call assert_equal("L1\nL2\nL1\nL2\n", @")
+
close!
endfunc
@@ -222,12 +227,24 @@ func Test_change_cmd()
close!
endfunc
+" Test for the :language command
+func Test_language_cmd()
+ CheckNotMSWindows " FIXME: why does this fail on Windows CI?
+ CheckNotBSD " FIXME: why does this fail on OpenBSD CI?
+ CheckFeature multi_lang
+
+ call assert_fails('language ctype non_existing_lang', 'E197:')
+ call assert_fails('language time non_existing_lang', 'E197:')
+endfunc
+
" Test for the :confirm command dialog
func Test_confirm_cmd()
CheckNotGui
CheckRunVimInTerminal
+
call writefile(['foo1'], 'foo')
call writefile(['bar1'], 'bar')
+
" Test for saving all the modified buffers
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
@@ -240,8 +257,10 @@ func Test_confirm_cmd()
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "A")
call StopVimInTerminal(buf)
+
call assert_equal(['foo2'], readfile('foo'))
call assert_equal(['bar2'], readfile('bar'))
+
" Test for discarding all the changes to modified buffers
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
@@ -254,8 +273,10 @@ func Test_confirm_cmd()
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "D")
call StopVimInTerminal(buf)
+
call assert_equal(['foo2'], readfile('foo'))
call assert_equal(['bar2'], readfile('bar'))
+
" Test for saving and discarding changes to some buffers
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
@@ -270,6 +291,7 @@ func Test_confirm_cmd()
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "Y")
call StopVimInTerminal(buf)
+
call assert_equal(['foo4'], readfile('foo'))
call assert_equal(['bar2'], readfile('bar'))
@@ -391,6 +413,11 @@ func Test_confirm_write_partial_file()
call delete('Xscript')
endfunc
+" Test for the :print command
+func Test_print_cmd()
+ call assert_fails('print', 'E749:')
+endfunc
+
" Test for the :winsize command
func Test_winsize_cmd()
call assert_fails('winsize 1', 'E465:')
@@ -399,6 +426,67 @@ func Test_winsize_cmd()
" Actually changing the window size would be flaky.
endfunc
+" Test for the :redir command
+func Test_redir_cmd()
+ call assert_fails('redir @@', 'E475:')
+ call assert_fails('redir abc', 'E475:')
+ if has('unix')
+ call mkdir('Xdir')
+ call assert_fails('redir > Xdir', 'E17:')
+ call delete('Xdir', 'd')
+ endif
+ if !has('bsd')
+ call writefile([], 'Xfile')
+ call setfperm('Xfile', 'r--r--r--')
+ call assert_fails('redir! > Xfile', 'E190:')
+ call delete('Xfile')
+ endif
+
+ " Test for redirecting to a register
+ redir @q> | echon 'clean ' | redir END
+ redir @q>> | echon 'water' | redir END
+ call assert_equal('clean water', @q)
+
+ " Test for redirecting to a variable
+ redir => color | echon 'blue ' | redir END
+ redir =>> color | echon 'sky' | redir END
+ call assert_equal('blue sky', color)
+endfunc
+
+" Test for the :filetype command
+func Test_filetype_cmd()
+ call assert_fails('filetype abc', 'E475:')
+endfunc
+
+" Test for the :mode command
+func Test_mode_cmd()
+ call assert_fails('mode abc', 'E359:')
+endfunc
+
+" Test for the :sleep command
+func Test_sleep_cmd()
+ call assert_fails('sleep x', 'E475:')
+endfunc
+
+" Test for the :read command
+func Test_read_cmd()
+ call writefile(['one'], 'Xfile')
+ new
+ call assert_fails('read', 'E32:')
+ edit Xfile
+ read
+ call assert_equal(['one', 'one'], getline(1, '$'))
+ close!
+ new
+ read Xfile
+ call assert_equal(['', 'one'], getline(1, '$'))
+ call deletebufline('', 1, '$')
+ call feedkeys("Qr Xfile\<CR>visual\<CR>", 'xt')
+ call assert_equal(['one'], getline(1, '$'))
+ close!
+ call delete('Xfile')
+endfunc
+
" Test for running Ex commands when text is locked.
" <C-\>e in the command line is used to lock the text
func Test_run_excmd_with_text_locked()
@@ -423,6 +511,107 @@ func Test_run_excmd_with_text_locked()
call assert_fails("call feedkeys(\":\<C-R>=execute('bnext')\<CR>\", 'xt')", 'E565:')
endfunc
+" Test for the :verbose command
+func Test_verbose_cmd()
+ call assert_equal([' verbose=1'], split(execute('verbose set vbs'), "\n"))
+ call assert_equal([' verbose=0'], split(execute('0verbose set vbs'), "\n"))
+ let l = execute("4verbose set verbose | set verbose")
+ call assert_equal([' verbose=4', ' verbose=0'], split(l, "\n"))
+endfunc
+
+" Test for the :delete command and the related abbreviated commands
+func Test_excmd_delete()
+ new
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('dl'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('dell'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('delel'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('deletl'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('deletel'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('dp'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('dep'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('delp'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('delep'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('deletp'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('deletep'), "\n"))
+ close!
+endfunc
+
+" Test for commands that are blocked in a sandbox
+func Sandbox_tests()
+ call assert_fails("call histadd(':', 'ls')", 'E48:')
+ call assert_fails("call mkdir('Xdir')", 'E48:')
+ call assert_fails("call rename('a', 'b')", 'E48:')
+ call assert_fails("call setbufvar(1, 'myvar', 1)", 'E48:')
+ call assert_fails("call settabvar(1, 'myvar', 1)", 'E48:')
+ call assert_fails("call settabwinvar(1, 1, 'myvar', 1)", 'E48:')
+ call assert_fails("call setwinvar(1, 'myvar', 1)", 'E48:')
+ call assert_fails("call timer_start(100, '')", 'E48:')
+ if has('channel')
+ call assert_fails("call prompt_setcallback(1, '')", 'E48:')
+ call assert_fails("call prompt_setinterrupt(1, '')", 'E48:')
+ call assert_fails("call prompt_setprompt(1, '')", 'E48:')
+ endif
+ call assert_fails("let $TESTVAR=1", 'E48:')
+ call assert_fails("call feedkeys('ivim')", 'E48:')
+ call assert_fails("source! Xfile", 'E48:')
+ call assert_fails("call delete('Xfile')", 'E48:')
+ call assert_fails("call writefile([], 'Xfile')", 'E48:')
+ call assert_fails('!ls', 'E48:')
+ " call assert_fails('shell', 'E48:')
+ call assert_fails('stop', 'E48:')
+ call assert_fails('exe "normal \<C-Z>"', 'E48:')
+ " set insertmode
+ " call assert_fails('call feedkeys("\<C-Z>", "xt")', 'E48:')
+ " set insertmode&
+ call assert_fails('suspend', 'E48:')
+ call assert_fails('call system("ls")', 'E48:')
+ call assert_fails('call systemlist("ls")', 'E48:')
+ if has('clientserver')
+ call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:')
+ if !has('win32')
+ " remote_foreground() doesn't thrown an error message on MS-Windows
+ call assert_fails('call remote_foreground("gvim")', 'E48:')
+ endif
+ call assert_fails('let s=remote_peek("gvim")', 'E48:')
+ call assert_fails('let s=remote_read("gvim")', 'E48:')
+ call assert_fails('let s=remote_send("gvim", "abc")', 'E48:')
+ call assert_fails('let s=server2client("gvim", "abc")', 'E48:')
+ endif
+ if has('terminal')
+ call assert_fails('terminal', 'E48:')
+ call assert_fails('call term_start("vim")', 'E48:')
+ call assert_fails('call term_dumpwrite(1, "Xfile")', 'E48:')
+ endif
+ if has('channel')
+ call assert_fails("call ch_logfile('chlog')", 'E48:')
+ call assert_fails("call ch_open('localhost:8765')", 'E48:')
+ endif
+ if has('job')
+ call assert_fails("call job_start('vim')", 'E48:')
+ endif
+ if has('unix') && has('libcall')
+ call assert_fails("echo libcall('libc.so', 'getenv', 'HOME')", 'E48:')
+ endif
+ if has('unix')
+ call assert_fails('cd `pwd`', 'E48:')
+ endif
+endfunc
+
+func Test_sandbox()
+ sandbox call Sandbox_tests()
+endfunc
+
func Test_not_break_expression_register()
call setreg('=', '1+1')
if 0
diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim
index 48dce25bb3..d86fea4f45 100644
--- a/src/nvim/testdir/test_expand.vim
+++ b/src/nvim/testdir/test_expand.vim
@@ -1,5 +1,7 @@
" Test for expanding file names
+source shared.vim
+
func Test_with_directories()
call mkdir('Xdir1')
call mkdir('Xdir2')
@@ -79,5 +81,48 @@ func Test_expandcmd()
call assert_fails('call expandcmd("make <afile>")', 'E495:')
enew
call assert_fails('call expandcmd("make %")', 'E499:')
- close
+ let $FOO="blue\tsky"
+ call setline(1, "$FOO")
+ call assert_equal("grep pat blue\tsky", expandcmd('grep pat <cfile>'))
+ unlet $FOO
+ close!
+endfunc
+
+" Test for expanding <sfile>, <slnum> and <sflnum> outside of sourcing a script
+func Test_source_sfile()
+ let lines =<< trim [SCRIPT]
+ :call assert_fails('echo expandcmd("<sfile>")', 'E498:')
+ :call assert_fails('echo expandcmd("<slnum>")', 'E842:')
+ :call assert_fails('echo expandcmd("<sflnum>")', 'E961:')
+ :call assert_fails('call expandcmd("edit <cfile>")', 'E446:')
+ :call assert_fails('call expandcmd("edit #")', 'E194:')
+ :call assert_fails('call expandcmd("edit #<2")', 'E684:')
+ :call assert_fails('call expandcmd("edit <cword>")', 'E348:')
+ :call assert_fails('call expandcmd("edit <cexpr>")', 'E348:')
+ :call assert_fails('autocmd User MyCmd echo "<sfile>"', 'E498:')
+ :call writefile(v:errors, 'Xresult')
+ :qall!
+
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -s Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for expanding filenames multiple times in a command line
+func Test_expand_filename_multicmd()
+ edit foo
+ call setline(1, 'foo!')
+ new
+ call setline(1, 'foo!')
+ new <cword> | new <cWORD>
+ call assert_equal(4, winnr('$'))
+ call assert_equal('foo!', bufname(winbufnr(1)))
+ call assert_equal('foo', bufname(winbufnr(2)))
+ %bwipe!
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
index 1b0f49ca51..c6e781a1ef 100644
--- a/src/nvim/testdir/test_filechanged.vim
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -237,7 +237,7 @@ func Test_file_changed_dialog()
sleep 2
silent !touch Xchanged_d
let v:warningmsg = ''
- checktime
+ checktime Xchanged_d
call assert_equal('', v:warningmsg)
call assert_equal(1, line('$'))
call assert_equal('new line', getline(1))
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 00ba548e97..dee04e66dc 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -757,6 +757,30 @@ func Test_setfiletype_completion()
call assert_equal('"setfiletype java javacc javascript javascriptreact', @:)
endfunc
+" Test for ':filetype detect' command for a buffer without a file
+func Test_emptybuf_ftdetect()
+ new
+ call setline(1, '#!/bin/sh')
+ call assert_equal('', &filetype)
+ filetype detect
+ call assert_equal('sh', &filetype)
+ close!
+endfunc
+
+" Test for ':filetype indent on' and ':filetype indent off' commands
+func Test_filetype_indent_off()
+ new Xtest.vim
+ filetype indent on
+ call assert_equal(1, g:did_indent_on)
+ call assert_equal(['filetype detection:ON plugin:OFF indent:ON'],
+ \ execute('filetype')->split("\n"))
+ filetype indent off
+ call assert_equal(0, exists('g:did_indent_on'))
+ call assert_equal(['filetype detection:ON plugin:OFF indent:OFF'],
+ \ execute('filetype')->split("\n"))
+ close
+endfunc
+
"""""""""""""""""""""""""""""""""""""""""""""""""
" Tests for specific extensions and filetypes.
" Keep sorted.
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index d465e48c7b..dae164b11c 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -45,6 +45,14 @@ func Test_filter_fails()
call assert_fails('filter /pat', 'E476:')
call assert_fails('filter /pat/', 'E476:')
call assert_fails('filter /pat/ asdf', 'E492:')
+ " Using assert_fails() causes E476 instead of E866. So use a try-catch.
+ let caught_e866 = 0
+ try
+ filter /\@>b/ ls
+ catch /E866:/
+ let caught_e866 = 1
+ endtry
+ call assert_equal(1, caught_e866)
call assert_fails('filter!', 'E471:')
call assert_fails('filter! pat', 'E476:')
diff --git a/src/nvim/testdir/test_findfile.vim b/src/nvim/testdir/test_findfile.vim
index 1684c5d30a..0f4b30aec2 100644
--- a/src/nvim/testdir/test_findfile.vim
+++ b/src/nvim/testdir/test_findfile.vim
@@ -193,12 +193,14 @@ func Test_find_cmd()
set path=.,./**/*
call CreateFiles()
cd Xdir1
+
" Test for :find
find foo
call assert_equal('foo', expand('%:.'))
2find foo
call assert_equal('Xdir2/foo', expand('%:.'))
call assert_fails('3find foo', 'E347:')
+
" Test for :sfind
enew
sfind barfoo
@@ -207,6 +209,7 @@ func Test_find_cmd()
close
call assert_fails('sfind baz', 'E345:')
call assert_equal(2, winnr('$'))
+
" Test for :tabfind
enew
tabfind foobar
@@ -215,7 +218,8 @@ func Test_find_cmd()
tabclose
call assert_fails('tabfind baz', 'E345:')
call assert_equal(1, tabpagenr('$'))
- " call chdir(save_dir)
+
+ call chdir(save_dir)
exe 'cd ' . save_dir
call CleanFiles()
let &path = save_path
diff --git a/src/nvim/testdir/test_global.vim b/src/nvim/testdir/test_global.vim
index ad561baf4a..feddf85346 100644
--- a/src/nvim/testdir/test_global.vim
+++ b/src/nvim/testdir/test_global.vim
@@ -66,6 +66,18 @@ func Test_global_print()
close!
endfunc
+" Test for global command with newline character
+func Test_global_newline()
+ new
+ call setline(1, ['foo'])
+ exe "g/foo/s/f/h/\<NL>s/o$/w/"
+ call assert_equal('how', getline(1))
+ call setline(1, ["foo\<NL>bar"])
+ exe "g/foo/s/foo\\\<NL>bar/xyz/"
+ call assert_equal('xyz', getline(1))
+ close!
+endfunc
+
func Test_wrong_delimiter()
call assert_fails('g x^bxd', 'E146:')
endfunc
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
index ece8ccf215..e84726bbfc 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -125,6 +125,11 @@ func Test_help_tagjump()
call assert_true(getline('.') =~ '\*/\\bar\*')
helpclose
+ help \_$
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*/\\_$\*')
+ helpclose
+
help CTRL-\_CTRL-N
call assert_equal("help", &filetype)
call assert_true(getline('.') =~ '\*CTRL-\\_CTRL-N\*')
diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim
index 96006ac7e7..feb521e232 100644
--- a/src/nvim/testdir/test_history.vim
+++ b/src/nvim/testdir/test_history.vim
@@ -114,6 +114,7 @@ function Test_Search_history_window()
bwipe!
endfunc
+" Test for :history command option completion
function Test_history_completion()
call feedkeys(":history \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"history / : = > ? @ all cmd debug expr input search', @:)
@@ -122,8 +123,9 @@ endfunc
" Test for increasing the 'history' option value
func Test_history_size()
let save_histsz = &history
- call histdel(':')
set history=10
+ call histadd(':', 'ls')
+ call histdel(':')
for i in range(1, 5)
call histadd(':', 'cmd' .. i)
endfor
@@ -173,6 +175,53 @@ func Test_history_search()
call assert_equal(['pat2', 'pat1', ''], g:pat)
cunmap <F2>
delfunc SavePat
+
+ " Search for a pattern that is not present in the history
+ call assert_beeps('call feedkeys("/a1b2\<Up>\<CR>", "xt")')
+
+ " Recall patterns with 'history' set to 0
+ set history=0
+ let @/ = 'abc'
+ let cmd = 'call feedkeys("/\<Up>\<Down>\<S-Up>\<S-Down>\<CR>", "xt")'
+ call assert_fails(cmd, 'E486:')
+ set history&
+
+ " Recall patterns till the end of history
+ set history=4
+ call histadd('/', 'pat')
+ call histdel('/')
+ call histadd('/', 'pat1')
+ call histadd('/', 'pat2')
+ call assert_beeps('call feedkeys("/\<Up>\<Up>\<Up>\<C-U>\<cr>", "xt")')
+ call assert_beeps('call feedkeys("/\<Down><cr>", "xt")')
+
+ " Test for wrapping around the history list
+ for i in range(3, 7)
+ call histadd('/', 'pat' .. i)
+ endfor
+ let upcmd = "\<up>\<up>\<up>\<up>\<up>"
+ let downcmd = "\<down>\<down>\<down>\<down>\<down>"
+ try
+ call feedkeys("/" .. upcmd .. "\<cr>", 'xt')
+ catch /E486:/
+ endtry
+ call assert_equal('pat4', @/)
+ try
+ call feedkeys("/" .. upcmd .. downcmd .. "\<cr>", 'xt')
+ catch /E486:/
+ endtry
+ call assert_equal('pat4', @/)
+
+ " Test for changing the search command separator in the history
+ call assert_fails('call feedkeys("/def/\<cr>", "xt")', 'E486:')
+ call assert_fails('call feedkeys("?\<up>\<cr>", "xt")', 'E486:')
+ call assert_equal('def?', histget('/', -1))
+
+ call assert_fails('call feedkeys("/ghi?\<cr>", "xt")', 'E486:')
+ call assert_fails('call feedkeys("?\<up>\<cr>", "xt")', 'E486:')
+ call assert_equal('ghi\?', histget('/', -1))
+
+ set history&
endfunc
" Test for making sure the key value is not stored in history
diff --git a/src/nvim/testdir/test_increment.vim b/src/nvim/testdir/test_increment.vim
index 12fe52f057..2559654f25 100644
--- a/src/nvim/testdir/test_increment.vim
+++ b/src/nvim/testdir/test_increment.vim
@@ -776,6 +776,14 @@ func Test_increment_empty_line()
call setline(1, ['0', '0', '0', '0', '0', '0', ''])
exe "normal Gvgg\<C-A>"
call assert_equal(['1', '1', '1', '1', '1', '1', ''], getline(1, 7))
+
+ " Ctrl-A/Ctrl-X should do nothing in operator pending mode
+ %d
+ call setline(1, 'one two')
+ exe "normal! c\<C-A>l"
+ exe "normal! c\<C-X>l"
+ call assert_equal('one two', getline(1))
+
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_join.vim b/src/nvim/testdir/test_join.vim
index ac6ef8f29f..1f7a0825a5 100644
--- a/src/nvim/testdir/test_join.vim
+++ b/src/nvim/testdir/test_join.vim
@@ -437,5 +437,11 @@ func Test_join_lines()
call setline(1, ['a', 'b', '', 'c', 'd'])
normal 5J
call assert_equal('a b c d', getline(1))
+ call setline(1, ['a', 'b', 'c'])
+ 2,2join
+ call assert_equal(['a', 'b', 'c'], getline(1, '$'))
+ call assert_equal(2, line('.'))
+ 2join
+ call assert_equal(['a', 'b c'], getline(1, '$'))
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index e2b7554797..a34a950526 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -643,6 +643,13 @@ func Test_map_error()
map <expr> ,f abc
call assert_fails('normal ,f', 'E121:')
unmap <expr> ,f
+
+ " Recursive use of :normal in a map
+ set maxmapdepth=100
+ map gq :normal gq<CR>
+ call assert_fails('normal gq', 'E192:')
+ unmap gq
+ set maxmapdepth&
endfunc
" Test for <special> key mapping
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index 608f9883c2..74e63d9d69 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -215,6 +215,10 @@ func Test_mark_error()
call assert_fails('mark', 'E471:')
call assert_fails('mark xx', 'E488:')
call assert_fails('mark _', 'E191:')
+ call assert_beeps('normal! m~')
+
+ call setpos("'k", [0, 100, 1, 0])
+ call assert_fails("normal 'k", 'E19:')
endfunc
" Test for :lockmarks when pasting content
@@ -241,6 +245,29 @@ func Test_marks_k_cmd()
close!
endfunc
+" Test for file marks (A-Z)
+func Test_file_mark()
+ new Xone
+ call setline(1, ['aaa', 'bbb'])
+ norm! G$mB
+ w!
+ new Xtwo
+ call setline(1, ['ccc', 'ddd'])
+ norm! GmD
+ w!
+
+ enew
+ normal! `B
+ call assert_equal('Xone', bufname())
+ call assert_equal([2, 3], [line('.'), col('.')])
+ normal! 'D
+ call assert_equal('Xtwo', bufname())
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ call delete('Xone')
+ call delete('Xtwo')
+endfunc
+
" Test for the getmarklist() function
func Test_getmarklist()
new
diff --git a/src/nvim/testdir/test_move.vim b/src/nvim/testdir/test_move.vim
index f666a904b0..8c40369dbd 100644
--- a/src/nvim/testdir/test_move.vim
+++ b/src/nvim/testdir/test_move.vim
@@ -38,6 +38,7 @@ func Test_move()
call assert_fails("move -100", 'E16:')
call assert_fails("move +100", 'E16:')
call assert_fails('move', 'E16:')
+ call assert_fails("move 'r", 'E20:')
%bwipeout!
endfunc
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index f146726b7b..2d5b66df26 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -1,6 +1,8 @@
" Test for various Normal mode commands
source shared.vim
+source check.vim
+source view_util.vim
func Setup_NewWindow()
10new
@@ -53,7 +55,7 @@ func OpfuncDummy(type, ...)
let g:bufnr=bufnr('%')
endfunc
-fun! Test_normal00_optrans()
+func Test_normal00_optrans()
new
call append(0, ['1 This is a simple test: abcd', '2 This is the second line', '3 this is the third line'])
1
@@ -95,6 +97,12 @@ func Test_normal01_keymodel()
50
call feedkeys("\<S-Up>y", 'tx')
call assert_equal(['49', '5'], getreg(0, 0, 1))
+ " Use the different Shift special keys
+ 50
+ call feedkeys("\<S-Right>\<S-Left>\<S-Up>\<S-Down>\<S-Home>\<S-End>y", 'tx')
+ call assert_equal(['50'], getline("'<", "'>"))
+ call assert_equal(['50', ''], getreg(0, 0, 1))
+
" Do not start visual mode when keymodel=
set keymodel=
50
@@ -486,8 +494,8 @@ func Test_normal11_showcmd()
bw!
endfunc
+" Test for nv_error and normal command errors
func Test_normal12_nv_error()
- " Test for nv_error
10new
call setline(1, range(1,5))
" should not do anything, just beep
@@ -497,6 +505,22 @@ func Test_normal12_nv_error()
call assert_beeps("normal! g\<C-A>")
call assert_beeps("normal! g\<C-X>")
call assert_beeps("normal! g\<C-B>")
+ " call assert_beeps("normal! vQ\<Esc>")
+ call assert_beeps("normal! 2[[")
+ call assert_beeps("normal! 2]]")
+ call assert_beeps("normal! 2[]")
+ call assert_beeps("normal! 2][")
+ call assert_beeps("normal! 4[z")
+ call assert_beeps("normal! 4]z")
+ call assert_beeps("normal! 4[c")
+ call assert_beeps("normal! 4]c")
+ call assert_beeps("normal! 200%")
+ call assert_beeps("normal! %")
+ call assert_beeps("normal! 2{")
+ call assert_beeps("normal! 2}")
+ call assert_beeps("normal! r\<Right>")
+ call assert_beeps("normal! 8ry")
+ call assert_beeps('normal! "@')
bw!
endfunc
@@ -658,6 +682,13 @@ func Test_normal16_z_scroll_hor()
$put =lineB
1d
+ " Test for zl and zh with a count
+ norm! 0z10l
+ call assert_equal([11, 1], [col('.'), wincol()])
+ norm! z4h
+ call assert_equal([11, 5], [col('.'), wincol()])
+ normal! 2gg
+
" Test for zl
1
norm! 5zl
@@ -780,6 +811,27 @@ func Test_normal17_z_scroll_hor2()
bw!
endfunc
+" Test for H, M and L commands with folds
+func Test_scroll_cmds()
+ 15new
+ call setline(1, range(1, 100))
+ exe "normal! 30ggz\<CR>"
+ set foldenable
+ 33,36fold
+ 40,43fold
+ 46,49fold
+ let h = winheight(0)
+ " Top of the screen = 30
+ " Folded lines = 9
+ " Bottom of the screen = 30 + h + 9 - 1
+ normal! 4L
+ call assert_equal(35 + h, line('.'))
+ normal! 4H
+ call assert_equal(33, line('.'))
+ set foldenable&
+ close!
+endfunc
+
func Test_normal18_z_fold()
" basic tests for foldopen/folddelete
if !has("folding")
@@ -789,6 +841,9 @@ func Test_normal18_z_fold()
50
setl foldenable fdm=marker foldlevel=5
+ call assert_beeps('normal! zj')
+ call assert_beeps('normal! zk')
+
" Test for zF
" First fold
norm! 4zF
@@ -1221,6 +1276,9 @@ func Test_normal22_zet()
let a = readfile('Xfile_Test_normal22_zet')
call assert_equal(['1', '2'], a)
+ " Unsupported Z command
+ call assert_beeps('normal! ZW')
+
" Nvim: This sometimes hangs the TSAN build.
" for file in ['Xfile_Test_normal22_zet']
" call delete(file)
@@ -1289,6 +1347,15 @@ func Test_normal23_K()
call assert_match("man --pager=cat 'man'", a)
endif
+ " Error cases
+ call setline(1, '#$#')
+ call assert_fails('normal! ggK', 'E349:')
+ call setline(1, '---')
+ call assert_fails('normal! ggv2lK', 'E349:')
+ call setline(1, ['abc', 'xyz'])
+ call assert_fails("normal! gg2lv2h\<C-]>", 'E426:')
+ call assert_beeps("normal! ggVjK")
+
" clean up
let &keywordprg = k
bw!
@@ -1499,12 +1566,27 @@ func Test_normal28_parenthesis()
norm! $d(
call assert_equal(['With some sentences!', '', ' ', '', 'This is a long sentence', ''], getline(1, '$'))
+ " It is an error if a next sentence is not found
+ %d
+ call setline(1, '.SH')
+ call assert_beeps('normal )')
+
+ " Jumping to a fold should open the fold
+ call setline(1, ['', '', 'one', 'two', 'three'])
+ set foldenable
+ 2,$fold
+ call feedkeys(')', 'xt')
+ call assert_equal(3, line('.'))
+ call assert_equal(1, foldlevel('.'))
+ call assert_equal(-1, foldclosed('.'))
+ set foldenable&
+
" clean up
bw!
endfunc
-fun! Test_normal29_brace()
- " basic test for { and } movements
+" Test for { and } paragraph movements
+func Test_normal29_brace()
let text =<< trim [DATA]
A paragraph begins after each empty line, and also at each of a set of
paragraph macros, specified by the pairs of characters in the 'paragraphs'
@@ -1657,12 +1739,24 @@ fun! Test_normal29_brace()
" [DATA]
" call assert_equal(expected, getline(1, '$'))
+ " Jumping to a fold should open the fold
+ " %d
+ " call setline(1, ['', 'one', 'two', ''])
+ " set foldenable
+ " 2,$fold
+ " call feedkeys('}', 'xt')
+ " call assert_equal(4, line('.'))
+ " call assert_equal(1, foldlevel('.'))
+ " call assert_equal(-1, foldclosed('.'))
+ " set foldenable&
+
" clean up
set cpo-={
bw!
endfunc
-fun! Test_normal30_changecase()
+" Test for ~ command
+func Test_normal30_changecase()
new
call append(0, 'This is a simple test: äüöß')
norm! 1ggVu
@@ -1682,8 +1776,23 @@ fun! Test_normal30_changecase()
norm! V~
call assert_equal('THIS IS A simple test: äüöss', getline('.'))
- " Turkish ASCII turns to multi-byte. On some systems Turkish locale
- " is available but toupper()/tolower() don't do the right thing.
+ " Test for changing case across lines using 'whichwrap'
+ call setline(1, ['aaaaaa', 'aaaaaa'])
+ normal! gg10~
+ call assert_equal(['AAAAAA', 'aaaaaa'], getline(1, 2))
+ set whichwrap+=~
+ normal! gg10~
+ call assert_equal(['aaaaaa', 'AAAAaa'], getline(1, 2))
+ set whichwrap&
+
+ " clean up
+ bw!
+endfunc
+
+" Turkish ASCII turns to multi-byte. On some systems Turkish locale
+" is available but toupper()/tolower() don't do the right thing.
+func Test_normal_changecase_turkish()
+ new
try
lang tr_TR.UTF-8
set casemap=
@@ -1727,21 +1836,11 @@ fun! Test_normal30_changecase()
" can't use Turkish locale
throw 'Skipped: Turkish locale not available'
endtry
-
- call setline(1, ['aaaaaa', 'aaaaaa'])
- normal! gg10~
- call assert_equal(['AAAAAA', 'aaaaaa'], getline(1, 2))
- set whichwrap+=~
- normal! gg10~
- call assert_equal(['aaaaaa', 'AAAAaa'], getline(1, 2))
- set whichwrap&
-
- " clean up
- bw!
+ close!
endfunc
-fun! Test_normal31_r_cmd()
- " Test for r command
+" Test for r (replace) command
+func Test_normal31_r_cmd()
new
call append(0, 'This is a simple test: abcd')
exe "norm! 1gg$r\<cr>"
@@ -1760,6 +1859,22 @@ fun! Test_normal31_r_cmd()
exe "norm! 1gg05rf"
call assert_equal('fffffis a', getline(1))
+ " When replacing characters, copy characters from above and below lines
+ " using CTRL-Y and CTRL-E.
+ " Different code paths are used for utf-8 and latin1 encodings
+ set showmatch
+ for enc in ['latin1', 'utf-8']
+ enew!
+ let &encoding = enc
+ call setline(1, [' {a}', 'xxxxxxxxxx', ' [b]'])
+ exe "norm! 2gg5r\<C-Y>l5r\<C-E>"
+ call assert_equal(' {a}x [b]x', getline(2))
+ endfor
+ set showmatch&
+
+ " r command should fail in operator pending mode
+ call assert_beeps('normal! cr')
+
" clean up
set noautoindent
bw!
@@ -1783,7 +1898,7 @@ endfunc
" Test for g`, g;, g,, g&, gv, gk, gj, gJ, g0, g^, g_, gm, g$, gM, g CTRL-G,
" gi and gI commands
-fun! Test_normal33_g_cmd2()
+func Test_normal33_g_cmd2()
if !has("jumplist")
return
endif
@@ -1832,6 +1947,16 @@ fun! Test_normal33_g_cmd2()
norm! g&
call assert_equal(['11', '22', '33', '44', '55', '66', '77', '88', '9', '110', 'a', 'b', 'c', 'dd'], getline(1, '$'))
+ " Jumping to a fold using gg should open the fold
+ set foldenable
+ set foldopen+=jump
+ 5,8fold
+ call feedkeys('6gg', 'xt')
+ call assert_equal(1, foldlevel('.'))
+ call assert_equal(-1, foldclosed('.'))
+ set foldopen-=jump
+ set foldenable&
+
" Test for gv
%d
call append('$', repeat(['abcdefgh'], 8))
@@ -1975,6 +2100,10 @@ fun! Test_normal33_g_cmd2()
call assert_equal('foo first line', getline(1))
set virtualedit&
+ " Test for aboring a g command using CTRL-\ CTRL-G
+ exe "normal! g\<C-\>\<C-G>"
+ call assert_equal('foo first line', getline('.'))
+
" clean up
bw!
endfunc
@@ -1995,6 +2124,10 @@ func Test_g_ctrl_g()
let a = execute(":norm! g\<c-g>")
call assert_equal("\n--No lines in buffer--", a)
+ " Test for CTRL-G (same as :file)
+ let a = execute(":norm! \<c-g>")
+ call assert_equal("\n\n\"[No Name]\" --No lines in buffer--", a)
+
call setline(1, ['first line', 'second line'])
" Test g CTRL-g with dos, mac and unix file type.
@@ -2063,7 +2196,7 @@ func Test_g_ctrl_g()
endfunc
" Test for g8
-fun! Test_normal34_g_cmd3()
+func Test_normal34_g_cmd3()
new
let a=execute(':norm! 1G0g8')
call assert_equal("\nNUL", a)
@@ -2113,7 +2246,7 @@ func Test_normal_8g8()
endfunc
" Test for g<
-fun! Test_normal35_g_cmd4()
+func Test_normal35_g_cmd4()
" Cannot capture its output,
" probably a bug, therefore, test disabled:
throw "Skipped: output of g< can't be tested currently"
@@ -2123,7 +2256,7 @@ fun! Test_normal35_g_cmd4()
endfunc
" Test for gp gP go
-fun! Test_normal36_g_cmd5()
+func Test_normal36_g_cmd5()
new
call append(0, 'abcdefghijklmnopqrstuvwxyz')
set ff=unix
@@ -2162,7 +2295,7 @@ fun! Test_normal36_g_cmd5()
endfunc
" Test for gt and gT
-fun! Test_normal37_g_cmd6()
+func Test_normal37_g_cmd6()
tabnew 1.txt
tabnew 2.txt
tabnew 3.txt
@@ -2189,7 +2322,7 @@ fun! Test_normal37_g_cmd6()
endfunc
" Test for <Home> and <C-Home> key
-fun! Test_normal38_nvhome()
+func Test_normal38_nvhome()
new
call setline(1, range(10))
$
@@ -2211,8 +2344,21 @@ fun! Test_normal38_nvhome()
bw!
endfunc
+" Test for <End> and <C-End> keys
+func Test_normal_nvend()
+ new
+ call setline(1, map(range(1, 10), '"line" .. v:val'))
+ exe "normal! \<End>"
+ call assert_equal(5, col('.'))
+ exe "normal! 4\<End>"
+ call assert_equal([4, 5], [line('.'), col('.')])
+ exe "normal! \<C-End>"
+ call assert_equal([10, 6], [line('.'), col('.')])
+ close!
+endfunc
+
" Test for cw cW ce
-fun! Test_normal39_cw()
+func Test_normal39_cw()
" Test for cw and cW on whitespace
" and cpo+=w setting
new
@@ -2253,7 +2399,7 @@ fun! Test_normal39_cw()
endfunc
" Test for CTRL-\ commands
-fun! Test_normal40_ctrl_bsl()
+func Test_normal40_ctrl_bsl()
new
call append(0, 'here are some words')
exe "norm! 1gg0a\<C-\>\<C-N>"
@@ -2271,14 +2417,19 @@ fun! Test_normal40_ctrl_bsl()
exe ":norm! \<c-\>\<c-n>dw"
" set noim
call assert_equal('are some words', getline(1))
- " call assert_false(&insertmode)
+ call assert_false(&insertmode)
+ call assert_beeps("normal! \<C-\>\<C-A>")
+
+ " Using CTRL-\ CTRL-N in cmd window should close the window
+ call feedkeys("q:\<C-\>\<C-N>", 'xt')
+ call assert_equal('', getcmdwintype())
" clean up
bw!
endfunc
" Test for <c-r>=, <c-r><c-r>= and <c-r><c-o>= in insert mode
-fun! Test_normal41_insert_reg()
+func Test_normal41_insert_reg()
new
set sts=2 sw=2 ts=8 tw=0
call append(0, ["aaa\tbbb\tccc", '', '', ''])
@@ -2334,7 +2485,7 @@ func Test_normal42_halfpage()
endfunc
" Tests for text object aw
-fun! Test_normal43_textobject1()
+func Test_normal43_textobject1()
new
call append(0, ['foobar,eins,foobar', 'foo,zwei,foo '])
" diw
@@ -2505,7 +2656,7 @@ func Test_normal49_counts()
endfunc
func Test_normal50_commandline()
- if !has("timers") || !has("cmdline_hist") || !has("vertsplit")
+ if !has("timers") || !has("cmdline_hist")
return
endif
func! DoTimerWork(id)
@@ -2567,6 +2718,8 @@ func Test_normal52_rl()
call assert_equal(19, col('.'))
call feedkeys("\<right>", 'tx')
call assert_equal(18, col('.'))
+ call feedkeys("\<left>", 'tx')
+ call assert_equal(19, col('.'))
call feedkeys("\<s-right>", 'tx')
call assert_equal(13, col('.'))
call feedkeys("\<c-right>", 'tx')
@@ -2690,6 +2843,8 @@ func Test_changelist()
normal g;
call assert_equal([2, 2], [line('.'), col('.')])
call assert_fails('normal g;', 'E662:')
+ new
+ call assert_fails('normal g;', 'E664:')
%bwipe!
let &ul = save_ul
endfunc
@@ -2736,6 +2891,10 @@ endfunc
" Jumping to beginning and end of methods in Java-like languages
func Test_java_motion()
new
+ call assert_beeps('normal! [m')
+ call assert_beeps('normal! ]m')
+ call assert_beeps('normal! [M')
+ call assert_beeps('normal! ]M')
a
Piece of Java
{
@@ -2810,7 +2969,7 @@ Piece of Java
close!
endfunc
-fun! Test_normal_gdollar_cmd()
+func Test_normal_gdollar_cmd()
if !has("jumplist")
return
endif
@@ -2935,6 +3094,29 @@ func Test_normal_cpo_minus()
close!
endfunc
+" Test for displaying dollar when changing text ('$' flag in 'cpoptions')
+func Test_normal_cpo_dollar()
+ throw 'Skipped: use test/functional/legacy/cpoptions_spec.lua'
+ new
+ let g:Line = ''
+ func SaveFirstLine()
+ let g:Line = Screenline(1)
+ return ''
+ endfunc
+ inoremap <expr> <buffer> <F2> SaveFirstLine()
+ call test_override('redraw_flag', 1)
+ set cpo+=$
+ call setline(1, 'one two three')
+ redraw!
+ exe "normal c2w\<F2>vim"
+ call assert_equal('one tw$ three', g:Line)
+ call assert_equal('vim three', getline(1))
+ set cpo-=$
+ call test_override('ALL', 0)
+ delfunc SaveFirstLine
+ %bw!
+endfunc
+
" Test for using : to run a multi-line Ex command in operator pending mode
func Test_normal_yank_with_excmd()
new
@@ -2975,12 +3157,28 @@ func Test_wincmd_with_count()
endfunc
" Test for 'b', 'B' 'ge' and 'gE' commands
-func Test_backward_motion()
+func Test_horiz_motion()
+ new
normal! gg
call assert_beeps('normal! b')
call assert_beeps('normal! B')
call assert_beeps('normal! gE')
call assert_beeps('normal! ge')
+ " <S-Backspace> moves one word left and <C-Backspace> moves one WORD left
+ call setline(1, 'one ,two ,three')
+ exe "normal! $\<S-BS>"
+ call assert_equal(11, col('.'))
+ exe "normal! $\<C-BS>"
+ call assert_equal(10, col('.'))
+ close!
+endfunc
+
+" Test for using a : command in operator pending mode
+func Test_normal_colon_op()
+ new
+ call setline(1, ['one', 'two'])
+ call assert_beeps("normal! Gc:d\<CR>")
+ close!
endfunc
" Some commands like yy, cc, dd, >>, << and !! accept a count after
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 7b6cfa6bb4..2840378b97 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -290,9 +290,10 @@ func Test_set_errors()
call assert_fails('set regexpengine=3', 'E474:')
call assert_fails('set history=10001', 'E474:')
call assert_fails('set numberwidth=21', 'E474:')
- call assert_fails('set colorcolumn=-a')
- call assert_fails('set colorcolumn=a')
- call assert_fails('set colorcolumn=1,')
+ call assert_fails('set colorcolumn=-a', 'E474:')
+ call assert_fails('set colorcolumn=a', 'E474:')
+ call assert_fails('set colorcolumn=1,', 'E474:')
+ call assert_fails('set colorcolumn=1;', 'E474:')
call assert_fails('set cmdheight=-1', 'E487:')
call assert_fails('set cmdwinheight=-1', 'E487:')
if has('conceal')
@@ -343,9 +344,13 @@ func Test_set_errors()
call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:')
call assert_fails('set guicursor=i-ci', 'E545:')
call assert_fails('set guicursor=x', 'E545:')
+ call assert_fails('set guicursor=x:', 'E546:')
call assert_fails('set guicursor=r-cr:horx', 'E548:')
call assert_fails('set guicursor=r-cr:hor0', 'E549:')
endif
+ if has('mouseshape')
+ call assert_fails('se mouseshape=i-r:x', 'E547:')
+ endif
call assert_fails('set backupext=~ patchmode=~', 'E589:')
call assert_fails('set winminheight=10 winheight=9', 'E591:')
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
@@ -736,7 +741,26 @@ func Test_buftype()
call setline(1, ['L1'])
set buftype=nowrite
call assert_fails('write', 'E382:')
- close!
+
+ " for val in ['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', 'terminal', 'prompt', 'popup']
+ for val in ['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', 'prompt']
+ exe 'set buftype=' .. val
+ call writefile(['something'], 'XBuftype')
+ call assert_fails('write XBuftype', 'E13:', 'with buftype=' .. val)
+ endfor
+
+ call delete('XBuftype')
+ bwipe!
+endfunc
+
+" Test for the 'shell' option
+func Test_shell()
+ throw 'Skipped: Nvim does not have :shell'
+ CheckUnix
+ let save_shell = &shell
+ set shell=
+ call assert_fails('shell', 'E91:')
+ let &shell = save_shell
endfunc
" Test for the 'shellquote' option
diff --git a/src/nvim/testdir/test_plus_arg_edit.vim b/src/nvim/testdir/test_plus_arg_edit.vim
index 64533e71cf..c52044d064 100644
--- a/src/nvim/testdir/test_plus_arg_edit.vim
+++ b/src/nvim/testdir/test_plus_arg_edit.vim
@@ -18,7 +18,7 @@ func Test_edit_bad()
e! ++enc=utf8 Xfile
call assert_equal('[?][?][???][??]', getline(1))
- e! ++enc=utf8 ++bad=_ Xfile
+ e! ++encoding=utf8 ++bad=_ Xfile
call assert_equal('[_][_][___][__]', getline(1))
e! ++enc=utf8 ++bad=drop Xfile
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index a46ef8b3fe..97af3699a8 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -114,6 +114,16 @@ func Test_put_p_indent_visual()
bwipe!
endfunc
+" Test for deleting all the contents of a buffer with a put
+func Test_put_visual_delete_all_lines()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ let @r = ''
+ normal! VG"rgp
+ call assert_equal(1, line('$'))
+ close!
+endfunc
+
func Test_gp_with_count_leaves_cursor_at_end()
new
call setline(1, '<---->')
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 4f83c45770..5649652fd2 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -499,6 +499,7 @@ func Xtest_browse(cchar)
\ 'RegularLine2']
Xfirst
+ call assert_fails('-5Xcc', 'E16:')
call assert_fails('Xprev', 'E553')
call assert_fails('Xpfile', 'E553')
Xnfile
@@ -2891,6 +2892,21 @@ func Test_vimgrep_incsearch()
set noincsearch
endfunc
+" Test vimgrep with the last search pattern not set
+func Test_vimgrep_with_no_last_search_pat()
+ let lines =<< trim [SCRIPT]
+ call assert_fails('vimgrep // *', 'E35:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
" Test vimgrep without swap file
func Test_vimgrep_without_swap_file()
let lines =<< trim [SCRIPT]
@@ -4400,6 +4416,20 @@ func Test_splitview()
call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
new | only
+ " Using :split or :vsplit from a quickfix window should behave like a :new
+ " or a :vnew command
+ copen
+ split
+ call assert_equal(3, winnr('$'))
+ let l = getwininfo()
+ call assert_equal([0, 0, 1], [l[0].quickfix, l[1].quickfix, l[2].quickfix])
+ close
+ copen
+ vsplit
+ let l = getwininfo()
+ call assert_equal([0, 0, 1], [l[0].quickfix, l[1].quickfix, l[2].quickfix])
+ new | only
+
call delete('Xtestfile1')
call delete('Xtestfile2')
endfunc
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index 45e60a6d44..82d250e8b3 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -122,7 +122,10 @@ endfunc
" Tests for regexp patterns without multi-byte support.
func Test_regexp_single_line_pat()
" tl is a List of Lists with:
- " regexp engine
+ " regexp engines to test
+ " 0 - test with 'regexpengine' values 0 and 1
+ " 1 - test with 'regexpengine' values 0 and 2
+ " 2 - test with 'regexpengine' values 0, 1 and 2
" regexp pattern
" text to test the pattern on
" expected match (optional)
@@ -143,6 +146,8 @@ func Test_regexp_single_line_pat()
call add(tl, [2, 'c*', 'abdef', ''])
call add(tl, [2, 'bc\+', 'abccccdef', 'bcccc'])
call add(tl, [2, 'bc\+', 'abdef']) " no match
+ " match newline character in a string
+ call add(tl, [2, 'o\nb', "foo\nbar", "o\nb"])
" operator \|
call add(tl, [2, 'a\|ab', 'cabd', 'a']) " alternation is ordered
@@ -566,6 +571,9 @@ func Test_regexp_single_line_pat()
" Test \%V atom
call add(tl, [2, '\%>70vGesamt', 'Jean-Michel Charlier & Victor Hubinon\Gesamtausgabe [Salleck] Buck Danny {Jean-Michel Charlier & Victor Hubinon}\Gesamtausgabe', 'Gesamt'])
+ " Test for ignoring case and matching repeated characters
+ call add(tl, [2, '\cb\+', 'aAbBbBcC', 'bBbB'])
+
" Run the tests
for t in tl
let re = t[0]
@@ -625,6 +633,14 @@ endfunc
" Tests for multi-line regexp patterns without multi-byte support.
func Test_regexp_multiline_pat()
+ " tl is a List of Lists with:
+ " regexp engines to test
+ " 0 - test with 'regexpengine' values 0 and 1
+ " 1 - test with 'regexpengine' values 0 and 2
+ " 2 - test with 'regexpengine' values 0, 1 and 2
+ " regexp pattern
+ " List with text to test the pattern on
+ " List with the expected match
let tl = []
" back references
@@ -634,6 +650,70 @@ func Test_regexp_multiline_pat()
" line breaks
call add(tl, [2, '\S.*\nx', ['abc', 'def', 'ghi', 'xjk', 'lmn'], ['abc', 'def', 'XXjk', 'lmn']])
+ " Any single character or end-of-line
+ call add(tl, [2, '\_.\+', ['a', 'b', 'c'], ['XX']])
+ " Any identifier or end-of-line
+ call add(tl, [2, '\_i\+', ['a', 'b', ';', '2'], ['XX;XX']])
+ " Any identifier but excluding digits or end-of-line
+ call add(tl, [2, '\_I\+', ['a', 'b', ';', '2'], ['XX;XX2XX']])
+ " Any keyword or end-of-line
+ call add(tl, [2, '\_k\+', ['a', 'b', '=', '2'], ['XX=XX']])
+ " Any keyword but excluding digits or end-of-line
+ call add(tl, [2, '\_K\+', ['a', 'b', '=', '2'], ['XX=XX2XX']])
+ " Any filename character or end-of-line
+ call add(tl, [2, '\_f\+', ['a', 'b', '.', '5'], ['XX']])
+ " Any filename character but excluding digits or end-of-line
+ call add(tl, [2, '\_F\+', ['a', 'b', '.', '5'], ['XX5XX']])
+ " Any printable character or end-of-line
+ call add(tl, [2, '\_p\+', ['a', 'b', '=', '4'], ['XX']])
+ " Any printable character excluding digits or end-of-line
+ call add(tl, [2, '\_P\+', ['a', 'b', '=', '4'], ['XX4XX']])
+ " Any whitespace character or end-of-line
+ call add(tl, [2, '\_s\+', [' ', ' ', 'a', 'b'], ['XXaXXbXX']])
+ " Any non-whitespace character or end-of-line
+ call add(tl, [2, '\_S\+', [' ', ' ', 'a', 'b'], [' XX XX']])
+ " Any decimal digit or end-of-line
+ call add(tl, [2, '\_d\+', ['1', 'a', '2', 'b', '3'], ['XXaXXbXX']])
+ " Any non-decimal digit or end-of-line
+ call add(tl, [2, '\_D\+', ['1', 'a', '2', 'b', '3'], ['1XX2XX3XX']])
+ " Any hexadecimal digit or end-of-line
+ call add(tl, [2, '\_x\+', ['1', 'a', 'g', '9', '8'], ['XXgXX']])
+ " Any non-hexadecimal digit or end-of-line
+ call add(tl, [2, '\_X\+', ['1', 'a', 'g', '9', '8'], ['1XXaXX9XX8XX']])
+ " Any octal digit or end-of-line
+ call add(tl, [2, '\_o\+', ['0', '7', '8', '9', '0'], ['XX8XX9XX']])
+ " Any non-octal digit or end-of-line
+ call add(tl, [2, '\_O\+', ['0', '7', '8', '9', '0'], ['0XX7XX0XX']])
+ " Any word character or end-of-line
+ call add(tl, [2, '\_w\+', ['A', 'B', '=', 'C', 'D'], ['XX=XX']])
+ " Any non-word character or end-of-line
+ call add(tl, [2, '\_W\+', ['A', 'B', '=', 'C', 'D'], ['AXXBXXCXXDXX']])
+ " Any head-of-word character or end-of-line
+ call add(tl, [2, '\_h\+', ['a', '1', 'b', '2', 'c'], ['XX1XX2XX']])
+ " Any non-head-of-word character or end-of-line
+ call add(tl, [2, '\_H\+', ['a', '1', 'b', '2', 'c'], ['aXXbXXcXX']])
+ " Any alphabetic character or end-of-line
+ call add(tl, [2, '\_a\+', ['a', '1', 'b', '2', 'c'], ['XX1XX2XX']])
+ " Any non-alphabetic character or end-of-line
+ call add(tl, [2, '\_A\+', ['a', '1', 'b', '2', 'c'], ['aXXbXXcXX']])
+ " Any lowercase character or end-of-line
+ call add(tl, [2, '\_l\+', ['a', 'A', 'b', 'B'], ['XXAXXBXX']])
+ " Any non-lowercase character or end-of-line
+ call add(tl, [2, '\_L\+', ['a', 'A', 'b', 'B'], ['aXXbXX']])
+ " Any uppercase character or end-of-line
+ call add(tl, [2, '\_u\+', ['a', 'A', 'b', 'B'], ['aXXbXX']])
+ " Any non-uppercase character or end-of-line
+ call add(tl, [2, '\_U\+', ['a', 'A', 'b', 'B'], ['XXAXXBXX']])
+ " Collection or end-of-line
+ call add(tl, [2, '\_[a-z]\+', ['a', 'A', 'b', 'B'], ['XXAXXBXX']])
+ " start of line anywhere in the text
+ call add(tl, [2, 'one\zs\_s*\_^\zetwo',
+ \ ['', 'one', ' two', 'one', '', 'two'],
+ \ ['', 'one', ' two', 'oneXXtwo']])
+ " end of line anywhere in the text
+ call add(tl, [2, 'one\zs\_$\_s*two',
+ \ ['', 'one', ' two', 'one', '', 'two'], ['', 'oneXX', 'oneXX']])
+
" Check that \_[0-9] matching EOL does not break a following \>
call add(tl, [2, '\<\(\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\.\)\{3\}\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\>', ['', 'localnet/192.168.0.1', ''], ['', 'localnet/XX', '']])
@@ -649,7 +729,7 @@ func Test_regexp_multiline_pat()
let before = t[2]
let after = t[3]
for engine in [0, 1, 2]
- if engine == 2 && re == 0 || engine == 1 && re ==1
+ if engine == 2 && re == 0 || engine == 1 && re == 1
continue
endif
let &regexpengine = engine
@@ -697,9 +777,8 @@ func Test_lookbehind_across_line()
bwipe!
endfunc
-" Check matching Visual area
-func Test_matching_visual_area()
- new
+" Test for the \%V atom (match inside the visual area)
+func Regex_Match_Visual_Area()
call append(0, ['Visual:', 'thexe the thexethe', 'andaxand andaxand',
\ 'oooxofor foroxooo', 'oooxofor foroxooo'])
call cursor(1, 1)
@@ -708,12 +787,22 @@ func Test_matching_visual_area()
exe "normal jfx\<C-V>fxj:s/\\%Vo/O/g\<CR>"
call assert_equal(['Visual:', 'thexE thE thExethe', 'AndAxAnd AndAxAnd',
\ 'oooxOfOr fOrOxooo', 'oooxOfOr fOrOxooo', ''], getline(1, '$'))
+ %d
+endfunc
+
+" Check matching Visual area
+func Test_matching_visual_area()
+ new
+ set regexpengine=1
+ call Regex_Match_Visual_Area()
+ set regexpengine=2
+ call Regex_Match_Visual_Area()
+ set regexpengine&
bwipe!
endfunc
" Check matching marks
-func Test_matching_marks()
- new
+func Regex_Mark()
call append(0, ['', '', '', 'Marks:', 'asdfSasdfsadfEasdf', 'asdfSas',
\ 'dfsadfEasdf', '', '', '', '', ''])
call cursor(4, 1)
@@ -721,6 +810,15 @@ func Test_matching_marks()
exe "normal jfSmsj0fEme:.-4,.+6s/.\\%>'s\\_.*\\%<'e../again/\<CR>"
call assert_equal(['', '', '', 'Marks:', 'asdfhereasdf', 'asdfagainasdf',
\ '', '', '', '', '', ''], getline(1, '$'))
+ %d
+endfunc
+
+func Test_matching_marks()
+ new
+ set regexpengine=1
+ call Regex_Mark()
+ set regexpengine=2
+ call Regex_Mark()
bwipe!
endfunc
@@ -761,8 +859,7 @@ func Test_matching_curpos()
endfunc
" Test for matching the start and end of a buffer
-func Test_start_end_of_buffer_match()
- new
+func Regex_start_end_buffer()
call setline(1, repeat(['vim edit'], 20))
/\%^
call assert_equal([0, 1, 1, 0], getpos('.'))
@@ -772,6 +869,15 @@ func Test_start_end_of_buffer_match()
call assert_equal([0, 20, 8, 0], getpos('.'))
exe "normal 6gg/..\\%$\<CR>"
call assert_equal([0, 20, 7, 0], getpos('.'))
+ %d
+endfunc
+
+func Test_start_end_of_buffer_match()
+ new
+ set regexpengine=1
+ call Regex_start_end_buffer()
+ set regexpengine=2
+ call Regex_start_end_buffer()
bwipe!
endfunc
@@ -784,10 +890,20 @@ endfunc
" Check for detecting error
func Test_regexp_error()
- set regexpengine=2
- call assert_fails("call matchlist('x x', ' \\ze*')", 'E888:')
- call assert_fails("call matchlist('x x', ' \\zs*')", 'E888:')
- set re&
+ call assert_fails("call matchlist('x x', '\\%#=1 \\zs*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=1 \\ze*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=2 \\zs*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=2 \\ze*')", 'E888:')
+ call assert_fails('exe "normal /\\%#=1\\%[x\\%[x]]\<CR>"', 'E369:')
+endfunc
+
+" Test for using the last substitute string pattern (~)
+func Test_regexp_last_subst_string()
+ new
+ s/bar/baz/e
+ call assert_equal(matchstr("foo\nbaz\nbar", "\\%#=1\~"), "baz")
+ call assert_equal(matchstr("foo\nbaz\nbar", "\\%#=2\~"), "baz")
+ close!
endfunc
" Check patterns matching cursor position.
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index b852cfd22f..abe28b77cd 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -416,6 +416,20 @@ func Test_put_reg_restart_mode()
bwipe!
endfunc
+" Test for executing a register using :@ command
+func Test_execute_register()
+ call setreg('r', [])
+ call assert_beeps('@r')
+ let i = 1
+ let @q = 'let i+= 1'
+ @q
+ @
+ call assert_equal(3, i)
+
+ " cannot execute a register in operator pending mode
+ call assert_beeps('normal! c@r')
+endfunc
+
" Test for getting register info
func Test_get_reginfo()
enew
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 454c956996..747fb0e384 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -19,9 +19,9 @@ func Test_search_cmdline()
set noincsearch
:1
call feedkeys("/foobar\<cr>", 'tx')
- call feedkeys("/the\<cr>",'tx')
+ call feedkeys("/the\<cr>", 'tx')
call assert_equal('the', @/)
- call feedkeys("/thes\<C-P>\<C-P>\<cr>",'tx')
+ call feedkeys("/thes\<C-P>\<C-P>\<cr>", 'tx')
call assert_equal('foobar', @/)
" Test 2
@@ -655,10 +655,49 @@ func Test_search_cmdline7()
bw!
endfunc
-" Tests for regexp with various magic settings
-func Test_search_regexp()
- enew!
+func Test_search_cmdline8()
+ " Highlighting is cleared in all windows
+ " since hls applies to all windows
+ CheckOption incsearch
+ CheckFeature terminal
+ CheckNotGui
+ if has("win32")
+ throw "Skipped: Bug with sending <ESC> to terminal window not fixed yet"
+ endif
+
+ let h = winheight(0)
+ if h < 3
+ return
+ endif
+ " Prepare buffer text
+ let lines = ['abb vim vim vi', 'vimvivim']
+ call writefile(lines, 'Xsearch.txt')
+ let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
+ call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
+
+ call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
+ call term_sendkeys(buf, ":14vsp\<cr>")
+ call term_sendkeys(buf, "/vim\<cr>")
+ call term_sendkeys(buf, "/b\<esc>")
+ call term_sendkeys(buf, "gg0")
+ call TermWait(buf, 250)
+ let screen_line = term_scrape(buf, 1)
+ let [a0,a1,a2,a3] = [screen_line[3].attr, screen_line[4].attr,
+ \ screen_line[18].attr, screen_line[19].attr]
+ call assert_notequal(a0, a1)
+ call assert_notequal(a0, a3)
+ call assert_notequal(a1, a2)
+ call assert_equal(a0, a2)
+ call assert_equal(a1, a3)
+ " clean up
+ call delete('Xsearch.txt')
+
+ bwipe!
+endfunc
+
+" Tests for regexp with various magic settings
+func Run_search_regexp_magic_opt()
put ='1 a aa abb abbccc'
exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
call assert_equal([0, 2, 17, 0], getpos('.'))
@@ -693,6 +732,18 @@ func Test_search_regexp()
exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
call assert_equal([0, 9, 7, 0], getpos('.'))
+ %d
+endfunc
+
+func Test_search_regexp()
+ enew!
+
+ set regexpengine=1
+ call Run_search_regexp_magic_opt()
+ set regexpengine=2
+ call Run_search_regexp_magic_opt()
+ set regexpengine&
+
set undolevels=100
put ='9 foobar'
put =''
@@ -700,12 +751,12 @@ func Test_search_regexp()
normal G
exe 'normal! dv?bar?' . "\<CR>"
call assert_equal('9 foo', getline('.'))
- call assert_equal([0, 10, 5, 0], getpos('.'))
- call assert_equal(10, line('$'))
+ call assert_equal([0, 2, 5, 0], getpos('.'))
+ call assert_equal(2, line('$'))
normal u
call assert_equal('9 foobar', getline('.'))
- call assert_equal([0, 10, 6, 0], getpos('.'))
- call assert_equal(11, line('$'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
+ call assert_equal(3, line('$'))
set undolevels&
enew!
@@ -1433,7 +1484,7 @@ func Test_large_hex_chars2()
endfunc
func Test_one_error_msg()
- " This was also giving an internal error
+ " This was also giving an internal error
call assert_fails('call search(" \\((\\v[[=P=]]){185}+ ")', 'E871:')
endfunc
@@ -1478,6 +1529,20 @@ func Test_search_match_at_curpos()
close!
endfunc
+" Test for error cases with the search() function
+func Test_search_errors()
+ call assert_fails("call search('pat', [])", 'E730:')
+ call assert_fails("call search('pat', 'b', {})", 'E728:')
+ call assert_fails("call search('pat', 'b', 1, [])", 'E745:')
+ call assert_fails("call search('pat', 'ns')", 'E475:')
+ call assert_fails("call search('pat', 'mr')", 'E475:')
+
+ new
+ call setline(1, ['foo', 'bar'])
+ call assert_fails('call feedkeys("/foo/;/bar/;\<CR>", "tx")', 'E386:')
+ bwipe!
+endfunc
+
func Test_search_display_pattern()
new
call setline(1, ['foo', 'bar', 'foobar'])
@@ -1541,6 +1606,132 @@ func Test_search_special()
exe "norm /\x80PS"
endfunc
+" Test for command failures when the last search pattern is not set.
+" Need to run this in a new vim instance where last search pattern is not set.
+func Test_search_with_no_last_pat()
+ let lines =<< trim [SCRIPT]
+ call assert_fails("normal i\<C-R>/\e", 'E35:')
+ call assert_fails("exe '/'", 'E35:')
+ call assert_fails("exe '?'", 'E35:')
+ call assert_fails("/", 'E35:')
+ call assert_fails("?", 'E35:')
+ call assert_fails("normal n", 'E35:')
+ call assert_fails("normal N", 'E35:')
+ call assert_fails("normal gn", 'E35:')
+ call assert_fails("normal gN", 'E35:')
+ call assert_fails("normal cgn", 'E35:')
+ call assert_fails("normal cgN", 'E35:')
+ let p = []
+ let p = @/
+ call assert_equal('', p)
+ call assert_fails("normal :\<C-R>/", 'E35:')
+ call assert_fails("//p", 'E35:')
+ call assert_fails(";//p", 'E35:')
+ call assert_fails("??p", 'E35:')
+ call assert_fails(";??p", 'E35:')
+ call assert_fails('g//p', 'E476:')
+ call assert_fails('v//p', 'E476:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for using tilde (~) atom in search. This should use the last used
+" substitute pattern
+func Test_search_tilde_pat()
+ let lines =<< trim [SCRIPT]
+ set regexpengine=1
+ call assert_fails('exe "normal /~\<CR>"', 'E33:')
+ call assert_fails('exe "normal ?~\<CR>"', 'E33:')
+ set regexpengine=2
+ call assert_fails('exe "normal /~\<CR>"', 'E383:')
+ call assert_fails('exe "normal ?~\<CR>"', 'E383:')
+ set regexpengine&
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for searching a pattern that is not present with 'nowrapscan'
+func Test_search_pat_not_found()
+ new
+ set nowrapscan
+ let @/ = '1abcxyz2'
+ call assert_fails('normal n', 'E385:')
+ call assert_fails('normal N', 'E384:')
+ set wrapscan&
+ close
+endfunc
+
+" Test for v:searchforward variable
+func Test_searchforward_var()
+ new
+ call setline(1, ['foo', '', 'foo'])
+ call cursor(2, 1)
+ let @/ = 'foo'
+ let v:searchforward = 0
+ normal N
+ call assert_equal(3, line('.'))
+ call cursor(2, 1)
+ let v:searchforward = 1
+ normal N
+ call assert_equal(1, line('.'))
+ close!
+endfunc
+
+" Test for invalid regular expressions
+func Test_invalid_regexp()
+ set regexpengine=1
+ call assert_fails("call search(repeat('\\(.\\)', 10))", 'E51:')
+ call assert_fails("call search('\\%(')", 'E53:')
+ call assert_fails("call search('\\(')", 'E54:')
+ call assert_fails("call search('\\)')", 'E55:')
+ call assert_fails("call search('x\\@#')", 'E59:')
+ call assert_fails('call search(''\v%(%(%(%(%(%(%(%(%(%(%(a){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}'')', 'E60:')
+ call assert_fails("call search('a\\+*')", 'E61:')
+ call assert_fails("call search('\\_m')", 'E63:')
+ call assert_fails("call search('\\+')", 'E64:')
+ call assert_fails("call search('\\1')", 'E65:')
+ call assert_fails("call search('\\z\\(\\)')", 'E66:')
+ call assert_fails("call search('\\z2')", 'E67:')
+ call assert_fails("call search('\\zx')", 'E68:')
+ call assert_fails("call search('\\%[ab')", 'E69:')
+ call assert_fails("call search('\\%[]')", 'E70:')
+ call assert_fails("call search('\\%a')", 'E71:')
+ call assert_fails("call search('ab\\%[\\(cd\\)]')", 'E369:')
+ call assert_fails("call search('ab\\%[\\%(cd\\)]')", 'E369:')
+ set regexpengine=2
+ call assert_fails("call search('\\_')", 'E865:')
+ call assert_fails("call search('\\+')", 'E866:')
+ call assert_fails("call search('\\zx')", 'E867:')
+ call assert_fails("call search('\\%a')", 'E867:')
+ call assert_fails("call search('x\\@#')", 'E869:')
+ call assert_fails("call search(repeat('\\(.\\)', 10))", 'E872:')
+ call assert_fails("call search('\\_m')", 'E877:')
+ call assert_fails("call search('\\%(')", 'E53:')
+ call assert_fails("call search('\\(')", 'E54:')
+ call assert_fails("call search('\\)')", 'E55:')
+ call assert_fails("call search('\\z\\(\\)')", 'E66:')
+ call assert_fails("call search('\\%[ab')", 'E69:')
+ call assert_fails("call search('\\%[]')", 'E70:')
+ call assert_fails("call search('\\%9999999999999999999999999999v')", 'E951:')
+ set regexpengine&
+ call assert_fails("call search('\\%#=3ab')", 'E864:')
+endfunc
+
" Test 'smartcase' with utf-8.
func Test_search_smartcase_utf8()
new
diff --git a/src/nvim/testdir/test_smartindent.vim b/src/nvim/testdir/test_smartindent.vim
index f3650a9ac4..e2d028e828 100644
--- a/src/nvim/testdir/test_smartindent.vim
+++ b/src/nvim/testdir/test_smartindent.vim
@@ -21,9 +21,7 @@ endfunc
func Test_smartindent_has_no_effect()
new
exe "normal! i\<Tab>one\<Esc>"
- set noautoindent
- set smartindent
- set indentexpr=
+ setlocal noautoindent smartindent indentexpr=
exe "normal! Gotwo\<Esc>"
call assert_equal("\ttwo", getline("$"))
@@ -32,16 +30,13 @@ func Test_smartindent_has_no_effect()
call assert_equal("three", getline("$"))
delfunction! MyIndent
- set autoindent&
- set smartindent&
- set indentexpr&
bwipe!
endfunc
" Test for inserting '{' and '} with smartindent
func Test_smartindent_braces()
new
- set smartindent shiftwidth=4
+ setlocal smartindent shiftwidth=4
call setline(1, [' if (a)', "\tif (b)", "\t return 1"])
normal 2ggO{
normal 3ggA {
@@ -57,7 +52,62 @@ func Test_smartindent_braces()
\ "\t}",
\ ' }'
\ ], getline(1, '$'))
- set si& sw& ai&
+ close!
+endfunc
+
+" Test for adding a new line before and after comments with smartindent
+func Test_si_add_line_around_comment()
+ new
+ setlocal smartindent shiftwidth=4
+ call setline(1, [' A', '# comment1', '# comment2'])
+ exe "normal GoC\<Esc>2GOB"
+ call assert_equal([' A', ' B', '# comment1', '# comment2', ' C'],
+ \ getline(1, '$'))
+ close!
+endfunc
+
+" After a C style comment, indent for a following line should line up with the
+" line containing the start of the comment.
+func Test_si_indent_after_c_comment()
+ new
+ setlocal smartindent shiftwidth=4 fo+=ro
+ exe "normal i\<C-t>/*\ncomment\n/\n#define FOOBAR\n75\<Esc>ggOabc"
+ normal 3jOcont
+ call assert_equal([' abc', ' /*', ' * comment', ' * cont',
+ \ ' */', '#define FOOBAR', ' 75'], getline(1, '$'))
+ close!
+endfunc
+
+" Test for indenting a statement after a if condition split across lines
+func Test_si_if_cond_split_across_lines()
+ new
+ setlocal smartindent shiftwidth=4
+ exe "normal i\<C-t>if (cond1 &&\n\<C-t>cond2) {\ni = 10;\n}"
+ call assert_equal([' if (cond1 &&', "\t cond2) {", "\ti = 10;",
+ \ ' }'], getline(1, '$'))
+ close!
+endfunc
+
+" Test for inserting lines before and after a one line comment
+func Test_si_one_line_comment()
+ new
+ setlocal smartindent shiftwidth=4
+ exe "normal i\<C-t>abc;\n\<C-t>/* comment */"
+ normal oi = 10;
+ normal kOj = 1;
+ call assert_equal([' abc;', "\tj = 1;", "\t/* comment */", "\ti = 10;"],
+ \ getline(1, '$'))
+ close!
+endfunc
+
+" Test for smartindent with a comment continued across multiple lines
+func Test_si_comment_line_continuation()
+ new
+ setlocal smartindent shiftwidth=4
+ call setline(1, ['# com1', '# com2 \', ' contd', '# com3', ' xyz'])
+ normal ggOabc
+ call assert_equal([' abc', '# com1', '# com2 \', ' contd', '# com3',
+ \ ' xyz'], getline(1, '$'))
close!
endfunc
diff --git a/src/nvim/testdir/test_sort.vim b/src/nvim/testdir/test_sort.vim
index 540c73a772..9895ad754c 100644
--- a/src/nvim/testdir/test_sort.vim
+++ b/src/nvim/testdir/test_sort.vim
@@ -1489,6 +1489,22 @@ func Test_sort_last_search_pat()
close!
endfunc
+" Test for :sort with no last search pattern
+func Test_sort_with_no_last_search_pat()
+ let lines =<< trim [SCRIPT]
+ call setline(1, ['3b', '1c', '2a'])
+ call assert_fails('sort //', 'E35:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
" Test for retaining marks across a :sort
func Test_sort_with_marks()
new
diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim
index b8fe8422b3..ba6fd5ad95 100644
--- a/src/nvim/testdir/test_source.vim
+++ b/src/nvim/testdir/test_source.vim
@@ -57,3 +57,34 @@ func Test_different_script()
call assert_fails('source XtwoScript', 'E121:')
call delete('XtwoScript')
endfunc
+
+" When sourcing a vim script, shebang should be ignored.
+func Test_source_ignore_shebang()
+ call writefile(['#!./xyzabc', 'let g:val=369'], 'Xfile.vim')
+ source Xfile.vim
+ call assert_equal(g:val, 369)
+ call delete('Xfile.vim')
+endfunc
+
+" Test for expanding <sfile> in a autocmd and for <slnum> and <sflnum>
+func Test_source_autocmd_sfile()
+ let code =<< trim [CODE]
+ let g:SfileName = ''
+ augroup sfiletest
+ au!
+ autocmd User UserAutoCmd let g:Sfile = '<sfile>:t'
+ augroup END
+ doautocmd User UserAutoCmd
+ let g:Slnum = expand('<slnum>')
+ let g:Sflnum = expand('<sflnum>')
+ augroup! sfiletest
+ [CODE]
+ call writefile(code, 'Xscript.vim')
+ source Xscript.vim
+ call assert_equal('Xscript.vim', g:Sfile)
+ call assert_equal('7', g:Slnum)
+ call assert_equal('8', g:Sflnum)
+ call delete('Xscript.vim')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 58f0760f48..7744c5bcca 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -827,6 +827,16 @@ func Test_spell_good_word_invalid()
bwipe!
endfunc
+func Test_spell_good_word_slash()
+ " This caused E1280.
+ new
+ norm afoo /
+ 1
+ norm zG
+
+ bwipe!
+endfunc
+
func LoadAffAndDic(aff_contents, dic_contents)
throw 'skipped: Nvim does not support enc=latin1'
set enc=latin1
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 619b63202a..f795d1c0cf 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -294,7 +294,7 @@ endfunc
" Test for *:s%* on :substitute.
func Test_sub_cmd_6()
- throw "skipped: Nvim removed POSIX-related 'cpoptions' flags"
+ throw 'Skipped: Nvim does not support cpoptions flag "/"'
set magic&
set cpo+=/
@@ -808,6 +808,41 @@ func Test_sub_expand_text()
close!
endfunc
+" Test for command failures when the last substitute pattern is not set.
+func Test_sub_with_no_last_pat()
+ let lines =<< trim [SCRIPT]
+ call assert_fails('~', 'E33:')
+ call assert_fails('s//abc/g', 'E476:')
+ call assert_fails('s\/bar', 'E476:')
+ call assert_fails('s\&bar&', 'E476:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+
+ " Nvim does not support cpoptions flag "/"'
+ " let lines =<< trim [SCRIPT]
+ " set cpo+=/
+ " call assert_fails('s/abc/%/', 'E33:')
+ " call writefile(v:errors, 'Xresult')
+ " qall!
+ " [SCRIPT]
+ " call writefile(lines, 'Xscript')
+ " if RunVim([], [], '--clean -S Xscript')
+ " call assert_equal([], readfile('Xresult'))
+ " endif
+
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+func Test_substitute()
+ call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+endfunc
+
func Test_submatch_list_concatenate()
let pat = 'A\(.\)'
let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])}
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index b180f27685..923e1cbf50 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -278,7 +278,6 @@ func Test_swap_recover_ext()
autocmd SwapExists * let v:swapchoice = 'r'
augroup END
-
" Create a valid swapfile by editing a file with a special extension.
split Xtest.scr
call setline(1, ['one', 'two', 'three'])
@@ -311,6 +310,46 @@ func Test_swap_recover_ext()
augroup! test_swap_recover_ext
endfunc
+" Test for closing a split window automatically when a swap file is detected
+" and 'Q' is selected in the confirmation prompt.
+func Test_swap_split_win()
+ autocmd! SwapExists
+ augroup test_swap_splitwin
+ autocmd!
+ autocmd SwapExists * let v:swapchoice = 'q'
+ augroup END
+
+ " Create a valid swapfile by editing a file with a special extension.
+ split Xtest.scr
+ call setline(1, ['one', 'two', 'three'])
+ write " file is written, not modified
+ write " write again to make sure the swapfile is created
+ " read the swapfile as a Blob
+ let swapfile_name = swapname('%')
+ let swapfile_bytes = readfile(swapfile_name, 'B')
+
+ " Close and delete the file and recreate the swap file.
+ quit
+ call delete('Xtest.scr')
+ call writefile(swapfile_bytes, swapfile_name)
+ " Split edit the file again. This should fail to open the window
+ try
+ split Xtest.scr
+ catch
+ " E308 should be caught, not E306.
+ call assert_exception('E308:') " Original file may have been changed
+ endtry
+ call assert_equal(1, winnr('$'))
+
+ call delete('Xtest.scr')
+ call delete(swapfile_name)
+
+ augroup test_swap_splitwin
+ autocmd!
+ augroup END
+ augroup! test_swap_splitwin
+endfunc
+
" Test for selecting 'q' in the attention prompt
func Test_swap_prompt_splitwin()
CheckRunVimInTerminal
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 51ab5c1022..9a115da8d3 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -139,7 +139,11 @@ function Test_tabpage()
call assert_fails("tabmove -99", 'E474:')
call assert_fails("tabmove -3+", 'E474:')
call assert_fails("tabmove $3", 'E474:')
+ call assert_fails("%tabonly", 'E16:')
1tabonly!
+ tabnew
+ call assert_fails("-2tabmove", 'E474:')
+ tabonly!
endfunc
" Test autocommands
@@ -607,6 +611,16 @@ func Test_tabpage_cmdheight()
call delete('XTest_tabpage_cmdheight')
endfunc
+" Test for closing the tab page from a command window
+func Test_tabpage_close_cmdwin()
+ tabnew
+ call feedkeys("q/:tabclose\<CR>\<Esc>", 'xt')
+ call assert_equal(2, tabpagenr('$'))
+ call feedkeys("q/:tabonly\<CR>\<Esc>", 'xt')
+ call assert_equal(2, tabpagenr('$'))
+ tabonly
+endfunc
+
" Return the terminal key code for selecting a tab page from the tabline. This
" sequence contains the following codes: a CSI (0x9b), KS_TABLINE (0xf0),
" KS_FILLER (0x58) and then the tab page number.
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 11e32067b2..b1746641ee 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -935,6 +935,11 @@ func Test_tag_multimatch()
tag FIRST
tnext
call assert_equal(2, line('.'))
+ tlast
+ tprev
+ call assert_equal(2, line('.'))
+ tNext
+ call assert_equal(1, line('.'))
set ignorecase&
call delete('Xtags')
@@ -1077,6 +1082,213 @@ Type number and <Enter> (q or empty cancels):
%bwipe
endfunc
+" Test for :isearch, :ilist, :ijump and :isplit commands
+" Test for [i, ]i, [I, ]I, [ CTRL-I, ] CTRL-I and CTRL-W i commands
+func Test_inc_search()
+ new
+ call setline(1, ['1:foo', '2:foo', 'foo', '3:foo', '4:foo'])
+ call cursor(3, 1)
+
+ " Test for [i and ]i
+ call assert_equal('1:foo', execute('normal [i'))
+ call assert_equal('2:foo', execute('normal 2[i'))
+ call assert_fails('normal 3[i', 'E387:')
+ call assert_equal('3:foo', execute('normal ]i'))
+ call assert_equal('4:foo', execute('normal 2]i'))
+ call assert_fails('normal 3]i', 'E389:')
+
+ " Test for :isearch
+ call assert_equal('1:foo', execute('isearch foo'))
+ call assert_equal('3:foo', execute('isearch 4 /foo/'))
+ call assert_fails('isearch 3 foo', 'E387:')
+ call assert_equal('3:foo', execute('+1,$isearch foo'))
+ call assert_fails('1,.-1isearch 3 foo', 'E389:')
+ call assert_fails('isearch bar', 'E389:')
+ call assert_fails('isearch /foo/3', 'E488:')
+
+ " Test for [I and ]I
+ call assert_equal([
+ \ ' 1: 1 1:foo',
+ \ ' 2: 2 2:foo',
+ \ ' 3: 3 foo',
+ \ ' 4: 4 3:foo',
+ \ ' 5: 5 4:foo'], split(execute('normal [I'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 3:foo',
+ \ ' 2: 5 4:foo'], split(execute('normal ]I'), "\n"))
+
+ " Test for :ilist
+ call assert_equal([
+ \ ' 1: 1 1:foo',
+ \ ' 2: 2 2:foo',
+ \ ' 3: 3 foo',
+ \ ' 4: 4 3:foo',
+ \ ' 5: 5 4:foo'], split(execute('ilist foo'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 3:foo',
+ \ ' 2: 5 4:foo'], split(execute('+1,$ilist /foo/'), "\n"))
+ call assert_fails('ilist bar', 'E389:')
+
+ " Test for [ CTRL-I and ] CTRL-I
+ exe "normal [\t"
+ call assert_equal([1, 3], [line('.'), col('.')])
+ exe "normal 2j4[\t"
+ call assert_equal([4, 3], [line('.'), col('.')])
+ call assert_fails("normal k3[\t", 'E387:')
+ call assert_fails("normal 6[\t", 'E389:')
+ exe "normal ]\t"
+ call assert_equal([4, 3], [line('.'), col('.')])
+ exe "normal k2]\t"
+ call assert_equal([5, 3], [line('.'), col('.')])
+ call assert_fails("normal 2k3]\t", 'E389:')
+
+ " Test for :ijump
+ call cursor(3, 1)
+ ijump foo
+ call assert_equal([1, 3], [line('.'), col('.')])
+ call cursor(3, 1)
+ ijump 4 /foo/
+ call assert_equal([4, 3], [line('.'), col('.')])
+ call cursor(3, 1)
+ call assert_fails('ijump 3 foo', 'E387:')
+ +,$ijump 2 foo
+ call assert_equal([5, 3], [line('.'), col('.')])
+ call assert_fails('ijump bar', 'E389:')
+
+ " Test for CTRL-W i
+ call cursor(3, 1)
+ wincmd i
+ call assert_equal([1, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ 5wincmd i
+ call assert_equal([5, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('3wincmd i', 'E387:')
+ call assert_fails('6wincmd i', 'E389:')
+
+ " Test for :isplit
+ isplit foo
+ call assert_equal([1, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ isplit 5 /foo/
+ call assert_equal([5, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('isplit 3 foo', 'E387:')
+ call assert_fails('isplit 6 foo', 'E389:')
+ call assert_fails('isplit bar', 'E389:')
+
+ close!
+endfunc
+
+" this was using a line from ml_get() freed by the regexp
+func Test_isearch_copy_line()
+ new
+ norm o
+ norm 0
+ 0norm o
+ sil! norm bc0
+ sil! isearch \%')
+ bwipe!
+endfunc
+
+" Test for :dsearch, :dlist, :djump and :dsplit commands
+" Test for [d, ]d, [D, ]D, [ CTRL-D, ] CTRL-D and CTRL-W d commands
+func Test_macro_search()
+ new
+ call setline(1, ['#define FOO 1', '#define FOO 2', '#define FOO 3',
+ \ '#define FOO 4', '#define FOO 5'])
+ call cursor(3, 9)
+
+ " Test for [d and ]d
+ call assert_equal('#define FOO 1', execute('normal [d'))
+ call assert_equal('#define FOO 2', execute('normal 2[d'))
+ call assert_fails('normal 3[d', 'E387:')
+ call assert_equal('#define FOO 4', execute('normal ]d'))
+ call assert_equal('#define FOO 5', execute('normal 2]d'))
+ call assert_fails('normal 3]d', 'E388:')
+
+ " Test for :dsearch
+ call assert_equal('#define FOO 1', execute('dsearch FOO'))
+ call assert_equal('#define FOO 5', execute('dsearch 5 /FOO/'))
+ call assert_fails('dsearch 3 FOO', 'E387:')
+ call assert_equal('#define FOO 4', execute('+1,$dsearch FOO'))
+ call assert_fails('1,.-1dsearch 3 FOO', 'E388:')
+ call assert_fails('dsearch BAR', 'E388:')
+
+ " Test for [D and ]D
+ call assert_equal([
+ \ ' 1: 1 #define FOO 1',
+ \ ' 2: 2 #define FOO 2',
+ \ ' 3: 3 #define FOO 3',
+ \ ' 4: 4 #define FOO 4',
+ \ ' 5: 5 #define FOO 5'], split(execute('normal [D'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 #define FOO 4',
+ \ ' 2: 5 #define FOO 5'], split(execute('normal ]D'), "\n"))
+
+ " Test for :dlist
+ call assert_equal([
+ \ ' 1: 1 #define FOO 1',
+ \ ' 2: 2 #define FOO 2',
+ \ ' 3: 3 #define FOO 3',
+ \ ' 4: 4 #define FOO 4',
+ \ ' 5: 5 #define FOO 5'], split(execute('dlist FOO'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 #define FOO 4',
+ \ ' 2: 5 #define FOO 5'], split(execute('+1,$dlist /FOO/'), "\n"))
+ call assert_fails('dlist BAR', 'E388:')
+
+ " Test for [ CTRL-D and ] CTRL-D
+ exe "normal [\<C-D>"
+ call assert_equal([1, 9], [line('.'), col('.')])
+ exe "normal 2j4[\<C-D>"
+ call assert_equal([4, 9], [line('.'), col('.')])
+ call assert_fails("normal k3[\<C-D>", 'E387:')
+ call assert_fails("normal 6[\<C-D>", 'E388:')
+ exe "normal ]\<C-D>"
+ call assert_equal([4, 9], [line('.'), col('.')])
+ exe "normal k2]\<C-D>"
+ call assert_equal([5, 9], [line('.'), col('.')])
+ call assert_fails("normal 2k3]\<C-D>", 'E388:')
+
+ " Test for :djump
+ call cursor(3, 9)
+ djump FOO
+ call assert_equal([1, 9], [line('.'), col('.')])
+ call cursor(3, 9)
+ djump 4 /FOO/
+ call assert_equal([4, 9], [line('.'), col('.')])
+ call cursor(3, 9)
+ call assert_fails('djump 3 FOO', 'E387:')
+ +,$djump 2 FOO
+ call assert_equal([5, 9], [line('.'), col('.')])
+ call assert_fails('djump BAR', 'E388:')
+
+ " Test for CTRL-W d
+ call cursor(3, 9)
+ wincmd d
+ call assert_equal([1, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ 5wincmd d
+ call assert_equal([5, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('3wincmd d', 'E387:')
+ call assert_fails('6wincmd d', 'E388:')
+
+ " Test for :dsplit
+ dsplit FOO
+ call assert_equal([1, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ dsplit 5 /FOO/
+ call assert_equal([5, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('dsplit 3 FOO', 'E387:')
+ call assert_fails('dsplit 6 FOO', 'E388:')
+ call assert_fails('dsplit BAR', 'E388:')
+
+ close!
+endfunc
+
func Test_define_search()
" this was accessing freed memory
new
@@ -1092,6 +1304,37 @@ func Test_define_search()
bwipe!
endfunc
+" Test for [*, [/, ]* and ]/
+func Test_comment_search()
+ new
+ call setline(1, ['', '/*', ' *', ' *', ' */'])
+ normal! 4gg[/
+ call assert_equal([2, 1], [line('.'), col('.')])
+ normal! 3gg[*
+ call assert_equal([2, 1], [line('.'), col('.')])
+ normal! 3gg]/
+ call assert_equal([5, 3], [line('.'), col('.')])
+ normal! 3gg]*
+ call assert_equal([5, 3], [line('.'), col('.')])
+ %d
+ call setline(1, ['', '/*', ' *', ' *'])
+ call assert_beeps('normal! 3gg]/')
+ %d
+ call setline(1, ['', ' *', ' *', ' */'])
+ call assert_beeps('normal! 4gg[/')
+ %d
+ call setline(1, ' /* comment */')
+ normal! 15|[/
+ call assert_equal(9, col('.'))
+ normal! 15|]/
+ call assert_equal(21, col('.'))
+ call setline(1, ' comment */')
+ call assert_beeps('normal! 15|[/')
+ call setline(1, ' /* comment')
+ call assert_beeps('normal! 15|]/')
+ close!
+endfunc
+
" Test for the 'taglength' option
func Test_tag_length()
set tags=Xtags
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 748af199b2..f0a0f894c3 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -1137,8 +1137,79 @@ func Test_whichwrap_multi_byte()
bwipe!
endfunc
-func Test_substitute()
- call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+" Test for the 'f' flag in 'comments' (only the first line has the comment
+" string)
+func Test_firstline_comment()
+ new
+ setlocal comments=f:- fo+=ro
+ exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
+ call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$'))
+ %d
+ setlocal comments=:-
+ exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
+ call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$'))
+ %bw!
+endfunc
+
+" Test for the 'r' flag in 'comments' (right align comment)
+func Test_comment_rightalign()
+ new
+ setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro
+ exe "normal i=\<C-C>o\t /***\nD\n/"
+ exe "normal 2GOA\<C-C>joB\<C-C>jOC\<C-C>joE\<C-C>GOF\<C-C>joG"
+ let expected =<< trim END
+ =
+ A
+ /***
+ ** B
+ ** C
+ ** D
+ ** E
+ ** F
+ ******/
+ G
+ END
+ call assert_equal(expected, getline(1, '$'))
+ %bw!
+endfunc
+
+" Test for the 'b' flag in 'comments'
+func Test_comment_blank()
+ new
+ setlocal comments=b:* fo+=ro
+ exe "normal i* E\nF\n\<BS>G\nH\<C-C>ggOC\<C-C>O\<BS>B\<C-C>OA\<C-C>2joD"
+ let expected =<< trim END
+ A
+ *B
+ * C
+ * D
+ * E
+ * F
+ *G
+ H
+ END
+ call assert_equal(expected, getline(1, '$'))
+ %bw!
+endfunc
+
+" Test for the 'n' flag in comments
+func Test_comment_nested()
+ new
+ setlocal comments=n:> fo+=ro
+ exe "normal i> B\nD\<C-C>ggOA\<C-C>joC\<C-C>Go\<BS>>>> F\nH"
+ exe "normal 5GOE\<C-C>6GoG"
+ let expected =<< trim END
+ > A
+ > B
+ > C
+ > D
+ >>>> E
+ >>>> F
+ >>>> G
+ >>>> H
+ END
+ call assert_equal(expected, getline(1, '$'))
+ %bw!
endfunc
" Test for 'a' and 'w' flags in 'formatoptions'
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index e5b4bc23e8..56a5ec96af 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -7,6 +7,10 @@ source shared.vim
source term_util.vim
source load.vim
+func SetUp()
+ call timer_stopall()
+endfunc
+
func MyHandler(timer)
let g:val += 1
endfunc
@@ -15,7 +19,7 @@ func MyHandlerWithLists(lists, timer)
let x = string(a:lists)
endfunc
-func Test_oneshot()
+func Test_timer_oneshot()
let g:val = 0
let timer = timer_start(50, 'MyHandler')
let slept = WaitFor('g:val == 1')
@@ -27,7 +31,7 @@ func Test_oneshot()
endif
endfunc
-func Test_repeat_three()
+func Test_timer_repeat_three()
let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': 3})
let slept = WaitFor('g:val == 3')
@@ -39,8 +43,7 @@ func Test_repeat_three()
endif
endfunc
-func Test_repeat_many()
- call timer_stopall()
+func Test_timer_repeat_many()
let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': -1})
if has('mac')
@@ -51,7 +54,7 @@ func Test_repeat_many()
call assert_inrange((has('mac') ? 1 : 2), LoadAdjust(5), g:val)
endfunc
-func Test_with_partial_callback()
+func Test_timer_with_partial_callback()
let g:val = 0
let meow = {'one': 1}
function meow.bite(...)
@@ -68,13 +71,13 @@ func Test_with_partial_callback()
endif
endfunc
-func Test_retain_partial()
+func Test_timer_retain_partial()
call timer_start(50, function('MyHandlerWithLists', [['a']]))
- call garbagecollect()
+ call test_garbagecollect_now()
sleep 100m
endfunc
-func Test_info()
+func Test_timer_info()
let id = timer_start(1000, 'MyHandler')
let info = id->timer_info()
call assert_equal(id, info[0]['id'])
@@ -91,10 +94,11 @@ func Test_info()
call timer_stop(id)
call assert_equal([], timer_info(id))
+
+ call assert_fails('call timer_info("abc")', 'E39:')
endfunc
-func Test_stopall()
- call timer_stopall()
+func Test_timer_stopall()
let id1 = timer_start(1000, 'MyHandler')
let id2 = timer_start(2000, 'MyHandler')
let info = timer_info()
@@ -105,7 +109,7 @@ func Test_stopall()
call assert_equal(0, len(info))
endfunc
-func Test_paused()
+func Test_timer_paused()
let g:val = 0
let id = timer_start(50, 'MyHandler')
@@ -129,6 +133,8 @@ func Test_paused()
else
call assert_inrange(0, 10, slept)
endif
+
+ call assert_fails('call timer_pause("abc", 1)', 'E39:')
endfunc
func StopMyself(timer)
@@ -138,7 +144,7 @@ func StopMyself(timer)
endif
endfunc
-func Test_delete_myself()
+func Test_timer_delete_myself()
let g:called = 0
let t = timer_start(10, 'StopMyself', {'repeat': -1})
call WaitForAssert({-> assert_equal(2, g:called)})
@@ -150,33 +156,45 @@ func StopTimer1(timer)
let g:timer2 = 10->timer_start('StopTimer2')
" avoid maxfuncdepth error
call timer_pause(g:timer1, 1)
- sleep 40m
+ sleep 20m
endfunc
func StopTimer2(timer)
call timer_stop(g:timer1)
endfunc
-func Test_stop_in_callback()
+func Test_timer_stop_in_callback()
+ call assert_equal(0, len(timer_info()))
let g:timer1 = timer_start(10, 'StopTimer1')
- sleep 40m
+ let slept = 0
+ for i in range(10)
+ if len(timer_info()) == 0
+ break
+ endif
+ sleep 10m
+ let slept += 10
+ endfor
+ " This should take only 30 msec, but on Mac it's often longer
+ call assert_inrange(0, 50, slept)
endfunc
func StopTimerAll(timer)
call timer_stopall()
endfunc
-func Test_stop_all_in_callback()
- call timer_stopall()
- let g:timer1 = timer_start(10, 'StopTimerAll')
- let info = timer_info()
- call assert_equal(1, len(info))
- if has('mac')
- sleep 100m
- endif
- sleep 40m
- let info = timer_info()
- call assert_equal(0, len(info))
+func Test_timer_stop_all_in_callback()
+ call assert_equal(0, len(timer_info()))
+ call timer_start(10, 'StopTimerAll')
+ call assert_equal(1, len(timer_info()))
+ let slept = 0
+ for i in range(10)
+ if len(timer_info()) == 0
+ break
+ endif
+ sleep 10m
+ let slept += 10
+ endfor
+ call assert_inrange(0, 30, slept)
endfunc
func FeedkeysCb(timer)
@@ -189,7 +207,7 @@ func InputCb(timer)
call Resume()
endfunc
-func Test_input_in_timer()
+func Test_timer_input_in_timer()
let g:val = ''
call timer_start(10, 'InputCb')
call Standby(1000)
@@ -211,6 +229,10 @@ func Test_timer_errors()
call WaitForAssert({-> assert_equal(3, g:call_count)})
sleep 50m
call assert_equal(3, g:call_count)
+
+ call assert_fails('call timer_start(100, "MyHandler", "abc")', 'E475:')
+ call assert_fails('call timer_start(100, [])', 'E921:')
+ call assert_fails('call timer_stop("abc")', 'E39:')
endfunc
func FuncWithCaughtError(timer)
@@ -242,7 +264,7 @@ func Interrupt(timer)
call nvim_input("\<C-C>")
endfunc
-func Test_peek_and_get_char()
+func Test_timer_peek_and_get_char()
if !has('unix') && !has('gui_running')
return
endif
@@ -253,7 +275,7 @@ func Test_peek_and_get_char()
eval intr->timer_stop()
endfunc
-func Test_getchar_zero()
+func Test_timer_getchar_zero()
if has('win32') && !has('gui_running')
" Console: no low-level input
return
@@ -271,7 +293,7 @@ func Test_getchar_zero()
call timer_stop(id)
endfunc
-func Test_ex_mode()
+func Test_timer_ex_mode()
" Function with an empty line.
func Foo(...)
@@ -282,9 +304,9 @@ func Test_ex_mode()
call timer_stop(timer)
endfunc
-func Test_restore_count()
+func Test_timer_restore_count()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot run Vim in a terminal window'
endif
" Check that v:count is saved and restored, not changed by a timer.
call writefile([
@@ -315,7 +337,7 @@ endfunc
" Test that the garbage collector isn't triggered if a timer callback invokes
" vgetc().
-func Test_nocatch_garbage_collect()
+func Test_timer_nocatch_garbage_collect()
" skipped: Nvim does not support test_garbagecollect_soon(), test_override()
return
" 'uptimetime. must be bigger than the timer timeout
@@ -339,7 +361,7 @@ func Test_nocatch_garbage_collect()
delfunc FeedChar
endfunc
-func Test_error_in_timer_callback()
+func Test_timer_error_in_timer_callback()
if !has('terminal') || (has('win32') && has('gui_running'))
throw 'Skipped: cannot run Vim in a terminal window'
endif
@@ -374,6 +396,15 @@ func Test_error_in_timer_callback()
exe buf .. 'bwipe!'
endfunc
+" Test for garbage collection when a timer is still running
+func Test_timer_garbage_collect()
+ let timer = timer_start(1000, function('MyHandler'), {'repeat' : 10})
+ call test_garbagecollect_now()
+ let l = timer_info(timer)
+ call assert_equal(function('MyHandler'), l[0].callback)
+ call timer_stop(timer)
+endfunc
+
func Test_timer_invalid_callback()
call assert_fails('call timer_start(0, "0")', 'E921')
endfunc
diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim
index 205ed095ea..598402fafe 100644
--- a/src/nvim/testdir/test_trycatch.vim
+++ b/src/nvim/testdir/test_trycatch.vim
@@ -1996,6 +1996,47 @@ func Test_reload_in_try_catch()
call delete('Xreload')
endfunc
+" Test for errors with :catch, :throw, :finally {{{1
+func Test_try_catch_errors()
+ call assert_fails('throw |', 'E471:')
+ call assert_fails("throw \n ", 'E471:')
+ call assert_fails('catch abc', 'E603:')
+ call assert_fails('try | let i = 1| finally | catch | endtry', 'E604:')
+ call assert_fails('finally', 'E606:')
+ call assert_fails('try | finally | finally | endtry', 'E607:')
+ " v8.2.3486 has been ported, but v8.2.1183 hasn't, so E170 appears here.
+ " call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
+ call assert_fails('try | for i in range(5) | endif | endtry', 'E170:')
+ call assert_fails('try | while v:true | endtry', 'E170:')
+ call assert_fails('try | if v:true | endtry', 'E171:')
+endfunc
+
+" Test for verbose messages with :try :catch, and :finally {{{1
+func Test_try_catch_verbose()
+ " This test works only when the language is English
+ if v:lang != "C" && v:lang !~ '^[Ee]n'
+ return
+ endif
+
+ set verbose=14
+ redir => msg
+ try
+ echo i
+ catch /E121:/
+ finally
+ endtry
+ redir END
+ let expected = [
+ \ 'Exception thrown: Vim(echo):E121: Undefined variable: i',
+ \ '',
+ \ 'Exception caught: Vim(echo):E121: Undefined variable: i',
+ \ '',
+ \ 'Exception finished: Vim(echo):E121: Undefined variable: i'
+ \ ]
+ call assert_equal(expected, split(msg, "\n"))
+ set verbose&
+endfunc
+
" Test for using throw in a called function with following error {{{1
func Test_user_command_throw_in_function_call()
let lines =<< trim END
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index af92328387..da8bf12318 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -299,6 +299,8 @@ func Test_undo_write()
close!
call delete('Xtest')
bwipe! Xtest
+
+ call assert_fails('earlier xyz', 'E475:')
endfunc
func Test_insert_expr()
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index f93eb6e274..1323288676 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1771,6 +1771,125 @@ func Test_function_defined_line()
call delete('Xtest.vim')
endfunc
+" Test for missing :endif, :endfor, :endwhile and :endtry {{{1
+func Test_missing_end()
+ call writefile(['if 2 > 1', 'echo ">"'], 'Xscript')
+ call assert_fails('source Xscript', 'E171:')
+ call writefile(['for i in range(5)', 'echo i'], 'Xscript')
+ call assert_fails('source Xscript', 'E170:')
+ call writefile(['while v:true', 'echo "."'], 'Xscript')
+ call assert_fails('source Xscript', 'E170:')
+ call writefile(['try', 'echo "."'], 'Xscript')
+ call assert_fails('source Xscript', 'E600:')
+ call delete('Xscript')
+
+ " Using endfor with :while
+ let caught_e732 = 0
+ try
+ while v:true
+ endfor
+ catch /E732:/
+ let caught_e732 = 1
+ endtry
+ call assert_equal(1, caught_e732)
+
+ " Using endwhile with :for
+ let caught_e733 = 0
+ try
+ for i in range(1)
+ endwhile
+ catch /E733:/
+ let caught_e733 = 1
+ endtry
+ call assert_equal(1, caught_e733)
+
+ " Missing 'in' in a :for statement
+ call assert_fails('for i range(1) | endfor', 'E690:')
+endfunc
+
+" Test for deep nesting of if/for/while/try statements {{{1
+func Test_deep_nest()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot run vim in terminal'
+ endif
+
+ let lines =<< trim [SCRIPT]
+ " Deep nesting of if ... endif
+ func Test1()
+ let @a = join(repeat(['if v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endif'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of for ... endfor
+ func Test2()
+ let @a = join(repeat(['for i in [1]'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endfor'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of while ... endwhile
+ func Test3()
+ let @a = join(repeat(['while v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endwhile'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of try ... endtry
+ func Test4()
+ let @a = join(repeat(['try'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endtry'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 6})
+
+ " Deep nesting of if ... endif
+ call term_sendkeys(buf, ":call Test1()\n")
+ call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})
+
+ " Deep nesting of for ... endfor
+ call term_sendkeys(buf, ":call Test2()\n")
+ call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
+
+ " Deep nesting of while ... endwhile
+ call term_sendkeys(buf, ":call Test3()\n")
+ call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
+
+ " Deep nesting of try ... endtry
+ call term_sendkeys(buf, ":call Test4()\n")
+ call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})
+
+ "let l = ''
+ "for i in range(1, 6)
+ " let l ..= term_getline(buf, i) . "\n"
+ "endfor
+ "call assert_report(l)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+endfunc
+
+" Test for <sfile>, <slnum> in a function {{{1
+func Test_sfile_in_function()
+ func Xfunc()
+ call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>'))
+ call assert_equal('2', expand('<slnum>'))
+ endfunc
+ call Xfunc()
+ delfunc Xfunc
+endfunc
+
func Test_for_over_string()
let res = ''
for c in 'aéc̀d'
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 349c4fde50..f77765d415 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -284,6 +284,15 @@ func Test_virtual_replace2()
call assert_equal(['abcd',
\ 'efgh',
\ 'ijkl'], getline(1, '$'))
+
+ " Test for truncating spaces in a newly added line using 'autoindent' if
+ " characters are not added to that line.
+ %d_
+ call setline(1, [' app', ' bee', ' cat'])
+ setlocal autoindent
+ exe "normal gg$gRt\n\nr"
+ call assert_equal([' apt', '', ' rat'], getline(1, '$'))
+
" clean up
%d_
set bs&vim
@@ -1169,8 +1178,8 @@ func Test_exclusive_selection()
close!
endfunc
-" Test for starting visual mode with a count
-" This test should be run withou any previous visual modes. So this should be
+" Test for starting visual mode with a count.
+" This test should be run without any previous visual modes. So this should be
" run as a first test.
func Test_AAA_start_visual_mode_with_count()
new
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index d295e520c7..41b0cd874c 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -172,6 +172,35 @@ func Test_window_split_edit_bufnr()
%bw!
endfunc
+func Test_window_split_no_room()
+ " N horizontal windows need >= 2*N + 1 lines:
+ " - 1 line + 1 status line in each window
+ " - 1 Ex command line
+ "
+ " 2*N + 1 <= &lines
+ " N <= (lines - 1)/2
+ "
+ " Beyond that number of windows, E36: Not enough room is expected.
+ let hor_win_count = (&lines - 1)/2
+ let hor_split_count = hor_win_count - 1
+ for s in range(1, hor_split_count) | split | endfor
+ call assert_fails('split', 'E36:')
+
+ " N vertical windows need >= 2*(N - 1) + 1 columns:
+ " - 1 column + 1 separator for each window (except last window)
+ " - 1 column for the last window which does not have separator
+ "
+ " 2*(N - 1) + 1 <= &columns
+ " 2*N - 1 <= &columns
+ " N <= (&columns + 1)/2
+ let ver_win_count = (&columns + 1)/2
+ let ver_split_count = ver_win_count - 1
+ for s in range(1, ver_split_count) | vsplit | endfor
+ call assert_fails('vsplit', 'E36:')
+
+ %bw!
+endfunc
+
func Test_window_exchange()
e Xa
@@ -886,6 +915,155 @@ func Test_floatwin_splitmove()
bwipe
endfunc
+" Test for the :only command
+func Test_window_only()
+ new
+ set modified
+ new
+ call assert_fails('only', 'E445:')
+ only!
+ " Test for :only with a count
+ let wid = win_getid()
+ new
+ new
+ 3only
+ call assert_equal(1, winnr('$'))
+ call assert_equal(wid, win_getid())
+ call assert_fails('close', 'E444:')
+ call assert_fails('%close', 'E16:')
+endfunc
+
+" Test for errors with :wincmd
+func Test_wincmd_errors()
+ call assert_fails('wincmd g', 'E474:')
+ call assert_fails('wincmd ab', 'E474:')
+endfunc
+
+" Test for errors with :winpos
+func Test_winpos_errors()
+ throw 'Skipped: Nvim does not have :winpos'
+ if !has("gui_running") && !has('win32')
+ call assert_fails('winpos', 'E188:')
+ endif
+ call assert_fails('winpos 10', 'E466:')
+endfunc
+
+" Test for +cmd in a :split command
+func Test_split_cmd()
+ split +set\ readonly
+ call assert_equal(1, &readonly)
+ call assert_equal(2, winnr('$'))
+ close
+endfunc
+
+" Create maximum number of horizontally or vertically split windows and then
+" run commands that create a new horizontally/vertically split window
+func Run_noroom_for_newwindow_test(dir_arg)
+ let dir = (a:dir_arg == 'v') ? 'vert ' : ''
+
+ " Open as many windows as possible
+ for i in range(500)
+ try
+ exe dir . 'new'
+ catch /E36:/
+ break
+ endtry
+ endfor
+
+ call writefile(['first', 'second', 'third'], 'Xfile1')
+ call writefile([], 'Xfile2')
+ call writefile([], 'Xfile3')
+
+ " Argument list related commands
+ args Xfile1 Xfile2 Xfile3
+ next
+ for cmd in ['sargument 2', 'snext', 'sprevious', 'sNext', 'srewind',
+ \ 'sfirst', 'slast']
+ call assert_fails(dir .. cmd, 'E36:')
+ endfor
+ %argdelete
+
+ " Buffer related commands
+ set modified
+ hide enew
+ for cmd in ['sbuffer Xfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind',
+ \ 'sbfirst', 'sblast', 'sball', 'sbmodified', 'sunhide']
+ call assert_fails(dir .. cmd, 'E36:')
+ endfor
+
+ " Window related commands
+ for cmd in ['split', 'split Xfile2', 'new', 'new Xfile3', 'sview Xfile1',
+ \ 'sfind runtest.vim']
+ call assert_fails(dir .. cmd, 'E36:')
+ endfor
+
+ " Help
+ call assert_fails(dir .. 'help', 'E36:')
+ call assert_fails(dir .. 'helpgrep window', 'E36:')
+
+ " Command-line window
+ if a:dir_arg == 'h'
+ " Cmd-line window is always a horizontally split window
+ call assert_beeps('call feedkeys("q:\<CR>", "xt")')
+ endif
+
+ " Quickfix and location list window
+ if has('quickfix')
+ cexpr ''
+ call assert_fails(dir .. 'copen', 'E36:')
+ lexpr ''
+ call assert_fails(dir .. 'lopen', 'E36:')
+
+ " Preview window
+ call assert_fails(dir .. 'pedit Xfile2', 'E36:')
+ call setline(1, 'abc')
+ call assert_fails(dir .. 'psearch abc', 'E36:')
+ endif
+
+ " Window commands (CTRL-W ^ and CTRL-W f)
+ if a:dir_arg == 'h'
+ call assert_fails('call feedkeys("\<C-W>^", "xt")', 'E36:')
+ call setline(1, 'Xfile1')
+ call assert_fails('call feedkeys("gg\<C-W>f", "xt")', 'E36:')
+ endif
+ enew!
+
+ " Tag commands (:stag, :stselect and :stjump)
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "second\tXfile1\t2",
+ \ "third\tXfile1\t3",],
+ \ 'Xtags')
+ set tags=Xtags
+ call assert_fails(dir .. 'stag second', 'E36:')
+ call assert_fails('call feedkeys(":" .. dir .. "stselect second\n1\n", "xt")', 'E36:')
+ call assert_fails(dir .. 'stjump second', 'E36:')
+ call assert_fails(dir .. 'ptag second', 'E36:')
+ set tags&
+ call delete('Xtags')
+
+ " :isplit and :dsplit
+ call setline(1, ['#define FOO 1', 'FOO'])
+ normal 2G
+ call assert_fails(dir .. 'isplit FOO', 'E36:')
+ call assert_fails(dir .. 'dsplit FOO', 'E36:')
+
+ " terminal
+ if has('terminal')
+ call assert_fails(dir .. 'terminal', 'E36:')
+ endif
+
+ %bwipe!
+ call delete('Xfile1')
+ call delete('Xfile2')
+ call delete('Xfile3')
+ only
+endfunc
+
+func Test_split_cmds_with_no_room()
+ call Run_noroom_for_newwindow_test('h')
+ call Run_noroom_for_newwindow_test('v')
+endfunc
+
func Test_window_resize()
throw 'Skipped: Nvim supports cmdheight=0'
" Vertical :resize (absolute, relative, min and max size).
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index b42665c9b5..bfbba1f793 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -206,6 +206,8 @@ func Test_write_errors()
call assert_fails('1,2write', 'E140:')
close!
+ call assert_fails('w > Xtest', 'E494:')
+
" Try to overwrite a directory
if has('unix')
call mkdir('Xdir1')
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index 9207ebe73b..69b687e44f 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -110,9 +110,13 @@ static void ga_concat_shorten_esc(garray_T *gap, const char_u *str)
/// Fill "gap" with information about an assert error.
static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str,
- typval_T *exp_tv, typval_T *got_tv, assert_type_T atype)
+ typval_T *exp_tv_arg, typval_T *got_tv_arg, assert_type_T atype)
{
char_u *tofree;
+ typval_T *exp_tv = exp_tv_arg;
+ typval_T *got_tv = got_tv_arg;
+ bool did_copy = false;
+ int omitted = 0;
if (opt_msg_tv->v_type != VAR_UNKNOWN) {
tofree = (char_u *)encode_tv2echo(opt_msg_tv, NULL);
@@ -130,6 +134,55 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_s
}
if (exp_str == NULL) {
+ // When comparing dictionaries, drop the items that are equal, so that
+ // it's a lot easier to see what differs.
+ if (atype != ASSERT_NOTEQUAL
+ && exp_tv->v_type == VAR_DICT && got_tv->v_type == VAR_DICT
+ && exp_tv->vval.v_dict != NULL && got_tv->vval.v_dict != NULL) {
+ dict_T *exp_d = exp_tv->vval.v_dict;
+ dict_T *got_d = got_tv->vval.v_dict;
+
+ did_copy = true;
+ exp_tv->vval.v_dict = tv_dict_alloc();
+ got_tv->vval.v_dict = tv_dict_alloc();
+
+ int todo = (int)exp_d->dv_hashtab.ht_used;
+ for (const hashitem_T *hi = exp_d->dv_hashtab.ht_array; todo > 0; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ dictitem_T *item2 = tv_dict_find(got_d, (const char *)hi->hi_key, -1);
+ if (item2 == NULL
+ || !tv_equal(&TV_DICT_HI2DI(hi)->di_tv, &item2->di_tv, false, false)) {
+ // item of exp_d not present in got_d or values differ.
+ const size_t key_len = STRLEN(hi->hi_key);
+ tv_dict_add_tv(exp_tv->vval.v_dict, (const char *)hi->hi_key, key_len,
+ &TV_DICT_HI2DI(hi)->di_tv);
+ if (item2 != NULL) {
+ tv_dict_add_tv(got_tv->vval.v_dict, (const char *)hi->hi_key, key_len,
+ &item2->di_tv);
+ }
+ } else {
+ omitted++;
+ }
+ todo--;
+ }
+ }
+
+ // Add items only present in got_d.
+ todo = (int)got_d->dv_hashtab.ht_used;
+ for (const hashitem_T *hi = got_d->dv_hashtab.ht_array; todo > 0; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ dictitem_T *item2 = tv_dict_find(exp_d, (const char *)hi->hi_key, -1);
+ if (item2 == NULL) {
+ // item of got_d not present in exp_d
+ const size_t key_len = STRLEN(hi->hi_key);
+ tv_dict_add_tv(got_tv->vval.v_dict, (const char *)hi->hi_key, key_len,
+ &TV_DICT_HI2DI(hi)->di_tv);
+ }
+ todo--;
+ }
+ }
+ }
+
tofree = (char_u *)encode_tv2string(exp_tv, NULL);
ga_concat_shorten_esc(gap, tofree);
xfree(tofree);
@@ -148,6 +201,18 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_s
tofree = (char_u *)encode_tv2string(got_tv, NULL);
ga_concat_shorten_esc(gap, tofree);
xfree(tofree);
+
+ if (omitted != 0) {
+ char buf[100];
+ vim_snprintf(buf, sizeof(buf), " - %d equal item%s omitted", omitted,
+ omitted == 1 ? "" : "s");
+ ga_concat(gap, buf);
+ }
+ }
+
+ if (did_copy) {
+ tv_clear(exp_tv);
+ tv_clear(got_tv);
}
}
@@ -405,15 +470,15 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const cmd = tv_get_string_chk(&argvars[0]);
garray_T ga;
int save_trylevel = trylevel;
+ const int called_emsg_before = called_emsg;
// trylevel must be zero for a ":throw" command to be considered failed
trylevel = 0;
- called_emsg = false;
suppress_errthrow = true;
emsg_silent = true;
do_cmdline_cmd(cmd);
- if (!called_emsg) {
+ if (called_emsg == called_emsg_before) {
prepare_assert_error(&ga);
ga_concat(&ga, "command did not fail: ");
assert_append_cmd_or_arg(&ga, argvars, cmd);
@@ -438,7 +503,6 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
trylevel = save_trylevel;
- called_emsg = false;
suppress_errthrow = false;
emsg_silent = false;
emsg_on_display = false;
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 7895391697..cf10e635b6 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -331,6 +331,7 @@ newwindow:
// move window to new tab page
case 'T':
+ CHECK_CMDWIN;
if (one_window(curwin)) {
msg(_(m_onlyone));
} else {
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index fbb67f9c03..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)
@@ -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/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/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua
index 244b6bf00f..98f113bbd0 100644
--- a/test/functional/legacy/ex_mode_spec.lua
+++ b/test/functional/legacy/ex_mode_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
@@ -39,4 +40,86 @@ describe('Ex mode', function()
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
index 174f7d292e..6b3b265579 100644
--- a/test/functional/legacy/excmd_spec.lua
+++ b/test/functional/legacy/excmd_spec.lua
@@ -1,9 +1,15 @@
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
@@ -30,3 +36,153 @@ describe('Ex command', function()
]]
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/filechanged_spec.lua b/test/functional/legacy/filechanged_spec.lua
index 6eb853d630..ecb861098c 100644
--- a/test/functional/legacy/filechanged_spec.lua
+++ b/test/functional/legacy/filechanged_spec.lua
@@ -62,7 +62,7 @@ describe('file changed dialog', function()
sleep 2
silent !touch Xchanged_d
let v:warningmsg = ''
- checktime
+ checktime Xchanged_d
call assert_equal('', v:warningmsg)
call assert_equal(1, line('$'))
call assert_equal('new line', getline(1))
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 22589fb107..e065a727f3 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -1848,8 +1848,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")
@@ -2240,4 +2239,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/messages_spec.lua b/test/functional/ui/messages_spec.lua
index e9c0e1b2a1..00f126a1f2 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1196,6 +1196,53 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim
{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()
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index c3b9af5e72..c5c88323a2 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -5,6 +5,7 @@ local command = helpers.command
local feed_command = helpers.feed_command
local eq = helpers.eq
local eval = helpers.eval
+local funcs = helpers.funcs
local testprg = helpers.testprg
describe('search highlighting', function()
@@ -321,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('@/'))
@@ -422,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)
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": []})'))