aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml5
-rw-r--r--CMakeLists.txt48
-rwxr-xr-xci/after_success.sh9
-rw-r--r--ci/build.bat6
-rw-r--r--ci/common/build.sh8
-rw-r--r--ci/common/test.sh12
-rwxr-xr-xci/install.sh4
-rwxr-xr-xci/run_tests.sh4
-rw-r--r--codecov.yml2
-rw-r--r--runtime/autoload/health/provider.vim2
-rw-r--r--runtime/autoload/provider/clipboard.vim2
-rw-r--r--runtime/doc/editing.txt12
-rw-r--r--runtime/doc/options.txt7
-rw-r--r--runtime/doc/term.txt5
-rw-r--r--runtime/doc/vim_diff.txt3
-rw-r--r--runtime/filetype.vim40
-rwxr-xr-xscripts/vim-patch.sh3
-rw-r--r--src/nvim/README.md6
-rw-r--r--src/nvim/api/ui.c3
-rw-r--r--src/nvim/api/ui_events.in.h11
-rw-r--r--src/nvim/buffer.c17
-rw-r--r--src/nvim/diff.c28
-rw-r--r--src/nvim/eval.c10
-rw-r--r--src/nvim/ex_cmds.c2
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/ex_cmds2.c53
-rw-r--r--src/nvim/ex_docmd.c24
-rw-r--r--src/nvim/ex_getln.c39
-rw-r--r--src/nvim/fileio.c41
-rw-r--r--src/nvim/highlight_defs.h29
-rw-r--r--src/nvim/main.c3
-rw-r--r--src/nvim/memline.c19
-rw-r--r--src/nvim/misc1.c18
-rw-r--r--src/nvim/normal.c39
-rw-r--r--src/nvim/ops.c13
-rw-r--r--src/nvim/option.c108
-rw-r--r--src/nvim/options.lua4
-rw-r--r--src/nvim/os/shell.c97
-rw-r--r--src/nvim/os/time.c22
-rw-r--r--src/nvim/os_unix.c3
-rw-r--r--src/nvim/popupmnu.c8
-rw-r--r--src/nvim/quickfix.c18
-rw-r--r--src/nvim/screen.c50
-rw-r--r--src/nvim/search.c30
-rw-r--r--src/nvim/syntax.c47
-rw-r--r--src/nvim/syntax.h13
-rw-r--r--src/nvim/syntax_defs.h17
-rw-r--r--src/nvim/terminal.c5
-rw-r--r--src/nvim/testdir/Makefile14
-rw-r--r--src/nvim/testdir/runtest.vim102
-rw-r--r--src/nvim/testdir/setup.vim12
-rw-r--r--src/nvim/testdir/test32.in60
-rw-r--r--src/nvim/testdir/test32.ok15
-rw-r--r--src/nvim/testdir/test53.in74
-rw-r--r--src/nvim/testdir/test53.ok45
-rw-r--r--src/nvim/testdir/test79.inbin3335 -> 0 bytes
-rw-r--r--src/nvim/testdir/test79.okbin570 -> 0 bytes
-rw-r--r--src/nvim/testdir/test_alot.vim3
-rw-r--r--src/nvim/testdir/test_arglist.vim355
-rw-r--r--src/nvim/testdir/test_autochdir.vim19
-rw-r--r--src/nvim/testdir/test_autocmd.vim747
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim1
-rw-r--r--src/nvim/testdir/test_cmdline.vim1
-rw-r--r--src/nvim/testdir/test_command_count.vim20
-rw-r--r--src/nvim/testdir/test_curswant.vim23
-rw-r--r--src/nvim/testdir/test_diffmode.vim1
-rw-r--r--src/nvim/testdir/test_digraph.vim1
-rw-r--r--src/nvim/testdir/test_edit.vim1310
-rw-r--r--src/nvim/testdir/test_exists.vim321
-rw-r--r--src/nvim/testdir/test_file_size.vim58
-rw-r--r--src/nvim/testdir/test_filetype.vim557
-rw-r--r--src/nvim/testdir/test_hardcopy.vim1
-rw-r--r--src/nvim/testdir/test_ins_complete.vim92
-rw-r--r--src/nvim/testdir/test_let.vim27
-rw-r--r--src/nvim/testdir/test_lineending.vim19
-rw-r--r--src/nvim/testdir/test_lispwords.vim82
-rw-r--r--src/nvim/testdir/test_normal.vim1
-rw-r--r--src/nvim/testdir/test_popup.vim37
-rw-r--r--src/nvim/testdir/test_quickfix.vim2
-rw-r--r--src/nvim/testdir/test_recover.vim63
-rw-r--r--src/nvim/testdir/test_scrollbind.vim32
-rw-r--r--src/nvim/testdir/test_search.vim146
-rw-r--r--src/nvim/testdir/test_signs.vim2
-rw-r--r--src/nvim/testdir/test_source_utf8.vim30
-rw-r--r--src/nvim/testdir/test_substitute.vim207
-rw-r--r--src/nvim/testdir/test_tab.vim45
-rw-r--r--src/nvim/testdir/test_tabpage.vim19
-rw-r--r--src/nvim/testdir/test_tagjump.vim37
-rw-r--r--src/nvim/testdir/test_textobjects.vim128
-rw-r--r--src/nvim/testdir/test_undo.vim24
-rw-r--r--src/nvim/testdir/test_usercommands.vim1
-rw-r--r--src/nvim/testdir/test_visual.vim102
-rw-r--r--src/nvim/testdir/test_winbuf_close.vim124
-rw-r--r--src/nvim/testdir/test_window_cmd.vim12
-rw-r--r--src/nvim/tui/tui.c113
-rw-r--r--src/nvim/ugrid.c7
-rw-r--r--src/nvim/ugrid.h6
-rw-r--r--src/nvim/ui.c150
-rw-r--r--src/nvim/ui.h8
-rw-r--r--src/nvim/ui_bridge.c27
-rw-r--r--src/nvim/version.c26
-rw-r--r--src/nvim/vim.h4
-rw-r--r--src/nvim/window.c11
-rw-r--r--test/functional/api/vim_spec.lua23
-rw-r--r--test/functional/eval/backtick_expansion_spec.lua16
-rw-r--r--test/functional/eval/execute_spec.lua9
-rw-r--r--test/functional/ex_cmds/bang_filter_spec.lua51
-rw-r--r--test/functional/fixtures/shell-test.c23
-rw-r--r--test/functional/fixtures/shell_data.txtbin0 -> 50 bytes
-rw-r--r--test/functional/legacy/arglist_spec.lua11
-rw-r--r--test/functional/legacy/edit_spec.lua25
-rw-r--r--test/functional/legacy/search_spec.lua110
-rw-r--r--test/functional/plugin/man_spec.lua4
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua50
-rw-r--r--test/functional/terminal/tui_spec.lua4
-rw-r--r--test/functional/ui/bufhl_spec.lua15
-rw-r--r--test/functional/ui/highlight_spec.lua1
-rw-r--r--test/functional/ui/mouse_spec.lua2
-rw-r--r--test/functional/ui/output_spec.lua179
-rw-r--r--test/functional/ui/screen.lua3
-rw-r--r--test/functional/ui/spell_spec.lua49
-rw-r--r--test/helpers.lua23
-rw-r--r--test/unit/viml/expressions/parser_tests.lua60
-rw-r--r--third-party/cmake/BuildLua.cmake4
-rw-r--r--third-party/cmake/BuildLuarocks.cmake29
125 files changed, 5923 insertions, 1043 deletions
diff --git a/.travis.yml b/.travis.yml
index 9a62a8a942..0c1f7da9ec 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -60,7 +60,10 @@ jobs:
sudo: true
- os: linux
compiler: gcc
- env: FUNCTIONALTEST=functionaltest-lua
+ env: >
+ FUNCTIONALTEST=functionaltest-lua
+ CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
+ DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
- os: linux
# Travis creates a cache per compiler. Set a different value here to
# store 32-bit dependencies in a separate cache.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 14eb4c952b..94a78f85c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -515,28 +515,6 @@ if(BUSTED_PRG)
list(APPEND TEST_TARGET_ARGS "USES_TERMINAL")
endif()
- if(${CMAKE_VERSION} VERSION_LESS 2.8.12)
- if(CMAKE_GENERATOR MATCHES "Visual Studio")
- set(TEST_LIBNVIM_PATH ${CMAKE_BINARY_DIR}/lib/nvim-test.dll)
- else()
- get_target_property(TEST_LIBNVIM_PATH nvim-test LOCATION)
- endif()
- configure_file(
- ${CMAKE_SOURCE_DIR}/test/config/paths.lua.in
- ${CMAKE_BINARY_DIR}/test/config/paths.lua)
- else()
- # To avoid duplicating paths.lua.in while we still support CMake < 2.8.12,
- # use configure_file() to add the generator expression and then generate
- # the final file
- set(TEST_LIBNVIM_PATH $<TARGET_FILE:nvim-test>)
- configure_file(
- ${CMAKE_SOURCE_DIR}/test/config/paths.lua.in
- ${CMAKE_BINARY_DIR}/test/config/paths.lua.gen)
- file(GENERATE
- OUTPUT ${CMAKE_BINARY_DIR}/test/config/paths.lua
- INPUT ${CMAKE_BINARY_DIR}/test/config/paths.lua.gen)
- endif()
-
set(UNITTEST_PREREQS nvim-test unittest-headers)
set(FUNCTIONALTEST_PREREQS nvim printargs-test shell-test)
if(NOT WIN32)
@@ -573,6 +551,32 @@ if(BUSTED_PRG)
message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}")
endif()
+ if(${CMAKE_VERSION} VERSION_LESS 2.8.12)
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ set(TEST_LIBNVIM_PATH ${CMAKE_BINARY_DIR}/lib/nvim-test.dll)
+ else()
+ get_target_property(TEST_LIBNVIM_PATH nvim-test LOCATION)
+ endif()
+ configure_file(
+ ${CMAKE_SOURCE_DIR}/test/config/paths.lua.in
+ ${CMAKE_BINARY_DIR}/test/config/paths.lua)
+ else()
+ # To avoid duplicating paths.lua.in while we still support CMake < 2.8.12,
+ # use configure_file() to add the generator expression and then generate
+ # the final file
+ if(LUA_HAS_FFI)
+ set(TEST_LIBNVIM_PATH $<TARGET_FILE:nvim-test>)
+ else()
+ set(TEST_LIBNVIM_PATH "")
+ endif()
+ configure_file(
+ ${CMAKE_SOURCE_DIR}/test/config/paths.lua.in
+ ${CMAKE_BINARY_DIR}/test/config/paths.lua.gen)
+ file(GENERATE
+ OUTPUT ${CMAKE_BINARY_DIR}/test/config/paths.lua
+ INPUT ${CMAKE_BINARY_DIR}/test/config/paths.lua.gen)
+ endif()
+
add_custom_target(functionaltest
COMMAND ${CMAKE_COMMAND}
-DBUSTED_PRG=${BUSTED_PRG}
diff --git a/ci/after_success.sh b/ci/after_success.sh
deleted file mode 100755
index 388b6eb714..0000000000
--- a/ci/after_success.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o pipefail
-
-if [[ -n "${GCOV}" ]]; then
- coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.'
- bash <(curl -s https://codecov.io/bash) || echo 'codecov upload failed.'
-fi
diff --git a/ci/build.bat b/ci/build.bat
index 9909d102a4..5c7f14ad0a 100644
--- a/ci/build.bat
+++ b/ci/build.bat
@@ -56,6 +56,10 @@ bin\nvim --version || goto :error
:: Functional tests
mingw32-make functionaltest VERBOSE=1 || goto :error
+if defined USE_GCOV (
+ C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F functionaltest || echo 'codecov upload failed.'"
+)
+
:: Old tests
setlocal
set PATH=%PATH%;C:\msys64\usr\bin
@@ -63,7 +67,7 @@ mingw32-make -C "%~dp0\..\src\nvim\testdir" VERBOSE=1
endlocal
if defined USE_GCOV (
- C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) || echo 'codecov upload failed.'"
+ C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F oldtest || echo 'codecov upload failed.'"
)
:: Build artifacts
diff --git a/ci/common/build.sh b/ci/common/build.sh
index adfd7b9e8a..2748b15b0d 100644
--- a/ci/common/build.sh
+++ b/ci/common/build.sh
@@ -71,9 +71,11 @@ build_nvim() {
exit 1
fi
- echo "Building nvim-test."
- if ! top_make nvim-test ; then
- exit 1
+ if test "${FUNCTIONALTEST}" != "functionaltest-lua"; then
+ echo "Building nvim-test."
+ if ! top_make nvim-test ; then
+ exit 1
+ fi
fi
fi
diff --git a/ci/common/test.sh b/ci/common/test.sh
index 1cb3a6224b..bc80dfead7 100644
--- a/ci/common/test.sh
+++ b/ci/common/test.sh
@@ -1,6 +1,15 @@
. "${CI_DIR}/common/build.sh"
. "${CI_DIR}/common/suite.sh"
+submit_coverage() {
+ if [ -n "${GCOV}" ]; then
+ if curl --fail --output codecov.bash --silent https://codecov.io/bash; then
+ bash codecov.bash -c -F "$1" || echo "codecov upload failed."
+ rm -f codecov.bash
+ fi
+ fi
+}
+
print_core() {
local app="$1"
local core="$2"
@@ -82,6 +91,7 @@ run_unittests() {(
if ! build_make unittest ; then
fail 'unittests' F 'Unit tests failed'
fi
+ submit_coverage unittest
check_core_dumps "$(which luajit)"
exit_suite
)}
@@ -92,6 +102,7 @@ run_functionaltests() {(
if ! build_make ${FUNCTIONALTEST}; then
fail 'functionaltests' F 'Functional tests failed'
fi
+ submit_coverage functionaltest
asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
@@ -105,6 +116,7 @@ run_oldtests() {(
reset
fail 'oldtests' F 'Legacy tests failed'
fi
+ submit_coverage oldtest
asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
diff --git a/ci/install.sh b/ci/install.sh
index eb7fb14760..60d9507bfb 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -13,8 +13,8 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
fi
# Use default CC to avoid compilation problems when installing Python modules.
-echo "Install neovim module and coveralls for Python 2."
-CC=cc pip2.7 -q install --user --upgrade neovim cpp-coveralls
+echo "Install neovim module for Python 2."
+CC=cc pip2.7 -q install --user --upgrade neovim
echo "Install neovim module for Python 3."
# Allow failure. pyenv pip3 on travis is broken:
diff --git a/ci/run_tests.sh b/ci/run_tests.sh
index a0bf6e010d..c175910da5 100755
--- a/ci/run_tests.sh
+++ b/ci/run_tests.sh
@@ -22,7 +22,9 @@ enter_suite tests
if test "$CLANG_SANITIZER" != "TSAN" ; then
# Additional threads are only created when the builtin UI starts, which
# doesn't happen in the unit/functional tests
- run_test run_unittests
+ if test "${FUNCTIONALTEST}" != "functionaltest-lua"; then
+ run_test run_unittests
+ fi
run_test run_functionaltests
fi
run_test run_oldtests
diff --git a/codecov.yml b/codecov.yml
index 0b3de06b97..481eea89ee 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,6 +1,6 @@
codecov:
notify:
- require_ci_to_pass: yes
+ require_ci_to_pass: no
ci:
- appveyor
- travis
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index ae106095f9..073dcf92a8 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -126,7 +126,7 @@ endfunction
function! s:check_clipboard() abort
call health#report_start('Clipboard (optional)')
- if !empty($TMUX) && executable('tmux') && executable('pbcopy') && !s:cmd_ok('pbcopy')
+ if !empty($TMUX) && executable('tmux') && executable('pbpaste') && !s:cmd_ok('pbpaste')
let tmux_version = matchstr(system('tmux -V'), '\d\+\.\d\+')
call health#report_error('pbcopy does not work with tmux version: '.tmux_version,
\ ['Install tmux 2.6+. https://superuser.com/q/231130',
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 9e2e6046f8..87a0315073 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -64,7 +64,7 @@ function! provider#clipboard#Executable() abort
let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null })
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
return get(g:clipboard, 'name', 'g:clipboard')
- elseif has('mac') && executable('pbcopy') && s:cmd_ok('pbcopy')
+ elseif has('mac') && executable('pbpaste') && s:cmd_ok('pbpaste')
let s:copy['+'] = 'pbcopy'
let s:paste['+'] = 'pbpaste'
let s:copy['*'] = s:copy['+']
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 1b9a1b38fb..5939cb8a8b 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -562,16 +562,16 @@ list of the current window.
buffer.
Also see |++opt| and |+cmd|.
-:[count]arge[dit][!] [++opt] [+cmd] {name} *:arge* *:argedit*
- Add {name} to the argument list and edit it.
+:[count]arge[dit][!] [++opt] [+cmd] {name} .. *:arge* *:argedit*
+ Add {name}s to the argument list and edit it.
When {name} already exists in the argument list, this
entry is edited.
This is like using |:argadd| and then |:edit|.
- Note that only one file name is allowed, and spaces
- inside the file name are allowed, like with |:edit|.
+ Spaces in filenames have to be escaped with "\".
[count] is used like with |:argadd|.
- [!] is required if the current file cannot be
- |abandon|ed.
+ If the current file cannot be |abandon|ed {name}s will
+ still be added to the argument list, but won't be
+ edited. No check for duplicates is done.
Also see |++opt| and |+cmd|.
:[count]arga[dd] {name} .. *:arga* *:argadd* *E479*
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 6a36202177..a1a361fc85 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5445,14 +5445,13 @@ A jump table for the options with a short description can be found at |Q_op|.
See |tab-page| for more information about tab pages.
*'sidescroll'* *'ss'*
-'sidescroll' 'ss' number (default 0)
+'sidescroll' 'ss' number (default 1)
global
The minimal number of columns to scroll horizontally. Used only when
the 'wrap' option is off and the cursor is moved off of the screen.
When it is zero the cursor will be put in the middle of the screen.
- When using a slow terminal set it to a large number or 0. When using
- a fast terminal use a small number or 1. Not used for "zh" and "zl"
- commands.
+ When using a slow terminal set it to a large number or 0. Not used
+ for "zh" and "zl" commands.
*'sidescrolloff'* *'siso'*
'sidescrolloff' 'siso' number (default 0)
diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt
index 6cf62f9bb5..075ffdac52 100644
--- a/runtime/doc/term.txt
+++ b/runtime/doc/term.txt
@@ -232,11 +232,6 @@ correct values. See |:mode|.
Slow and fast terminals *slow-fast-terminal*
*slow-terminal*
-If you have a fast terminal you may like to set the 'ruler' option. The
-cursor position is shown in the status line. If you are using horizontal
-scrolling ('wrap' option off) consider setting 'sidescroll' to a small
-number.
-
If you have a slow terminal you may want to reset the 'showcmd' and 'ruler'
options. The command characters and cursor positions will not be shown in the
status line (which involves a lot of cursor motions and attribute changes for
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index c5c558279e..7426cd0940 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -48,6 +48,7 @@ a complete and centralized reference of those differences.
- 'ruler' is set by default
- 'sessionoptions' doesn't include "options"
- 'showcmd' is set by default
+- 'sidescroll' defaults to 1
- 'smarttab' is set by default
- 'tabpagemax' defaults to 50
- 'tags' defaults to "./tags;,tags"
@@ -375,7 +376,6 @@ MS-DOS support:
Test functions:
test_alloc_fail()
test_autochdir()
- test_disable_char_avail()
test_garbagecollect_now()
test_null_channel()
test_null_dict()
@@ -383,6 +383,7 @@ Test functions:
test_null_list()
test_null_partial()
test_null_string()
+ test_override()
test_settime()
Other options:
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 76f76af345..a2e1f23bf1 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1019,7 +1019,7 @@ au BufNewFile,BufRead *.java,*.jav setf java
au BufNewFile,BufRead *.jj,*.jjt setf javacc
" JavaScript, ECMAScript
-au BufNewFile,BufRead *.js,*.javascript,*.es,*.jsx setf javascript
+au BufNewFile,BufRead *.js,*.javascript,*.es,*.jsx,*.mjs setf javascript
" Java Server Pages
au BufNewFile,BufRead *.jsp setf jsp
@@ -1183,14 +1183,21 @@ au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
" Mason
au BufNewFile,BufRead *.mason,*.mhtml,*.comp setf mason
-" Matlab or Objective C
+" Mathematica, Matlab, Murphi or Objective C
au BufNewFile,BufRead *.m call s:FTm()
func! s:FTm()
let n = 1
- while n < 10
+ let saw_comment = 0 " Whether we've seen a multiline comment leader.
+ while n < 100
let line = getline(n)
- if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\|//\)'
+ if line =~ '^\s*/\*'
+ " /* ... */ is a comment in Objective C and Murphi, so we can't conclude
+ " it's either of them yet, but track this as a hint in case we don't see
+ " anything more definitive.
+ let saw_comment = 1
+ endif
+ if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
setf objc
return
endif
@@ -1202,11 +1209,23 @@ func! s:FTm()
setf mma
return
endif
+ if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
+ setf murphi
+ return
+ endif
let n = n + 1
endwhile
- if exists("g:filetype_m")
+
+ if saw_comment
+ " We didn't see anything definitive, but this looks like either Objective C
+ " or Murphi based on the comment leader. Assume the former as it is more
+ " common.
+ setf objc
+ elseif exists("g:filetype_m")
+ " Use user specified default filetype for .m
exe "setf " . g:filetype_m
else
+ " Default is matlab
setf matlab
endif
endfunc
@@ -1315,6 +1334,9 @@ au BufNewFile,BufRead *.mush setf mush
" Mutt setup file (also for Muttng)
au BufNewFile,BufRead Mutt{ng,}rc setf muttrc
+" N1QL
+au BufRead,BufNewfile *.n1ql,*.nql setf n1ql
+
" Nano
au BufNewFile,BufRead */etc/nanorc,*.nanorc setf nanorc
@@ -2246,6 +2268,8 @@ func! s:FTtex()
elseif format == 'plaintex'
let format = 'plain'
endif
+ elseif expand('%') =~ 'tex/context/.*/.*.tex'
+ let format = 'context'
else
" Default value, may be changed later:
let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
@@ -2287,7 +2311,7 @@ func! s:FTtex()
endfunc
" ConTeXt
-au BufNewFile,BufRead tex/context/*/*.tex,*.mkii,*.mkiv,*.mkvi setf context
+au BufNewFile,BufRead *.mkii,*.mkiv,*.mkvi setf context
" Texinfo
au BufNewFile,BufRead *.texinfo,*.texi,*.txi setf texinfo
@@ -2792,12 +2816,12 @@ runtime! ftdetect/*.vim
" state.
augroup END
-" Generic configuration file (check this last, it's just guessing!)
+" Generic configuration file. Use FALLBACK, it's just guessing!
au filetypedetect BufNewFile,BufRead,StdinReadPost *
\ if !did_filetype() && expand("<amatch>") !~ g:ft_ignore_pat
\ && (getline(1) =~ '^#' || getline(2) =~ '^#' || getline(3) =~ '^#'
\ || getline(4) =~ '^#' || getline(5) =~ '^#') |
- \ setf conf |
+ \ setf FALLBACK conf |
\ endif
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index ac5e326e9d..c7a23abe5e 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -234,7 +234,8 @@ stage_patch() {
printf "\n✘ 'patch' command not found\n"
else
printf "\nApplying patch...\n"
- patch -p1 --posix < "${patch_file}" || true
+ patch -p1 < "${patch_file}" || true
+ find -name '*.orig' -type f -delete
fi
printf "\nInstructions:\n Proceed to port the patch.\n"
else
diff --git a/src/nvim/README.md b/src/nvim/README.md
index 1ece92e44d..d668db0cdc 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -90,6 +90,12 @@ Record a Nvim terminal session and format it with `vterm-dump`:
Then you can compare `bar` with another session, to debug TUI behavior.
+### TUI redraw
+
+Set the 'writedelay' option to see where and when the UI is painted.
+
+ :set writedelay=1
+
### Terminal reference
- `man terminfo`
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 760c95eb5b..e53a45bd93 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -86,6 +86,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->put = remote_ui_put;
ui->bell = remote_ui_bell;
ui->visual_bell = remote_ui_visual_bell;
+ ui->default_colors_set = remote_ui_default_colors_set;
ui->update_fg = remote_ui_update_fg;
ui->update_bg = remote_ui_update_bg;
ui->update_sp = remote_ui_update_sp;
@@ -243,7 +244,7 @@ static void push_call(UI *ui, char *name, Array args)
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{
Array args = ARRAY_DICT_INIT;
- Dictionary hl = hlattrs2dict(attrs);
+ Dictionary hl = hlattrs2dict(&attrs, ui->rgb);
ADD(args, DICTIONARY_OBJ(hl));
push_call(ui, "highlight_set", args);
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 3d2253e918..c599b0ce72 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -47,11 +47,14 @@ void visual_bell(void)
void flush(void)
FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
void update_fg(Integer fg)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void update_bg(Integer bg)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void update_sp(Integer sp)
- FUNC_API_SINCE(3);
+ FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
+void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
+ Integer cterm_fg, Integer cterm_bg)
+ FUNC_API_SINCE(4);
void suspend(void)
FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void set_title(String title)
@@ -59,7 +62,7 @@ void set_title(String title)
void set_icon(String icon)
FUNC_API_SINCE(3);
void option_set(String name, Object value)
- FUNC_API_SINCE(4) FUNC_API_BRIDGE_IMPL;
+ FUNC_API_SINCE(4);
void popupmenu_show(Array items, Integer selected, Integer row, Integer col)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index e5da5b835b..8d0738dd29 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1387,20 +1387,25 @@ void set_curbuf(buf_T *buf, int action)
/* Don't restart Select mode after switching to another buffer. */
VIsual_reselect = FALSE;
- /* close_windows() or apply_autocmds() may change curbuf */
+ // close_windows() or apply_autocmds() may change curbuf and wipe out "buf"
prevbuf = curbuf;
- bufref_T bufref;
- set_bufref(&bufref, prevbuf);
+ bufref_T newbufref;
+ bufref_T prevbufref;
+ set_bufref(&prevbufref, prevbuf);
+ set_bufref(&newbufref, buf);
+ // Autocommands may delete the curren buffer and/or the buffer we wan to go
+ // to. In those cases don't close the buffer.
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf)
- || (bufref_valid(&bufref) && !aborting())) {
+ || (bufref_valid(&prevbufref) && bufref_valid(&newbufref)
+ && !aborting())) {
if (prevbuf == curwin->w_buffer) {
reset_synblock(curwin);
}
if (unload) {
close_windows(prevbuf, false);
}
- if (bufref_valid(&bufref) && !aborting()) {
+ if (bufref_valid(&prevbufref) && !aborting()) {
win_T *previouswin = curwin;
if (prevbuf == curbuf)
u_sync(FALSE);
@@ -4466,7 +4471,7 @@ do_arg_all (
// leaving an empty tab page when executed locally.
if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
&& curbuf->b_ffname == NULL && !curbuf->b_changed) {
- use_firstwin = TRUE;
+ use_firstwin = true;
}
for (i = 0; i < count && i < opened_len && !got_int; ++i) {
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index c2ab57a59b..0ee1c3815d 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -855,7 +855,7 @@ void ex_diffpatch(exarg_T *eap)
{
char_u *buf = NULL;
win_T *old_curwin = curwin;
- char_u *newname = NULL; // name of patched file buffer
+ char_u *newname = NULL; // name of patched file buffer
char_u *esc_name = NULL;
#ifdef UNIX
@@ -886,9 +886,9 @@ void ex_diffpatch(exarg_T *eap)
esc_name = vim_strsave_shellescape(
#ifdef UNIX
- fullname != NULL ? fullname :
+ fullname != NULL ? fullname :
#endif
- eap->arg, true, true);
+ eap->arg, true, true);
if (esc_name == NULL) {
goto theend;
}
@@ -1058,6 +1058,20 @@ void ex_diffthis(exarg_T *eap)
diff_win_options(curwin, TRUE);
}
+static void set_diff_option(win_T *wp, int value)
+{
+ win_T *old_curwin = curwin;
+
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ curbuf_lock++;
+ set_option_value("diff", (long)value, NULL, OPT_LOCAL);
+ curbuf_lock--;
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
+}
+
+
/// Set options in window "wp" for diff mode.
///
/// @param addbuf Add buffer to diff.
@@ -1115,10 +1129,10 @@ void diff_win_options(win_T *wp, int addbuf)
do_cmdline_cmd("set sbo+=hor");
}
- // Saved the current values, to be restored in ex_diffoff().
- wp->w_p_diff_saved = TRUE;
+ // Save the current values, to be restored in ex_diffoff().
+ wp->w_p_diff_saved = true;
- wp->w_p_diff = true;
+ set_diff_option(wp, true);
if (addbuf) {
diff_buf_add(wp->w_buffer);
@@ -1139,7 +1153,7 @@ void ex_diffoff(exarg_T *eap)
// Set 'diff' off. If option values were saved in
// diff_win_options(), restore the ones whose settings seem to have
// been left over from diff mode.
- wp->w_p_diff = false;
+ set_diff_option(wp, false);
if (wp->w_p_diff_saved) {
if (wp->w_p_scb) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 1d483eee18..923b4527c2 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -19372,14 +19372,10 @@ void ex_echo(exarg_T *eap)
}
msg_putchar_attr((uint8_t)(*p), echo_attr);
} else {
- if (has_mbyte) {
- int i = (*mb_ptr2len)((const char_u *)p);
+ int i = (*mb_ptr2len)((const char_u *)p);
- (void)msg_outtrans_len_attr((char_u *)p, i, echo_attr);
- p += i - 1;
- } else {
- (void)msg_outtrans_len_attr((char_u *)p, 1, echo_attr);
- }
+ (void)msg_outtrans_len_attr((char_u *)p, i, echo_attr);
+ p += i - 1;
}
}
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 6ffd255dc7..9cfcecf8ad 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1175,7 +1175,7 @@ static void do_filter(
// to read the error messages. Otherwise errors are ignored, so you can see
// the error messages from the command that appear on stdout; use 'u' to fix
// the text.
- // Pass on the kShellDoOut flag when the output is being redirected.
+ // Pass on the kShellOptDoOut flag when the output is being redirected.
if (call_shell(
cmd_buf,
kShellOptFilter | shell_flags,
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index c8593f7460..ce02808ad3 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -108,7 +108,7 @@ return {
},
{
command='argedit',
- flags=bit.bor(BANG, NEEDARG, RANGE, NOTADR, ZEROR, FILE1, EDITCMD, ARGOPT, TRLBAR),
+ flags=bit.bor(BANG, NEEDARG, RANGE, NOTADR, ZEROR, FILES, EDITCMD, ARGOPT, TRLBAR),
addr_type=ADDR_ARGUMENTS,
func='ex_argedit',
},
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 28b021d4e4..5975ca43e6 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1558,12 +1558,17 @@ static char_u *do_one_arg(char_u *str)
/// Separate the arguments in "str" and return a list of pointers in the
/// growarray "gap".
-void get_arglist(garray_T *gap, char_u *str)
+static void get_arglist(garray_T *gap, char_u *str, int escaped)
{
ga_init(gap, (int)sizeof(char_u *), 20);
while (*str != NUL) {
GA_APPEND(char_u *, gap, str);
+ // If str is escaped, don't handle backslashes or spaces
+ if (!escaped) {
+ return;
+ }
+
// Isolate one argument, change it in-place, put a NUL after it.
str = do_one_arg(str);
}
@@ -1578,7 +1583,7 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
garray_T ga;
int i;
- get_arglist(&ga, str);
+ get_arglist(&ga, str, true);
if (wig) {
i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
@@ -1609,6 +1614,7 @@ static int do_arglist(char_u *str, int what, int after)
char_u **exp_files;
char_u *p;
int match;
+ int arg_escaped = true;
// Set default argument for ":argadd" command.
if (what == AL_ADD && *str == NUL) {
@@ -1616,10 +1622,11 @@ static int do_arglist(char_u *str, int what, int after)
return FAIL;
}
str = curbuf->b_fname;
+ arg_escaped = false;
}
// Collect all file name arguments in "new_ga".
- get_arglist(&new_ga, str);
+ get_arglist(&new_ga, str, arg_escaped);
if (what == AL_DEL) {
regmatch_T regmatch;
@@ -1915,31 +1922,21 @@ void ex_next(exarg_T *eap)
/// ":argedit"
void ex_argedit(exarg_T *eap)
{
- int fnum;
- int i;
- char_u *s;
-
- // Add the argument to the buffer list and get the buffer number.
- fnum = buflist_add(eap->arg, BLN_LISTED);
+ int i = eap->addr_count ? (int)eap->line2 : curwin->w_arg_idx + 1;
- // Check if this argument is already in the argument list.
- for (i = 0; i < ARGCOUNT; i++) {
- if (ARGLIST[i].ae_fnum == fnum) {
- break;
- }
- }
- if (i == ARGCOUNT) {
- // Can't find it, add it to the argument list.
- s = vim_strsave(eap->arg);
- int after = eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1;
- i = alist_add_list(1, &s, after);
- curwin->w_arg_idx = i;
+ if (do_arglist(eap->arg, AL_ADD, i) == FAIL) {
+ return;
}
+ maketitle();
- alist_check_arg_idx();
-
+ if (curwin->w_arg_idx == 0 && (curbuf->b_ml.ml_flags & ML_EMPTY)
+ && curbuf->b_ffname == NULL) {
+ i = 0;
+ }
// Edit the argument.
- do_argfile(eap, i);
+ if (i < ARGCOUNT) {
+ do_argfile(eap, i);
+ }
}
/// ":argadd"
@@ -1959,8 +1956,14 @@ void ex_argdelete(exarg_T *eap)
eap->line2 = ARGCOUNT;
}
linenr_T n = eap->line2 - eap->line1 + 1;
- if (*eap->arg != NUL || n <= 0) {
+ if (*eap->arg != NUL) {
+ // Can't have both a range and an argument.
EMSG(_(e_invarg));
+ } else if (n <= 0) {
+ // Don't give an error for ":%argdel" if the list is empty.
+ if (eap->line1 != 1 || eap->line2 != 0) {
+ EMSG(_(e_invrange));
+ }
} else {
for (linenr_T i = eap->line1; i <= eap->line2; i++) {
xfree(ARGLIST[i - 1].ae_fname);
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 4f0208c5c3..aebc395f56 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5974,15 +5974,18 @@ static void ex_quit(exarg_T *eap)
wp = curwin;
}
- apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, curbuf);
+ // Refuse to quit when locked.
+ if (curbuf_locked()) {
+ return;
+ }
+ apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer);
// Refuse to quit when locked or when the buffer in the last window is
// being closed (can only happen in autocommands).
- if (curbuf_locked()
+ if (!win_valid(wp)
|| (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0)) {
return;
}
-
/*
* If there are more files or windows we won't exit.
*/
@@ -9740,13 +9743,20 @@ void filetype_maybe_enable(void)
}
}
-/*
- * ":setfiletype {name}"
- */
+/// ":setfiletype [FALLBACK] {name}"
static void ex_setfiletype(exarg_T *eap)
{
if (!did_filetype) {
- set_option_value("filetype", 0L, (char *)eap->arg, OPT_LOCAL);
+ char_u *arg = eap->arg;
+
+ if (STRNCMP(arg, "FALLBACK ", 9) == 0) {
+ arg += 9;
+ }
+
+ set_option_value("filetype", 0L, (char *)arg, OPT_LOCAL);
+ if (arg != eap->arg) {
+ did_filetype = false;
+ }
}
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index ba51f18518..07aab3307a 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -443,14 +443,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
}
- if (s->gotesc) { // abandon command line
- xfree(ccline.cmdbuff);
- ccline.cmdbuff = NULL;
- if (msg_scrolled == 0) {
- compute_cmdrow();
- }
- MSG("");
- redraw_cmdline = true;
+ if (s->gotesc) {
+ abandon_cmdline();
}
}
@@ -1062,6 +1056,12 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
// put back on the match
s->search_start = t;
(void)decl(&s->search_start);
+ } else if (next_match && s->firstc == '?') {
+ // move just after the current match, so that
+ // when nv_search finishes the cursor will be
+ // put back on the match
+ s->search_start = t;
+ (void)incl(&s->search_start);
}
if (lt(t, s->search_start) && next_match) {
// wrap around
@@ -1549,7 +1549,7 @@ static int command_line_handle_key(CommandLineState *s)
}
if (s->c != NUL) {
if (s->c == s->firstc
- || vim_strchr((char_u *)(p_magic ? "\\^$.*[" : "\\^$"), s->c)
+ || vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), s->c)
!= NULL) {
// put a backslash before special characters
stuffcharReadbuff(s->c);
@@ -1673,9 +1673,6 @@ static int command_line_handle_key(CommandLineState *s)
case Ctrl_G: // next match
case Ctrl_T: // previous match
if (p_is && !cmd_silent && (s->firstc == '/' || s->firstc == '?')) {
- if (char_avail()) {
- return 1;
- }
if (ccline.cmdlen != 0) {
command_line_next_incsearch(s, s->c == Ctrl_G);
}
@@ -1941,6 +1938,18 @@ static int command_line_changed(CommandLineState *s)
return 1;
}
+/// Abandon the command line.
+static void abandon_cmdline(void)
+{
+ xfree(ccline.cmdbuff);
+ ccline.cmdbuff = NULL;
+ if (msg_scrolled == 0) {
+ compute_cmdrow();
+ }
+ MSG("");
+ redraw_cmdline = true;
+}
+
/*
* getcmdline() - accept a command line starting with firstc.
*
@@ -2929,11 +2938,11 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
Array item = ARRAY_DICT_INIT;
if (chunk.attr) {
- attrentry_T *aep = syn_cterm_attr2entry(chunk.attr);
+ HlAttrs *aep = syn_cterm_attr2entry(chunk.attr);
// TODO(bfredl): this desicion could be delayed by making attr_code a
// recognized type
- HlAttrs rgb_attrs = attrentry2hlattrs(aep, true);
- ADD(item, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs)));
+ Dictionary rgb_attrs = hlattrs2dict(aep, true);
+ ADD(item, DICTIONARY_OBJ(rgb_attrs));
} else {
ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 44d74c92cd..91b0a695f1 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -6274,13 +6274,13 @@ do_doautocmd (
fname = skipwhite(fname);
- /*
- * Loop over the events.
- */
- while (*arg && !ascii_iswhite(*arg))
- if (apply_autocmds_group(event_name2nr(arg, &arg),
- fname, NULL, TRUE, group, curbuf, NULL))
- nothing_done = FALSE;
+ // Loop over the events.
+ while (*arg && !ends_excmd(*arg) && !ascii_iswhite(*arg)) {
+ if (apply_autocmds_group(event_name2nr(arg, &arg), fname, NULL, true,
+ group, curbuf, NULL)) {
+ nothing_done = false;
+ }
+ }
if (nothing_done && do_msg) {
MSG(_("No matching autocommands"));
@@ -6671,12 +6671,12 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
proftime_T wait_time;
bool did_save_redobuff = false;
- /*
- * Quickly return if there are no autocommands for this event or
- * autocommands are blocked.
- */
- if (first_autopat[(int)event] == NULL || autocmd_blocked > 0)
+ // Quickly return if there are no autocommands for this event or
+ // autocommands are blocked.
+ if (event == NUM_EVENTS || first_autopat[(int)event] == NULL
+ || autocmd_blocked > 0) {
goto BYPASS_AU;
+ }
/*
* When autocommands are busy, new autocommands are only executed when
@@ -6742,19 +6742,22 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
* invalid.
*/
if (fname_io == NULL) {
- if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET)
+ if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET) {
autocmd_fname = NULL;
- else if (fname != NULL && *fname != NUL)
+ } else if (fname != NULL && !ends_excmd(*fname)) {
autocmd_fname = fname;
- else if (buf != NULL)
+ } else if (buf != NULL) {
autocmd_fname = buf->b_ffname;
- else
+ } else {
autocmd_fname = NULL;
- } else
+ }
+ } else {
autocmd_fname = fname_io;
- if (autocmd_fname != NULL)
+ }
+ if (autocmd_fname != NULL) {
autocmd_fname = vim_strsave(autocmd_fname);
- autocmd_fname_full = FALSE; /* call FullName_save() later */
+ }
+ autocmd_fname_full = false; // call FullName_save() later
/*
* Set the buffer number to be used for <abuf>.
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 927fc94bbe..08157935f5 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -7,6 +7,34 @@
typedef int32_t RgbValue;
+/// Highlighting attribute bits.
+typedef enum {
+ HL_INVERSE = 0x01,
+ HL_BOLD = 0x02,
+ HL_ITALIC = 0x04,
+ HL_UNDERLINE = 0x08,
+ HL_UNDERCURL = 0x10,
+ HL_STANDOUT = 0x20,
+} HlAttrFlags;
+
+/// Stores a complete highlighting entry, including colors and attributes
+/// for both TUI and GUI.
+typedef struct attr_entry {
+ int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
+ RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
+ int cterm_fg_color, cterm_bg_color;
+} HlAttrs;
+
+#define HLATTRS_INIT (HlAttrs) { \
+ .rgb_ae_attr = 0, \
+ .cterm_ae_attr = 0, \
+ .rgb_fg_color = -1, \
+ .rgb_bg_color = -1, \
+ .rgb_sp_color = -1, \
+ .cterm_fg_color = 0, \
+ .cterm_bg_color = 0, \
+}
+
/// Values for index in highlight_attr[].
/// When making changes, also update hlf_names below!
typedef enum {
@@ -117,7 +145,6 @@ EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
EXTERN int highlight_user[9]; // User[1-9] attributes
EXTERN int highlight_stlnc[9]; // On top of user
EXTERN int cterm_normal_fg_color INIT(= 0);
-EXTERN int cterm_normal_fg_bold INIT(= 0);
EXTERN int cterm_normal_bg_color INIT(= 0);
EXTERN RgbValue normal_fg INIT(= -1);
EXTERN RgbValue normal_bg INIT(= -1);
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 3402e2bebc..4fd55f1491 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -577,8 +577,9 @@ int main(int argc, char **argv)
return 0;
}
-/* Exit properly */
+/// Exit properly
void getout(int exitval)
+ FUNC_ATTR_NORETURN
{
tabpage_T *tp, *next_tp;
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 80775c607d..c594782a1c 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1330,10 +1330,14 @@ recover_names (
names[2] = (char_u *)concat_fnames((char *)dir_name, ".sw?", TRUE);
num_names = 3;
} else {
- p = dir_name + STRLEN(dir_name);
- if (after_pathsep((char *)dir_name, (char *)p) && p[-1] == p[-2]) {
- /* Ends with '//', Use Full path for swap name */
- tail = (char_u *)make_percent_swname((char *)dir_name, (char *)fname_res);
+ int len = STRLEN(dir_name);
+ p = dir_name + len;
+ if (after_pathsep((char *)dir_name, (char *)p)
+ && len > 1
+ && p[-1] == p[-2]) {
+ // Ends with '//', Use Full path for swap name
+ tail = (char_u *)make_percent_swname((char *)dir_name,
+ (char *)fname_res);
} else {
tail = path_tail(fname_res);
tail = (char_u *)concat_fnames((char *)dir_name, (char *)tail, TRUE);
@@ -3054,9 +3058,12 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
#endif
+ int len = STRLEN(dir_name);
- s = dir_name + STRLEN(dir_name);
- if (after_pathsep((char *)dir_name, (char *)s) && s[-1] == s[-2]) { /* Ends with '//', Use Full path */
+ s = dir_name + len;
+ if (after_pathsep((char *)dir_name, (char *)s)
+ && len > 1
+ && s[-1] == s[-2]) { // Ends with '//', Use Full path
r = NULL;
if ((s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname)) != NULL) {
r = (char_u *)modname((char *)s, ".swp", FALSE);
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index a498c7f4da..b0232b6516 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -1469,7 +1469,7 @@ void ins_char_bytes(char_u *buf, size_t charlen)
}
}
- char_u *newp = (char_u *) xmalloc((size_t)(linelen + newlen - oldlen));
+ char_u *newp = xmalloc((size_t)(linelen + newlen - oldlen));
// Copy bytes before the cursor.
if (col > 0) {
@@ -1478,7 +1478,10 @@ void ins_char_bytes(char_u *buf, size_t charlen)
// Copy bytes after the changed character(s).
char_u *p = newp + col;
- memmove(p + newlen, oldp + col + oldlen, (size_t)(linelen - col - oldlen));
+ if (linelen > col + oldlen) {
+ memmove(p + newlen, oldp + col + oldlen,
+ (size_t)(linelen - col - oldlen));
+ }
// Insert or overwrite the new character.
memmove(p, buf, charlen);
@@ -2610,13 +2613,12 @@ int match_user(char_u *name)
return result;
}
-/*
- * Preserve files and exit.
- * When called IObuff must contain a message.
- * NOTE: This may be called from deathtrap() in a signal handler, avoid unsafe
- * functions, such as allocating memory.
- */
+/// Preserve files and exit.
+/// @note IObuff must contain a message.
+/// @note This may be called from deadly_signal() in a signal handler, avoid
+/// unsafe functions, such as allocating memory.
void preserve_exit(void)
+ FUNC_ATTR_NORETURN
{
// 'true' when we are sure to exit, e.g., after a deadly signal
static bool really_exiting = false;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 47044a6072..8f585aef73 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1637,16 +1637,22 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
/* Prepare for redoing. Only use the nchar field for "r",
* otherwise it might be the second char of the operator. */
if (cap->cmdchar == 'g' && (cap->nchar == 'n'
- || cap->nchar == 'N'))
+ || cap->nchar == 'N')) {
prep_redo(oap->regname, cap->count0,
- get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
- oap->motion_force, cap->cmdchar, cap->nchar);
- else if (cap->cmdchar != ':')
- prep_redo(oap->regname, 0L, NUL, 'v',
- get_op_char(oap->op_type),
- get_extra_op_char(oap->op_type),
- oap->op_type == OP_REPLACE
- ? cap->nchar : NUL);
+ get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+ oap->motion_force, cap->cmdchar, cap->nchar);
+ } else if (cap->cmdchar != ':') {
+ int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL;
+
+ // reverse what nv_replace() did
+ if (nchar == REPLACE_CR_NCHAR) {
+ nchar = CAR;
+ } else if (nchar == REPLACE_NL_NCHAR) {
+ nchar = NL;
+ }
+ prep_redo(oap->regname, 0L, NUL, 'v', get_op_char(oap->op_type),
+ get_extra_op_char(oap->op_type), nchar);
+ }
if (!redo_VIsual_busy) {
redo_VIsual_mode = resel_VIsual_mode;
redo_VIsual_vcol = resel_VIsual_vcol;
@@ -5031,8 +5037,8 @@ static void nv_right(cmdarg_T *cap)
if ((!PAST_LINE && oneright() == false)
|| (PAST_LINE && *get_cursor_pos_ptr() == NUL)
) {
- // <Space> wraps to next line if 'whichwrap' has 's'.
- // 'l' wraps to next line if 'whichwrap' has 'l'.
+ // <Space> wraps to next line if 'whichwrap' has 's'.
+ // 'l' wraps to next line if 'whichwrap' has 'l'.
// CURS_RIGHT wraps to next line if 'whichwrap' has '>'.
if (((cap->cmdchar == ' ' && vim_strchr(p_ww, 's') != NULL)
|| (cap->cmdchar == 'l' && vim_strchr(p_ww, 'l') != NULL)
@@ -5854,10 +5860,13 @@ static void nv_replace(cmdarg_T *cap)
if (got_int)
reset_VIsual();
if (had_ctrl_v) {
- if (cap->nchar == '\r')
- cap->nchar = -1;
- else if (cap->nchar == '\n')
- cap->nchar = -2;
+ // Use a special (negative) number to make a difference between a
+ // literal CR or NL and a line break.
+ if (cap->nchar == CAR) {
+ cap->nchar = REPLACE_CR_NCHAR;
+ } else if (cap->nchar == NL) {
+ cap->nchar = REPLACE_NL_NCHAR;
+ }
}
nv_operator(cap);
return;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 665a102253..4d974f5760 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1629,13 +1629,18 @@ int op_replace(oparg_T *oap, int c)
colnr_T oldlen;
struct block_def bd;
char_u *after_p = NULL;
- int had_ctrl_v_cr = (c == -1 || c == -2);
+ int had_ctrl_v_cr = false;
if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty)
return OK; /* nothing to do */
- if (had_ctrl_v_cr)
- c = (c == -1 ? '\r' : '\n');
+ if (c == REPLACE_CR_NCHAR) {
+ had_ctrl_v_cr = true;
+ c = CAR;
+ } else if (c == REPLACE_NL_NCHAR) {
+ had_ctrl_v_cr = true;
+ c = NL;
+ }
if (has_mbyte)
mb_adjust_opend(oap);
@@ -1713,7 +1718,7 @@ int op_replace(oparg_T *oap, int c)
// insert pre-spaces
memset(newp + bd.textcol, ' ', (size_t)bd.startspaces);
// insert replacement chars CHECK FOR ALLOCATED SPACE
- // -1/-2 is used for entering CR literally.
+ // REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR literally.
size_t after_p_len = 0;
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
// strlen(newp) at this point
diff --git a/src/nvim/option.c b/src/nvim/option.c
index aa1f5f3fe7..c805e41ec5 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1498,6 +1498,7 @@ do_set (
char_u *newval;
char_u *origval = NULL;
char *saved_origval = NULL;
+ char *saved_newval = NULL;
unsigned newlen;
int comma;
int bs;
@@ -1514,7 +1515,17 @@ do_set (
/* The old value is kept until we are sure that the
* new value is valid. */
oldval = *(char_u **)varp;
- if (nextchar == '&') { /* set to default val */
+
+ // When setting the local value of a global
+ // option, the old value may be the global value.
+ if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags
+ & OPT_LOCAL)) {
+ origval = *(char_u **)get_varp(&options[opt_idx]);
+ } else {
+ origval = oldval;
+ }
+
+ if (nextchar == '&') { // set to default val
newval = options[opt_idx].def_val[
((flags & P_VI_DEF) || cp_val)
? VI_DEFAULT : VIM_DEFAULT];
@@ -1573,6 +1584,9 @@ do_set (
break;
}
xfree(oldval);
+ if (origval == oldval) {
+ origval = *(char_u **)varp;
+ }
oldval = *(char_u **)varp;
}
/*
@@ -1609,15 +1623,6 @@ do_set (
++arg;
}
- /* When setting the local value of a global
- * option, the old value may be the global value. */
- if (((int)options[opt_idx].indir & PV_BOTH)
- && (opt_flags & OPT_LOCAL))
- origval = *(char_u **)get_varp(
- &options[opt_idx]);
- else
- origval = oldval;
-
/*
* Copy the new string into allocated memory.
* Can't use set_string_option_direct(), because
@@ -1787,43 +1792,37 @@ do_set (
new_value_alloced = TRUE;
}
- /* Set the new value. */
+ // Set the new value.
*(char_u **)(varp) = newval;
- if (!starting && origval != NULL) {
+ if (!starting && origval != NULL && newval != NULL) {
// origval may be freed by
// did_set_string_option(), make a copy.
- saved_origval = xstrdup((char *) origval);
+ saved_origval = xstrdup((char *)origval);
+ // newval (and varp) may become invalid if the
+ // buffer is closed by autocommands.
+ saved_newval = xstrdup((char *)newval);
}
- /* Handle side effects, and set the global value for
- * ":set" on local options. */
+ // Handle side effects, and set the global value for
+ // ":set" on local options. Note: when setting 'syntax'
+ // or 'filetype' autocommands may be triggered that can
+ // cause havoc.
errmsg = did_set_string_option(opt_idx, (char_u **)varp,
new_value_alloced, oldval, errbuf, opt_flags);
+ if (errmsg == NULL) {
+ trigger_optionsset_string(opt_idx, opt_flags, saved_origval,
+ saved_newval);
+ }
+ xfree(saved_origval);
+ xfree(saved_newval);
+
// If error detected, print the error message.
if (errmsg != NULL) {
- xfree(saved_origval);
goto skip;
}
- if (saved_origval != NULL) {
- char buf_type[7];
- vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
- (opt_flags & OPT_LOCAL) ? "local" : "global");
- set_vim_var_string(VV_OPTION_NEW, *(char **) varp, -1);
- set_vim_var_string(VV_OPTION_OLD, saved_origval, -1);
- set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
- apply_autocmds(EVENT_OPTIONSET,
- (char_u *)options[opt_idx].fullname,
- NULL, false, NULL);
- reset_v_option_vars();
- xfree(saved_origval);
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- STRING_OBJ(cstr_as_string(*(char **)varp)));
- }
- }
} else {
// key code option(FIXME(tarruda): Show a warning or something
// similar)
@@ -2406,6 +2405,7 @@ static char *set_string_option(const int opt_idx, const char *const value,
*varp = s;
char *const saved_oldval = (starting ? NULL : xstrdup(oldval));
+ char *const saved_newval = (starting ? NULL : xstrdup(s));
char *const r = (char *)did_set_string_option(
opt_idx, (char_u **)varp, (int)true, (char_u *)oldval, NULL, opt_flags);
@@ -2414,23 +2414,12 @@ static char *set_string_option(const int opt_idx, const char *const value,
}
// call autocommand after handling side effects
- if (saved_oldval != NULL) {
- char buf_type[7];
- vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
- (opt_flags & OPT_LOCAL) ? "local" : "global");
- set_vim_var_string(VV_OPTION_NEW, (char *)(*varp), -1);
- set_vim_var_string(VV_OPTION_OLD, saved_oldval, -1);
- set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
- apply_autocmds(EVENT_OPTIONSET,
- (char_u *)options[opt_idx].fullname,
- NULL, false, NULL);
- reset_v_option_vars();
- xfree(saved_oldval);
- if (options[opt_idx].flags & P_UI_OPTION) {
- ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
- STRING_OBJ(cstr_as_string((char *)(*varp))));
- }
+ if (r == NULL) {
+ trigger_optionsset_string(opt_idx, opt_flags,
+ saved_oldval, saved_newval);
}
+ xfree(saved_oldval);
+ xfree(saved_newval);
return r;
}
@@ -4461,6 +4450,27 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
return (char *)errmsg;
}
+static void trigger_optionsset_string(int opt_idx, int opt_flags,
+ char *oldval, char *newval)
+{
+ if (oldval != NULL && newval != NULL) {
+ char buf_type[7];
+
+ vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
+ (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_OLD, oldval, -1);
+ set_vim_var_string(VV_OPTION_NEW, newval, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET,
+ (char_u *)options[opt_idx].fullname, NULL, false, NULL);
+ reset_v_option_vars();
+ if (options[opt_idx].flags & P_UI_OPTION) {
+ ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
+ STRING_OBJ(cstr_as_string(newval)));
+ }
+ }
+}
+
/*
* Called after an option changed: check if something needs to be redrawn.
*/
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index db7ed9da45..6e8100594d 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2185,7 +2185,7 @@ return {
type='number', scope={'global'},
vi_def=true,
varname='p_ss',
- defaults={if_true={vi=0}}
+ defaults={if_true={vi=1}}
},
{
full_name='sidescrolloff', abbreviation='siso',
@@ -2447,7 +2447,7 @@ return {
full_name='termguicolors', abbreviation='tgc',
type='bool', scope={'global'},
vi_def=false,
- redraw={'everything', 'ui_option'},
+ redraw={'ui_option'},
varname='p_tgc',
defaults={if_true={vi=false}}
},
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index c205e4b3af..f650a51fe7 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -123,6 +123,9 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
if (opts & kShellOptRead) {
output_ptr = &output;
forward_output = false;
+ } else if (opts & kShellOptDoOut) {
+ // Caller has already redirected output
+ forward_output = false;
}
}
@@ -257,11 +260,25 @@ static int do_os_system(char **argv,
// busy state.
ui_busy_start();
ui_flush();
+ if (forward_output) {
+ msg_sb_eol();
+ msg_start();
+ msg_no_more = true;
+ lines_left = -1;
+ }
int exitcode = process_wait(proc, -1, NULL);
if (!got_int && out_data_decide_throttle(0)) {
// Last chunk of output was skipped; display it now.
out_data_ring(NULL, SIZE_MAX);
}
+ if (forward_output) {
+ // caller should decide if wait_return is invoked
+ no_wait_return++;
+ msg_end();
+ no_wait_return--;
+ msg_no_more = false;
+ }
+
ui_busy_stop();
// prepare the out parameters if requested
@@ -405,7 +422,7 @@ static void out_data_ring(char *output, size_t size)
}
if (output == NULL && size == SIZE_MAX) { // Print mode
- out_data_append_to_screen(last_skipped, last_skipped_len, true);
+ out_data_append_to_screen(last_skipped, &last_skipped_len, true);
return;
}
@@ -433,60 +450,40 @@ static void out_data_ring(char *output, size_t size)
/// @param output Data to append to screen lines.
/// @param remaining Size of data.
/// @param new_line If true, next data output will be on a new line.
-static void out_data_append_to_screen(char *output, size_t remaining,
- bool new_line)
+static void out_data_append_to_screen(char *output, size_t *count,
+ bool eof)
{
- static colnr_T last_col = 0; // Column of last row to append to.
-
- size_t off = 0;
- int last_row = (int)Rows - 1;
-
- while (output != NULL && off < remaining) {
- // Found end of line?
- if (output[off] == NL) {
- // Can we start a new line or do we need to continue the last one?
- if (last_col == 0) {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
+ char *p = output, *end = output + *count;
+ while (p < end) {
+ if (*p == '\n' || *p == '\r' || *p == TAB || *p == BELL) {
+ msg_putchar_attr((uint8_t)(*p), 0);
+ p++;
+ } else {
+ // Note: this is not 100% precise:
+ // 1. we don't check if received continuation bytes are already invalid
+ // and we thus do some buffering that could be avoided
+ // 2. we don't compose chars over buffer boundaries, even if we see an
+ // incomplete UTF-8 sequence that could be composing with the last
+ // complete sequence.
+ // This will be corrected when we switch to vterm based implementation
+ int i = *p ? mb_ptr2len_len((char_u *)p, (int)(end-p)) : 1;
+ if (!eof && i == 1 && utf8len_tab_zero[*(uint8_t *)p] > (end-p)) {
+ *count = (size_t)(p - output);
+ goto end;
}
- screen_puts_len((char_u *)output, (int)off, last_row, last_col, 0);
- last_col = 0;
-
- size_t skip = off + 1;
- output += skip;
- remaining -= skip;
- off = 0;
- continue;
- }
- // TODO(bfredl): using msg_puts would be better until
- // terminal emulation is implemented.
- if (output[off] < 0x20) {
- output[off] = ' ';
+ (void)msg_outtrans_len_attr((char_u *)p, i, 0);
+ p += i;
}
-
- off++;
- }
-
- if (output != NULL && remaining) {
- if (last_col == 0) {
- screen_del_lines(0, 0, 1, (int)Rows, NULL);
- }
- screen_puts_len((char_u *)output, (int)remaining, last_row, last_col, 0);
- last_col += (colnr_T)remaining;
- }
-
- if (new_line) {
- last_col = 0;
}
+end:
ui_flush();
}
static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
bool eof)
{
- // We always output the whole buffer, so the buffer can never
- // wrap around.
size_t cnt;
char *ptr = rbuffer_read_ptr(buf, &cnt);
@@ -495,12 +492,16 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
// Save the skipped output. If it is the final chunk, we display it later.
out_data_ring(ptr, cnt);
} else {
- out_data_append_to_screen(ptr, cnt, eof);
+ out_data_append_to_screen(ptr, &cnt, eof);
}
if (cnt) {
rbuffer_consumed(buf, cnt);
}
+
+ // Move remaining data to start of buffer, so the buffer can never
+ // wrap around.
+ rbuffer_reset(buf);
}
/// Parses a command string into a sequence of words, taking quotes into
@@ -589,14 +590,10 @@ static void read_input(DynamicBuffer *buf)
if (len == l) {
// Finished a line, add a NL, unless this line should not have one.
- // FIXME need to make this more readable
if (lnum != curbuf->b_op_end.lnum
- || (!curbuf->b_p_bin
- && curbuf->b_p_fixeol)
+ || (!curbuf->b_p_bin && curbuf->b_p_fixeol)
|| (lnum != curbuf->b_no_eol_lnum
- && (lnum !=
- curbuf->b_ml.ml_line_count
- || curbuf->b_p_eol))) {
+ && (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) {
dynamic_buffer_ensure(buf, buf->len + 1);
buf->data[buf->len++] = NL;
}
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index c471352c02..290d421acc 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -38,33 +38,33 @@ uint64_t os_hrtime(void)
return uv_hrtime();
}
-/// Sleeps for a certain amount of milliseconds.
+/// Sleeps for `ms` milliseconds.
///
-/// @param milliseconds Number of milliseconds to sleep
+/// @param ms Number of milliseconds to sleep
/// @param ignoreinput If true, only SIGINT (CTRL-C) can interrupt.
-void os_delay(uint64_t milliseconds, bool ignoreinput)
+void os_delay(uint64_t ms, bool ignoreinput)
{
if (ignoreinput) {
- if (milliseconds > INT_MAX) {
- milliseconds = INT_MAX;
+ if (ms > INT_MAX) {
+ ms = INT_MAX;
}
- LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)milliseconds, got_int);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, (int)ms, got_int);
} else {
- os_microdelay(milliseconds * 1000u, ignoreinput);
+ os_microdelay(ms * 1000u, ignoreinput);
}
}
-/// Sleeps for a certain amount of microseconds.
+/// Sleeps for `us` microseconds.
///
-/// @param ms Number of microseconds to sleep.
+/// @param us Number of microseconds to sleep.
/// @param ignoreinput If true, ignore all input (including SIGINT/CTRL-C).
/// If false, waiting is aborted on any input.
-void os_microdelay(uint64_t ms, bool ignoreinput)
+void os_microdelay(uint64_t us, bool ignoreinput)
{
uint64_t elapsed = 0u;
uint64_t base = uv_hrtime();
// Convert microseconds to nanoseconds, or UINT64_MAX on overflow.
- const uint64_t ns = (ms < UINT64_MAX / 1000u) ? ms * 1000u : UINT64_MAX;
+ const uint64_t ns = (us < UINT64_MAX / 1000u) ? us * 1000u : UINT64_MAX;
uv_mutex_lock(&delay_mutex);
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index d7ba675b68..a27fee4e90 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -133,7 +133,8 @@ void mch_free_acl(vim_acl_T aclent)
}
#endif
-void mch_exit(int r) FUNC_ATTR_NORETURN
+void mch_exit(int r)
+ FUNC_ATTR_NORETURN
{
exiting = true;
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index bf79e4b84f..348daf028a 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -567,6 +567,7 @@ static int pum_set_selected(int n, int repeat)
&& (repeat <= 1)
&& (vim_strchr(p_cot, 'p') != NULL)) {
win_T *curwin_save = curwin;
+ tabpage_T *curtab_save = curtab;
int res = OK;
// Open a preview window. 3 lines by default. Prefer
@@ -647,7 +648,12 @@ static int pum_set_selected(int n, int repeat)
curwin->w_cursor.lnum = 1;
curwin->w_cursor.col = 0;
- if ((curwin != curwin_save) && win_valid(curwin_save)) {
+ if ((curwin != curwin_save && win_valid(curwin_save))
+ || (curtab != curtab_save && valid_tabpage(curtab_save))) {
+ if (curtab != curtab_save && valid_tabpage(curtab_save)) {
+ goto_tabpage_tp(curtab_save, false, false);
+ }
+
// When the first completion is done and the preview
// window is not resized, skip the preview window's
// status line redrawing.
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 63252df3dc..1aeadcec4a 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3148,10 +3148,9 @@ void ex_make(exarg_T *eap)
}
msg_start();
MSG_PUTS(":!");
- msg_outtrans((char_u *) cmd); // show what we are doing
+ msg_outtrans((char_u *)cmd); // show what we are doing
- // let the shell know if we are redirecting output or not
- do_shell((char_u *) cmd, *p_sp != NUL ? kShellOptDoOut : 0);
+ do_shell((char_u *)cmd, 0);
res = qf_init(wp, fname, (eap->cmdidx != CMD_make
@@ -3910,6 +3909,7 @@ load_dummy_buffer (
bufref_T newbuf_to_wipe;
int failed = true;
aco_save_T aco;
+ int readfile_result;
// Allocate a buffer without putting it in the buffer list.
newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
@@ -3923,7 +3923,9 @@ load_dummy_buffer (
/* need to open the memfile before putting the buffer in a window */
if (ml_open(newbuf) == OK) {
- /* set curwin/curbuf to buf and save a few things */
+ // Make sure this buffer isn't wiped out by auto commands.
+ newbuf->b_locked++;
+ // set curwin/curbuf to buf and save a few things
aucmd_prepbuf(&aco, newbuf);
/* Need to set the filename for autocommands. */
@@ -3937,9 +3939,11 @@ load_dummy_buffer (
curbuf->b_flags &= ~BF_DUMMY;
newbuf_to_wipe.br_buf = NULL;
- if (readfile(fname, NULL,
- (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
- NULL, READ_NEW | READ_DUMMY) == OK
+ readfile_result = readfile(fname, NULL, (linenr_T)0, (linenr_T)0,
+ (linenr_T)MAXLNUM, NULL,
+ READ_NEW | READ_DUMMY);
+ newbuf->b_locked--;
+ if (readfile_result == OK
&& !got_int
&& !(curbuf->b_flags & BF_NEW)) {
failed = FALSE;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 8a29734025..238d9a92a6 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -139,11 +139,6 @@
* doesn't fit. */
#define W_ENDCOL(wp) (wp->w_wincol + wp->w_width)
-/*
- * The attributes that are actually active for writing to the screen.
- */
-static int screen_attr = 0;
-
static match_T search_hl; /* used for 'hlsearch' highlight matching */
static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
@@ -189,8 +184,6 @@ void redraw_win_later(win_T *wp, int type)
void redraw_later_clear(void)
{
redraw_all_later(CLEAR);
- /* Use attributes that is very unlikely to appear in text. */
- screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE;
}
/*
@@ -3360,10 +3353,11 @@ win_line (
/* Use nextline[] if possible, it has the start of the
* next line concatenated. */
- if ((prev_ptr - line) - nextlinecol >= 0)
- p = nextline + (prev_ptr - line) - nextlinecol;
- else
+ if ((prev_ptr - line) - nextlinecol >= 0) {
+ p = nextline + ((prev_ptr - line) - nextlinecol);
+ } else {
p = prev_ptr;
+ }
cap_col -= (int)(prev_ptr - line);
size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange);
assert(tmplen <= INT_MAX);
@@ -5847,30 +5841,16 @@ next_search_hl_pos(
return 0;
}
-static void screen_start_highlight(int attr)
-{
- screen_attr = attr;
- ui_start_highlight(attr);
-}
-
-static void screen_stop_highlight(void)
-{
- ui_stop_highlight();
- screen_attr = 0;
-}
-
/*
* Put character ScreenLines["off"] on the screen at position "row" and "col",
* using the attributes from ScreenAttrs["off"].
*/
static void screen_char(unsigned off, int row, int col)
{
- int attr;
-
- /* Check for illegal values, just in case (could happen just after
- * resizing). */
- if (row >= screen_Rows || col >= screen_Columns)
+ // Check for illegal values, just in case (could happen just after resizing).
+ if (row >= screen_Rows || col >= screen_Columns) {
return;
+ }
// Outputting the last character on the screen may scrollup the screen.
// Don't to it! Mark the character invalid (update it when scrolled up)
@@ -5882,17 +5862,8 @@ static void screen_char(unsigned off, int row, int col)
return;
}
- /*
- * Stop highlighting first, so it's easier to move the cursor.
- */
- attr = ScreenAttrs[off];
- if (screen_attr != attr)
- screen_stop_highlight();
-
ui_cursor_goto(row, col);
-
- if (screen_attr != attr)
- screen_start_highlight(attr);
+ ui_set_highlight(ScreenAttrs[off]);
if (enc_utf8 && ScreenLinesUC[off] != 0) {
char_u buf[MB_MAXBYTES + 1];
@@ -6001,7 +5972,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
++off;
if (off < end_off) { /* something to be cleared */
col = off - LineOffset[row];
- screen_stop_highlight();
+ ui_clear_highlight();
ui_cursor_goto(row, col); // clear rest of this screen line
ui_call_eol_clear();
col = end_col - col;
@@ -6383,8 +6354,7 @@ static void screenclear2(void)
return;
}
- screen_stop_highlight(); /* don't want highlighting here */
-
+ ui_clear_highlight(); // don't want highlighting here
/* blank out ScreenLines */
for (i = 0; i < Rows; ++i) {
diff --git a/src/nvim/search.c b/src/nvim/search.c
index bbcac45369..5d41ed9c2a 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -775,12 +775,17 @@ int searchit(
}
}
if (ptr[matchcol] == NUL
- || (nmatched = vim_regexec_multi(&regmatch,
- win, buf, lnum + matchpos.lnum,
- matchcol,
- tm
- )) == 0)
- break;
+ || (nmatched = vim_regexec_multi(
+ &regmatch, win, buf, lnum + matchpos.lnum, matchcol,
+ tm)) == 0) {
+ // If the search timed out, we did find a match
+ // but it might be the wrong one, so that's not
+ // OK.
+ if (tm != NULL && profile_passed_limit(*tm)) {
+ match_ok = false;
+ }
+ break;
+ }
/* Need to get the line pointer again, a
* multi-line search may have made it invalid. */
@@ -3707,7 +3712,7 @@ current_quote (
int selected_quote = FALSE; /* Has quote inside selection */
int i;
- /* Correct cursor when 'selection' is exclusive */
+ // Correct cursor when 'selection' is "exclusive".
if (VIsual_active) {
// this only works within one line
if (VIsual.lnum != curwin->w_cursor.lnum) {
@@ -3715,8 +3720,17 @@ current_quote (
}
vis_bef_curs = lt(VIsual, curwin->w_cursor);
- if (*p_sel == 'e' && vis_bef_curs)
+ if (*p_sel == 'e') {
+ if (!vis_bef_curs) {
+ // VIsual needs to be start of Visual selection.
+ pos_T t = curwin->w_cursor;
+
+ curwin->w_cursor = VIsual;
+ VIsual = t;
+ vis_bef_curs = true;
+ }
dec_cursor();
+ }
vis_empty = equalpos(VIsual, curwin->w_cursor);
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 40479e05dd..0a7f703461 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -64,7 +64,7 @@ struct hl_group {
int sg_cterm_bold; ///< bold attr was set for light color
// for RGB UIs
int sg_gui; ///< "gui=" highlighting attributes
- ///< (combination of \ref HL_ATTRIBUTES)
+ ///< (combination of \ref HlAttrFlags)
RgbValue sg_rgb_fg; ///< RGB foreground color
RgbValue sg_rgb_bg; ///< RGB background color
RgbValue sg_rgb_sp; ///< RGB special color
@@ -6796,7 +6796,6 @@ void do_highlight(const char *line, const bool forceit, const bool init)
HL_TABLE()[idx].sg_cterm_fg = color + 1;
if (is_normal_group) {
cterm_normal_fg_color = color + 1;
- cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
must_redraw = CLEAR;
}
} else {
@@ -6940,7 +6939,6 @@ void restore_cterm_colors(void)
normal_bg = -1;
normal_sp = -1;
cterm_normal_fg_color = 0;
- cterm_normal_fg_bold = 0;
cterm_normal_bg_color = 0;
}
@@ -6994,9 +6992,9 @@ static void highlight_clear(int idx)
/// GUI can redraw at any time for any buffer.
static garray_T attr_table = GA_EMPTY_INIT_VALUE;
-static inline attrentry_T * ATTR_ENTRY(int idx)
+static inline HlAttrs * ATTR_ENTRY(int idx)
{
- return &((attrentry_T *)attr_table.ga_data)[idx];
+ return &((HlAttrs *)attr_table.ga_data)[idx];
}
@@ -7004,23 +7002,21 @@ static inline attrentry_T * ATTR_ENTRY(int idx)
/// Add a new entry to the term_attr_table, attr_table or gui_attr_table
/// if the combination is new.
/// @return 0 for error.
-int get_attr_entry(attrentry_T *aep)
+int get_attr_entry(HlAttrs *aep)
{
garray_T *table = &attr_table;
- attrentry_T *taep;
- static int recursive = FALSE;
+ HlAttrs *taep;
+ static int recursive = false;
/*
* Init the table, in case it wasn't done yet.
*/
- table->ga_itemsize = sizeof(attrentry_T);
+ table->ga_itemsize = sizeof(HlAttrs);
ga_set_growsize(table, 7);
- /*
- * Try to find an entry with the same specifications.
- */
- for (int i = 0; i < table->ga_len; ++i) {
- taep = &(((attrentry_T *)table->ga_data)[i]);
+ // Try to find an entry with the same specifications.
+ for (int i = 0; i < table->ga_len; i++) {
+ taep = &(((HlAttrs *)table->ga_data)[i]);
if (aep->cterm_ae_attr == taep->cterm_ae_attr
&& aep->cterm_fg_color == taep->cterm_fg_color
&& aep->cterm_bg_color == taep->cterm_bg_color
@@ -7057,7 +7053,7 @@ int get_attr_entry(attrentry_T *aep)
// This is a new combination of colors and font, add an entry.
- taep = GA_APPEND_VIA_PTR(attrentry_T, table);
+ taep = GA_APPEND_VIA_PTR(HlAttrs, table);
memset(taep, 0, sizeof(*taep));
taep->cterm_ae_attr = aep->cterm_ae_attr;
taep->cterm_fg_color = aep->cterm_fg_color;
@@ -7085,9 +7081,9 @@ void clear_hl_tables(void)
// Return the resulting attributes.
int hl_combine_attr(int char_attr, int prim_attr)
{
- attrentry_T *char_aep = NULL;
- attrentry_T *spell_aep;
- attrentry_T new_en = ATTRENTRY_INIT;
+ HlAttrs *char_aep = NULL;
+ HlAttrs *spell_aep;
+ HlAttrs new_en = HLATTRS_INIT;
if (char_attr == 0) {
return prim_attr;
@@ -7136,7 +7132,7 @@ int hl_combine_attr(int char_attr, int prim_attr)
/// \note this function does not apply exclusively to cterm attr contrary
/// to what its name implies
/// \warn don't call it with attr 0 (i.e., the null attribute)
-attrentry_T *syn_cterm_attr2entry(int attr)
+HlAttrs *syn_cterm_attr2entry(int attr)
{
attr -= ATTR_OFF;
if (attr >= attr_table.ga_len) {
@@ -7385,7 +7381,7 @@ syn_list_header(int did_header, int outlen, int id)
/// @param idx corrected highlight index
static void set_hl_attr(int idx)
{
- attrentry_T at_en = ATTRENTRY_INIT;
+ HlAttrs at_en = HLATTRS_INIT;
struct hl_group *sgp = HL_TABLE() + idx;
@@ -8509,24 +8505,21 @@ RgbValue name_to_color(const char_u *name)
/// Gets highlight description for id `attr_id` as a map.
Dictionary hl_get_attr_by_id(Integer attr_id, Boolean rgb, Error *err)
{
- HlAttrs attrs = HLATTRS_INIT;
+ HlAttrs *aep = NULL;
Dictionary dic = ARRAY_DICT_INIT;
if (attr_id == 0) {
- goto end;
+ return dic;
}
- attrentry_T *aep = syn_cterm_attr2entry((int)attr_id);
+ aep = syn_cterm_attr2entry((int)attr_id);
if (!aep) {
api_set_error(err, kErrorTypeException,
"Invalid attribute id: %" PRId64, attr_id);
return dic;
}
- attrs = attrentry2hlattrs(aep, rgb);
-
-end:
- return hlattrs2dict(attrs);
+ return hlattrs2dict(aep, rgb);
}
diff --git a/src/nvim/syntax.h b/src/nvim/syntax.h
index c9b0665ec8..f8282955a6 100644
--- a/src/nvim/syntax.h
+++ b/src/nvim/syntax.h
@@ -6,19 +6,6 @@
#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h"
-/// Terminal highlighting attribute bits.
-/// Attributes above HL_ALL are used for syntax highlighting.
-/// \addtogroup HL_ATTRIBUTES
-/// @{
-#define HL_NORMAL 0x00
-#define HL_INVERSE 0x01
-#define HL_BOLD 0x02
-#define HL_ITALIC 0x04
-#define HL_UNDERLINE 0x08
-#define HL_UNDERCURL 0x10
-#define HL_STANDOUT 0x20
-/// @}
-
#define HL_CONTAINED 0x01 /* not used on toplevel */
#define HL_TRANSP 0x02 /* has no highlighting */
#define HL_ONELINE 0x04 /* match within one line only */
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 7260853703..63089a62af 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -68,21 +68,4 @@ struct syn_state {
* may have made the state invalid */
};
-// Structure shared between syntax.c, screen.c
-typedef struct attr_entry {
- int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
- RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
- int cterm_fg_color, cterm_bg_color;
-} attrentry_T;
-
-#define ATTRENTRY_INIT { \
- .rgb_ae_attr = 0, \
- .cterm_ae_attr = 0, \
- .rgb_fg_color = -1, \
- .rgb_bg_color = -1, \
- .rgb_sp_color = -1, \
- .cterm_fg_color = 0, \
- .cterm_bg_color = 0, \
-}
-
#endif // NVIM_SYNTAX_DEFS_H
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index dfa758f41e..f3eb6883ce 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -61,7 +61,6 @@
#include "nvim/edit.h"
#include "nvim/mouse.h"
#include "nvim/memline.h"
-#include "nvim/mark.h"
#include "nvim/map.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
@@ -376,8 +375,6 @@ void terminal_enter(void)
// Ensure the terminal is properly sized.
terminal_resize(s->term, 0, 0);
- checkpcmark();
- setpcmark();
int save_state = State;
s->save_rd = RedrawingDisabled;
State = TERM_FOCUS;
@@ -588,7 +585,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
int attr_id = 0;
if (hl_attrs || vt_fg != -1 || vt_bg != -1) {
- attr_id = get_attr_entry(&(attrentry_T) {
+ attr_id = get_attr_entry(&(HlAttrs) {
.cterm_ae_attr = (int16_t)hl_attrs,
.cterm_fg_color = vt_fg_idx,
.cterm_bg_color = vt_bg_idx,
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index bd9842ea19..aa5d534530 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -22,15 +22,12 @@ SCRIPTS_DEFAULT = \
test48.out \
test49.out \
test52.out \
- test53.out \
test64.out \
test73.out \
- test79.out \
ifneq ($(OS),Windows_NT)
SCRIPTS_DEFAULTS := $(SCRIPTS_DEFAULT) \
test17.out \
- test32.out \
endif
@@ -48,9 +45,13 @@ NEW_TESTS ?= \
test_cmdline.res \
test_command_count.res \
test_cscope.res \
+ test_curswant.res \
test_digraph.res \
+ test_edit.res \
+ test_exists.res \
test_diffmode.res \
test_farsi.res \
+ test_file_size.res \
test_filter_map.res \
test_findfile.res \
test_fnameescape.res \
@@ -66,8 +67,11 @@ NEW_TESTS ?= \
test_hlsearch.res \
test_increment.res \
test_increment_dbcs.res \
+ test_ins_complete.res \
test_lambda.res \
test_langmap.res \
+ test_let.res \
+ test_lineending.res \
test_makeencoding.res \
test_marks.res \
test_match.res \
@@ -81,7 +85,9 @@ NEW_TESTS ?= \
test_options.res \
test_profile.res \
test_quickfix.res \
+ test_recover.res \
test_retab.res \
+ test_scrollbind.res \
test_search.res \
test_signs.res \
test_smartindent.res \
@@ -92,6 +98,7 @@ NEW_TESTS ?= \
test_substitute.res \
test_syntax.res \
test_system.res \
+ test_tab.res \
test_tabpage.res \
test_textobjects.res \
test_timers.res \
@@ -99,6 +106,7 @@ NEW_TESTS ?= \
test_usercommands.res \
test_vimscript.res \
test_visual.res \
+ test_winbuf_close.res \
test_window_id.res \
test_writefile.res \
test_alot.res
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index a0e8cfeb99..2d2dc8fbf8 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -4,7 +4,7 @@
"
" To execute only specific test functions, add a second argument. It will be
" matched against the names of the Test_ function. E.g.:
-" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
+" ../vim -u NONE -S runtest.vim test_channel.vim open_delay
" The output can be found in the "messages" file.
"
" The test script may contain anything, only functions that start with
@@ -42,10 +42,11 @@ endif
" Common with all tests on all systems.
source setup.vim
+" For consistency run all tests with 'nocompatible' set.
" This also enables use of line continuation.
-set viminfo+=nviminfo
+set nocp viminfo+=nviminfo
-" Use utf-8 or latin1 be default, instead of whatever the system default
+" Use utf-8 or latin1 by default, instead of whatever the system default
" happens to be. Individual tests can overrule this at the top of the file.
if has('multi_byte')
set encoding=utf-8
@@ -62,22 +63,38 @@ lang mess C
" Always use forward slashes.
set shellslash
-" Make sure $HOME does not get read or written.
-let $HOME = '/does/not/exist'
-
-" Prepare for calling garbagecollect_for_testing().
+" Prepare for calling test_garbagecollect_now().
let v:testing = 1
-" Align Nvim defaults to Vim.
-set directory^=.
-set backspace=
-set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
-set listchars=eol:$
-" Prevent Nvim log from writing to stderr.
-let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
+" Support function: get the alloc ID by name.
+function GetAllocId(name)
+ exe 'split ' . s:srcdir . '/alloc.h'
+ let top = search('typedef enum')
+ if top == 0
+ call add(v:errors, 'typedef not found in alloc.h')
+ endif
+ let lnum = search('aid_' . a:name . ',')
+ if lnum == 0
+ call add(v:errors, 'Alloc ID ' . a:name . ' not defined')
+ endif
+ close
+ return lnum - top - 1
+endfunc
func RunTheTest(test)
echo 'Executing ' . a:test
+
+ " Avoid stopping at the "hit enter" prompt
+ set nomore
+
+ " Avoid a three second wait when a message is about to be overwritten by the
+ " mode message.
+ set noshowmode
+
+ " Some tests wipe out buffers. To be consistent, always wipe out all
+ " buffers.
+ %bwipe!
+
if exists("*SetUp")
try
call SetUp()
@@ -88,14 +105,21 @@ func RunTheTest(test)
call add(s:messages, 'Executing ' . a:test)
let s:done += 1
- try
+
+ if a:test =~ 'Test_nocatch_'
+ " Function handles errors itself. This avoids skipping commands after the
+ " error.
exe 'call ' . a:test
- catch /^\cskipped/
- call add(s:messages, ' Skipped')
- call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
- catch
- call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
- endtry
+ else
+ try
+ exe 'call ' . a:test
+ catch /^\cskipped/
+ call add(s:messages, ' Skipped')
+ call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
+ catch
+ call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
+ endtry
+ endif
if exists("*TearDown")
try
@@ -105,7 +129,14 @@ func RunTheTest(test)
endtry
endif
- " Close any extra windows and make the current one not modified.
+ " Clear any autocommands
+ au!
+
+ " Close any extra tab pages and windows and make the current one not modified.
+ while tabpagenr('$') > 1
+ quit!
+ endwhile
+
while 1
let wincount = winnr('$')
if wincount == 1
@@ -118,7 +149,6 @@ func RunTheTest(test)
break
endif
endwhile
- set nomodified
endfunc
func AfterTheTest()
@@ -198,8 +228,14 @@ endif
" Names of flaky tests.
let s:flaky = [
\ 'Test_exit_callback_interval()',
- \ 'Test_with_partial_callback()',
\ 'Test_oneshot()',
+ \ 'Test_out_cb()',
+ \ 'Test_paused()',
+ \ 'Test_reltime()',
+ \ 'Test_terminal_composing_unicode()',
+ \ 'Test_terminal_redir_file()',
+ \ 'Test_terminal_tmap()',
+ \ 'Test_with_partial_callback()',
\ 'Test_lambda_with_timer()',
\ ]
@@ -216,12 +252,30 @@ endif
" Execute the tests in alphabetical order.
for s:test in sort(s:tests)
+ " Silence, please!
+ set belloff=all
+
call RunTheTest(s:test)
if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
+ call add(s:messages, 'Found errors in ' . s:test . ':')
+ call extend(s:messages, v:errors)
call add(s:messages, 'Flaky test failed, running it again')
+ let first_run = v:errors
+
+ " Flakiness is often caused by the system being very busy. Sleep a couple
+ " of seconds to have a higher chance of succeeding the second time.
+ sleep 2
+
let v:errors = []
call RunTheTest(s:test)
+ if len(v:errors) > 0
+ let second_run = v:errors
+ let v:errors = ['First run:']
+ call extend(v:errors, first_run)
+ call add(v:errors, 'Second run:')
+ call extend(v:errors, second_run)
+ endif
endif
call AfterTheTest()
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index 06f2199214..87cf1f6163 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -1,8 +1,14 @@
" Common preparations for running tests.
-set noruler
-set noshowcmd
-set belloff=
+" Align Nvim defaults to Vim.
+set sidescroll=0
+set directory^=.
+set backspace=
+set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
+set listchars=eol:$
+" Prevent Nvim log from writing to stderr.
+let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
+
" Make sure 'runtimepath' and 'packpath' does not include $HOME.
set rtp=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
diff --git a/src/nvim/testdir/test32.in b/src/nvim/testdir/test32.in
deleted file mode 100644
index 76bd9be889..0000000000
--- a/src/nvim/testdir/test32.in
+++ /dev/null
@@ -1,60 +0,0 @@
-Test for insert expansion
-
-:se cpt=.,w
-* add-expands (word from next line) from other window
-* add-expands (current buffer first)
-* Local expansion, ends in an empty line (unless it becomes a global expansion)
-* starts Local and switches to global add-expansion
-:se cpt=.,w,i
-* i-add-expands and switches to local
-* add-expands lines (it would end in an empty line if it didn't ignored it self)
-:se cpt=kXtestfile
-* checks k-expansion, and file expansion (use Xtest11 instead of test11,
-* because TEST11.OUT may match first on DOS)
-:se cpt=w
-* checks make_cyclic in other window
-:se cpt=u nohid
-* checks unloaded buffer expansion
-* checks adding mode abortion
-:se cpt=t,d
-* tag expansion, define add-expansion interrupted
-* t-expansion
-
-STARTTEST
-:se backspace=""
-:se cpt=.,w ff=unix | $-2,$w!Xtestfile | set ff&
-:se cot=
-nO#include "Xtestfile"
-ru
-O
-
-
-:se cpt=.,w,i
-kOM
-  
-:se cpt=kXtestfile
-:w Xtest11.one
-:w Xtest11.two
-OIXA
-:" use CTRL-X CTRL-F to complete Xtest11.one, remove it and then use
-:" CTRL-X CTRL-F again to verify this doesn't cause trouble.
-OXddk
-:se cpt=w
-OST
-:se cpt=u nohid
-oOEN
-unl
-:se cpt=t,d def=^\\k* tags=Xtestfile notagbsearch
-O
-a
-:wq! test.out
-ENDTEST
-
-start of testfile
-run1
-run2
-end of testfile
-
-test11 36Gepeto /Tag/
-asd test11file 36G
-Makefile to run
diff --git a/src/nvim/testdir/test32.ok b/src/nvim/testdir/test32.ok
deleted file mode 100644
index afc4463fac..0000000000
--- a/src/nvim/testdir/test32.ok
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "Xtestfile"
-run1 run3
-run3 run3
-
-Makefile to run3
-Makefile to run3
-Makefile to run3
-Xtest11.two
-STARTTEST
-ENDTEST
-unless
-test11file 36Gepeto /Tag/ asd
-asd
-run1 run2
-
diff --git a/src/nvim/testdir/test53.in b/src/nvim/testdir/test53.in
deleted file mode 100644
index 20b5d019af..0000000000
--- a/src/nvim/testdir/test53.in
+++ /dev/null
@@ -1,74 +0,0 @@
-Tests for string and html text objects. vim: set ft=vim :
-
-Note that the end-of-line moves the cursor to the next test line.
-
-Also test match() and matchstr()
-
-STARTTEST
-/^start:/
-da"
-0va'a'rx
-02f`da`
-0fXdi"
-03f'vi'ry
-:set quoteescape=+*-
-di`
-$F"va"oha"i"rz
-:"
-/^<begin
-jfXdit
-0fXdit
-fXdat
-0fXdat
-dit
-:"
-:put =matchstr(\"abcd\", \".\", 0, 2) " b
-:put =matchstr(\"abcd\", \"..\", 0, 2) " bc
-:put =matchstr(\"abcd\", \".\", 2, 0) " c (zero and negative -> first match)
-:put =matchstr(\"abcd\", \".\", 0, -1) " a
-:put =match(\"abcd\", \".\", 0, 5) " -1
-:put =match(\"abcd\", \".\", 0, -1) " 0
-:put =match('abc', '.', 0, 1) " 0
-:put =match('abc', '.', 0, 2) " 1
-:put =match('abc', '.', 0, 3) " 2
-:put =match('abc', '.', 0, 4) " -1
-:put =match('abc', '.', 1, 1) " 1
-:put =match('abc', '.', 2, 1) " 2
-:put =match('abc', '.', 3, 1) " -1
-:put =match('abc', '$', 0, 1) " 3
-:put =match('abc', '$', 0, 2) " -1
-:put =match('abc', '$', 1, 1) " 3
-:put =match('abc', '$', 2, 1) " 3
-:put =match('abc', '$', 3, 1) " 3
-:put =match('abc', '$', 4, 1) " -1
-:put =match('abc', '\zs', 0, 1) " 0
-:put =match('abc', '\zs', 0, 2) " 1
-:put =match('abc', '\zs', 0, 3) " 2
-:put =match('abc', '\zs', 0, 4) " 3
-:put =match('abc', '\zs', 0, 5) " -1
-:put =match('abc', '\zs', 1, 1) " 1
-:put =match('abc', '\zs', 2, 1) " 2
-:put =match('abc', '\zs', 3, 1) " 3
-:put =match('abc', '\zs', 4, 1) " -1
-:/^start:/,/^end:/wq! test.out
-ENDTEST
-
-start: "wo\"rd\\" foo
-'foo' 'bar' 'piep'
-bla bla `quote` blah
-out " in "noXno"
-"'" 'blah' rep 'buh'
-bla `s*`d-`+++`l**` b`la
-voo "nah" sdf " asdf" sdf " sdf" sd
-
-<begin>
--<b>asdf<i>Xasdf</i>asdf</b>-
--<b>asdX<i>a<i />sdf</i>asdf</b>-
--<b>asdf<i>Xasdf</i>asdf</b>-
--<b>asdX<i>as<b />df</i>asdf</b>-
--<b>
-innertext object
-</b>
-</begin>
-SEARCH:
-end:
diff --git a/src/nvim/testdir/test53.ok b/src/nvim/testdir/test53.ok
deleted file mode 100644
index d57d86bbb0..0000000000
--- a/src/nvim/testdir/test53.ok
+++ /dev/null
@@ -1,45 +0,0 @@
-start: foo
-xxxxxxxxxxxx'piep'
-bla bla blah
-out " in ""
-"'" 'blah'yyyyy'buh'
-bla `` b`la
-voo "zzzzzzzzzzzzzzzzzzzzzzzzzzzzsd
-
-<begin>
--<b>asdf<i></i>asdf</b>-
--<b></b>-
--<b>asdfasdf</b>-
---
--<b></b>
-</begin>
-b
-bc
-c
-a
--1
-0
-0
-1
-2
--1
-1
-2
--1
-3
--1
-3
-3
-3
--1
-0
-1
-2
-3
--1
-1
-2
-3
--1
-SEARCH:
-end:
diff --git a/src/nvim/testdir/test79.in b/src/nvim/testdir/test79.in
deleted file mode 100644
index afbf2083d2..0000000000
--- a/src/nvim/testdir/test79.in
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test79.ok b/src/nvim/testdir/test79.ok
deleted file mode 100644
index d4e0ae8819..0000000000
--- a/src/nvim/testdir/test79.ok
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 6df5aae677..735c4bb691 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -1,7 +1,6 @@
" A series of tests that can run in one Vim invocation.
" This makes testing go faster, since Vim doesn't need to restart.
-set belloff=all
source test_assign.vim
source test_changedtick.vim
source test_cursor_func.vim
@@ -19,12 +18,14 @@ source test_ga.vim
source test_goto.vim
source test_jumps.vim
source test_fileformat.vim
+source test_filetype.vim
source test_lambda.vim
source test_menu.vim
source test_mapping.vim
source test_messages.vim
source test_partial.vim
source test_popup.vim
+source test_recover.vim
source test_regexp_utf8.vim
source test_source_utf8.vim
source test_statusline.vim
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
new file mode 100644
index 0000000000..19d0cee47a
--- /dev/null
+++ b/src/nvim/testdir/test_arglist.vim
@@ -0,0 +1,355 @@
+" Test argument list commands
+
+func Test_argidx()
+ args a b c
+ last
+ call assert_equal(2, argidx())
+ %argdelete
+ call assert_equal(0, argidx())
+ " doing it again doesn't result in an error
+ %argdelete
+ call assert_equal(0, argidx())
+ call assert_fails('2argdelete', 'E16:')
+
+ args a b c
+ call assert_equal(0, argidx())
+ next
+ call assert_equal(1, argidx())
+ next
+ call assert_equal(2, argidx())
+ 1argdelete
+ call assert_equal(1, argidx())
+ 1argdelete
+ call assert_equal(0, argidx())
+ 1argdelete
+ call assert_equal(0, argidx())
+endfunc
+
+func Test_argadd()
+ %argdelete
+ argadd a b c
+ call assert_equal(0, argidx())
+
+ %argdelete
+ argadd a
+ call assert_equal(0, argidx())
+ argadd b c d
+ call assert_equal(0, argidx())
+
+ call Init_abc()
+ argadd x
+ call Assert_argc(['a', 'b', 'x', 'c'])
+ call assert_equal(1, argidx())
+
+ call Init_abc()
+ 0argadd x
+ call Assert_argc(['x', 'a', 'b', 'c'])
+ call assert_equal(2, argidx())
+
+ call Init_abc()
+ 1argadd x
+ call Assert_argc(['a', 'x', 'b', 'c'])
+ call assert_equal(2, argidx())
+
+ call Init_abc()
+ $argadd x
+ call Assert_argc(['a', 'b', 'c', 'x'])
+ call assert_equal(1, argidx())
+
+ call Init_abc()
+ $argadd x
+ +2argadd y
+ call Assert_argc(['a', 'b', 'c', 'x', 'y'])
+ call assert_equal(1, argidx())
+
+ %argd
+ edit d
+ arga
+ call assert_equal(1, len(argv()))
+ call assert_equal('d', get(argv(), 0, ''))
+
+ %argd
+ edit some\ file
+ arga
+ call assert_equal(1, len(argv()))
+ call assert_equal('some file', get(argv(), 0, ''))
+
+ %argd
+ new
+ arga
+ call assert_equal(0, len(argv()))
+endfunc
+
+func Init_abc()
+ args a b c
+ next
+endfunc
+
+func Assert_argc(l)
+ call assert_equal(len(a:l), argc())
+ let i = 0
+ while i < len(a:l) && i < argc()
+ call assert_equal(a:l[i], argv(i))
+ let i += 1
+ endwhile
+endfunc
+
+" Test for [count]argument and [count]argdelete commands
+" Ported from the test_argument_count.in test script
+func Test_argument()
+ " Clean the argument list
+ arga a | %argd
+
+ let save_hidden = &hidden
+ set hidden
+
+ let g:buffers = []
+ augroup TEST
+ au BufEnter * call add(buffers, expand('%:t'))
+ augroup END
+
+ argadd a b c d
+ $argu
+ $-argu
+ -argu
+ 1argu
+ +2argu
+
+ augroup TEST
+ au!
+ augroup END
+
+ call assert_equal(['d', 'c', 'b', 'a', 'c'], g:buffers)
+
+ redir => result
+ ar
+ redir END
+ call assert_true(result =~# 'a b \[c] d')
+
+ .argd
+ call assert_equal(['a', 'b', 'd'], argv())
+
+ -argd
+ call assert_equal(['a', 'd'], argv())
+
+ $argd
+ call assert_equal(['a'], argv())
+
+ 1arga c
+ 1arga b
+ $argu
+ $arga x
+ call assert_equal(['a', 'b', 'c', 'x'], argv())
+
+ 0arga y
+ call assert_equal(['y', 'a', 'b', 'c', 'x'], argv())
+
+ %argd
+ call assert_equal([], argv())
+
+ arga a b c d e f
+ 2,$-argd
+ call assert_equal(['a', 'f'], argv())
+
+ let &hidden = save_hidden
+
+ " Setting argument list should fail when the current buffer has unsaved
+ " changes
+ %argd
+ enew!
+ set modified
+ call assert_fails('args x y z', 'E37:')
+ args! x y z
+ call assert_equal(['x', 'y', 'z'], argv())
+ call assert_equal('x', expand('%:t'))
+
+ last | enew | argu
+ call assert_equal('z', expand('%:t'))
+
+ %argdelete
+ call assert_fails('argument', 'E163:')
+endfunc
+
+" Test for 0argadd and 0argedit
+" Ported from the test_argument_0count.in test script
+func Test_zero_argadd()
+ " Clean the argument list
+ arga a | %argd
+
+ arga a b c d
+ 2argu
+ 0arga added
+ call assert_equal(['added', 'a', 'b', 'c', 'd'], argv())
+
+ 2argu
+ arga third
+ call assert_equal(['added', 'a', 'third', 'b', 'c', 'd'], argv())
+
+ %argd
+ arga a b c d
+ 2argu
+ 0arge edited
+ call assert_equal(['edited', 'a', 'b', 'c', 'd'], argv())
+
+ 2argu
+ arga third
+ call assert_equal(['edited', 'a', 'third', 'b', 'c', 'd'], argv())
+
+ 2argu
+ argedit file\ with\ spaces another file
+ call assert_equal(['edited', 'a', 'file with spaces', 'another', 'file', 'third', 'b', 'c', 'd'], argv())
+ call assert_equal('file with spaces', expand('%'))
+endfunc
+
+func Reset_arglist()
+ args a | %argd
+endfunc
+
+" Test for argc()
+func Test_argc()
+ call Reset_arglist()
+ call assert_equal(0, argc())
+ argadd a b
+ call assert_equal(2, argc())
+endfunc
+
+" Test for arglistid()
+func Test_arglistid()
+ call Reset_arglist()
+ arga a b
+ call assert_equal(0, arglistid())
+ split
+ arglocal
+ call assert_equal(1, arglistid())
+ tabnew | tabfirst
+ call assert_equal(0, arglistid(2))
+ call assert_equal(1, arglistid(1, 1))
+ call assert_equal(0, arglistid(2, 1))
+ call assert_equal(1, arglistid(1, 2))
+ tabonly | only | enew!
+ argglobal
+ call assert_equal(0, arglistid())
+endfunc
+
+" Test for argv()
+func Test_argv()
+ call Reset_arglist()
+ call assert_equal([], argv())
+ call assert_equal("", argv(2))
+ argadd a b c d
+ call assert_equal('c', argv(2))
+endfunc
+
+" Test for the :argedit command
+func Test_argedit()
+ call Reset_arglist()
+ argedit a
+ call assert_equal(['a'], argv())
+ call assert_equal('a', expand('%:t'))
+ argedit b
+ call assert_equal(['a', 'b'], argv())
+ call assert_equal('b', expand('%:t'))
+ argedit a
+ call assert_equal(['a', 'b', 'a'], argv())
+ call assert_equal('a', expand('%:t'))
+ " When file name case is ignored, an existing buffer with only case
+ " difference is re-used.
+ argedit C D
+ call assert_equal('C', expand('%:t'))
+ call assert_equal(['a', 'b', 'a', 'C', 'D'], argv())
+ argedit c
+ if has('fname_case')
+ call assert_equal(['a', 'b', 'a', 'C', 'c', 'D'], argv())
+ else
+ call assert_equal(['a', 'b', 'a', 'C', 'C', 'D'], argv())
+ endif
+ 0argedit x
+ if has('fname_case')
+ call assert_equal(['x', 'a', 'b', 'a', 'C', 'c', 'D'], argv())
+ else
+ call assert_equal(['x', 'a', 'b', 'a', 'C', 'C', 'D'], argv())
+ endif
+ enew! | set modified
+ call assert_fails('argedit y', 'E37:')
+ argedit! y
+ if has('fname_case')
+ call assert_equal(['x', 'y', 'y', 'a', 'b', 'a', 'C', 'c', 'D'], argv())
+ else
+ call assert_equal(['x', 'y', 'y', 'a', 'b', 'a', 'C', 'C', 'D'], argv())
+ endif
+ %argd
+ bwipe! C
+ bwipe! D
+endfunc
+
+" Test for the :argdelete command
+func Test_argdelete()
+ call Reset_arglist()
+ args aa a aaa b bb
+ argdelete a*
+ call assert_equal(['b', 'bb'], argv())
+ call assert_equal('aa', expand('%:t'))
+ last
+ argdelete %
+ call assert_equal(['b'], argv())
+ call assert_fails('argdelete', 'E471:')
+ call assert_fails('1,100argdelete', 'E16:')
+ %argd
+endfunc
+
+" Tests for the :next, :prev, :first, :last, :rewind commands
+func Test_argpos()
+ call Reset_arglist()
+ args a b c d
+ last
+ call assert_equal(3, argidx())
+ call assert_fails('next', 'E165:')
+ prev
+ call assert_equal(2, argidx())
+ Next
+ call assert_equal(1, argidx())
+ first
+ call assert_equal(0, argidx())
+ call assert_fails('prev', 'E164:')
+ 3next
+ call assert_equal(3, argidx())
+ rewind
+ call assert_equal(0, argidx())
+ %argd
+endfunc
+
+" Test for autocommand that redefines the argument list, when doing ":all".
+func Test_arglist_autocmd()
+ autocmd BufReadPost Xxx2 next Xxx2 Xxx1
+ call writefile(['test file Xxx1'], 'Xxx1')
+ call writefile(['test file Xxx2'], 'Xxx2')
+ call writefile(['test file Xxx3'], 'Xxx3')
+
+ new
+ " redefine arglist; go to Xxx1
+ next! Xxx1 Xxx2 Xxx3
+ " open window for all args
+ all
+ call assert_equal('test file Xxx1', getline(1))
+ wincmd w
+ wincmd w
+ call assert_equal('test file Xxx1', getline(1))
+ " should now be in Xxx2
+ rewind
+ call assert_equal('test file Xxx2', getline(1))
+
+ autocmd! BufReadPost Xxx2
+ enew! | only
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('Xxx3')
+ argdelete Xxx*
+ bwipe! Xxx1 Xxx2 Xxx3
+endfunc
+
+func Test_arg_all_expand()
+ call writefile(['test file Xxx1'], 'Xx x')
+ next notexist Xx\ x runtest.vim
+ call assert_equal('notexist Xx\ x runtest.vim', expand('##'))
+ call delete('Xx x')
+endfunc
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
new file mode 100644
index 0000000000..05d69631c4
--- /dev/null
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -0,0 +1,19 @@
+" Test 'autochdir' behavior
+
+if !exists("+autochdir")
+ finish
+endif
+
+func Test_set_filename()
+ let cwd = getcwd()
+ call test_autochdir()
+ set acd
+ new
+ w samples/Xtest
+ call assert_equal("Xtest", expand('%'))
+ call assert_equal("samples", substitute(getcwd(), '.*/\(\k*\)', '\1', ''))
+ bwipe!
+ set noacd
+ exe 'cd ' . cwd
+ call delete('samples/Xtest')
+endfunc
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 82c04abf5b..24651b75e1 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1,14 +1,13 @@
" Tests for autocommands
-set belloff=all
-function! s:cleanup_buffers() abort
+func! s:cleanup_buffers() abort
for bnr in range(1, bufnr('$'))
if bufloaded(bnr) && bufnr('%') != bnr
execute 'bd! ' . bnr
endif
endfor
-endfunction
+endfunc
func Test_vim_did_enter()
call assert_false(v:vim_did_enter)
@@ -49,7 +48,7 @@ if has('timers')
endfunc
endif
-function Test_bufunload()
+func Test_bufunload()
augroup test_bufunload_group
autocmd!
autocmd BufUnload * call add(s:li, "bufunload")
@@ -80,7 +79,7 @@ function Test_bufunload()
endfunc
" SEGV occurs in older versions. (At least 7.4.2005 or older)
-function Test_autocmd_bufunload_with_tabnext()
+func Test_autocmd_bufunload_with_tabnext()
tabedit
tabfirst
@@ -98,7 +97,7 @@ function Test_autocmd_bufunload_with_tabnext()
quit
endfunc
-function Test_autocmd_bufwinleave_with_tabfirst()
+func Test_autocmd_bufwinleave_with_tabfirst()
tabedit
augroup sample
autocmd!
@@ -110,7 +109,7 @@ function Test_autocmd_bufwinleave_with_tabfirst()
endfunc
" SEGV occurs in older versions. (At least 7.4.2321 or older)
-function Test_autocmd_bufunload_avoiding_SEGV_01()
+func Test_autocmd_bufunload_avoiding_SEGV_01()
split aa.txt
let lastbuf = bufnr('$')
@@ -128,7 +127,7 @@ function Test_autocmd_bufunload_avoiding_SEGV_01()
endfunc
" SEGV occurs in older versions. (At least 7.4.2321 or older)
-function Test_autocmd_bufunload_avoiding_SEGV_02()
+func Test_autocmd_bufunload_avoiding_SEGV_02()
setlocal buftype=nowrite
let lastbuf = bufnr('$')
@@ -353,8 +352,10 @@ endfunc
" Closing a window might cause an endless loop
" E814 for older Vims
-function Test_autocmd_bufwipe_in_SessLoadPost()
+func Test_autocmd_bufwipe_in_SessLoadPost()
+ edit Xtest
tabnew
+ file Xsomething
set noswapfile
mksession!
@@ -362,7 +363,7 @@ function Test_autocmd_bufwipe_in_SessLoadPost()
\ 'let v:swapchoice="e"',
\ 'augroup test_autocmd_sessionload',
\ 'autocmd!',
- \ 'autocmd SessionLoadPost * 4bw!',
+ \ 'autocmd SessionLoadPost * exe bufnr("Xsomething") . "bw!"',
\ 'augroup END',
\ '',
\ 'func WriteErrors()',
@@ -382,7 +383,7 @@ function Test_autocmd_bufwipe_in_SessLoadPost()
endfunc
" SEGV occurs in older versions.
-function Test_autocmd_bufwipe_in_SessLoadPost2()
+func Test_autocmd_bufwipe_in_SessLoadPost2()
tabnew
set noswapfile
mksession!
@@ -421,6 +422,382 @@ function Test_autocmd_bufwipe_in_SessLoadPost2()
endfor
endfunc
+func Test_empty_doau()
+ doau \|
+endfunc
+
+func s:AutoCommandOptionSet(match)
+ let item = remove(g:options, 0)
+ let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3])
+ let actual = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type)
+ let g:opt = [expected, actual]
+ "call assert_equal(expected, actual)
+endfunc
+
+func Test_OptionSet()
+ throw 'skipped: Nvim does not support test_override()'
+ if !has("eval") || !has("autocmd") || !exists("+autochdir")
+ return
+ endif
+
+ call test_override('starting', 1)
+ set nocp
+ au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>"))
+
+ " 1: Setting number option"
+ let g:options=[['number', 0, 1, 'global']]
+ set nu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 2: Setting local number option"
+ let g:options=[['number', 1, 0, 'local']]
+ setlocal nonu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 3: Setting global number option"
+ let g:options=[['number', 1, 0, 'global']]
+ setglobal nonu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 4: Setting local autoindent option"
+ let g:options=[['autoindent', 0, 1, 'local']]
+ setlocal ai
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 5: Setting global autoindent option"
+ let g:options=[['autoindent', 0, 1, 'global']]
+ setglobal ai
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 6: Setting global autoindent option"
+ let g:options=[['autoindent', 1, 0, 'global']]
+ set ai!
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " Should not print anything, use :noa
+ " 7: don't trigger OptionSet"
+ let g:options=[['invalid', 1, 1, 'invalid']]
+ noa set nonu
+ call assert_equal([['invalid', 1, 1, 'invalid']], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 8: Setting several global list and number option"
+ let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']]
+ set list nu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 9: don't trigger OptionSet"
+ let g:options=[['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']]
+ noa set nolist nonu
+ call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 10: Setting global acd"
+ let g:options=[['autochdir', 0, 1, 'local']]
+ setlocal acd
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 11: Setting global autoread (also sets local value)"
+ let g:options=[['autoread', 0, 1, 'global']]
+ set ar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 12: Setting local autoread"
+ let g:options=[['autoread', 1, 1, 'local']]
+ setlocal ar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 13: Setting global autoread"
+ let g:options=[['autoread', 1, 0, 'global']]
+ setglobal invar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 14: Setting option backspace through :let"
+ let g:options=[['backspace', '', 'eol,indent,start', 'global']]
+ let &bs="eol,indent,start"
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 15: Setting option backspace through setbufvar()"
+ let g:options=[['backup', 0, 1, 'local']]
+ " try twice, first time, shouldn't trigger because option name is invalid,
+ " second time, it should trigger
+ call assert_fails("call setbufvar(1, '&l:bk', 1)", "E355")
+ " should trigger, use correct option name
+ call setbufvar(1, '&backup', 1)
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 16: Setting number option using setwinvar"
+ let g:options=[['number', 0, 1, 'local']]
+ call setwinvar(0, '&number', 1)
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 17: Setting key option, shouldn't trigger"
+ let g:options=[['key', 'invalid', 'invalid1', 'invalid']]
+ setlocal key=blah
+ setlocal key=
+ call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 18: Setting string option"
+ let oldval = &tags
+ let g:options=[['tags', oldval, 'tagpath', 'global']]
+ set tags=tagpath
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 1l: Resetting string option"
+ let g:options=[['tags', 'tagpath', oldval, 'global']]
+ set tags&
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " Cleanup
+ au! OptionSet
+ for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp']
+ exe printf(":set %s&vi", opt)
+ endfor
+ call test_override('starting', 0)
+ delfunc! AutoCommandOptionSet
+endfunc
+
+func Test_OptionSet_diffmode()
+ throw 'skipped: Nvim does not support test_override()'
+ call test_override('starting', 1)
+ " 18: Changing an option when enetering diff mode
+ new
+ au OptionSet diff :let &l:cul=v:option_new
+
+ call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
+ call assert_equal(0, &l:cul)
+ diffthis
+ call assert_equal(1, &l:cul)
+
+ vnew
+ call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
+ call assert_equal(0, &l:cul)
+ diffthis
+ call assert_equal(1, &l:cul)
+
+ diffoff
+ call assert_equal(0, &l:cul)
+ call assert_equal(1, getwinvar(2, '&l:cul'))
+ bw!
+
+ call assert_equal(1, &l:cul)
+ diffoff!
+ call assert_equal(0, &l:cul)
+ call assert_equal(0, getwinvar(1, '&l:cul'))
+ bw!
+
+ " Cleanup
+ au! OptionSet
+ call test_override('starting', 0)
+endfunc
+
+func Test_OptionSet_diffmode_close()
+ throw 'skipped: Nvim does not support test_override()'
+ call test_override('starting', 1)
+ " 19: Try to close the current window when entering diff mode
+ " should not segfault
+ new
+ au OptionSet diff close
+
+ call setline(1, ['buffer 1', 'line2', 'line3', 'line4'])
+ call assert_fails(':diffthis', 'E788')
+ call assert_equal(1, &diff)
+ vnew
+ call setline(1, ['buffer 2', 'line 2', 'line 3', 'line4'])
+ call assert_fails(':diffthis', 'E788')
+ call assert_equal(1, &diff)
+ bw!
+ call assert_fails(':diffoff!', 'E788')
+ bw!
+
+ " Cleanup
+ au! OptionSet
+ call test_override('starting', 0)
+ "delfunc! AutoCommandOptionSet
+endfunc
+
+" Test for Bufleave autocommand that deletes the buffer we are about to edit.
+func Test_BufleaveWithDelete()
+ new | edit Xfile1
+
+ augroup test_bufleavewithdelete
+ autocmd!
+ autocmd BufLeave Xfile1 bwipe Xfile2
+ augroup END
+
+ call assert_fails('edit Xfile2', 'E143:')
+ call assert_equal('Xfile1', bufname('%'))
+
+ autocmd! test_bufleavewithdelete BufLeave Xfile1
+ augroup! test_bufleavewithdelete
+
+ new
+ bwipe! Xfile1
+endfunc
+
+" Test for autocommand that changes the buffer list, when doing ":ball".
+func Test_Acmd_BufAll()
+ enew!
+ %bwipe!
+ call writefile(['Test file Xxx1'], 'Xxx1')
+ call writefile(['Test file Xxx2'], 'Xxx2')
+ call writefile(['Test file Xxx3'], 'Xxx3')
+
+ " Add three files to the buffer list
+ split Xxx1
+ close
+ split Xxx2
+ close
+ split Xxx3
+ close
+
+ " Wipe the buffer when the buffer is opened
+ au BufReadPost Xxx2 bwipe
+
+ call append(0, 'Test file Xxx4')
+ ball
+
+ call assert_equal(2, winnr('$'))
+ call assert_equal('Xxx1', bufname(winbufnr(winnr('$'))))
+ wincmd t
+
+ au! BufReadPost
+ %bwipe!
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('Xxx3')
+ enew! | only
+endfunc
+
+" Test for autocommand that changes current buffer on BufEnter event.
+" Check if modelines are interpreted for the correct buffer.
+func Test_Acmd_BufEnter()
+ %bwipe!
+ call writefile(['start of test file Xxx1',
+ \ "\<Tab>this is a test",
+ \ 'end of test file Xxx1'], 'Xxx1')
+ call writefile(['start of test file Xxx2',
+ \ 'vim: set noai :',
+ \ "\<Tab>this is a test",
+ \ 'end of test file Xxx2'], 'Xxx2')
+
+ au BufEnter Xxx2 brew
+ set ai modeline modelines=3
+ edit Xxx1
+ " edit Xxx2, autocmd will do :brew
+ edit Xxx2
+ exe "normal G?this is a\<CR>"
+ " Append text with autoindent to this file
+ normal othis should be auto-indented
+ call assert_equal("\<Tab>this should be auto-indented", getline('.'))
+ call assert_equal(3, line('.'))
+ " Remove autocmd and edit Xxx2 again
+ au! BufEnter Xxx2
+ buf! Xxx2
+ exe "normal G?this is a\<CR>"
+ " append text without autoindent to Xxx
+ normal othis should be in column 1
+ call assert_equal("this should be in column 1", getline('.'))
+ call assert_equal(4, line('.'))
+
+ %bwipe!
+ call delete('Xxx1')
+ call delete('Xxx2')
+ set ai&vim modeline&vim modelines&vim
+endfunc
+
+" Test for issue #57
+" do not move cursor on <c-o> when autoindent is set
+func Test_ai_CTRL_O()
+ enew!
+ set ai
+ let save_fo = &fo
+ set fo+=r
+ exe "normal o# abcdef\<Esc>2hi\<CR>\<C-O>d0\<Esc>"
+ exe "normal o# abcdef\<Esc>2hi\<C-O>d0\<Esc>"
+ call assert_equal(['# abc', 'def', 'def'], getline(2, 4))
+
+ set ai&vim
+ let &fo = save_fo
+ enew!
+endfunc
+
+" Test for autocommand that deletes the current buffer on BufLeave event.
+" Also test deleting the last buffer, should give a new, empty buffer.
+func Test_BufLeave_Wipe()
+ throw 'skipped: TODO: '
+ %bwipe!
+ let content = ['start of test file Xxx',
+ \ 'this is a test',
+ \ 'end of test file Xxx']
+ call writefile(content, 'Xxx1')
+ call writefile(content, 'Xxx2')
+
+ au BufLeave Xxx2 bwipe
+ edit Xxx1
+ split Xxx2
+ " delete buffer Xxx2, we should be back to Xxx1
+ bwipe
+ call assert_equal('Xxx1', bufname('%'))
+ call assert_equal(1, winnr('$'))
+
+ " Create an alternate buffer
+ %write! test.out
+ call assert_equal('test.out', bufname('#'))
+ " delete alternate buffer
+ bwipe test.out
+ call assert_equal('Xxx1', bufname('%'))
+ call assert_equal('', bufname('#'))
+
+ au BufLeave Xxx1 bwipe
+ " delete current buffer, get an empty one
+ bwipe!
+ call assert_equal(1, line('$'))
+ call assert_equal('', bufname('%'))
+ let g:bufinfo = getbufinfo()
+ call assert_equal(1, len(g:bufinfo))
+
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('test.out')
+ %bwipe
+ au! BufLeave
+
+ " check that bufinfo doesn't contain a pointer to freed memory
+ call test_garbagecollect_now()
+endfunc
+
+func Test_QuitPre()
+ edit Xfoo
+ let winid = win_getid(winnr())
+ split Xbar
+ au! QuitPre * let g:afile = expand('<afile>')
+ " Close the other window, <afile> should be correct.
+ exe win_id2win(winid) . 'q'
+ call assert_equal('Xfoo', g:afile)
+
+ unlet g:afile
+ bwipe Xfoo
+ bwipe Xbar
+endfunc
+
func Test_Cmdline()
au! CmdlineEnter : let g:entered = expand('<afile>')
au! CmdlineLeave : let g:left = expand('<afile>')
@@ -436,9 +813,355 @@ func Test_Cmdline()
au! CmdlineLeave / let g:left = expand('<afile>')
let g:entered = 0
let g:left = 0
- call feedkeys("/hello<CR>", 'xt')
+ new
+ call setline(1, 'hello')
+ call feedkeys("/hello\<CR>", 'xt')
call assert_equal('/', g:entered)
call assert_equal('/', g:left)
+ bwipe!
au! CmdlineEnter
au! CmdlineLeave
endfunc
+
+" Test for BufWritePre autocommand that deletes or unloads the buffer.
+func Test_BufWritePre()
+ %bwipe
+ au BufWritePre Xxx1 bunload
+ au BufWritePre Xxx2 bwipe
+
+ call writefile(['start of Xxx1', 'test', 'end of Xxx1'], 'Xxx1')
+ call writefile(['start of Xxx2', 'test', 'end of Xxx2'], 'Xxx2')
+
+ edit Xtest
+ e! Xxx2
+ bdel Xtest
+ e Xxx1
+ " write it, will unload it and give an error msg
+ call assert_fails('w', 'E203')
+ call assert_equal('Xxx2', bufname('%'))
+ edit Xtest
+ e! Xxx2
+ bwipe Xtest
+ " write it, will delete the buffer and give an error msg
+ call assert_fails('w', 'E203')
+ call assert_equal('Xxx1', bufname('%'))
+ au! BufWritePre
+ call delete('Xxx1')
+ call delete('Xxx2')
+endfunc
+
+" Test for BufUnload autocommand that unloads all the other buffers
+func Test_bufunload_all()
+ call writefile(['Test file Xxx1'], 'Xxx1')"
+ call writefile(['Test file Xxx2'], 'Xxx2')"
+
+ let content = [
+ \ "func UnloadAllBufs()",
+ \ " let i = 1",
+ \ " while i <= bufnr('$')",
+ \ " if i != bufnr('%') && bufloaded(i)",
+ \ " exe i . 'bunload'",
+ \ " endif",
+ \ " let i += 1",
+ \ " endwhile",
+ \ "endfunc",
+ \ "au BufUnload * call UnloadAllBufs()",
+ \ "au VimLeave * call writefile(['Test Finished'], 'Xout')",
+ \ "edit Xxx1",
+ \ "split Xxx2",
+ \ "q"]
+ call writefile(content, 'Xtest')
+
+ call delete('Xout')
+ call system(v:progpath. ' -u NORC -i NONE -N -S Xtest')
+ call assert_true(filereadable('Xout'))
+
+ call delete('Xxx1')
+ call delete('Xxx2')
+ call delete('Xtest')
+ call delete('Xout')
+endfunc
+
+" Some tests for buffer-local autocommands
+func Test_buflocal_autocmd()
+ let g:bname = ''
+ edit xx
+ au BufLeave <buffer> let g:bname = expand("%")
+ " here, autocommand for xx should trigger.
+ " but autocommand shall not apply to buffer named <buffer>.
+ edit somefile
+ call assert_equal('xx', g:bname)
+ let g:bname = ''
+ " here, autocommand shall be auto-deleted
+ bwipe xx
+ " autocmd should not trigger
+ edit xx
+ call assert_equal('', g:bname)
+ " autocmd should not trigger
+ edit somefile
+ call assert_equal('', g:bname)
+ enew
+ unlet g:bname
+endfunc
+
+" Test for "*Cmd" autocommands
+func Test_Cmd_Autocmds()
+ call writefile(['start of Xxx', "\tabc2", 'end of Xxx'], 'Xxx')
+
+ enew!
+ au BufReadCmd XtestA 0r Xxx|$del
+ edit XtestA " will read text of Xxd instead
+ call assert_equal('start of Xxx', getline(1))
+
+ au BufWriteCmd XtestA call append(line("$"), "write")
+ write " will append a line to the file
+ call assert_equal('write', getline('$'))
+ call assert_fails('read XtestA', 'E484') " should not read anything
+ call assert_equal('write', getline(4))
+
+ " now we have:
+ " 1 start of Xxx
+ " 2 abc2
+ " 3 end of Xxx
+ " 4 write
+
+ au FileReadCmd XtestB '[r Xxx
+ 2r XtestB " will read Xxx below line 2 instead
+ call assert_equal('start of Xxx', getline(3))
+
+ " now we have:
+ " 1 start of Xxx
+ " 2 abc2
+ " 3 start of Xxx
+ " 4 abc2
+ " 5 end of Xxx
+ " 6 end of Xxx
+ " 7 write
+
+ au FileWriteCmd XtestC '[,']copy $
+ normal 4GA1
+ 4,5w XtestC " will copy lines 4 and 5 to the end
+ call assert_equal("\tabc21", getline(8))
+ call assert_fails('r XtestC', 'E484') " should not read anything
+ call assert_equal("end of Xxx", getline(9))
+
+ " now we have:
+ " 1 start of Xxx
+ " 2 abc2
+ " 3 start of Xxx
+ " 4 abc21
+ " 5 end of Xxx
+ " 6 end of Xxx
+ " 7 write
+ " 8 abc21
+ " 9 end of Xxx
+
+ let g:lines = []
+ au FileAppendCmd XtestD call extend(g:lines, getline(line("'["), line("']")))
+ w >>XtestD " will add lines to 'lines'
+ call assert_equal(9, len(g:lines))
+ call assert_fails('$r XtestD', 'E484') " should not read anything
+ call assert_equal(9, line('$'))
+ call assert_equal('end of Xxx', getline('$'))
+
+ au BufReadCmd XtestE 0r Xxx|$del
+ sp XtestE " split window with test.out
+ call assert_equal('end of Xxx', getline(3))
+
+ let g:lines = []
+ exe "normal 2Goasdf\<Esc>\<C-W>\<C-W>"
+ au BufWriteCmd XtestE call extend(g:lines, getline(0, '$'))
+ wall " will write other window to 'lines'
+ call assert_equal(4, len(g:lines), g:lines)
+ call assert_equal("\tasdf", g:lines[2])
+
+ au! BufReadCmd
+ au! BufWriteCmd
+ au! FileReadCmd
+ au! FileWriteCmd
+ au! FileAppendCmd
+ %bwipe!
+ call delete('Xxx')
+ enew!
+endfunc
+
+func SetChangeMarks(start, end)
+ exe a:start. 'mark ['
+ exe a:end. 'mark ]'
+endfunc
+
+" Verify the effects of autocmds on '[ and ']
+func Test_change_mark_in_autocmds()
+ edit! Xtest
+ call feedkeys("ia\<CR>b\<CR>c\<CR>d\<C-g>u", 'xtn')
+
+ call SetChangeMarks(2, 3)
+ write
+ call assert_equal([1, 4], [line("'["), line("']")])
+
+ call SetChangeMarks(2, 3)
+ au BufWritePre * call assert_equal([1, 4], [line("'["), line("']")])
+ write
+ au! BufWritePre
+
+ if executable('cat')
+ write XtestFilter
+ write >> XtestFilter
+
+ call SetChangeMarks(2, 3)
+ " Marks are set to the entire range of the write
+ au FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")])
+ " '[ is adjusted to just before the line that will receive the filtered
+ " data
+ au FilterReadPre * call assert_equal([4, 4], [line("'["), line("']")])
+ " The filtered data is read into the buffer, and the source lines are
+ " still present, so the range is after the source lines
+ au FilterReadPost * call assert_equal([5, 12], [line("'["), line("']")])
+ %!cat XtestFilter
+ " After the filtered data is read, the original lines are deleted
+ call assert_equal([1, 8], [line("'["), line("']")])
+ au! FilterWritePre,FilterReadPre,FilterReadPost
+ undo
+
+ call SetChangeMarks(1, 4)
+ au FilterWritePre * call assert_equal([2, 3], [line("'["), line("']")])
+ au FilterReadPre * call assert_equal([3, 3], [line("'["), line("']")])
+ au FilterReadPost * call assert_equal([4, 11], [line("'["), line("']")])
+ 2,3!cat XtestFilter
+ call assert_equal([2, 9], [line("'["), line("']")])
+ au! FilterWritePre,FilterReadPre,FilterReadPost
+ undo
+
+ call delete('XtestFilter')
+ endif
+
+ call SetChangeMarks(1, 4)
+ au FileWritePre * call assert_equal([2, 3], [line("'["), line("']")])
+ 2,3write Xtest2
+ au! FileWritePre
+
+ call SetChangeMarks(2, 3)
+ au FileAppendPre * call assert_equal([1, 4], [line("'["), line("']")])
+ write >> Xtest2
+ au! FileAppendPre
+
+ call SetChangeMarks(1, 4)
+ au FileAppendPre * call assert_equal([2, 3], [line("'["), line("']")])
+ 2,3write >> Xtest2
+ au! FileAppendPre
+
+ call SetChangeMarks(1, 1)
+ au FileReadPre * call assert_equal([3, 1], [line("'["), line("']")])
+ au FileReadPost * call assert_equal([4, 11], [line("'["), line("']")])
+ 3read Xtest2
+ au! FileReadPre,FileReadPost
+ undo
+
+ call SetChangeMarks(4, 4)
+ " When the line is 0, it's adjusted to 1
+ au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
+ au FileReadPost * call assert_equal([1, 8], [line("'["), line("']")])
+ 0read Xtest2
+ au! FileReadPre,FileReadPost
+ undo
+
+ call SetChangeMarks(4, 4)
+ " When the line is 0, it's adjusted to 1
+ au FileReadPre * call assert_equal([1, 4], [line("'["), line("']")])
+ au FileReadPost * call assert_equal([2, 9], [line("'["), line("']")])
+ 1read Xtest2
+ au! FileReadPre,FileReadPost
+ undo
+
+ bwipe!
+ call delete('Xtest')
+ call delete('Xtest2')
+endfunc
+
+func Test_Filter_noshelltemp()
+ if !executable('cat')
+ return
+ endif
+
+ enew!
+ call setline(1, ['a', 'b', 'c', 'd'])
+
+ let shelltemp = &shelltemp
+ set shelltemp
+
+ let g:filter_au = 0
+ au FilterWritePre * let g:filter_au += 1
+ au FilterReadPre * let g:filter_au += 1
+ au FilterReadPost * let g:filter_au += 1
+ %!cat
+ call assert_equal(3, g:filter_au)
+
+ if has('filterpipe')
+ set noshelltemp
+
+ let g:filter_au = 0
+ au FilterWritePre * let g:filter_au += 1
+ au FilterReadPre * let g:filter_au += 1
+ au FilterReadPost * let g:filter_au += 1
+ %!cat
+ call assert_equal(0, g:filter_au)
+ endif
+
+ au! FilterWritePre,FilterReadPre,FilterReadPost
+ let &shelltemp = shelltemp
+ bwipe!
+endfunc
+
+func Test_TextYankPost()
+ enew!
+ call setline(1, ['foo'])
+
+ let g:event = []
+ au TextYankPost * let g:event = copy(v:event)
+
+ call assert_equal({}, v:event)
+ call assert_fails('let v:event = {}', 'E46:')
+ call assert_fails('let v:event.mykey = 0', 'E742:')
+
+ norm "ayiw
+ call assert_equal(
+ \{'regcontents': ['foo'], 'regname': 'a', 'operator': 'y', 'regtype': 'v'},
+ \g:event)
+ norm y_
+ call assert_equal(
+ \{'regcontents': ['foo'], 'regname': '', 'operator': 'y', 'regtype': 'V'},
+ \g:event)
+ call feedkeys("\<C-V>y", 'x')
+ call assert_equal(
+ \{'regcontents': ['f'], 'regname': '', 'operator': 'y', 'regtype': "\x161"},
+ \g:event)
+ norm "xciwbar
+ call assert_equal(
+ \{'regcontents': ['foo'], 'regname': 'x', 'operator': 'c', 'regtype': 'v'},
+ \g:event)
+ norm "bdiw
+ call assert_equal(
+ \{'regcontents': ['bar'], 'regname': 'b', 'operator': 'd', 'regtype': 'v'},
+ \g:event)
+
+ call assert_equal({}, v:event)
+
+ au! TextYankPost
+ unlet g:event
+ bwipe!
+endfunc
+
+func Test_nocatch_wipe_all_buffers()
+ " Real nasty autocommand: wipe all buffers on any event.
+ au * * bwipe *
+ call assert_fails('next x', 'E93')
+ bwipe
+ au!
+endfunc
+
+func Test_nocatch_wipe_dummy_buffer()
+ " Nasty autocommand: wipe buffer on any event.
+ au * x bwipe
+ call assert_fails('lv½ /x', 'E480')
+ au!
+endfunc
diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim
index 1c9350c416..a592cd7b11 100644
--- a/src/nvim/testdir/test_bufwintabinfo.vim
+++ b/src/nvim/testdir/test_bufwintabinfo.vim
@@ -1,7 +1,6 @@
" Tests for the getbufinfo(), getwininfo() and gettabinfo() functions
function Test_getbufwintabinfo()
- 1,$bwipeout
edit Xtestfile1
edit Xtestfile2
let buflist = getbufinfo()
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 0d2dad80ce..19b0624c1f 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -1,6 +1,5 @@
" Tests for editing the command line.
-set belloff=all
func Test_complete_tab()
call writefile(['testfile'], 'Xtestfile')
diff --git a/src/nvim/testdir/test_command_count.vim b/src/nvim/testdir/test_command_count.vim
index e438a8b077..2d793ed88f 100644
--- a/src/nvim/testdir/test_command_count.vim
+++ b/src/nvim/testdir/test_command_count.vim
@@ -1,6 +1,7 @@
" Test for user command counts.
func Test_command_count_0()
+ let bufnr = bufnr('%')
set hidden
set noswapfile
@@ -15,17 +16,17 @@ func Test_command_count_0()
command! -range=% -addr=buffers RangeBuffersAll :let lines = [<line1>, <line2>]
.,$RangeLoadedBuffers
- call assert_equal([1, 1], lines)
+ call assert_equal([bufnr, bufnr], lines)
%RangeLoadedBuffers
- call assert_equal([1, 1], lines)
+ call assert_equal([bufnr, bufnr], lines)
RangeLoadedBuffersAll
- call assert_equal([1, 1], lines)
+ call assert_equal([bufnr, bufnr], lines)
.,$RangeBuffers
- call assert_equal([1, lastbuf], lines)
+ call assert_equal([bufnr, lastbuf], lines)
%RangeBuffers
- call assert_equal([1, lastbuf], lines)
+ call assert_equal([bufnr, lastbuf], lines)
RangeBuffersAll
- call assert_equal([1, lastbuf], lines)
+ call assert_equal([bufnr, lastbuf], lines)
delcommand RangeLoadedBuffers
delcommand RangeLoadedBuffersAll
@@ -138,6 +139,7 @@ func Test_command_count_2()
endfunc
func Test_command_count_3()
+ let bufnr = bufnr('%')
se nohidden
e aaa
let buf_aaa = bufnr('%')
@@ -145,7 +147,7 @@ func Test_command_count_3()
let buf_bbb = bufnr('%')
e ccc
let buf_ccc = bufnr('%')
- buf 1
+ exe bufnr . 'buf'
call assert_equal([1, 1, 1], [buflisted(buf_aaa), buflisted(buf_bbb), buflisted(buf_ccc)])
exe buf_bbb . "," . buf_ccc . "bdelete"
call assert_equal([1, 0, 0], [buflisted(buf_aaa), buflisted(buf_bbb), buflisted(buf_ccc)])
@@ -155,7 +157,7 @@ endfunc
func Test_command_count_4()
%argd
- let bufnr = bufnr('$') + 1
+ let bufnr = bufnr('$')
arga aa bb cc dd ee ff
3argu
let args = []
@@ -171,6 +173,8 @@ func Test_command_count_4()
only!
exe bufnr . 'buf'
+ bnext
+ let bufnr = bufnr('%')
let buffers = []
.,$-bufdo call add(buffers, bufnr('%'))
call assert_equal([bufnr, bufnr + 1, bufnr + 2, bufnr + 3, bufnr + 4], buffers)
diff --git a/src/nvim/testdir/test_curswant.vim b/src/nvim/testdir/test_curswant.vim
new file mode 100644
index 0000000000..e54cd4b280
--- /dev/null
+++ b/src/nvim/testdir/test_curswant.vim
@@ -0,0 +1,23 @@
+" Tests for curswant not changing when setting an option
+
+func Test_curswant()
+ new
+ call append(0, ['1234567890', '12345'])
+
+ normal! ggf8j
+ call assert_equal(7, winsaveview().curswant)
+ let &tabstop=&tabstop
+ call assert_equal(4, winsaveview().curswant)
+
+ normal! ggf8j
+ call assert_equal(7, winsaveview().curswant)
+ let &timeoutlen=&timeoutlen
+ call assert_equal(7, winsaveview().curswant)
+
+ normal! ggf8j
+ call assert_equal(7, winsaveview().curswant)
+ let &ttimeoutlen=&ttimeoutlen
+ call assert_equal(7, winsaveview().curswant)
+
+ enew!
+endfunc
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 088ec5ccf6..d95b29759e 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -1,5 +1,4 @@
" Tests for diff mode
-set belloff=all
func Test_diff_fold_sync()
enew!
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
index 30dc9a4683..6290680305 100644
--- a/src/nvim/testdir/test_digraph.vim
+++ b/src/nvim/testdir/test_digraph.vim
@@ -3,7 +3,6 @@
if !has("digraphs") || !has("multi_byte")
finish
endif
-set belloff=all
func! Put_Dig(chars)
exe "norm! o\<c-k>".a:chars
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
new file mode 100644
index 0000000000..0c54becde8
--- /dev/null
+++ b/src/nvim/testdir/test_edit.vim
@@ -0,0 +1,1310 @@
+" Test for edit functions
+"
+if exists("+t_kD")
+ let &t_kD="[3;*~"
+endif
+
+" Needed for testing basic rightleft: Test_edit_rightleft
+source view_util.vim
+
+" Needs to come first until the bug in getchar() is
+" fixed: https://groups.google.com/d/msg/vim_dev/fXL9yme4H4c/bOR-U6_bAQAJ
+func! Test_edit_00b()
+ new
+ call setline(1, ['abc '])
+ inoreabbr <buffer> h here some more
+ call cursor(1, 4)
+ " <c-l> expands the abbreviation and ends insertmode
+ call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ call assert_equal(['abc here some more '], getline(1,'$'))
+ iunabbr <buffer> h
+ bw!
+endfunc
+
+func! Test_edit_01()
+ " set for Travis CI?
+ " set nocp noesckeys
+ new
+ " 1) empty buffer
+ call assert_equal([''], getline(1,'$'))
+ " 2) delete in an empty line
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
+ " 3) delete one character
+ call setline(1, 'a')
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
+ " 4) delete a multibyte character
+ if has("multi_byte")
+ call setline(1, "\u0401")
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
+ endif
+ " 5.1) delete linebreak with 'bs' option containing eol
+ let _bs=&bs
+ set bs=eol
+ call setline(1, ["abc def", "ghi jkl"])
+ call cursor(1, 1)
+ call feedkeys("A\<del>\<esc>", 'tnix')
+ call assert_equal(['abc defghi jkl'], getline(1, 2))
+ %d
+ " 5.2) delete linebreak with backspace option w/out eol
+ set bs=
+ call setline(1, ["abc def", "ghi jkl"])
+ call cursor(1, 1)
+ call feedkeys("A\<del>\<esc>", 'tnix')
+ call assert_equal(["abc def", "ghi jkl"], getline(1, 2))
+ let &bs=_bs
+ bw!
+endfunc
+
+func! Test_edit_02()
+ " Change cursor position in InsertCharPre command
+ new
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ fu! DoIt(...)
+ call cursor(1, 4)
+ if len(a:000)
+ let v:char=a:1
+ endif
+ endfu
+ au InsertCharPre <buffer> :call DoIt('y')
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['abcy'], getline(1, '$'))
+ " Setting <Enter> in InsertCharPre
+ au! InsertCharPre <buffer> :call DoIt("\n")
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['abc', ''], getline(1, '$'))
+ %d
+ au! InsertCharPre
+ " Change cursor position in InsertEnter command
+ " 1) when setting v:char, keeps changed cursor position
+ au! InsertEnter <buffer> :call DoIt('y')
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['abxc'], getline(1, '$'))
+ " 2) when not setting v:char, restores changed cursor position
+ au! InsertEnter <buffer> :call DoIt()
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_equal(['xabc'], getline(1, '$'))
+ au! InsertEnter
+ delfu DoIt
+ bw!
+endfunc
+
+func! Test_edit_03()
+ " Change cursor after <c-o> command to end of line
+ new
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("i\<c-o>$y\<esc>", 'tnix')
+ call assert_equal(['abcy'], getline(1, '$'))
+ %d
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("i\<c-o>80|y\<esc>", 'tnix')
+ call assert_equal(['abcy'], getline(1, '$'))
+ %d
+ call setline(1, 'abc')
+ call feedkeys("Ad\<c-o>:s/$/efg/\<cr>hij", 'tnix')
+ call assert_equal(['hijabcdefg'], getline(1, '$'))
+ bw!
+endfunc
+
+func! Test_edit_04()
+ " test for :stopinsert
+ new
+ call setline(1, 'abc')
+ call cursor(1, 1)
+ call feedkeys("i\<c-o>:stopinsert\<cr>$", 'tnix')
+ call feedkeys("aX\<esc>", 'tnix')
+ call assert_equal(['abcX'], getline(1, '$'))
+ %d
+ bw!
+endfunc
+
+func! Test_edit_05()
+ " test for folds being opened
+ new
+ call setline(1, ['abcX', 'abcX', 'zzzZ'])
+ call cursor(1, 1)
+ set foldmethod=manual foldopen+=insert
+ " create fold for those two lines
+ norm! Vjzf
+ call feedkeys("$ay\<esc>", 'tnix')
+ call assert_equal(['abcXy', 'abcX', 'zzzZ'], getline(1, '$'))
+ %d
+ call setline(1, ['abcX', 'abcX', 'zzzZ'])
+ call cursor(1, 1)
+ set foldmethod=manual foldopen-=insert
+ " create fold for those two lines
+ norm! Vjzf
+ call feedkeys("$ay\<esc>", 'tnix')
+ call assert_equal(['abcXy', 'abcX', 'zzzZ'], getline(1, '$'))
+ %d
+ bw!
+endfunc
+
+func! Test_edit_06()
+ " Test in diff mode
+ if !has("diff") || !executable("diff")
+ return
+ endif
+ new
+ call setline(1, ['abc', 'xxx', 'yyy'])
+ vnew
+ call setline(1, ['abc', 'zzz', 'xxx', 'yyy'])
+ wincmd p
+ diffthis
+ wincmd p
+ diffthis
+ wincmd p
+ call cursor(2, 1)
+ norm! zt
+ call feedkeys("Ozzz\<esc>", 'tnix')
+ call assert_equal(['abc', 'zzz', 'xxx', 'yyy'], getline(1,'$'))
+ bw!
+ bw!
+endfunc
+
+func! Test_edit_07()
+ " 1) Test with completion <c-l> when popupmenu is visible
+ new
+ call setline(1, 'J')
+
+ func! ListMonths()
+ call complete(col('.')-1, ['January', 'February', 'March',
+ \ 'April', 'May', 'June', 'July', 'August', 'September',
+ \ 'October', 'November', 'December'])
+ return ''
+ endfunc
+ inoremap <buffer> <F5> <C-R>=ListMonths()<CR>
+
+ call feedkeys("A\<f5>\<c-p>". repeat("\<down>", 6)."\<c-l>\<down>\<c-l>\<cr>", 'tx')
+ call assert_equal(['July'], getline(1,'$'))
+ " 1) Test completion when InsertCharPre kicks in
+ %d
+ call setline(1, 'J')
+ fu! DoIt()
+ if v:char=='u'
+ let v:char='an'
+ endif
+ endfu
+ au InsertCharPre <buffer> :call DoIt()
+ call feedkeys("A\<f5>\<c-p>u\<cr>\<c-l>\<cr>", 'tx')
+ call assert_equal(["Jan\<c-l>",''], getline(1,'$'))
+ %d
+ call setline(1, 'J')
+ call feedkeys("A\<f5>\<c-p>u\<down>\<c-l>\<cr>", 'tx')
+ call assert_equal(["January"], getline(1,'$'))
+
+ delfu ListMonths
+ delfu DoIt
+ iunmap <buffer> <f5>
+ bw!
+endfunc
+
+func! Test_edit_08()
+ throw 'skipped: moved to test/functional/legacy/edit_spec.lua'
+ " reset insertmode from i_ctrl-r_=
+ new
+ call setline(1, ['abc'])
+ call cursor(1, 4)
+ call feedkeys(":set im\<cr>ZZZ\<c-r>=setbufvar(1,'&im', 0)\<cr>",'tnix')
+ call assert_equal(['abZZZc'], getline(1,'$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call assert_false(0, '&im')
+ bw!
+endfunc
+
+func! Test_edit_09()
+ " test i_CTRL-\ combinations
+ new
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 1)
+ " 1) CTRL-\ CTLR-N
+ call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ call assert_equal(['ABC', 'def', 'ghi'], getline(1,'$'))
+ call setline(1, ['ABC', 'def', 'ghi'])
+ " 2) CTRL-\ CTLR-G
+ call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<c-l>", 'txin')
+ call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
+ call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
+ set noinsertmode
+ " 3) CTRL-\ CTRL-O
+ call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
+ call cursor(1, 1)
+ call feedkeys("A\<c-o>ix", 'txin')
+ call assert_equal(['ABxC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ call feedkeys("A\<c-\>\<c-o>ix", 'txin')
+ call assert_equal(['ABxCx', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ " 4) CTRL-\ a (should be inserted literally, not special after <c-\>
+ call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
+ call cursor(1, 1)
+ call feedkeys("A\<c-\>a", 'txin')
+ call assert_equal(["ABC\<c-\>a", 'ZZZ', 'def', 'ghi'], getline(1, '$'))
+ bw!
+endfunc
+
+func! Test_edit_10()
+ " Test for starting selectmode
+ new
+ set selectmode=key keymodel=startsel
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 4)
+ call feedkeys("A\<s-home>start\<esc>", 'txin')
+ call assert_equal(['startdef', 'ghi'], getline(1, '$'))
+ set selectmode= keymodel=
+ bw!
+endfunc
+
+func! Test_edit_11()
+ " Test that indenting kicks in
+ new
+ set cindent
+ call setline(1, ['{', '', ''])
+ call cursor(2, 1)
+ call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("i/* comment */", 'tnix')
+ call assert_equal(['{', "\<tab>int c;", "/* comment */"], getline(1, '$'))
+ " added changed cindentkeys slightly
+ set cindent cinkeys+=*/
+ call setline(1, ['{', '', ''])
+ call cursor(2, 1)
+ call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("i/* comment */", 'tnix')
+ call assert_equal(['{', "\<tab>int c;", "\<tab>/* comment */"], getline(1, '$'))
+ set cindent cinkeys+==end
+ call feedkeys("oend\<cr>\<esc>", 'tnix')
+ call assert_equal(['{', "\<tab>int c;", "\<tab>/* comment */", "\tend", ''], getline(1, '$'))
+ set cinkeys-==end
+ %d
+ " Use indentexpr instead of cindenting
+ func! Do_Indent()
+ if v:lnum == 3
+ return 3*shiftwidth()
+ else
+ return 2*shiftwidth()
+ endif
+ endfunc
+ setl indentexpr=Do_Indent() indentkeys+=*/
+ call setline(1, ['{', '', ''])
+ call cursor(2, 1)
+ call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("i/* comment */", 'tnix')
+ call assert_equal(['{', "\<tab>\<tab>int c;", "\<tab>\<tab>\<tab>/* comment */"], getline(1, '$'))
+ set cinkeys&vim indentkeys&vim
+ set nocindent indentexpr=
+ delfu Do_Indent
+ bw!
+endfunc
+
+func! Test_edit_12()
+ " Test changing indent in replace mode
+ new
+ call setline(1, ["\tabc", "\tdef"])
+ call cursor(2, 4)
+ call feedkeys("R^\<c-d>", 'tnix')
+ call assert_equal(["\tabc", "def"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ %d
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R^\<c-d>", 'tnix')
+ call assert_equal(["\tabc", "def"], getline(1, '$'))
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ %d
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ bw!
+ 10vnew
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ %d
+ set sw=4
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ %d
+ call setline(1, ["\tabc", "\t\tdef"])
+ call cursor(2, 2)
+ call feedkeys("R\<c-t>\<c-t>", 'tnix')
+ call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
+ call assert_equal([0, 2, 2, 0], getpos('.'))
+ set et
+ set sw& et&
+ %d
+ call setline(1, ["\t/*"])
+ set formatoptions=croql
+ call cursor(1, 3)
+ call feedkeys("A\<cr>\<cr>/", 'tnix')
+ call assert_equal(["\t/*", " *", " */"], getline(1, '$'))
+ set formatoptions&
+ bw!
+endfunc
+
+func! Test_edit_13()
+ " Test smartindenting
+ if exists("+smartindent")
+ new
+ set smartindent autoindent
+ call setline(1, ["\tabc"])
+ call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
+ call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
+ set smartindent& autoindent&
+ bw!
+ endif
+endfunc
+
+func! Test_edit_CR()
+ " Test for <CR> in insert mode
+ " basically only in quickfix mode ist tested, the rest
+ " has been taken care of by other tests
+ if !has("quickfix")
+ return
+ endif
+ botright new
+ call writefile(range(1, 10), 'Xqflist.txt')
+ call setqflist([{'filename': 'Xqflist.txt', 'lnum': 2}])
+ copen
+ set modifiable
+ call feedkeys("A\<cr>", 'tnix')
+ call assert_equal('Xqflist.txt', bufname(''))
+ call assert_equal(2, line('.'))
+ cclose
+ botright new
+ call setloclist(0, [{'filename': 'Xqflist.txt', 'lnum': 10}])
+ lopen
+ set modifiable
+ call feedkeys("A\<cr>", 'tnix')
+ call assert_equal('Xqflist.txt', bufname(''))
+ call assert_equal(10, line('.'))
+ call feedkeys("A\<Enter>", 'tnix')
+ call feedkeys("A\<kEnter>", 'tnix')
+ call feedkeys("A\n", 'tnix')
+ call feedkeys("A\r", 'tnix')
+ call assert_equal(map(range(1, 10), 'string(v:val)') + ['', '', '', ''], getline(1, '$'))
+ bw!
+ lclose
+ call delete('Xqflist.txt')
+endfunc
+
+func! Test_edit_CTRL_()
+ " disabled for Windows builds, why?
+ if !has("multi_byte") || !has("rightleft") || has("win32")
+ return
+ endif
+ let _encoding=&encoding
+ set encoding=utf-8
+ " Test for CTRL-_
+ new
+ call setline(1, ['abc'])
+ call cursor(1, 1)
+ call feedkeys("i\<c-_>xyz\<esc>", 'tnix')
+ call assert_equal(["\<C-_>xyzabc"], getline(1, '$'))
+ call assert_false(&revins)
+ set ari
+ call setline(1, ['abc'])
+ call cursor(1, 1)
+ call feedkeys("i\<c-_>xyz\<esc>", 'tnix')
+ call assert_equal(["æèñabc"], getline(1, '$'))
+ call assert_true(&revins)
+ call setline(1, ['abc'])
+ call cursor(1, 1)
+ call feedkeys("i\<c-_>xyz\<esc>", 'tnix')
+ call assert_equal(["xyzabc"], getline(1, '$'))
+ call assert_false(&revins)
+ set noari
+ let &encoding=_encoding
+ bw!
+endfunc
+
+" needs to come first, to have the @. register empty
+func! Test_edit_00a_CTRL_A()
+ " Test pressing CTRL-A
+ new
+ call setline(1, repeat([''], 5))
+ call cursor(1, 1)
+ try
+ call feedkeys("A\<NUL>", 'tnix')
+ catch /^Vim\%((\a\+)\)\=:E29/
+ call assert_true(1, 'E29 error caught')
+ endtry
+ call cursor(1, 1)
+ call feedkeys("Afoobar \<esc>", 'tnix')
+ call cursor(2, 1)
+ call feedkeys("A\<c-a>more\<esc>", 'tnix')
+ call cursor(3, 1)
+ call feedkeys("A\<NUL>and more\<esc>", 'tnix')
+ call assert_equal(['foobar ', 'foobar more', 'foobar morend more', '', ''], getline(1, '$'))
+ bw!
+endfunc
+
+func! Test_edit_CTRL_EY()
+ " Ctrl-E/ Ctrl-Y in insert mode completion to scroll
+ 10new
+ call setline(1, range(1, 100))
+ call cursor(30, 1)
+ norm! z.
+ call feedkeys("A\<c-x>\<c-e>\<c-e>\<c-e>\<c-e>\<c-e>", 'tnix')
+ call assert_equal(30, winsaveview()['topline'])
+ call assert_equal([0, 30, 2, 0], getpos('.'))
+ call feedkeys("A\<c-x>\<c-e>\<c-e>\<c-e>\<c-e>\<c-e>", 'tnix')
+ call feedkeys("A\<c-x>".repeat("\<c-y>", 10), 'tnix')
+ call assert_equal(21, winsaveview()['topline'])
+ call assert_equal([0, 30, 2, 0], getpos('.'))
+ bw!
+endfunc
+
+func! Test_edit_CTRL_G()
+ new
+ call setline(1, ['foobar', 'foobar', 'foobar'])
+ call cursor(2, 4)
+ call feedkeys("ioooooooo\<c-g>k\<c-r>.\<esc>", 'tnix')
+ call assert_equal(['foooooooooobar', 'foooooooooobar', 'foobar'], getline(1, '$'))
+ call assert_equal([0, 1, 11, 0], getpos('.'))
+ call feedkeys("i\<c-g>k\<esc>", 'tnix')
+ call assert_equal([0, 1, 10, 0], getpos('.'))
+ call cursor(2, 4)
+ call feedkeys("i\<c-g>jzzzz\<esc>", 'tnix')
+ call assert_equal(['foooooooooobar', 'foooooooooobar', 'foozzzzbar'], getline(1, '$'))
+ call assert_equal([0, 3, 7, 0], getpos('.'))
+ call feedkeys("i\<c-g>j\<esc>", 'tnix')
+ call assert_equal([0, 3, 6, 0], getpos('.'))
+ bw!
+endfunc
+
+func! Test_edit_CTRL_I()
+ " Tab in completion mode
+ let path=expand("%:p:h")
+ new
+ call setline(1, [path."/", ''])
+ call feedkeys("Arunt\<c-x>\<c-f>\<tab>\<cr>\<esc>", 'tnix')
+ call assert_match('runtest\.vim', getline(1))
+ %d
+ call writefile(['one', 'two', 'three'], 'Xinclude.txt')
+ let include='#include Xinclude.txt'
+ call setline(1, [include, ''])
+ call cursor(2, 1)
+ call feedkeys("A\<c-x>\<tab>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, 'one', ''], getline(1, '$'))
+ call feedkeys("2ggC\<c-x>\<tab>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, 'two', ''], getline(1, '$'))
+ call feedkeys("2ggC\<c-x>\<tab>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, 'three', ''], getline(1, '$'))
+ call feedkeys("2ggC\<c-x>\<tab>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal([include, '', ''], getline(1, '$'))
+ call delete("Xinclude.txt")
+ bw!
+endfunc
+
+func! Test_edit_CTRL_K()
+ " Test pressing CTRL-K (basically only dictionary completion and digraphs
+ " the rest is already covered
+ call writefile(['A', 'AA', 'AAA', 'AAAA'], 'Xdictionary.txt')
+ set dictionary=Xdictionary.txt
+ new
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AA', ''], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AAA'], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AAAA'], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['A'], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AA'], getline(1, '$'))
+
+ " press an unexecpted key after dictionary completion
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<c-]>\<cr>\<esc>", 'tnix')
+ call assert_equal(['AA', ''], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<c-s>\<cr>\<esc>", 'tnix')
+ call assert_equal(["AA\<c-s>", ''], getline(1, '$'))
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-k>\<c-f>\<cr>\<esc>", 'tnix')
+ call assert_equal(["AA\<c-f>", ''], getline(1, '$'))
+
+ set dictionary=
+ %d
+ call setline(1, 'A')
+ call cursor(1, 1)
+ let v:testing = 1
+ try
+ call feedkeys("A\<c-x>\<c-k>\<esc>", 'tnix')
+ catch
+ " error sleeps 2 seconds, when v:testing is not set
+ let v:testing = 0
+ endtry
+ call delete('Xdictionary.txt')
+
+ if has("multi_byte") && !has("nvim")
+ call test_override("char_avail", 1)
+ set showcmd
+ %d
+ call feedkeys("A\<c-k>a:\<esc>", 'tnix')
+ call assert_equal(['ä'], getline(1, '$'))
+ call test_override("char_avail", 0)
+ set noshowcmd
+ endif
+ bw!
+endfunc
+
+func! Test_edit_CTRL_L()
+ " Test Ctrl-X Ctrl-L (line completion)
+ new
+ set complete=.
+ call setline(1, ['one', 'two', 'three', '', '', '', ''])
+ call cursor(4, 1)
+ call feedkeys("A\<c-x>\<c-l>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'two', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-p>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'two', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-p>\<c-p>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-p>\<c-p>\<c-p>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ set complete=
+ call cursor(5, 1)
+ call feedkeys("A\<c-x>\<c-l>\<c-p>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 'three', "\<c-l>\<c-p>\<c-n>", '', ''], getline(1, '$'))
+ set complete&
+ %d
+ if has("conceal") && has("syntax") && !has("nvim")
+ call setline(1, ['foo', 'bar', 'foobar'])
+ call test_override("char_avail", 1)
+ set conceallevel=2 concealcursor=n
+ syn on
+ syn match ErrorMsg "^bar"
+ call matchadd("Conceal", 'oo', 10, -1, {'conceal': 'X'})
+ func! DoIt()
+ let g:change=1
+ endfunc
+ au! TextChangedI <buffer> :call DoIt()
+
+ call cursor(2, 1)
+ call assert_false(exists("g:change"))
+ call feedkeys("A \<esc>", 'tnix')
+ call assert_equal(['foo', 'bar ', 'foobar'], getline(1, '$'))
+ call assert_equal(1, g:change)
+
+ call test_override("char_avail", 0)
+ call clearmatches()
+ syn off
+ au! TextChangedI
+ delfu DoIt
+ unlet! g:change
+ endif
+ bw!
+endfunc
+
+func! Test_edit_CTRL_N()
+ " Check keyword completion
+ new
+ set complete=.
+ call setline(1, ['INFER', 'loWER', '', '', ])
+ call cursor(3, 1)
+ call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix")
+ call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'))
+ %d
+ call setline(1, ['INFER', 'loWER', '', '', ])
+ call cursor(3, 1)
+ set ignorecase infercase
+ call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
+ call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'))
+
+ set noignorecase noinfercase complete&
+ bw!
+endfunc
+
+func! Test_edit_CTRL_O()
+ " Check for CTRL-O in insert mode
+ new
+ inoreabbr <buffer> h here some more
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ " Ctrl-O after an abbreviation
+ exe "norm A h\<c-o>:set nu\<cr> text"
+ call assert_equal(['abc here some more text', 'def'], getline(1, '$'))
+ call assert_true(&nu)
+ set nonu
+ iunabbr <buffer> h
+ " Ctrl-O at end of line with 've'=onemore
+ call cursor(1, 1)
+ call feedkeys("A\<c-o>:let g:a=getpos('.')\<cr>\<esc>", 'tnix')
+ call assert_equal([0, 1, 23, 0], g:a)
+ call cursor(1, 1)
+ set ve=onemore
+ call feedkeys("A\<c-o>:let g:a=getpos('.')\<cr>\<esc>", 'tnix')
+ call assert_equal([0, 1, 24, 0], g:a)
+ set ve=
+ unlet! g:a
+ bw!
+endfunc
+
+func! Test_edit_CTRL_R()
+ throw 'skipped: Nvim does not support test_override()'
+ " Insert Register
+ new
+ call test_override("ALL", 1)
+ set showcmd
+ call feedkeys("AFOOBAR eins zwei\<esc>", 'tnix')
+ call feedkeys("O\<c-r>.", 'tnix')
+ call feedkeys("O\<c-r>=10*500\<cr>\<esc>", 'tnix')
+ call feedkeys("O\<c-r>=getreg('=', 1)\<cr>\<esc>", 'tnix')
+ call assert_equal(["getreg('=', 1)", '5000', "FOOBAR eins zwei", "FOOBAR eins zwei"], getline(1, '$'))
+ call test_override("ALL", 0)
+ set noshowcmd
+ bw!
+endfunc
+
+func! Test_edit_CTRL_S()
+ " Test pressing CTRL-S (basically only spellfile completion)
+ " the rest is already covered
+ new
+ if !has("spell")
+ call setline(1, 'vim')
+ call feedkeys("A\<c-x>ss\<cr>\<esc>", 'tnix')
+ call assert_equal(['vims', ''], getline(1, '$'))
+ bw!
+ return
+ endif
+ call setline(1, 'vim')
+ " spell option not yet set
+ try
+ call feedkeys("A\<c-x>\<c-s>\<cr>\<esc>", 'tnix')
+ catch /^Vim\%((\a\+)\)\=:E756/
+ call assert_true(1, 'error caught')
+ endtry
+ call assert_equal(['vim', ''], getline(1, '$'))
+ %d
+ setl spell spelllang=en
+ call setline(1, 'vim')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<cr>\<esc>", 'tnix')
+ call assert_equal(['Vim', ''], getline(1, '$'))
+ %d
+ call setline(1, 'vim')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<down>\<cr>\<esc>", 'tnix')
+ call assert_equal(['Aim'], getline(1, '$'))
+ %d
+ call setline(1, 'vim')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<c-p>\<cr>\<esc>", 'tnix')
+ call assert_equal(['vim', ''], getline(1, '$'))
+ %d
+ " empty buffer
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-s>\<c-p>\<cr>\<esc>", 'tnix')
+ call assert_equal(['', ''], getline(1, '$'))
+ setl nospell
+ bw!
+endfunc
+
+func! Test_edit_CTRL_T()
+ " Check for CTRL-T and CTRL-X CTRL-T in insert mode
+ " 1) increase indent
+ new
+ call setline(1, "abc")
+ call cursor(1, 1)
+ call feedkeys("A\<c-t>xyz", 'tnix')
+ call assert_equal(["\<tab>abcxyz"], getline(1, '$'))
+ " 2) also when paste option is set
+ set paste
+ call setline(1, "abc")
+ call cursor(1, 1)
+ call feedkeys("A\<c-t>xyz", 'tnix')
+ call assert_equal(["\<tab>abcxyz"], getline(1, '$'))
+ set nopaste
+ " CTRL-X CTRL-T (thesaurus complete)
+ call writefile(['angry furious mad enraged'], 'Xthesaurus')
+ set thesaurus=Xthesaurus
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['angry', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['furious', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['enraged', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<c-n>\<c-n>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ " Using <c-p> <c-n> when 'complete' is empty
+ set complete=
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['angry', ''], getline(1, '$'))
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<c-p>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ set complete&
+
+ set thesaurus=
+ %d
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ let v:testing = 1
+ try
+ call feedkeys("A\<c-x>\<c-t>\<esc>", 'tnix')
+ catch
+ " error sleeps 2 seconds, when v:testing is not set
+ let v:testing = 0
+ endtry
+ call assert_equal(['mad'], getline(1, '$'))
+ call delete('Xthesaurus')
+ bw!
+endfunc
+
+func! Test_edit_CTRL_U()
+ " Test 'completefunc'
+ new
+ " -1, -2 and -3 are special return values
+ let g:special=0
+ fun! CompleteMonths(findstart, base)
+ if a:findstart
+ " locate the start of the word
+ return g:special
+ else
+ " find months matching with "a:base"
+ let res = []
+ for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec")
+ if m =~ '^\c'.a:base
+ call add(res, {'word': m, 'abbr': m.' Month', 'icase': 0})
+ endif
+ endfor
+ return {'words': res, 'refresh': 'always'}
+ endif
+ endfun
+ set completefunc=CompleteMonths
+ call setline(1, ['', ''])
+ call cursor(1, 1)
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['X', '', ''], getline(1, '$'))
+ %d
+ let g:special=-1
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['XJan', ''], getline(1, '$'))
+ %d
+ let g:special=-2
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['X', ''], getline(1, '$'))
+ %d
+ let g:special=-3
+ call feedkeys("AX\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['X', ''], getline(1, '$'))
+ %d
+ let g:special=0
+ call feedkeys("AM\<c-x>\<c-u>\<cr>\<esc>", 'tnix')
+ call assert_equal(['Mar', ''], getline(1, '$'))
+ %d
+ call feedkeys("AM\<c-x>\<c-u>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['May', ''], getline(1, '$'))
+ %d
+ call feedkeys("AM\<c-x>\<c-u>\<c-n>\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['M', ''], getline(1, '$'))
+ delfu CompleteMonths
+ %d
+ try
+ call feedkeys("A\<c-x>\<c-u>", 'tnix')
+ call assert_fails(1, 'unknown completion function')
+ catch /^Vim\%((\a\+)\)\=:E117/
+ call assert_true(1, 'E117 error caught')
+ endtry
+ set completefunc=
+ bw!
+endfunc
+
+func! Test_edit_CTRL_Z()
+ " Ctrl-Z when insertmode is not set inserts it literally
+ new
+ call setline(1, 'abc')
+ call feedkeys("A\<c-z>\<esc>", 'tnix')
+ call assert_equal(["abc\<c-z>"], getline(1,'$'))
+ bw!
+ " TODO: How to Test Ctrl-Z in insert mode, e.g. suspend?
+endfunc
+
+func! Test_edit_DROP()
+ if !has("dnd")
+ return
+ endif
+ new
+ call setline(1, ['abc def ghi'])
+ call cursor(1, 1)
+ try
+ call feedkeys("i\<Drop>\<Esc>", 'tnix')
+ call assert_fails(1, 'Invalid register name')
+ catch /^Vim\%((\a\+)\)\=:E353/
+ call assert_true(1, 'error caught')
+ endtry
+ bw!
+endfunc
+
+func! Test_edit_CTRL_V()
+ throw 'skipped: Nvim does not support test_override()'
+ if has("ebcdic")
+ return
+ endif
+ new
+ call setline(1, ['abc'])
+ call cursor(2, 1)
+ " force some redraws
+ set showmode showcmd
+ "call test_override_char_avail(1)
+ call test_override('ALL', 1)
+ call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix')
+ call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$'))
+
+ if has("rightleft") && exists("+rl")
+ set rl
+ call setline(1, ['abc'])
+ call cursor(2, 1)
+ call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix')
+ call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$'))
+ set norl
+ endif
+
+ call test_override('ALL', 0)
+ set noshowmode showcmd
+ bw!
+endfunc
+
+func! Test_edit_F1()
+ " Pressing <f1>
+ new
+ call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ set noinsertmode
+ call assert_equal('help', &buftype)
+ bw
+ bw
+endfunc
+
+func! Test_edit_F21()
+ " Pressing <f21>
+ " sends a netbeans command
+ if has("netbeans_intg")
+ new
+ " I have no idea what this is supposed to do :)
+ call feedkeys("A\<F21>\<F1>\<esc>", 'tnix')
+ bw
+ endif
+endfunc
+
+func! Test_edit_HOME_END()
+ " Test Home/End Keys
+ new
+ set foldopen+=hor
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ call feedkeys("AX\<Home>Y\<esc>", 'tnix')
+ call cursor(2, 1)
+ call feedkeys("iZ\<End>Y\<esc>", 'tnix')
+ call assert_equal(['YabcX', 'ZdefY'], getline(1, '$'))
+
+ set foldopen-=hor
+ bw!
+endfunc
+
+func! Test_edit_INS()
+ " Test for Pressing <Insert>
+ new
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ call feedkeys("i\<Insert>ZYX>", 'tnix')
+ call assert_equal(['ZYX>', 'def'], getline(1, '$'))
+ call setline(1, ['abc', 'def'])
+ call cursor(1, 1)
+ call feedkeys("i\<Insert>Z\<Insert>YX>", 'tnix')
+ call assert_equal(['ZYX>bc', 'def'], getline(1, '$'))
+ bw!
+endfunc
+
+func! Test_edit_LEFT_RIGHT()
+ " Left, Shift-Left, Right, Shift-Right
+ new
+ call setline(1, ['abc def ghi', 'ABC DEF GHI', 'ZZZ YYY XXX'])
+ let _ww=&ww
+ set ww=
+ call cursor(2, 1)
+ call feedkeys("i\<left>\<esc>", 'tnix')
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ " Is this a bug, <s-left> does not respect whichwrap option
+ call feedkeys("i\<s-left>\<esc>", 'tnix')
+ call assert_equal([0, 1, 8, 0], getpos('.'))
+ call feedkeys("i". repeat("\<s-left>", 3). "\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call feedkeys("i\<right>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call feedkeys("i\<right>\<right>\<esc>", 'tnix')
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+ call feedkeys("A\<right>\<esc>", 'tnix')
+ call assert_equal([0, 1, 11, 0], getpos('.'))
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ call feedkeys("i\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 2, 4, 0], getpos('.'))
+ call cursor(3, 11)
+ call feedkeys("A\<right>\<esc>", 'tnix')
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 11, 0], getpos('.'))
+ call cursor(2, 11)
+ " <S-Right> does not respect 'whichwrap' option
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ " Check motion when 'whichwrap' contains cursor keys for insert mode
+ set ww+=[,]
+ call cursor(2, 1)
+ call feedkeys("i\<left>\<esc>", 'tnix')
+ call assert_equal([0, 1, 11, 0], getpos('.'))
+ call cursor(2, 11)
+ call feedkeys("A\<right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ call cursor(2, 11)
+ call feedkeys("A\<s-right>\<esc>", 'tnix')
+ call assert_equal([0, 3, 1, 0], getpos('.'))
+ let &ww = _ww
+ bw!
+endfunc
+
+func! Test_edit_MOUSE()
+ " This is a simple test, since we not really using the mouse here
+ if !has("mouse")
+ return
+ endif
+ 10new
+ call setline(1, range(1, 100))
+ call cursor(1, 1)
+ set mouse=a
+ call feedkeys("A\<ScrollWheelDown>\<esc>", 'tnix')
+ call assert_equal([0, 4, 1, 0], getpos('.'))
+ " This should move by one pageDown, but only moves
+ " by one line when the test is run...
+ call feedkeys("A\<S-ScrollWheelDown>\<esc>", 'tnix')
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ set nostartofline
+ call feedkeys("A\<C-ScrollWheelDown>\<esc>", 'tnix')
+ call assert_equal([0, 6, 1, 0], getpos('.'))
+ call feedkeys("A\<LeftMouse>\<esc>", 'tnix')
+ call assert_equal([0, 6, 1, 0], getpos('.'))
+ call feedkeys("A\<RightMouse>\<esc>", 'tnix')
+ call assert_equal([0, 6, 1, 0], getpos('.'))
+ call cursor(1, 100)
+ norm! zt
+ " this should move by a screen up, but when the test
+ " is run, it moves up to the top of the buffer...
+ call feedkeys("A\<ScrollWheelUp>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call cursor(1, 30)
+ norm! zt
+ call feedkeys("A\<S-ScrollWheelUp>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ call cursor(1, 30)
+ norm! zt
+ call feedkeys("A\<C-ScrollWheelUp>\<esc>", 'tnix')
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ %d
+ call setline(1, repeat(["12345678901234567890"], 100))
+ call cursor(2, 1)
+ call feedkeys("A\<ScrollWheelRight>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<ScrollWheelLeft>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<S-ScrollWheelRight>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<S-ScrollWheelLeft>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<C-ScrollWheelRight>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ call feedkeys("A\<C-ScrollWheelLeft>\<esc>", 'tnix')
+ call assert_equal([0, 2, 20, 0], getpos('.'))
+ set mouse& startofline
+ bw!
+endfunc
+
+func! Test_edit_PAGEUP_PAGEDOWN()
+ 10new
+ call setline(1, repeat(['abc def ghi'], 30))
+ call cursor(1, 1)
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 9, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 17, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 25, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("i\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 29, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 21, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 13, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ " <S-Up> is the same as <PageUp>
+ " <S-Down> is the same as <PageDown>
+ call cursor(1, 1)
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 9, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 17, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 25, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("i\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 29, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 21, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 13, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ set nostartofline
+ call cursor(30, 11)
+ norm! zt
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 29, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 21, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 13, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call feedkeys("A\<PageUp>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call cursor(1, 1)
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 9, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 17, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 25, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ call feedkeys("A\<PageDown>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ " <S-Up> is the same as <PageUp>
+ " <S-Down> is the same as <PageDown>
+ call cursor(30, 11)
+ norm! zt
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 29, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 21, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 13, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Up>\<esc>", 'tnix')
+ call assert_equal([0, 5, 11, 0], getpos('.'))
+ call cursor(1, 1)
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 9, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 17, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 25, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ call feedkeys("A\<S-Down>\<esc>", 'tnix')
+ call assert_equal([0, 30, 11, 0], getpos('.'))
+ bw!
+endfunc
+
+func! Test_edit_forbidden()
+ new
+ " 1) edit in the sandbox is not allowed
+ call setline(1, 'a')
+ com! Sandbox :sandbox call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_fails(':Sandbox', 'E48:')
+ com! Sandbox :sandbox exe "norm! i\<del>"
+ call assert_fails(':Sandbox', 'E48:')
+ delcom Sandbox
+ call assert_equal(['a'], getline(1,'$'))
+ " 2) edit with textlock set
+ fu! DoIt()
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ endfu
+ au InsertCharPre <buffer> :call DoIt()
+ try
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_fails(1, 'textlock')
+ catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here
+ endtry
+ " TODO: Might be a bug: should x really be inserted here
+ call assert_equal(['xa'], getline(1, '$'))
+ delfu DoIt
+ try
+ call feedkeys("ix\<esc>", 'tnix')
+ call assert_fails(1, 'unknown function')
+ catch /^Vim\%((\a\+)\)\=:E117/ " catch E117: unknown function
+ endtry
+ au! InsertCharPre
+ " 3) edit when completion is shown
+ fun! Complete(findstart, base)
+ if a:findstart
+ return col('.')
+ else
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ return []
+ endif
+ endfun
+ set completefunc=Complete
+ try
+ call feedkeys("i\<c-x>\<c-u>\<esc>", 'tnix')
+ call assert_fails(1, 'change in complete function')
+ catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
+ endtry
+ delfu Complete
+ set completefunc=
+ if has("rightleft") && exists("+fkmap")
+ " 4) 'R' when 'fkmap' and 'revins' is set.
+ set revins fkmap
+ try
+ normal Ri
+ call assert_fails(1, "R with 'fkmap' and 'ri' set")
+ catch
+ finally
+ set norevins nofkmap
+ endtry
+ endif
+ bw!
+endfunc
+
+func! Test_edit_rightleft()
+ " Cursor in rightleft mode moves differently
+ if !exists("+rightleft")
+ return
+ endif
+ call NewWindow(10, 20)
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 2)
+ set rightleft
+ " Screen looks as expected
+ let lines = ScreenLines([1, 4], winwidth(0))
+ let expect = [
+ \" cba",
+ \" fed",
+ \" ihg",
+ \" ~"]
+ call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ " 2) right moves to the left
+ call feedkeys("i\<right>\<esc>x", 'txin')
+ call assert_equal(['bc', 'def', 'ghi'], getline(1,'$'))
+ call cursor(1, 2)
+ call feedkeys("i\<s-right>\<esc>", 'txin')
+ call cursor(1, 2)
+ call feedkeys("i\<c-right>\<esc>", 'txin')
+ " Screen looks as expected
+ let lines = ScreenLines([1, 4], winwidth(0))
+ let expect = [
+ \" cb",
+ \" fed",
+ \" ihg",
+ \" ~"]
+ call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ " 2) left moves to the right
+ call setline(1, ['abc', 'def', 'ghi'])
+ call cursor(1, 2)
+ call feedkeys("i\<left>\<esc>x", 'txin')
+ call assert_equal(['ac', 'def', 'ghi'], getline(1,'$'))
+ call cursor(1, 2)
+ call feedkeys("i\<s-left>\<esc>", 'txin')
+ call cursor(1, 2)
+ call feedkeys("i\<c-left>\<esc>", 'txin')
+ " Screen looks as expected
+ let lines = ScreenLines([1, 4], winwidth(0))
+ let expect = [
+ \" ca",
+ \" fed",
+ \" ihg",
+ \" ~"]
+ call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ set norightleft
+ bw!
+endfunc
diff --git a/src/nvim/testdir/test_exists.vim b/src/nvim/testdir/test_exists.vim
new file mode 100644
index 0000000000..fd34be83b0
--- /dev/null
+++ b/src/nvim/testdir/test_exists.vim
@@ -0,0 +1,321 @@
+" Tests for the exists() function
+func Test_exists()
+ augroup myagroup
+ autocmd! BufEnter *.my echo "myfile edited"
+ autocmd! FuncUndefined UndefFun exec "fu UndefFun()\nendfu"
+ augroup END
+ set rtp+=./sautest
+
+ " valid autocmd group
+ call assert_equal(1, exists('#myagroup'))
+ " valid autocmd group with garbage
+ call assert_equal(0, exists('#myagroup+b'))
+ " Valid autocmd group and event
+ call assert_equal(1, exists('#myagroup#BufEnter'))
+ " Valid autocmd group, event and pattern
+ call assert_equal(1, exists('#myagroup#BufEnter#*.my'))
+ " Valid autocmd event
+ call assert_equal(1, exists('#BufEnter'))
+ " Valid autocmd event and pattern
+ call assert_equal(1, exists('#BufEnter#*.my'))
+ " Non-existing autocmd group or event
+ call assert_equal(0, exists('#xyzagroup'))
+ " Non-existing autocmd group and valid autocmd event
+ call assert_equal(0, exists('#xyzagroup#BufEnter'))
+ " Valid autocmd group and event with no matching pattern
+ call assert_equal(0, exists('#myagroup#CmdwinEnter'))
+ " Valid autocmd group and non-existing autocmd event
+ call assert_equal(0, exists('#myagroup#xyzacmd'))
+ " Valid autocmd group and event and non-matching pattern
+ call assert_equal(0, exists('#myagroup#BufEnter#xyzpat'))
+ " Valid autocmd event and non-matching pattern
+ call assert_equal(0, exists('#BufEnter#xyzpat'))
+ " Empty autocmd group, event and pattern
+ call assert_equal(0, exists('###'))
+ " Empty autocmd group and event or empty event and pattern
+ call assert_equal(0, exists('##'))
+ " Valid autocmd event
+ call assert_equal(1, exists('##FileReadCmd'))
+ " Non-existing autocmd event
+ call assert_equal(0, exists('##MySpecialCmd'))
+
+ " Existing and working option (long form)
+ call assert_equal(1, exists('&textwidth'))
+ " Existing and working option (short form)
+ call assert_equal(1, exists('&tw'))
+ " Existing and working option with garbage
+ call assert_equal(0, exists('&tw-'))
+ " Global option
+ call assert_equal(1, exists('&g:errorformat'))
+ " Local option
+ call assert_equal(1, exists('&l:errorformat'))
+ " Negative form of existing and working option (long form)
+ call assert_equal(0, exists('&nojoinspaces'))
+ " Negative form of existing and working option (short form)
+ call assert_equal(0, exists('&nojs'))
+ " Non-existing option
+ call assert_equal(0, exists('&myxyzoption'))
+
+ " Existing and working option (long form)
+ call assert_equal(1, exists('+incsearch'))
+ " Existing and working option with garbage
+ call assert_equal(0, exists('+incsearch!1'))
+ " Existing and working option (short form)
+ call assert_equal(1, exists('+is'))
+ " Existing option that is hidden.
+ call assert_equal(0, exists('+autoprint'))
+
+ " Existing environment variable
+ let $EDITOR_NAME = 'Vim Editor'
+ call assert_equal(1, exists('$EDITOR_NAME'))
+ " Non-existing environment variable
+ call assert_equal(0, exists('$NON_ENV_VAR'))
+
+ " Valid internal function
+ call assert_equal(1, exists('*bufnr'))
+ " Valid internal function with ()
+ call assert_equal(1, exists('*bufnr()'))
+ " Non-existing internal function
+ call assert_equal(0, exists('*myxyzfunc'))
+ " Valid internal function with garbage
+ call assert_equal(0, exists('*bufnr&6'))
+ " Valid user defined function
+ call assert_equal(1, exists('*Test_exists'))
+ " Non-existing user defined function
+ call assert_equal(0, exists('*MyxyzFunc'))
+ " Function that may be created by FuncUndefined event
+ call assert_equal(0, exists('*UndefFun'))
+ " Function that may be created by script autoloading
+ call assert_equal(0, exists('*footest#F'))
+
+ " Valid internal command (full match)
+ call assert_equal(2, exists(':edit'))
+ " Valid internal command (full match) with garbage
+ call assert_equal(0, exists(':edit/a'))
+ " Valid internal command (partial match)
+ call assert_equal(1, exists(':q'))
+ " Non-existing internal command
+ call assert_equal(0, exists(':invalidcmd'))
+
+ " User defined command (full match)
+ command! MyCmd :echo 'My command'
+ call assert_equal(2, exists(':MyCmd'))
+ " User defined command (partial match)
+ command! MyOtherCmd :echo 'Another command'
+ call assert_equal(3, exists(':My'))
+
+ " Command modifier
+ call assert_equal(2, exists(':rightbelow'))
+
+ " Non-existing user defined command (full match)
+ delcommand MyCmd
+ call assert_equal(0, exists(':MyCmd'))
+
+ " Non-existing user defined command (partial match)
+ delcommand MyOtherCmd
+ call assert_equal(0, exists(':My'))
+
+ " Valid local variable
+ let local_var = 1
+ call assert_equal(1, exists('local_var'))
+ " Valid local variable with garbage
+ call assert_equal(0, exists('local_var%n'))
+ " Non-existing local variable
+ unlet local_var
+ call assert_equal(0, exists('local_var'))
+
+ " Non-existing autoload variable that may be autoloaded
+ call assert_equal(0, exists('footest#x'))
+
+ " Valid local list
+ let local_list = ["blue", "orange"]
+ call assert_equal(1, exists('local_list'))
+ " Valid local list item
+ call assert_equal(1, exists('local_list[1]'))
+ " Valid local list item with garbage
+ call assert_equal(0, exists('local_list[1]+5'))
+ " Invalid local list item
+ call assert_equal(0, exists('local_list[2]'))
+ " Non-existing local list
+ unlet local_list
+ call assert_equal(0, exists('local_list'))
+ " Valid local dictionary
+ let local_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('local_dict'))
+ " Non-existing local dictionary
+ unlet local_dict
+ call assert_equal(0, exists('local_dict'))
+ " Existing local curly-brace variable
+ let str = "local"
+ let curly_{str}_var = 1
+ call assert_equal(1, exists('curly_{str}_var'))
+ " Non-existing local curly-brace variable
+ unlet curly_{str}_var
+ call assert_equal(0, exists('curly_{str}_var'))
+
+ " Existing global variable
+ let g:global_var = 1
+ call assert_equal(1, exists('g:global_var'))
+ " Existing global variable with garbage
+ call assert_equal(0, exists('g:global_var-n'))
+ " Non-existing global variable
+ unlet g:global_var
+ call assert_equal(0, exists('g:global_var'))
+ " Existing global list
+ let g:global_list = ["blue", "orange"]
+ call assert_equal(1, exists('g:global_list'))
+ " Non-existing global list
+ unlet g:global_list
+ call assert_equal(0, exists('g:global_list'))
+ " Existing global dictionary
+ let g:global_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('g:global_dict'))
+ " Non-existing global dictionary
+ unlet g:global_dict
+ call assert_equal(0, exists('g:global_dict'))
+ " Existing global curly-brace variable
+ let str = "global"
+ let g:curly_{str}_var = 1
+ call assert_equal(1, exists('g:curly_{str}_var'))
+ " Non-existing global curly-brace variable
+ unlet g:curly_{str}_var
+ call assert_equal(0, exists('g:curly_{str}_var'))
+
+ " Existing window variable
+ let w:window_var = 1
+ call assert_equal(1, exists('w:window_var'))
+ " Non-existing window variable
+ unlet w:window_var
+ call assert_equal(0, exists('w:window_var'))
+ " Existing window list
+ let w:window_list = ["blue", "orange"]
+ call assert_equal(1, exists('w:window_list'))
+ " Non-existing window list
+ unlet w:window_list
+ call assert_equal(0, exists('w:window_list'))
+ " Existing window dictionary
+ let w:window_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('w:window_dict'))
+ " Non-existing window dictionary
+ unlet w:window_dict
+ call assert_equal(0, exists('w:window_dict'))
+ " Existing window curly-brace variable
+ let str = "window"
+ let w:curly_{str}_var = 1
+ call assert_equal(1, exists('w:curly_{str}_var'))
+ " Non-existing window curly-brace variable
+ unlet w:curly_{str}_var
+ call assert_equal(0, exists('w:curly_{str}_var'))
+
+ " Existing tab variable
+ let t:tab_var = 1
+ call assert_equal(1, exists('t:tab_var'))
+ " Non-existing tab variable
+ unlet t:tab_var
+ call assert_equal(0, exists('t:tab_var'))
+ " Existing tab list
+ let t:tab_list = ["blue", "orange"]
+ call assert_equal(1, exists('t:tab_list'))
+ " Non-existing tab list
+ unlet t:tab_list
+ call assert_equal(0, exists('t:tab_list'))
+ " Existing tab dictionary
+ let t:tab_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('t:tab_dict'))
+ " Non-existing tab dictionary
+ unlet t:tab_dict
+ call assert_equal(0, exists('t:tab_dict'))
+ " Existing tab curly-brace variable
+ let str = "tab"
+ let t:curly_{str}_var = 1
+ call assert_equal(1, exists('t:curly_{str}_var'))
+ " Non-existing tab curly-brace variable
+ unlet t:curly_{str}_var
+ call assert_equal(0, exists('t:curly_{str}_var'))
+
+ " Existing buffer variable
+ let b:buffer_var = 1
+ call assert_equal(1, exists('b:buffer_var'))
+ " Non-existing buffer variable
+ unlet b:buffer_var
+ call assert_equal(0, exists('b:buffer_var'))
+ " Existing buffer list
+ let b:buffer_list = ["blue", "orange"]
+ call assert_equal(1, exists('b:buffer_list'))
+ " Non-existing buffer list
+ unlet b:buffer_list
+ call assert_equal(0, exists('b:buffer_list'))
+ " Existing buffer dictionary
+ let b:buffer_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('b:buffer_dict'))
+ " Non-existing buffer dictionary
+ unlet b:buffer_dict
+ call assert_equal(0, exists('b:buffer_dict'))
+ " Existing buffer curly-brace variable
+ let str = "buffer"
+ let b:curly_{str}_var = 1
+ call assert_equal(1, exists('b:curly_{str}_var'))
+ " Non-existing buffer curly-brace variable
+ unlet b:curly_{str}_var
+ call assert_equal(0, exists('b:curly_{str}_var'))
+
+ " Existing Vim internal variable
+ call assert_equal(1, exists('v:version'))
+ " Non-existing Vim internal variable
+ call assert_equal(0, exists('v:non_exists_var'))
+
+ " Existing script-local variable
+ let s:script_var = 1
+ call assert_equal(1, exists('s:script_var'))
+ " Non-existing script-local variable
+ unlet s:script_var
+ call assert_equal(0, exists('s:script_var'))
+ " Existing script-local list
+ let s:script_list = ["blue", "orange"]
+ call assert_equal(1, exists('s:script_list'))
+ " Non-existing script-local list
+ unlet s:script_list
+ call assert_equal(0, exists('s:script_list'))
+ " Existing script-local dictionary
+ let s:script_dict = {"xcord":100, "ycord":2}
+ call assert_equal(1, exists('s:script_dict'))
+ " Non-existing script-local dictionary
+ unlet s:script_dict
+ call assert_equal(0, exists('s:script_dict'))
+ " Existing script curly-brace variable
+ let str = "script"
+ let s:curly_{str}_var = 1
+ call assert_equal(1, exists('s:curly_{str}_var'))
+ " Non-existing script-local curly-brace variable
+ unlet s:curly_{str}_var
+ call assert_equal(0, exists('s:curly_{str}_var'))
+
+ " Existing script-local function
+ function! s:my_script_func()
+ endfunction
+
+ echo '*s:my_script_func: 1'
+ call assert_equal(1, exists('*s:my_script_func'))
+
+ " Non-existing script-local function
+ delfunction s:my_script_func
+
+ call assert_equal(0, exists('*s:my_script_func'))
+ unlet str
+
+ call assert_equal(1, g:footest#x)
+ call assert_equal(0, footest#F())
+ call assert_equal(0, UndefFun())
+endfunc
+
+" exists() test for Function arguments
+func FuncArg_Tests(func_arg, ...)
+ call assert_equal(1, exists('a:func_arg'))
+ call assert_equal(0, exists('a:non_exists_arg'))
+ call assert_equal(1, exists('a:1'))
+ call assert_equal(0, exists('a:2'))
+endfunc
+
+func Test_exists_funcarg()
+ call FuncArg_Tests("arg1", "arg2")
+endfunc
diff --git a/src/nvim/testdir/test_file_size.vim b/src/nvim/testdir/test_file_size.vim
new file mode 100644
index 0000000000..3e78a7b23c
--- /dev/null
+++ b/src/nvim/testdir/test_file_size.vim
@@ -0,0 +1,58 @@
+" Inserts 2 million lines with consecutive integers starting from 1
+" (essentially, the output of GNU's seq 1 2000000), writes them to Xtest
+" and writes its cksum to test.out.
+"
+" We need 2 million lines to trigger a call to mf_hash_grow(). If it would mess
+" up the lines the checksum would differ.
+"
+" cksum is part of POSIX and so should be available on most Unixes.
+" If it isn't available then the test will be skipped.
+func Test_File_Size()
+ if !executable('cksum')
+ return
+ endif
+
+ new
+ set fileformat=unix undolevels=-1
+ for i in range(1, 2000000, 100)
+ call append(i, range(i, i + 99))
+ endfor
+
+ 1delete
+ w! Xtest
+ let res = systemlist('cksum Xtest')[0]
+ let res = substitute(res, "\r", "", "")
+ call assert_equal('3678979763 14888896 Xtest', res)
+
+ enew!
+ call delete('Xtest')
+ set fileformat& undolevels&
+endfunc
+
+" Test for writing and reading a file of over 100 Kbyte
+func Test_File_Read_Write()
+ enew!
+
+ " Create a file with the following contents
+ " 1 line: "This is the start"
+ " 3001 lines: "This is the leader"
+ " 1 line: "This is the middle"
+ " 3001 lines: "This is the trailer"
+ " 1 line: "This is the end"
+ call append(0, "This is the start")
+ call append(1, repeat(["This is the leader"], 3001))
+ call append(3002, "This is the middle")
+ call append(3003, repeat(["This is the trailer"], 3001))
+ call append(6004, "This is the end")
+
+ write! Xtest
+ enew!
+ edit! Xtest
+
+ call assert_equal("This is the start", getline(1))
+ call assert_equal("This is the middle", getline(3003))
+ call assert_equal("This is the end", getline(6005))
+
+ enew!
+ call delete("Xtest")
+endfunc
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
new file mode 100644
index 0000000000..43dc383f3d
--- /dev/null
+++ b/src/nvim/testdir/test_filetype.vim
@@ -0,0 +1,557 @@
+" Test :setfiletype
+
+func Test_detection()
+ filetype on
+ augroup filetypedetect
+ au BufNewFile,BufRead * call assert_equal(1, did_filetype())
+ augroup END
+ new something.vim
+ call assert_equal('vim', &filetype)
+
+ bwipe!
+ filetype off
+endfunc
+
+func Test_conf_type()
+ filetype on
+ call writefile(['# some comment', 'must be conf'], 'Xfile')
+ augroup filetypedetect
+ au BufNewFile,BufRead * call assert_equal(0, did_filetype())
+ augroup END
+ split Xfile
+ call assert_equal('conf', &filetype)
+
+ bwipe!
+ call delete('Xfile')
+ filetype off
+endfunc
+
+func Test_other_type()
+ filetype on
+ augroup filetypedetect
+ au BufNewFile,BufRead * call assert_equal(0, did_filetype())
+ au BufNewFile,BufRead Xfile setf testfile
+ au BufNewFile,BufRead * call assert_equal(1, did_filetype())
+ augroup END
+ call writefile(['# some comment', 'must be conf'], 'Xfile')
+ split Xfile
+ call assert_equal('testfile', &filetype)
+
+ bwipe!
+ call delete('Xfile')
+ filetype off
+endfunc
+
+" Filetypes detected just from matching the file name.
+let s:filename_checks = {
+ \ 'a2ps': ['/etc/a2ps.cfg', '/etc/a2ps/file.cfg', 'a2psrc', '.a2psrc'],
+ \ 'a65': ['file.a65'],
+ \ 'abap': ['file.abap'],
+ \ 'abc': ['file.abc'],
+ \ 'abel': ['file.abl'],
+ \ 'acedb': ['file.wrm'],
+ \ 'ada': ['file.adb', 'file.ads', 'file.ada', 'file.gpr'],
+ \ 'ahdl': ['file.tdf'],
+ \ 'alsaconf': ['.asoundrc', '/usr/share/alsa/alsa.conf', '/etc/asound.conf'],
+ \ 'aml': ['file.aml'],
+ \ 'ampl': ['file.run'],
+ \ 'ant': ['build.xml'],
+ \ 'apache': ['.htaccess', '/etc/httpd/file.conf'],
+ \ 'applescript': ['file.scpt'],
+ \ 'aptconf': ['apt.conf', '/.aptitude/config'],
+ \ 'arch': ['.arch-inventory'],
+ \ 'arduino': ['file.ino', 'file.pde'],
+ \ 'art': ['file.art'],
+ \ 'asciidoc': ['file.asciidoc', 'file.adoc'],
+ \ 'asn': ['file.asn', 'file.asn1'],
+ \ 'atlas': ['file.atl', 'file.as'],
+ \ 'autohotkey': ['file.ahk'],
+ \ 'autoit': ['file.au3'],
+ \ 'automake': ['GNUmakefile.am'],
+ \ 'ave': ['file.ave'],
+ \ 'awk': ['file.awk'],
+ \ 'b': ['file.mch', 'file.ref', 'file.imp'],
+ \ 'bc': ['file.bc'],
+ \ 'bdf': ['file.bdf'],
+ \ 'bib': ['file.bib'],
+ \ 'bindzone': ['named.root'],
+ \ 'blank': ['file.bl'],
+ \ 'bst': ['file.bst'],
+ \ 'bzr': ['bzr_log.any'],
+ \ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c'],
+ \ 'cabal': ['file.cabal'],
+ \ 'calendar': ['calendar'],
+ \ 'catalog': ['catalog'],
+ \ 'cdl': ['file.cdl'],
+ \ 'cdrdaoconf': ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao'],
+ \ 'cdrtoc': ['file.toc'],
+ \ 'cf': ['file.cfm', 'file.cfi', 'file.cfc'],
+ \ 'cfengine': ['cfengine.conf'],
+ \ 'cfg': ['file.cfg', 'file.hgrc', 'filehgrc'],
+ \ 'ch': ['file.chf'],
+ \ 'chaiscript': ['file.chai'],
+ \ 'chaskell': ['file.chs'],
+ \ 'chill': ['file..ch'],
+ \ 'chordpro': ['file.chopro', 'file.crd', 'file.cho', 'file.crdpro', 'file.chordpro'],
+ \ 'cl': ['file.eni'],
+ \ 'clean': ['file.dcl', 'file.icl'],
+ \ 'clojure': ['file.clj', 'file.cljs', 'file.cljx', 'file.cljc'],
+ \ 'cmake': ['CMakeLists.txt', 'file.cmake', 'file.cmake.in'],
+ \ 'cmusrc': ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme'],
+ \ 'cobol': ['file.cbl', 'file.cob', 'file.lib'],
+ \ 'coco': ['file.atg'],
+ \ 'conaryrecipe': ['file.recipe'],
+ \ 'conf': ['auto.master'],
+ \ 'config': ['configure.in', 'configure.ac'],
+ \ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi'],
+ \ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
+ \ 'crm': ['file.crm'],
+ \ 'cs': ['file.cs'],
+ \ 'csc': ['file.csc'],
+ \ 'csdl': ['file.csdl'],
+ \ 'csp': ['file.csp', 'file.fdr'],
+ \ 'css': ['file.css'],
+ \ 'cterm': ['file.con'],
+ \ 'cucumber': ['file.feature'],
+ \ 'cuda': ['file.cu'],
+ \ 'cupl': ['file.pld'],
+ \ 'cuplsim': ['file.si'],
+ \ 'cvs': ['cvs123'],
+ \ 'cvsrc': ['.cvsrc'],
+ \ 'cynpp': ['file.cyn'],
+ \ 'datascript': ['file.ds'],
+ \ 'dcd': ['file.dcd'],
+ \ 'debcontrol': ['/debian/control'],
+ \ 'debsources': ['/etc/apt/sources.list', '/etc/apt/sources.list.d/file.list'],
+ \ 'def': ['file.def'],
+ \ 'denyhosts': ['denyhosts.conf'],
+ \ 'desc': ['file.desc'],
+ \ 'desktop': ['file.desktop', '.directory'],
+ \ 'dictconf': ['dict.conf', '.dictrc'],
+ \ 'dictdconf': ['dictd.conf'],
+ \ 'diff': ['file.diff', 'file.rej'],
+ \ 'dircolors': ['.dir_colors', '.dircolors', '/etc/DIR_COLORS'],
+ \ 'dnsmasq': ['/etc/dnsmasq.conf'],
+ \ 'dockerfile': ['Dockerfile', 'file.Dockerfile'],
+ \ 'dosbatch': ['file.bat', 'file.sys'],
+ \ 'dosini': ['.editorconfig', '/etc/yum.conf', 'file.ini'],
+ \ 'dot': ['file.dot'],
+ \ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe'],
+ \ 'dsl': ['file.dsl'],
+ \ 'dtd': ['file.dtd'],
+ \ 'dts': ['file.dts', 'file.dtsi'],
+ \ 'dylan': ['file.dylan'],
+ \ 'dylanintr': ['file.intr'],
+ \ 'dylanlid': ['file.lid'],
+ \ 'ecd': ['file.ecd'],
+ \ 'edif': ['file.edf', 'file.edif', 'file.edo'],
+ \ 'elinks': ['/etc/elinks.conf', '/.elinks/elinks.conf'],
+ \ 'elmfilt': ['filter-rules'],
+ \ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'],
+ \ 'eruby': ['file.erb', 'file.rhtml'],
+ \ 'esmtprc': ['anyesmtprc'],
+ \ 'esqlc': ['file.ec', 'file.EC'],
+ \ 'esterel': ['file.strl'],
+ \ 'eterm': ['anyEterm/file.cfg'],
+ \ 'exim': ['exim.conf'],
+ \ 'expect': ['file.exp'],
+ \ 'exports': ['exports'],
+ \ 'factor': ['file.factor'],
+ \ 'falcon': ['file.fal'],
+ \ 'fan': ['file.fan', 'file.fwt'],
+ \ 'fetchmail': ['.fetchmailrc'],
+ \ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
+ \ 'focexec': ['file.fex', 'file.focexec'],
+ \ 'forth': ['file.fs', 'file.ft'],
+ \ 'fortran': ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'],
+ \ 'framescript': ['file.fsl'],
+ \ 'freebasic': ['file.fb', 'file.bi'],
+ \ 'fstab': ['fstab', 'mtab'],
+ \ 'gdb': ['.gdbinit'],
+ \ 'gdmo': ['file.mo', 'file.gdmo'],
+ \ 'gedcom': ['file.ged', 'lltxxxxx.txt'],
+ \ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'],
+ \ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config'],
+ \ 'gitolite': ['gitolite.conf'],
+ \ 'gitrebase': ['git-rebase-todo'],
+ \ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'],
+ \ 'gkrellmrc': ['gkrellmrc', 'gkrellmrc_x'],
+ \ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'],
+ \ 'gnuplot': ['file.gpi'],
+ \ 'go': ['file.go'],
+ \ 'gp': ['file.gp', '.gprc'],
+ \ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel'],
+ \ 'grads': ['file.gs'],
+ \ 'gretl': ['file.gretl'],
+ \ 'groovy': ['file.gradle', 'file.groovy'],
+ \ 'group': ['any/etc/group', 'any/etc/group-', 'any/etc/group.edit', 'any/etc/gshadow', 'any/etc/gshadow-', 'any/etc/gshadow.edit', 'any/var/backups/group.bak', 'any/var/backups/gshadow.bak'],
+ \ 'grub': ['/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf'],
+ \ 'gsp': ['file.gsp'],
+ \ 'gtkrc': ['.gtkrc', 'gtkrc'],
+ \ 'haml': ['file.haml'],
+ \ 'hamster': ['file.hsc', 'file.hsm'],
+ \ 'haskell': ['file.hs', 'file.hs-boot'],
+ \ 'haste': ['file.ht'],
+ \ 'hastepreproc': ['file.htpp'],
+ \ 'hb': ['file.hb'],
+ \ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
+ \ 'hex': ['file.hex', 'file.h32'],
+ \ 'hgcommit': ['hg-editor-file.txt'],
+ \ 'hog': ['file.hog', 'snort.conf', 'vision.conf'],
+ \ 'hostconf': ['/etc/host.conf'],
+ \ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny'],
+ \ 'htmlcheetah': ['file.tmpl'],
+ \ 'htmlm4': ['file.html.m4'],
+ \ 'httest': ['file.htt', 'file.htb'],
+ \ 'ibasic': ['file.iba', 'file.ibi'],
+ \ 'icemenu': ['/.icewm/menu'],
+ \ 'icon': ['file.icn'],
+ \ 'indent': ['.indent.pro', 'indentrc'],
+ \ 'inform': ['file.inf', 'file.INF'],
+ \ 'initng': ['/etc/initng/any/file.i', 'file.ii'],
+ \ 'inittab': ['inittab'],
+ \ 'ipfilter': ['ipf.conf', 'ipf6.conf', 'ipf.rules'],
+ \ 'iss': ['file.iss'],
+ \ 'ist': ['file.ist', 'file.mst'],
+ \ 'j': ['file.ijs'],
+ \ 'jal': ['file.jal', 'file.JAL'],
+ \ 'jam': ['file.jpl', 'file.jpr'],
+ \ 'java': ['file.java', 'file.jav'],
+ \ 'javacc': ['file.jj', 'file.jjt'],
+ \ 'javascript': ['file.js', 'file.javascript', 'file.es', 'file.jsx', 'file.mjs'],
+ \ 'jess': ['file.clp'],
+ \ 'jgraph': ['file.jgr'],
+ \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
+ \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest'],
+ \ 'jsp': ['file.jsp'],
+ \ 'kconfig': ['Kconfig', 'Kconfig.debug'],
+ \ 'kivy': ['file.kv'],
+ \ 'kix': ['file.kix'],
+ \ 'kscript': ['file.ks'],
+ \ 'kwt': ['file.k'],
+ \ 'lace': ['file.ace', 'file.ACE'],
+ \ 'latte': ['file.latte', 'file.lte'],
+ \ 'ld': ['file.ld'],
+ \ 'ldif': ['file.ldif'],
+ \ 'less': ['file.less'],
+ \ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'],
+ \ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc'],
+ \ 'lhaskell': ['file.lhs'],
+ \ 'libao': ['/etc/libao.conf', '/.libao'],
+ \ 'lifelines': ['file.ll'],
+ \ 'lilo': ['lilo.conf'],
+ \ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf'],
+ \ 'liquid': ['file.liquid'],
+ \ 'lisp': ['sbclrc', '.sbclrc'],
+ \ 'lite': ['file.lite', 'file.lt'],
+ \ 'litestep': ['/LiteStep/any/file.rc'],
+ \ 'loginaccess': ['/etc/login.access'],
+ \ 'logindefs': ['/etc/login.defs'],
+ \ 'logtalk': ['file.lgt'],
+ \ 'lotos': ['file.lot', 'file.lotos'],
+ \ 'lout': ['file.lou', 'file.lout'],
+ \ 'lprolog': ['file.sig'],
+ \ 'lsl': ['file.lsl'],
+ \ 'lss': ['file.lss'],
+ \ 'lua': ['file.lua', 'file.rockspec', 'file.nse'],
+ \ 'lynx': ['lynx.cfg'],
+ \ 'm4': ['file.at'],
+ \ 'mail': ['snd.123', '.letter', '.letter.123', '.followup', '.article', '.article.123', 'pico.123', 'mutt-xx-xxx', 'muttng-xx-xxx', 'ae123.txt', 'file.eml'],
+ \ 'mailaliases': ['/etc/mail/aliases', '/etc/aliases'],
+ \ 'mailcap': ['.mailcap', 'mailcap'],
+ \ 'make': ['file.mk', 'file.mak', 'file.dsp'],
+ \ 'mallard': ['file.page'],
+ \ 'manconf': ['/etc/man.conf', 'man.config'],
+ \ 'map': ['file.map'],
+ \ 'maple': ['file.mv', 'file.mpl', 'file.mws'],
+ \ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
+ \ 'mason': ['file.mason', 'file.mhtml', 'file.comp'],
+ \ 'master': ['file.mas', 'file.master'],
+ \ 'mel': ['file.mel'],
+ \ 'messages': ['/log/auth', '/log/cron', '/log/daemon', '/log/debug', '/log/kern', '/log/lpr', '/log/mail', '/log/messages', '/log/news/news', '/log/syslog', '/log/user',
+ \ '/log/auth.log', '/log/cron.log', '/log/daemon.log', '/log/debug.log', '/log/kern.log', '/log/lpr.log', '/log/mail.log', '/log/messages.log', '/log/news/news.log', '/log/syslog.log', '/log/user.log',
+ \ '/log/auth.err', '/log/cron.err', '/log/daemon.err', '/log/debug.err', '/log/kern.err', '/log/lpr.err', '/log/mail.err', '/log/messages.err', '/log/news/news.err', '/log/syslog.err', '/log/user.err',
+ \ '/log/auth.info', '/log/cron.info', '/log/daemon.info', '/log/debug.info', '/log/kern.info', '/log/lpr.info', '/log/mail.info', '/log/messages.info', '/log/news/news.info', '/log/syslog.info', '/log/user.info',
+ \ '/log/auth.warn', '/log/cron.warn', '/log/daemon.warn', '/log/debug.warn', '/log/kern.warn', '/log/lpr.warn', '/log/mail.warn', '/log/messages.warn', '/log/news/news.warn', '/log/syslog.warn', '/log/user.warn',
+ \ '/log/auth.crit', '/log/cron.crit', '/log/daemon.crit', '/log/debug.crit', '/log/kern.crit', '/log/lpr.crit', '/log/mail.crit', '/log/messages.crit', '/log/news/news.crit', '/log/syslog.crit', '/log/user.crit',
+ \ '/log/auth.notice', '/log/cron.notice', '/log/daemon.notice', '/log/debug.notice', '/log/kern.notice', '/log/lpr.notice', '/log/mail.notice', '/log/messages.notice', '/log/news/news.notice', '/log/syslog.notice', '/log/user.notice'],
+ \ 'mf': ['file.mf'],
+ \ 'mgl': ['file.mgl'],
+ \ 'mgp': ['file.mgp'],
+ \ 'mib': ['file.mib', 'file.my'],
+ \ 'mix': ['file.mix', 'file.mixal'],
+ \ 'mma': ['file.nb'],
+ \ 'mmp': ['file.mmp'],
+ \ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules'],
+ \ 'modula2': ['file.m2', 'file.mi'],
+ \ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
+ \ 'moo': ['file.moo'],
+ \ 'mp': ['file.mp'],
+ \ 'mplayerconf': ['mplayer.conf', '/.mplayer/config'],
+ \ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
+ \ 'msidl': ['file.odl', 'file.mof'],
+ \ 'msql': ['file.msql'],
+ \ 'mupad': ['file.mu'],
+ \ 'mush': ['file.mush'],
+ \ 'muttrc': ['Muttngrc', 'Muttrc'],
+ \ 'mysql': ['file.mysql'],
+ \ 'n1ql': ['file.n1ql', 'file.nql'],
+ \ 'named': ['namedfile.conf', 'rndcfile.conf'],
+ \ 'nanorc': ['/etc/nanorc', 'file.nanorc'],
+ \ 'ncf': ['file.ncf'],
+ \ 'netrc': ['.netrc'],
+ \ 'ninja': ['file.ninja'],
+ \ 'nqc': ['file.nqc'],
+ \ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom'],
+ \ 'nsis': ['file.nsi', 'file.nsh'],
+ \ 'obj': ['file.obj'],
+ \ 'ocaml': ['file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit'],
+ \ 'occam': ['file.occ'],
+ \ 'omnimark': ['file.xom', 'file.xin'],
+ \ 'openroad': ['file.or'],
+ \ 'ora': ['file.ora'],
+ \ 'pamconf': ['/etc/pam.conf'],
+ \ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
+ \ 'pascal': ['file.pas', 'file.dpr'],
+ \ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'],
+ \ 'pccts': ['file.g'],
+ \ 'pdf': ['file.pdf'],
+ \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
+ \ 'perl6': ['file.p6', 'file.pm6', 'file.pl6'],
+ \ 'pf': ['pf.conf'],
+ \ 'pfmain': ['main.cf'],
+ \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp'],
+ \ 'pike': ['file.pike', 'file.lpc', 'file.ulpc', 'file.pmod'],
+ \ 'pilrc': ['file.rcp'],
+ \ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
+ \ 'pinfo': ['/etc/pinforc', '/.pinforc'],
+ \ 'pli': ['file.pli', 'file.pl1'],
+ \ 'plm': ['file.plm', 'file.p36', 'file.pac'],
+ \ 'plp': ['file.plp'],
+ \ 'plsql': ['file.pls', 'file.plsql'],
+ \ 'po': ['file.po', 'file.pot'],
+ \ 'pod': ['file.pod'],
+ \ 'pod6': ['file.pod6'],
+ \ 'postscr': ['file.ps', 'file.pfa', 'file.afm', 'file.eps', 'file.epsf', 'file.epsi', 'file.ai'],
+ \ 'pov': ['file.pov'],
+ \ 'povini': ['.povrayrc'],
+ \ 'ppd': ['file.ppd'],
+ \ 'ppwiz': ['file.it', 'file.ih'],
+ \ 'privoxy': ['file.action'],
+ \ 'proc': ['file.pc'],
+ \ 'procmail': ['.procmail', '.procmailrc'],
+ \ 'prolog': ['file.pdb'],
+ \ 'promela': ['file.pml'],
+ \ 'proto': ['file.proto'],
+ \ 'protocols': ['/etc/protocols'],
+ \ 'psf': ['file.psf'],
+ \ 'pyrex': ['file.pyx', 'file.pxd'],
+ \ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl'],
+ \ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg'],
+ \ 'radiance': ['file.rad', 'file.mat'],
+ \ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
+ \ 'rc': ['file.rc', 'file.rch'],
+ \ 'rcs': ['file,v'],
+ \ 'readline': ['.inputrc', 'inputrc'],
+ \ 'remind': ['.reminders', 'file.remind', 'file.rem'],
+ \ 'resolv': ['resolv.conf'],
+ \ 'reva': ['file.frt'],
+ \ 'rexx': ['file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'],
+ \ 'rib': ['file.rib'],
+ \ 'rnc': ['file.rnc'],
+ \ 'rng': ['file.rng'],
+ \ 'robots': ['robots.txt'],
+ \ 'rpcgen': ['file.x'],
+ \ 'rpl': ['file.rpl'],
+ \ 'rst': ['file.rst'],
+ \ 'rtf': ['file.rtf'],
+ \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake'],
+ \ 'rust': ['file.rs'],
+ \ 'samba': ['smb.conf'],
+ \ 'sas': ['file.sas'],
+ \ 'sass': ['file.sass'],
+ \ 'sather': ['file.sa'],
+ \ 'sbt': ['file.sbt'],
+ \ 'scala': ['file.scala'],
+ \ 'scheme': ['file.scm', 'file.ss', 'file.rkt'],
+ \ 'scilab': ['file.sci', 'file.sce'],
+ \ 'screen': ['.screenrc', 'screenrc'],
+ \ 'scss': ['file.scss'],
+ \ 'sd': ['file.sd'],
+ \ 'sdc': ['file.sdc'],
+ \ 'sdl': ['file.sdl', 'file.pr'],
+ \ 'sed': ['file.sed'],
+ \ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf'],
+ \ 'services': ['/etc/services'],
+ \ 'setserial': ['/etc/serial.conf'],
+ \ 'sh': ['/etc/udev/cdsymlinks.conf'],
+ \ 'sieve': ['file.siv'],
+ \ 'simula': ['file.sim'],
+ \ 'sinda': ['file.sin', 'file.s85'],
+ \ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'],
+ \ 'skill': ['file.il', 'file.ils', 'file.cdf'],
+ \ 'slang': ['file.sl'],
+ \ 'slice': ['file.ice'],
+ \ 'slpconf': ['/etc/slp.conf'],
+ \ 'slpreg': ['/etc/slp.reg'],
+ \ 'slpspi': ['/etc/slp.spi'],
+ \ 'slrnrc': ['.slrnrc'],
+ \ 'slrnsc': ['file.score'],
+ \ 'sm': ['sendmail.cf'],
+ \ 'smarty': ['file.tpl'],
+ \ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
+ \ 'smith': ['file.smt', 'file.smith'],
+ \ 'sml': ['file.sml'],
+ \ 'snobol4': ['file.sno', 'file.spt'],
+ \ 'spec': ['file.spec'],
+ \ 'spice': ['file.sp', 'file.spice'],
+ \ 'spup': ['file.speedup', 'file.spdata', 'file.spd'],
+ \ 'spyce': ['file.spy', 'file.spi'],
+ \ 'sql': ['file.tyb', 'file.typ', 'file.tyc', 'file.pkb', 'file.pks'],
+ \ 'sqlj': ['file.sqlj'],
+ \ 'sqr': ['file.sqr', 'file.sqi'],
+ \ 'squid': ['squid.conf'],
+ \ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'],
+ \ 'sshconfig': ['ssh_config', '/.ssh/config'],
+ \ 'sshdconfig': ['sshd_config'],
+ \ 'st': ['file.st'],
+ \ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'],
+ \ 'stp': ['file.stp'],
+ \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp'],
+ \ 'svg': ['file.svg'],
+ \ 'svn': ['svn-commitfile.tmp'],
+ \ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'],
+ \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer'],
+ \ 'systemverilog': ['file.sv', 'file.svh'],
+ \ 'tags': ['tags'],
+ \ 'tak': ['file.tak'],
+ \ 'taskdata': ['pending.data', 'completed.data', 'undo.data'],
+ \ 'taskedit': ['file.task'],
+ \ 'tcl': ['file.tcl', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl'],
+ \ 'teraterm': ['file.ttl'],
+ \ 'terminfo': ['file.ti'],
+ \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'],
+ \ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'],
+ \ 'texmf': ['texmf.cnf'],
+ \ 'text': ['file.text', 'README'],
+ \ 'tf': ['file.tf', '.tfrc', 'tfrc'],
+ \ 'tidy': ['.tidyrc', 'tidyrc'],
+ \ 'tilde': ['file.t.html'],
+ \ 'tli': ['file.tli'],
+ \ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf'],
+ \ 'tpp': ['file.tpp'],
+ \ 'treetop': ['file.treetop'],
+ \ 'trustees': ['trustees.conf'],
+ \ 'tsalt': ['file.slt'],
+ \ 'tsscl': ['file.tsscl'],
+ \ 'tssgm': ['file.tssgm'],
+ \ 'tssop': ['file.tssop'],
+ \ 'twig': ['file.twig'],
+ \ 'uc': ['file.uc'],
+ \ 'udevconf': ['/etc/udev/udev.conf'],
+ \ 'udevperm': ['/etc/udev/permissions.d/file.permissions'],
+ \ 'uil': ['file.uit', 'file.uil'],
+ \ 'updatedb': ['/etc/updatedb.conf'],
+ \ 'upstart': ['/usr/share/upstart/file.conf', '/usr/share/upstart/file.override', '/etc/init/file.conf', '/etc/init/file.override', '/.init/file.conf', '/.init/file.override', '/.config/upstart/file.conf', '/.config/upstart/file.override'],
+ \ 'upstreamdat': ['upstream.dat', 'UPSTREAM.DAT', 'upstream.file.dat', 'UPSTREAM.FILE.DAT', 'file.upstream.dat', 'FILE.UPSTREAM.DAT'],
+ \ 'upstreaminstalllog': ['upstreaminstall.log', 'UPSTREAMINSTALL.LOG', 'upstreaminstall.file.log', 'UPSTREAMINSTALL.FILE.LOG', 'file.upstreaminstall.log', 'FILE.UPSTREAMINSTALL.LOG'],
+ \ 'upstreamlog': ['fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'],
+ \ 'usserverlog': ['usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'],
+ \ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'],
+ \ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
+ \ 'vera': ['file.vr', 'file.vri', 'file.vrh'],
+ \ 'verilog': ['file.v'],
+ \ 'verilogams': ['file.va', 'file.vams'],
+ \ 'vgrindefs': ['vgrindefs'],
+ \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst'],
+ \ 'vim': ['file.vim', 'file.vba', '.exrc', '_exrc'],
+ \ 'viminfo': ['.viminfo', '_viminfo'],
+ \ 'vmasm': ['file.mar'],
+ \ 'voscm': ['file.cm'],
+ \ 'vrml': ['file.wrl'],
+ \ 'vroom': ['file.vroom'],
+ \ 'webmacro': ['file.wm'],
+ \ 'wget': ['.wgetrc', 'wgetrc'],
+ \ 'winbatch': ['file.wbt'],
+ \ 'wml': ['file.wml'],
+ \ 'wsml': ['file.wsml'],
+ \ 'wvdial': ['wvdial.conf', '.wvdialrc'],
+ \ 'xdefaults': ['.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad'],
+ \ 'xhtml': ['file.xhtml', 'file.xht'],
+ \ 'xinetd': ['/etc/xinetd.conf'],
+ \ 'xmath': ['file.msc', 'file.msf'],
+ \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.ts', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul'],
+ \ 'xmodmap': ['anyXmodmap'],
+ \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
+ \ 'xpm2': ['file.xpm2'],
+ \ 'xquery': ['file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'],
+ \ 'xs': ['file.xs'],
+ \ 'xsd': ['file.xsd'],
+ \ 'xslt': ['file.xsl', 'file.xslt'],
+ \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
+ \ 'yaml': ['file.yaml', 'file.yml'],
+ \ 'z8a': ['file.z8a'],
+ \ 'zimbu': ['file.zu'],
+ \ 'zimbutempl': ['file.zut'],
+ \ 'zsh': ['.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh'],
+ \
+ \ 'aap': ['file.aap'],
+ \ 'help': [$VIMRUNTIME . '/doc/help.txt'],
+ \ 'xpm': ['file.xpm'],
+ \ }
+
+let s:filename_case_checks = {
+ \ 'modula2': ['file.DEF', 'file.MOD'],
+ \ }
+
+func CheckItems(checks)
+ for [ft, names] in items(a:checks)
+ for i in range(0, len(names) - 1)
+ new
+ try
+ exe 'edit ' . names[i]
+ catch
+ call assert_report('cannot edit "' . names[i] . '": ' . v:errmsg)
+ endtry
+ call assert_equal(ft, &filetype, 'with file name: ' . names[i])
+ bwipe!
+ endfor
+ endfor
+endfunc
+
+func Test_filetype_detection()
+ filetype on
+ call CheckItems(s:filename_checks)
+ if has('fname_case')
+ call CheckItems(s:filename_case_checks)
+ endif
+ filetype off
+endfunc
+
+" Filetypes detected from the file contents by scripts.vim
+let s:script_checks = {
+ \ 'virata': [['% Virata'],
+ \ ['', '% Virata'],
+ \ ['', '', '% Virata'],
+ \ ['', '', '', '% Virata'],
+ \ ['', '', '', '', '% Virata']],
+ \ 'strace': [['execve("/usr/bin/pstree", ["pstree"], 0x7ff0 /* 63 vars */) = 0'],
+ \ ['15:17:47 execve("/usr/bin/pstree", ["pstree"], ... "_=/usr/bin/strace"]) = 0'],
+ \ ['__libc_start_main and something']],
+ \ }
+
+func Test_script_detection()
+ filetype on
+ for [ft, files] in items(s:script_checks)
+ for file in files
+ call writefile(file, 'Xtest')
+ split Xtest
+ call assert_equal(ft, &filetype, 'for text: ' . string(file))
+ bwipe!
+ endfor
+ endfor
+ call delete('Xtest')
+ filetype off
+endfunc
+
diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim
index ea9790d134..7aea704e86 100644
--- a/src/nvim/testdir/test_hardcopy.vim
+++ b/src/nvim/testdir/test_hardcopy.vim
@@ -50,6 +50,7 @@ endfunc
" We don't check much of the contents.
func Test_with_syntax()
if has('postscript')
+ edit test_hardcopy.vim
set printoptions=syntax:y
syn on
hardcopy > Xhardcopy
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
new file mode 100644
index 0000000000..bdad26a8c7
--- /dev/null
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -0,0 +1,92 @@
+
+" Test for insert expansion
+func Test_ins_complete()
+ edit test_ins_complete.vim
+ set ff=unix
+ call writefile(["test11\t36Gepeto\t/Tag/",
+ \ "asd\ttest11file\t36G",
+ \ "Makefile\tto\trun"], 'Xtestfile')
+ call writefile(['', 'start of testfile',
+ \ 'ru',
+ \ 'run1',
+ \ 'run2',
+ \ 'STARTTEST',
+ \ 'ENDTEST',
+ \ 'end of testfile'], 'Xtestdata')
+ set ff&
+
+ enew!
+ edit Xtestdata
+ new
+ call append(0, ['#include "Xtestfile"', ''])
+ call cursor(2, 1)
+
+ set cot=
+ set cpt=.,w
+ " add-expands (word from next line) from other window
+ exe "normal iru\<C-N>\<C-N>\<C-X>\<C-N>\<Esc>\<C-A>"
+ call assert_equal('run1 run3', getline('.'))
+ " add-expands (current buffer first)
+ exe "normal o\<C-P>\<C-X>\<C-N>"
+ call assert_equal('run3 run3', getline('.'))
+ " Local expansion, ends in an empty line (unless it becomes a global
+ " expansion)
+ exe "normal o\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>"
+ call assert_equal('', getline('.'))
+ " starts Local and switches to global add-expansion
+ exe "normal o\<C-X>\<C-P>\<C-P>\<C-X>\<C-X>\<C-N>\<C-X>\<C-N>\<C-N>"
+ call assert_equal('run1 run2', getline('.'))
+
+ set cpt=.,w,i
+ " i-add-expands and switches to local
+ exe "normal OM\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-X>\<C-X>\<C-P>"
+ call assert_equal("Makefile\tto\trun3", getline('.'))
+ " add-expands lines (it would end in an empty line if it didn't ignored
+ " itself)
+ exe "normal o\<C-X>\<C-L>\<C-X>\<C-L>\<C-P>\<C-P>"
+ call assert_equal("Makefile\tto\trun3", getline('.'))
+ call assert_equal("Makefile\tto\trun3", getline(line('.') - 1))
+
+ set cpt=kXtestfile
+ " checks k-expansion, and file expansion (use Xtest11 instead of test11,
+ " because TEST11.OUT may match first on DOS)
+ write Xtest11.one
+ write Xtest11.two
+ exe "normal o\<C-N>\<Esc>IX\<Esc>A\<C-X>\<C-F>\<C-N>"
+ call assert_equal('Xtest11.two', getline('.'))
+
+ " use CTRL-X CTRL-F to complete Xtest11.one, remove it and then use CTRL-X
+ " CTRL-F again to verify this doesn't cause trouble.
+ exe "normal oXt\<C-X>\<C-F>\<BS>\<BS>\<BS>\<BS>\<BS>\<BS>\<BS>\<BS>\<C-X>\<C-F>"
+ call assert_equal('Xtest11.one', getline('.'))
+ normal ddk
+
+ set cpt=w
+ " checks make_cyclic in other window
+ exe "normal oST\<C-N>\<C-P>\<C-P>\<C-P>\<C-P>"
+ call assert_equal('STARTTEST', getline('.'))
+
+ set cpt=u nohid
+ " checks unloaded buffer expansion
+ only
+ exe "normal oEN\<C-N>"
+ call assert_equal('ENDTEST', getline('.'))
+ " checks adding mode abortion
+ exe "normal ounl\<C-N>\<C-X>\<C-X>\<C-P>"
+ call assert_equal('unless', getline('.'))
+
+ set cpt=t,d def=^\\k* tags=Xtestfile notagbsearch
+ " tag expansion, define add-expansion interrupted
+ exe "normal o\<C-X>\<C-]>\<C-X>\<C-D>\<C-X>\<C-D>\<C-X>\<C-X>\<C-D>\<C-X>\<C-D>\<C-X>\<C-D>\<C-X>\<C-D>"
+ call assert_equal('test11file 36Gepeto /Tag/ asd', getline('.'))
+ " t-expansion
+ exe "normal oa\<C-N>\<Esc>"
+ call assert_equal('asd', getline('.'))
+
+ %bw!
+ call delete('Xtestfile')
+ call delete('Xtest11.one')
+ call delete('Xtest11.two')
+ call delete('Xtestdata')
+ set cpt& cot& def& tags& tagbsearch& hidden&
+endfunc
diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim
new file mode 100644
index 0000000000..24c6ef5e01
--- /dev/null
+++ b/src/nvim/testdir/test_let.vim
@@ -0,0 +1,27 @@
+" Tests for the :let command.
+
+func Test_let()
+ " Test to not autoload when assigning. It causes internal error.
+ set runtimepath+=./sautest
+ let Test104#numvar = function('tr')
+ call assert_equal("function('tr')", string(Test104#numvar))
+
+ let a = 1
+ let b = 2
+
+ let out = execute('let a b')
+ let s = "\na #1\nb #2"
+ call assert_equal(s, out)
+
+ let out = execute('let {0 == 1 ? "a" : "b"}')
+ let s = "\nb #2"
+ call assert_equal(s, out)
+
+ let out = execute('let {0 == 1 ? "a" : "b"} a')
+ let s = "\nb #2\na #1"
+ call assert_equal(s, out)
+
+ let out = execute('let a {0 == 1 ? "a" : "b"}')
+ let s = "\na #1\nb #2"
+ call assert_equal(s, out)
+endfunc
diff --git a/src/nvim/testdir/test_lineending.vim b/src/nvim/testdir/test_lineending.vim
new file mode 100644
index 0000000000..5be3be8db3
--- /dev/null
+++ b/src/nvim/testdir/test_lineending.vim
@@ -0,0 +1,19 @@
+" Tests for saving/loading a file with some lines ending in
+" CTRL-M, some not
+func Test_lineending()
+ let l = ["this line ends in a\<CR>",
+ \ "this one doesn't",
+ \ "this one does\<CR>",
+ \ "and the last one doesn't"]
+ set fileformat=dos
+ enew!
+ call append(0, l)
+ $delete
+ write Xfile1
+ bwipe Xfile1
+ edit Xfile1
+ let t = getline(1, '$')
+ call assert_equal(l, t)
+ new | only
+ call delete('Xfile1')
+endfunc
diff --git a/src/nvim/testdir/test_lispwords.vim b/src/nvim/testdir/test_lispwords.vim
new file mode 100644
index 0000000000..4c05504cf1
--- /dev/null
+++ b/src/nvim/testdir/test_lispwords.vim
@@ -0,0 +1,82 @@
+" Tests for 'lispwords' settings being global-local
+
+set nocompatible viminfo+=nviminfo
+
+func Test_global_local_lispwords()
+ setglobal lispwords=foo,bar,baz
+ setlocal lispwords-=foo | setlocal lispwords+=quux
+ call assert_equal('foo,bar,baz', &g:lispwords)
+ call assert_equal('bar,baz,quux', &l:lispwords)
+ call assert_equal('bar,baz,quux', &lispwords)
+
+ setlocal lispwords<
+ call assert_equal('foo,bar,baz', &g:lispwords)
+ call assert_equal('foo,bar,baz', &l:lispwords)
+ call assert_equal('foo,bar,baz', &lispwords)
+endfunc
+
+func Test_lisp_indent()
+ enew!
+
+ call append(0, [
+ \ '(defun html-file (base)',
+ \ '(format nil "~(~A~).html" base))',
+ \ '',
+ \ '(defmacro page (name title &rest body)',
+ \ '(let ((ti (gensym)))',
+ \ '`(with-open-file (*standard-output*',
+ \ '(html-file ,name)',
+ \ ':direction :output',
+ \ ':if-exists :supersede)',
+ \ '(let ((,ti ,title))',
+ \ '(as title ,ti)',
+ \ '(with center ',
+ \ '(as h2 (string-upcase ,ti)))',
+ \ '(brs 3)',
+ \ ',@body))))',
+ \ '',
+ \ ';;; Utilities for generating links',
+ \ '',
+ \ '(defmacro with-link (dest &rest body)',
+ \ '`(progn',
+ \ '(format t "<a href=\"~A\">" (html-file ,dest))',
+ \ ',@body',
+ \ '(princ "</a>")))'
+ \ ])
+ set lisp
+ set lispwords&
+ let save_copt = &cpoptions
+ set cpoptions+=p
+ normal 1G=G
+
+ call assert_equal([
+ \ '(defun html-file (base)',
+ \ ' (format nil "~(~A~).html" base))',
+ \ '',
+ \ '(defmacro page (name title &rest body)',
+ \ ' (let ((ti (gensym)))',
+ \ ' `(with-open-file (*standard-output*',
+ \ ' (html-file ,name)',
+ \ ' :direction :output',
+ \ ' :if-exists :supersede)',
+ \ ' (let ((,ti ,title))',
+ \ ' (as title ,ti)',
+ \ ' (with center ',
+ \ ' (as h2 (string-upcase ,ti)))',
+ \ ' (brs 3)',
+ \ ' ,@body))))',
+ \ '',
+ \ ';;; Utilities for generating links',
+ \ '',
+ \ '(defmacro with-link (dest &rest body)',
+ \ ' `(progn',
+ \ ' (format t "<a href=\"~A\">" (html-file ,dest))',
+ \ ' ,@body',
+ \ ' (princ "</a>")))',
+ \ ''
+ \ ], getline(1, "$"))
+
+ enew!
+ let &cpoptions=save_copt
+ set nolisp
+endfunc
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 307f62e17a..c7c0dc164c 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -2,7 +2,6 @@
source shared.vim
-set belloff=all
func! Setup_NewWindow()
10new
call setline(1, range(1,100))
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index e1ba142d1c..7f818dd40d 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -570,4 +570,41 @@ func Test_completion_clear_candidate_list()
endfunc
+func Test_popup_and_preview_autocommand()
+ " This used to crash Vim
+ if !has('python')
+ return
+ endif
+ let h = winheight(0)
+ if h < 15
+ return
+ endif
+ new
+ augroup MyBufAdd
+ au!
+ au BufAdd * nested tab sball
+ augroup END
+ set omnifunc=pythoncomplete#Complete
+ call setline(1, 'import os')
+ " make the line long
+ call setline(2, ' os.')
+ $
+ call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
+ call assert_equal(["import os", " os.EX_IOERR", ''], getline(1,'$'))
+ call assert_equal(1, winnr('$'))
+ " previewwindow option is not set
+ call assert_equal(0, &previewwindow)
+ norm! gt
+ call assert_equal(0, &previewwindow)
+ norm! gT
+ call assert_equal(12, tabpagenr('$'))
+ tabonly
+ pclose
+ augroup MyBufAdd
+ au!
+ augroup END
+ augroup! MyBufAdd
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 95a7d29089..dd177fd633 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -151,7 +151,7 @@ endfunc
func XageTests(cchar)
call s:setup_commands(a:cchar)
- let list = [{'bufnr': 1, 'lnum': 1}]
+ let list = [{'bufnr': bufnr('%'), 'lnum': 1}]
call g:Xsetlist(list)
" Jumping to a non existent list should return error
diff --git a/src/nvim/testdir/test_recover.vim b/src/nvim/testdir/test_recover.vim
new file mode 100644
index 0000000000..46d884a97c
--- /dev/null
+++ b/src/nvim/testdir/test_recover.vim
@@ -0,0 +1,63 @@
+" Test :recover
+
+func Test_recover_root_dir()
+ " This used to access invalid memory.
+ split Xtest
+ set dir=/
+ call assert_fails('recover', 'E305:')
+ close!
+
+ if has('win32') || filewritable('/') == 2
+ " can write in / directory on MS-Windows
+ set dir=/notexist/
+ endif
+ call assert_fails('split Xtest', 'E303:')
+ set dir&
+endfunc
+
+" Inserts 10000 lines with text to fill the swap file with two levels of pointer
+" blocks. Then recovers from the swap file and checks all text is restored.
+"
+" We need about 10000 lines of 100 characters to get two levels of pointer
+" blocks.
+func Test_swap_file()
+ set directory=.
+ set fileformat=unix undolevels=-1
+ edit! Xtest
+ let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
+ let i = 1
+ let linecount = 10000
+ while i <= linecount
+ call append(i - 1, i . text)
+ let i += 1
+ endwhile
+ $delete
+ preserve
+ " get the name of the swap file
+ let swname = split(execute("swapname"))[0]
+ let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
+ " make a copy of the swap file in Xswap
+ set binary
+ exe 'sp ' . swname
+ w! Xswap
+ set nobinary
+ new
+ only!
+ bwipe! Xtest
+ call rename('Xswap', swname)
+ recover Xtest
+ call delete(swname)
+ let linedollar = line('$')
+ call assert_equal(linecount, linedollar)
+ if linedollar < linecount
+ let linecount = linedollar
+ endif
+ let i = 1
+ while i <= linecount
+ call assert_equal(i . text, getline(i))
+ let i += 1
+ endwhile
+
+ set undolevels&
+ enew! | only
+endfunc
diff --git a/src/nvim/testdir/test_scrollbind.vim b/src/nvim/testdir/test_scrollbind.vim
new file mode 100644
index 0000000000..baa24f1979
--- /dev/null
+++ b/src/nvim/testdir/test_scrollbind.vim
@@ -0,0 +1,32 @@
+" Test for 'scrollbind' causing an unexpected scroll of one of the windows.
+func Test_scrollbind()
+ " We don't want the status line to cause problems:
+ set laststatus=0
+ let totalLines = &lines * 20
+ let middle = totalLines / 2
+ new | only
+ for i in range(1, totalLines)
+ call setline(i, 'LINE ' . i)
+ endfor
+ exe string(middle)
+ normal zt
+ normal M
+ aboveleft vert new
+ for i in range(1, totalLines)
+ call setline(i, 'line ' . i)
+ endfor
+ exe string(middle)
+ normal zt
+ normal M
+ " Execute the following two commands at once to reproduce the problem.
+ setl scb | wincmd p
+ setl scb
+ wincmd w
+ let topLineLeft = line('w0')
+ wincmd p
+ let topLineRight = line('w0')
+ setl noscrollbind
+ wincmd p
+ setl noscrollbind
+ call assert_equal(0, topLineLeft - topLineRight)
+endfunc
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 40e373cdd2..9456f9c438 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -1,15 +1,14 @@
" Test for the search command
-set belloff=all
func Test_search_cmdline()
" See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_disable_char_avail()'
+ throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
" need to disable char_avail,
" so that expansion of commandline works
- call test_disable_char_avail(1)
+ call test_override("char_avail", 1)
new
call setline(1, [' 1', ' 2 these', ' 3 the', ' 4 their', ' 5 there', ' 6 their', ' 7 the', ' 8 them', ' 9 these', ' 10 foobar'])
" Test 1
@@ -196,19 +195,19 @@ func Test_search_cmdline()
call assert_equal(' 3 the', getline('.'))
" clean up
- call test_disable_char_avail(0)
+ call test_override("char_avail", 0)
bw!
endfunc
func Test_search_cmdline2()
" See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_disable_char_avail()'
+ throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
" need to disable char_avail,
" so that expansion of commandline works
- call test_disable_char_avail(1)
+ call test_override("char_avail", 1)
new
call setline(1, [' 1', ' 2 these', ' 3 the theother'])
" Test 1
@@ -270,7 +269,7 @@ func Test_search_cmdline2()
" clean up
set noincsearch
- call test_disable_char_avail(0)
+ call test_override("char_avail", 0)
bw!
endfunc
@@ -306,3 +305,136 @@ func Test_searchc()
exe "norm 0t\u93cf"
bw!
endfunc
+
+func Test_search_cmdline3()
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' 1', ' 2 the~e', ' 3 the theother'])
+ set incsearch
+ 1
+ " first match
+ call feedkeys("/the\<c-l>\<cr>", 'tx')
+ call assert_equal(' 2 the~e', getline('.'))
+ " clean up
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline4()
+ " See test/functional/legacy/search_spec.lua
+ throw 'skipped: Nvim does not support test_override()'
+ if !exists('+incsearch')
+ return
+ endif
+ " need to disable char_avail,
+ " so that expansion of commandline works
+ call test_override("char_avail", 1)
+ new
+ call setline(1, [' 1 the first', ' 2 the second', ' 3 the third'])
+ set incsearch
+ $
+ call feedkeys("?the\<c-g>\<cr>", 'tx')
+ call assert_equal(' 3 the third', getline('.'))
+ $
+ call feedkeys("?the\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal(' 1 the first', getline('.'))
+ $
+ call feedkeys("?the\<c-g>\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal(' 2 the second', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<cr>", 'tx')
+ call assert_equal(' 1 the first', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<c-t>\<cr>", 'tx')
+ call assert_equal(' 3 the third', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
+ call assert_equal(' 2 the second', getline('.'))
+ " clean up
+ set noincsearch
+ call test_override("char_avail", 0)
+ bw!
+endfunc
+
+func Test_search_cmdline5()
+ if !exists('+incsearch')
+ return
+ endif
+ " Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work
+ " regardless char_avail.
+ new
+ call setline(1, [' 1 the first', ' 2 the second', ' 3 the third'])
+ set incsearch
+ 1
+ call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx')
+ call assert_equal(' 3 the third', getline('.'))
+ $
+ call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx')
+ call assert_equal(' 2 the second', getline('.'))
+ " clean up
+ set noincsearch
+ bw!
+endfunc
+
+" Tests for regexp with various magic settings
+func Test_search_regexp()
+ enew!
+
+ put ='1 a aa abb abbccc'
+ exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
+ call assert_equal([0, 2, 17, 0], getpos('.'))
+
+ put ='2 d dd dee deefff'
+ exe 'normal! /\Md\*e\{2}f\+/e' . "\<CR>"
+ call assert_equal([0, 3, 17, 0], getpos('.'))
+
+ set nomagic
+ put ='3 g gg ghh ghhiii'
+ exe 'normal! /g\*h\{2}i\+/e' . "\<CR>"
+ call assert_equal([0, 4, 17, 0], getpos('.'))
+
+ put ='4 j jj jkk jkklll'
+ exe 'normal! /\mj*k\{2}l\+/e' . "\<CR>"
+ call assert_equal([0, 5, 17, 0], getpos('.'))
+
+ put ='5 m mm mnn mnnooo'
+ exe 'normal! /\vm*n{2}o+/e' . "\<CR>"
+ call assert_equal([0, 6, 17, 0], getpos('.'))
+
+ put ='6 x ^aa$ x'
+ exe 'normal! /\V^aa$' . "\<CR>"
+ call assert_equal([0, 7, 5, 0], getpos('.'))
+
+ set magic
+ put ='7 (a)(b) abbaa'
+ exe 'normal! /\v(a)(b)\2\1\1/e' . "\<CR>"
+ call assert_equal([0, 8, 14, 0], getpos('.'))
+
+ put ='8 axx [ab]xx'
+ exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
+ call assert_equal([0, 9, 7, 0], getpos('.'))
+
+ set undolevels=100
+ put ='9 foobar'
+ put =''
+ exe "normal! a\<C-G>u\<Esc>"
+ 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('$'))
+ normal u
+ call assert_equal('9 foobar', getline('.'))
+ call assert_equal([0, 10, 6, 0], getpos('.'))
+ call assert_equal(11, line('$'))
+
+ set undolevels&
+ enew!
+endfunc
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index 75dbd74b34..a967435346 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -182,7 +182,7 @@ func Test_sign_invalid_commands()
call assert_fails('sign define Sign1 xxx', 'E475:')
call assert_fails('sign undefine', 'E156:')
call assert_fails('sign list xxx', 'E155:')
- call assert_fails('sign place 1 buffer=', 'E158:')
+ call assert_fails('sign place 1 buffer=999', 'E158:')
call assert_fails('sign define Sign2 text=', 'E239:')
endfunc
diff --git a/src/nvim/testdir/test_source_utf8.vim b/src/nvim/testdir/test_source_utf8.vim
index edb76fc43d..c29c2ec1f3 100644
--- a/src/nvim/testdir/test_source_utf8.vim
+++ b/src/nvim/testdir/test_source_utf8.vim
@@ -31,3 +31,33 @@ func Test_source_latin()
bwipe!
call delete('Xscript')
endfunc
+
+" Test for sourcing a file with CTRL-V's at the end of the line
+func Test_source_ctrl_v()
+ call writefile(['map __1 afirst',
+ \ 'map __2 asecond',
+ \ 'map __3 athird',
+ \ 'map __4 afourth',
+ \ 'map __5 afifth',
+ \ "map __1 asd\<C-V>",
+ \ "map __2 asd\<C-V>\<C-V>",
+ \ "map __3 asd\<C-V>\<C-V>",
+ \ "map __4 asd\<C-V>\<C-V>\<C-V>",
+ \ "map __5 asd\<C-V>\<C-V>\<C-V>",
+ \ ], 'Xtestfile')
+ source Xtestfile
+ enew!
+ exe "normal __1\<Esc>\<Esc>__2\<Esc>__3\<Esc>\<Esc>__4\<Esc>__5\<Esc>"
+ exe "%s/\<C-J>/0/g"
+ call assert_equal(['sd',
+ \ "map __2 asd\<Esc>secondsd\<Esc>sd0map __5 asd0fifth"],
+ \ getline(1, 2))
+
+ enew!
+ call delete('Xtestfile')
+ unmap __1
+ unmap __2
+ unmap __3
+ unmap __4
+ unmap __5
+endfunc
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index f2dfdc7019..75ce24de46 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -114,3 +114,210 @@ func Test_substitute_repeat()
call feedkeys("Qsc\<CR>y", 'tx')
bwipe!
endfunc
+
+" Tests for *sub-replace-special* and *sub-replace-expression* on :substitute.
+
+" Execute a list of :substitute command tests
+func Run_SubCmd_Tests(tests)
+ enew!
+ for t in a:tests
+ let start = line('.') + 1
+ let end = start + len(t[2]) - 1
+ exe "normal o" . t[0]
+ call cursor(start, 1)
+ exe t[1]
+ call assert_equal(t[2], getline(start, end), t[1])
+ endfor
+ enew!
+endfunc
+
+func Test_sub_cmd_1()
+ set magic
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [['A', 's/A/&&/', ['AA']],
+ \ ['B', 's/B/\&/', ['&']],
+ \ ['C123456789', 's/C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
+ \ ['D', 's/D/d/', ['d']],
+ \ ['E', 's/E/~/', ['d']],
+ \ ['F', 's/F/\~/', ['~']],
+ \ ['G', 's/G/\ugg/', ['Gg']],
+ \ ['H', 's/H/\Uh\Eh/', ['Hh']],
+ \ ['I', 's/I/\lII/', ['iI']],
+ \ ['J', 's/J/\LJ\EJ/', ['jJ']],
+ \ ['K', 's/K/\Uk\ek/', ['Kk']],
+ \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
+ \ ['mMm', 's/M/\r/', ['m', 'm']],
+ \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
+ \ ['oOo', 's/O/\n/', ["o\no"]],
+ \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
+ \ ['qQq', 's/Q/\t/', ["q\tq"]],
+ \ ['rRr', 's/R/\\/', ['r\r']],
+ \ ['sSs', 's/S/\c/', ['scs']],
+ \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
+ \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
+ \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']]
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+func Test_sub_cmd_2()
+ set nomagic
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [['A', 's/A/&&/', ['&&']],
+ \ ['B', 's/B/\&/', ['B']],
+ \ ['C123456789', 's/\mC\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\0\9\8\7\6\5\4\3\2\1/', ['C123456789987654321']],
+ \ ['D', 's/D/d/', ['d']],
+ \ ['E', 's/E/~/', ['~']],
+ \ ['F', 's/F/\~/', ['~']],
+ \ ['G', 's/G/\ugg/', ['Gg']],
+ \ ['H', 's/H/\Uh\Eh/', ['Hh']],
+ \ ['I', 's/I/\lII/', ['iI']],
+ \ ['J', 's/J/\LJ\EJ/', ['jJ']],
+ \ ['K', 's/K/\Uk\ek/', ['Kk']],
+ \ ['lLl', "s/L/\<C-V>\<C-M>/", ["l\<C-V>", 'l']],
+ \ ['mMm', 's/M/\r/', ['m', 'm']],
+ \ ['nNn', "s/N/\\\<C-V>\<C-M>/", ["n\<C-V>", 'n']],
+ \ ['oOo', 's/O/\n/', ["o\no"]],
+ \ ['pPp', 's/P/\b/', ["p\<C-H>p"]],
+ \ ['qQq', 's/Q/\t/', ["q\tq"]],
+ \ ['rRr', 's/R/\\/', ['r\r']],
+ \ ['sSs', 's/S/\c/', ['scs']],
+ \ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
+ \ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
+ \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']]
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+func Test_sub_cmd_3()
+ set nomagic
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [['aAa', "s/A/\\='\\'/", ['a\a']],
+ \ ['bBb', "s/B/\\='\\\\'/", ['b\\b']],
+ \ ['cCc', "s/C/\\='\<C-V>\<C-M>'/", ["c\<C-V>", 'c']],
+ \ ['dDd', "s/D/\\='\\\<C-V>\<C-M>'/", ["d\\\<C-V>", 'd']],
+ \ ['eEe', "s/E/\\='\\\\\<C-V>\<C-M>'/", ["e\\\\\<C-V>", 'e']],
+ \ ['fFf', "s/F/\\='\r'/", ['f', 'f']],
+ \ ['gGg', "s/G/\\='\<C-V>\<C-J>'/", ["g\<C-V>", 'g']],
+ \ ['hHh', "s/H/\\='\\\<C-V>\<C-J>'/", ["h\\\<C-V>", 'h']],
+ \ ['iIi', "s/I/\\='\\\\\<C-V>\<C-J>'/", ["i\\\\\<C-V>", 'i']],
+ \ ['jJj', "s/J/\\='\n'/", ['j', 'j']],
+ \ ['kKk', 's/K/\="\r"/', ['k', 'k']],
+ \ ['lLl', 's/L/\="\n"/', ['l', 'l']]
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+" Test for submatch() on :substitue.
+func Test_sub_cmd_4()
+ set magic&
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/",
+ \ ['a\a']],
+ \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/",
+ \ ['b\b']],
+ \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/",
+ \ ["c\<C-V>", 'c']],
+ \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/",
+ \ ["d\<C-V>", 'd']],
+ \ ['eEe', "s/E/\\=substitute(submatch(0), '.', '\\\\\<C-V>\<C-M>', '')/",
+ \ ["e\\\<C-V>", 'e']],
+ \ ['fFf', "s/F/\\=substitute(submatch(0), '.', '\\r', '')/",
+ \ ['f', 'f']],
+ \ ['gGg', 's/G/\=substitute(submatch(0), ".", "\<C-V>\<C-J>", "")/',
+ \ ["g\<C-V>", 'g']],
+ \ ['hHh', 's/H/\=substitute(submatch(0), ".", "\\\<C-V>\<C-J>", "")/',
+ \ ["h\<C-V>", 'h']],
+ \ ['iIi', 's/I/\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-J>", "")/',
+ \ ["i\\\<C-V>", 'i']],
+ \ ['jJj', "s/J/\\=substitute(submatch(0), '.', '\\n', '')/",
+ \ ['j', 'j']],
+ \ ['kKk', "s/K/\\=substitute(submatch(0), '.', '\\r', '')/",
+ \ ['k', 'k']],
+ \ ['lLl', "s/L/\\=substitute(submatch(0), '.', '\\n', '')/",
+ \ ['l', 'l']],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+func Test_sub_cmd_5()
+ set magic&
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ['A123456789', 's/A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . submatch(6) . submatch(5) . submatch(4) . submatch(3) . submatch(2) . submatch(1)/', ['A123456789987654321']],
+ \ ['B123456789', 's/B\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)/\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), submatch(3, 1), submatch(2, 1), submatch(1, 1)])/', ["[['B123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], ['2'], ['1']]"]],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+endfunc
+
+" Test for *:s%* on :substitute.
+func Test_sub_cmd_6()
+ throw "skipped: Nvim removed POSIX-related 'cpoptions' flags"
+ set magic&
+ set cpo+=/
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ['A', 's/A/a/', ['a']],
+ \ ['B', 's/B/%/', ['a']],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+
+ set cpo-=/
+ let tests = [ ['C', 's/C/c/', ['c']],
+ \ ['D', 's/D/%/', ['%']],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+
+ set cpo&
+endfunc
+
+" Test for :s replacing \n with line break.
+func Test_sub_cmd_7()
+ set magic&
+ set cpo&
+
+ " List entry format: [input, cmd, output]
+ let tests = [ ["A\<C-V>\<C-M>A", 's/A./\=submatch(0)/', ['A', 'A']],
+ \ ["B\<C-V>\<C-J>B", 's/B./\=submatch(0)/', ['B', 'B']],
+ \ ["C\<C-V>\<C-J>C", 's/C./\=strtrans(string(submatch(0, 1)))/', [strtrans("['C\<C-J>']C")]],
+ \ ["D\<C-V>\<C-J>\nD", 's/D.\nD/\=strtrans(string(submatch(0, 1)))/', [strtrans("['D\<C-J>', 'D']")]],
+ \ ["E\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>\n\<C-V>\<C-J>E", 's/E\_.\{-}E/\=strtrans(string(submatch(0, 1)))/', [strtrans("['E\<C-J>', '\<C-J>', '\<C-J>', '\<C-J>', '\<C-J>E']")]],
+ \ ]
+ call Run_SubCmd_Tests(tests)
+
+ exe "normal oQ\nQ\<Esc>k"
+ call assert_fails('s/Q[^\n]Q/\=submatch(0)."foobar"/', 'E486')
+ enew!
+endfunc
+
+func TitleString()
+ let check = 'foo' =~ 'bar'
+ return ""
+endfunc
+
+func Test_sub_cmd_8()
+ set titlestring=%{TitleString()}
+
+ enew!
+ call append(0, ['', 'test_one', 'test_two'])
+ call cursor(1,1)
+ /^test_one/s/.*/\="foo\nbar"/
+ call assert_equal('foo', getline(2))
+ call assert_equal('bar', getline(3))
+ call feedkeys(':/^test_two/s/.*/\="foo\nbar"/c', "t")
+ call feedkeys("\<CR>y", "xt")
+ call assert_equal('foo', getline(4))
+ call assert_equal('bar', getline(5))
+
+ enew!
+ set titlestring&
+endfunc
diff --git a/src/nvim/testdir/test_tab.vim b/src/nvim/testdir/test_tab.vim
new file mode 100644
index 0000000000..b847dbd962
--- /dev/null
+++ b/src/nvim/testdir/test_tab.vim
@@ -0,0 +1,45 @@
+
+" Tests for "r<Tab>" with 'smarttab' and 'expandtab' set/not set.
+" Also test that dv_ works correctly
+func Test_smarttab()
+ enew!
+ set smarttab expandtab ts=8 sw=4
+ " make sure that backspace works, no matter what termcap is used
+ exe "set t_kD=\<C-V>x7f t_kb=\<C-V>x08"
+ call append(0, ['start text',
+ \ "\t\tsome test text",
+ \ 'test text',
+ \ "\t\tother test text",
+ \ ' a cde',
+ \ ' f ghi',
+ \ 'test text',
+ \ ' Second line beginning with whitespace'
+ \ ])
+ call cursor(1, 1)
+ exe "normal /some\<CR>"
+ exe "normal r\t"
+ call assert_equal("\t\t ome test text", getline('.'))
+ set noexpandtab
+ exe "normal /other\<CR>"
+ exe "normal r\t"
+ call assert_equal("\t\t ther test text", getline('.'))
+
+ " Test replacing with Tabs and then backspacing to undo it
+ exe "normal j0wR\t\t\t\<BS>\<BS>\<BS>"
+ call assert_equal(" a cde", getline('.'))
+ " Test replacing with Tabs
+ exe "normal j0wR\t\t\t"
+ call assert_equal(" \t\thi", getline('.'))
+
+ " Test that copyindent works with expandtab set
+ set expandtab smartindent copyindent ts=8 sw=8 sts=8
+ exe "normal jo{\<CR>x"
+ call assert_equal('{', getline(line('.') - 1))
+ call assert_equal(' x', getline('.'))
+ set nosol
+ exe "normal /Second line/\<CR>"
+ exe "normal fwdv_"
+ call assert_equal(' with whitespace', getline('.'))
+ enew!
+ set expandtab& smartindent& copyindent& ts& sw& sts&
+endfunc
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 33139fcda0..180563ebbd 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -473,5 +473,24 @@ func Test_tabnext_on_buf_unload2()
endwhile
endfunc
+func Test_close_on_quitpre()
+ " This once caused a crash
+ edit Xtest
+ new
+ only
+ set bufhidden=delete
+ au QuitPre <buffer> close
+ tabnew tab1
+ tabnew tab2
+ 1tabn
+ q!
+ call assert_equal(1, tabpagenr())
+ call assert_equal(2, tabpagenr('$'))
+ " clean up
+ while tabpagenr('$') > 1
+ bwipe!
+ endwhile
+ buf Xtest
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 0d697b3f3e..d5ce193bc6 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -95,4 +95,41 @@ function Test_keyword_jump()
call delete('Xinclude')
endfunction
+" Test for jumping to a tag with 'hidden' set, with symbolic link in path of
+" tag. This only works for Unix, because of the symbolic link.
+func Test_tag_symbolic()
+ if !has('unix')
+ return
+ endif
+ set hidden
+ call delete("Xtest.dir", "rf")
+ call system("ln -s . Xtest.dir")
+ " Create a tags file with the current directory name inserted.
+ call writefile([
+ \ "SECTION_OFF " . getcwd() . "/Xtest.dir/Xtest.c /^#define SECTION_OFF 3$/",
+ \ '',
+ \ ], 'Xtags')
+ call writefile(['#define SECTION_OFF 3',
+ \ '#define NUM_SECTIONS 3'], 'Xtest.c')
+
+ " Try jumping to a tag, but with a path that contains a symbolic link. When
+ " wrong, this will give the ATTENTION message. The next space will then be
+ " eaten by hit-return, instead of moving the cursor to 'd'.
+ set tags=Xtags
+ enew!
+ call append(0, 'SECTION_OFF')
+ call cursor(1,1)
+ exe "normal \<C-]> "
+ call assert_equal('Xtest.c', expand('%:t'))
+ call assert_equal(2, col('.'))
+
+ set hidden&
+ set tags&
+ enew!
+ call delete('Xtags')
+ call delete('Xtest.c')
+ call delete("Xtest.dir", "rf")
+ %bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index 5e67f25286..684f197f5f 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -4,8 +4,7 @@ if !has('textobjects')
finish
endif
-set belloff=all
-function! CpoM(line, useM, expected)
+func CpoM(line, useM, expected)
new
if a:useM
@@ -29,16 +28,127 @@ function! CpoM(line, useM, expected)
call assert_equal(getreg('"'), a:expected[2])
q!
-endfunction
+endfunc
-function! Test_inner_block_without_cpo_M()
+func Test_inner_block_without_cpo_M()
call CpoM('(red \(blue) green)', 0, ['red \(blue', 'red \(blue', ''])
-endfunction
+endfunc
-function! Test_inner_block_with_cpo_M_left_backslash()
+func Test_inner_block_with_cpo_M_left_backslash()
call CpoM('(red \(blue) green)', 1, ['red \(blue) green', 'blue', 'red \(blue) green'])
-endfunction
+endfunc
-function! Test_inner_block_with_cpo_M_right_backslash()
+func Test_inner_block_with_cpo_M_right_backslash()
call CpoM('(red (blue\) green)', 1, ['red (blue\) green', 'blue\', 'red (blue\) green'])
-endfunction
+endfunc
+
+func Test_quote_selection_selection_exclusive()
+ new
+ call setline(1, "a 'bcde' f")
+ set selection=exclusive
+ exe "norm! fdvhi'y"
+ call assert_equal('bcde', @")
+ set selection&vim
+ bw!
+endfunc
+
+" Tests for string and html text objects
+func Test_string_html_objects()
+ enew!
+
+ let t = '"wo\"rd\\" foo'
+ put =t
+ normal! da"
+ call assert_equal('foo', getline('.'))
+
+ let t = "'foo' 'bar' 'piep'"
+ put =t
+ normal! 0va'a'rx
+ call assert_equal("xxxxxxxxxxxx'piep'", getline('.'))
+
+ let t = "bla bla `quote` blah"
+ put =t
+ normal! 02f`da`
+ call assert_equal("bla bla blah", getline('.'))
+
+ let t = 'out " in "noXno"'
+ put =t
+ normal! 0fXdi"
+ call assert_equal('out " in ""', getline('.'))
+
+ let t = "\"'\" 'blah' rep 'buh'"
+ put =t
+ normal! 03f'vi'ry
+ call assert_equal("\"'\" 'blah'yyyyy'buh'", getline('.'))
+
+ set quoteescape=+*-
+ let t = "bla `s*`d-`+++`l**` b`la"
+ put =t
+ normal! di`
+ call assert_equal("bla `` b`la", getline('.'))
+
+ let t = 'voo "nah" sdf " asdf" sdf " sdf" sd'
+ put =t
+ normal! $F"va"oha"i"rz
+ call assert_equal('voo "zzzzzzzzzzzzzzzzzzzzzzzzzzzzsd', getline('.'))
+
+ let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
+ put =t
+ normal! fXdit
+ call assert_equal('-<b>asdf<i></i>asdf</b>-', getline('.'))
+
+ let t = "-<b>asdX<i>a<i />sdf</i>asdf</b>-"
+ put =t
+ normal! 0fXdit
+ call assert_equal('-<b></b>-', getline('.'))
+
+ let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
+ put =t
+ normal! fXdat
+ call assert_equal('-<b>asdfasdf</b>-', getline('.'))
+
+ let t = "-<b>asdX<i>as<b />df</i>asdf</b>-"
+ put =t
+ normal! 0fXdat
+ call assert_equal('--', getline('.'))
+
+ let t = "-<b>\ninnertext object\n</b>"
+ put =t
+ normal! dit
+ call assert_equal('-<b></b>', getline('.'))
+
+ set quoteescape&
+ enew!
+endfunc
+
+" Tests for match() and matchstr()
+func Test_match()
+ call assert_equal("b", matchstr("abcd", ".", 0, 2))
+ call assert_equal("bc", matchstr("abcd", "..", 0, 2))
+ call assert_equal("c", matchstr("abcd", ".", 2, 0))
+ call assert_equal("a", matchstr("abcd", ".", 0, -1))
+ call assert_equal(-1, match("abcd", ".", 0, 5))
+ call assert_equal(0 , match("abcd", ".", 0, -1))
+ call assert_equal(0 , match('abc', '.', 0, 1))
+ call assert_equal(1 , match('abc', '.', 0, 2))
+ call assert_equal(2 , match('abc', '.', 0, 3))
+ call assert_equal(-1, match('abc', '.', 0, 4))
+ call assert_equal(1 , match('abc', '.', 1, 1))
+ call assert_equal(2 , match('abc', '.', 2, 1))
+ call assert_equal(-1, match('abc', '.', 3, 1))
+ call assert_equal(3 , match('abc', '$', 0, 1))
+ call assert_equal(-1, match('abc', '$', 0, 2))
+ call assert_equal(3 , match('abc', '$', 1, 1))
+ call assert_equal(3 , match('abc', '$', 2, 1))
+ call assert_equal(3 , match('abc', '$', 3, 1))
+ call assert_equal(-1, match('abc', '$', 4, 1))
+ call assert_equal(0 , match('abc', '\zs', 0, 1))
+ call assert_equal(1 , match('abc', '\zs', 0, 2))
+ call assert_equal(2 , match('abc', '\zs', 0, 3))
+ call assert_equal(3 , match('abc', '\zs', 0, 4))
+ call assert_equal(-1, match('abc', '\zs', 0, 5))
+ call assert_equal(1 , match('abc', '\zs', 1, 1))
+ call assert_equal(2 , match('abc', '\zs', 2, 1))
+ call assert_equal(3 , match('abc', '\zs', 3, 1))
+ call assert_equal(-1, match('abc', '\zs', 4, 1))
+endfunc
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 0f9f6c3310..2bc6073d52 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -3,7 +3,6 @@
" undo-able pieces. Do that by setting 'undolevels'.
" Also tests :earlier and :later.
-set belloff=all
func Test_undotree()
exe "normal Aabc\<Esc>"
set ul=100
@@ -266,3 +265,26 @@ func Test_undofile_earlier()
call delete('Xfile')
call delete('Xundofile')
endfunc
+
+" Test for undo working properly when executing commands from a register.
+" Also test this in an empty buffer.
+func Test_cmd_in_reg_undo()
+ enew!
+ let @a="Ox\<Esc>jAy\<Esc>kdd"
+ edit +/^$ test_undo.vim
+ normal @au
+ call assert_equal(0, &modified)
+ return
+ new
+ normal @au
+ call assert_equal(0, &modified)
+ only!
+ let @a=''
+endfunc
+
+func Test_redo_empty_line()
+ new
+ exe "norm\x16r\x160"
+ exe "norm."
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index d2574fc0d0..db603610da 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -1,7 +1,6 @@
" Tests for user defined commands
" Test for <mods> in user defined commands
-set belloff=all
function Test_cmdmods()
let g:mods = ''
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 6a61942025..0f2e7e493e 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -3,7 +3,6 @@ if !has('visual')
finish
endif
-set belloff=all
func Test_block_shift_multibyte()
" Uses double-wide character.
@@ -52,3 +51,104 @@ func Test_Visual_inner_quote()
normal vki'
bwipe!
endfunc
+
+" Test for visual block shift and tab characters.
+func Test_block_shift_tab()
+ enew!
+ call append(0, repeat(['one two three'], 5))
+ call cursor(1,1)
+ exe "normal i\<C-G>u"
+ exe "normal fe\<C-V>4jR\<Esc>ugvr1"
+ call assert_equal('on1 two three', getline(1))
+ call assert_equal('on1 two three', getline(2))
+ call assert_equal('on1 two three', getline(5))
+
+ enew!
+ call append(0, repeat(['abcdefghijklmnopqrstuvwxyz'], 5))
+ call cursor(1,1)
+ exe "normal \<C-V>4jI \<Esc>j<<11|D"
+ exe "normal j7|a\<Tab>\<Tab>"
+ exe "normal j7|a\<Tab>\<Tab> "
+ exe "normal j7|a\<Tab> \<Tab>\<Esc>4k13|\<C-V>4j<"
+ call assert_equal(' abcdefghijklmnopqrstuvwxyz', getline(1))
+ call assert_equal('abcdefghij', getline(2))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(3))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(4))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
+
+ %s/\s\+//g
+ call cursor(1,1)
+ exe "normal \<C-V>4jI \<Esc>j<<"
+ exe "normal j7|a\<Tab>\<Tab>"
+ exe "normal j7|a\<Tab>\<Tab>\<Tab>\<Tab>\<Tab>"
+ exe "normal j7|a\<Tab> \<Tab>\<Tab>\<Esc>4k13|\<C-V>4j3<"
+ call assert_equal(' abcdefghijklmnopqrstuvwxyz', getline(1))
+ call assert_equal('abcdefghij', getline(2))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(3))
+ call assert_equal(" abc\<Tab>\<Tab>defghijklmnopqrstuvwxyz", getline(4))
+ call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
+
+ enew!
+endfunc
+
+" Tests Blockwise Visual when there are TABs before the text.
+func Test_blockwise_visual()
+ enew!
+ call append(0, ['123456',
+ \ '234567',
+ \ '345678',
+ \ '',
+ \ 'test text test tex start here',
+ \ "\t\tsome text",
+ \ "\t\ttest text",
+ \ 'test text'])
+ call cursor(1,1)
+ exe "normal /start here$\<CR>"
+ exe 'normal "by$' . "\<C-V>jjlld"
+ exe "normal /456$\<CR>"
+ exe "normal \<C-V>jj" . '"bP'
+ call assert_equal(['123start here56',
+ \ '234start here67',
+ \ '345start here78',
+ \ '',
+ \ 'test text test tex rt here',
+ \ "\t\tsomext",
+ \ "\t\ttesext"], getline(1, 7))
+
+ enew!
+endfunc
+
+" Test Virtual replace mode.
+func Test_virtual_replace()
+ throw 'skipped: TODO: '
+ exe "set t_kD=\<C-V>x7f t_kb=\<C-V>x08"
+ enew!
+ exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz"
+ call cursor(1,1)
+ set ai bs=2
+ exe "normal gR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR"
+ call assert_equal([' 1',
+ \ ' A',
+ \ ' BCDEFGHIJ',
+ \ ' KL',
+ \ ' MNO',
+ \ ' PQR',
+ \ ], getline(1, 6))
+ normal G
+ mark a
+ inoremap <C-D> <Del>
+ exe "normal o0\<C-D>\nabcdefghi\njk\tlmn\n opq\trst\n\<C-D>uvwxyz\n"
+ exe "normal 'ajgR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" . repeat("\<BS>", 29)
+ call assert_equal([' 1',
+ \ 'abcdefghi',
+ \ 'jk lmn',
+ \ ' opq rst',
+ \ 'uvwxyz'], getline(7, 11))
+ normal G
+ exe "normal iab\tcdefghi\tjkl"
+ exe "normal 0gRAB......CDEFGHI.J\<Esc>o"
+ exe "normal iabcdefghijklmnopqrst\<Esc>0gRAB\tIJKLMNO\tQR"
+ call assert_equal(['AB......CDEFGHI.Jkl',
+ \ 'AB IJKLMNO QRst'], getline(12, 13))
+ enew!
+endfunc
diff --git a/src/nvim/testdir/test_winbuf_close.vim b/src/nvim/testdir/test_winbuf_close.vim
new file mode 100644
index 0000000000..ed64dd79b7
--- /dev/null
+++ b/src/nvim/testdir/test_winbuf_close.vim
@@ -0,0 +1,124 @@
+" Test for commands that close windows and/or buffers:
+" :quit
+" :close
+" :hide
+" :only
+" :sall
+" :all
+" :ball
+" :buf
+" :edit
+"
+func Test_winbuf_close()
+ enew | only
+
+ call writefile(['testtext 1'], 'Xtest1')
+ call writefile(['testtext 2'], 'Xtest2')
+ call writefile(['testtext 3'], 'Xtest3')
+
+ next! Xtest1 Xtest2
+ call setline(1, 'testtext 1 1')
+
+ " test for working :n when hidden set
+ set hidden
+ next
+ call assert_equal('Xtest2', bufname('%'))
+
+ " test for failing :rew when hidden not set
+ set nohidden
+ call setline(1, 'testtext 2 2')
+ call assert_fails('rewind', 'E37')
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2', getline(1))
+
+ " test for working :rew when hidden set
+ set hidden
+ rewind
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1 1', getline(1))
+
+ " test for :all keeping a buffer when it's modified
+ set nohidden
+ call setline(1, 'testtext 1 1 1')
+ split
+ next Xtest2 Xtest3
+ all
+ 1wincmd w
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1 1 1', getline(1))
+
+ " test abandoning changed buffer, should be unloaded even when 'hidden' set
+ set hidden
+ call setline(1, 'testtext 1 1 1 1')
+ quit!
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2', getline(1))
+ unhide
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2', getline(1))
+
+ " test ":hide" hides anyway when 'hidden' not set
+ set nohidden
+ call setline(1, 'testtext 2 2 2')
+ hide
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_equal('testtext 3', getline(1))
+
+ " test ":edit" failing in modified buffer when 'hidden' not set
+ call setline(1, 'testtext 3 3')
+ call assert_fails('edit Xtest1', 'E37')
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_equal('testtext 3 3', getline(1))
+
+ " test ":edit" working in modified buffer when 'hidden' set
+ set hidden
+ edit Xtest1
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1', getline(1))
+
+ " test ":close" not hiding when 'hidden' not set in modified buffer
+ split Xtest3
+ set nohidden
+ call setline(1, 'testtext 3 3 3')
+ call assert_fails('close', 'E37')
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_equal('testtext 3 3 3', getline(1))
+
+ " test ":close!" does hide when 'hidden' not set in modified buffer;
+ call setline(1, 'testtext 3 3 3 3')
+ close!
+ call assert_equal('Xtest1', bufname('%'))
+ call assert_equal('testtext 1', getline(1))
+
+ set nohidden
+
+ " test ":all!" hides changed buffer
+ split Xtest4
+ call setline(1, 'testtext 4')
+ all!
+ 1wincmd w
+ call assert_equal('Xtest2', bufname('%'))
+ call assert_equal('testtext 2 2 2', getline(1))
+
+ " test ":q!" and hidden buffer.
+ bwipe! Xtest1 Xtest2 Xtest3 Xtest4
+ split Xtest1
+ wincmd w
+ bwipe!
+ set modified
+ bot split Xtest2
+ set modified
+ bot split Xtest3
+ set modified
+ wincmd t
+ hide
+ call assert_equal('Xtest2', bufname('%'))
+ quit!
+ call assert_equal('Xtest3', bufname('%'))
+ call assert_fails('silent! quit!', 'E162')
+ call assert_equal('Xtest1', bufname('%'))
+
+ call delete('Xtest1')
+ call delete('Xtest2')
+ call delete('Xtest3')
+endfunc
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 9d61921988..139d29a48b 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -306,20 +306,14 @@ func Test_window_width()
set winfixwidth
vsplit Xc
let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
- " FIXME: commented out: I would expect the width of 2nd window to
- " remain 2 but it's actually 1?!
- "call assert_equal(2, winwidth(2))
+ call assert_equal(2, winwidth(2))
call assert_inrange(ww3, ww3 + 1, ww1)
3wincmd >
- " FIXME: commented out: I would expect the width of 2nd window to
- " remain 2 but it's actually 1?!
- "call assert_equal(2, winwidth(2))
+ call assert_equal(2, winwidth(2))
call assert_equal(ww1 + 3, winwidth(1))
call assert_equal(ww3 - 3, winwidth(3))
wincmd =
- " FIXME: commented out: I would expect the width of 2nd window to
- " remain 2 but it's actually 1?!
- "call assert_equal(2, winwidth(2))
+ call assert_equal(2, winwidth(2))
call assert_equal(ww1, winwidth(1))
call assert_equal(ww3, winwidth(3))
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 70e19e1d93..62bdc61a68 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -125,7 +125,6 @@ UI *tui_start(void)
{
UI *ui = xcalloc(1, sizeof(UI)); // Freed by ui_bridge_stop().
ui->stop = tui_stop;
- ui->rgb = p_tgc;
ui->resize = tui_resize;
ui->clear = tui_clear;
ui->eol_clear = tui_eol_clear;
@@ -143,15 +142,12 @@ UI *tui_start(void)
ui->put = tui_put;
ui->bell = tui_bell;
ui->visual_bell = tui_visual_bell;
- ui->update_fg = tui_update_fg;
- ui->update_bg = tui_update_bg;
- ui->update_sp = tui_update_sp;
+ ui->default_colors_set = tui_default_colors_set;
ui->flush = tui_flush;
ui->suspend = tui_suspend;
ui->set_title = tui_set_title;
ui->set_icon = tui_set_icon;
ui->option_set= tui_option_set;
- ui->event = tui_event;
memset(ui->ui_ext, 0, sizeof(ui->ui_ext));
@@ -410,36 +406,58 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
ui_schedule_refresh();
}
-static bool attrs_differ(HlAttrs a1, HlAttrs a2)
+static bool attrs_differ(HlAttrs a1, HlAttrs a2, bool rgb)
{
- return a1.foreground != a2.foreground || a1.background != a2.background
- || a1.bold != a2.bold || a1.italic != a2.italic
- || a1.undercurl != a2.undercurl || a1.underline != a2.underline
- || a1.reverse != a2.reverse;
+ if (rgb) {
+ // TODO(bfredl): when we start to support special color,
+ // rgb_sp_color must be added here
+ return a1.rgb_fg_color != a2.rgb_fg_color
+ || a1.rgb_bg_color != a2.rgb_bg_color
+ || a1.rgb_ae_attr != a2.rgb_ae_attr;
+ } else {
+ return a1.cterm_fg_color != a2.cterm_fg_color
+ || a1.cterm_bg_color != a2.cterm_bg_color
+ || a1.cterm_ae_attr != a2.cterm_ae_attr;
+ }
}
static void update_attrs(UI *ui, HlAttrs attrs)
{
TUIData *data = ui->data;
- if (!attrs_differ(attrs, data->print_attrs)) {
+ if (!attrs_differ(attrs, data->print_attrs, ui->rgb)) {
return;
}
data->print_attrs = attrs;
UGrid *grid = &data->grid;
- int fg = attrs.foreground != -1 ? attrs.foreground : grid->fg;
- int bg = attrs.background != -1 ? attrs.background : grid->bg;
+ int fg = ui->rgb ? attrs.rgb_fg_color : (attrs.cterm_fg_color - 1);
+ if (fg == -1) {
+ fg = ui->rgb ? grid->clear_attrs.rgb_fg_color
+ : (grid->clear_attrs.cterm_fg_color - 1);
+ }
+
+ int bg = ui->rgb ? attrs.rgb_bg_color : (attrs.cterm_bg_color - 1);
+ if (bg == -1) {
+ bg = ui->rgb ? grid->clear_attrs.rgb_bg_color
+ : (grid->clear_attrs.cterm_bg_color - 1);
+ }
+
+ int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
+ bool bold = attr & HL_BOLD;
+ bool italic = attr & HL_ITALIC;
+ bool reverse = attr & (HL_INVERSE | HL_STANDOUT);
+ bool underline = attr & (HL_UNDERLINE), undercurl = attr & (HL_UNDERCURL);
if (unibi_get_str(data->ut, unibi_set_attributes)) {
- if (attrs.bold || attrs.reverse || attrs.underline || attrs.undercurl) {
+ if (bold || reverse || underline || undercurl) {
UNIBI_SET_NUM_VAR(data->params[0], 0); // standout
- UNIBI_SET_NUM_VAR(data->params[1], attrs.underline || attrs.undercurl);
- UNIBI_SET_NUM_VAR(data->params[2], attrs.reverse);
+ UNIBI_SET_NUM_VAR(data->params[1], underline || undercurl);
+ UNIBI_SET_NUM_VAR(data->params[2], reverse);
UNIBI_SET_NUM_VAR(data->params[3], 0); // blink
UNIBI_SET_NUM_VAR(data->params[4], 0); // dim
- UNIBI_SET_NUM_VAR(data->params[5], attrs.bold);
+ UNIBI_SET_NUM_VAR(data->params[5], bold);
UNIBI_SET_NUM_VAR(data->params[6], 0); // blank
UNIBI_SET_NUM_VAR(data->params[7], 0); // protect
UNIBI_SET_NUM_VAR(data->params[8], 0); // alternate character set
@@ -451,17 +469,17 @@ static void update_attrs(UI *ui, HlAttrs attrs)
if (!data->default_attr) {
unibi_out(ui, unibi_exit_attribute_mode);
}
- if (attrs.bold) {
+ if (bold) {
unibi_out(ui, unibi_enter_bold_mode);
}
- if (attrs.underline || attrs.undercurl) {
+ if (underline || undercurl) {
unibi_out(ui, unibi_enter_underline_mode);
}
- if (attrs.reverse) {
+ if (reverse) {
unibi_out(ui, unibi_enter_reverse_mode);
}
}
- if (attrs.italic) {
+ if (italic) {
unibi_out(ui, unibi_enter_italics_mode);
}
if (ui->rgb) {
@@ -491,8 +509,7 @@ static void update_attrs(UI *ui, HlAttrs attrs)
}
data->default_attr = fg == -1 && bg == -1
- && !attrs.bold && !attrs.italic && !attrs.underline && !attrs.undercurl
- && !attrs.reverse;
+ && !bold && !italic && !underline && !undercurl && !reverse;
}
static void final_column_wrap(UI *ui)
@@ -534,7 +551,7 @@ static bool cheap_to_print(UI *ui, int row, int col, int next)
UCell *cell = grid->cells[row] + col;
while (next) {
next--;
- if (attrs_differ(cell->attrs, data->print_attrs)) {
+ if (attrs_differ(cell->attrs, data->print_attrs, ui->rgb)) {
if (data->default_attr) {
return false;
}
@@ -659,13 +676,12 @@ static void clear_region(UI *ui, int top, int bot, int left, int right)
int saved_col = grid->col;
bool cleared = false;
- if (grid->bg == -1 && right == ui->width -1) {
+ bool nobg = ui->rgb ? grid->clear_attrs.rgb_bg_color == -1
+ : grid->clear_attrs.cterm_bg_color == 0;
+ if (nobg && right == ui->width -1) {
// Background is set to the default color and the right edge matches the
// screen end, try to use terminal codes for clearing the requested area.
- HlAttrs clear_attrs = HLATTRS_INIT;
- clear_attrs.foreground = grid->fg;
- clear_attrs.background = grid->bg;
- update_attrs(ui, clear_attrs);
+ update_attrs(ui, grid->clear_attrs);
if (left == 0) {
if (bot == ui->height - 1) {
if (top == 0) {
@@ -788,6 +804,7 @@ static void tui_clear(UI *ui)
TUIData *data = ui->data;
UGrid *grid = &data->grid;
ugrid_clear(grid);
+ kv_size(data->invalid_regions) = 0;
clear_region(ui, grid->top, grid->bot, grid->left, grid->right);
}
@@ -905,7 +922,7 @@ static void tui_set_mode(UI *ui, ModeShape mode)
if (c.id != 0 && ui->rgb) {
int attr = syn_id2attr(c.id);
if (attr > 0) {
- attrentry_T *aep = syn_cterm_attr2entry(attr);
+ HlAttrs *aep = syn_cterm_attr2entry(attr);
UNIBI_SET_NUM_VAR(data->params[0], aep->rgb_bg_color);
unibi_out_ext(ui, data->unibi_ext.set_cursor_color);
}
@@ -960,10 +977,7 @@ static void tui_scroll(UI *ui, Integer count)
cursor_goto(ui, grid->top, grid->left);
// also set default color attributes or some terminals can become funny
if (scroll_clears_to_current_colour) {
- HlAttrs clear_attrs = HLATTRS_INIT;
- clear_attrs.foreground = grid->fg;
- clear_attrs.background = grid->bg;
- update_attrs(ui, clear_attrs);
+ update_attrs(ui, grid->clear_attrs);
}
if (count > 0) {
@@ -1028,19 +1042,16 @@ static void tui_visual_bell(UI *ui)
unibi_out(ui, unibi_flash_screen);
}
-static void tui_update_fg(UI *ui, Integer fg)
-{
- ((TUIData *)ui->data)->grid.fg = (int)fg;
-}
-
-static void tui_update_bg(UI *ui, Integer bg)
-{
- ((TUIData *)ui->data)->grid.bg = (int)bg;
-}
-
-static void tui_update_sp(UI *ui, Integer sp)
+static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,
+ Integer rgb_sp,
+ Integer cterm_fg, Integer cterm_bg)
{
- // Do nothing; 'special' color is for GUI only
+ UGrid *grid = &((TUIData *)ui->data)->grid;
+ grid->clear_attrs.rgb_fg_color = (int)rgb_fg;
+ grid->clear_attrs.rgb_bg_color = (int)rgb_bg;
+ grid->clear_attrs.rgb_sp_color = (int)rgb_sp;
+ grid->clear_attrs.cterm_fg_color = (int)cterm_fg;
+ grid->clear_attrs.cterm_bg_color = (int)cterm_bg;
}
static void tui_flush(UI *ui)
@@ -1065,6 +1076,7 @@ static void tui_flush(UI *ui)
while (kv_size(data->invalid_regions)) {
Rect r = kv_pop(data->invalid_regions);
+ assert(r.bot < grid->height && r.right < grid->width);
UGRID_FOREACH_CELL(grid, r.top, r.bot, r.left, r.right, {
cursor_goto(ui, row, col);
print_cell(ui, cell);
@@ -1149,18 +1161,13 @@ static void tui_set_icon(UI *ui, String icon)
static void tui_option_set(UI *ui, String name, Object value)
{
+ TUIData *data = ui->data;
if (strequal(name.data, "termguicolors")) {
- // NB: value for bridge is set in ui_bridge.c
ui->rgb = value.data.boolean;
+ invalidate(ui, 0, data->grid.height-1, 0, data->grid.width-1);
}
}
-// NB: if we start to use this, the ui_bridge must be updated
-// to make a copy for the tui thread
-static void tui_event(UI *ui, char *name, Array args, bool *args_consumed)
-{
-}
-
static void invalidate(UI *ui, int top, int bot, int left, int right)
{
TUIData *data = ui->data;
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index e0880b4c76..6d420ef2f8 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -17,7 +17,7 @@
void ugrid_init(UGrid *grid)
{
grid->attrs = HLATTRS_INIT;
- grid->fg = grid->bg = -1;
+ grid->clear_attrs = HLATTRS_INIT;
grid->cells = NULL;
}
@@ -107,6 +107,7 @@ UCell *ugrid_put(UGrid *grid, uint8_t *text, size_t size)
UCell *cell = grid->cells[grid->row] + grid->col;
cell->data[size] = 0;
cell->attrs = grid->attrs;
+ assert(size <= CELLBYTES);
if (text) {
memcpy(cell->data, text, size);
@@ -118,9 +119,7 @@ UCell *ugrid_put(UGrid *grid, uint8_t *text, size_t size)
static void clear_region(UGrid *grid, int top, int bot, int left, int right)
{
- HlAttrs clear_attrs = HLATTRS_INIT;
- clear_attrs.foreground = grid->fg;
- clear_attrs.background = grid->bg;
+ HlAttrs clear_attrs = grid->clear_attrs;
UGRID_FOREACH_CELL(grid, top, bot, left, right, {
cell->data[0] = ' ';
cell->data[1] = 0;
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index 1cf047502d..60c9068eb1 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -7,15 +7,17 @@
typedef struct ucell UCell;
typedef struct ugrid UGrid;
+#define CELLBYTES (4 * (MAX_MCO+1))
+
struct ucell {
- char data[6 * MAX_MCO + 1];
+ char data[CELLBYTES + 1];
HlAttrs attrs;
};
struct ugrid {
int top, bot, left, right;
int row, col;
- int bg, fg;
+ HlAttrs clear_attrs;
int width, height;
HlAttrs attrs;
UCell **cells;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 8aec923538..e8f5477db0 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -55,7 +55,7 @@ static int row = 0, col = 0;
static struct {
int top, bot, left, right;
} sr;
-static int current_attr_code = 0;
+static int current_attr_code = -1;
static bool pending_cursor_update = false;
static int busy = 0;
static int height, width;
@@ -107,8 +107,9 @@ static char uilog_last_event[1024] = { 0 };
} \
} while (0)
#endif
-#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, ZERO, ignore)
-#define SELECT_NTH(a1, a2, a3, a4, a5, a6, ...) a6
+#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, \
+ MORE, MORE, ZERO, ignore)
+#define SELECT_NTH(a1, a2, a3, a4, a5, a6, a7, ...) a7
#define UI_CALL_HELPER(c, ...) UI_CALL_HELPER2(c, __VA_ARGS__)
// Resolves to UI_CALL_MORE or UI_CALL_ZERO.
#define UI_CALL_HELPER2(c, ...) UI_CALL_##c(__VA_ARGS__)
@@ -151,6 +152,9 @@ bool ui_is_stopped(UI *ui)
bool ui_rgb_attached(void)
{
+ if (!headless_mode && p_tgc) {
+ return true;
+ }
for (size_t i = 0; i < ui_count; i++) {
if (uis[i]->rgb) {
return true;
@@ -174,84 +178,57 @@ void ui_event(char *name, Array args)
}
-/// Converts an attrentry_T into an HlAttrs
+/// Converts an HlAttrs into Dictionary
///
/// @param[in] aep data to convert
/// @param use_rgb use 'gui*' settings if true, else resorts to 'cterm*'
-HlAttrs attrentry2hlattrs(const attrentry_T *aep, bool use_rgb)
+Dictionary hlattrs2dict(const HlAttrs *aep, bool use_rgb)
{
assert(aep);
-
- HlAttrs attrs = HLATTRS_INIT;
- int mask = 0;
-
- mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr;
-
- attrs.bold = mask & HL_BOLD;
- attrs.underline = mask & HL_UNDERLINE;
- attrs.undercurl = mask & HL_UNDERCURL;
- attrs.italic = mask & HL_ITALIC;
- attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT);
-
- if (use_rgb) {
- if (aep->rgb_fg_color != -1) {
- attrs.foreground = aep->rgb_fg_color;
- }
-
- if (aep->rgb_bg_color != -1) {
- attrs.background = aep->rgb_bg_color;
- }
-
- if (aep->rgb_sp_color != -1) {
- attrs.special = aep->rgb_sp_color;
- }
- } else {
- if (cterm_normal_fg_color != aep->cterm_fg_color) {
- attrs.foreground = aep->cterm_fg_color - 1;
- }
-
- if (cterm_normal_bg_color != aep->cterm_bg_color) {
- attrs.background = aep->cterm_bg_color - 1;
- }
- }
-
- return attrs;
-}
-
-Dictionary hlattrs2dict(HlAttrs attrs)
-{
Dictionary hl = ARRAY_DICT_INIT;
+ int mask = use_rgb ? aep->rgb_ae_attr : aep->cterm_ae_attr;
- if (attrs.bold) {
+ if (mask & HL_BOLD) {
PUT(hl, "bold", BOOLEAN_OBJ(true));
}
- if (attrs.underline) {
+ if (mask & HL_UNDERLINE) {
PUT(hl, "underline", BOOLEAN_OBJ(true));
}
- if (attrs.undercurl) {
+ if (mask & HL_UNDERCURL) {
PUT(hl, "undercurl", BOOLEAN_OBJ(true));
}
- if (attrs.italic) {
+ if (mask & HL_ITALIC) {
PUT(hl, "italic", BOOLEAN_OBJ(true));
}
- if (attrs.reverse) {
+ if (mask & (HL_INVERSE | HL_STANDOUT)) {
PUT(hl, "reverse", BOOLEAN_OBJ(true));
}
- if (attrs.foreground != -1) {
- PUT(hl, "foreground", INTEGER_OBJ(attrs.foreground));
- }
- if (attrs.background != -1) {
- PUT(hl, "background", INTEGER_OBJ(attrs.background));
- }
+ if (use_rgb) {
+ if (aep->rgb_fg_color != -1) {
+ PUT(hl, "foreground", INTEGER_OBJ(aep->rgb_fg_color));
+ }
- if (attrs.special != -1) {
- PUT(hl, "special", INTEGER_OBJ(attrs.special));
+ if (aep->rgb_bg_color != -1) {
+ PUT(hl, "background", INTEGER_OBJ(aep->rgb_bg_color));
+ }
+
+ if (aep->rgb_sp_color != -1) {
+ PUT(hl, "special", INTEGER_OBJ(aep->rgb_sp_color));
+ }
+ } else {
+ if (cterm_normal_fg_color != aep->cterm_fg_color) {
+ PUT(hl, "foreground", INTEGER_OBJ(aep->cterm_fg_color - 1));
+ }
+
+ if (cterm_normal_bg_color != aep->cterm_bg_color) {
+ PUT(hl, "background", INTEGER_OBJ(aep->cterm_bg_color - 1));
+ }
}
return hl;
@@ -296,6 +273,7 @@ void ui_refresh(void)
ui_mode_info_set();
old_mode_idx = -1;
ui_cursor_shape();
+ current_attr_code = -1;
}
static void ui_refresh_event(void **argv)
@@ -313,6 +291,11 @@ void ui_resize(int new_width, int new_height)
width = new_width;
height = new_height;
+ // TODO(bfredl): update default colors when they changed, NOT on resize.
+ ui_call_default_colors_set(normal_fg, normal_bg, normal_sp,
+ cterm_normal_fg_color, cterm_normal_bg_color);
+
+ // Deprecated:
UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1));
UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1));
UI_CALL(update_sp, (ui->rgb ? normal_sp : -1));
@@ -406,26 +389,28 @@ void ui_reset_scroll_region(void)
ui_call_set_scroll_region(sr.top, sr.bot, sr.left, sr.right);
}
-void ui_start_highlight(int attr_code)
+void ui_set_highlight(int attr_code)
{
+ if (current_attr_code == attr_code) {
+ return;
+ }
current_attr_code = attr_code;
- if (!ui_active()) {
- return;
+ HlAttrs attrs = HLATTRS_INIT;
+
+ if (attr_code != 0) {
+ HlAttrs *aep = syn_cterm_attr2entry(attr_code);
+ if (aep) {
+ attrs = *aep;
+ }
}
- set_highlight_args(current_attr_code);
+ UI_CALL(highlight_set, attrs);
}
-void ui_stop_highlight(void)
+void ui_clear_highlight(void)
{
- current_attr_code = HL_NORMAL;
-
- if (!ui_active()) {
- return;
- }
-
- set_highlight_args(current_attr_code);
+ ui_set_highlight(0);
}
void ui_puts(uint8_t *str)
@@ -453,6 +438,13 @@ void ui_puts(uint8_t *str)
ui_linefeed();
}
p += clen;
+
+ if (p_wd) { // 'writedelay': flush & delay each time.
+ ui_flush();
+ assert(p_wd >= 0
+ && (sizeof(long) <= sizeof(uint64_t) || p_wd <= UINT64_MAX));
+ os_delay((uint64_t)p_wd, false);
+ }
}
}
@@ -496,26 +488,6 @@ void ui_flush(void)
ui_call_flush();
}
-static void set_highlight_args(int attr_code)
-{
- HlAttrs rgb_attrs = HLATTRS_INIT;
- HlAttrs cterm_attrs = rgb_attrs;
-
- if (attr_code == HL_NORMAL) {
- goto end;
- }
- attrentry_T *aep = syn_cterm_attr2entry(attr_code);
-
- if (!aep) {
- goto end;
- }
-
- rgb_attrs = attrentry2hlattrs(aep, true);
- cterm_attrs = attrentry2hlattrs(aep, false);
-
-end:
- UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs));
-}
void ui_linefeed(void)
{
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 0e40a1a215..60adcb974f 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -16,14 +16,6 @@ typedef enum {
} UIWidget;
#define UI_WIDGETS (kUIWildmenu + 1)
-typedef struct {
- bool bold, underline, undercurl, italic, reverse;
- int foreground, background, special;
-} HlAttrs;
-
-#define HLATTRS_INIT \
- ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
-
typedef struct ui_t UI;
struct ui_t {
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 16dd42ebaa..b0f8905771 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -59,9 +59,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.put = ui_bridge_put;
rv->bridge.bell = ui_bridge_bell;
rv->bridge.visual_bell = ui_bridge_visual_bell;
- rv->bridge.update_fg = ui_bridge_update_fg;
- rv->bridge.update_bg = ui_bridge_update_bg;
- rv->bridge.update_sp = ui_bridge_update_sp;
+ rv->bridge.default_colors_set = ui_bridge_default_colors_set;
rv->bridge.flush = ui_bridge_flush;
rv->bridge.suspend = ui_bridge_suspend;
rv->bridge.set_title = ui_bridge_set_title;
@@ -146,29 +144,6 @@ static void ui_bridge_highlight_set_event(void **argv)
xfree(argv[1]);
}
-static void ui_bridge_option_set(UI *ui, String name, Object value)
-{
- // Assumes bridge is only used by TUI
- if (strequal(name.data, "termguicolors")) {
- ui->rgb = value.data.boolean;
- }
- String copy_name = copy_string(name);
- Object *copy_value = xmalloc(sizeof(Object));
- *copy_value = copy_object(value);
- UI_BRIDGE_CALL(ui, option_set, 4, ui,
- copy_name.data, INT2PTR(copy_name.size), copy_value);
-}
-static void ui_bridge_option_set_event(void **argv)
-{
- UI *ui = UI(argv[0]);
- String name = (String){ .data = argv[1], .size = (size_t)argv[2] };
- Object value = *(Object *)argv[3];
- ui->option_set(ui, name, value);
- api_free_string(name);
- api_free_object(value);
- xfree(argv[3]);
-}
-
static void ui_bridge_suspend(UI *b)
{
UIBridgeData *data = (UIBridgeData *)b;
diff --git a/src/nvim/version.c b/src/nvim/version.c
index c95be072cf..5fd94fcee8 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -78,6 +78,22 @@ NULL
// clang-format off
static const int included_patches[] = {
+ 1435,
+ // 1434,
+ // 1433,
+ // 1432,
+ // 1431,
+ // 1430,
+ // 1429,
+ // 1428,
+ // 1427,
+ // 1426,
+ // 1425,
+ // 1424,
+ // 1423,
+ // 1422,
+ // 1421,
+ // 1420,
1419,
// 1418,
// 1417,
@@ -1039,7 +1055,7 @@ static const int included_patches[] = {
461,
// 460,
459,
- // 458,
+ 458,
457,
// 456,
// 455,
@@ -1063,7 +1079,7 @@ static const int included_patches[] = {
437,
// 436,
// 435,
- // 434,
+ 434,
433,
// 432,
431,
@@ -1073,7 +1089,7 @@ static const int included_patches[] = {
427,
426,
// 425,
- // 424,
+ 424,
423,
// 422,
421,
@@ -1312,7 +1328,7 @@ static const int included_patches[] = {
188,
187,
186,
- // 185,
+ 185,
// 184,
183,
182,
@@ -1322,7 +1338,7 @@ static const int included_patches[] = {
178,
177,
176,
- // 175,
+ 175,
174,
173,
172,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index b932c2d0f8..0c13d331c8 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -313,4 +313,8 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
# define OPEN_CHR_FILES
#endif
+// Replacement for nchar used by nv_replace().
+#define REPLACE_CR_NCHAR -1
+#define REPLACE_NL_NCHAR -2
+
#endif // NVIM_VIM_H
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 4dfc72f212..8d7e20bb73 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -641,11 +641,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (oldwin->w_width - new_size - 1 < p_wmw)
do_equal = TRUE;
- /* We don't like to take lines for the new window from a
- * 'winfixwidth' window. Take them from a window to the left or right
- * instead, if possible. */
- if (oldwin->w_p_wfw)
- win_setwidth_win(oldwin->w_width + new_size, oldwin);
+ // We don't like to take lines for the new window from a
+ // 'winfixwidth' window. Take them from a window to the left or right
+ // instead, if possible. Add one for the separator.
+ if (oldwin->w_p_wfw) {
+ win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
+ }
/* Only make all windows the same width if one of them (except oldwin)
* is wider than one of the split windows. */
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 39db831fe3..1faed4e9b1 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -11,6 +11,7 @@ local funcs = helpers.funcs
local request = helpers.request
local meth_pcall = helpers.meth_pcall
local command = helpers.command
+local iswin = helpers.iswin
local intchar2lua = global_helpers.intchar2lua
local format_string = global_helpers.format_string
@@ -99,8 +100,9 @@ describe('api', function()
[[echo nvim_command_output('echo "nested1\nnested2"') | ls]]))
end)
- it('does not return shell |:!| output', function()
- eq(':!echo "foo"\r\n', nvim('command_output', [[!echo "foo"]]))
+ it('returns shell |:!| output', function()
+ local win_lf = iswin() and '\r' or ''
+ eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]]))
end)
it("parse error: fails (specific error), does NOT update v:errmsg", function()
@@ -951,9 +953,20 @@ describe('api', function()
end
end)
if not err then
- msg = format_string('Error while processing test (%r, %s):\n%s',
- str, FLAGS_TO_STR[flags], msg)
- error(msg)
+ if type(msg) == 'table' then
+ local merr, new_msg = pcall(
+ format_string, 'table error:\n%s\n\n(%r)', msg.message, msg)
+ if merr then
+ msg = new_msg
+ else
+ msg = format_string('table error without .message:\n(%r)',
+ msg)
+ end
+ elseif type(msg) ~= 'string' then
+ msg = format_string('non-string non-table error:\n%r', msg)
+ end
+ error(format_string('Error while processing test (%r, %s):\n%s',
+ str, FLAGS_TO_STR[flags], msg))
end
end
end
diff --git a/test/functional/eval/backtick_expansion_spec.lua b/test/functional/eval/backtick_expansion_spec.lua
index 81e8e295fa..b1b44cfa8b 100644
--- a/test/functional/eval/backtick_expansion_spec.lua
+++ b/test/functional/eval/backtick_expansion_spec.lua
@@ -21,11 +21,19 @@ describe("backtick expansion", function()
end)
it("with default 'shell'", function()
- if helpers.pending_win32(pending) then return end -- Need win32 shell fixes
- command(":silent args `echo ***2`")
+ if helpers.iswin() then
+ command(":silent args `dir /b *2`")
+ else
+ command(":silent args `echo ***2`")
+ end
eq({ "file2", }, eval("argv()"))
- command(":silent args `echo */*4`")
- eq({ "subdir/file4", }, eval("argv()"))
+ if helpers.iswin() then
+ command(":silent args `dir /s/b *4`")
+ eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')"))
+ else
+ command(":silent args `echo */*4`")
+ eq({ "subdir/file4", }, eval("argv()"))
+ end
end)
it("with shell=fish", function()
diff --git a/test/functional/eval/execute_spec.lua b/test/functional/eval/execute_spec.lua
index 91966ed3dd..183884a51e 100644
--- a/test/functional/eval/execute_spec.lua
+++ b/test/functional/eval/execute_spec.lua
@@ -9,6 +9,7 @@ local funcs = helpers.funcs
local Screen = require('test.functional.ui.screen')
local command = helpers.command
local feed = helpers.feed
+local iswin = helpers.iswin
describe('execute()', function()
before_each(clear)
@@ -118,9 +119,11 @@ describe('execute()', function()
feed('<CR>')
end)
- -- This matches Vim behavior.
- it('does not capture shell-command output', function()
- eq('\n:!echo "foo"\13\n', funcs.execute('!echo "foo"'))
+ -- This deviates from vim behavior, but is consistent
+ -- with how nvim currently displays the output.
+ it('does capture shell-command output', function()
+ local win_lf = iswin() and '\13' or ''
+ eq('\n:!echo foo\r\n\nfoo'..win_lf..'\n', funcs.execute('!echo foo'))
end)
describe('{silent} argument', function()
diff --git a/test/functional/ex_cmds/bang_filter_spec.lua b/test/functional/ex_cmds/bang_filter_spec.lua
deleted file mode 100644
index aaec983b73..0000000000
--- a/test/functional/ex_cmds/bang_filter_spec.lua
+++ /dev/null
@@ -1,51 +0,0 @@
--- Specs for bang/filter commands
-
-local helpers = require('test.functional.helpers')(after_each)
-local feed, command, clear = helpers.feed, helpers.command, helpers.clear
-local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
-
-if helpers.pending_win32(pending) then return end
-
-local Screen = require('test.functional.ui.screen')
-
-
-describe('issues', function()
- local screen
-
- before_each(function()
- clear()
- rmdir('bang_filter_spec')
- mkdir('bang_filter_spec')
- write_file('bang_filter_spec/f1', 'f1')
- write_file('bang_filter_spec/f2', 'f2')
- write_file('bang_filter_spec/f3', 'f3')
- screen = Screen.new()
- screen:attach()
- end)
-
- after_each(function()
- rmdir('bang_filter_spec')
- end)
-
- it('#3269 Last line of shell output is not truncated', function()
- command([[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
- feed([[\l]])
- screen:expect([[
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- ~ |
- :!ls bang_filter_spec |
- |
- f1 |
- f2 |
- f3 |
- Press ENTER or type command to continue^ |
- ]])
- end)
-
-end)
diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c
index 8dbec2aaee..38695ce76b 100644
--- a/test/functional/fixtures/shell-test.c
+++ b/test/functional/fixtures/shell-test.c
@@ -4,6 +4,13 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
+#include <unistd.h>
+
+static void wait(void)
+{
+ fflush(stdout);
+ usleep(10*1000);
+}
static void help(void)
{
@@ -61,6 +68,22 @@ int main(int argc, char **argv)
for (uint8_t i = 0; i < number; i++) {
printf("%d: %s\n", (int) i, argv[3]);
}
+ } else if (strcmp(argv[1], "UTF-8") == 0) {
+ // test split-up UTF-8 sequence
+ printf("\xc3"); wait();
+ printf("\xa5\n"); wait();
+
+ // split up a 2+2 grapheme clusters all possible ways
+ printf("ref: \xc3\xa5\xcc\xb2\n"); wait();
+
+ printf("1: \xc3"); wait();
+ printf("\xa5\xcc\xb2\n"); wait();
+
+ printf("2: \xc3\xa5"); wait();
+ printf("\xcc\xb2\n"); wait();
+
+ printf("3: \xc3\xa5\xcc"); wait();
+ printf("\xb2\n"); wait();
} else {
fprintf(stderr, "Unknown first argument\n");
return 3;
diff --git a/test/functional/fixtures/shell_data.txt b/test/functional/fixtures/shell_data.txt
new file mode 100644
index 0000000000..ef3506c5b1
--- /dev/null
+++ b/test/functional/fixtures/shell_data.txt
Binary files differ
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index 191f145095..ec754a533b 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -222,20 +222,19 @@ describe('argument list commands', function()
eq({'a', 'b'}, eval('argv()'))
eq('b', eval('expand("%:t")'))
command('argedit a')
- eq({'a', 'b'}, eval('argv()'))
+ eq({'a', 'b', 'a'}, eval('argv()'))
eq('a', eval('expand("%:t")'))
command('argedit c')
- eq({'a', 'c', 'b'}, eval('argv()'))
+ eq({'a', 'b', 'a', 'c'}, eval('argv()'))
command('0argedit x')
- eq({'x', 'a', 'c', 'b'}, eval('argv()'))
+ eq({'x', 'a', 'b', 'a', 'c'}, eval('argv()'))
command('enew! | set modified')
assert_fails('argedit y', 'E37:')
command('argedit! y')
- eq({'x', 'y', 'a', 'c', 'b'}, eval('argv()'))
+ eq({'x', 'y', 'y', 'a', 'b', 'a', 'c'}, eval('argv()'))
command('%argd')
- -- Nvim allows unescaped spaces in filename on all platforms. #6010
command('argedit a b')
- eq({'a b'}, eval('argv()'))
+ eq({'a', 'b'}, eval('argv()'))
end)
it('test for :argdelete command', function()
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
new file mode 100644
index 0000000000..91d602924c
--- /dev/null
+++ b/test/functional/legacy/edit_spec.lua
@@ -0,0 +1,25 @@
+-- Test for edit functions
+-- See also: src/nvim/testdir/test_edit.vim
+
+local helpers = require('test.functional.helpers')(after_each)
+local source = helpers.source
+local eq, eval = helpers.eq, helpers.eval
+local funcs = helpers.funcs
+local clear = helpers.clear
+
+describe('edit', function()
+ before_each(clear)
+
+ it('reset insertmode from i_ctrl-r_=', function()
+ source([=[
+ call setline(1, ['abc'])
+ call cursor(1, 4)
+ call feedkeys(":set im\<cr>ZZZ\<c-r>=setbufvar(1,'&im', 0)\<cr>",'tnix')
+ ]=])
+ eq({'abZZZc'}, funcs.getline(1,'$'))
+ eq({0, 1, 1, 0}, funcs.getpos('.'))
+ eq(0, eval('&im'))
+ end)
+
+end)
+
diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua
index 5f71861821..277d8d6c7f 100644
--- a/test/functional/legacy/search_spec.lua
+++ b/test/functional/legacy/search_spec.lua
@@ -6,6 +6,7 @@ local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local funcs = helpers.funcs
+local wait = helpers.wait
describe('search cmdline', function()
local screen
@@ -471,4 +472,113 @@ describe('search cmdline', function()
coladd = 0, skipcol = 0, curswant = 0},
funcs.winsaveview())
end)
+
+ it("CTRL-G with 'incsearch' and ? goes in the right direction", function()
+ -- oldtest: Test_search_cmdline4().
+ screen:detach()
+ screen = Screen.new(40, 4)
+ screen:attach()
+ screen:set_default_attr_ids({
+ inc = {reverse = true},
+ err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
+ more = { bold = true, foreground = Screen.colors.SeaGreen4 },
+ tilde = { bold = true, foreground = Screen.colors.Blue1 },
+ })
+ command('enew!')
+ funcs.setline(1, {' 1 the first', ' 2 the second', ' 3 the third'})
+ command('set laststatus=0 shortmess+=s')
+ command('set incsearch')
+ command('$')
+ -- Send the input in chunks, so the cmdline logic regards it as
+ -- "interactive". This mimics Vim's test_override("char_avail").
+ -- (See legacy test: test_search.vim)
+ feed('?the')
+ wait()
+ feed('<c-g>')
+ wait()
+ feed('<cr>')
+ screen:expect([[
+ 1 the first |
+ 2 the second |
+ 3 ^the third |
+ ?the |
+ ]])
+
+ command('$')
+ feed('?the')
+ wait()
+ feed('<c-g>')
+ wait()
+ feed('<c-g>')
+ wait()
+ feed('<cr>')
+ screen:expect([[
+ 1 ^the first |
+ 2 the second |
+ 3 the third |
+ ?the |
+ ]])
+
+ command('$')
+ feed('?the')
+ wait()
+ feed('<c-g>')
+ wait()
+ feed('<c-g>')
+ wait()
+ feed('<c-g>')
+ wait()
+ feed('<cr>')
+ screen:expect([[
+ 1 the first |
+ 2 ^the second |
+ 3 the third |
+ ?the |
+ ]])
+
+ command('$')
+ feed('?the')
+ wait()
+ feed('<c-t>')
+ wait()
+ feed('<cr>')
+ screen:expect([[
+ 1 ^the first |
+ 2 the second |
+ 3 the third |
+ ?the |
+ ]])
+
+ command('$')
+ feed('?the')
+ wait()
+ feed('<c-t>')
+ wait()
+ feed('<c-t>')
+ wait()
+ feed('<cr>')
+ screen:expect([[
+ 1 the first |
+ 2 the second |
+ 3 ^the third |
+ ?the |
+ ]])
+
+ command('$')
+ feed('?the')
+ wait()
+ feed('<c-t>')
+ wait()
+ feed('<c-t>')
+ wait()
+ feed('<c-t>')
+ wait()
+ feed('<cr>')
+ screen:expect([[
+ 1 the first |
+ 2 ^the second |
+ 3 the third |
+ ?the |
+ ]])
+ end)
end)
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index dc189b8f8e..e5da7932a5 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -66,13 +66,13 @@ describe(':Man', function()
ithis <C-v><ESC>[1mis <C-v><ESC>[3ma <C-v><ESC>[4mtest<C-v><ESC>[0m
<C-v><ESC>[4mwith<C-v><ESC>[24m <C-v><ESC>[4mescaped<C-v><ESC>[24m <C-v><ESC>[4mtext<C-v><ESC>[24m<ESC>]])
- screen:expect([[
+ screen:expect([=[
this ^[[1mis ^[[3ma ^[[4mtest^[[0m |
^[[4mwith^[[24m ^[[4mescaped^[[24m ^[[4mtext^[[24^m |
~ |
~ |
|
- ]])
+ ]=])
eval('man#init_pager()')
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index ee92ba6865..0a30b9bb02 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -2,8 +2,11 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, wait, nvim = helpers.clear, helpers.wait, helpers.nvim
local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
+local feed = helpers.feed
local feed_command, eval = helpers.feed_command, helpers.eval
+local funcs = helpers.funcs
local retry = helpers.retry
+local ok = helpers.ok
local iswin = helpers.iswin
describe(':terminal', function()
@@ -24,13 +27,16 @@ describe(':terminal', function()
]])
-- Invoke a command that emits frequent terminal activity.
if iswin() then
- feed_command([[terminal for /L \\%I in (1,0,2) do echo \\%I]])
+ feed_command([[terminal for /L \%I in (1,0,2) do echo \%I]])
else
feed_command([[terminal while true; do echo X; done]])
end
- helpers.feed([[<C-\><C-N>]])
+ feed([[<C-\><C-N>]])
wait()
- screen:sleep(10) -- Let some terminal activity happen.
+ -- Wait for some terminal activity.
+ retry(nil, 4000, function()
+ ok(funcs.line('$') > 6)
+ end)
feed_command("messages")
screen:expect([[
msg1 |
@@ -46,7 +52,7 @@ describe(':terminal', function()
else
feed_command([[terminal while true; do echo foo; sleep .1; done]])
end
- helpers.feed([[<C-\><C-N>M]]) -- move cursor away from last line
+ feed([[<C-\><C-N>M]]) -- move cursor away from last line
wait()
eq(3, eval("line('$')")) -- window height
eq(2, eval("line('.')")) -- cursor is in the middle
@@ -56,6 +62,32 @@ describe(':terminal', function()
eq(2, eval("line('.')")) -- cursor stays where we put it
end)
+ it('Enter/Leave does not increment jumplist #3723', function()
+ feed_command('terminal')
+ local function enter_and_leave()
+ local lines_before = funcs.line('$')
+ -- Create a new line (in the shell). For a normal buffer this
+ -- increments the jumplist; for a terminal-buffer it should not. #3723
+ feed('i')
+ wait()
+ feed('<CR><CR><CR><CR>')
+ wait()
+ feed([[<C-\><C-N>]])
+ wait()
+ -- Wait for >=1 lines to be created.
+ retry(nil, 4000, function()
+ ok(funcs.line('$') > lines_before)
+ end)
+ end
+ enter_and_leave()
+ enter_and_leave()
+ enter_and_leave()
+ ok(funcs.line('$') > 6) -- Verify assumption.
+ local jumps = funcs.split(funcs.execute('jumps'), '\n')
+ eq(' jump line col file/text', jumps[1])
+ eq(3, #jumps)
+ end)
+
end)
describe(':terminal (with fake shell)', function()
@@ -151,12 +183,12 @@ describe(':terminal (with fake shell)', function()
it('ignores writes if the backing stream closes', function()
terminal_with_fake_shell()
- helpers.feed('iiXXXXXXX')
+ feed('iiXXXXXXX')
wait()
-- Race: Though the shell exited (and streams were closed by SIGCHLD
-- handler), :terminal cleanup is pending on the main-loop.
-- This write should be ignored (not crash, #5445).
- helpers.feed('iiYYYYYYY')
+ feed('iiYYYYYYY')
eq(2, eval("1+1")) -- Still alive?
end)
@@ -175,7 +207,7 @@ describe(':terminal (with fake shell)', function()
:terminal |
]])
eq('term://', string.match(eval('bufname("%")'), "^term://"))
- helpers.feed([[<C-\><C-N>]])
+ feed([[<C-\><C-N>]])
feed_command([[find */shadacat.py]])
if iswin() then
eq('scripts\\shadacat.py', eval('bufname("%")'))
@@ -192,9 +224,9 @@ describe(':terminal (with fake shell)', function()
[Process exited 0] |
:terminal echo "scripts/shadacat.py" |
]])
- helpers.feed([[<C-\><C-N>]])
+ feed([[<C-\><C-N>]])
eq('term://', string.match(eval('bufname("%")'), "^term://"))
- helpers.feed([[ggf"lgf]])
+ feed([[ggf"lgf]])
eq('scripts/shadacat.py', eval('bufname("%")'))
end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index a62c03b70f..171745eb57 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -242,7 +242,7 @@ describe('tui', function()
{9:~ }|
{9:~ }|
{3:[No Name] [+] }|
- |
+ :set termguicolors |
{4:-- TERMINAL --} |
]])
@@ -253,7 +253,7 @@ describe('tui', function()
{2:~ }|
{2:~ }|
{3:[No Name] [+] }|
- |
+ :set notermguicolors |
{4:-- TERMINAL --} |
]])
end)
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index 091c45596d..5b38921e50 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -2,11 +2,11 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local command, request, neq = helpers.command, helpers.request, helpers.neq
+local command, neq = helpers.command, helpers.neq
+local curbufmeths = helpers.curbufmeths
describe('Buffer highlighting', function()
local screen
- local curbuf
before_each(function()
clear()
@@ -25,21 +25,14 @@ describe('Buffer highlighting', function()
[9] = {foreground = Screen.colors.SlateBlue, underline = true},
[10] = {foreground = Screen.colors.Red}
})
- curbuf = request('nvim_get_current_buf')
end)
after_each(function()
screen:detach()
end)
- local function add_hl(...)
- return request('nvim_buf_add_highlight', curbuf, ...)
- end
-
- local function clear_hl(...)
- return request('nvim_buf_clear_highlight', curbuf, ...)
- end
-
+ local add_hl = curbufmeths.add_highlight
+ local clear_hl = curbufmeths.clear_highlight
it('works', function()
insert([[
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 2252e3580f..95fb2ce21c 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -905,6 +905,7 @@ describe("'winhighlight' highlight", function()
end)
it('background applies also to non-text', function()
+ command('set sidescroll=0')
insert('Lorem ipsum dolor sit amet ')
command('set shiftwidth=2')
feed('>>')
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 13820af3b8..e5708d51ef 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths
local insert, feed_command = helpers.insert, helpers.feed_command
local eq, funcs = helpers.eq, helpers.funcs
+local command = helpers.command
describe('ui/mouse/input', function()
local screen
@@ -706,6 +707,7 @@ describe('ui/mouse/input', function()
end)
it('horizontal scrolling', function()
+ command('set sidescroll=0')
feed("<esc>:set nowrap<cr>")
feed("a <esc>20Ab<esc>")
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index c6d564e8dc..4246020fab 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -1,14 +1,24 @@
-local session = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local helpers = require('test.functional.helpers')(after_each)
local child_session = require('test.functional.terminal.helpers')
-
-if session.pending_win32(pending) then return end
+local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+local iswin = helpers.iswin
+local clear = helpers.clear
+local command = helpers.command
+local nvim_dir = helpers.nvim_dir
describe("shell command :!", function()
+ if helpers.pending_win32(pending) then return end
+
local screen
before_each(function()
- session.clear()
- screen = child_session.screen_setup(0, '["'..session.nvim_prog..
- '", "-u", "NONE", "-i", "NONE", "--cmd", "'..session.nvim_set..'"]')
+ clear()
+ screen = child_session.screen_setup(0, '["'..helpers.nvim_prog..
+ '", "-u", "NONE", "-i", "NONE", "--cmd", "'..helpers.nvim_set..'"]')
screen:expect([[
{1: } |
{4:~ }|
@@ -33,15 +43,15 @@ describe("shell command :!", function()
{4:~ }|
{4:~ }|
{4:~ }|
+ {4:~ }|
:!printf foo; sleep 200 |
- |
foo |
{3:-- TERMINAL --} |
]])
end)
it("throttles shell-command output greater than ~10KB", function()
- if os.getenv("TRAVIS") and session.os_name() == "osx" then
+ if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
pending("[Unreliable on Travis macOS.]", function() end)
return
end
@@ -56,13 +66,164 @@ describe("shell command :!", function()
-- Final chunk of output should always be displayed, never skipped.
-- (Throttling is non-deterministic, this test is merely a sanity check.)
screen:expect([[
- XXXXXXXXXX 2996 |
XXXXXXXXXX 2997 |
XXXXXXXXXX 2998 |
XXXXXXXXXX 2999 |
XXXXXXXXXX 3000 |
+ |
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
]])
end)
end)
+
+describe("shell command :!", function()
+ before_each(function()
+ clear()
+ end)
+
+ it("cat a binary file #4142", function()
+ feed(":exe 'silent !cat '.shellescape(v:progpath)<CR>")
+ eq(2, eval('1+1')) -- Still alive?
+ end)
+
+ it([[display \x08 char #4142]], function()
+ feed(":silent !echo \08<CR>")
+ eq(2, eval('1+1')) -- Still alive?
+ end)
+
+ it([[handles control codes]], function()
+ if iswin() then
+ pending('missing printf', function() end)
+ return
+ end
+ local screen = Screen.new(50, 4)
+ screen:attach()
+ -- Print TAB chars. #2958
+ feed([[:!printf '1\t2\t3'<CR>]])
+ screen:expect([[
+ ~ |
+ :!printf '1\t2\t3' |
+ 1 2 3 |
+ Press ENTER or type command to continue^ |
+ ]])
+ feed([[<CR>]])
+ -- Print BELL control code. #4338
+ screen.bell = false
+ feed([[:!printf '\x07\x07\x07\x07text'<CR>]])
+ screen:expect([[
+ ~ |
+ :!printf '\x07\x07\x07\x07text' |
+ text |
+ Press ENTER or type command to continue^ |
+ ]], nil, nil, function()
+ eq(true, screen.bell)
+ end)
+ feed([[<CR>]])
+ -- Print BS control code.
+ feed([[:echo system('printf ''\x08\n''')<CR>]])
+ screen:expect([[
+ ~ |
+ ^H |
+ |
+ Press ENTER or type command to continue^ |
+ ]])
+ feed([[<CR>]])
+ -- Print LF control code.
+ feed([[:!printf '\n'<CR>]])
+ screen:expect([[
+ :!printf '\n' |
+ |
+ |
+ Press ENTER or type command to continue^ |
+ ]])
+ feed([[<CR>]])
+ end)
+
+ describe('', function()
+ local screen
+ before_each(function()
+ rmdir('bang_filter_spec')
+ mkdir('bang_filter_spec')
+ write_file('bang_filter_spec/f1', 'f1')
+ write_file('bang_filter_spec/f2', 'f2')
+ write_file('bang_filter_spec/f3', 'f3')
+ screen = Screen.new(53,10)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {foreground = Screen.colors.Blue1},
+ [3] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ })
+ screen:attach()
+ end)
+
+ after_each(function()
+ rmdir('bang_filter_spec')
+ end)
+
+ it("doesn't truncate Last line of shell output #3269", function()
+ command(helpers.iswin()
+ and [[nnoremap <silent>\l :!dir /b bang_filter_spec<cr>]]
+ or [[nnoremap <silent>\l :!ls bang_filter_spec<cr>]])
+ local result = (helpers.iswin()
+ and [[:!dir /b bang_filter_spec]]
+ or [[:!ls bang_filter_spec ]])
+ feed([[\l]])
+ screen:expect([[
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]..result..[[ |
+ f1 |
+ f2 |
+ f3 |
+ |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+
+ it('handles binary and multibyte data', function()
+ feed_command('!cat test/functional/fixtures/shell_data.txt')
+ screen.bell = false
+ screen:expect([[
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ :!cat test/functional/fixtures/shell_data.txt |
+ {2:^@^A^B^C^D^E^F^H} |
+ {2:^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\^]^^^_} |
+ ö 한글 {2:<a5><c3>} |
+ t {2:<ff>} |
+ |
+ {3:Press ENTER or type command to continue}^ |
+ ]], nil, nil, function()
+ eq(true, screen.bell)
+ end)
+ end)
+
+ it('handles multibyte sequences split over buffer boundaries', function()
+ command('cd '..nvim_dir)
+ local cmd
+ if iswin() then
+ cmd = '!shell-test UTF-8 '
+ else
+ cmd = '!./shell-test UTF-8'
+ end
+ feed_command(cmd)
+ -- Note: only the first example of split composed char works
+ screen:expect([[
+ {1:~ }|
+ {1:~ }|
+ :]]..cmd..[[ |
+ å |
+ ref: å̲ |
+ 1: å̲ |
+ 2: å ̲ |
+ 3: å ̲ |
+ |
+ {3:Press ENTER or type command to continue}^ |
+ ]])
+ end)
+ end)
+end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 696feabeed..52e108f389 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -455,6 +455,9 @@ function Screen:_handle_visual_bell()
self.visual_bell = true
end
+function Screen:_handle_default_colors_set()
+end
+
function Screen:_handle_update_fg(fg)
self._fg = fg
end
diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
new file mode 100644
index 0000000000..913f1b9bed
--- /dev/null
+++ b/test/functional/ui/spell_spec.lua
@@ -0,0 +1,49 @@
+-- Test for scenarios involving 'spell'
+
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+local feed_command = helpers.feed_command
+local insert = helpers.insert
+
+describe("'spell'", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(80, 8)
+ screen:attach()
+ screen:set_default_attr_ids( {
+ [0] = {bold=true, foreground=Screen.colors.Blue},
+ [1] = {special = Screen.colors.Red, undercurl = true}
+ })
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it('joins long lines #7937', function()
+ feed_command('set spell')
+ insert([[
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
+ non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ ]])
+ feed('ggJJJJJJ0')
+ screen:expect([[
+ {1:^Lorem} {1:ipsum} dolor sit {1:amet}, {1:consectetur} {1:adipiscing} {1:elit}, {1:sed} do {1:eiusmod} {1:tempor} {1:i}|
+ {1:ncididunt} {1:ut} {1:labore} {1:et} {1:dolore} {1:magna} {1:aliqua}. {1:Ut} {1:enim} ad minim {1:veniam}, {1:quis} {1:nostru}|
+ {1:d} {1:exercitation} {1:ullamco} {1:laboris} {1:nisi} {1:ut} {1:aliquip} ex ea {1:commodo} {1:consequat}. {1:Duis} {1:aut}|
+ {1:e} {1:irure} dolor in {1:reprehenderit} in {1:voluptate} {1:velit} {1:esse} {1:cillum} {1:dolore} {1:eu} {1:fugiat} {1:n}|
+ {1:ulla} {1:pariatur}. {1:Excepteur} {1:sint} {1:occaecat} {1:cupidatat} non {1:proident}, {1:sunt} in culpa {1:qui}|
+ {1:officia} {1:deserunt} {1:mollit} {1:anim} id est {1:laborum}. |
+ {0:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/helpers.lua b/test/helpers.lua
index faf5c8e7f2..1c64f41b65 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -423,11 +423,13 @@ format_luav = function(v, indent, opts)
if opts.literal_strings then
ret = v
else
- ret = tostring(v):gsub('[\'\\]', '\\%0'):gsub(
- '[%z\1-\31]', function(match)
- return SUBTBL[match:byte() + 1]
- end)
- ret = '\'' .. ret .. '\''
+ local quote = opts.dquote_strings and '"' or '\''
+ ret = quote .. tostring(v):gsub(
+ opts.dquote_strings and '["\\]' or '[\'\\]',
+ '\\%0'):gsub(
+ '[%z\1-\31]', function(match)
+ return SUBTBL[match:byte() + 1]
+ end) .. quote
end
elseif type(v) == 'table' then
if v == REMOVE_THIS then
@@ -490,11 +492,14 @@ local function format_string(fmt, ...)
if subfmt:sub(-1) ~= '%' then
arg = getarg()
end
- if subfmt:sub(-1) == 'r' then
- -- %r is like %q, but it is supposed to single-quote strings and not
- -- double-quote them, and also work not only for strings.
+ if subfmt:sub(-1) == 'r' or subfmt:sub(-1) == 'q' then
+ -- %r is like built-in %q, but it is supposed to single-quote strings and
+ -- not double-quote them, and also work not only for strings.
+ -- Builtin %q is replaced here as it gives invalid and inconsistent with
+ -- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`,
+ -- lua leaves as-is.
+ arg = format_luav(arg, nil, {dquote_strings = (subfmt:sub(-1) == 'q')})
subfmt = subfmt:sub(1, -2) .. 's'
- arg = format_luav(arg)
end
if subfmt == '%e' then
return format_float(arg)
diff --git a/test/unit/viml/expressions/parser_tests.lua b/test/unit/viml/expressions/parser_tests.lua
index e085d7e932..da61672bb1 100644
--- a/test/unit/viml/expressions/parser_tests.lua
+++ b/test/unit/viml/expressions/parser_tests.lua
@@ -5025,7 +5025,7 @@ return function(itp, _check_parsing, hl, fmtn)
-- 0123456789012345
-- 0 1
ast = {
- [[DoubleQuotedString(val="\8\27\12\13\9\\"):0:0:"\b\e\f\r\t\\"]],
+ [[DoubleQuotedString(val="\008\027\012\r\t\\"):0:0:"\b\e\f\r\t\\"]],
},
}, {
hl('DoubleQuote', '"'),
@@ -5040,7 +5040,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\n\n"', {
-- 01234
ast = {
- fmtn('DoubleQuotedString', 'val="\\\n\\\n"', ':0:0:"\\n\n"'),
+ fmtn('DoubleQuotedString', 'val="\\n\\n"', ':0:0:"\\n\n"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5051,7 +5051,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\x00"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\0"', ':0:0:"\\x00"'),
+ fmtn('DoubleQuotedString', 'val="\\000"', ':0:0:"\\x00"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5071,7 +5071,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\xF"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\15"', ':0:0:"\\xF"'),
+ fmtn('DoubleQuotedString', 'val="\\015"', ':0:0:"\\xF"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5126,7 +5126,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\xF', {
-- 0123
ast = {
- fmtn('DoubleQuotedString', 'val="\\15"', ':0:0:"\\xF'),
+ fmtn('DoubleQuotedString', 'val="\\015"', ':0:0:"\\xF'),
},
err = {
arg = '"\\xF',
@@ -5190,7 +5190,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\xFX"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\15X"', ':0:0:"\\xFX"'),
+ fmtn('DoubleQuotedString', 'val="\\015X"', ':0:0:"\\xFX"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5202,7 +5202,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\XFX"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\15X"', ':0:0:"\\XFX"'),
+ fmtn('DoubleQuotedString', 'val="\\015X"', ':0:0:"\\XFX"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5262,7 +5262,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\x0X"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\x0X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\x0X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5274,7 +5274,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\X0X"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\X0X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\X0X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5286,7 +5286,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\u0X"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\u0X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\u0X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5298,7 +5298,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\U0X"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U0X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U0X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5310,7 +5310,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\x00X"', {
-- 0123456
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\x00X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\x00X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5322,7 +5322,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\X00X"', {
-- 0123456
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\X00X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\X00X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5334,7 +5334,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\u00X"', {
-- 0123456
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\u00X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\u00X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5346,7 +5346,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\U00X"', {
-- 0123456
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U00X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U00X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5358,7 +5358,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\u000X"', {
-- 01234567
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\u000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\u000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5370,7 +5370,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\U000X"', {
-- 01234567
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5382,7 +5382,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\u0000X"', {
-- 012345678
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\u0000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\u0000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5394,7 +5394,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\U0000X"', {
-- 012345678
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U0000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U0000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5406,7 +5406,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\U00000X"', {
-- 0123456789
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U00000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U00000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5419,7 +5419,7 @@ return function(itp, _check_parsing, hl, fmtn)
-- 01234567890
-- 0 1
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U000000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U000000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5432,7 +5432,7 @@ return function(itp, _check_parsing, hl, fmtn)
-- 012345678901
-- 0 1
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U0000000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U0000000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5445,7 +5445,7 @@ return function(itp, _check_parsing, hl, fmtn)
-- 0123456789012
-- 0 1
ast = {
- fmtn('DoubleQuotedString', 'val="\\0X"', ':0:0:"\\U00000000X"'),
+ fmtn('DoubleQuotedString', 'val="\\000X"', ':0:0:"\\U00000000X"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5506,7 +5506,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\0"', {
-- 0123
ast = {
- fmtn('DoubleQuotedString', 'val="\\0"', ':0:0:"\\0"'),
+ fmtn('DoubleQuotedString', 'val="\\000"', ':0:0:"\\0"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5517,7 +5517,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\00"', {
-- 01234
ast = {
- fmtn('DoubleQuotedString', 'val="\\0"', ':0:0:"\\00"'),
+ fmtn('DoubleQuotedString', 'val="\\000"', ':0:0:"\\00"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5528,7 +5528,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\000"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\0"', ':0:0:"\\000"'),
+ fmtn('DoubleQuotedString', 'val="\\000"', ':0:0:"\\000"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -5620,7 +5620,7 @@ return function(itp, _check_parsing, hl, fmtn)
check_parsing('"\\<C-u>"', {
-- 012345
ast = {
- fmtn('DoubleQuotedString', 'val="\\21"', ':0:0:"\\<C-u>"'),
+ fmtn('DoubleQuotedString', 'val="\\021"', ':0:0:"\\<C-u>"'),
},
}, {
hl('DoubleQuote', '"'),
@@ -7119,7 +7119,7 @@ return function(itp, _check_parsing, hl, fmtn)
'Or:0:0:|',
children = {
'Missing:0:0:',
- fmtn('DoubleQuotedString', 'val="\\27"', ':0:1:"\\e"'),
+ fmtn('DoubleQuotedString', 'val="\\027"', ':0:1:"\\e"'),
},
},
},
@@ -7180,9 +7180,9 @@ return function(itp, _check_parsing, hl, fmtn)
hl('InvalidDoubleQuotedUnknownEscape', '\\<'),
})
check_parsing('"\\1', {
- -- 012
+ -- 01 2
ast = {
- fmtn('DoubleQuotedString', 'val="\\1"', ':0:0:"\\1'),
+ fmtn('DoubleQuotedString', 'val="\\001"', ':0:0:"\\1'),
},
err = {
arg = '"\\1',
diff --git a/third-party/cmake/BuildLua.cmake b/third-party/cmake/BuildLua.cmake
index ea1371d1d5..da617e3ccd 100644
--- a/third-party/cmake/BuildLua.cmake
+++ b/third-party/cmake/BuildLua.cmake
@@ -71,6 +71,7 @@ set(LUA_CONFIGURE_COMMAND
-e "s@-lncurses@@g"
-i ${DEPS_BUILD_DIR}/src/lua/src/Makefile &&
sed -e "/#define LUA_USE_READLINE/d"
+ -e "s@\\(#define LUA_ROOT[ ]*\"\\)/usr/local@\\1${DEPS_INSTALL_DIR}@"
-i ${DEPS_BUILD_DIR}/src/lua/src/luaconf.h)
set(LUA_INSTALL_TOP_ARG "INSTALL_TOP=${DEPS_INSTALL_DIR}")
set(LUA_BUILD_COMMAND
@@ -84,14 +85,13 @@ BuildLua(CONFIGURE_COMMAND ${LUA_CONFIGURE_COMMAND}
BUILD_COMMAND ${LUA_BUILD_COMMAND}
INSTALL_COMMAND ${LUA_INSTALL_COMMAND})
list(APPEND THIRD_PARTY_DEPS lua)
-add_dependencies(lua busted)
set(BUSTED ${DEPS_INSTALL_DIR}/bin/busted)
set(BUSTED_LUA ${BUSTED}-lua)
add_custom_command(OUTPUT ${BUSTED_LUA}
COMMAND sed -e 's/^exec/exec $$LUA_DEBUGGER/' -e 's/jit//g' < ${BUSTED} > ${BUSTED_LUA} && chmod +x ${BUSTED_LUA}
- DEPENDS lua)
+ DEPENDS lua busted)
add_custom_target(busted-lua
DEPENDS ${DEPS_INSTALL_DIR}/bin/busted-lua)
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index 1343948d36..2d9c77ff97 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -56,13 +56,16 @@ if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING))
if(USE_BUNDLED_LUAJIT)
list(APPEND LUAROCKS_OPTS
--with-lua=${HOSTDEPS_INSTALL_DIR}
- --with-lua-include=${HOSTDEPS_INSTALL_DIR}/include/luajit-2.0)
+ --with-lua-include=${HOSTDEPS_INSTALL_DIR}/include/luajit-2.0
+ --lua-suffix=jit)
+ elseif(USE_BUNDLED_LUA)
+ list(APPEND LUAROCKS_OPTS
+ --with-lua=${HOSTDEPS_INSTALL_DIR})
endif()
BuildLuarocks(
CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/src/luarocks/configure
--prefix=${HOSTDEPS_INSTALL_DIR} --force-config ${LUAROCKS_OPTS}
- --lua-suffix=jit
INSTALL_COMMAND ${MAKE_PRG} bootstrap)
elseif(MSVC OR MINGW)
@@ -94,6 +97,8 @@ if(USE_BUNDLED_LUAJIT)
if(MINGW AND CMAKE_CROSSCOMPILING)
add_dependencies(luarocks luajit_host)
endif()
+elseif(USE_BUNDLED_LUA)
+ add_dependencies(luarocks lua)
endif()
# DEPENDS on the previous module, because Luarocks breaks if parallel.
@@ -125,12 +130,30 @@ add_custom_target(inspect
list(APPEND THIRD_PARTY_DEPS inspect)
+if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA)
+ # DEPENDS on the previous module, because Luarocks breaks if parallel.
+ add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luabitop
+ COMMAND ${LUAROCKS_BINARY}
+ ARGS build luabitop ${LUAROCKS_BUILDARGS}
+ DEPENDS inspect)
+ add_custom_target(luabitop
+ DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luabitop)
+
+ list(APPEND THIRD_PARTY_DEPS luabitop)
+endif()
+
if(USE_BUNDLED_BUSTED)
+ if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA)
+ set(PENLIGHT_DEPENDS luabitop)
+ else()
+ set(PENLIGHT_DEPENDS inspect)
+ endif()
+
# DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/penlight/1.3.2-2
COMMAND ${LUAROCKS_BINARY}
ARGS build penlight 1.3.2-2 ${LUAROCKS_BUILDARGS}
- DEPENDS inspect)
+ DEPENDS ${PENLIGHT_DEPENDS})
add_custom_target(penlight
DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/penlight/1.3.2-2)